UNPKG

@openzeppelin/upgrades

Version:

JavaScript library for the OpenZeppelin smart contract platform

213 lines 11.9 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const lodash_1 = require("lodash"); const Proxy_1 = __importDefault(require("../proxy/Proxy")); const Logger_1 = require("../utils/Logger"); const Package_1 = __importDefault(require("../application/Package")); const Transactions_1 = __importDefault(require("../utils/Transactions")); const Addresses_1 = require("../utils/Addresses"); const Bytecode_1 = require("../utils/Bytecode"); const Semver_1 = require("../utils/Semver"); const ABIs_1 = require("../utils/ABIs"); const ProxyFactory_1 = __importDefault(require("../proxy/ProxyFactory")); class BaseSimpleProject { constructor(name, proxyFactory, txParams = {}) { this.txParams = txParams; this.name = name; this.implementations = {}; this.dependencies = {}; this.proxyFactory = proxyFactory; } setImplementation(contract, contractName) { return __awaiter(this, void 0, void 0, function* () { Logger_1.Loggy.onVerbose(__filename, 'setImplementation', `set-implementation-for-${contract.schema.contractName}`, `Deploying logic contract for ${contract.schema.contractName}`); if (!contractName) contractName = contract.schema.contractName; const implementation = yield Transactions_1.default.deployContract(contract, [], this.txParams); yield this.registerImplementation(contractName, { address: implementation.address, bytecodeHash: Bytecode_1.bytecodeDigest(contract.schema.linkedDeployedBytecode), }); return implementation; }); } unsetImplementation(contractName) { delete this.implementations[contractName]; } registerImplementation(contractName, { address, bytecodeHash }) { return __awaiter(this, void 0, void 0, function* () { this.implementations[contractName] = { address, bytecodeHash }; }); } // TS-TODO: review return type // TS-TODO: review parameter type (it's packageName?+(contractName|contract)) getImplementation({ packageName, contractName, contract, }) { return __awaiter(this, void 0, void 0, function* () { contractName = contractName || contract.schema.contractName; return !packageName || packageName === this.name ? this.implementations[contractName] && this.implementations[contractName].address : this._getDependencyImplementation(packageName, contractName); }); } getDependencyPackage(name) { return __awaiter(this, void 0, void 0, function* () { return Package_1.default.fetch(this.dependencies[name].package); }); } getDependencyVersion(name) { return Semver_1.toSemanticVersion(this.dependencies[name].version); } hasDependency(name) { return !!this.dependencies[name]; } setDependency(name, packageAddress, version) { // TODO: Validate that the package exists and has thatversion this.dependencies[name] = { package: packageAddress, version }; } unsetDependency(name) { delete this.dependencies[name]; } createProxy(contract, { packageName, contractName, initMethod, initArgs, redeployIfChanged, admin } = {}) { return __awaiter(this, void 0, void 0, function* () { if (!lodash_1.isEmpty(initArgs) && !initMethod) initMethod = 'initialize'; const implementationAddress = yield this._getOrDeployImplementation(contract, packageName, contractName, redeployIfChanged); const initCallData = this._getAndLogInitCallData(contract, initMethod, initArgs, implementationAddress, 'Creating'); const proxyAdmin = admin || (yield this.getAdminAddress()); const proxy = yield Proxy_1.default.deploy(implementationAddress, proxyAdmin, initCallData, this.txParams); Logger_1.Loggy.succeed(`create-proxy`, `Instance created at ${proxy.address}`); return contract.at(proxy.address); }); } createProxyWithSalt(contract, salt, signature, { packageName, contractName, initMethod, initArgs, redeployIfChanged, admin } = {}) { return __awaiter(this, void 0, void 0, function* () { if (!lodash_1.isEmpty(initArgs) && !initMethod) initMethod = 'initialize'; const implementationAddress = yield this._getOrDeployImplementation(contract, packageName, contractName, redeployIfChanged); const initCallData = this._getAndLogInitCallData(contract, initMethod, initArgs, implementationAddress, 'Creating'); const proxyFactory = yield this.ensureProxyFactory(); const adminAddress = admin || (yield this.getAdminAddress()); const proxy = yield proxyFactory.createProxy(salt, implementationAddress, adminAddress, initCallData, signature); Logger_1.Loggy.succeed(`create-proxy`, `Instance created at ${proxy.address}`); return contract.at(proxy.address); }); } createMinimalProxy(contract, { packageName, contractName, initMethod, initArgs, redeployIfChanged } = {}) { return __awaiter(this, void 0, void 0, function* () { if (!lodash_1.isEmpty(initArgs) && !initMethod) initMethod = 'initialize'; const implementationAddress = yield this._getOrDeployImplementation(contract, packageName, contractName, redeployIfChanged); const initCallData = this._getAndLogInitCallData(contract, initMethod, initArgs, implementationAddress, 'Creating'); const proxyFactory = yield this.ensureProxyFactory(); const proxy = yield proxyFactory.createMinimalProxy(implementationAddress, initCallData); Logger_1.Loggy.succeed(`create-proxy`, `Instance created at ${proxy.address}`); return contract.at(proxy.address); }); } // REFACTOR: De-duplicate from AppProject getProxyDeploymentAddress(salt, sender) { return __awaiter(this, void 0, void 0, function* () { const proxyFactory = yield this.ensureProxyFactory(); return proxyFactory.getDeploymentAddress(salt, sender); }); } // REFACTOR: De-duplicate from AppProject and test getProxyDeploymentSigner(contract, salt, signature, { packageName, contractName, initMethod, initArgs, admin } = {}) { return __awaiter(this, void 0, void 0, function* () { const proxyFactory = yield this.ensureProxyFactory(); const implementationAddress = yield this.getImplementation({ packageName, contractName, contract, }); if (!implementationAddress) throw new Error(`Contract ${contractName || contract.schema.contractName} was not found or is not deployed in the current network.`); const adminAddress = admin || (yield this.getAdminAddress()); const initData = initMethod ? ABIs_1.buildCallData(contract, initMethod, initArgs).callData : null; return proxyFactory.getSigner(salt, implementationAddress, adminAddress, initData, signature); }); } ensureProxyFactory() { return __awaiter(this, void 0, void 0, function* () { if (!this.proxyFactory) { this.proxyFactory = yield ProxyFactory_1.default.deploy(this.txParams); } return this.proxyFactory; }); } _getOrDeployOwnImplementation(contract, contractName, redeployIfChanged) { return __awaiter(this, void 0, void 0, function* () { const existing = this.implementations[contractName]; const contractChanged = existing && existing.bytecodeHash !== Bytecode_1.bytecodeDigest(contract.schema.linkedDeployedBytecode); const shouldRedeploy = !existing || (redeployIfChanged && contractChanged); if (!shouldRedeploy) return existing.address; const newInstance = yield this.setImplementation(contract, contractName); return newInstance.address; }); } _getDependencyImplementation(packageName, contractName) { return __awaiter(this, void 0, void 0, function* () { if (!this.hasDependency(packageName)) return null; const { package: packageAddress, version } = this.dependencies[packageName]; const thepackage = yield Package_1.default.fetch(packageAddress, this.txParams); return thepackage.getImplementation(version, contractName); }); } _setUpgradeParams(proxyAddress, contract, { packageName, contractName, initMethod: initMethodName, initArgs, redeployIfChanged } = {}) { return __awaiter(this, void 0, void 0, function* () { const implementationAddress = yield this._getOrDeployImplementation(contract, packageName, contractName, redeployIfChanged); const initCallData = this._getAndLogInitCallData(contract, initMethodName, initArgs, implementationAddress, 'Upgrading', proxyAddress); return { initCallData, implementationAddress, pAddress: Addresses_1.toAddress(proxyAddress), }; }); } _getOrDeployImplementation(contract, packageName, contractName, redeployIfChanged) { return __awaiter(this, void 0, void 0, function* () { if (!contractName) contractName = contract.schema.contractName; const implementation = !packageName || packageName === this.name ? yield this._getOrDeployOwnImplementation(contract, contractName, redeployIfChanged) : yield this._getDependencyImplementation(packageName, contractName); if (!implementation) throw Error(`Could not retrieve or deploy contract ${packageName}/${contractName}`); return implementation; }); } _getAndLogInitCallData(contract, initMethodName, initArgs, implementationAddress, actionLabel, proxyAddress) { const logReference = actionLabel === 'Creating' ? 'create-proxy' : `upgrade-proxy-${proxyAddress}`; const logMessage = actionLabel === 'Creating' ? `Creating instance for contract at ${implementationAddress}` : `Upgrading instance at ${proxyAddress}`; if (initMethodName) { const { method: initMethod, callData } = ABIs_1.buildCallData(contract, initMethodName, initArgs); if (actionLabel) Logger_1.Loggy.spin(__filename, '_getAndLogInitCallData', logReference, `${logMessage} and calling ${ABIs_1.callDescription(initMethod, initArgs)}`); return callData; } else { if (actionLabel) Logger_1.Loggy.spin(__filename, '_getAndLogInitCallData', logReference, logMessage); return null; } } } exports.default = BaseSimpleProject; //# sourceMappingURL=BaseSimpleProject.js.map