UNPKG

@solarity/hardhat-migrate

Version:
226 lines 12.4 kB
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); var _, done = false; for (var i = decorators.length - 1; i >= 0; i--) { var context = {}; for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; for (var p in contextIn.access) context.access[p] = contextIn.access[p]; context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); if (kind === "accessor") { if (result === void 0) continue; if (result === null || typeof result !== "object") throw new TypeError("Object expected"); if (_ = accept(result.get)) descriptor.get = _; if (_ = accept(result.set)) descriptor.set = _; if (_ = accept(result.init)) initializers.unshift(_); } else if (_ = accept(result)) { if (kind === "field") initializers.unshift(_); else descriptor[key] = _; } } if (target) Object.defineProperty(target, contextIn.name, descriptor); done = true; }; var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) { var useValue = arguments.length > 2; for (var i = 0; i < initializers.length; i++) { value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); } return useValue ? value : void 0; }; import { Interface, isAddress, resolveAddress } from "ethers"; import { MinimalContract } from "./MinimalContract.js"; import { MigrateError } from "../utils/index.js"; import { CatchClassError } from "../utils/index.js"; import { Reporter } from "../tools/reporters/Reporter.js"; import { ArtifactProcessor } from "../tools/storage/ArtifactProcessor.js"; import { TransactionProcessor } from "../tools/storage/TransactionProcessor.js"; let LinkerHelper = (() => { let _classDecorators = [CatchClassError]; let _classDescriptor; let _classExtraInitializers = []; let _classThis; var LinkerHelper = class { static { _classThis = this; } static { const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0; __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers); LinkerHelper = _classThis = _classDescriptor.value; if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); __runInitializers(_classThis, _classExtraInitializers); } constructor() { } isBytecodeNeedsLinking(bytecode) { return bytecode.indexOf("__") !== -1; } async tryLinkBytecode(contractName, bytecode, libraries) { const artifact = this._mustGetContractArtifact(contractName, bytecode); const neededLibraries = this._cleanNeededLibraries(bytecode, artifact, artifact.neededLibraries); let linksToApply = new Map(); for (const [linkedLibraryName, linkedLibraryAddress] of Object.entries(libraries)) { const neededLibrary = this._mustGetNeededLibrary(neededLibraries, linkedLibraryName, linksToApply); const neededLibraryFQN = `${neededLibrary.sourceName}:${neededLibrary.libName}`; linksToApply.set(neededLibraryFQN, { sourceName: neededLibrary.sourceName, libraryName: neededLibrary.libName, address: await resolveAddress(linkedLibraryAddress), }); } if (linksToApply.size < neededLibraries.length) { const separatelyDeployedLibraries = await this._findMissingLibraries(neededLibraries.filter((lib) => !linksToApply.has(`${lib.sourceName}:${lib.libName}`))); linksToApply = new Map([...linksToApply.entries(), ...separatelyDeployedLibraries.entries()]); this._validateLibrariesToLink(linksToApply, neededLibraries); } return this._linkBytecode(bytecode, artifact, [...linksToApply.values()]); } _mustGetNeededLibrary(neededLibraries, libraryName, linksToApply) { const matchingNeededLibraries = neededLibraries.filter((lib) => lib.libName === libraryName || `${lib.sourceName}:${lib.libName}` === libraryName); return this._validateMatchedNeededLibraries(neededLibraries, matchingNeededLibraries, linksToApply); } _validateMatchedNeededLibraries(neededLibraries, matchingNeededLibraries, linksToApply) { if (matchingNeededLibraries.length === 0) { if (neededLibraries.length > 0) { const libraryFQNames = neededLibraries .map((lib) => `${lib.sourceName}:${lib.libName}`) .map((x) => `* ${x}`) .join("\n"); throw new MigrateError(`The libraries needed are:\n${libraryFQNames}`); } else { throw new MigrateError("This contract doesn't need linking any libraries."); } } if (matchingNeededLibraries.length > 1) { const matchingNeededLibrariesFQNs = matchingNeededLibraries .map(({ sourceName, libName }) => `${sourceName}:${libName}`) .map((x) => `* ${x}`) .join("\n"); throw new MigrateError(`The library name is ambiguous.\nIt may resolve to one of the following libraries:\n${matchingNeededLibrariesFQNs}\n\nTo fix this, choose one of these fully qualified library names and replace where appropriate.`); } const neededLibrary = matchingNeededLibraries[0]; const neededLibraryFQN = `${neededLibrary.sourceName}:${neededLibrary.libName}`; if (linksToApply.has(neededLibraryFQN)) { throw new MigrateError(`The library names ${neededLibrary.libName} and ${neededLibraryFQN} refer to the same library and were given as two separate library links.\nRemove one of them and review your library links before proceeding.`); } return neededLibrary; } async _findMissingLibraries(missingLibraries) { const missingLibrariesMap = new Map(); for (const missingLibrary of missingLibraries) { const lib = `${missingLibrary.sourceName}:${missingLibrary.libName}`; const address = await this._getOrDeployLibrary(lib); if (isAddress(address)) { missingLibrariesMap.set(lib, { sourceName: missingLibrary.sourceName, libraryName: missingLibrary.libName, address: address, }); } } return missingLibrariesMap; } _validateLibrariesToLink(linksToApply, neededLibraries) { if (linksToApply.size < neededLibraries.length) { const missingLibraries = neededLibraries .map((lib) => `${lib.sourceName}:${lib.libName}`) .filter((libFQName) => !linksToApply.has(libFQName)) .map((x) => `* ${x}`) .join("\n"); throw new MigrateError(`The contract is missing links for the following libraries:\n${missingLibraries}`); } } _cleanNeededLibraries(bytecode, artifact, libraries) { const actuallyNeededLibs = new Map(); for (const { sourceName, libName } of libraries) { const linkReferences = artifact.linkReferences[sourceName][libName]; for (const { start, length } of linkReferences) { if (!this._isLinkedLibrary(bytecode, start, length)) { actuallyNeededLibs.set(`${sourceName}:${libName}`, { sourceName, libName }); } } } return [...actuallyNeededLibs.values()]; } /** * The address of the linked library can be extracted like this: bytecode.slice(prefixLength + 2, suffixStart + 2) */ _isLinkedLibrary(bytecode, start, length) { const prefixLength = start * 2; const prefix = bytecode.slice(prefixLength + 2, prefixLength + 5); const suffixStart = (start + length) * 2; const suffix = bytecode.slice(suffixStart - 1, suffixStart + 2); return `${prefix}${suffix}` !== "__$$__"; } _linkBytecode(bytecode, artifact, libraries) { for (const { sourceName, libraryName, address } of libraries) { const linkReferences = artifact.linkReferences[sourceName][libraryName]; for (const { start, length } of linkReferences) { const prefixLength = 2 + start * 2; const prefix = bytecode.slice(0, prefixLength); const suffixStart = 2 + (start + length) * 2; const suffix = bytecode.slice(suffixStart); bytecode = prefix + address.slice(2) + suffix; } } return bytecode; } async _getOrDeployLibrary(libraryName) { try { return (await TransactionProcessor?.tryRestoreContractAddressByName(libraryName)); } catch { const artifact = this._mustGetLibraryArtifact(libraryName); // https://github.com/ethers-io/ethers.js/issues/2431 // https://github.com/ethers-io/ethers.js/issues/1126 const core = new MinimalContract(artifact.bytecode, new Interface(artifact.abi), libraryName); Reporter.notifyDeploymentOfMissingLibrary(libraryName); return core.deploy(); } } _mustGetContractArtifact(contractName, contractBytecode) { const artifact = this._getContractFromStorage(contractName, contractBytecode); if (!artifact) { throw new MigrateError(`Contract artifact of ${contractName} not found. Linking cannot be performed.`); } return artifact; } _mustGetLibraryArtifact(libraryName) { const artifact = this._getContractFromStorage(libraryName); if (!artifact) { throw new MigrateError(`Library artifact of ${libraryName} not found. Linking cannot be performed.`); } return artifact; } _getContractFromStorage(contractName, contractBytecode) { try { return ArtifactProcessor.tryGetArtifactByName(contractName); } catch { /* ignore */ } try { const txData = TransactionProcessor?.tryRestoreSavedDeployedTxByContractName(contractName); return ArtifactProcessor.tryGetArtifactByName(txData.metadata.fullyQualifiedContractName); } catch { /* ignore */ } if (contractBytecode) { try { return ArtifactProcessor.tryGetArtifactByBytecode(contractBytecode); } catch { /* ignore */ } } return null; } }; return LinkerHelper = _classThis; })(); export let Linker = new LinkerHelper(); //# sourceMappingURL=Linker.js.map