Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ContractFactory runner is null when Hardhat config has no accounts #4594

Open
ericglau opened this issue Nov 16, 2023 · 0 comments
Open

ContractFactory runner is null when Hardhat config has no accounts #4594

ericglau opened this issue Nov 16, 2023 · 0 comments
Labels
status:ready This issue is ready to be worked on

Comments

@ericglau
Copy link

ericglau commented Nov 16, 2023

Version of Hardhat

2.17.2

What happened?

When using a network that is defined in the Hardhat config with only url and no accounts, ethers.getContractFactory instantiates a ContractFactory with no runner.

While it may make sense in the context of the ContractFactory itself for deployments (there is no signer for deploying new contracts), subsequent usage of this ContractFactory might attempt to use the runner not as a signer but as a provider.

For example, consider the following code when there are no accounts:

import { ethers } from "hardhat";

async function main() {
  const MyToken = await ethers.getContractFactory("MyToken"); // MyToken.runner is null
  const instance = MyToken.attach('0xf37F5FE27A63876C172B110B0C229e2Ff3B29Eb8'); // instance.runner is null
  await instance.waitForDeployment();
}

This is a simplified example but we want to wait for a contract instance to exist on the network, but the contract instance may either be a new deployment or something that was previously deployed. In the above, it was previously deployed.

Since ethers uses the contract instance's runner in waitForDeployment to check for deployed code, the above fails with:

Error: runner does not support .provider (operation="getDeployedCode", code=UNSUPPORTED_OPERATION, version=6.7.1)
    at makeError (/Users/eric/Downloads/project 19/node_modules/ethers/src.ts/utils/errors.ts:685:21)
    at assert (/Users/eric/Downloads/project 19/node_modules/ethers/src.ts/utils/errors.ts:702:25)
    at Proxy.getDeployedCode (/Users/eric/Downloads/project 19/node_modules/ethers/src.ts/contract/contract.ts:817:15)
    at Proxy.waitForDeployment (/Users/eric/Downloads/project 19/node_modules/ethers/src.ts/contract/contract.ts:838:33)
    at main (/Users/eric/Downloads/project 19/scripts/waitForDeployment.ts:10:18)
    at processTicksAndRejections (node:internal/process/task_queues:95:5) {
  code: 'UNSUPPORTED_OPERATION',
  operation: 'getDeployedCode'
}

I am wondering if either of the following would make sense for Hardhat:

  • getContractFactory should use the default hre.ethers.provider as the runner if there are no accounts
    or
  • Hardhat should provide an alternative to ContractFactory.attach where Hardhat injects the default hre.ethers.provider if there is no runner in the ContractFactory

Alternatively, please let me know if this is a usage error. For example, the following both work. Would any of these be preferred in terms of usage?

import { ethers } from "hardhat";

async function main() {
  const MyToken = await ethers.getContractFactory("MyToken");
  const MyTokenWithRunner = new ethers.ContractFactory(MyToken.interface, MyToken.bytecode, ethers.provider);
  const instance = MyTokenWithRunner.attach('0xf37F5FE27A63876C172B110B0C229e2Ff3B29Eb8');
  await instance.waitForDeployment();
}

or

import { ethers } from "hardhat";

async function main() {
  const MyToken = await ethers.getContractFactory("MyToken");
  const instance = new ethers.Contract('0xf37F5FE27A63876C172B110B0C229e2Ff3B29Eb8', MyToken.interface, ethers.provider);
  await instance.waitForDeployment();
}

Minimal reproduction steps

Create a new Hardhat project using ethers and hardhat-ethers.

In hardhat-config.ts, specify the following under networks (without any accounts):

    baseGoerli: {
      url: 'https://goerli.base.org',
    }

Create the following script and run it as npx hardhat run scripts/waitForDeployment.ts --network baseGoerli

import { ethers } from "hardhat";

async function main() {
  const MyToken = await ethers.getContractFactory("MyToken");

  console.log('runner', MyToken.runner);

  const instance = MyToken.attach('0xf37F5FE27A63876C172B110B0C229e2Ff3B29Eb8');
  await instance.waitForDeployment();
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

Output:

runner null
Error: runner does not support .provider (operation="getDeployedCode", code=UNSUPPORTED_OPERATION, version=6.7.1)
    at makeError (/Users/eric/Downloads/project 19/node_modules/ethers/src.ts/utils/errors.ts:685:21)
    at assert (/Users/eric/Downloads/project 19/node_modules/ethers/src.ts/utils/errors.ts:702:25)
    at Proxy.getDeployedCode (/Users/eric/Downloads/project 19/node_modules/ethers/src.ts/contract/contract.ts:817:15)
    at Proxy.waitForDeployment (/Users/eric/Downloads/project 19/node_modules/ethers/src.ts/contract/contract.ts:838:33)
    at main (/Users/eric/Downloads/project 19/scripts/waitForDeployment.ts:9:18)
    at processTicksAndRejections (node:internal/process/task_queues:95:5) {
  code: 'UNSUPPORTED_OPERATION',
  operation: 'getDeployedCode'
}

Search terms

ContractFactory runner provider accounts

@github-project-automation github-project-automation bot moved this to Backlog in Hardhat Nov 16, 2023
@ChristopherDedominici ChristopherDedominici added status:ready This issue is ready to be worked on and removed status:triaging labels Nov 24, 2023
@ChristopherDedominici ChristopherDedominici moved this from Backlog to To-do in Hardhat Nov 24, 2023
@schaable schaable removed their assignment Dec 5, 2023
@kanej kanej moved this from To-do to Backlog in Hardhat May 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status:ready This issue is ready to be worked on
Projects
Status: Backlog
Development

No branches or pull requests

3 participants