diff --git a/migrations/scripts/1_deployer.js b/migrations/scripts/1_deployer.js index 66bc77d3..a3382c96 100644 --- a/migrations/scripts/1_deployer.js +++ b/migrations/scripts/1_deployer.js @@ -4,27 +4,27 @@ const utils = require("../../scripts/utils") const WitnetDeployer = artifacts.require("WitnetDeployer") module.exports = async function (deployer, network, [, from,, master]) { - const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" - const ecosystem = utils.getRealmNetworkFromArgs()[0] - network = network.split("-")[0] + const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" + const ecosystem = utils.getRealmNetworkFromArgs()[0] + network = network.split("-")[0] - if (!addresses[ecosystem]) addresses[ecosystem] = {} - if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} + if (!addresses[ecosystem]) addresses[ecosystem] = {} + if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} - let factory - if (utils.isNullAddress(addresses[ecosystem][network]?.WitnetDeployer)) { - await deployer.deploy(WitnetDeployer, { from: master }) - factory = await WitnetDeployer.deployed() - addresses[ecosystem][network].WitnetDeployer = factory.address - } else { - factory = await WitnetDeployer.at(addresses[ecosystem][network].WitnetDeployer) - WitnetDeployer.address = factory.address - utils.traceHeader("Skipped 'WitnetDeployer'") - console.info(" > Contract address:", factory.address) - console.info() - } + let factory + if (utils.isNullAddress(addresses[ecosystem][network]?.WitnetDeployer)) { + await deployer.deploy(WitnetDeployer, { from: master }) + factory = await WitnetDeployer.deployed() + addresses[ecosystem][network].WitnetDeployer = factory.address + } else { + factory = await WitnetDeployer.at(addresses[ecosystem][network].WitnetDeployer) + WitnetDeployer.address = factory.address + utils.traceHeader("Skipped 'WitnetDeployer'") + console.info(" > Contract address:", factory.address) + console.info() + } - if (!isDryRun) { - utils.saveAddresses(addresses) - } + if (!isDryRun) { + utils.saveAddresses(addresses) + } } diff --git a/migrations/scripts/2_libs.js b/migrations/scripts/2_libs.js index edaf9599..451663e5 100644 --- a/migrations/scripts/2_libs.js +++ b/migrations/scripts/2_libs.js @@ -6,53 +6,52 @@ const utils = require("../../scripts/utils") const WitnetDeployer = artifacts.require("WitnetDeployer") module.exports = async function (_, network, [, from]) { - const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" - const ecosystem = utils.getRealmNetworkFromArgs()[0] - network = network.split("-")[0] + const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" + const ecosystem = utils.getRealmNetworkFromArgs()[0] + network = network.split("-")[0] - const addresses = require("../witnet.addresses") - if (!addresses[ecosystem]) addresses[ecosystem] = {} - if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} + const addresses = require("../witnet.addresses") + if (!addresses[ecosystem]) addresses[ecosystem] = {} + if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} - const targets = merge( - settings.artifacts.default, - settings.artifacts[ecosystem], - settings.artifacts[network] - ) - const libs = [ - targets.WitnetErrorsLib, - targets.WitnetEncodingLib, - targets.WitnetPriceFeedsLib, - ] + const targets = merge( + settings.artifacts.default, + settings.artifacts[ecosystem], + settings.artifacts[network] + ) + const libs = [ + targets.WitnetErrorsLib, + targets.WitnetEncodingLib, + targets.WitnetPriceFeedsLib, + ] - const deployer = await WitnetDeployer.deployed() - for (index in libs) { - const key = libs[index] - const artifact = artifacts.require(key) - if (utils.isNullAddress(addresses[ecosystem][network][key])) { - utils.traceHeader(`Deploying '${key}'...`) - const libInitCode = artifact.toJSON().bytecode - const libAddr = await deployer.determineAddr.call(libInitCode, "0x0", { from }) - console.info(" ", "> account: ", from) - console.info(" ", "> balance: ", web3.utils.fromWei(await web3.eth.getBalance(from), 'ether'), "ETH") - const tx = await deployer.deploy(libInitCode, "0x0", { from }) - utils.traceTx(tx) - if ((await web3.eth.getCode(libAddr)).length > 3) { - addresses[ecosystem][network][key] = libAddr - } else { - console.info(`Error: Library was not deployed on expected address: ${libAddr}`) - process.exit(1) - } - } else { - utils.traceHeader(`Skipped '${key}'`) - } - artifact.address = addresses[ecosystem][network][key] - console.info(" ", "> library address: ", artifact.address) - console.info(" ", "> library codehash: ", web3.utils.soliditySha3(await web3.eth.getCode(artifact.address))) - console.info() - if (!isDryRun) { - utils.saveAddresses(addresses) - } + const deployer = await WitnetDeployer.deployed() + for (index in libs) { + const key = libs[index] + const artifact = artifacts.require(key) + if (utils.isNullAddress(addresses[ecosystem][network][key])) { + utils.traceHeader(`Deploying '${key}'...`) + const libInitCode = artifact.toJSON().bytecode + const libAddr = await deployer.determineAddr.call(libInitCode, "0x0", { from }) + console.info(" ", "> account: ", from) + console.info(" ", "> balance: ", web3.utils.fromWei(await web3.eth.getBalance(from), "ether"), "ETH") + const tx = await deployer.deploy(libInitCode, "0x0", { from }) + utils.traceTx(tx) + if ((await web3.eth.getCode(libAddr)).length > 3) { + addresses[ecosystem][network][key] = libAddr + } else { + console.info(`Error: Library was not deployed on expected address: ${libAddr}`) + process.exit(1) + } + } else { + utils.traceHeader(`Skipped '${key}'`) } - + artifact.address = addresses[ecosystem][network][key] + console.info(" ", "> library address: ", artifact.address) + console.info(" ", "> library codehash: ", web3.utils.soliditySha3(await web3.eth.getCode(artifact.address))) + console.info() + if (!isDryRun) { + utils.saveAddresses(addresses) + } + } } diff --git a/migrations/scripts/3_core.js b/migrations/scripts/3_core.js index 887ae59a..cf999f89 100644 --- a/migrations/scripts/3_core.js +++ b/migrations/scripts/3_core.js @@ -5,142 +5,160 @@ const addresses = require("../witnet.addresses") const settings = require("../witnet.settings") const utils = require("../../scripts/utils") const version = `${ - require("../../package").version - }-${ - require("child_process").execSync("git rev-parse HEAD").toString().trim().substring(0, 7) - }` + require("../../package").version +}-${ + require("child_process").execSync("git rev-parse HEAD").toString().trim().substring(0, 7) +}` const WitnetDeployer = artifacts.require("WitnetDeployer") module.exports = async function (_, network, [, from]) { - const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" - const ecosystem = utils.getRealmNetworkFromArgs()[0] - network = network.split("-")[0] + const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" + const ecosystem = utils.getRealmNetworkFromArgs()[0] + network = network.split("-")[0] - if (!addresses[ecosystem]) addresses[ecosystem] = {} - if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} + if (!addresses[ecosystem]) addresses[ecosystem] = {} + if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} - const specs = merge( - settings.specs.default, - settings.specs[ecosystem], - settings.specs[network], - ) - const targets = merge( - settings.artifacts.default, - settings.artifacts[ecosystem], - settings.artifacts[network] - ) + const specs = merge( + settings.specs.default, + settings.specs[ecosystem], + settings.specs[network], + ) + const targets = merge( + settings.artifacts.default, + settings.artifacts[ecosystem], + settings.artifacts[network] + ) - // Deploy/upgrade WitnetBytecodes target implementation, if required - { - await deploy({ - from, ecosystem, network, targets, - key: targets.WitnetBytecodes, - libs: specs.WitnetBytecodes.libs, - immutables: specs.WitnetBytecodes.immutables, - intrinsics: { types: [ 'bool', 'bytes32' ], values: [ - /* _upgradable */ true, - /* _versionTag */ utils.fromAscii(version) - ]}, - }); - if (!isDryRun) { - utils.saveAddresses(addresses); - } + // Deploy/upgrade WitnetBytecodes target implementation, if required + { + await deploy({ + from, + ecosystem, + network, + targets, + key: targets.WitnetBytecodes, + libs: specs.WitnetBytecodes.libs, + immutables: specs.WitnetBytecodes.immutables, + intrinsics: { + types: ["bool", "bytes32"], + values: [ + /* _upgradable */ true, + /* _versionTag */ utils.fromAscii(version), + ], + }, + }) + if (!isDryRun) { + utils.saveAddresses(addresses) } - // Deploy/upgrade WitnetRequestFactory target implementation, if required - { - await deploy({ - from, ecosystem, network, targets, - key: targets.WitnetRequestFactory, - libs: specs.WitnetRequestFactory.libs, - immutables: specs.WitnetRequestFactory.immutables, - intrinsics: { types: [ 'address', 'address', 'bool', 'bytes32' ], values: [ - /* _witnet */ await determineProxyAddr(from, specs.WitnetRequestBoard?.vanity || 3), - /* _registry */ await determineProxyAddr(from, specs.WitnetBytecodes?.vanity || 1), - /* _upgradable */ true, - /* _versionTag */ utils.fromAscii(version), - ]}, - }); - if (!isDryRun) { - utils.saveAddresses(addresses); - } + } + // Deploy/upgrade WitnetRequestFactory target implementation, if required + { + await deploy({ + from, + ecosystem, + network, + targets, + key: targets.WitnetRequestFactory, + libs: specs.WitnetRequestFactory.libs, + immutables: specs.WitnetRequestFactory.immutables, + intrinsics: { + types: ["address", "address", "bool", "bytes32"], + values: [ + /* _witnet */ await determineProxyAddr(from, specs.WitnetRequestBoard?.vanity || 3), + /* _registry */ await determineProxyAddr(from, specs.WitnetBytecodes?.vanity || 1), + /* _upgradable */ true, + /* _versionTag */ utils.fromAscii(version), + ], + }, + }) + if (!isDryRun) { + utils.saveAddresses(addresses) } - // Deploy/upgrade WitnetRequestBoard target implementation, if required - { - await deploy({ - from, ecosystem, network, targets, - key: targets.WitnetRequestBoard, - libs: specs.WitnetRequestBoard.libs, - immutables: specs.WitnetRequestBoard.immutables, - intrinsics: { types: [ 'address', 'address', 'bool', 'bytes32' ], values: [ - /* _factory */ await determineProxyAddr(from, specs.WitnetRequestFactory?.vanity || 2), - /* _registry */ await determineProxyAddr(from, specs.WitnetBytecodes?.vanity || 1), - /* _upgradable */ true, - /* _versionTag */ utils.fromAscii(version), - ]}, - }); - if (!isDryRun) { - utils.saveAddresses(addresses); - } + } + // Deploy/upgrade WitnetRequestBoard target implementation, if required + { + await deploy({ + from, + ecosystem, + network, + targets, + key: targets.WitnetRequestBoard, + libs: specs.WitnetRequestBoard.libs, + immutables: specs.WitnetRequestBoard.immutables, + intrinsics: { + types: ["address", "address", "bool", "bytes32"], + values: [ + /* _factory */ await determineProxyAddr(from, specs.WitnetRequestFactory?.vanity || 2), + /* _registry */ await determineProxyAddr(from, specs.WitnetBytecodes?.vanity || 1), + /* _upgradable */ true, + /* _versionTag */ utils.fromAscii(version), + ], + }, + }) + if (!isDryRun) { + utils.saveAddresses(addresses) } + } } -async function deploy(specs) { - const { from, ecosystem, network, key, libs, intrinsics, immutables, targets } = specs; - const contract = artifacts.require(key) - if (utils.isNullAddress(addresses[ecosystem][network][key])) { - utils.traceHeader(`Deploying '${key}'...`) - console.info(" ", "> account: ", from) - console.info(" ", "> balance: ", web3.utils.fromWei(await web3.eth.getBalance(from), 'ether'), "ETH") - const deployer = await WitnetDeployer.deployed() - let { types, values } = intrinsics - if (immutables?.types) types = [ ...types, ...immutables.types ] - if (immutables?.values) values = [ ...values, ...immutables.values ] - const constructorArgs = web3.eth.abi.encodeParameters(types, values) - if (constructorArgs.length > 2) { - console.info(" ", "> constructor types:", types) - console.info(" ", "> constructor args: ", constructorArgs.slice(2)) - } - const coreBytecode = link(contract.toJSON().bytecode, libs, targets) - if (coreBytecode.indexOf("__") > -1) { - console.info(bytecode) - console.info("Error: Cannot deploy due to some missing libs") - process.exit(1) - } - const coreInitCode = coreBytecode + constructorArgs.slice(2) - const coreAddr = await deployer.determineAddr.call(coreInitCode, "0x0", { from }) - const tx = await deployer.deploy(coreInitCode, "0x0", { from }) - utils.traceTx(tx) - if ((await web3.eth.getCode(coreAddr)).length > 3) { - addresses[ecosystem][network][key] = coreAddr - } else { - console.info(`Error: Contract was not deployed on expected address: ${coreAddr}`) - process.exit(1) - } +async function deploy (specs) { + const { from, ecosystem, network, key, libs, intrinsics, immutables, targets } = specs + const contract = artifacts.require(key) + if (utils.isNullAddress(addresses[ecosystem][network][key])) { + utils.traceHeader(`Deploying '${key}'...`) + console.info(" ", "> account: ", from) + console.info(" ", "> balance: ", web3.utils.fromWei(await web3.eth.getBalance(from), "ether"), "ETH") + const deployer = await WitnetDeployer.deployed() + let { types, values } = intrinsics + if (immutables?.types) types = [...types, ...immutables.types] + if (immutables?.values) values = [...values, ...immutables.values] + const constructorArgs = web3.eth.abi.encodeParameters(types, values) + if (constructorArgs.length > 2) { + console.info(" ", "> constructor types:", types) + console.info(" ", "> constructor args: ", constructorArgs.slice(2)) + } + const coreBytecode = link(contract.toJSON().bytecode, libs, targets) + if (coreBytecode.indexOf("__") > -1) { + console.info(bytecode) + console.info("Error: Cannot deploy due to some missing libs") + process.exit(1) + } + const coreInitCode = coreBytecode + constructorArgs.slice(2) + const coreAddr = await deployer.determineAddr.call(coreInitCode, "0x0", { from }) + const tx = await deployer.deploy(coreInitCode, "0x0", { from }) + utils.traceTx(tx) + if ((await web3.eth.getCode(coreAddr)).length > 3) { + addresses[ecosystem][network][key] = coreAddr } else { - utils.traceHeader(`Skipped '${key}'`) + console.info(`Error: Contract was not deployed on expected address: ${coreAddr}`) + process.exit(1) } - contract.address = addresses[ecosystem][network][key] - console.info(" ", "> contract address: ", contract.address) - console.info(" ", "> contract codehash:", web3.utils.soliditySha3(await web3.eth.getCode(contract.address))) - console.info() - return contract + } else { + utils.traceHeader(`Skipped '${key}'`) + } + contract.address = addresses[ecosystem][network][key] + console.info(" ", "> contract address: ", contract.address) + console.info(" ", "> contract codehash:", web3.utils.soliditySha3(await web3.eth.getCode(contract.address))) + console.info() + return contract } -async function determineProxyAddr(from, nonce) { - const salt = nonce ? "0x" + ethUtils.setLengthLeft(ethUtils.toBuffer(nonce), 32).toString("hex") : "0x0" - const deployer = await WitnetDeployer.deployed() - return await deployer.determineProxyAddr.call(salt, { from }) +async function determineProxyAddr (from, nonce) { + const salt = nonce ? "0x" + ethUtils.setLengthLeft(ethUtils.toBuffer(nonce), 32).toString("hex") : "0x0" + const deployer = await WitnetDeployer.deployed() + return await deployer.determineProxyAddr.call(salt, { from }) } -function link(bytecode, libs, targets) { - if (libs && Array.isArray(libs) && libs.length > 0) { - for (index in libs) { - const key = targets[libs[index]] - const lib = artifacts.require(key) - bytecode = bytecode.replaceAll(`__${key}${"_".repeat(38-key.length)}`, lib.address.slice(2)) - console.info(" ", `> linked library: ${key} => ${lib.address}`) - } +function link (bytecode, libs, targets) { + if (libs && Array.isArray(libs) && libs.length > 0) { + for (index in libs) { + const key = targets[libs[index]] + const lib = artifacts.require(key) + bytecode = bytecode.replaceAll(`__${key}${"_".repeat(38 - key.length)}`, lib.address.slice(2)) + console.info(" ", `> linked library: ${key} => ${lib.address}`) } - return bytecode -} \ No newline at end of file + } + return bytecode +} diff --git a/migrations/scripts/4_proxies.js b/migrations/scripts/4_proxies.js index e5fbcf5d..08f104d1 100644 --- a/migrations/scripts/4_proxies.js +++ b/migrations/scripts/4_proxies.js @@ -9,137 +9,141 @@ const WitnetDeployer = artifacts.require("WitnetDeployer") const WitnetProxy = artifacts.require("WitnetProxy") module.exports = async function (_, network, [, from, reporter]) { - const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" - const ecosystem = utils.getRealmNetworkFromArgs()[0] - network = network.split("-")[0] + const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" + const ecosystem = utils.getRealmNetworkFromArgs()[0] + network = network.split("-")[0] - if (!addresses[ecosystem]) addresses[ecosystem] = {} - if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} + if (!addresses[ecosystem]) addresses[ecosystem] = {} + if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} - const targets = merge( - settings.artifacts.default, - settings.artifacts[ecosystem], - settings.artifacts[network] - ) - const specs = merge( - settings.specs.default, - settings.specs[ecosystem], - settings.specs[network], - ) - const singletons = [ - "WitnetBytecodes", - "WitnetRequestFactory", - "WitnetRequestBoard", - ] + const targets = merge( + settings.artifacts.default, + settings.artifacts[ecosystem], + settings.artifacts[network] + ) + const specs = merge( + settings.specs.default, + settings.specs[ecosystem], + settings.specs[network], + ) + const singletons = [ + "WitnetBytecodes", + "WitnetRequestFactory", + "WitnetRequestBoard", + ] - specs["WitnetRequestBoard"].mutables = merge({ - types: [ 'address[]', ], - values: [ [ reporter, ], ], - }, specs["WitnetRequestBoard"].mutables - ) + specs.WitnetRequestBoard.mutables = merge({ + types: ["address[]"], + values: [[reporter]], + }, specs.WitnetRequestBoard.mutables + ) - // Deploy/upgrade singleton proxies, if required - for (index in singletons) { - await deploy({ - from, ecosystem, network, specs, targets, - key: singletons[index], - }); - if (!isDryRun) { - utils.saveAddresses(addresses); - } + // Deploy/upgrade singleton proxies, if required + for (index in singletons) { + await deploy({ + from, + ecosystem, + network, + specs, + targets, + key: singletons[index], + }) + if (!isDryRun) { + utils.saveAddresses(addresses) } + } } -async function deploy(target) { - const { from, ecosystem, network, key, specs, targets } = target; - - const mutables = specs[key].mutables - const proxy = artifacts.require(key) - const proxy_salt = specs[key].vanity ? "0x" + ethUtils.setLengthLeft(ethUtils.toBuffer(specs[key].vanity), 32).toString("hex") : "0x0" - - if (utils.isNullAddress(addresses[ecosystem][network][key])) { - utils.traceHeader(`Deploying '${key}'...`) - console.info(" ", "> account: ", from) - console.info(" ", "> balance: ", web3.utils.fromWei(await web3.eth.getBalance(from), 'ether'), "ETH") - const deployer = await WitnetDeployer.deployed() - const impl = await artifacts.require(targets[key]).deployed() - const proxyAddr = await deployer.determineProxyAddr.call(proxy_salt, { from }) - if ((await web3.eth.getCode(proxyAddr)).length < 3) { - const initdata = mutables ? web3.eth.abi.encodeParameters(mutables.types, mutables.values) : "0x" - if (initdata.length > 2) { - console.info(" ", "> initialize types: ", mutables.types) - console.info(" ", "> initialize params:", mutables.values) - } - const tx = await deployer.proxify(proxy_salt, impl.address, initdata, { from }) - utils.traceTx(tx) - // save/overwrite exportable abi file - utils.saveJsonAbi(key, proxy.abi) - } else { - try { - const oldImplAddr = await getProxyImplementation(from, proxyAddr) - const oldImpl = await artifacts.require(targets[key]).at(oldImplAddr) - const oldClass = await oldImpl.class.call({ from }) - const newClass = await impl.class.call({ from }) - if (oldClass !== newClass) { - console.info(`Error: proxy address already taken (\"${oldClass}\" != \"${newClass}\")`) - process.exit(1) - } else { - console.info(" ", `> recovered proxy address on class \"${oldClass}\" ;-)`) - } - } catch (ex) { - console.info("Error: cannot check proxy recoverability:", ex) - } - } - if ((await web3.eth.getCode(proxyAddr)).length > 3) { - addresses[ecosystem][network][key] = proxyAddr +async function deploy (target) { + const { from, ecosystem, network, key, specs, targets } = target + + const mutables = specs[key].mutables + const proxy = artifacts.require(key) + const proxy_salt = specs[key].vanity ? "0x" + ethUtils.setLengthLeft(ethUtils.toBuffer(specs[key].vanity), 32).toString("hex") : "0x0" + + if (utils.isNullAddress(addresses[ecosystem][network][key])) { + utils.traceHeader(`Deploying '${key}'...`) + console.info(" ", "> account: ", from) + console.info(" ", "> balance: ", web3.utils.fromWei(await web3.eth.getBalance(from), "ether"), "ETH") + const deployer = await WitnetDeployer.deployed() + const impl = await artifacts.require(targets[key]).deployed() + const proxyAddr = await deployer.determineProxyAddr.call(proxy_salt, { from }) + if ((await web3.eth.getCode(proxyAddr)).length < 3) { + const initdata = mutables ? web3.eth.abi.encodeParameters(mutables.types, mutables.values) : "0x" + if (initdata.length > 2) { + console.info(" ", "> initialize types: ", mutables.types) + console.info(" ", "> initialize params:", mutables.values) + } + const tx = await deployer.proxify(proxy_salt, impl.address, initdata, { from }) + utils.traceTx(tx) + // save/overwrite exportable abi file + utils.saveJsonAbi(key, proxy.abi) + } else { + try { + const oldImplAddr = await getProxyImplementation(from, proxyAddr) + const oldImpl = await artifacts.require(targets[key]).at(oldImplAddr) + const oldClass = await oldImpl.class.call({ from }) + const newClass = await impl.class.call({ from }) + if (oldClass !== newClass) { + console.info(`Error: proxy address already taken (\"${oldClass}\" != \"${newClass}\")`) + process.exit(1) } else { - console.info(`Error: Contract was not deployed on expected address: ${proxyAddr}`) - process.exit(1) + console.info(" ", `> recovered proxy address on class \"${oldClass}\" ;-)`) } + } catch (ex) { + console.info("Error: cannot check proxy recoverability:", ex) + } + } + if ((await web3.eth.getCode(proxyAddr)).length > 3) { + addresses[ecosystem][network][key] = proxyAddr } else { - const oldAddr = await getProxyImplementation(from, addresses[ecosystem][network][key]) - const oldImpl = await artifacts.require(targets[key]).at(oldAddr) - const newImpl = await artifacts.require(targets[key]).deployed() - if (oldAddr !== newImpl.address) { - utils.traceHeader(`Upgrading '${key}'...`) - const oldVersion = await oldImpl.version.call({ from }) - const newVersion = await newImpl.version.call({ from }) - if( - process.argv.length >= 3 && process.argv[2].includes("--upgrade-all") || ["y", "yes"].includes( - (await utils.prompt(` > From v${oldVersion} to v${newVersion} ? [y / N]`)).toLowerCase().trim() - ) - ) { - const initdata = mutables ? web3.eth.abi.encodeParameters(mutables.types, mutables.values) : "0x" - if (initdata.length > 2) { - console.info(" ", "> initialize types: ", mutables.types) - console.info(" ", "> initialize params:", mutables.values) - } - const tx = await upgradeProxyTo(from, proxy, newImpl.address, initdata) - utils.traceTx(tx) - // save/overwrite exportable abi file - utils.saveJsonAbi(key, proxy.abi) - } - } else { - utils.traceHeader(`Skipped '${key}'`) + console.info(`Error: Contract was not deployed on expected address: ${proxyAddr}`) + process.exit(1) + } + } else { + const oldAddr = await getProxyImplementation(from, addresses[ecosystem][network][key]) + const oldImpl = await artifacts.require(targets[key]).at(oldAddr) + const newImpl = await artifacts.require(targets[key]).deployed() + if (oldAddr !== newImpl.address) { + utils.traceHeader(`Upgrading '${key}'...`) + const oldVersion = await oldImpl.version.call({ from }) + const newVersion = await newImpl.version.call({ from }) + if ( + process.argv.length >= 3 && process.argv[2].includes("--upgrade-all") || ["y", "yes"].includes( + (await utils.prompt(` > From v${oldVersion} to v${newVersion} ? [y / N]`)).toLowerCase().trim() + ) + ) { + const initdata = mutables ? web3.eth.abi.encodeParameters(mutables.types, mutables.values) : "0x" + if (initdata.length > 2) { + console.info(" ", "> initialize types: ", mutables.types) + console.info(" ", "> initialize params:", mutables.values) } + const tx = await upgradeProxyTo(from, proxy, newImpl.address, initdata) + utils.traceTx(tx) + // save/overwrite exportable abi file + utils.saveJsonAbi(key, proxy.abi) + } + } else { + utils.traceHeader(`Skipped '${key}'`) } - proxy.address = addresses[ecosystem][network][key] - const impl = await artifacts.require(targets[key]).at(proxy.address) - console.info(" ", "> proxy address: ", impl.address) - console.info(" ", "> proxy codehash: ", web3.utils.soliditySha3(await web3.eth.getCode(impl.address))) - console.info(" ", "> proxy operator: ", await impl.owner.call()) - console.info(" ", "> impl. address: ", await getProxyImplementation(from, proxy.address)) - console.info(" ", "> impl. version: ", await impl.version.call()) - console.info() - return proxy + } + proxy.address = addresses[ecosystem][network][key] + const impl = await artifacts.require(targets[key]).at(proxy.address) + console.info(" ", "> proxy address: ", impl.address) + console.info(" ", "> proxy codehash: ", web3.utils.soliditySha3(await web3.eth.getCode(impl.address))) + console.info(" ", "> proxy operator: ", await impl.owner.call()) + console.info(" ", "> impl. address: ", await getProxyImplementation(from, proxy.address)) + console.info(" ", "> impl. version: ", await impl.version.call()) + console.info() + return proxy } -async function getProxyImplementation(from, proxyAddr) { - proxy = await WitnetProxy.at(proxyAddr) - return await proxy.implementation.call({ from }) +async function getProxyImplementation (from, proxyAddr) { + proxy = await WitnetProxy.at(proxyAddr) + return await proxy.implementation.call({ from }) } -async function upgradeProxyTo(from, proxy, implAddr, initData) { - proxy = await WitnetProxy.at(proxy.address) - return await proxy.upgradeTo(implAddr, initData, { from }) +async function upgradeProxyTo (from, proxy, implAddr, initData) { + proxy = await WitnetProxy.at(proxy.address) + return await proxy.upgradeTo(implAddr, initData, { from }) } diff --git a/migrations/scripts/5_apps.js b/migrations/scripts/5_apps.js index 3692fa4b..3080cc8a 100644 --- a/migrations/scripts/5_apps.js +++ b/migrations/scripts/5_apps.js @@ -8,117 +8,129 @@ const utils = require("../../scripts/utils") const WitnetDeployer = artifacts.require("WitnetDeployer") module.exports = async function (_, network, [,,, from]) { - const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" - const ecosystem = utils.getRealmNetworkFromArgs()[0] - network = network.split("-")[0] + const isDryRun = network === "test" || network.split("-")[1] === "fork" || network.split("-")[0] === "develop" + const ecosystem = utils.getRealmNetworkFromArgs()[0] + network = network.split("-")[0] - if (!addresses[ecosystem]) addresses[ecosystem] = {} - if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} + if (!addresses[ecosystem]) addresses[ecosystem] = {} + if (!addresses[ecosystem][network]) addresses[ecosystem][network] = {} - const specs = merge( - settings.specs.default, - settings.specs[ecosystem], - settings.specs[network], - ) - const targets = merge( - settings.artifacts.default, - settings.artifacts[ecosystem], - settings.artifacts[network] - ) + const specs = merge( + settings.specs.default, + settings.specs[ecosystem], + settings.specs[network], + ) + const targets = merge( + settings.artifacts.default, + settings.artifacts[ecosystem], + settings.artifacts[network] + ) - // Deploy the WitnetPriceFeeds oracle, if required - { - await deploy({ - from, ecosystem, network, targets, - key: targets.WitnetPriceFeeds, - libs: specs.WitnetPriceFeeds.libs, - vanity: specs.WitnetPriceFeeds?.vanity || 0, - immutables: specs.WitnetPriceFeeds.immutables, - intrinsics: { types: [ 'address', 'address' ], values: [ - /* _operator */ from, - /* _wrb */ await determineProxyAddr(from, specs.WitnetRequestBoard?.vanity || 3), - ]}, - }); - if (!isDryRun) utils.saveAddresses(addresses); - } - // Deploy the WitnetRandomness oracle, if required - { - await deploy({ - from, ecosystem, network, targets, - key: targets.WitnetRandomness, - libs: specs.WitnetRandomness?.libs, - vanity: specs.WitnetRandomness?.vanity || 0, - immutables: specs.WitnetRandomness?.immutables, - intrinsics: { types: [ 'address', 'address' ], values: [ - /* _operator */ from, - /* _wrb */ await determineProxyAddr(from, specs.WitnetRequestBoard?.vanity || 3), - ]}, - }); - if (!isDryRun) utils.saveAddresses(addresses); - } + // Deploy the WitnetPriceFeeds oracle, if required + { + await deploy({ + from, + ecosystem, + network, + targets, + key: targets.WitnetPriceFeeds, + libs: specs.WitnetPriceFeeds.libs, + vanity: specs.WitnetPriceFeeds?.vanity || 0, + immutables: specs.WitnetPriceFeeds.immutables, + intrinsics: { + types: ["address", "address"], + values: [ + /* _operator */ from, + /* _wrb */ await determineProxyAddr(from, specs.WitnetRequestBoard?.vanity || 3), + ], + }, + }) + if (!isDryRun) utils.saveAddresses(addresses) + } + // Deploy the WitnetRandomness oracle, if required + { + await deploy({ + from, + ecosystem, + network, + targets, + key: targets.WitnetRandomness, + libs: specs.WitnetRandomness?.libs, + vanity: specs.WitnetRandomness?.vanity || 0, + immutables: specs.WitnetRandomness?.immutables, + intrinsics: { + types: ["address", "address"], + values: [ + /* _operator */ from, + /* _wrb */ await determineProxyAddr(from, specs.WitnetRequestBoard?.vanity || 3), + ], + }, + }) + if (!isDryRun) utils.saveAddresses(addresses) + } } -async function deploy(specs) { - const { from, ecosystem, network, key, libs, intrinsics, immutables, targets, vanity } = specs; - const artifact = artifacts.require(key) - const salt = vanity ? "0x" + ethUtils.setLengthLeft(ethUtils.toBuffer(vanity), 32).toString("hex") : "0x0" - if (utils.isNullAddress(addresses[ecosystem][network][key])) { - utils.traceHeader(`Deploying '${key}'...`) - const deployer = await WitnetDeployer.deployed() - let { types, values } = intrinsics - if (immutables?.types) types = [ ...types, ...immutables.types ] - if (immutables?.values) values = [ ...values, ...immutables.values ] - const constructorArgs = web3.eth.abi.encodeParameters(types, values) - if (constructorArgs.length > 2) { - console.info(" ", "> constructor types:", types) - console.info(" ", "> constructor args: ", constructorArgs.slice(2)) - } - const coreBytecode = link(artifact.toJSON().bytecode, libs, targets) - if (coreBytecode.indexOf("__") > -1) { - console.info(bytecode) - console.info("Cannot deploy due to some missing libs") - process.exit(1) - } - const dappInitCode = coreBytecode + constructorArgs.slice(2) - const dappAddr = await deployer.determineAddr.call(dappInitCode, salt, { from }) - console.info(" ", "> account: ", from) - console.info(" ", "> balance: ", web3.utils.fromWei(await web3.eth.getBalance(from), 'ether'), "ETH") - const tx = await deployer.deploy(dappInitCode, salt, { from }) - utils.traceTx(tx) - if ((await web3.eth.getCode(dappAddr)).length > 3) { - addresses[ecosystem][network][key] = dappAddr - // save/overwrite exportable abi file - utils.saveJsonAbi(key, artifact.abi) - } else { - console.info(`Contract was not deployed on expected address: ${dappAddr}`) - console.log(tx.receipt) - process.exit(1) - } +async function deploy (specs) { + const { from, ecosystem, network, key, libs, intrinsics, immutables, targets, vanity } = specs + const artifact = artifacts.require(key) + const salt = vanity ? "0x" + ethUtils.setLengthLeft(ethUtils.toBuffer(vanity), 32).toString("hex") : "0x0" + if (utils.isNullAddress(addresses[ecosystem][network][key])) { + utils.traceHeader(`Deploying '${key}'...`) + const deployer = await WitnetDeployer.deployed() + let { types, values } = intrinsics + if (immutables?.types) types = [...types, ...immutables.types] + if (immutables?.values) values = [...values, ...immutables.values] + const constructorArgs = web3.eth.abi.encodeParameters(types, values) + if (constructorArgs.length > 2) { + console.info(" ", "> constructor types:", types) + console.info(" ", "> constructor args: ", constructorArgs.slice(2)) + } + const coreBytecode = link(artifact.toJSON().bytecode, libs, targets) + if (coreBytecode.indexOf("__") > -1) { + console.info(bytecode) + console.info("Cannot deploy due to some missing libs") + process.exit(1) + } + const dappInitCode = coreBytecode + constructorArgs.slice(2) + const dappAddr = await deployer.determineAddr.call(dappInitCode, salt, { from }) + console.info(" ", "> account: ", from) + console.info(" ", "> balance: ", web3.utils.fromWei(await web3.eth.getBalance(from), "ether"), "ETH") + const tx = await deployer.deploy(dappInitCode, salt, { from }) + utils.traceTx(tx) + if ((await web3.eth.getCode(dappAddr)).length > 3) { + addresses[ecosystem][network][key] = dappAddr + // save/overwrite exportable abi file + utils.saveJsonAbi(key, artifact.abi) } else { - utils.traceHeader(`Skipped '${key}'`) + console.info(`Contract was not deployed on expected address: ${dappAddr}`) + console.log(tx.receipt) + process.exit(1) } - artifact.address = addresses[ecosystem][network][key] - console.info(" ", "> contract address: ", artifact.address) - console.info(" ", "> contract codehash:", web3.utils.soliditySha3(await web3.eth.getCode(artifact.address))) - console.info() - return artifact + } else { + utils.traceHeader(`Skipped '${key}'`) + } + artifact.address = addresses[ecosystem][network][key] + console.info(" ", "> contract address: ", artifact.address) + console.info(" ", "> contract codehash:", web3.utils.soliditySha3(await web3.eth.getCode(artifact.address))) + console.info() + return artifact } -async function determineProxyAddr(from, nonce) { - const salt = nonce ? "0x" + ethUtils.setLengthLeft(ethUtils.toBuffer(nonce), 32).toString("hex") : "0x0" - const deployer = await WitnetDeployer.deployed() - const addr = await deployer.determineProxyAddr.call(salt, { from }) - return addr +async function determineProxyAddr (from, nonce) { + const salt = nonce ? "0x" + ethUtils.setLengthLeft(ethUtils.toBuffer(nonce), 32).toString("hex") : "0x0" + const deployer = await WitnetDeployer.deployed() + const addr = await deployer.determineProxyAddr.call(salt, { from }) + return addr } -function link(bytecode, libs, targets) { - if (libs && Array.isArray(libs) && libs.length > 0) { - for (index in libs) { - const key = targets[libs[index]] - const lib = artifacts.require(key) - bytecode = bytecode.replaceAll(`__${key}${"_".repeat(38-key.length)}`, lib.address.slice(2)) - console.info(" ", `> linked library: ${key} => ${lib.address}`) - } +function link (bytecode, libs, targets) { + if (libs && Array.isArray(libs) && libs.length > 0) { + for (index in libs) { + const key = targets[libs[index]] + const lib = artifacts.require(key) + bytecode = bytecode.replaceAll(`__${key}${"_".repeat(38 - key.length)}`, lib.address.slice(2)) + console.info(" ", `> linked library: ${key} => ${lib.address}`) } - return bytecode -} \ No newline at end of file + } + return bytecode +} diff --git a/migrations/witnet.settings.js b/migrations/witnet.settings.js index 80bcc6fa..5081d57d 100644 --- a/migrations/witnet.settings.js +++ b/migrations/witnet.settings.js @@ -659,7 +659,7 @@ module.exports = { specs: { default: { WitnetBytecodes: { - libs: [ "WitnetEncodingLib", ], + libs: ["WitnetEncodingLib"], vanity: 172582, }, WitnetRandomness: { @@ -667,31 +667,31 @@ module.exports = { }, WitnetRequestBoard: { immutables: { - types: [ 'uint256', 'uint256', 'uint256', 'uint256', ], + types: ["uint256", "uint256", "uint256", "uint256"], values: [ - /* _reportResultGasBase */ 58282, - /* _reportResultWithCallbackGasBase */ 65273, - /* _reportResultWithCallbackRevertGasBase */ 69546, - /* _sstoreFromZeroGas */ 20000, - ] + /* _reportResultGasBase */ 58282, + /* _reportResultWithCallbackGasBase */ 65273, + /* _reportResultWithCallbackRevertGasBase */ 69546, + /* _sstoreFromZeroGas */ 20000, + ], }, - libs: [ "WitnetErrorsLib", ], + libs: ["WitnetErrorsLib"], vanity: 899032812, // => 0x000071F0c823bD30D2Bf4CD1E829Eba5A6070000 }, WitnetRequestFactory: { vanity: 178848, }, WitnetPriceFeeds: { - libs: [ "WitnetPriceFeedsLib", ], + libs: ["WitnetPriceFeedsLib"], vanity: 5, - } + }, }, avalanche: { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 155000, - ] + /* _reportResultGasBase */ 155000, + ], }, }, }, @@ -699,8 +699,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 114000, - ] + /* _reportResultGasBase */ 114000, + ], }, }, }, @@ -708,8 +708,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 78500, - ] + /* _reportResultGasBase */ 78500, + ], }, }, }, @@ -717,8 +717,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 225000, - ] + /* _reportResultGasBase */ 225000, + ], }, }, }, @@ -726,8 +726,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 225000, - ] + /* _reportResultGasBase */ 225000, + ], }, }, }, @@ -735,8 +735,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 137500, - ] + /* _reportResultGasBase */ 137500, + ], }, }, }, @@ -744,8 +744,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 85000, - ] + /* _reportResultGasBase */ 85000, + ], }, }, }, @@ -753,8 +753,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 530000, - ] + /* _reportResultGasBase */ 530000, + ], }, }, }, @@ -762,8 +762,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 85000, - ] + /* _reportResultGasBase */ 85000, + ], }, }, }, @@ -771,8 +771,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 92500, - ] + /* _reportResultGasBase */ 92500, + ], }, }, }, @@ -780,8 +780,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 105000, - ] + /* _reportResultGasBase */ 105000, + ], }, }, }, @@ -789,8 +789,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 85000, - ] + /* _reportResultGasBase */ 85000, + ], }, }, }, @@ -798,8 +798,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 134800, - ] + /* _reportResultGasBase */ 134800, + ], }, }, }, @@ -807,8 +807,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 115000, - ] + /* _reportResultGasBase */ 115000, + ], }, }, }, @@ -816,8 +816,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 145000, - ] + /* _reportResultGasBase */ 145000, + ], }, }, }, @@ -825,8 +825,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 135000, - ] + /* _reportResultGasBase */ 135000, + ], }, }, }, @@ -834,8 +834,8 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ "0x3100A1CAC7EF19DC", - ] + /* _reportResultGasBase */ "0x3100A1CAC7EF19DC", + ], }, }, }, @@ -843,10 +843,10 @@ module.exports = { WitnetRequestBoard: { immutables: { values: [ - /* _reportResultGasBase */ 83949, - ] + /* _reportResultGasBase */ 83949, + ], }, }, }, }, -} \ No newline at end of file +} diff --git a/scripts/eth-create2.js b/scripts/eth-create2.js index 52a0f84c..5a364f00 100644 --- a/scripts/eth-create2.js +++ b/scripts/eth-create2.js @@ -1,6 +1,6 @@ -const assert = require('nanoassert') -const { utils } = require('eth-helpers') -const keccak = require('sha3-wasm').keccak256 +const assert = require("nanoassert") +const { utils } = require("eth-helpers") +const keccak = require("sha3-wasm").keccak256 const prefix = Buffer.from([0xff]) @@ -16,13 +16,13 @@ const prefix = Buffer.from([0xff]) * `eth-checksum` or similar modules */ module.exports = function create2 (address, salt, initCode) { - if (typeof address === 'string') address = utils.parse.address(address) - if (typeof salt === 'string') salt = utils.parse.uint256(salt) - if (typeof initCode === 'string') initCode = utils.parse.bytes(initCode) + if (typeof address === "string") address = utils.parse.address(address) + if (typeof salt === "string") salt = utils.parse.uint256(salt) + if (typeof initCode === "string") initCode = utils.parse.bytes(initCode) - assert(address.byteLength === 20, 'address must be 20 bytes') - assert(salt.byteLength === 32, 'salt must be 32 bytes') - assert(initCode.byteLength != null, 'initCode must be Buffer') + assert(address.byteLength === 20, "address must be 20 bytes") + assert(salt.byteLength === 32, "salt must be 32 bytes") + assert(initCode.byteLength != null, "initCode must be Buffer") const codeHash = keccak().update(initCode).digest() @@ -34,4 +34,3 @@ module.exports = function create2 (address, salt, initCode) { .digest() .slice(-20)) } - diff --git a/scripts/eth-create3.js b/scripts/eth-create3.js index 2f5347d4..613e8de5 100644 --- a/scripts/eth-create3.js +++ b/scripts/eth-create3.js @@ -1,6 +1,6 @@ -const assert = require('nanoassert') -const { utils } = require('eth-helpers') -const keccak = require('sha3-wasm').keccak256 +const assert = require("nanoassert") +const { utils } = require("eth-helpers") +const keccak = require("sha3-wasm").keccak256 const factoryPrefix = Buffer.from([0xff]) @@ -15,11 +15,11 @@ const factoryPrefix = Buffer.from([0xff]) * `eth-checksum` or similar modules */ module.exports = function create3 (address, salt) { - if (typeof address === 'string') address = utils.parse.address(address) - if (typeof salt === 'string') salt = utils.parse.uint256(salt) + if (typeof address === "string") address = utils.parse.address(address) + if (typeof salt === "string") salt = utils.parse.uint256(salt) - assert(address.byteLength === 20, 'address must be 20 bytes') - assert(salt.byteLength === 32, 'salt must be 32 bytes') + assert(address.byteLength === 20, "address must be 20 bytes") + assert(salt.byteLength === 32, "salt must be 32 bytes") const factoryHash = utils.parse.uint256("0x21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f") const factoryAddr = keccak() @@ -29,8 +29,8 @@ module.exports = function create3 (address, salt) { .update(factoryHash) .digest() .slice(-20) - ; - assert(factoryAddr.byteLength === 20, 'address must be 20 bytes') + + assert(factoryAddr.byteLength === 20, "address must be 20 bytes") return utils.format.address(keccak() .update(Buffer.from([0xd6, 0x94])) @@ -38,6 +38,5 @@ module.exports = function create3 (address, salt) { .update(Buffer.from([0x01])) .digest() .slice(-20) - ) + ) } - diff --git a/scripts/utils/index.js b/scripts/utils/index.js index 6d9190a6..1cce66d5 100644 --- a/scripts/utils/index.js +++ b/scripts/utils/index.js @@ -121,7 +121,7 @@ function saveAddresses (addrs) { function saveJsonAbi (key, abi) { const version = require("../../package.json").version - const latest_fn = `./migrations/abis/${key}.json`; + const latest_fn = `./migrations/abis/${key}.json` const version_fn = `./migrations/abis/${key}-${version}.json` let latest_abi = [] if (fs.existsSync(latest_fn)) { diff --git a/scripts/utils/traceTx.js b/scripts/utils/traceTx.js index 4c36b722..28134518 100644 --- a/scripts/utils/traceTx.js +++ b/scripts/utils/traceTx.js @@ -4,5 +4,5 @@ module.exports = function (tx) { console.info(" ", "> transaction hash: ", tx.receipt.transactionHash) console.info(" ", "> gas used: ", tx.receipt.gasUsed.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")) console.info(" ", "> gas price: ", tx.receipt.effectiveGasPrice / 10 ** 9, "gwei") - console.info(" ", "> total cost: ", web3.utils.fromWei(BigInt(tx.receipt.gasUsed * tx.receipt.effectiveGasPrice).toString(), 'ether'), "ETH") + console.info(" ", "> total cost: ", web3.utils.fromWei(BigInt(tx.receipt.gasUsed * tx.receipt.effectiveGasPrice).toString(), "ether"), "ETH") } diff --git a/scripts/vanity2gen.js b/scripts/vanity2gen.js index 8a835413..0ce0ee90 100644 --- a/scripts/vanity2gen.js +++ b/scripts/vanity2gen.js @@ -80,4 +80,3 @@ module.exports = async function () { offset++ } } - diff --git a/scripts/vanity3gen.js b/scripts/vanity3gen.js index 6452d3b8..3e172168 100644 --- a/scripts/vanity3gen.js +++ b/scripts/vanity3gen.js @@ -14,7 +14,7 @@ module.exports = async function () { let network = "default" let prefix = "0x00" let suffix = "0x00" - let hexArgs = "" + const hexArgs = "" process.argv.map((argv, index, args) => { if (argv === "--offset") { offset = parseInt(args[index + 1])