UNPKG

12.6 kBJavaScriptView Raw
1"use strict";
2var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3 if (k2 === undefined) k2 = k;
4 var desc = Object.getOwnPropertyDescriptor(m, k);
5 if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6 desc = { enumerable: true, get: function() { return m[k]; } };
7 }
8 Object.defineProperty(o, k2, desc);
9}) : (function(o, m, k, k2) {
10 if (k2 === undefined) k2 = k;
11 o[k2] = m[k];
12}));
13var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14 Object.defineProperty(o, "default", { enumerable: true, value: v });
15}) : function(o, v) {
16 o["default"] = v;
17});
18var __importStar = (this && this.__importStar) || function (mod) {
19 if (mod && mod.__esModule) return mod;
20 var result = {};
21 if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22 __setModuleDefault(result, mod);
23 return result;
24};
25Object.defineProperty(exports, "__esModule", { value: true });
26exports.getContractAtFromArtifact = exports.deployContract = exports.getContractAt = exports.getContractFactoryFromArtifact = exports.getContractFactory = exports.getImpersonatedSigner = exports.getSigner = exports.getSigners = void 0;
27const plugins_1 = require("hardhat/plugins");
28const pluginName = "hardhat-ethers";
29function isArtifact(artifact) {
30 const { contractName, sourceName, abi, bytecode, deployedBytecode, linkReferences, deployedLinkReferences, } = artifact;
31 return (typeof contractName === "string" &&
32 typeof sourceName === "string" &&
33 Array.isArray(abi) &&
34 typeof bytecode === "string" &&
35 typeof deployedBytecode === "string" &&
36 linkReferences !== undefined &&
37 deployedLinkReferences !== undefined);
38}
39async function getSigners(hre) {
40 const accounts = await hre.ethers.provider.listAccounts();
41 const signersWithAddress = await Promise.all(accounts.map((account) => getSigner(hre, account)));
42 return signersWithAddress;
43}
44exports.getSigners = getSigners;
45async function getSigner(hre, address) {
46 const { SignerWithAddress: SignerWithAddressImpl } = await Promise.resolve().then(() => __importStar(require("../signers")));
47 const signer = hre.ethers.provider.getSigner(address);
48 const signerWithAddress = await SignerWithAddressImpl.create(signer);
49 return signerWithAddress;
50}
51exports.getSigner = getSigner;
52async function getImpersonatedSigner(hre, address) {
53 await hre.ethers.provider.send("hardhat_impersonateAccount", [address]);
54 return getSigner(hre, address);
55}
56exports.getImpersonatedSigner = getImpersonatedSigner;
57async function getContractFactory(hre, nameOrAbi, bytecodeOrFactoryOptions, signer) {
58 if (typeof nameOrAbi === "string") {
59 const artifact = await hre.artifacts.readArtifact(nameOrAbi);
60 return getContractFactoryFromArtifact(hre, artifact, bytecodeOrFactoryOptions);
61 }
62 return getContractFactoryByAbiAndBytecode(hre, nameOrAbi, bytecodeOrFactoryOptions, signer);
63}
64exports.getContractFactory = getContractFactory;
65function isFactoryOptions(signerOrOptions) {
66 const { Signer } = require("ethers");
67 return signerOrOptions !== undefined && !Signer.isSigner(signerOrOptions);
68}
69async function getContractFactoryFromArtifact(hre, artifact, signerOrOptions) {
70 let libraries = {};
71 let signer;
72 if (!isArtifact(artifact)) {
73 throw new plugins_1.NomicLabsHardhatPluginError(pluginName, `You are trying to create a contract factory from an artifact, but you have not passed a valid artifact parameter.`);
74 }
75 if (isFactoryOptions(signerOrOptions)) {
76 signer = signerOrOptions.signer;
77 libraries = signerOrOptions.libraries ?? {};
78 }
79 else {
80 signer = signerOrOptions;
81 }
82 if (artifact.bytecode === "0x") {
83 throw new plugins_1.NomicLabsHardhatPluginError(pluginName, `You are trying to create a contract factory for the contract ${artifact.contractName}, which is abstract and can't be deployed.
84If you want to call a contract using ${artifact.contractName} as its interface use the "getContractAt" function instead.`);
85 }
86 const linkedBytecode = await collectLibrariesAndLink(artifact, libraries);
87 return getContractFactoryByAbiAndBytecode(hre, artifact.abi, linkedBytecode, signer);
88}
89exports.getContractFactoryFromArtifact = getContractFactoryFromArtifact;
90async function collectLibrariesAndLink(artifact, libraries) {
91 const { utils } = require("ethers");
92 const neededLibraries = [];
93 for (const [sourceName, sourceLibraries] of Object.entries(artifact.linkReferences)) {
94 for (const libName of Object.keys(sourceLibraries)) {
95 neededLibraries.push({ sourceName, libName });
96 }
97 }
98 const linksToApply = new Map();
99 for (const [linkedLibraryName, linkedLibraryAddress] of Object.entries(libraries)) {
100 if (!utils.isAddress(linkedLibraryAddress)) {
101 throw new plugins_1.NomicLabsHardhatPluginError(pluginName, `You tried to link the contract ${artifact.contractName} with the library ${linkedLibraryName}, but provided this invalid address: ${linkedLibraryAddress}`);
102 }
103 const matchingNeededLibraries = neededLibraries.filter((lib) => {
104 return (lib.libName === linkedLibraryName ||
105 `${lib.sourceName}:${lib.libName}` === linkedLibraryName);
106 });
107 if (matchingNeededLibraries.length === 0) {
108 let detailedMessage;
109 if (neededLibraries.length > 0) {
110 const libraryFQNames = neededLibraries
111 .map((lib) => `${lib.sourceName}:${lib.libName}`)
112 .map((x) => `* ${x}`)
113 .join("\n");
114 detailedMessage = `The libraries needed are:
115${libraryFQNames}`;
116 }
117 else {
118 detailedMessage = "This contract doesn't need linking any libraries.";
119 }
120 throw new plugins_1.NomicLabsHardhatPluginError(pluginName, `You tried to link the contract ${artifact.contractName} with ${linkedLibraryName}, which is not one of its libraries.
121${detailedMessage}`);
122 }
123 if (matchingNeededLibraries.length > 1) {
124 const matchingNeededLibrariesFQNs = matchingNeededLibraries
125 .map(({ sourceName, libName }) => `${sourceName}:${libName}`)
126 .map((x) => `* ${x}`)
127 .join("\n");
128 throw new plugins_1.NomicLabsHardhatPluginError(pluginName, `The library name ${linkedLibraryName} is ambiguous for the contract ${artifact.contractName}.
129It may resolve to one of the following libraries:
130${matchingNeededLibrariesFQNs}
131
132To fix this, choose one of these fully qualified library names and replace where appropriate.`);
133 }
134 const [neededLibrary] = matchingNeededLibraries;
135 const neededLibraryFQN = `${neededLibrary.sourceName}:${neededLibrary.libName}`;
136 // The only way for this library to be already mapped is
137 // for it to be given twice in the libraries user input:
138 // once as a library name and another as a fully qualified library name.
139 if (linksToApply.has(neededLibraryFQN)) {
140 throw new plugins_1.NomicLabsHardhatPluginError(pluginName, `The library names ${neededLibrary.libName} and ${neededLibraryFQN} refer to the same library and were given as two separate library links.
141Remove one of them and review your library links before proceeding.`);
142 }
143 linksToApply.set(neededLibraryFQN, {
144 sourceName: neededLibrary.sourceName,
145 libraryName: neededLibrary.libName,
146 address: linkedLibraryAddress,
147 });
148 }
149 if (linksToApply.size < neededLibraries.length) {
150 const missingLibraries = neededLibraries
151 .map((lib) => `${lib.sourceName}:${lib.libName}`)
152 .filter((libFQName) => !linksToApply.has(libFQName))
153 .map((x) => `* ${x}`)
154 .join("\n");
155 throw new plugins_1.NomicLabsHardhatPluginError(pluginName, `The contract ${artifact.contractName} is missing links for the following libraries:
156${missingLibraries}
157
158Learn more about linking contracts at https://hardhat.org/hardhat-runner/plugins/nomiclabs-hardhat-ethers#library-linking
159`);
160 }
161 return linkBytecode(artifact, [...linksToApply.values()]);
162}
163async function getContractFactoryByAbiAndBytecode(hre, abi, bytecode, signer) {
164 const { ContractFactory } = require("ethers");
165 if (signer === undefined) {
166 const signers = await hre.ethers.getSigners();
167 signer = signers[0];
168 }
169 const abiWithAddedGas = addGasToAbiMethodsIfNecessary(hre.network.config, abi);
170 return new ContractFactory(abiWithAddedGas, bytecode, signer);
171}
172async function getContractAt(hre, nameOrAbi, address, signer) {
173 if (typeof nameOrAbi === "string") {
174 const artifact = await hre.artifacts.readArtifact(nameOrAbi);
175 return getContractAtFromArtifact(hre, artifact, address, signer);
176 }
177 const { Contract } = require("ethers");
178 if (signer === undefined) {
179 const signers = await hre.ethers.getSigners();
180 signer = signers[0];
181 }
182 // If there's no signer, we want to put the provider for the selected network here.
183 // This allows read only operations on the contract interface.
184 const signerOrProvider = signer !== undefined ? signer : hre.ethers.provider;
185 const abiWithAddedGas = addGasToAbiMethodsIfNecessary(hre.network.config, nameOrAbi);
186 return new Contract(address, abiWithAddedGas, signerOrProvider);
187}
188exports.getContractAt = getContractAt;
189async function deployContract(hre, name, argsOrSignerOrOptions, signerOrOptions) {
190 let args = [];
191 if (Array.isArray(argsOrSignerOrOptions)) {
192 args = argsOrSignerOrOptions;
193 }
194 else {
195 signerOrOptions = argsOrSignerOrOptions;
196 }
197 const factory = await getContractFactory(hre, name, signerOrOptions);
198 return factory.deploy(...args);
199}
200exports.deployContract = deployContract;
201async function getContractAtFromArtifact(hre, artifact, address, signer) {
202 if (!isArtifact(artifact)) {
203 throw new plugins_1.NomicLabsHardhatPluginError(pluginName, `You are trying to create a contract by artifact, but you have not passed a valid artifact parameter.`);
204 }
205 const factory = await getContractFactoryByAbiAndBytecode(hre, artifact.abi, "0x", signer);
206 let contract = factory.attach(address);
207 // If there's no signer, we connect the contract instance to the provider for the selected network.
208 if (contract.provider === null) {
209 contract = contract.connect(hre.ethers.provider);
210 }
211 return contract;
212}
213exports.getContractAtFromArtifact = getContractAtFromArtifact;
214// This helper adds a `gas` field to the ABI function elements if the network
215// is set up to use a fixed amount of gas.
216// This is done so that ethers doesn't automatically estimate gas limits on
217// every call.
218function addGasToAbiMethodsIfNecessary(networkConfig, abi) {
219 const { BigNumber } = require("ethers");
220 if (networkConfig.gas === "auto" || networkConfig.gas === undefined) {
221 return abi;
222 }
223 // ethers adds 21000 to whatever the abi `gas` field has. This may lead to
224 // OOG errors, as people may set the default gas to the same value as the
225 // block gas limit, especially on Hardhat Network.
226 // To avoid this, we substract 21000.
227 // HOTFIX: We substract 1M for now. See: https://github.com/ethers-io/ethers.js/issues/1058#issuecomment-703175279
228 const gasLimit = BigNumber.from(networkConfig.gas).sub(1000000).toHexString();
229 const modifiedAbi = [];
230 for (const abiElement of abi) {
231 if (abiElement.type !== "function") {
232 modifiedAbi.push(abiElement);
233 continue;
234 }
235 modifiedAbi.push({
236 ...abiElement,
237 gas: gasLimit,
238 });
239 }
240 return modifiedAbi;
241}
242function linkBytecode(artifact, libraries) {
243 let bytecode = artifact.bytecode;
244 // TODO: measure performance impact
245 for (const { sourceName, libraryName, address } of libraries) {
246 const linkReferences = artifact.linkReferences[sourceName][libraryName];
247 for (const { start, length } of linkReferences) {
248 bytecode =
249 bytecode.substr(0, 2 + start * 2) +
250 address.substr(2) +
251 bytecode.substr(2 + (start + length) * 2);
252 }
253 }
254 return bytecode;
255}
256//# sourceMappingURL=helpers.js.map
\No newline at end of file