Skip to content

Commit

Permalink
Add Artifact as param option to getContractAt on ethers
Browse files Browse the repository at this point in the history
Let users pass in their own `Artifact` instance to `getContractAt`, this is mainly to maintain parity with `getContractFactory`.

Relates to #1716.
  • Loading branch information
kanej committed Dec 1, 2021
1 parent 9763569 commit da3dd8c
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 28 deletions.
65 changes: 38 additions & 27 deletions packages/hardhat-ethers/src/internal/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,46 +297,57 @@ async function getContractFactoryByAbiAndBytecode(

export async function getContractAt(
hre: HardhatRuntimeEnvironment,
nameOrAbi: string | any[],
nameOrArtifactOrAbi: string | Artifact | any[],
address: string,
signer?: ethers.Signer
) {
const { Contract } = require("ethers") as typeof ethers;

if (typeof nameOrAbi === "string") {
const artifact = await hre.artifacts.readArtifact(nameOrAbi);
const factory = await getContractFactoryByAbiAndBytecode(
hre,
artifact.abi,
"0x",
signer
);

let contract = factory.attach(address);
// If there's no signer, we connect the contract instance to the provider for the selected network.
if (contract.provider === null) {
contract = contract.connect(hre.ethers.provider);
if (Array.isArray(nameOrArtifactOrAbi)) {
if (signer === undefined) {
const signers = await hre.ethers.getSigners();
signer = signers[0];
}

return contract;
}
// If there's no signer, we want to put the provider for the selected network here.
// This allows read only operations on the contract interface.
const signerOrProvider: ethers.Signer | ethers.providers.Provider =
signer !== undefined ? signer : hre.ethers.provider;

if (signer === undefined) {
const signers = await hre.ethers.getSigners();
signer = signers[0];
const abiWithAddedGas = addGasToAbiMethodsIfNecessary(
hre.network.config,
nameOrArtifactOrAbi
);

return new Contract(address, abiWithAddedGas, signerOrProvider);
}

// If there's no signer, we want to put the provider for the selected network here.
// This allows read only operations on the contract interface.
const signerOrProvider: ethers.Signer | ethers.providers.Provider =
signer !== undefined ? signer : hre.ethers.provider;
let artifact: Artifact;
if (typeof nameOrArtifactOrAbi === "string") {
artifact = await hre.artifacts.readArtifact(nameOrArtifactOrAbi);
} else if (isArtifact(nameOrArtifactOrAbi)) {
artifact = nameOrArtifactOrAbi;
} else {
throw new NomicLabsHardhatPluginError(
pluginName,
"Bad parameter passed to `getContractAt`"
);
}

const abiWithAddedGas = addGasToAbiMethodsIfNecessary(
hre.network.config,
nameOrAbi
const factory = await getContractFactoryByAbiAndBytecode(
hre,
artifact.abi,
"0x",
signer
);

return new Contract(address, abiWithAddedGas, signerOrProvider);
let contract = factory.attach(address);
// If there's no signer, we connect the contract instance to the provider for the selected network.
if (contract.provider === null) {
contract = contract.connect(hre.ethers.provider);
}

return contract;
}

// This helper adds a `gas` field to the ABI function elements if the network
Expand Down
2 changes: 1 addition & 1 deletion packages/hardhat-ethers/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export interface HardhatEthersHelpers {

getContractFactory: typeof getContractFactory;
getContractAt: (
nameOrAbi: string | any[],
nameOrAbi: string | Artifact | any[],
address: string,
signer?: ethers.Signer
) => Promise<ethers.Contract>;
Expand Down
45 changes: 45 additions & 0 deletions packages/hardhat-ethers/test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,51 @@ describe("Ethers plugin", function () {
});
});

describe("by artifact and address", function () {
it("Should return an instance of a contract", async function () {
const contract = await this.env.ethers.getContractAt(
greeterArtifact,
deployedGreeter.address
);

assert.containsAllKeys(contract.functions, [
"setGreeting(string)",
"greet()",
]);

assert.equal(
await contract.signer.getAddress(),
await signers[0].getAddress()
);
});

it("Should be able to send txs and make calls", async function () {
const greeter = await this.env.ethers.getContractAt(
greeterArtifact,
deployedGreeter.address
);

assert.equal(await greeter.functions.greet(), "Hi");
await greeter.functions.setGreeting("Hola");
assert.equal(await greeter.functions.greet(), "Hola");
});

describe("with custom signer", function () {
it("Should return an instance of a contract associated to a custom signer", async function () {
const contract = await this.env.ethers.getContractAt(
greeterArtifact,
deployedGreeter.address,
signers[1]
);

assert.equal(
await contract.signer.getAddress(),
await signers[1].getAddress()
);
});
});
});

describe("by abi and address", function () {
it("Should return an instance of a contract", async function () {
const contract = await this.env.ethers.getContractAt(
Expand Down

0 comments on commit da3dd8c

Please sign in to comment.