From 9d972eb279b08c07148531be3949f61e532c965d Mon Sep 17 00:00:00 2001 From: Blockchain Guy Date: Thu, 4 Jul 2024 16:40:29 +0530 Subject: [PATCH 01/44] feat: add script to transfer object (#256) * feat: add script to transfer object * chore: lint and spelling improvemnts * chore: updated readme * refactor: address PR comments * refactor: remove dotenv setup from utils * refactor: address PR comments * refactor: remove unnecessary throws * Update sui/transfer-object.js Co-authored-by: Milap Sheth * refactor: remove extra validation for objectId --------- Co-authored-by: Milap Sheth --- sui/README.md | 10 ++++++ sui/cli-utils.js | 11 ++++++ sui/transfer-object.js | 77 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 sui/transfer-object.js diff --git a/sui/README.md b/sui/README.md index ec4d96c0..c6171be4 100644 --- a/sui/README.md +++ b/sui/README.md @@ -109,3 +109,13 @@ Use the same nonce for `--currentNonce` as the `--nonce` when deploying the gate 1. Move build error during the deployment step Delete the `node_modules` folder and `package-lock.json` file and then run `npm install` again. + +## Transfer object + +Please note shared objects cannot be transferred via this script. + +```bash +node sui/transfer-object.js --objectId --recipient + +node sui/transfer-object.js --contractName --objectName --recipient +``` \ No newline at end of file diff --git a/sui/cli-utils.js b/sui/cli-utils.js index ad647e77..1ef5569b 100644 --- a/sui/cli-utils.js +++ b/sui/cli-utils.js @@ -41,6 +41,17 @@ const addBaseOptions = (program, options = {}) => { return program; }; +const addExtendedOptions = (program, options = {}) => { + addBaseOptions(program, options); + + if (options.contractName) { + program.addOption(new Option('-c, --contractName ', 'contract name')); + } + + return program; +}; + module.exports = { addBaseOptions, + addExtendedOptions, }; diff --git a/sui/transfer-object.js b/sui/transfer-object.js new file mode 100644 index 00000000..c1532ff1 --- /dev/null +++ b/sui/transfer-object.js @@ -0,0 +1,77 @@ +const { TransactionBlock } = require('@mysten/sui.js/transactions'); +const { Command, Option } = require('commander'); +const { printInfo, validateParameters } = require('../evm/utils'); +const { addExtendedOptions } = require('./cli-utils'); +const { getWallet, printWalletInfo } = require('./sign-utils'); +const { loadSuiConfig } = require('./utils'); + +async function processCommand(chain, options) { + const [keypair, client] = getWallet(chain, options); + await printWalletInfo(keypair, client, chain, options); + const recipient = options.recipient; + + validateParameters({ + isKeccak256Hash: { recipient }, + }); + + let objectId; + + if (options.objectId) { + objectId = options.objectId; + } else if (options.contractName && options.objectName) { + const { contractName, objectName } = options; + + validateParameters({ + isString: { contractName, objectName }, + }); + + const contractsData = chain?.contracts; + const contractObject = contractsData?.[contractName]; + const objectsData = contractObject?.objects; + objectId = objectsData?.[objectName]; + } else { + throw new Error('Provide object id or contract name with object name'); + } + + validateParameters({ + isKeccak256Hash: { objectId }, + }); + + const tx = new TransactionBlock(); + tx.transferObjects([`${objectId}`], tx.pure(recipient)); + + const result = await client.signAndExecuteTransactionBlock({ + transactionBlock: tx, + signer: keypair, + options: { + showObjectChanges: true, + showBalanceChanges: true, + showEvents: true, + }, + }); + + printInfo('Transaction result', JSON.stringify(result)); +} + +async function mainProcessor(options, processor) { + const config = loadSuiConfig(options.env); + await processor(config.sui, options); +} + +if (require.main === module) { + const program = new Command(); + + program.name('transfer-object').description('Transfer object to recipient address'); + + addExtendedOptions(program, { contractName: true }); + + program.addOption(new Option('--objectId ', 'object id to be transferred')); + program.addOption(new Option('--objectName ', 'object name to be transferred')); + program.addOption(new Option('--recipient ', 'recipient to transfer object to').makeOptionMandatory(true)); + + program.action(async (options) => { + mainProcessor(options, processCommand); + }); + + program.parse(); +} From 1b3e5cbec696c2f476f2422e16795f02dffec8b6 Mon Sep 17 00:00:00 2001 From: Milap Sheth Date: Fri, 5 Jul 2024 11:20:04 -0400 Subject: [PATCH 02/44] chore(config): release v1.3.0 axelar-chains-config (#286) --- axelar-chains-config/package-lock.json | 4 ++-- axelar-chains-config/package.json | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/axelar-chains-config/package-lock.json b/axelar-chains-config/package-lock.json index c2ad0ad7..ca24661e 100644 --- a/axelar-chains-config/package-lock.json +++ b/axelar-chains-config/package-lock.json @@ -1,12 +1,12 @@ { "name": "@axelar-network/axelar-chains-config", - "version": "1.2.0", + "version": "1.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@axelar-network/axelar-chains-config", - "version": "1.2.0", + "version": "1.3.0", "license": "MIT", "dependencies": { "@ethersproject/keccak256": "^5.7.0", diff --git a/axelar-chains-config/package.json b/axelar-chains-config/package.json index f3b70fc3..dc6ac968 100644 --- a/axelar-chains-config/package.json +++ b/axelar-chains-config/package.json @@ -1,6 +1,6 @@ { "name": "@axelar-network/axelar-chains-config", - "version": "1.2.0", + "version": "1.3.0", "description": "A utility to get chain information from Axelar", "main": "src/index.js", "types": "dist/index.d.ts", diff --git a/package-lock.json b/package-lock.json index 9420cbf9..23ddf9fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@axelar-network/axelar-contract-deployments", - "version": "1.2.0", + "version": "1.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@axelar-network/axelar-contract-deployments", - "version": "1.2.0", + "version": "1.3.0", "license": "MIT", "dependencies": { "@0xpolygonhermez/zkevm-commonjs": "github:0xpolygonhermez/zkevm-commonjs#v1.0.0", diff --git a/package.json b/package.json index ba66f5ae..f4cfc151 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@axelar-network/axelar-contract-deployments", - "version": "1.2.0", + "version": "1.3.0", "description": "Axelar contract deployment scripts", "main": "index.js", "scripts": { From 11a63f922260e76feeec52ddd2b7057b5a4604d0 Mon Sep 17 00:00:00 2001 From: Milap Sheth Date: Fri, 5 Jul 2024 13:35:00 -0400 Subject: [PATCH 03/44] v1.3.0 From a14505192943a4218f000a841b6e3423fa9a9045 Mon Sep 17 00:00:00 2001 From: Milap Sheth Date: Fri, 5 Jul 2024 14:40:43 -0400 Subject: [PATCH 04/44] chore(evm): update account nonces (#287) --- evm/nonces.json | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/evm/nonces.json b/evm/nonces.json index ac9b42e1..159f3ba3 100644 --- a/evm/nonces.json +++ b/evm/nonces.json @@ -57,12 +57,12 @@ "0x027c1882B975E2cd771AE068b0389FA38B9dda73": 3 }, "celo": { - "0x3f5876a2b06E54949aB106651Ab6694d0289b2b4": 2, + "0x3f5876a2b06E54949aB106651Ab6694d0289b2b4": 3, "0x9256Fd872118ed3a97754B0fB42c15015d17E0CC": 1, - "0x1486157d505C7F7E546aD00E3E2Eee25BF665C9b": 2, + "0x1486157d505C7F7E546aD00E3E2Eee25BF665C9b": 3, "0x2eC991B5c0B742AbD9d2ea31fe6c14a85e91C821": 3, "0xf505462A29E36E26f25Ef0175Ca1eCBa09CC118f": 2, - "0x027c1882B975E2cd771AE068b0389FA38B9dda73": 1 + "0x027c1882B975E2cd771AE068b0389FA38B9dda73": 2 }, "kava": { "0x3f5876a2b06E54949aB106651Ab6694d0289b2b4": 3, @@ -143,6 +143,14 @@ "0x2eC991B5c0B742AbD9d2ea31fe6c14a85e91C821": 0, "0xf505462A29E36E26f25Ef0175Ca1eCBa09CC118f": 0, "0x027c1882B975E2cd771AE068b0389FA38B9dda73": 0 + }, + "immutable": { + "0x3f5876a2b06E54949aB106651Ab6694d0289b2b4": 0, + "0x9256Fd872118ed3a97754B0fB42c15015d17E0CC": 0, + "0x1486157d505C7F7E546aD00E3E2Eee25BF665C9b": 0, + "0x2eC991B5c0B742AbD9d2ea31fe6c14a85e91C821": 0, + "0xf505462A29E36E26f25Ef0175Ca1eCBa09CC118f": 0, + "0x027c1882B975E2cd771AE068b0389FA38B9dda73": 0 } }, "testnet": { From 92774ba8ce12865f20e3ad4d90f031f1f3cf5988 Mon Sep 17 00:00:00 2001 From: eguajardo Date: Mon, 8 Jul 2024 18:15:46 -0600 Subject: [PATCH 05/44] feat(amplifier): script to submit store code governance proposal (#283) * add script to submit store code proposals * add deposit option * add instantiate permission --------- Co-authored-by: Milap Sheth --- cosmwasm/deploy-contract.js | 20 ++++---- cosmwasm/submit-proposal.js | 77 +++++++++++++++++++++++++++++ cosmwasm/utils.js | 97 ++++++++++++++++++++++++++++++++++++- 3 files changed, 182 insertions(+), 12 deletions(-) create mode 100644 cosmwasm/submit-proposal.js diff --git a/cosmwasm/deploy-contract.js b/cosmwasm/deploy-contract.js index e638f5d1..2a8c8bc4 100644 --- a/cosmwasm/deploy-contract.js +++ b/cosmwasm/deploy-contract.js @@ -3,11 +3,16 @@ require('dotenv').config(); const { isNil } = require('lodash'); -const { SigningCosmWasmClient } = require('@cosmjs/cosmwasm-stargate'); -const { DirectSecp256k1HdWallet } = require('@cosmjs/proto-signing'); - const { printInfo, loadConfig, saveConfig, isString, isStringArray, isKeccak256Hash, isNumber, prompt } = require('../evm/utils'); -const { uploadContract, instantiateContract, isValidCosmosAddress, calculateDomainSeparator, governanceAddress } = require('./utils'); +const { + prepareWallet, + prepareClient, + uploadContract, + instantiateContract, + isValidCosmosAddress, + calculateDomainSeparator, + governanceAddress, +} = require('./utils'); const { Command, Option } = require('commander'); @@ -372,13 +377,6 @@ const makeInstantiateMsg = (contractName, chainName, config) => { throw new Error(`${contractName} is not supported.`); }; -const prepareWallet = ({ mnemonic }) => DirectSecp256k1HdWallet.fromMnemonic(mnemonic, { prefix: 'axelar' }); - -const prepareClient = ({ axelar: { rpc, gasPrice } }, wallet) => - SigningCosmWasmClient.connectWithSigner(rpc, wallet, { gasPrice }).then((client) => { - return { wallet, client }; - }); - const upload = (client, wallet, chainName, config, options) => { const { reuseCodeId, contractName } = options; const { diff --git a/cosmwasm/submit-proposal.js b/cosmwasm/submit-proposal.js new file mode 100644 index 00000000..49dfdd3c --- /dev/null +++ b/cosmwasm/submit-proposal.js @@ -0,0 +1,77 @@ +'use strict'; + +require('dotenv').config(); + +const { prepareWallet, prepareClient, submitStoreCodeProposal } = require('./utils'); +const { saveConfig, loadConfig, printInfo } = require('../evm/utils'); + +const { Command, Option } = require('commander'); + +const storeCode = (client, wallet, config, options) => { + const { contractName } = options; + const { + axelar: { + contracts: { [contractName]: contractConfig }, + }, + } = config; + + submitStoreCodeProposal(client, wallet, config, options).then((proposalId) => { + printInfo('Proposal submitted', proposalId); + + contractConfig.storeCodeProposalId = proposalId; + }); +}; + +const main = async (options) => { + const { env } = options; + const config = loadConfig(env); + + await prepareWallet(options) + .then((wallet) => prepareClient(config, wallet)) + .then(({ wallet, client }) => storeCode(client, wallet, config, options)) + .then(() => saveConfig(config, env)); +}; + +const programHandler = () => { + const program = new Command(); + + program.name('submit-proposal').description('Submit governance proposals'); + + program.addOption( + new Option('-e, --env ', 'environment') + .choices(['local', 'devnet', 'devnet-amplifier', 'devnet-verifiers', 'stagenet', 'testnet', 'mainnet']) + .default('devnet-amplifier') + .makeOptionMandatory(true) + .env('ENV'), + ); + program.addOption(new Option('-m, --mnemonic ', 'mnemonic').makeOptionMandatory(true).env('MNEMONIC')); + program.addOption(new Option('-a, --artifactPath ', 'artifact path').makeOptionMandatory(true).env('ARTIFACT_PATH')); + program.addOption(new Option('-c, --contractName ', 'contract name').makeOptionMandatory(true)); + + program.addOption(new Option('--aarch64', 'aarch64').env('AARCH64').default(false)); + program.addOption(new Option('-y, --yes', 'skip prompt confirmation').env('YES')); + + program.addOption(new Option('-t, --title ', 'title of proposal').makeOptionMandatory(true)); + program.addOption(new Option('-d, --description <description>', 'description of proposal').makeOptionMandatory(true)); + program.addOption(new Option('--deposit <deposit>', 'the proposal deposit').makeOptionMandatory(true)); + + program.addOption(new Option('-r, --runAs <runAs>', 'the address that will execute the message').makeOptionMandatory(true)); + + program.addOption(new Option('--source <source>', "a valid HTTPS URI to the contract's source code")); + program.addOption( + new Option('--builder <builder>', 'a valid docker image name with tag, such as "cosmwasm/workspace-optimizer:0.16.0'), + ); + program.addOption( + new Option('-i, --instantiateAddresses <instantiateAddresses>', 'comma separated list of addresses allowed to instantiate'), + ); + + program.action((options) => { + main(options); + }); + + program.parse(); +}; + +if (require.main === module) { + programHandler(); +} diff --git a/cosmwasm/utils.js b/cosmwasm/utils.js index 1eb1ca09..4067c07c 100644 --- a/cosmwasm/utils.js +++ b/cosmwasm/utils.js @@ -4,15 +4,27 @@ const { ethers } = require('hardhat'); const { utils: { keccak256 }, } = ethers; +const { createHash } = require('crypto'); const { readFileSync } = require('fs'); const { calculateFee, GasPrice } = require('@cosmjs/stargate'); -const { instantiate2Address } = require('@cosmjs/cosmwasm-stargate'); +const { instantiate2Address, SigningCosmWasmClient } = require('@cosmjs/cosmwasm-stargate'); +const { DirectSecp256k1HdWallet } = require('@cosmjs/proto-signing'); +const { MsgSubmitProposal } = require('cosmjs-types/cosmos/gov/v1beta1/tx'); +const { StoreCodeProposal } = require('cosmjs-types/cosmwasm/wasm/v1/proposal'); +const { AccessType } = require('cosmjs-types/cosmwasm/wasm/v1/types'); const { getSaltFromKey } = require('../evm/utils'); const { normalizeBech32 } = require('@cosmjs/encoding'); const governanceAddress = 'axelar10d07y265gmmuvt4z0w9aw880jnsr700j7v9daj'; +const prepareWallet = ({ mnemonic }) => DirectSecp256k1HdWallet.fromMnemonic(mnemonic, { prefix: 'axelar' }); + +const prepareClient = ({ axelar: { rpc, gasPrice } }, wallet) => + SigningCosmWasmClient.connectWithSigner(rpc, wallet, { gasPrice }).then((client) => { + return { wallet, client }; + }); + const pascalToSnake = (str) => str.replace(/([A-Z])/g, (group) => `_${group.toLowerCase()}`).replace(/^_/, ''); const isValidCosmosAddress = (str) => { @@ -83,10 +95,93 @@ const instantiateContract = (client, wallet, initMsg, config, { contractName, sa .then(({ contractAddress }) => contractAddress); }; +const getInstantiatePermission = (accessType, addresses) => { + return { + permission: accessType, + addresses: addresses.split(',').map((address) => address.trim()), + }; +}; + +const encodeStoreCodeProposal = (options) => { + const { artifactPath, contractName, aarch64, title, description, runAs, source, builder, instantiateAddresses } = options; + + const wasm = readFileSync(`${artifactPath}/${pascalToSnake(contractName)}${aarch64 ? '-aarch64' : ''}.wasm`); + + let codeHash; + + // source, builder and codeHash are optional, but mandatory if one is provided + if (source && builder) { + codeHash = createHash('sha256').update(wasm).digest(); + } + + const instantiatePermission = instantiateAddresses + ? getInstantiatePermission(AccessType.ACCESS_TYPE_ANY_OF_ADDRESSES, instantiateAddresses) + : getInstantiatePermission(AccessType.ACCESS_TYPE_NOBODY, ''); + + const proposal = StoreCodeProposal.fromPartial({ + title, + description, + runAs, + wasmByteCode: wasm, + source, + builder, + codeHash, + instantiatePermission, + }); + + return { + typeUrl: '/cosmwasm.wasm.v1.StoreCodeProposal', + value: Uint8Array.from(StoreCodeProposal.encode(proposal).finish()), + }; +}; + +const encodeSubmitProposal = (content, config, options, proposer) => { + const { + axelar: { tokenSymbol }, + } = config; + const { deposit } = options; + + return { + typeUrl: '/cosmos.gov.v1beta1.MsgSubmitProposal', + value: MsgSubmitProposal.fromPartial({ + content, + initialDeposit: [{ denom: `u${tokenSymbol.toLowerCase()}`, amount: deposit }], + proposer, + }), + }; +}; + +const submitProposal = (client, wallet, config, options, content) => { + return wallet + .getAccounts() + .then(([account]) => { + const { + axelar: { gasPrice, gasLimit }, + } = config; + + const submitProposalMsg = encodeSubmitProposal(content, config, options, account.address); + + const storeFee = gasLimit === 'auto' ? 'auto' : calculateFee(gasLimit, GasPrice.fromString(gasPrice)); + return client.signAndBroadcast(account.address, [submitProposalMsg], storeFee, ''); + }) + .then( + ({ events }) => events.find(({ type }) => type === 'submit_proposal').attributes.find(({ key }) => key === 'proposal_id').value, + ); +}; + +const submitStoreCodeProposal = (client, wallet, config, options) => { + const content = encodeStoreCodeProposal(options); + + return submitProposal(client, wallet, config, options, content); +}; + module.exports = { governanceAddress, + prepareWallet, + prepareClient, calculateDomainSeparator, uploadContract, instantiateContract, + submitStoreCodeProposal, isValidCosmosAddress, }; From 22a6f006c56cf47827b9f52bc69c7ad499f3b783 Mon Sep 17 00:00:00 2001 From: eguajardo <edwin@axelar.network> Date: Mon, 8 Jul 2024 19:38:01 -0600 Subject: [PATCH 06/44] feat(amplifier): update devnet-amplifier and devnet-verifiers json configurations after v0.5 migration (#288) * update codeIds * update initialVerifierSetId --- .../info/devnet-amplifier.json | 30 +++++++++++-------- .../info/devnet-verifiers.json | 30 +++++++++++-------- 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/axelar-chains-config/info/devnet-amplifier.json b/axelar-chains-config/info/devnet-amplifier.json index 5fac88b6..59e78ead 100644 --- a/axelar-chains-config/info/devnet-amplifier.json +++ b/axelar-chains-config/info/devnet-amplifier.json @@ -30,7 +30,8 @@ "0x25C97DC353fF1dBBD04d8096AC6C87B5244D856d", "0xd7A0e641Bfbb9AA83aAb9f3e89bf83e128d321c4", "0x000000000000000000000000ba76c6980428a0b10cfc5d8ccb61949677a612330000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000cb9e1000000000000000000000000000000000000000000000000000000000000000300000000000000000000000051380cbf0777990e197a3e498ffafd26143e35f8000000000000000000000000000000000000000000000000000000000000000100000000000000000000000061373485594010371dfbf3a8f8bd1736bfda7c090000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c70aa87b38e6ab3c0df6e56338f96a5c00e653080000000000000000000000000000000000000000000000000000000000000001" - ] + ], + "initialVerifierSetId": "87bba3c9140d07b5e585b35254e9c1068574117685e34a51561cab4b719df381" }, "InterchainGovernance": { "governanceChain": "Axelarnet", @@ -95,7 +96,8 @@ "0x37e6F01C4BA68BA121dA57CfB0d54B822006010d", "0x0aa18e321c89bbdfCE9913aa0cA20B977aDc4B48", "0x000000000000000000000000ba76c6980428a0b10cfc5d8ccb61949677a612330000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000cba59000000000000000000000000000000000000000000000000000000000000000300000000000000000000000051380cbf0777990e197a3e498ffafd26143e35f8000000000000000000000000000000000000000000000000000000000000000100000000000000000000000061373485594010371dfbf3a8f8bd1736bfda7c090000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c70aa87b38e6ab3c0df6e56338f96a5c00e653080000000000000000000000000000000000000000000000000000000000000001" - ] + ], + "initialVerifierSetId": "6fa58485dfe7043bd61ce646c3353e4afdb30d5686371e7ef5d00fba13d589fd" }, "InterchainGovernance": { "governanceChain": "Axelarnet", @@ -162,7 +164,8 @@ "0x957E7eC2da3Cd93Fd49E1ac7DF0499a3EC9814a1", "0x3Cd679Cd00b61a8540Fcc3aE90Bba30DC3eeb6ee", "0x000000000000000000000000ba76c6980428a0b10cfc5d8ccb61949677a612330000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000cbac7000000000000000000000000000000000000000000000000000000000000000300000000000000000000000051380cbf0777990e197a3e498ffafd26143e35f8000000000000000000000000000000000000000000000000000000000000000100000000000000000000000061373485594010371dfbf3a8f8bd1736bfda7c090000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c70aa87b38e6ab3c0df6e56338f96a5c00e653080000000000000000000000000000000000000000000000000000000000000001" - ] + ], + "initialVerifierSetId": "7c394e3acd7ab02d9518e18f21a73499275623b19fb51d9a428bf329eea1e1e8" }, "InterchainGovernance": { "governanceChain": "Axelarnet", @@ -227,7 +230,8 @@ "0xC7547fb5bc2Fde4Aec37De85DecA111FF3E0169b", "0xE7741c9044F96FDb1fb08405a6199995E94Ef6ba", "0x000000000000000000000000ba76c6980428a0b10cfc5d8ccb61949677a612330000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000cbb3c000000000000000000000000000000000000000000000000000000000000000300000000000000000000000051380cbf0777990e197a3e498ffafd26143e35f8000000000000000000000000000000000000000000000000000000000000000100000000000000000000000061373485594010371dfbf3a8f8bd1736bfda7c090000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c70aa87b38e6ab3c0df6e56338f96a5c00e653080000000000000000000000000000000000000000000000000000000000000001" - ] + ], + "initialVerifierSetId": "f844cbd6aa9c37f48687a07818a8938291054e7ce0347bc2e4b788d38521baba" }, "InterchainGovernance": { "governanceChain": "Axelarnet", @@ -267,24 +271,24 @@ "contracts": { "ServiceRegistry": { "governanceAccount": "axelar1zlr7e5qf3sz7yf890rkh9tcnu87234k6k7ytd9", - "codeId": 223, + "codeId": 499, "address": "axelar1c9fkszt5lq34vvvlat3fxj6yv7ejtqapz04e97vtc9m5z9cwnamq8zjlhz" }, "Router": { "adminAddress": "axelar1zlr7e5qf3sz7yf890rkh9tcnu87234k6k7ytd9", "governanceAddress": "axelar1zlr7e5qf3sz7yf890rkh9tcnu87234k6k7ytd9", - "codeId": 222, + "codeId": 498, "address": "axelar14jjdxqhuxk803e9pq64w4fgf385y86xxhkpzswe9crmu6vxycezst0zq8y" }, "Multisig": { "governanceAddress": "axelar1zlr7e5qf3sz7yf890rkh9tcnu87234k6k7ytd9", "blockExpiry": 10, - "codeId": 218, + "codeId": 494, "address": "axelar19jxy26z0qnnspa45y5nru0l5rmy9d637z5km2ndjxthfxf5qaswst9290r" }, "Coordinator": { "governanceAddress": "axelar1zlr7e5qf3sz7yf890rkh9tcnu87234k6k7ytd9", - "codeId": 216, + "codeId": 492, "address": "axelar1m2498n4h2tskcsmssjnzswl5e6eflmqnh487ds47yxyu6y5h4zuqr9zk4g" }, "Rewards": { @@ -298,12 +302,12 @@ "10" ] }, - "codeId": 221, + "codeId": 497, "address": "axelar1vaj9sfzc3z0gpel90wu4ljutncutv0wuhvvwfsh30rqxq422z89qnd989l" }, "NexusGateway": { "nexus": "axelar17h8uk4ct0mdv9mgkuxszt4gp2htpfr08mge20r", - "codeId": 220, + "codeId": 496, "address": "axelar1jjjr3tqs0nzjv3y9fg4xvzkww50jq06a9qp77r8kzmqyla97556sxx7702" }, "VotingVerifier": { @@ -320,7 +324,7 @@ "msgIdFormat": "hex_tx_hash_and_event_index", "address": "axelar1ty7mx0cllgz8xuvhn2j7e3qy8999ssgmjtktyqetl335em0g88lq6rjhl2" }, - "codeId": 224, + "codeId": 500, "fantom": { "governanceAddress": "axelar1zlr7e5qf3sz7yf890rkh9tcnu87234k6k7ytd9", "serviceName": "validators", @@ -365,7 +369,7 @@ "avalanche": { "address": "axelar16hdkkxjyapw5zyf2wxs42854278tpwgqkz87kst8wamvr4pcy4pqrpn96s" }, - "codeId": 217, + "codeId": 493, "fantom": { "address": "axelar1pvcj8m7gp30tl26kt7n2ncg9g7xnt86wlqatlvwehh8s2ve2anmq6ea96w" }, @@ -392,7 +396,7 @@ "domainSeparator": "0x598ba04d225cec385d1ce3cf3c9a076af803aa5c614bc0e0d176f04ac8d28f55", "address": "axelar1g6520uhs8u37el40wqngf60z06mjgk6z7nezytd2mxrmh7yesnmsyc0zjw" }, - "codeId": 219, + "codeId": 495, "fantom": { "governanceAddress": "axelar1zlr7e5qf3sz7yf890rkh9tcnu87234k6k7ytd9", "adminAddress": "axelar1zlr7e5qf3sz7yf890rkh9tcnu87234k6k7ytd9", diff --git a/axelar-chains-config/info/devnet-verifiers.json b/axelar-chains-config/info/devnet-verifiers.json index 0d54db6d..491ab243 100644 --- a/axelar-chains-config/info/devnet-verifiers.json +++ b/axelar-chains-config/info/devnet-verifiers.json @@ -35,7 +35,8 @@ "0x6d7963f2d9434ecC04ff75AADD95a139EFa25232", "0x3230E865358d8d1a560192ae8cb3Eae303cBd098", "0x000000000000000000000000ba76c6980428a0b10cfc5d8ccb61949677a612330000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000ae8a20000000000000000000000000000000000000000000000000000000000000003000000000000000000000000438b7642a57aa47d1a4d290a5e2a046f45c9a6a4000000000000000000000000000000000000000000000000000000000000000100000000000000000000000044b994544df974b36fa75ed80dfb17332dc65fcc0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000f1e9b98362820cc9257635b1e86dbf00d0bd92090000000000000000000000000000000000000000000000000000000000000001" - ] + ], + "initialVerifierSetId": "686781d395c71268dbf002f691ebf1bab85c541866297c31f3278f56d00fd570" }, "InterchainGovernance": { "governanceChain": "Axelarnet", @@ -124,7 +125,8 @@ "0x77e04bBdE02a37F7d626Df532d225D0C7198c8B5", "0x23888e6A0e0FE2D1C337e297D4dE3F2Ac8C721F6", "0x000000000000000000000000ba76c6980428a0b10cfc5d8ccb61949677a612330000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000ae91a0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000438b7642a57aa47d1a4d290a5e2a046f45c9a6a4000000000000000000000000000000000000000000000000000000000000000100000000000000000000000044b994544df974b36fa75ed80dfb17332dc65fcc0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000f1e9b98362820cc9257635b1e86dbf00d0bd92090000000000000000000000000000000000000000000000000000000000000001" - ] + ], + "initialVerifierSetId": "b2810f7735b93fb4ef850631c68d2e4056f7c5d79463beed4456911896e99471" }, "InterchainGovernance": { "governanceChain": "Axelarnet", @@ -213,7 +215,8 @@ "0xEc37bb3AeC26639F3510414fF30A000f2f4F7922", "0x01117C0Bb2a764Fc66162C6132F4069576D9226e", "0x000000000000000000000000ba76c6980428a0b10cfc5d8ccb61949677a612330000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000ae9eb0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000438b7642a57aa47d1a4d290a5e2a046f45c9a6a4000000000000000000000000000000000000000000000000000000000000000100000000000000000000000044b994544df974b36fa75ed80dfb17332dc65fcc0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000f1e9b98362820cc9257635b1e86dbf00d0bd92090000000000000000000000000000000000000000000000000000000000000001" - ] + ], + "initialVerifierSetId": "539fdbf1b9d4df9e3041cb34532be4b845bc07481f09c67c6a50b36b79475170" }, "InterchainGovernance": { "governanceChain": "Axelarnet", @@ -302,7 +305,8 @@ "0x30c5F5df4465cf98096557F3E8ce1411723BD663", "0x552CA7dA45EB6CbA0Ad8b5167CceDb37Bd587136", "0x000000000000000000000000ba76c6980428a0b10cfc5d8ccb61949677a612330000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000aed9c0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000438b7642a57aa47d1a4d290a5e2a046f45c9a6a4000000000000000000000000000000000000000000000000000000000000000100000000000000000000000044b994544df974b36fa75ed80dfb17332dc65fcc0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000f1e9b98362820cc9257635b1e86dbf00d0bd92090000000000000000000000000000000000000000000000000000000000000001" - ] + ], + "initialVerifierSetId": "d490e2330e717a7087bcc90652833b3fb60cea97291250e0d16a7e40b650050f" }, "InterchainGovernance": { "governanceChain": "Axelarnet", @@ -361,24 +365,24 @@ "contracts": { "ServiceRegistry": { "governanceAccount": "axelar19vvhwq57656hqfczhxw3r874l29jtd3uns4fsu", - "codeId": 28, + "codeId": 46, "address": "axelar1qk00h5atutpsv900x202pxx42npjr9thg58dnqpa72f2p7m2luas9x8txw" }, "Router": { "adminAddress": "axelar19vvhwq57656hqfczhxw3r874l29jtd3uns4fsu", "governanceAddress": "axelar19vvhwq57656hqfczhxw3r874l29jtd3uns4fsu", - "codeId": 27, + "codeId": 45, "address": "axelar1q3g7fdqfpftqfpuakwn7x037k80wv35jj9ged7v5e798pds7hnasgj6azz" }, "Multisig": { "governanceAddress": "axelar19vvhwq57656hqfczhxw3r874l29jtd3uns4fsu", "blockExpiry": 10, - "codeId": 23, + "codeId": 41, "address": "axelar15nczwuqh0zcu6syeqsc4td6dphql7n2p7cgkl9raz97z5s3zdjrsc8we9y" }, "Coordinator": { "governanceAddress": "axelar19vvhwq57656hqfczhxw3r874l29jtd3uns4fsu", - "codeId": 21, + "codeId": 39, "address": "axelar12wrtrzqt7atsen2wsl9k5hu82jsj6739h7pck20gtdd24mqyxv6q43lyh7" }, "Rewards": { @@ -392,12 +396,12 @@ "10" ] }, - "codeId": 26, + "codeId": 44, "address": "axelar1guczj53xxl4347adagh23eelyhnxvugw2nqq0q0dr6kws7q35jyqqnan33" }, "NexusGateway": { "nexus": "axelar17h8uk4ct0mdv9mgkuxszt4gp2htpfr08mge20r", - "codeId": 25, + "codeId": 43, "address": "axelar1e77ukfqk3yjjpscurp0la3ae3ssafw5zmvxfqsvljh0duectfcnqzxc86l" }, "VotingVerifier": { @@ -414,7 +418,7 @@ "msgIdFormat": "hex_tx_hash_and_event_index", "address": "axelar1elaymnd2epmfr498h2x9p2nezc4eklv95uv92u9csfs8wl75w7yqdc0h67" }, - "codeId": 29, + "codeId": 47, "fantom": { "governanceAddress": "axelar19vvhwq57656hqfczhxw3r874l29jtd3uns4fsu", "serviceName": "validators", @@ -459,7 +463,7 @@ "avalanche": { "address": "axelar1vnfn0e4vnn58ydpm05wqcc9zp8t5ztwd5rw5f895lykqaezmuccqujmwl2" }, - "codeId": 22, + "codeId": 40, "fantom": { "address": "axelar12xk7d7lksh6z94vvt4qqur765trqdcn7w86mfak62qjz63zvmhvstaswtt" }, @@ -486,7 +490,7 @@ "domainSeparator": "0x333e4afab949ca00f9b5daa5a021f942b614c91cb5ced70ded38cd89da2b55ef", "address": "axelar1qt0gkcrvcpv765k8ec4tl2svvg6hd3e3td8pvg2fsncrt3dzjefswsq3w2" }, - "codeId": 24, + "codeId": 42, "fantom": { "governanceAddress": "axelar19vvhwq57656hqfczhxw3r874l29jtd3uns4fsu", "adminAddress": "axelar19vvhwq57656hqfczhxw3r874l29jtd3uns4fsu", From d7a14d9282e7b77316c335f4391a6947fee33cbf Mon Sep 17 00:00:00 2001 From: Milap Sheth <milap@interoplabs.io> Date: Tue, 9 Jul 2024 17:58:08 -0400 Subject: [PATCH 07/44] fix(sui): specify nonce in Sui gateway readme example (#289) --- sui/README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sui/README.md b/sui/README.md index c6171be4..ac6bc965 100644 --- a/sui/README.md +++ b/sui/README.md @@ -84,8 +84,10 @@ node sui/gateway.js call-contract ethereum 0xba76c6980428A0b10CFC5d8ccb61949677A Approve messages: +If the gateway was deployed using the wallet, you can submit a message approval with it + ```bash -node sui/gateway.js approve ethereum 0x0x32034b47cb29d162d9d803cc405356f4ac0ec07fe847ace431385fe8acf3e6e5-1 0x4F4495243837681061C4743b74B3eEdf548D56A5 0xa84d27bd6c9680e52e93779b8977bbcb73273b88f52a84d8dd8af1c3301341d7 0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad --proof wallet +node sui/gateway.js approve --proof wallet --currentNonce test ethereum 0x0x32034b47cb29d162d9d803cc405356f4ac0ec07fe847ace431385fe8acf3e6e5-1 0x4F4495243837681061C4743b74B3eEdf548D56A5 0xa84d27bd6c9680e52e93779b8977bbcb73273b88f52a84d8dd8af1c3301341d7 0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad ``` Rotate gateway signers: @@ -93,7 +95,7 @@ Rotate gateway signers: If gateway was deployed with the wallet as the verifier, and you want to rotate to the Amplifier verifiers, do ```bash -node sui/gateway.js rotate --proof wallet +node sui/gateway.js rotate --proof wallet --currentNonce test ``` If you want to rotate to the wallet again but with a new nonce, do @@ -118,4 +120,4 @@ Please note shared objects cannot be transferred via this script. node sui/transfer-object.js --objectId <object id to be transferred> --recipient <recipient address> node sui/transfer-object.js --contractName <Can be checked from config> --objectName <picked from config> --recipient <recipient address> -``` \ No newline at end of file +``` From e2a6a25393c9537bf201d9fd78d7605d72884919 Mon Sep 17 00:00:00 2001 From: jcs47 <11947034+jcs47@users.noreply.github.com> Date: Wed, 10 Jul 2024 02:35:45 +0100 Subject: [PATCH 08/44] chore(cosmwasm): update Multisig instantiation message (#291) --- cosmwasm/deploy-contract.js | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/cosmwasm/deploy-contract.js b/cosmwasm/deploy-contract.js index 2a8c8bc4..5397d3ec 100644 --- a/cosmwasm/deploy-contract.js +++ b/cosmwasm/deploy-contract.js @@ -3,7 +3,17 @@ require('dotenv').config(); const { isNil } = require('lodash'); -const { printInfo, loadConfig, saveConfig, isString, isStringArray, isKeccak256Hash, isNumber, prompt } = require('../evm/utils'); +const { + printInfo, + loadConfig, + saveConfig, + isString, + isStringArray, + isKeccak256Hash, + isNumber, + prompt, + toBigNumberString, +} = require('../evm/utils'); const { prepareWallet, prepareClient, @@ -36,7 +46,11 @@ const makeServiceRegistryInstantiateMsg = ({ governanceAccount }) => { return { governance_account: governanceAccount }; }; -const makeMultisigInstantiateMsg = ({ governanceAddress, blockExpiry }, { Rewards: { address: rewardsAddress } }) => { +const makeMultisigInstantiateMsg = ({ adminAddress, governanceAddress, blockExpiry }, { Rewards: { address: rewardsAddress } }) => { + if (!validateAddress(adminAddress)) { + throw new Error('Missing or invalid Multisig.adminAddress in axelar info'); + } + if (!validateAddress(governanceAddress)) { throw new Error('Missing or invalid Multisig.governanceAddress in axelar info'); } @@ -49,7 +63,12 @@ const makeMultisigInstantiateMsg = ({ governanceAddress, blockExpiry }, { Reward throw new Error(`Missing or invalid Multisig.blockExpiry in axelar info`); } - return { governance_address: governanceAddress, rewards_address: rewardsAddress, block_expiry: blockExpiry }; + return { + admin_address: adminAddress, + governance_address: governanceAddress, + rewards_address: rewardsAddress, + block_expiry: toBigNumberString(blockExpiry), + }; }; const makeRewardsInstantiateMsg = ({ governanceAddress, rewardsDenom, params }) => { From 0131909f058f10f5cb080439209eff557435643a Mon Sep 17 00:00:00 2001 From: jcs47 <11947034+jcs47@users.noreply.github.com> Date: Wed, 10 Jul 2024 17:33:54 +0100 Subject: [PATCH 09/44] fix(sui): correctly parse `current_verifier_set` query (#292) --- sui/utils.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sui/utils.js b/sui/utils.js index 45787a94..ea857e6e 100644 --- a/sui/utils.js +++ b/sui/utils.js @@ -10,8 +10,11 @@ const { CosmWasmClient } = require('@cosmjs/cosmwasm-stargate'); const getAmplifierSigners = async (config, chain) => { const client = await CosmWasmClient.connect(config.axelar.rpc); - const workerSet = await client.queryContractSmart(config.axelar.contracts.MultisigProver[chain].address, 'current_verifier_set'); - const signers = Object.values(workerSet.signers); + const { id: verifierSetId, verifier_set: verifierSet } = await client.queryContractSmart( + config.axelar.contracts.MultisigProver[chain].address, + 'current_verifier_set', + ); + const signers = Object.values(verifierSet.signers); const weightedSigners = signers .map((signer) => ({ @@ -22,8 +25,9 @@ const getAmplifierSigners = async (config, chain) => { return { signers: weightedSigners, - threshold: Number(workerSet.threshold), - nonce: ethers.utils.hexZeroPad(BigNumber.from(workerSet.created_at).toHexString(), 32), + threshold: Number(verifierSet.threshold), + nonce: ethers.utils.hexZeroPad(BigNumber.from(verifierSet.created_at).toHexString(), 32), + verifierSetId, }; }; From 4b0f89248624486007e1670af98db1dab2c67885 Mon Sep 17 00:00:00 2001 From: Talal Ashraf <talal@interoplabs.io> Date: Wed, 10 Jul 2024 19:52:56 -0400 Subject: [PATCH 10/44] chore: polygon amoy its and multisig (#294) * chore: deploy polygon amoy multisig and interchain governance contracts * - its --------- Co-authored-by: Talal Ashraf <talal@axelar.network> --- axelar-chains-config/info/testnet.json | 42 ++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/axelar-chains-config/info/testnet.json b/axelar-chains-config/info/testnet.json index 0c1c6827..d6271c23 100644 --- a/axelar-chains-config/info/testnet.json +++ b/axelar-chains-config/info/testnet.json @@ -1912,10 +1912,29 @@ "salt": "Create3Deployer" }, "InterchainGovernance": { - "address": "0x943AAd94e45bad24A3da01a3ba815C03fCAC53FC" + "address": "0xfDF36A30070ea0241d69052ea85ff44Ad0476a66", + "minimumTimeDelay": 300, + "governanceChain": "Axelarnet", + "governanceAddress": "axelar10d07y265gmmuvt4z0w9aw880jnsr700j7v9daj", + "deployer": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", + "deploymentMethod": "create3", + "codehash": "0x4bc0efa16652748f5c3fbb77aedff01e0c1df4156a4f4c82d6d8748ee28cb9af", + "predeployCodehash": "0xe2de43b29f2387b6f3575a1b50d566908fc00e03a8d88ad6be74b674a70874d2", + "salt": "InterchainGovernance v5.5" }, "Multisig": { - "address": "0x943AAd94e45bad24A3da01a3ba815C03fCAC53FC" + "address": "0xCC940AE49C78F20E3F13F3cF37e996b98Ac3EC68", + "threshold": 2, + "signers": [ + "0x15837c1318AB83d99b19392Fd4811813f520d843", + "0x64247a441CeF0b7A46614AC34d046c0fdfe35954", + "0xEE64c8eb48437DbD2D5B8598dc4A3E8a6c8CEaD9" + ], + "deployer": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", + "deploymentMethod": "create3", + "codehash": "0x912095d5076ee40a9dd49c0f9d61d61334c47a78c7512852791652baef26c296", + "predeployCodehash": "0x912095d5076ee40a9dd49c0f9d61d61334c47a78c7512852791652baef26c296", + "salt": "Multisig v5.5" }, "Operators": { "owner": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", @@ -1931,6 +1950,25 @@ "address": "0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6", "implementation": "0xCD6b34FaF1FD1056C728A27426AB6807f84BAa1b", "deployer": "0x5b593E7b1725dc6FcbbFe80b2415B19153F94A85" + }, + "InterchainTokenService": { + "salt": "ITS v1.2.4", + "deployer": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", + "proxySalt": "ITS v1.0.0", + "tokenManagerDeployer": "0x44dDBDD2c6CC9c5e0F4555620c06b1411F99Dc03", + "interchainToken": "0x2f8102DeA2caaee1Ec5Fe67754F828353C4c180F", + "interchainTokenDeployer": "0xCE014b2DCB26d77d4e8206A7EF5e33985E442d38", + "tokenManager": "0x81a0545091864617E7037171FdfcBbdCFE3aeb23", + "tokenHandler": "0x07715674F74c560200c7C95430673180812fCE73", + "implementation": "0x6d59D9360BDAe406614b7E61c53F43a03198A4ef", + "predeployCodehash": "0x08a4a556c4db879b4f24104d13a8baf86915d58b12c81b382dfea2a82d2856cf", + "address": "0xB5FB4BE02232B1bBA4dC8f81dc24C26980dE9e3C" + }, + "InterchainTokenFactory": { + "deployer": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", + "salt": "ITS Factory v1.0.0", + "implementation": "0xA852412D2d91fE05d790934B6E64C3C351fAB54f", + "address": "0x83a93500d23Fbc3e82B410aD07A6a9F7A0670D66" } }, "explorer": { From b1bd789a744e2937605cd2417fc47d885a30cdeb Mon Sep 17 00:00:00 2001 From: Talal Ashraf <talal@interoplabs.io> Date: Thu, 11 Jul 2024 07:47:14 -0400 Subject: [PATCH 11/44] chore: update linea-sepolia with its and multisig (#295) --- axelar-chains-config/info/testnet.json | 42 ++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/axelar-chains-config/info/testnet.json b/axelar-chains-config/info/testnet.json index d6271c23..327bc06f 100644 --- a/axelar-chains-config/info/testnet.json +++ b/axelar-chains-config/info/testnet.json @@ -2019,10 +2019,29 @@ "salt": "Create3Deployer" }, "InterchainGovernance": { - "address": "0x943AAd94e45bad24A3da01a3ba815C03fCAC53FC" + "address": "0xfDF36A30070ea0241d69052ea85ff44Ad0476a66", + "minimumTimeDelay": 300, + "governanceChain": "Axelarnet", + "governanceAddress": "axelar10d07y265gmmuvt4z0w9aw880jnsr700j7v9daj", + "deployer": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", + "deploymentMethod": "create3", + "codehash": "0x4bc0efa16652748f5c3fbb77aedff01e0c1df4156a4f4c82d6d8748ee28cb9af", + "predeployCodehash": "0xe2de43b29f2387b6f3575a1b50d566908fc00e03a8d88ad6be74b674a70874d2", + "salt": "InterchainGovernance v5.5" }, "Multisig": { - "address": "0x943AAd94e45bad24A3da01a3ba815C03fCAC53FC" + "threshold": 2, + "signers": [ + "0x15837c1318AB83d99b19392Fd4811813f520d843", + "0x64247a441CeF0b7A46614AC34d046c0fdfe35954", + "0xEE64c8eb48437DbD2D5B8598dc4A3E8a6c8CEaD9" + ], + "address": "0xCC940AE49C78F20E3F13F3cF37e996b98Ac3EC68", + "deployer": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", + "deploymentMethod": "create3", + "codehash": "0x912095d5076ee40a9dd49c0f9d61d61334c47a78c7512852791652baef26c296", + "predeployCodehash": "0x912095d5076ee40a9dd49c0f9d61d61334c47a78c7512852791652baef26c296", + "salt": "Multisig v5.5" }, "Operators": { "owner": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", @@ -2038,6 +2057,25 @@ "address": "0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6", "implementation": "0xCD6b34FaF1FD1056C728A27426AB6807f84BAa1b", "deployer": "0x5b593E7b1725dc6FcbbFe80b2415B19153F94A85" + }, + "InterchainTokenService": { + "salt": "ITS v1.2.4", + "deployer": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", + "proxySalt": "ITS v1.0.0", + "tokenManagerDeployer": "0x44dDBDD2c6CC9c5e0F4555620c06b1411F99Dc03", + "interchainToken": "0x2f8102DeA2caaee1Ec5Fe67754F828353C4c180F", + "interchainTokenDeployer": "0xCE014b2DCB26d77d4e8206A7EF5e33985E442d38", + "tokenManager": "0x81a0545091864617E7037171FdfcBbdCFE3aeb23", + "tokenHandler": "0x07715674F74c560200c7C95430673180812fCE73", + "implementation": "0x6d59D9360BDAe406614b7E61c53F43a03198A4ef", + "predeployCodehash": "0x08a4a556c4db879b4f24104d13a8baf86915d58b12c81b382dfea2a82d2856cf", + "address": "0xB5FB4BE02232B1bBA4dC8f81dc24C26980dE9e3C" + }, + "InterchainTokenFactory": { + "deployer": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", + "salt": "ITS Factory v1.0.0", + "implementation": "0xA852412D2d91fE05d790934B6E64C3C351fAB54f", + "address": "0x83a93500d23Fbc3e82B410aD07A6a9F7A0670D66" } }, "explorer": { From 6e682dc8af6a8c50765e2fcbbdefe0fdde9a1018 Mon Sep 17 00:00:00 2001 From: haiyizxx <haiyizxx@gmail.com> Date: Fri, 12 Jul 2024 15:21:02 -0400 Subject: [PATCH 12/44] chore: update devnet multisig prover code id (#300) --- axelar-chains-config/info/devnet-amplifier.json | 2 +- axelar-chains-config/info/devnet-verifiers.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/axelar-chains-config/info/devnet-amplifier.json b/axelar-chains-config/info/devnet-amplifier.json index 59e78ead..55b74cfa 100644 --- a/axelar-chains-config/info/devnet-amplifier.json +++ b/axelar-chains-config/info/devnet-amplifier.json @@ -396,7 +396,7 @@ "domainSeparator": "0x598ba04d225cec385d1ce3cf3c9a076af803aa5c614bc0e0d176f04ac8d28f55", "address": "axelar1g6520uhs8u37el40wqngf60z06mjgk6z7nezytd2mxrmh7yesnmsyc0zjw" }, - "codeId": 495, + "codeId": 505, "fantom": { "governanceAddress": "axelar1zlr7e5qf3sz7yf890rkh9tcnu87234k6k7ytd9", "adminAddress": "axelar1zlr7e5qf3sz7yf890rkh9tcnu87234k6k7ytd9", diff --git a/axelar-chains-config/info/devnet-verifiers.json b/axelar-chains-config/info/devnet-verifiers.json index 491ab243..10ccfde8 100644 --- a/axelar-chains-config/info/devnet-verifiers.json +++ b/axelar-chains-config/info/devnet-verifiers.json @@ -490,7 +490,7 @@ "domainSeparator": "0x333e4afab949ca00f9b5daa5a021f942b614c91cb5ced70ded38cd89da2b55ef", "address": "axelar1qt0gkcrvcpv765k8ec4tl2svvg6hd3e3td8pvg2fsncrt3dzjefswsq3w2" }, - "codeId": 42, + "codeId": 48, "fantom": { "governanceAddress": "axelar19vvhwq57656hqfczhxw3r874l29jtd3uns4fsu", "adminAddress": "axelar19vvhwq57656hqfczhxw3r874l29jtd3uns4fsu", From f5d4a3bbd7457f976caca0fa8ce7f76169275efc Mon Sep 17 00:00:00 2001 From: Talal Ashraf <talal@interoplabs.io> Date: Mon, 15 Jul 2024 11:17:08 -0400 Subject: [PATCH 13/44] chore: update nonces for arbitrum mainnet (#298) Co-authored-by: Talal Ashraf <talal@axelar.network> --- .../info/devnet-amplifier.json | 1 + .../info/devnet-verifiers.json | 1 + axelar-chains-config/info/mainnet.json | 1 + axelar-chains-config/info/stagenet.json | 1 + axelar-chains-config/info/testnet.json | 1 + axelar-chains-config/package-lock.json | 9 +++--- axelar-chains-config/package.json | 3 +- axelar-chains-config/tsconfig.json | 1 + evm/.example.keys.json | 1 + evm/legacy/ConstAddressDeployer.json | 1 + evm/nonces.json | 7 +++-- package-lock.json | 29 +++++++++++++++---- package.json | 4 +-- 13 files changed, 44 insertions(+), 16 deletions(-) diff --git a/axelar-chains-config/info/devnet-amplifier.json b/axelar-chains-config/info/devnet-amplifier.json index 55b74cfa..8fe0b0e1 100644 --- a/axelar-chains-config/info/devnet-amplifier.json +++ b/axelar-chains-config/info/devnet-amplifier.json @@ -455,3 +455,4 @@ "gasLimit": "auto" } } + diff --git a/axelar-chains-config/info/devnet-verifiers.json b/axelar-chains-config/info/devnet-verifiers.json index 10ccfde8..c15ddc32 100644 --- a/axelar-chains-config/info/devnet-verifiers.json +++ b/axelar-chains-config/info/devnet-verifiers.json @@ -549,3 +549,4 @@ "gasLimit": "auto" } } + diff --git a/axelar-chains-config/info/mainnet.json b/axelar-chains-config/info/mainnet.json index 61e890e9..1b8ec7f0 100644 --- a/axelar-chains-config/info/mainnet.json +++ b/axelar-chains-config/info/mainnet.json @@ -2350,3 +2350,4 @@ "axelarscanApi": "https://api.axelarscan.io" } } + diff --git a/axelar-chains-config/info/stagenet.json b/axelar-chains-config/info/stagenet.json index e0555542..eaa88190 100644 --- a/axelar-chains-config/info/stagenet.json +++ b/axelar-chains-config/info/stagenet.json @@ -641,3 +641,4 @@ "axelarscanApi": "https://testnet.api.axelarscan.io" } } + diff --git a/axelar-chains-config/info/testnet.json b/axelar-chains-config/info/testnet.json index 327bc06f..bd0d5b8d 100644 --- a/axelar-chains-config/info/testnet.json +++ b/axelar-chains-config/info/testnet.json @@ -2126,3 +2126,4 @@ "axelarscanApi": "https://testnet.api.axelarscan.io" } } + diff --git a/axelar-chains-config/package-lock.json b/axelar-chains-config/package-lock.json index ca24661e..8a3a6e95 100644 --- a/axelar-chains-config/package-lock.json +++ b/axelar-chains-config/package-lock.json @@ -15,7 +15,7 @@ "devDependencies": { "eslint": "^8.49.0", "jsonschema": "^1.4.1", - "prettier": "^3.0.3", + "prettier": "^3.3.2", "typescript": "^5.2.2", "vitest": "^0.34.4" } @@ -1769,9 +1769,9 @@ } }, "node_modules/prettier": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", - "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -2318,3 +2318,4 @@ } } } + diff --git a/axelar-chains-config/package.json b/axelar-chains-config/package.json index dc6ac968..55772c56 100644 --- a/axelar-chains-config/package.json +++ b/axelar-chains-config/package.json @@ -19,7 +19,7 @@ "devDependencies": { "eslint": "^8.49.0", "jsonschema": "^1.4.1", - "prettier": "^3.0.3", + "prettier": "^3.3.2", "typescript": "^5.2.2", "vitest": "^0.34.4" }, @@ -28,3 +28,4 @@ "fs-extra": "^11.1.1" } } + diff --git a/axelar-chains-config/tsconfig.json b/axelar-chains-config/tsconfig.json index e30aecae..09746962 100644 --- a/axelar-chains-config/tsconfig.json +++ b/axelar-chains-config/tsconfig.json @@ -19,3 +19,4 @@ "declarationMap": true } } + diff --git a/evm/.example.keys.json b/evm/.example.keys.json index f08c51e9..a6d17fe5 100644 --- a/evm/.example.keys.json +++ b/evm/.example.keys.json @@ -12,3 +12,4 @@ "private key 2" ] } + diff --git a/evm/legacy/ConstAddressDeployer.json b/evm/legacy/ConstAddressDeployer.json index 94463ed7..bcca9805 100644 --- a/evm/legacy/ConstAddressDeployer.json +++ b/evm/legacy/ConstAddressDeployer.json @@ -131,3 +131,4 @@ "linkReferences": {}, "deployedLinkReferences": {} } + diff --git a/evm/nonces.json b/evm/nonces.json index 159f3ba3..5a48ccee 100644 --- a/evm/nonces.json +++ b/evm/nonces.json @@ -49,12 +49,12 @@ "0x027c1882B975E2cd771AE068b0389FA38B9dda73": 8 }, "arbitrum": { - "0x3f5876a2b06E54949aB106651Ab6694d0289b2b4": 5, + "0x3f5876a2b06E54949aB106651Ab6694d0289b2b4": 6, "0x9256Fd872118ed3a97754B0fB42c15015d17E0CC": 4, "0x1486157d505C7F7E546aD00E3E2Eee25BF665C9b": 3, - "0x2eC991B5c0B742AbD9d2ea31fe6c14a85e91C821": 4, + "0x2eC991B5c0B742AbD9d2ea31fe6c14a85e91C821": 5, "0xf505462A29E36E26f25Ef0175Ca1eCBa09CC118f": 1, - "0x027c1882B975E2cd771AE068b0389FA38B9dda73": 3 + "0x027c1882B975E2cd771AE068b0389FA38B9dda73": 4 }, "celo": { "0x3f5876a2b06E54949aB106651Ab6694d0289b2b4": 3, @@ -164,3 +164,4 @@ } } } + diff --git a/package-lock.json b/package-lock.json index 23ddf9fb..393fc038 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,7 +33,7 @@ "fs-extra": "^11.1.1", "hardhat": "~2.19.5", "mocha": "^10.2.0", - "prettier": "^2.8.7", + "prettier": "^3.3.2", "readline-sync": "^1.4.10" }, "engines": { @@ -9521,15 +9521,15 @@ } }, "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", "dev": true, "bin": { - "prettier": "bin-prettier.js" + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=10.13.0" + "node": ">=14" }, "funding": { "url": "https://github.com/prettier/prettier?sponsor=1" @@ -11469,6 +11469,22 @@ "node": ">=10" } }, + "node_modules/typechain/node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "peer": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/typechain/node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -12350,3 +12366,4 @@ } } } + diff --git a/package.json b/package.json index f4cfc151..e80b4dd6 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "lint": "eslint --fix '**/*.js'", - "prettier": "prettier --write '**/*.js' 'axelar-chains-config/info/*.json' 'package.json' 'evm/**/*.json' '.github/**/*.yaml'" + "prettier": "prettier --write '**/*.js' 'axelar-chains-config/info/*.json' 'package.json' 'evm/**/*.json' '.github/**/*.yaml' && find axelar-chains-config/info evm -name \"*.json\" -type f -print0 | xargs -0 -I {} sh -c 'echo \"\" >> \"{}\"'" }, "repository": { "type": "git", @@ -46,7 +46,7 @@ "fs-extra": "^11.1.1", "hardhat": "~2.19.5", "mocha": "^10.2.0", - "prettier": "^2.8.7", + "prettier": "^3.3.2", "readline-sync": "^1.4.10" }, "engines": { From 04b38873bcc6928c5b99089e958e283923ed7cbc Mon Sep 17 00:00:00 2001 From: Blockchain Guy <ayusht11@outlook.com> Date: Wed, 17 Jul 2024 15:38:42 +0530 Subject: [PATCH 14/44] feat: add script to sign, combine and execute transactions from multisig (#276) Co-authored-by: Talal Ashraf <talal@interoplabs.io> --- sui/README.md | 86 +++++++++++++++++++++++++ sui/multisig.js | 160 ++++++++++++++++++++++++++++++++++++++++++++++ sui/sign-utils.js | 128 +++++++++++++++++++++++++++++++------ 3 files changed, 356 insertions(+), 18 deletions(-) create mode 100644 sui/multisig.js diff --git a/sui/README.md b/sui/README.md index ac6bc965..a1431007 100644 --- a/sui/README.md +++ b/sui/README.md @@ -106,6 +106,92 @@ node sui/gateway.js rotate --signers wallet --proof wallet --currentNonce test - Use the same nonce for `--currentNonce` as the `--nonce` when deploying the gateway. + +### Multisig + +To create a Multisig, follow the documentation [here](https://docs.sui.io/guides/developer/cryptography/multisig). + +Get test SUI coins to your multisig address via a faucet: +```bash +sui client faucet --address <multisig address> +``` + +Get public keys for all wallets: +```bash +sui keytool list +``` + +Get private key of wallet using wallet alias or address: +```bash +sui keytool export --key-identity <alias/wallet address> +``` + +Get tx data for testing: +```bash +sui client transfer-sui --to <recipient address> --amount 1 --sui-coin-object-id <sui coin object id> --serialize-unsigned-transaction --gas-budget 77047880 +``` + +To get sui coin object id +```bash +sui client gas <multisig address> +``` + +Sign transaction block for multisig: + +```bash +node sui/multisig.js --txBlockPath <path to unsigned tx block> --signatureFilePath <path to store signature> --action sign --offline +``` + +example txBlock file: +``` +{ + "bytes": "AAACACBC5cSnnYJrDEn9nSW1BDzPLLAbUJbYOeJnUgYl/b90..." +} +``` + +Combine signature files: + +```bash +node sui/multisig.js --txBlockPath <path to unsigned tx block> --signatureFilePath <path to store combined signature> --action combine --offline --signatures <paths to files containing signatures> +``` + +Execute combined signature: + +This command will broadcast the signature to the network + +```bash +node sui/multisig.js --txBlockPath <path to unsigned tx block> --action execute --combinedSignPath <path to combined signature> +``` + +use --multisigKey `multisigKey` to override existing multisig info in chains config + +example for adding multisig info to chains config: +``` +{ + "sui": { + "name": "Sui", + "axelarId": "sui", + "networkType": "testnet", + "tokenSymbol": "SUI", + "rpc": "https://fullnode.testnet.sui.io:443", + "contracts": {}, + "multisig": { + "threshold": 2, + "signers": [ + { + "publicKey": "AIqrCb324p6Qd4srkqCzn9NJHS7W17tA7r3t7Ur6aYN", + "weight": 1, + "schemeType": "ed25519" + }, + . + . + . + ] + } + } +} +``` + ## Troubleshooting 1. Move build error during the deployment step diff --git a/sui/multisig.js b/sui/multisig.js new file mode 100644 index 00000000..50d390c9 --- /dev/null +++ b/sui/multisig.js @@ -0,0 +1,160 @@ +const { Command, Option } = require('commander'); +const { fromB64 } = require('@mysten/bcs'); +const { addBaseOptions } = require('./cli-utils'); +const { getWallet, getMultisig, signTransactionBlockBytes, broadcastSignature } = require('./sign-utils'); +const { getSignedTx, storeSignedTx } = require('../evm/sign-utils'); +const { loadSuiConfig } = require('./utils'); +const { printInfo, validateParameters } = require('../evm/utils'); + +async function signTx(keypair, client, options) { + const txFileData = getSignedTx(options.txBlockPath); + const txData = txFileData?.bytes; + + validateParameters({ isNonEmptyString: { txData } }); + + const encodedTxBytes = fromB64(txData); + + const { signature, publicKey } = await signTransactionBlockBytes(keypair, client, encodedTxBytes, options); + return { signature, publicKey, txBytes: txData }; +} + +async function executeCombinedSignature(client, options) { + const { combinedSignPath } = options; + + if (options.offline) { + throw new Error('Cannot execute in offline mode'); + } + + if (!combinedSignPath) { + throw new Error('Invalid filePath provided'); + } + + const fileData = getSignedTx(combinedSignPath); + const txData = fileData.txBytes; + + validateParameters({ isNonEmptyString: { txData } }); + + const encodedTxBytes = fromB64(txData); + const combinedSignatureBytes = fileData.signature; + + if (!combinedSignatureBytes) { + throw new Error(`No signature specified in [${combinedSignPath}]`); + } + + const txResult = await broadcastSignature(client, encodedTxBytes, combinedSignatureBytes); + printInfo('Transaction result', JSON.stringify(txResult)); + + fileData.status = 'EXECUTED'; + storeSignedTx(combinedSignPath, fileData); +} + +async function combineSignature(client, chain, options) { + const { signatures } = options; + + if (!signatures || signatures.length === 0) { + throw new Error('FilePath is not provided in user info'); + } + + const multiSigPublicKey = await getMultisig(chain, options.multisigKey); + const signatureArray = []; + + const firstSignData = getSignedTx(signatures[0]); + const txBytes = firstSignData.txBytes; + + for (const file of signatures) { + const fileData = getSignedTx(file); + + if (fileData.txBytes !== txBytes) { + throw new Error(`Transaction bytes mismatch with file [${file}]`); + } + + signatureArray.push(fileData.signature); + } + + const txBlockBytes = fromB64(txBytes); + + const combinedSignature = multiSigPublicKey.combinePartialSignatures(signatureArray); + const isValid = await multiSigPublicKey.verifyTransactionBlock(txBlockBytes, combinedSignature); + + if (!isValid) { + throw new Error(`Verification failed for message [${txBytes}]`); + } + + if (!options.offline) { + const txResult = await broadcastSignature(client, txBlockBytes, combinedSignature); + printInfo('Transaction result', JSON.stringify(txResult)); + } else { + const data = { + signature: combinedSignature, + status: 'PENDING', + txBytes, + }; + return data; + } +} + +async function processCommand(chain, options) { + const [keypair, client] = getWallet(chain, options); + printInfo('Wallet Address', keypair.toSuiAddress()); + + let fileData; + + switch (options.action) { + case 'sign': { + fileData = await signTx(keypair, client, options); + break; + } + + case 'combine': { + fileData = await combineSignature(client, chain, options); + break; + } + + case 'execute': { + await executeCombinedSignature(client, options); + break; + } + + default: { + throw new Error(`Invalid action provided [${options.action}]`); + } + } + + if (options.offline) { + const { signatureFilePath } = options; + + if (!signatureFilePath) { + throw new Error('No filePath provided'); + } + + storeSignedTx(signatureFilePath, fileData); + printInfo(`The signed signature is`, fileData.signature); + } +} + +async function mainProcessor(options, processor) { + const config = loadSuiConfig(options.env); + await processor(config.sui, options); +} + +if (require.main === module) { + const program = new Command(); + + program.name('multisig').description('Script for multisig operators to sign, combine and execute data'); + + addBaseOptions(program); + + program.addOption(new Option('--txBlockPath <file>', 'path to unsigned tx block')); + program.addOption(new Option('--action <action>', 'action').choices(['sign', 'combine', 'execute']).makeOptionMandatory(true)); + program.addOption(new Option('--multisigKey <multisigKey>', 'multisig key').env('MULTISIG_KEY')); + program.addOption(new Option('--signatures [files...]', 'array of signed transaction files')); + program.addOption(new Option('--offline', 'run in offline mode')); + program.addOption(new Option('--combinedSignPath <file>', 'combined signature file path')); + program.addOption(new Option('--signatureFilePath <file>', 'signed signature will be stored')); + + program.action((options) => { + mainProcessor(options, processCommand); + }); + + program.parse(); +} diff --git a/sui/sign-utils.js b/sui/sign-utils.js index ca732209..34e67033 100644 --- a/sui/sign-utils.js +++ b/sui/sign-utils.js @@ -2,11 +2,17 @@ const { verifyTransactionBlock } = require('@mysten/sui.js/verify'); const { decodeSuiPrivateKey } = require('@mysten/sui.js/cryptography'); -const { Ed25519Keypair } = require('@mysten/sui.js/keypairs/ed25519'); -const { Secp256k1Keypair } = require('@mysten/sui.js/keypairs/secp256k1'); -const { Secp256r1Keypair } = require('@mysten/sui.js/keypairs/secp256r1'); -const { printInfo } = require('../evm/utils'); +const { Ed25519Keypair, Ed25519PublicKey } = require('@mysten/sui.js/keypairs/ed25519'); +const { MultiSigPublicKey } = require('@mysten/sui.js/multisig'); +const { Secp256k1Keypair, Secp256k1PublicKey } = require('@mysten/sui.js/keypairs/secp256k1'); +const { Secp256r1Keypair, Secp256r1PublicKey } = require('@mysten/sui.js/keypairs/secp256r1'); const { SuiClient, getFullnodeUrl } = require('@mysten/sui.js/client'); +const { fromB64, fromHEX } = require('@mysten/bcs'); +const { printInfo } = require('../evm/utils'); +const { ethers } = require('hardhat'); +const { + utils: { hexlify }, +} = ethers; function getWallet(chain, options) { let keypair; @@ -101,12 +107,19 @@ async function broadcast(client, keypair, tx) { }); } -async function signTransactionBlock(chain, txDetails, options) { - const { txBlock, buildOptions = {} } = txDetails; +async function broadcastSignature(client, txBytes, signature) { + return await client.executeTransactionBlock({ + transactionBlock: txBytes, + signature, + options: { + showEffects: true, + showObjectChanges: true, + showEvents: true, + }, + }); +} - const [keypair, client] = getWallet(chain, options); - txBlock.setSenderIfNotSet(keypair.toSuiAddress()); - const txBytes = await txBlock.build(buildOptions); +async function signTransactionBlockBytes(keypair, client, txBytes, options) { const serializedSignature = (await keypair.signTransactionBlock(txBytes)).signature; let publicKey; @@ -121,19 +134,94 @@ async function signTransactionBlock(chain, txDetails, options) { } if (!options.offline) { - const txResult = await client.executeTransactionBlock({ - transactionBlock: txBytes, + const txResult = await broadcastSignature(client, txBytes, serializedSignature); + printInfo('Transaction result', JSON.stringify(txResult)); + } else { + const hexPublicKey = hexlify(publicKey.toRawBytes()); + return { signature: serializedSignature, - }); + publicKey: hexPublicKey, + }; + } +} - printInfo('Transaction result', JSON.stringify(txResult)); +async function signTransactionBlock(chain, txDetails, options) { + const { txBlock, buildOptions = {} } = txDetails; + + const [keypair, client] = getWallet(chain, options); + txBlock.setSenderIfNotSet(keypair.toSuiAddress()); + const txBytes = await txBlock.build(buildOptions); + + const result = await signTransactionBlockBytes(keypair, client, txBytes, options); + result.txBytes = txBytes; + + return result; +} + +async function getWrappedPublicKey(bech64PublicKey, schemeType) { + const uint8PubKey = fromB64(bech64PublicKey).slice(1); + + switch (schemeType) { + case 'ed25519': { + return new Ed25519PublicKey(uint8PubKey); + } + + case 'secp256k1': { + return new Secp256k1PublicKey(uint8PubKey); + } + + case 'secp256r1': { + return new Secp256r1PublicKey(uint8PubKey); + } + + default: { + throw new Error(`Unsupported signature scheme: ${schemeType}`); + } } +} + +async function getMultisig(config, multisigKey) { + let multiSigPublicKey; + + if (multisigKey) { + multiSigPublicKey = new MultiSigPublicKey(fromHEX(multisigKey)); + } else { + const signers = config.multisig?.signers; + + if (!signers || signers.length === 0) { + throw new Error('Signers not provided in configuration'); + } + + const publicKeys = []; + + for (const signer of signers) { + if (!signer?.publicKey) { + throw new Error('PublicKey not found'); + } + + if (!signer?.schemeType) { + throw new Error('SchemeType not found'); + } + + if (!signer?.weight) { + throw new Error('Weight not found'); + } + + publicKeys.push({ + publicKey: await getWrappedPublicKey(signer.publicKey, signer.schemeType), + weight: signer.weight, + }); + } + + multiSigPublicKey = MultiSigPublicKey.fromPublicKeys({ + threshold: config.multisig?.threshold, + publicKeys, + }); + } + + printInfo('Multisig Wallet Address', multiSigPublicKey.toSuiAddress()); - return { - signature: serializedSignature, - txBlock, - publicKey, - }; + return multiSigPublicKey; } module.exports = { @@ -142,5 +230,9 @@ module.exports = { generateKeypair, getRawPrivateKey, broadcast, + broadcastSignature, signTransactionBlock, + getMultisig, + getWrappedPublicKey, + signTransactionBlockBytes, }; From b147520a4d3b7c15988c09632ec492ea3cad6af7 Mon Sep 17 00:00:00 2001 From: npty <78221556+npty@users.noreply.github.com> Date: Thu, 18 Jul 2024 15:34:24 +0700 Subject: [PATCH 15/44] feat: script to deploy gas service (#261) Co-authored-by: Milap Sheth <milap@interoplabs.io> --- sui/README.md | 7 ++++ sui/deploy-contract.js | 75 ++++++++++++++++++++++++++++++++++++++++++ sui/utils.js | 6 ++++ 3 files changed, 88 insertions(+) create mode 100644 sui/deploy-contract.js diff --git a/sui/README.md b/sui/README.md index a1431007..87897d3c 100644 --- a/sui/README.md +++ b/sui/README.md @@ -33,6 +33,7 @@ If you want to run against a local Sui network, then create a `axelar-chains-con "networkType": "localnet", "tokenSymbol": "SUI", "rpc": "http://127.0.0.1:9000", + "faucetUrl": "http://127.0.0.1:9123", "contracts": {} } } @@ -70,6 +71,12 @@ node sui/deploy-gateway.js --signers wallet --nonce test node sui/deploy-gateway.js -e testnet --signers '{"signers": [{"pubkey": "0x020194ead85b350d90472117e6122cf1764d93bf17d6de4b51b03d19afc4d6302b", "weight": 1}], "threshold": 1, "nonce": "0x0000000000000000000000000000000000000000000000000000000000000000"}' ``` +Deploy the Gas Service package: + +```bash +node sui/deploy-contract.js GasService +``` + Deploy the test GMP package: ```bash diff --git a/sui/deploy-contract.js b/sui/deploy-contract.js new file mode 100644 index 00000000..8692bf1b --- /dev/null +++ b/sui/deploy-contract.js @@ -0,0 +1,75 @@ +const { saveConfig, printInfo } = require('../evm/utils'); +const { Command, Argument, Option } = require('commander'); +const { publishPackage, updateMoveToml } = require('@axelar-network/axelar-cgp-sui/scripts/publish-package'); + +const { addBaseOptions } = require('./cli-utils'); +const { getWallet, printWalletInfo } = require('./sign-utils'); +const { loadSuiConfig, findPublishedObject } = require('./utils'); + +// Add more contracts here to support more modules deployment +const contractMap = { + GasService: { + packageName: 'gas_service', + }, +}; + +async function processCommand(contractName, config, chain, options) { + const contract = contractMap[contractName]; + const packageName = options.packageName || contract.packageName; + + const [keypair, client] = getWallet(chain, options); + + await printWalletInfo(keypair, client, chain, options); + + if (!chain.contracts[contractName]) { + chain.contracts[contractName] = {}; + } + + const published = await publishPackage(packageName, client, keypair); + const packageId = published.packageId; + + updateMoveToml(packageName, packageId); + + const contractObject = findPublishedObject(published, packageName, contractName); + const gasCollectorCapObject = findPublishedObject(published, packageName, 'GasCollectorCap'); + + const contractConfig = chain.contracts[contractName]; + contractConfig.address = packageId; + contractConfig.objects = { + [contractName]: contractObject.objectId, + }; + + switch (contractName) { + case 'GasService': + contractConfig.objects.GasCollectorCap = gasCollectorCapObject.objectId; + break; + default: + throw new Error(`${contractName} is not supported.`); + } + + printInfo(`${contractName} deployed`, JSON.stringify(contractConfig, null, 2)); +} + +async function mainProcessor(contractName, options, processor) { + const config = loadSuiConfig(options.env); + await processor(contractName, config, config.sui, options); + saveConfig(config, options.env); +} + +if (require.main === module) { + const program = new Command(); + + program + .name('deploy-contract') + .addOption(new Option('--packageName <packageName>', 'Package name to deploy')) + .addArgument(new Argument('<contractName>', 'Contract name to deploy').choices(Object.keys(contractMap))) + .description('Deploy SUI modules'); + + addBaseOptions(program); + + program.action((contractName, options) => { + mainProcessor(contractName, options, processCommand); + }); + + program.parse(); +} diff --git a/sui/utils.js b/sui/utils.js index ea857e6e..295aeb01 100644 --- a/sui/utils.js +++ b/sui/utils.js @@ -48,7 +48,13 @@ const loadSuiConfig = (env) => { return config; }; +const findPublishedObject = (published, packageName, contractName) => { + const packageId = published.packageId; + return published.publishTxn.objectChanges.find((change) => change.objectType === `${packageId}::${packageName}::${contractName}`); +}; + module.exports = { getAmplifierSigners, loadSuiConfig, + findPublishedObject, }; From 2ffd250b5aa82978e3d21d68d443d4555e6ddc9e Mon Sep 17 00:00:00 2001 From: CJ Cobb <46455409+cjcobb23@users.noreply.github.com> Date: Thu, 18 Jul 2024 02:54:15 -0600 Subject: [PATCH 16/44] chore: update router code id in devnet configs (#305) Co-authored-by: Milap Sheth <milap@interoplabs.io> --- axelar-chains-config/info/devnet-amplifier.json | 2 +- axelar-chains-config/info/devnet-verifiers.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/axelar-chains-config/info/devnet-amplifier.json b/axelar-chains-config/info/devnet-amplifier.json index 8fe0b0e1..ddf9f00b 100644 --- a/axelar-chains-config/info/devnet-amplifier.json +++ b/axelar-chains-config/info/devnet-amplifier.json @@ -277,7 +277,7 @@ "Router": { "adminAddress": "axelar1zlr7e5qf3sz7yf890rkh9tcnu87234k6k7ytd9", "governanceAddress": "axelar1zlr7e5qf3sz7yf890rkh9tcnu87234k6k7ytd9", - "codeId": 498, + "codeId": 509, "address": "axelar14jjdxqhuxk803e9pq64w4fgf385y86xxhkpzswe9crmu6vxycezst0zq8y" }, "Multisig": { diff --git a/axelar-chains-config/info/devnet-verifiers.json b/axelar-chains-config/info/devnet-verifiers.json index c15ddc32..99c60685 100644 --- a/axelar-chains-config/info/devnet-verifiers.json +++ b/axelar-chains-config/info/devnet-verifiers.json @@ -371,7 +371,7 @@ "Router": { "adminAddress": "axelar19vvhwq57656hqfczhxw3r874l29jtd3uns4fsu", "governanceAddress": "axelar19vvhwq57656hqfczhxw3r874l29jtd3uns4fsu", - "codeId": 45, + "codeId": 49, "address": "axelar1q3g7fdqfpftqfpuakwn7x037k80wv35jj9ged7v5e798pds7hnasgj6azz" }, "Multisig": { From 00c1b9b4cb25c239c4ced0bd8ead0587e3ca2940 Mon Sep 17 00:00:00 2001 From: Milap Sheth <milap@interoplabs.io> Date: Thu, 18 Jul 2024 05:18:16 -0400 Subject: [PATCH 17/44] fix(evm): support create3 deployed address prediction (#302) --- evm/deploy-amplifier-gateway.js | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/evm/deploy-amplifier-gateway.js b/evm/deploy-amplifier-gateway.js index 89ee6b7c..2c9c4a54 100644 --- a/evm/deploy-amplifier-gateway.js +++ b/evm/deploy-amplifier-gateway.js @@ -7,7 +7,7 @@ const { ContractFactory, Contract, Wallet, - utils: { defaultAbiCoder, getContractAddress, keccak256, hexlify }, + utils: { defaultAbiCoder, keccak256, hexlify }, getDefaultProvider, } = ethers; @@ -26,6 +26,8 @@ const { getContractConfig, isString, getWeightedSigners, + getContractJSON, + getDeployedAddress, } = require('./utils'); const { calculateDomainSeparator, isValidCosmosAddress } = require('../cosmwasm/utils'); const { addExtendedOptions } = require('./cli-utils'); @@ -107,7 +109,7 @@ async function deploy(config, chain, options) { if (owner !== wallet.address) { printWarn( - 'Governance address is not set to the wallet address. This is needed for official deployment and is transferred after deployment', + 'Owner address is not set to the wallet address. This is needed for official deployment and is transferred after deployment', ); } @@ -120,6 +122,7 @@ async function deploy(config, chain, options) { const deployerContract = options.deployMethod === 'create3' ? chain.contracts.Create3Deployer?.address : chain.contracts.ConstAddressDeployer?.address; + const salt = options.salt || 'AxelarAmplifierGateway'; let gateway; let proxyAddress; @@ -134,11 +137,20 @@ async function deploy(config, chain, options) { printInfo('Reusing Gateway Proxy address', proxyAddress); gateway = gatewayFactory.attach(proxyAddress); } else { - const transactionCount = await wallet.getTransactionCount(); - proxyAddress = getContractAddress({ - from: wallet.address, - nonce: transactionCount + 1, + if (options.deployMethod === 'create2') { + // TODO: support create2 prediction + printError('create2 prediction is not supported yet'); + } + + proxyAddress = await getDeployedAddress(wallet.address, options.deployMethod, { + salt, + deployerContract, + contractJson: getContractJSON('AxelarAmplifierGatewayProxy'), + constructorArgs: [], // TODO: populate constructor args for create2 prediction to work + provider: wallet.provider, + nonce: (await wallet.getTransactionCount()) + 1, }); + printInfo('Predicted gateway proxy address', proxyAddress, chalk.cyan); } @@ -155,6 +167,7 @@ async function deploy(config, chain, options) { if (existingAddress !== undefined && proxyAddress !== existingAddress) { printWarn(`Predicted address ${proxyAddress} does not match existing deployment ${existingAddress} in chain configs.`); printWarn('For official deployment, recheck the deployer, salt, args, or contract bytecode.'); + printWarn('This is NOT required if the deployments are done by different integrators'); } if (predictOnly || prompt(`Does derived address match existing gateway deployments? Proceed with deployment on ${chain.name}?`, yes)) { @@ -164,7 +177,6 @@ async function deploy(config, chain, options) { contractConfig.deployer = wallet.address; const domainSeparator = await getDomainSeparator(config, chain, options); const minimumRotationDelay = Number(options.minimumRotationDelay); - const salt = options.salt || 'AxelarAmplifierGateway'; printInfo(`Deploying gateway implementation contract`); printInfo('Gateway Implementation args', `${options.previousSignersRetention}, ${domainSeparator}, ${minimumRotationDelay}`); @@ -235,7 +247,7 @@ async function deploy(config, chain, options) { printInfo(`Existing owner`, ownerAddress); if (!reuseProxy && owner !== ownerAddress) { - printError(`ERROR: Retrieved governance address is different:`); + printError(`ERROR: Retrieved owner address is different:`); printError(` Actual: ${ownerAddress}`); printError(` Expected: ${owner}`); error = true; From 837621b212af765bf332755bcf5aa1e85c529b49 Mon Sep 17 00:00:00 2001 From: npty <78221556+npty@users.noreply.github.com> Date: Thu, 18 Jul 2024 16:23:00 +0700 Subject: [PATCH 18/44] feat: add gas service commands (#296) --- sui/README.md | 16 +++- sui/amount-utils.js | 16 ++++ sui/cli-utils.js | 28 +++++- sui/gas-service.js | 219 ++++++++++++++++++++++++++++++++++++++++++++ sui/types-utils.js | 12 +++ sui/utils.js | 14 +++ 6 files changed, 300 insertions(+), 5 deletions(-) create mode 100644 sui/amount-utils.js create mode 100644 sui/gas-service.js diff --git a/sui/README.md b/sui/README.md index 87897d3c..4fb3e275 100644 --- a/sui/README.md +++ b/sui/README.md @@ -51,7 +51,7 @@ node sui/faucet.js Deploy the gateway package: -- By querying the signer set from the Amplifier contract (this only works if Amplifier contracts have been setup): +- By querying the signer set from the Amplifier contract (this only works if Amplifier contracts have been setup): ```bash node sui/deploy-gateway.js @@ -59,13 +59,13 @@ node sui/deploy-gateway.js Use `--help` flag to see other setup params that can be overridden. -- For testing convenience, you can use the secp256k1 wallet as the signer set for the gateway. +- For testing convenience, you can use the secp256k1 wallet as the signer set for the gateway. ```bash node sui/deploy-gateway.js --signers wallet --nonce test ``` -- You can also provide a JSON object with a full signer set: +- You can also provide a JSON object with a full signer set: ```bash node sui/deploy-gateway.js -e testnet --signers '{"signers": [{"pubkey": "0x020194ead85b350d90472117e6122cf1764d93bf17d6de4b51b03d19afc4d6302b", "weight": 1}], "threshold": 1, "nonce": "0x0000000000000000000000000000000000000000000000000000000000000000"}' @@ -89,6 +89,14 @@ Call Contract: node sui/gateway.js call-contract ethereum 0xba76c6980428A0b10CFC5d8ccb61949677A61233 0x1234 ``` +Pay for gas: + +The syntax is `node sui/gas-service.js payGas --amount <amount> <destinationChain> <destinationAddress> <channelId> <payload>` + +```bash +node sui/gas-service.js payGas --amount 0.1 ethereum 0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05 0xba76c6980428A0b10CFC5d8ccb61949677A61233 0x1234 +``` + Approve messages: If the gateway was deployed using the wallet, you can submit a message approval with it @@ -189,7 +197,7 @@ example for adding multisig info to chains config: "publicKey": "AIqrCb324p6Qd4srkqCzn9NJHS7W17tA7r3t7Ur6aYN", "weight": 1, "schemeType": "ed25519" - }, + }, . . . diff --git a/sui/amount-utils.js b/sui/amount-utils.js new file mode 100644 index 00000000..8fa5bfee --- /dev/null +++ b/sui/amount-utils.js @@ -0,0 +1,16 @@ +const { ethers } = require('ethers'); + +// Convert formatted amount to atomic units (e.g. 1000000000). Default decimals is 9 for SUI +function getUnitAmount(amount, decimals = 9) { + return ethers.utils.parseUnits(amount, decimals).toBigInt(); +} + +// Convert atomic amount to formatted units (e.g. 1.0) with decimals. Default decimals is 9 for SUI +function getFormattedAmount(amount, decimals = 9) { + return ethers.utils.formatUnits(amount, decimals); +} + +module.exports = { + getUnitAmount, + getFormattedAmount, +}; diff --git a/sui/cli-utils.js b/sui/cli-utils.js index 1ef5569b..d36d9712 100644 --- a/sui/cli-utils.js +++ b/sui/cli-utils.js @@ -2,7 +2,8 @@ require('dotenv').config(); -const { Option } = require('commander'); +const { Option, InvalidArgumentError } = require('commander'); +const { getUnitAmount } = require('./amount-utils'); const addBaseOptions = (program, options = {}) => { program.addOption( @@ -51,7 +52,32 @@ const addExtendedOptions = (program, options = {}) => { return program; }; +// `optionMethod` is a method such as `addBaseOptions` +// `options` is an option object for optionMethod +const addOptionsToCommands = (program, optionMethod, options) => { + if (program.commands.length > 0) { + program.commands.forEach((command) => { + optionMethod(command, options); + }); + } + + optionMethod(program, options); +}; + +// Custom option processing for amount. https://github.com/tj/commander.js?tab=readme-ov-file#custom-option-processing +// The user is expected to pass a full amount (e.g. 1.0), and this option parser will convert it to smallest units (e.g. 1000000000). +// Note that this function will use decimals of 9 for SUI. So, other tokens with different decimals will not work. +const parseSuiUnitAmount = (value, previous) => { + try { + return getUnitAmount(value); + } catch (error) { + throw new InvalidArgumentError('Please use the correct format (e.g. 1.0)'); + } +}; + module.exports = { addBaseOptions, addExtendedOptions, + addOptionsToCommands, + parseSuiUnitAmount, }; diff --git a/sui/gas-service.js b/sui/gas-service.js new file mode 100644 index 00000000..fec7fb5f --- /dev/null +++ b/sui/gas-service.js @@ -0,0 +1,219 @@ +const { saveConfig, printInfo, printError } = require('../evm/utils'); +const { Command } = require('commander'); +const { TransactionBlock } = require('@mysten/sui.js/transactions'); +const { bcs } = require('@mysten/sui.js/bcs'); +const { gasServiceStruct } = require('./types-utils'); +const { loadSuiConfig, getBcsBytesByObjectId } = require('./utils'); +const { ethers } = require('hardhat'); +const { getFormattedAmount } = require('./amount-utils'); +const { + utils: { arrayify }, +} = ethers; + +const { addOptionsToCommands, addBaseOptions, parseSuiUnitAmount } = require('./cli-utils'); +const { getWallet, printWalletInfo, broadcast } = require('./sign-utils'); + +async function payGas(keypair, client, gasServiceConfig, args, options) { + const walletAddress = keypair.toSuiAddress(); + + const gasServicePackageId = gasServiceConfig.address; + + const refundAddress = options.refundAddress || walletAddress; + const params = options.params || '0x'; + + const [destinationChain, destinationAddress, channelId, payload] = args; + const unitAmount = options.amount; + + const tx = new TransactionBlock(); + const [coin] = tx.splitCoins(tx.gas, [unitAmount]); + + tx.moveCall({ + target: `${gasServicePackageId}::gas_service::pay_gas`, + arguments: [ + tx.object(gasServiceConfig.objects.GasService), + coin, // Coin<SUI> + tx.pure.address(channelId), // Channel address + tx.pure(bcs.string().serialize(destinationChain).toBytes()), // Destination chain + tx.pure(bcs.string().serialize(destinationAddress).toBytes()), // Destination address + tx.pure(bcs.vector(bcs.u8()).serialize(arrayify(payload)).toBytes()), // Payload + tx.pure.address(refundAddress), // Refund address + tx.pure(bcs.vector(bcs.u8()).serialize(arrayify(params)).toBytes()), // Params + ], + }); + + const receipt = await broadcast(client, keypair, tx); + + printInfo('Gas paid', receipt.digest); +} + +async function addGas(keypair, client, gasServiceConfig, args, options) { + const walletAddress = keypair.toSuiAddress(); + + const gasServicePackageId = gasServiceConfig.address; + + const refundAddress = options.refundAddress || walletAddress; + const params = options.params || '0x'; + + const [messageId] = args; + const unitAmount = options.amount; + + const tx = new TransactionBlock(); + const [coin] = tx.splitCoins(tx.gas, [unitAmount]); + + tx.moveCall({ + target: `${gasServicePackageId}::gas_service::add_gas`, + arguments: [ + tx.object(gasServiceConfig.objects.GasService), + coin, // Coin<SUI> + tx.pure(bcs.string().serialize(messageId).toBytes()), // Message ID for the contract call + tx.pure.address(refundAddress), // Refund address + tx.pure(bcs.vector(bcs.u8()).serialize(arrayify(params)).toBytes()), // Params + ], + }); + + const receipt = await broadcast(client, keypair, tx); + + printInfo('Gas added', receipt.digest); +} + +async function collectGas(keypair, client, gasServiceConfig, args, options) { + const walletAddress = keypair.toSuiAddress(); + + const gasServicePackageId = gasServiceConfig.address; + const gasServiceObjectId = gasServiceConfig.objects.GasService; + + const unitAmount = options.amount; + const receiver = options.receiver || walletAddress; + + const bytes = await getBcsBytesByObjectId(client, gasServiceObjectId); + const { balance: gasServiceBalance } = gasServiceStruct.parse(bytes); + + // Check if the gas service balance is sufficient + if (gasServiceBalance < unitAmount) { + printError('Insufficient gas service balance', `${getFormattedAmount(gasServiceBalance)} < ${getFormattedAmount(unitAmount)}`); + return; + } + + const tx = new TransactionBlock(); + + tx.moveCall({ + target: `${gasServicePackageId}::gas_service::collect_gas`, + arguments: [ + tx.object(gasServiceConfig.objects.GasService), + tx.object(gasServiceConfig.objects.GasCollectorCap), + tx.pure.address(receiver), // Receiver address + tx.pure.u64(unitAmount), // Amount + ], + }); + + const receipt = await broadcast(client, keypair, tx); + + printInfo('Gas collected', receipt.digest); +} + +async function refund(keypair, client, gasServiceConfig, args, options) { + const walletAddress = keypair.toSuiAddress(); + + const gasServicePackageId = gasServiceConfig.address; + const gasServiceObjectId = gasServiceConfig.objects.GasService; + + const [messageId] = args; + const unitAmount = options.amount; + const receiver = options.receiver || walletAddress; + + const bytes = await getBcsBytesByObjectId(client, gasServiceObjectId); + const { balance: gasServiceBalance } = gasServiceStruct.parse(bytes); + + // Check if the gas service balance is sufficient + if (gasServiceBalance < unitAmount) { + printError('Insufficient gas service balance', `${getFormattedAmount(gasServiceBalance)} < ${getFormattedAmount(unitAmount)}`); + return; + } + + const tx = new TransactionBlock(); + tx.moveCall({ + target: `${gasServicePackageId}::gas_service::refund`, + arguments: [ + tx.object(gasServiceConfig.objects.GasService), + tx.object(gasServiceConfig.objects.GasCollectorCap), + tx.pure(bcs.string().serialize(messageId).toBytes()), // Message ID for the contract call + tx.pure.address(receiver), // Refund address + tx.pure.u64(unitAmount), // Amount + ], + }); + + const receipt = await broadcast(client, keypair, tx); + + printInfo('Gas refunded', receipt.digest); +} + +async function processCommand(command, chain, args, options) { + const [keypair, client] = getWallet(chain, options); + + await printWalletInfo(keypair, client, chain, options); + + if (!chain.contracts.GasService) { + throw new Error('GasService contract not found'); + } + + await command(keypair, client, chain.contracts.GasService, args, options); +} + +async function mainProcessor(options, args, processor, command) { + const config = loadSuiConfig(options.env); + await processor(command, config.sui, args, options); + saveConfig(config, options.env); +} + +if (require.main === module) { + const program = new Command(); + + program.name('gas-service').description('Interact with the gas service contract.'); + + const payGasCmd = new Command() + .command('payGas <destinationChain> <destinationAddress> <channelId> <payload>') + .description('Pay gas for the new contract call.') + .option('--refundAddress <refundAddress>', 'Refund address. Default is the sender address.') + .requiredOption('--amount <amount>', 'Amount to pay gas', parseSuiUnitAmount) + .option('--params <params>', 'Params. Default is empty.') + .action((destinationChain, destinationAddress, channelId, payload, options) => { + mainProcessor(options, [destinationChain, destinationAddress, channelId, payload], processCommand, payGas); + }); + + const addGasCmd = new Command() + .command('addGas <message_id>') + .description('Add gas for the existing contract call.') + .option('--refundAddress <refundAddress>', 'Refund address.') + .requiredOption('--amount <amount>', 'Amount to add gas', parseSuiUnitAmount) + .option('--params <params>', 'Params. Default is empty.') + .action((messageId, options) => { + mainProcessor(options, [messageId], processCommand, addGas); + }); + + const collectGasCmd = new Command() + .command('collectGas') + .description('Collect gas from the gas service contract.') + .option('--receiver <receiver>', 'Receiver address. Default is the sender address.') + .requiredOption('--amount <amount>', 'Amount to collect gas', parseSuiUnitAmount) + .action((options) => { + mainProcessor(options, [], processCommand, collectGas); + }); + + const refundCmd = new Command() + .command('refund <messageId>') + .description('Refund gas from the gas service contract.') + .option('--receiver <receiver>', 'Receiver address. Default is the sender address.') + .requiredOption('--amount <amount>', 'Amount to refund gas', parseSuiUnitAmount) + .action((messageId, options) => { + mainProcessor(options, [messageId], processCommand, refund); + }); + + program.addCommand(payGasCmd); + program.addCommand(addGasCmd); + program.addCommand(collectGasCmd); + program.addCommand(refundCmd); + + addOptionsToCommands(program, addBaseOptions); + + program.parse(); +} diff --git a/sui/types-utils.js b/sui/types-utils.js index 8a2d38bb..5f2c0a4b 100644 --- a/sui/types-utils.js +++ b/sui/types-utils.js @@ -1,6 +1,7 @@ 'use strict'; const { bcs } = require('@mysten/sui.js/bcs'); +const { fromHEX, toHEX } = require('@mysten/bcs'); const { ethers } = require('hardhat'); const { utils: { arrayify, hexlify }, @@ -21,6 +22,11 @@ const bytes32Struct = bcs.fixedArray(32, bcs.u8()).transform({ output: (id) => hexlify(id), }); +const UID = bcs.fixedArray(32, bcs.u8()).transform({ + input: (id) => fromHEX(id), + output: (id) => toHEX(Uint8Array.from(id)), +}); + const signersStruct = bcs.struct('WeightedSigners', { signers: bcs.vector(signerStruct), threshold: bcs.u128(), @@ -46,6 +52,11 @@ const proofStruct = bcs.struct('Proof', { signatures: bcs.vector(bcs.vector(bcs.u8())), }); +const gasServiceStruct = bcs.struct('GasService', { + id: UID, + balance: bcs.u64(), +}); + module.exports = { addressStruct, signerStruct, @@ -54,4 +65,5 @@ module.exports = { messageToSignStruct, messageStruct, proofStruct, + gasServiceStruct, }; diff --git a/sui/utils.js b/sui/utils.js index 295aeb01..03d2de1b 100644 --- a/sui/utils.js +++ b/sui/utils.js @@ -6,6 +6,7 @@ const { BigNumber, utils: { arrayify, hexlify }, } = ethers; +const { fromB64 } = require('@mysten/bcs'); const { CosmWasmClient } = require('@cosmjs/cosmwasm-stargate'); const getAmplifierSigners = async (config, chain) => { @@ -31,6 +32,18 @@ const getAmplifierSigners = async (config, chain) => { }; }; +// Given sui client and object id, return the base64-decoded object bcs bytes +const getBcsBytesByObjectId = async (client, objectId) => { + const response = await client.getObject({ + id: objectId, + options: { + showBcs: true, + }, + }); + + return fromB64(response.data.bcs.bcsBytes); +}; + const loadSuiConfig = (env) => { const config = loadConfig(env); const suiEnv = env === 'local' ? 'localnet' : env; @@ -55,6 +68,7 @@ const findPublishedObject = (published, packageName, contractName) => { module.exports = { getAmplifierSigners, + getBcsBytesByObjectId, loadSuiConfig, findPublishedObject, }; From 8572a94db3f12044f0747c89f1a25fa0ff930b4c Mon Sep 17 00:00:00 2001 From: Foivos <foivos@umich.edu> Date: Thu, 18 Jul 2024 18:53:13 +0300 Subject: [PATCH 19/44] feat: add sui copy package util (#303) Co-authored-by: blockchainguyy <ayusht11@outlook.com> --- .gitignore | 3 + package-lock.json | 1040 ++++++++++++++++------------------------- package.json | 3 +- sui/deploy-gateway.js | 14 +- sui/deploy-test.js | 6 +- sui/deploy-utils.js | 177 +++++++ sui/utils.js | 17 + 7 files changed, 602 insertions(+), 658 deletions(-) create mode 100644 sui/deploy-utils.js diff --git a/.gitignore b/.gitignore index 53997b1f..e1981793 100644 --- a/.gitignore +++ b/.gitignore @@ -112,3 +112,6 @@ local.json keys.json temp-arguments.js + +# Sui Move Packages +sui/move \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 393fc038..227f614a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,11 +11,12 @@ "dependencies": { "@0xpolygonhermez/zkevm-commonjs": "github:0xpolygonhermez/zkevm-commonjs#v1.0.0", "@axelar-network/axelar-cgp-solidity": "6.3.1", - "@axelar-network/axelar-cgp-sui": "https://github.com/axelarnetwork/axelar-cgp-sui.git#main", + "@axelar-network/axelar-cgp-sui": "https://github.com/axelarnetwork/axelar-cgp-sui.git", "@axelar-network/axelar-gmp-sdk-solidity": "5.9.0", "@axelar-network/interchain-token-service": "1.2.4", "@cosmjs/cosmwasm-stargate": "^0.32.1", "@ledgerhq/hw-app-eth": "6.32.2", + "@mysten/sui.js": "^0.54.1", "@stellar/stellar-sdk": "^12.0.0-rc3", "axios": "^1.6.2", "path": "^0.12.7" @@ -54,9 +55,9 @@ } }, "node_modules/@0no-co/graphqlsp": { - "version": "1.12.7", - "resolved": "https://registry.npmjs.org/@0no-co/graphqlsp/-/graphqlsp-1.12.7.tgz", - "integrity": "sha512-jZeTKW8pl/IWTHWZUox5oQk0n+IsLNY+OkmxoZwW+AkZaQOXdzIlZ0OabJGw4+/vutwdZYR+UsoC8Nhi9hRnRw==", + "version": "1.12.11", + "resolved": "https://registry.npmjs.org/@0no-co/graphqlsp/-/graphqlsp-1.12.11.tgz", + "integrity": "sha512-vLja9r7L6BBXwxW86Wyi5z5hjTHscH7qoQooy+MXHkM9srBB6ZuesYZq5DQ/+SErQrFyaxeY+hwv2qBAksxriw==", "dependencies": { "@gql.tada/internal": "^1.0.0", "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0" @@ -69,6 +70,7 @@ "node_modules/@0xpolygonhermez/zkevm-commonjs": { "version": "1.0.0", "resolved": "git+ssh://git@github.com/0xpolygonhermez/zkevm-commonjs.git#34f72fe9f7a4c3c45965742476a87148c9e05c0f", + "license": "pending", "dependencies": { "@ethereumjs/block": "^3.6.2", "@ethereumjs/tx": "^3.4.0", @@ -117,12 +119,12 @@ } }, "node_modules/@aws-sdk/types": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.577.0.tgz", - "integrity": "sha512-FT2JZES3wBKN/alfmhlo+3ZOq/XJ0C7QOZcDNrpKjB0kqYoKjhVKZ/Hx6ArR0czkKfHzBBEs6y40ebIHx2nSmA==", + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", + "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", "dev": true, "dependencies": { - "@smithy/types": "^3.0.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { @@ -130,9 +132,9 @@ } }, "node_modules/@aws-sdk/types/node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", "dev": true }, "node_modules/@aws-sdk/util-utf8-browser": { @@ -145,9 +147,9 @@ } }, "node_modules/@aws-sdk/util-utf8-browser/node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", "dev": true }, "node_modules/@axelar-network/axelar-cgp-solidity": { @@ -171,10 +173,13 @@ }, "node_modules/@axelar-network/axelar-cgp-sui": { "version": "0.1.0", - "resolved": "git+ssh://git@github.com/axelarnetwork/axelar-cgp-sui.git#368b2d4032314e6400b5be3058490dcc79ed0fbb", + "resolved": "git+ssh://git@github.com/axelarnetwork/axelar-cgp-sui.git#44336e556e3e9e0fd36bfa854bf88573abc1461a", + "hasInstallScript": true, + "license": "MIT", "dependencies": { "@cosmjs/cosmwasm-stargate": "^0.32.2", "@mysten/sui.js": "^0.54.1", + "@types/tmp": "^0.2.6", "child_process": "^1.0.2", "ethers": "^5.0.0", "fs": "^0.0.1-security", @@ -225,9 +230,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", - "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz", + "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==", "bin": { "parser": "bin/babel-parser.js" }, @@ -271,41 +276,41 @@ } }, "node_modules/@cosmjs/amino": { - "version": "0.32.3", - "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.32.3.tgz", - "integrity": "sha512-G4zXl+dJbqrz1sSJ56H/25l5NJEk/pAPIr8piAHgbXYw88OdAOlpA26PQvk2IbSN/rRgVbvlLTNgX2tzz1dyUA==", + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.32.4.tgz", + "integrity": "sha512-zKYOt6hPy8obIFtLie/xtygCkH9ZROiQ12UHfKsOkWaZfPQUvVbtgmu6R4Kn1tFLI/SRkw7eqhaogmW/3NYu/Q==", "dependencies": { - "@cosmjs/crypto": "^0.32.3", - "@cosmjs/encoding": "^0.32.3", - "@cosmjs/math": "^0.32.3", - "@cosmjs/utils": "^0.32.3" + "@cosmjs/crypto": "^0.32.4", + "@cosmjs/encoding": "^0.32.4", + "@cosmjs/math": "^0.32.4", + "@cosmjs/utils": "^0.32.4" } }, "node_modules/@cosmjs/cosmwasm-stargate": { - "version": "0.32.3", - "resolved": "https://registry.npmjs.org/@cosmjs/cosmwasm-stargate/-/cosmwasm-stargate-0.32.3.tgz", - "integrity": "sha512-pqkt+QsLIPNMTRh9m+igJgIpzXXgn1BxmxfAb9zlC23kvsuzY/12un9M7iAdim1NwKXDFeYw46xC2YkprwQp+g==", - "dependencies": { - "@cosmjs/amino": "^0.32.3", - "@cosmjs/crypto": "^0.32.3", - "@cosmjs/encoding": "^0.32.3", - "@cosmjs/math": "^0.32.3", - "@cosmjs/proto-signing": "^0.32.3", - "@cosmjs/stargate": "^0.32.3", - "@cosmjs/tendermint-rpc": "^0.32.3", - "@cosmjs/utils": "^0.32.3", + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/cosmwasm-stargate/-/cosmwasm-stargate-0.32.4.tgz", + "integrity": "sha512-Fuo9BGEiB+POJ5WeRyBGuhyKR1ordvxZGLPuPosFJOH9U0gKMgcjwKMCgAlWFkMlHaTB+tNdA8AifWiHrI7VgA==", + "dependencies": { + "@cosmjs/amino": "^0.32.4", + "@cosmjs/crypto": "^0.32.4", + "@cosmjs/encoding": "^0.32.4", + "@cosmjs/math": "^0.32.4", + "@cosmjs/proto-signing": "^0.32.4", + "@cosmjs/stargate": "^0.32.4", + "@cosmjs/tendermint-rpc": "^0.32.4", + "@cosmjs/utils": "^0.32.4", "cosmjs-types": "^0.9.0", "pako": "^2.0.2" } }, "node_modules/@cosmjs/crypto": { - "version": "0.32.3", - "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.32.3.tgz", - "integrity": "sha512-niQOWJHUtlJm2GG4F00yGT7sGPKxfUwz+2qQ30uO/E3p58gOusTcH2qjiJNVxb8vScYJhFYFqpm/OA/mVqoUGQ==", + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.32.4.tgz", + "integrity": "sha512-zicjGU051LF1V9v7bp8p7ovq+VyC91xlaHdsFOTo2oVry3KQikp8L/81RkXmUIT8FxMwdx1T7DmFwVQikcSDIw==", "dependencies": { - "@cosmjs/encoding": "^0.32.3", - "@cosmjs/math": "^0.32.3", - "@cosmjs/utils": "^0.32.3", + "@cosmjs/encoding": "^0.32.4", + "@cosmjs/math": "^0.32.4", + "@cosmjs/utils": "^0.32.4", "@noble/hashes": "^1", "bn.js": "^5.2.0", "elliptic": "^6.5.4", @@ -313,9 +318,9 @@ } }, "node_modules/@cosmjs/encoding": { - "version": "0.32.3", - "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.32.3.tgz", - "integrity": "sha512-p4KF7hhv8jBQX3MkB3Defuhz/W0l3PwWVYU2vkVuBJ13bJcXyhU9nJjiMkaIv+XP+W2QgRceqNNgFUC5chNR7w==", + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.32.4.tgz", + "integrity": "sha512-tjvaEy6ZGxJchiizzTn7HVRiyTg1i4CObRRaTRPknm5EalE13SV+TCHq38gIDfyUeden4fCuaBVEdBR5+ti7Hw==", "dependencies": { "base64-js": "^1.3.0", "bech32": "^1.1.4", @@ -323,92 +328,92 @@ } }, "node_modules/@cosmjs/json-rpc": { - "version": "0.32.3", - "resolved": "https://registry.npmjs.org/@cosmjs/json-rpc/-/json-rpc-0.32.3.tgz", - "integrity": "sha512-JwFRWZa+Y95KrAG8CuEbPVOSnXO2uMSEBcaAB/FBU3Mo4jQnDoUjXvt3vwtFWxfAytrWCn1I4YDFaOAinnEG/Q==", + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/json-rpc/-/json-rpc-0.32.4.tgz", + "integrity": "sha512-/jt4mBl7nYzfJ2J/VJ+r19c92mUKF0Lt0JxM3MXEJl7wlwW5haHAWtzRujHkyYMXOwIR+gBqT2S0vntXVBRyhQ==", "dependencies": { - "@cosmjs/stream": "^0.32.3", + "@cosmjs/stream": "^0.32.4", "xstream": "^11.14.0" } }, "node_modules/@cosmjs/math": { - "version": "0.32.3", - "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.32.3.tgz", - "integrity": "sha512-amumUtZs8hCCnV+lSBaJIiZkGabQm22QGg/IotYrhcmoOEOjt82n7hMNlNXRs7V6WLMidGrGYcswB5zcmp0Meg==", + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.32.4.tgz", + "integrity": "sha512-++dqq2TJkoB8zsPVYCvrt88oJWsy1vMOuSOKcdlnXuOA/ASheTJuYy4+oZlTQ3Fr8eALDLGGPhJI02W2HyAQaw==", "dependencies": { "bn.js": "^5.2.0" } }, "node_modules/@cosmjs/proto-signing": { - "version": "0.32.3", - "resolved": "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.32.3.tgz", - "integrity": "sha512-kSZ0ZUY0DwcRT0NcIn2HkadH4NKlwjfZgbLj1ABwh/4l0RgeT84QCscZCu63tJYq3K6auwqTiZSZERwlO4/nbg==", - "dependencies": { - "@cosmjs/amino": "^0.32.3", - "@cosmjs/crypto": "^0.32.3", - "@cosmjs/encoding": "^0.32.3", - "@cosmjs/math": "^0.32.3", - "@cosmjs/utils": "^0.32.3", + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.32.4.tgz", + "integrity": "sha512-QdyQDbezvdRI4xxSlyM1rSVBO2st5sqtbEIl3IX03uJ7YiZIQHyv6vaHVf1V4mapusCqguiHJzm4N4gsFdLBbQ==", + "dependencies": { + "@cosmjs/amino": "^0.32.4", + "@cosmjs/crypto": "^0.32.4", + "@cosmjs/encoding": "^0.32.4", + "@cosmjs/math": "^0.32.4", + "@cosmjs/utils": "^0.32.4", "cosmjs-types": "^0.9.0" } }, "node_modules/@cosmjs/socket": { - "version": "0.32.3", - "resolved": "https://registry.npmjs.org/@cosmjs/socket/-/socket-0.32.3.tgz", - "integrity": "sha512-F2WwNmaUPdZ4SsH6Uyreq3wQk7jpaEkb3wfOP951f5Jt6HCW/PxbxhKzHkAAf6+Sqks6SPhkbWoE8XaZpjL2KA==", + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/socket/-/socket-0.32.4.tgz", + "integrity": "sha512-davcyYziBhkzfXQTu1l5NrpDYv0K9GekZCC9apBRvL1dvMc9F/ygM7iemHjUA+z8tJkxKxrt/YPjJ6XNHzLrkw==", "dependencies": { - "@cosmjs/stream": "^0.32.3", + "@cosmjs/stream": "^0.32.4", "isomorphic-ws": "^4.0.1", "ws": "^7", "xstream": "^11.14.0" } }, "node_modules/@cosmjs/stargate": { - "version": "0.32.3", - "resolved": "https://registry.npmjs.org/@cosmjs/stargate/-/stargate-0.32.3.tgz", - "integrity": "sha512-OQWzO9YWKerUinPIxrO1MARbe84XkeXJAW0lyMIjXIEikajuXZ+PwftiKA5yA+8OyditVmHVLtPud6Pjna2s5w==", + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/stargate/-/stargate-0.32.4.tgz", + "integrity": "sha512-usj08LxBSsPRq9sbpCeVdyLx2guEcOHfJS9mHGCLCXpdAPEIEQEtWLDpEUc0LEhWOx6+k/ChXTc5NpFkdrtGUQ==", "dependencies": { "@confio/ics23": "^0.6.8", - "@cosmjs/amino": "^0.32.3", - "@cosmjs/encoding": "^0.32.3", - "@cosmjs/math": "^0.32.3", - "@cosmjs/proto-signing": "^0.32.3", - "@cosmjs/stream": "^0.32.3", - "@cosmjs/tendermint-rpc": "^0.32.3", - "@cosmjs/utils": "^0.32.3", + "@cosmjs/amino": "^0.32.4", + "@cosmjs/encoding": "^0.32.4", + "@cosmjs/math": "^0.32.4", + "@cosmjs/proto-signing": "^0.32.4", + "@cosmjs/stream": "^0.32.4", + "@cosmjs/tendermint-rpc": "^0.32.4", + "@cosmjs/utils": "^0.32.4", "cosmjs-types": "^0.9.0", "xstream": "^11.14.0" } }, "node_modules/@cosmjs/stream": { - "version": "0.32.3", - "resolved": "https://registry.npmjs.org/@cosmjs/stream/-/stream-0.32.3.tgz", - "integrity": "sha512-J2zVWDojkynYifAUcRmVczzmp6STEpyiAARq0rSsviqjreGIfspfuws/8rmkPa6qQBZvpQOBQCm2HyZZwYplIw==", + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/stream/-/stream-0.32.4.tgz", + "integrity": "sha512-Gih++NYHEiP+oyD4jNEUxU9antoC0pFSg+33Hpp0JlHwH0wXhtD3OOKnzSfDB7OIoEbrzLJUpEjOgpCp5Z+W3A==", "dependencies": { "xstream": "^11.14.0" } }, "node_modules/@cosmjs/tendermint-rpc": { - "version": "0.32.3", - "resolved": "https://registry.npmjs.org/@cosmjs/tendermint-rpc/-/tendermint-rpc-0.32.3.tgz", - "integrity": "sha512-xeprW+VR9xKGstqZg0H/KBZoUp8/FfFyS9ljIUTLM/UINjP2MhiwncANPS2KScfJVepGufUKk0/phHUeIBSEkw==", - "dependencies": { - "@cosmjs/crypto": "^0.32.3", - "@cosmjs/encoding": "^0.32.3", - "@cosmjs/json-rpc": "^0.32.3", - "@cosmjs/math": "^0.32.3", - "@cosmjs/socket": "^0.32.3", - "@cosmjs/stream": "^0.32.3", - "@cosmjs/utils": "^0.32.3", + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/tendermint-rpc/-/tendermint-rpc-0.32.4.tgz", + "integrity": "sha512-MWvUUno+4bCb/LmlMIErLypXxy7ckUuzEmpufYYYd9wgbdCXaTaO08SZzyFM5PI8UJ/0S2AmUrgWhldlbxO8mw==", + "dependencies": { + "@cosmjs/crypto": "^0.32.4", + "@cosmjs/encoding": "^0.32.4", + "@cosmjs/json-rpc": "^0.32.4", + "@cosmjs/math": "^0.32.4", + "@cosmjs/socket": "^0.32.4", + "@cosmjs/stream": "^0.32.4", + "@cosmjs/utils": "^0.32.4", "axios": "^1.6.0", "readonly-date": "^1.0.0", "xstream": "^11.14.0" } }, "node_modules/@cosmjs/utils": { - "version": "0.32.3", - "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.32.3.tgz", - "integrity": "sha512-WCZK4yksj2hBDz4w7xFZQTRZQ/RJhBX26uFHmmQFIcNUUVAihrLO+RerqJgk0dZqC42wstM9pEUQGtPmLcIYvg==" + "version": "0.32.4", + "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.32.4.tgz", + "integrity": "sha512-D1Yc+Zy8oL/hkUkFUL/bwxvuDBzRGpc4cF7/SkdhxX4iHpSLgdOuTt1mhCh9+kl6NQREy9t7SYZ6xeW5gFe60w==" }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", @@ -450,9 +455,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", - "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -574,72 +579,17 @@ "node": ">=14" } }, - "node_modules/@ethereumjs/util/node_modules/@noble/curves": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.3.0.tgz", - "integrity": "sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA==", - "dev": true, - "peer": true, - "dependencies": { - "@noble/hashes": "1.3.3" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@ethereumjs/util/node_modules/@noble/hashes": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", - "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@ethereumjs/util/node_modules/@scure/bip32": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.3.tgz", - "integrity": "sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ==", - "dev": true, - "peer": true, - "dependencies": { - "@noble/curves": "~1.3.0", - "@noble/hashes": "~1.3.2", - "@scure/base": "~1.1.4" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@ethereumjs/util/node_modules/@scure/bip39": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.2.tgz", - "integrity": "sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA==", - "dev": true, - "peer": true, - "dependencies": { - "@noble/hashes": "~1.3.2", - "@scure/base": "~1.1.4" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@ethereumjs/util/node_modules/ethereum-cryptography": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.3.tgz", - "integrity": "sha512-BlwbIL7/P45W8FGW2r7LGuvoEZ+7PWsniMvQ4p5s2xCyw9tmaDlpfsN9HjAucbF+t/qpVHwZUisgfK24TCW8aA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", + "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", "dev": true, "peer": true, "dependencies": { - "@noble/curves": "1.3.0", - "@noble/hashes": "1.3.3", - "@scure/bip32": "1.3.3", - "@scure/bip39": "1.2.2" + "@noble/curves": "1.4.2", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" } }, "node_modules/@ethersproject/abi": { @@ -1362,26 +1312,27 @@ } }, "node_modules/@gql.tada/cli-utils": { - "version": "1.3.9", - "resolved": "https://registry.npmjs.org/@gql.tada/cli-utils/-/cli-utils-1.3.9.tgz", - "integrity": "sha512-oRb7SG/+csx9CiypSJTI21KaLfulOUnhX1vxg4FXi2snub9XShkGR2XnnlJVTAOZXY9Vcxti1NutAElxdDkycA==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@gql.tada/cli-utils/-/cli-utils-1.5.1.tgz", + "integrity": "sha512-JVLpoXLa4msrE7MHnmW/7fYnIl8dncLom8T/Ghsxu+Kz5iMGnzK2joJN5cZt4ewCAqfCV3HZZ0VH189OalGd9g==", "dependencies": { - "@0no-co/graphqlsp": "^1.12.1", - "@gql.tada/internal": "1.0.0", + "@0no-co/graphqlsp": "^1.12.9", + "@gql.tada/internal": "1.0.4", "@vue/compiler-dom": "^3.4.23", "@vue/language-core": "^2.0.17", "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0", "svelte2tsx": "^0.7.6" }, "peerDependencies": { + "@0no-co/graphqlsp": "^1.12.9", "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0", "typescript": "^5.0.0" } }, "node_modules/@gql.tada/internal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@gql.tada/internal/-/internal-1.0.0.tgz", - "integrity": "sha512-B55aIYyZn5ewdgMqoJciPAwF5DKYX6HBabTU+ap/dpNH3EgJrLomc8Y8w+MCxCyOx+dXL9OduT6eWnVr7J7Eyg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@gql.tada/internal/-/internal-1.0.4.tgz", + "integrity": "sha512-tq0rgoqjhdVqKWEsbrkiX7Qpp5gA4/Br9r9TVBeh3WpJIcuGh5U48UjB4IOxtXBePZdX8E0oc07GjOid/P60Wg==", "dependencies": { "@0no-co/graphql.web": "^1.0.5" }, @@ -1402,6 +1353,7 @@ "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "deprecated": "Use @eslint/config-array instead", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^2.0.2", @@ -1429,6 +1381,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", "dev": true }, "node_modules/@jridgewell/gen-mapping": { @@ -1464,9 +1417,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "peer": true }, "node_modules/@jridgewell/trace-mapping": { @@ -1488,20 +1441,20 @@ } }, "node_modules/@ledgerhq/devices": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@ledgerhq/devices/-/devices-8.3.0.tgz", - "integrity": "sha512-h5Scr+yIae8yjPOViCHLdMjpqn4oC2Whrsq8LinRxe48LEGMdPqSV1yY7+3Ch827wtzNpMv+/ilKnd8rY+rTlg==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@ledgerhq/devices/-/devices-8.4.0.tgz", + "integrity": "sha512-TUrMlWZJ+5AFp2lWMw4rGQoU+WtjIqlFX5SzQDL9phaUHrt4TFierAGHsaj5+tUHudhD4JhIaLI2cn1NOyq5NQ==", "dependencies": { - "@ledgerhq/errors": "^6.16.4", + "@ledgerhq/errors": "^6.17.0", "@ledgerhq/logs": "^6.12.0", "rxjs": "^7.8.1", "semver": "^7.3.5" } }, "node_modules/@ledgerhq/errors": { - "version": "6.16.4", - "resolved": "https://registry.npmjs.org/@ledgerhq/errors/-/errors-6.16.4.tgz", - "integrity": "sha512-M57yFaLYSN+fZCX0E0zUqOmrV6eipK+s5RhijHoUNlHUqrsvUz7iRQgpd5gRgHB5VkIjav7KdaZjKiWGcHovaQ==" + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@ledgerhq/errors/-/errors-6.17.0.tgz", + "integrity": "sha512-xnOVpy/gUUkusEORdr2Qhw3Vd0MGfjyVGgkGR9Ck6FXE26OIdIQ3tNmG5BdZN+gwMMFJJVxxS4/hr0taQfZ43w==" }, "node_modules/@ledgerhq/hw-app-eth": { "version": "6.32.2", @@ -1529,53 +1482,53 @@ } }, "node_modules/@ledgerhq/hw-transport": { - "version": "6.30.6", - "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport/-/hw-transport-6.30.6.tgz", - "integrity": "sha512-fT0Z4IywiuJuZrZE/+W0blkV5UCotDPFTYKLkKCLzYzuE6javva7D/ajRaIeR+hZ4kTmKF4EqnsmDCXwElez+w==", + "version": "6.31.0", + "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport/-/hw-transport-6.31.0.tgz", + "integrity": "sha512-BY1poLk8vlJdIYngp8Zfaa/V9n14dqgt1G7iNetVRhJVFEKp9EYONeC3x6q/N7x81LUpzBk6M+T+s46Z4UiXHw==", "dependencies": { - "@ledgerhq/devices": "^8.3.0", - "@ledgerhq/errors": "^6.16.4", + "@ledgerhq/devices": "^8.4.0", + "@ledgerhq/errors": "^6.17.0", "@ledgerhq/logs": "^6.12.0", "events": "^3.3.0" } }, "node_modules/@ledgerhq/hw-transport-mocker": { - "version": "6.28.6", - "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-mocker/-/hw-transport-mocker-6.28.6.tgz", - "integrity": "sha512-JDO2kqMOTRCQWNZr1KVlyX1AqE6WBzHjJDS3FnSI8Z/Bj2KSc2/1H/4lW6+Ap64yLtlmOW3GchdafFmLgYAgqw==", + "version": "6.29.0", + "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-mocker/-/hw-transport-mocker-6.29.0.tgz", + "integrity": "sha512-SbS4SvbMcpNquUsvN4Gd0bTi7ohySqIDMHFf2YLhYBRu1HviU3TG/p4zoFrJcFUiIX2/wOmUdHsWtaQFdMVGyQ==", "dependencies": { - "@ledgerhq/hw-transport": "^6.30.6", + "@ledgerhq/hw-transport": "^6.31.0", "@ledgerhq/logs": "^6.12.0", "rxjs": "^7.8.1" } }, "node_modules/@ledgerhq/hw-transport-node-hid": { - "version": "6.28.6", - "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-node-hid/-/hw-transport-node-hid-6.28.6.tgz", - "integrity": "sha512-USSTOO0zv9XtguWismP7/StnNS/s7Rz0JOGGaBhKe3Bzl7d5XPncUlmOvoNFzzY/QdasEoFs2QId1+ibJG71Vw==", + "version": "6.29.1", + "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-node-hid/-/hw-transport-node-hid-6.29.1.tgz", + "integrity": "sha512-l+zAfsE0uvo2/Wni0TSW+n6HoFmZdPH6ukrjPocY6jvbhcaxhpbK7ERvDpnZMir/pHwsDoAsvwPY/0sFRBf7bw==", "dev": true, "dependencies": { - "@ledgerhq/devices": "^8.3.0", - "@ledgerhq/errors": "^6.16.4", - "@ledgerhq/hw-transport": "^6.30.6", - "@ledgerhq/hw-transport-node-hid-noevents": "^6.29.6", + "@ledgerhq/devices": "^8.4.0", + "@ledgerhq/errors": "^6.17.0", + "@ledgerhq/hw-transport": "^6.31.0", + "@ledgerhq/hw-transport-node-hid-noevents": "^6.30.1", "@ledgerhq/logs": "^6.12.0", "lodash": "^4.17.21", - "node-hid": "^2.1.2", + "node-hid": "2.1.2", "usb": "2.9.0" } }, "node_modules/@ledgerhq/hw-transport-node-hid-noevents": { - "version": "6.29.6", - "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-node-hid-noevents/-/hw-transport-node-hid-noevents-6.29.6.tgz", - "integrity": "sha512-H1cGC4TLwSCxve3rbV7qfPJBZfy7VD7k9Czc9HOMDwQ9zHFtaoeiIotIMGjzHjfPtAGauMpAYvrpmEdBBX5sHg==", + "version": "6.30.1", + "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-node-hid-noevents/-/hw-transport-node-hid-noevents-6.30.1.tgz", + "integrity": "sha512-9Mb5vDBXfSaRhfl0U2DnJLN4FgosfQopkzjzZYYHT3+s9XMot4WN/eWWbv5Ksx5qsV8RLQ77dewFFomNthm/vQ==", "dev": true, "dependencies": { - "@ledgerhq/devices": "^8.3.0", - "@ledgerhq/errors": "^6.16.4", - "@ledgerhq/hw-transport": "^6.30.6", + "@ledgerhq/devices": "^8.4.0", + "@ledgerhq/errors": "^6.17.0", + "@ledgerhq/hw-transport": "^6.31.0", "@ledgerhq/logs": "^6.12.0", - "node-hid": "^2.1.2" + "node-hid": "2.1.2" } }, "node_modules/@ledgerhq/logs": { @@ -1665,9 +1618,9 @@ "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" }, "node_modules/@noble/curves": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.0.tgz", - "integrity": "sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", + "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", "dependencies": { "@noble/hashes": "1.4.0" }, @@ -1998,184 +1951,91 @@ } }, "node_modules/@nomicfoundation/solidity-analyzer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.1.tgz", - "integrity": "sha512-1LMtXj1puAxyFusBgUIy5pZk3073cNXYnXUpuNKFghHbIit/xZgbk0AokpUADbNm3gyD6bFWl3LRFh3dhVdREg==", + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.2.tgz", + "integrity": "sha512-q4n32/FNKIhQ3zQGGw5CvPF6GTvDCpYwIf7bEY/dZTZbgfDsHyjJwURxUJf3VQuuJj+fDIFl4+KkBVbw4Ef6jA==", "dev": true, "engines": { "node": ">= 12" }, "optionalDependencies": { - "@nomicfoundation/solidity-analyzer-darwin-arm64": "0.1.1", - "@nomicfoundation/solidity-analyzer-darwin-x64": "0.1.1", - "@nomicfoundation/solidity-analyzer-freebsd-x64": "0.1.1", - "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": "0.1.1", - "@nomicfoundation/solidity-analyzer-linux-arm64-musl": "0.1.1", - "@nomicfoundation/solidity-analyzer-linux-x64-gnu": "0.1.1", - "@nomicfoundation/solidity-analyzer-linux-x64-musl": "0.1.1", - "@nomicfoundation/solidity-analyzer-win32-arm64-msvc": "0.1.1", - "@nomicfoundation/solidity-analyzer-win32-ia32-msvc": "0.1.1", - "@nomicfoundation/solidity-analyzer-win32-x64-msvc": "0.1.1" + "@nomicfoundation/solidity-analyzer-darwin-arm64": "0.1.2", + "@nomicfoundation/solidity-analyzer-darwin-x64": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-arm64-musl": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-x64-gnu": "0.1.2", + "@nomicfoundation/solidity-analyzer-linux-x64-musl": "0.1.2", + "@nomicfoundation/solidity-analyzer-win32-x64-msvc": "0.1.2" } }, "node_modules/@nomicfoundation/solidity-analyzer-darwin-arm64": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.1.tgz", - "integrity": "sha512-KcTodaQw8ivDZyF+D76FokN/HdpgGpfjc/gFCImdLUyqB6eSWVaZPazMbeAjmfhx3R0zm/NYVzxwAokFKgrc0w==", - "cpu": [ - "arm64" - ], + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.2.tgz", + "integrity": "sha512-JaqcWPDZENCvm++lFFGjrDd8mxtf+CtLd2MiXvMNTBD33dContTZ9TWETwNFwg7JTJT5Q9HEecH7FA+HTSsIUw==", "dev": true, "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": ">= 10" + "node": ">= 12" } }, "node_modules/@nomicfoundation/solidity-analyzer-darwin-x64": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.1.tgz", - "integrity": "sha512-XhQG4BaJE6cIbjAVtzGOGbK3sn1BO9W29uhk9J8y8fZF1DYz0Doj8QDMfpMu+A6TjPDs61lbsmeYodIDnfveSA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-freebsd-x64": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-freebsd-x64/-/solidity-analyzer-freebsd-x64-0.1.1.tgz", - "integrity": "sha512-GHF1VKRdHW3G8CndkwdaeLkVBi5A9u2jwtlS7SLhBc8b5U/GcoL39Q+1CSO3hYqePNP+eV5YI7Zgm0ea6kMHoA==", - "cpu": [ - "x64" - ], + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.2.tgz", + "integrity": "sha512-fZNmVztrSXC03e9RONBT+CiksSeYcxI1wlzqyr0L7hsQlK1fzV+f04g2JtQ1c/Fe74ZwdV6aQBdd6Uwl1052sw==", "dev": true, "optional": true, - "os": [ - "freebsd" - ], "engines": { - "node": ">= 10" + "node": ">= 12" } }, "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.1.tgz", - "integrity": "sha512-g4Cv2fO37ZsUENQ2vwPnZc2zRenHyAxHcyBjKcjaSmmkKrFr64yvzeNO8S3GBFCo90rfochLs99wFVGT/0owpg==", - "cpu": [ - "arm64" - ], + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.2.tgz", + "integrity": "sha512-3d54oc+9ZVBuB6nbp8wHylk4xh0N0Gc+bk+/uJae+rUgbOBwQSfuGIbAZt1wBXs5REkSmynEGcqx6DutoK0tPA==", "dev": true, "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">= 10" + "node": ">= 12" } }, "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-musl": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.1.tgz", - "integrity": "sha512-WJ3CE5Oek25OGE3WwzK7oaopY8xMw9Lhb0mlYuJl/maZVo+WtP36XoQTb7bW/i8aAdHW5Z+BqrHMux23pvxG3w==", - "cpu": [ - "arm64" - ], + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.2.tgz", + "integrity": "sha512-iDJfR2qf55vgsg7BtJa7iPiFAsYf2d0Tv/0B+vhtnI16+wfQeTbP7teookbGvAo0eJo7aLLm0xfS/GTkvHIucA==", "dev": true, "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">= 10" + "node": ">= 12" } }, "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-gnu": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.1.tgz", - "integrity": "sha512-5WN7leSr5fkUBBjE4f3wKENUy9HQStu7HmWqbtknfXkkil+eNWiBV275IOlpXku7v3uLsXTOKpnnGHJYI2qsdA==", - "cpu": [ - "x64" - ], + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.2.tgz", + "integrity": "sha512-9dlHMAt5/2cpWyuJ9fQNOUXFB/vgSFORg1jpjX1Mh9hJ/MfZXlDdHQ+DpFCs32Zk5pxRBb07yGvSHk9/fezL+g==", "dev": true, "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">= 10" + "node": ">= 12" } }, "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-musl": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.1.tgz", - "integrity": "sha512-KdYMkJOq0SYPQMmErv/63CwGwMm5XHenEna9X9aB8mQmhDBrYrlAOSsIPgFCUSL0hjxE3xHP65/EPXR/InD2+w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-win32-arm64-msvc": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-arm64-msvc/-/solidity-analyzer-win32-arm64-msvc-0.1.1.tgz", - "integrity": "sha512-VFZASBfl4qiBYwW5xeY20exWhmv6ww9sWu/krWSesv3q5hA0o1JuzmPHR4LPN6SUZj5vcqci0O6JOL8BPw+APg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-win32-ia32-msvc": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-ia32-msvc/-/solidity-analyzer-win32-ia32-msvc-0.1.1.tgz", - "integrity": "sha512-JnFkYuyCSA70j6Si6cS1A9Gh1aHTEb8kOTBApp/c7NRTFGNMH8eaInKlyuuiIbvYFhlXW4LicqyYuWNNq9hkpQ==", - "cpu": [ - "ia32" - ], + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.2.tgz", + "integrity": "sha512-GzzVeeJob3lfrSlDKQw2bRJ8rBf6mEYaWY+gW0JnTDHINA0s2gPR4km5RLIj1xeZZOYz4zRw+AEeYgLRqB2NXg==", "dev": true, "optional": true, - "os": [ - "win32" - ], "engines": { - "node": ">= 10" + "node": ">= 12" } }, "node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.1.tgz", - "integrity": "sha512-HrVJr6+WjIXGnw3Q9u6KQcbZCtk0caVWhCdFADySvRyUxJ8PnzlaP+MhwNE8oyT8OZ6ejHBRrrgjSqDCFXGirw==", - "cpu": [ - "x64" - ], + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.2.tgz", + "integrity": "sha512-Fdjli4DCcFHb4Zgsz0uEJXZ2K7VEO+w5KVv7HmT7WO10iODdU9csC2az4jrhEsRtiR9Gfd74FlG0NYlw1BMdyA==", "dev": true, "optional": true, - "os": [ - "win32" - ], "engines": { - "node": ">= 10" + "node": ">= 12" } }, "node_modules/@nomiclabs/hardhat-ethers": { @@ -2405,6 +2265,7 @@ "name": "@0xpolygonhermez/zkevm-commonjs", "version": "0.5.0.1", "resolved": "git+ssh://git@github.com/hermeznetwork/zkevm-commonjs.git#3ee798329f567fa19b7c4f1ffbcf3d91cf5bf273", + "license": "pending", "dependencies": { "@ethereumjs/block": "^3.6.2", "@ethereumjs/tx": "^3.4.0", @@ -2502,9 +2363,9 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "node_modules/@scure/base": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.6.tgz", - "integrity": "sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.7.tgz", + "integrity": "sha512-PPNYBslrLNNUQ/Yad37MHYsNQtK67EhWb6WtSvNLLPo7SdVZgkUjD6Dg+5On7zNwmskf8OX7I7Nx5oN+MIWE0g==", "funding": { "url": "https://paulmillr.com/funding/" } @@ -2637,9 +2498,9 @@ } }, "node_modules/@smithy/types": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.0.0.tgz", - "integrity": "sha512-VvWuQk2RKFuOr98gFhjca7fkBS+xLLURT8bUjk5XQoV0ZLm7WPwWPPY3/AwzTLuUBDeoKDCthfe1AsTUWaSEhw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dev": true, "dependencies": { "tslib": "^2.6.2" @@ -2649,9 +2510,9 @@ } }, "node_modules/@smithy/types/node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", "dev": true }, "node_modules/@solidity-parser/parser": { @@ -2670,9 +2531,9 @@ "integrity": "sha512-3gnPjAz78htgqsNEDkEsKHKosV2BF2iZkoHCNxpmZwUxiPsw+2VaXMed8RRMe0rGk3d5GZe7RrSba8zV80J3Ag==" }, "node_modules/@stellar/stellar-base": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-12.0.0.tgz", - "integrity": "sha512-uGpahDFFXbE39myOmBnEZSjVys4yUkQ/ASNuYENGyS8MNdfA0TS7DPWkiO6t17P+rW+FRV1zmumJtjRHwxxMdw==", + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-12.0.1.tgz", + "integrity": "sha512-g6c27MNsDgEdUmoNQJn7zCWoCY50WHt0OIIOq3PhWaJRtUaT++qs1Jpb8+1bny2GmhtfRGOfPUFSyQBuHT9Mvg==", "dependencies": { "@stellar/js-xdr": "^3.1.1", "base32.js": "^0.1.0", @@ -2686,11 +2547,11 @@ } }, "node_modules/@stellar/stellar-sdk": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@stellar/stellar-sdk/-/stellar-sdk-12.0.1.tgz", - "integrity": "sha512-0+YXUTS2LpZ+Of383hSYVpsRl9BJ3X9lHcj05ouS3VkVL9BH7w+Par8RHPkiHS6lLYn3gWRgaJauTebkamY/Jw==", + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/@stellar/stellar-sdk/-/stellar-sdk-12.1.0.tgz", + "integrity": "sha512-Va0hu9SaPezmMbO5eMwL5D15Wrx1AGWRtxayUDRWV2Fr3ynY58mvCZS1vsgNQ4kE8MZe3nBVKv6T9Kzqwgx1PQ==", "dependencies": { - "@stellar/stellar-base": "^12.0.0", + "@stellar/stellar-base": "^12.0.1", "axios": "^1.7.2", "bignumber.js": "^9.1.2", "eventsource": "^2.0.2", @@ -2891,16 +2752,16 @@ "peer": true }, "node_modules/@types/mocha": { - "version": "10.0.6", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.6.tgz", - "integrity": "sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==", + "version": "10.0.7", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.7.tgz", + "integrity": "sha512-GN8yJ1mNTcFcah/wKEFIJckJx9iJLoMSzWcfRRuxz/Jk+U6KQNnml+etbtxFK8lPjzOw3zp4Ha/kjSst9fsHYw==", "dev": true, "peer": true }, "node_modules/@types/node": { - "version": "20.14.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.0.tgz", - "integrity": "sha512-5cHBxFGJx6L4s56Bubp4fglrEpmyJypsqI6RgzMfBHWUJQGWAAi8cWcgetEbZXHYXo9C2Fa4EEds/uSyS4cxmA==", + "version": "20.14.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz", + "integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==", "dependencies": { "undici-types": "~5.26.4" } @@ -2951,6 +2812,11 @@ "@types/node": "*" } }, + "node_modules/@types/tmp": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.2.6.tgz", + "integrity": "sha512-chhaNf2oKHlRkDGt+tiKE2Z5aJ6qalm7Z9rlLdBwmOiAAf09YQvvoLXjWK4HWPF1xU/fqvMgfNfpVoBscA/tKA==" + }, "node_modules/@types/w3c-web-usb": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/@types/w3c-web-usb/-/w3c-web-usb-1.0.10.tgz", @@ -2964,52 +2830,50 @@ "dev": true }, "node_modules/@volar/language-core": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.2.5.tgz", - "integrity": "sha512-2htyAuxRrAgETmFeUhT4XLELk3LiEcqoW/B8YUXMF6BrGWLMwIR09MFaZYvrA2UhbdAeSyeQ726HaWSWkexUcQ==", + "version": "2.4.0-alpha.16", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.0-alpha.16.tgz", + "integrity": "sha512-oOTnIZlx0P/idFwVw+W0NbzKDtZAQMzXSdIFfTePCKcXlb4Ys12GaGkx8NF9dsvPYV3nbv3ZsSxnkZWBmNKd7A==", "dependencies": { - "@volar/source-map": "2.2.5" + "@volar/source-map": "2.4.0-alpha.16" } }, "node_modules/@volar/source-map": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.2.5.tgz", - "integrity": "sha512-wrOEIiZNf4E+PWB0AxyM4tfhkfldPsb3bxg8N6FHrxJH2ohar7aGu48e98bp3pR9HUA7P/pR9VrLmkTrgCCnWQ==", - "dependencies": { - "muggle-string": "^0.4.0" - } + "version": "2.4.0-alpha.16", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.0-alpha.16.tgz", + "integrity": "sha512-sL9vNG7iR2hiKZor7UkD5Sufu3QCia4cbp2gX/nGRNSdaPbhOpdAoavwlBm0PrVkpiA19NZuavZoobD8krviFg==" }, "node_modules/@vue/compiler-core": { - "version": "3.4.27", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.27.tgz", - "integrity": "sha512-E+RyqY24KnyDXsCuQrI+mlcdW3ALND6U7Gqa/+bVwbcpcR3BRRIckFoz7Qyd4TTlnugtwuI7YgjbvsLmxb+yvg==", + "version": "3.4.32", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.32.tgz", + "integrity": "sha512-8tCVWkkLe/QCWIsrIvExUGnhYCAOroUs5dzhSoKL5w4MJS8uIYiou+pOPSVIOALOQ80B0jBs+Ri+kd5+MBnCDw==", "dependencies": { - "@babel/parser": "^7.24.4", - "@vue/shared": "3.4.27", + "@babel/parser": "^7.24.7", + "@vue/shared": "3.4.32", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-dom": { - "version": "3.4.27", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.27.tgz", - "integrity": "sha512-kUTvochG/oVgE1w5ViSr3KUBh9X7CWirebA3bezTbB5ZKBQZwR2Mwj9uoSKRMFcz4gSMzzLXBPD6KpCLb9nvWw==", + "version": "3.4.32", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.32.tgz", + "integrity": "sha512-PbSgt9KuYo4fyb90dynuPc0XFTfFPs3sCTbPLOLlo+PrUESW1gn/NjSsUvhR+mI2AmmEzexwYMxbHDldxSOr2A==", "dependencies": { - "@vue/compiler-core": "3.4.27", - "@vue/shared": "3.4.27" + "@vue/compiler-core": "3.4.32", + "@vue/shared": "3.4.32" } }, "node_modules/@vue/language-core": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.0.19.tgz", - "integrity": "sha512-A9EGOnvb51jOvnCYoRLnMP+CcoPlbZVxI9gZXE/y2GksRWM6j/PrLEIC++pnosWTN08tFpJgxhSS//E9v/Sg+Q==", + "version": "2.0.26", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.0.26.tgz", + "integrity": "sha512-/lt6SfQ3O1yDAhPsnLv9iSUgXd1dMHqUm/t3RctfqjuwQf1LnftZ414X3UBn6aXT4MiwXWtbNJ4Z0NZWwDWgJQ==", "dependencies": { - "@volar/language-core": "~2.2.4", + "@volar/language-core": "~2.4.0-alpha.15", "@vue/compiler-dom": "^3.4.0", "@vue/shared": "^3.4.0", "computeds": "^0.0.1", "minimatch": "^9.0.3", + "muggle-string": "^0.4.1", "path-browserify": "^1.0.1", "vue-template-compiler": "^2.7.14" }, @@ -3031,9 +2895,9 @@ } }, "node_modules/@vue/language-core/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -3045,9 +2909,9 @@ } }, "node_modules/@vue/shared": { - "version": "3.4.27", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.27.tgz", - "integrity": "sha512-DL3NmY2OFlqmYYrzp39yi3LDkKxa5vZVwxWdQ3rG0ekuWscHraeIbnI8t+aZK7qhYqEqWKTUdijadunb9pnrgA==" + "version": "3.4.32", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.32.tgz", + "integrity": "sha512-ep4mF1IVnX/pYaNwxwOpJHyBtOMKWoKZMbnUyd+z0udqIxLUh7YCCd/JfDna8aUrmnG9SFORyIq2HzEATRrQsg==" }, "node_modules/abbrev": { "version": "1.0.9", @@ -3131,9 +2995,9 @@ } }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "bin": { "acorn": "bin/acorn" }, @@ -3151,11 +3015,14 @@ } }, "node_modules/acorn-walk": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", - "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", + "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", "dev": true, "peer": true, + "dependencies": { + "acorn": "^8.11.0" + }, "engines": { "node": ">=0.4.0" } @@ -3603,12 +3470,12 @@ } }, "node_modules/axobject-query": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz", - "integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", "peer": true, - "dependencies": { - "dequal": "^2.0.3" + "engines": { + "node": ">= 0.4" } }, "node_modules/balanced-match": { @@ -3840,9 +3707,9 @@ } }, "node_modules/bs58check/node_modules/base-x": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", - "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.10.tgz", + "integrity": "sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==", "dependencies": { "safe-buffer": "^5.0.1" } @@ -4762,9 +4629,9 @@ "integrity": "sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ==" }, "node_modules/deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", "dev": true, "dependencies": { "type-detect": "^4.0.0" @@ -4917,9 +4784,9 @@ } }, "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "dev": true, "engines": { "node": ">=0.3.1" @@ -4976,9 +4843,9 @@ } }, "node_modules/elliptic": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.5.tgz", - "integrity": "sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw==", + "version": "6.5.6", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.6.tgz", + "integrity": "sha512-mpzdtpeCLuS3BmE3pO3Cpp5bbjlOPY2Q0PgoF+Od1XZrHLYI28Xe3ossCmYCQt11FQKEYd9+PF8jymTvtWJSHQ==", "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", @@ -5758,9 +5625,9 @@ } }, "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -6195,6 +6062,13 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==", + "dev": true, + "peer": true + }, "node_modules/fastq": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", @@ -6747,13 +6621,14 @@ } }, "node_modules/gql.tada": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/gql.tada/-/gql.tada-1.7.5.tgz", - "integrity": "sha512-GepPTee+FWSVVZQ7GiJHzsGNo7gOb59kcn4mUPYLlkbpeJfOUwpuoB05ZNaXG0W4qZVPd1I7R2UgMHBjY1lGlQ==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/gql.tada/-/gql.tada-1.8.2.tgz", + "integrity": "sha512-LLt+2RcLY6i+Rq+LQQwx3uiEAPfA+pmEaAo/bJjUdaV1CVJBy3Wowds6GHeerW5kvekRM/XdbPTJw5OvnLq/DQ==", "dependencies": { "@0no-co/graphql.web": "^1.0.5", - "@gql.tada/cli-utils": "1.3.9", - "@gql.tada/internal": "1.0.0" + "@0no-co/graphqlsp": "^1.12.9", + "@gql.tada/cli-utils": "1.5.1", + "@gql.tada/internal": "1.0.4" }, "bin": { "gql-tada": "bin/cli.js", @@ -6776,9 +6651,9 @@ "dev": true }, "node_modules/graphql": { - "version": "16.8.1", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", - "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", + "version": "16.9.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz", + "integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==", "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } @@ -7591,12 +7466,15 @@ } }, "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", + "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", "dev": true, "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -8203,16 +8081,16 @@ } }, "node_modules/libsodium-sumo": { - "version": "0.7.13", - "resolved": "https://registry.npmjs.org/libsodium-sumo/-/libsodium-sumo-0.7.13.tgz", - "integrity": "sha512-zTGdLu4b9zSNLfovImpBCbdAA4xkpkZbMnSQjP8HShyOutnGjRHmSOKlsylh1okao6QhLiz7nG98EGn+04cZjQ==" + "version": "0.7.14", + "resolved": "https://registry.npmjs.org/libsodium-sumo/-/libsodium-sumo-0.7.14.tgz", + "integrity": "sha512-2nDge6qlAjcwyslAhWfVumlkeSNK5+WCfKa2/VEq9prvlT5vP2FR0m0o5hmKaYqfsZ4TQVj5czQsimZvXDB1CQ==" }, "node_modules/libsodium-wrappers-sumo": { - "version": "0.7.13", - "resolved": "https://registry.npmjs.org/libsodium-wrappers-sumo/-/libsodium-wrappers-sumo-0.7.13.tgz", - "integrity": "sha512-lz4YdplzDRh6AhnLGF2Dj2IUj94xRN6Bh8T0HLNwzYGwPehQJX6c7iYVrFUPZ3QqxE0bqC+K0IIqqZJYWumwSQ==", + "version": "0.7.14", + "resolved": "https://registry.npmjs.org/libsodium-wrappers-sumo/-/libsodium-wrappers-sumo-0.7.14.tgz", + "integrity": "sha512-0lm7ZwN5a95J2yUi8R1rgQeeaVDIWnvNzgVmXmZswis4mC+bQtbDrB+QpJlL4qklaKx3hVpJjoc6ubzJFiv64Q==", "dependencies": { - "libsodium-sumo": "^0.7.13" + "libsodium-sumo": "^0.7.14" } }, "node_modules/locate-character": { @@ -8626,31 +8504,31 @@ } }, "node_modules/mocha": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.4.0.tgz", - "integrity": "sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA==", - "dev": true, - "dependencies": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "8.1.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.6.0.tgz", + "integrity": "sha512-hxjt4+EEB0SA0ZDygSS015t65lJw/I2yRCS3Ae+SJ5FrbzrXgfYwJr96f0OvIXdj7h4lv/vLCrH3rkiuizFSvw==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^8.1.0", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" }, "bin": { "_mocha": "bin/_mocha", @@ -8660,15 +8538,6 @@ "node": ">= 14.0.0" } }, - "node_modules/mocha/node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/mocha/node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -8678,56 +8547,6 @@ "balanced-match": "^1.0.0" } }, - "node_modules/mocha/node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/mocha/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/mocha/node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/mocha/node_modules/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", @@ -8748,22 +8567,10 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/mocha/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/mocha/node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -8859,9 +8666,9 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/node-abi": { - "version": "3.63.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.63.0.tgz", - "integrity": "sha512-vAszCsOUrUxjGAmdnM/pq7gUgie0IRteCQMX6d4A534fQCR93EJU5qgzBvU6EkFfK27s0T3HEV3BOyJIr7OMYw==", + "version": "3.65.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.65.0.tgz", + "integrity": "sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA==", "dev": true, "dependencies": { "semver": "^7.3.5" @@ -8916,9 +8723,9 @@ } }, "node_modules/node-hid": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/node-hid/-/node-hid-2.2.0.tgz", - "integrity": "sha512-vj48zh9j555DZzUhMc8tk/qw6xPFrDyPBH1ST1Z/hWaA/juBJw7IuSxPeOgpzNFNU36mGYj+THioRMt1xOdm/g==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/node-hid/-/node-hid-2.1.2.tgz", + "integrity": "sha512-qhCyQqrPpP93F/6Wc/xUR7L8mAJW0Z6R7HMQV8jCHHksAxNDe/4z4Un/H9CpLOT+5K39OPyt9tIQlavxWES3lg==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -9004,10 +8811,13 @@ } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "dev": true, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -9339,9 +9149,9 @@ } }, "node_modules/pg": { - "version": "8.11.5", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.5.tgz", - "integrity": "sha512-jqgNHSKL5cbDjFlHyYsCXmQDrfIX/3RsNwYqpd4N0Kt8niLuNoRNH+aazv6cOd43gPh9Y4DjQCtb+X0MH0Hvnw==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.12.0.tgz", + "integrity": "sha512-A+LHUSnwnxrnL/tZ+OLfqR1SxLN3c/pgDztZ47Rpbsd4jUytsTtwQo/TLPRzPJMp/1pbhYVhH9cuSZLAajNfjQ==", "dependencies": { "pg-connection-string": "^2.6.4", "pg-pool": "^3.6.2", @@ -9521,9 +9331,9 @@ } }, "node_modules/prettier": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", - "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -9615,9 +9425,9 @@ } }, "node_modules/qs": { - "version": "6.12.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.1.tgz", - "integrity": "sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==", + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.3.tgz", + "integrity": "sha512-AWJm14H1vVaO/iNZ4/hO+HyaTehuy9nRqVdkTqlJt0HWvBiBIEXFmb4C0DGeYo3Xes9rrEW+TxHsaigCbN5ICQ==", "dev": true, "peer": true, "dependencies": { @@ -10003,9 +9813,9 @@ } }, "node_modules/rxjs/node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/safe-array-concat": { "version": "1.1.2", @@ -10232,9 +10042,9 @@ } }, "node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "bin": { "semver": "bin/semver.js" }, @@ -10243,9 +10053,9 @@ } }, "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "dependencies": { "randombytes": "^2.1.0" @@ -10976,9 +10786,9 @@ } }, "node_modules/svelte2tsx": { - "version": "0.7.9", - "resolved": "https://registry.npmjs.org/svelte2tsx/-/svelte2tsx-0.7.9.tgz", - "integrity": "sha512-Rm+0LAwg9wT4H2IsR8EaM9EWErTzi9LmuZKxkH5b1ua94XjQmwHstBP4VabLgA9AE6XmwBg+xK7Cjzwfm6ustQ==", + "version": "0.7.13", + "resolved": "https://registry.npmjs.org/svelte2tsx/-/svelte2tsx-0.7.13.tgz", + "integrity": "sha512-aObZ93/kGAiLXA/I/kP+x9FriZM+GboB/ReOIGmLNbVGEd2xC+aTCppm3mk1cc9I/z60VQf7b2QDxC3jOXu3yw==", "dependencies": { "dedent-js": "^1.0.1", "pascal-case": "^3.1.1" @@ -11075,16 +10885,16 @@ } }, "node_modules/table/node_modules/ajv": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.14.0.tgz", - "integrity": "sha512-oYs1UUtO97ZO2lJ4bwnWeQW8/zvOIQLGKcvPTsWmvc2SYgBb+upuNS5NxoLaMU4h8Ju3Nbj6Cq8mD2LQoqVKFA==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -11586,9 +11396,9 @@ } }, "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", "peer": true, "bin": { "tsc": "bin/tsc", @@ -11609,9 +11419,9 @@ } }, "node_modules/uglify-js": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.0.tgz", + "integrity": "sha512-wNKHUY2hYYkf6oSFfhwwiHo4WCHzHmzcXsqXYTN9ja3iApYIFbb2U6ics9hBcYLHcYGQoAlwnZlTrf3oF+BL/Q==", "dev": true, "optional": true, "peer": true, @@ -11989,72 +11799,17 @@ "node": ">=8.0.0" } }, - "node_modules/web3-utils/node_modules/@noble/curves": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.3.0.tgz", - "integrity": "sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA==", - "dev": true, - "peer": true, - "dependencies": { - "@noble/hashes": "1.3.3" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/web3-utils/node_modules/@noble/hashes": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", - "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==", - "dev": true, - "peer": true, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/web3-utils/node_modules/@scure/bip32": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.3.tgz", - "integrity": "sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ==", - "dev": true, - "peer": true, - "dependencies": { - "@noble/curves": "~1.3.0", - "@noble/hashes": "~1.3.2", - "@scure/base": "~1.1.4" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/web3-utils/node_modules/@scure/bip39": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.2.tgz", - "integrity": "sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA==", - "dev": true, - "peer": true, - "dependencies": { - "@noble/hashes": "~1.3.2", - "@scure/base": "~1.1.4" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/web3-utils/node_modules/ethereum-cryptography": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.3.tgz", - "integrity": "sha512-BlwbIL7/P45W8FGW2r7LGuvoEZ+7PWsniMvQ4p5s2xCyw9tmaDlpfsN9HjAucbF+t/qpVHwZUisgfK24TCW8aA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", + "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", "dev": true, "peer": true, "dependencies": { - "@noble/curves": "1.3.0", - "@noble/hashes": "1.3.3", - "@scure/bip32": "1.3.3", - "@scure/bip39": "1.2.2" + "@noble/curves": "1.4.2", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" } }, "node_modules/webidl-conversions": { @@ -12211,9 +11966,9 @@ } }, "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", "dev": true }, "node_modules/wrap-ansi": { @@ -12240,9 +11995,9 @@ "dev": true }, "node_modules/ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", "engines": { "node": ">=8.3.0" }, @@ -12319,9 +12074,9 @@ } }, "node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, "engines": { "node": ">=10" @@ -12366,4 +12121,3 @@ } } } - diff --git a/package.json b/package.json index e80b4dd6..ddc89f29 100644 --- a/package.json +++ b/package.json @@ -24,11 +24,12 @@ "dependencies": { "@0xpolygonhermez/zkevm-commonjs": "github:0xpolygonhermez/zkevm-commonjs#v1.0.0", "@axelar-network/axelar-cgp-solidity": "6.3.1", - "@axelar-network/axelar-cgp-sui": "https://github.com/axelarnetwork/axelar-cgp-sui.git#main", + "@axelar-network/axelar-cgp-sui": "https://github.com/axelarnetwork/axelar-cgp-sui.git", "@axelar-network/axelar-gmp-sdk-solidity": "5.9.0", "@axelar-network/interchain-token-service": "1.2.4", "@cosmjs/cosmwasm-stargate": "^0.32.1", "@ledgerhq/hw-app-eth": "6.32.2", + "@mysten/sui.js": "^0.54.1", "@stellar/stellar-sdk": "^12.0.0-rc3", "axios": "^1.6.2", "path": "^0.12.7" diff --git a/sui/deploy-gateway.js b/sui/deploy-gateway.js index 2a4ea04c..6d28f0e1 100644 --- a/sui/deploy-gateway.js +++ b/sui/deploy-gateway.js @@ -1,6 +1,5 @@ const { saveConfig, prompt, printInfo } = require('../evm/utils'); const { Command, Option } = require('commander'); -const { publishPackage, updateMoveToml } = require('@axelar-network/axelar-cgp-sui/scripts/publish-package'); const { TransactionBlock } = require('@mysten/sui.js/transactions'); const { bcs } = require('@mysten/sui.js/bcs'); const { ethers } = require('hardhat'); @@ -12,7 +11,7 @@ const { const { addBaseOptions } = require('./cli-utils'); const { getWallet, printWalletInfo, broadcast } = require('./sign-utils'); const { bytes32Struct, signersStruct } = require('./types-utils'); -const { getAmplifierSigners, loadSuiConfig } = require('./utils'); +const { getAmplifierSigners, loadSuiConfig, deployPackage } = require('./utils'); async function getSigners(keypair, config, chain, options) { if (options.signers === 'wallet') { @@ -62,15 +61,10 @@ async function processCommand(config, chain, options) { return; } - const published = await publishPackage('axelar_gateway', client, keypair); - const packageId = published.packageId; + const { packageId, publishTxn } = await deployPackage('axelar_gateway', client, keypair); - updateMoveToml('axelar_gateway', packageId); - - const creatorCap = published.publishTxn.objectChanges.find((change) => change.objectType === `${packageId}::gateway::CreatorCap`); - const relayerDiscovery = published.publishTxn.objectChanges.find( - (change) => change.objectType === `${packageId}::discovery::RelayerDiscovery`, - ); + const creatorCap = publishTxn.objectChanges.find((change) => change.objectType === `${packageId}::gateway::CreatorCap`); + const relayerDiscovery = publishTxn.objectChanges.find((change) => change.objectType === `${packageId}::discovery::RelayerDiscovery`); const encodedSigners = signersStruct .serialize({ diff --git a/sui/deploy-test.js b/sui/deploy-test.js index 6a499f00..10c7cafd 100644 --- a/sui/deploy-test.js +++ b/sui/deploy-test.js @@ -1,12 +1,11 @@ const { saveConfig, prompt, printInfo } = require('../evm/utils'); const { Command, Option } = require('commander'); -const { publishPackage, updateMoveToml } = require('@axelar-network/axelar-cgp-sui/scripts/publish-package'); const { TransactionBlock } = require('@mysten/sui.js/transactions'); const { ethers } = require('hardhat'); const { constants: { HashZero }, } = ethers; -const { loadSuiConfig } = require('./utils'); +const { loadSuiConfig, deployPackage } = require('./utils'); const { addBaseOptions } = require('./cli-utils'); const { getWallet, printWalletInfo, broadcast } = require('./sign-utils'); @@ -30,8 +29,7 @@ async function processCommand(config, chain, options) { return; } - const published = await publishPackage('test', client, keypair); - updateMoveToml('test', published.packageId); + const published = await deployPackage('test', client, keypair); const singleton = published.publishTxn.objectChanges.find((change) => change.objectType === `${published.packageId}::test::Singleton`); diff --git a/sui/deploy-utils.js b/sui/deploy-utils.js new file mode 100644 index 00000000..a6f53db6 --- /dev/null +++ b/sui/deploy-utils.js @@ -0,0 +1,177 @@ +const { Command, Option } = require('commander'); +const { TxBuilder, updateMoveToml } = require('@axelar-network/axelar-cgp-sui'); +const { bcs } = require('@mysten/sui.js/bcs'); +const { fromB64, toB64 } = require('@mysten/bcs'); +const { saveConfig, printInfo, validateParameters, prompt, writeJSON } = require('../evm/utils'); +const { addBaseOptions } = require('./cli-utils'); +const { getWallet } = require('./sign-utils'); +const { loadSuiConfig } = require('./utils'); + +async function upgradePackage(client, keypair, packageName, packageConfig, builder, options) { + const { modules, dependencies, digest } = await builder.getContractBuild(packageName); + const { policy, offline } = options; + const sender = options.sender || keypair.toSuiAddress(); + const suiPackageId = '0x2'; + + const upgradeCap = packageConfig.objects?.UpgradeCap; + const digestHash = options.digest ? fromB64(options.digest) : digest; + + validateParameters({ isNonEmptyString: { upgradeCap, policy }, isNonEmptyStringArray: { modules, dependencies } }); + + const tx = builder.tx; + const cap = tx.object(upgradeCap); + + const ticket = tx.moveCall({ + target: `${suiPackageId}::package::authorize_upgrade`, + arguments: [cap, tx.pure(policy), tx.pure(bcs.vector(bcs.u8()).serialize(digestHash).toBytes())], + }); + + const receipt = tx.upgrade({ + modules, + dependencies, + packageId: packageConfig.address, + ticket, + }); + + tx.moveCall({ + target: `${suiPackageId}::package::commit_upgrade`, + arguments: [cap, receipt], + }); + + tx.setSender(sender); + const txBytes = await tx.build({ client }); + + if (offline) { + options.txBytes = txBytes; + } else { + const signature = (await keypair.signTransactionBlock(txBytes)).signature; + const result = await client.executeTransactionBlock({ + transactionBlock: txBytes, + signature, + options: { + showEffects: true, + showObjectChanges: true, + showEvents: true, + }, + }); + + const packageId = (result.objectChanges?.filter((a) => a.type === 'published') ?? [])[0].packageId; + packageConfig.address = packageId; + printInfo('Transaction result', JSON.stringify(result, null, 2)); + printInfo(`${packageName} upgraded`, packageId); + } +} + +async function deployPackage(chain, client, keypair, packageName, packageConfig, builder, options) { + const { offline, sender } = options; + + const address = sender || keypair.toSuiAddress(); + await builder.publishPackageAndTransferCap(packageName, address); + const tx = builder.tx; + tx.setSender(address); + const txBytes = await tx.build({ client }); + + if (offline) { + options.txBytes = txBytes; + } else { + if (prompt(`Proceed with deployment on ${chain.name}?`, options.yes)) { + return; + } + + const signature = (await keypair.signTransactionBlock(txBytes)).signature; + const publishTxn = await client.executeTransactionBlock({ + transactionBlock: txBytes, + signature, + options: { + showEffects: true, + showObjectChanges: true, + showEvents: true, + }, + }); + + packageConfig.address = (publishTxn.objectChanges?.find((a) => a.type === 'published') ?? []).packageId; + const objectChanges = publishTxn.objectChanges.filter((object) => object.type === 'created'); + packageConfig.objects = {}; + + for (const object of objectChanges) { + const array = object.objectType.split('::'); + const objectName = array[array.length - 1]; + + if (objectName) { + packageConfig.objects[objectName] = object.objectId; + } + } + + printInfo(`${packageName} deployed`, JSON.stringify(packageConfig, null, 2)); + } +} + +async function processCommand(chain, options) { + const [keypair, client] = getWallet(chain, options); + const { upgrade, packageName, packageDependencies, offline, txFilePath } = options; + + printInfo('Wallet address', keypair.toSuiAddress()); + + if (!chain.contracts[packageName]) { + chain.contracts[packageName] = {}; + } + + const contractsConfig = chain.contracts; + const packageConfig = contractsConfig?.[packageName]; + + validateParameters({ isNonEmptyString: { packageName } }); + + if (packageDependencies) { + for (const dependencies of packageDependencies) { + const packageId = contractsConfig[dependencies]?.address; + updateMoveToml(dependencies, packageId); + } + } + + const builder = new TxBuilder(client); + + if (upgrade) { + await upgradePackage(client, keypair, packageName, packageConfig, builder, options); + } else { + await deployPackage(chain, client, keypair, packageName, packageConfig, builder, options); + } + + if (offline) { + validateParameters({ isNonEmptyString: { txFilePath } }); + + const txB64Bytes = toB64(options.txBytes); + + writeJSON({ status: 'PENDING', bytes: txB64Bytes }, txFilePath); + printInfo(`The unsigned transaction is`, txB64Bytes); + } +} + +async function mainProcessor(options, processor) { + const config = loadSuiConfig(options.env); + + await processor(config.sui, options); + saveConfig(config, options.env); +} + +if (require.main === module) { + const program = new Command(); + + program.name('deploy-upgrade').description('Deploy/Upgrade the Sui package'); + + addBaseOptions(program); + + program.addOption(new Option('--packageName <packageName>', 'package name to deploy/upgrade')); + program.addOption(new Option('--packageDependencies [packageDependencies...]', 'array of package dependencies')); + program.addOption(new Option('--upgrade', 'deploy or upgrade')); + program.addOption(new Option('--policy <policy>', 'new policy to upgrade')); + program.addOption(new Option('--sender <sender>', 'transaction sender')); + program.addOption(new Option('--digest <digest>', 'digest hash for upgrade')); + program.addOption(new Option('--offline', 'store tx block for sign')); + program.addOption(new Option('--txFilePath <file>', 'unsigned transaction will be stored')); + + program.action((options) => { + mainProcessor(options, processCommand); + }); + + program.parse(); +} diff --git a/sui/utils.js b/sui/utils.js index 03d2de1b..9b9e760d 100644 --- a/sui/utils.js +++ b/sui/utils.js @@ -8,6 +8,7 @@ const { } = ethers; const { fromB64 } = require('@mysten/bcs'); const { CosmWasmClient } = require('@cosmjs/cosmwasm-stargate'); +const { updateMoveToml, copyMovePackage, TxBuilder } = require('@axelar-network/axelar-cgp-sui'); const getAmplifierSigners = async (config, chain) => { const client = await CosmWasmClient.connect(config.axelar.rpc); @@ -61,6 +62,21 @@ const loadSuiConfig = (env) => { return config; }; +const deployPackage = async (packageName, client, keypair, options = {}) => { + const compileDir = `${__dirname}/move`; + + copyMovePackage(packageName, null, compileDir); + + const builder = new TxBuilder(client); + await builder.publishPackageAndTransferCap(packageName, options.owner || keypair.toSuiAddress(), compileDir); + const publishTxn = await builder.signAndExecute(keypair); + + const packageId = (publishTxn.objectChanges?.find((a) => a.type === 'published') ?? []).packageId; + + updateMoveToml(packageName, packageId, compileDir); + return { packageId, publishTxn }; +}; + const findPublishedObject = (published, packageName, contractName) => { const packageId = published.packageId; return published.publishTxn.objectChanges.find((change) => change.objectType === `${packageId}::${packageName}::${contractName}`); @@ -70,5 +86,6 @@ module.exports = { getAmplifierSigners, getBcsBytesByObjectId, loadSuiConfig, + deployPackage, findPublishedObject, }; From f08eb066b0d9fc6a319eb0c2f61b87af0c188304 Mon Sep 17 00:00:00 2001 From: Foivos <foivos@umich.edu> Date: Thu, 18 Jul 2024 19:56:20 +0300 Subject: [PATCH 20/44] feat: add axelar trasceiver to the info files (#304) --- axelar-chains-config/info/mainnet.json | 20 ++++++++++++++++++++ axelar-chains-config/info/testnet.json | 20 ++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/axelar-chains-config/info/mainnet.json b/axelar-chains-config/info/mainnet.json index 1b8ec7f0..cb02b7ce 100644 --- a/axelar-chains-config/info/mainnet.json +++ b/axelar-chains-config/info/mainnet.json @@ -112,6 +112,16 @@ "deployer": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", "implementation": "0xA852412D2d91fE05d790934B6E64C3C351fAB54f", "address": "0x83a93500d23Fbc3e82B410aD07A6a9F7A0670D66" + }, + "AxelarTransceiver": { + "salt": "AXELAR_TRANSCEIVER v1.1.0", + "deployer": "0xba76c6980428A0b10CFC5d8ccb61949677A61233", + "implementation": "0x87fc4b27385bb4e69a40027931229d74ef4d1943", + "address": "0x723AEAD29acee7E9281C32D11eA4ed0070c41B13", + "TransceiverStructs": "0xa12bc993d8144404a8c8c812816048275a066ced", + "wstETH token": "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", + "NttManager": "0xb948a93827d68a82F6513Ad178964Da487fe2BD9", + "wormholeChainId": 2 } }, "explorer": { @@ -733,6 +743,16 @@ "deployer": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", "implementation": "0xA852412D2d91fE05d790934B6E64C3C351fAB54f", "address": "0x83a93500d23Fbc3e82B410aD07A6a9F7A0670D66" + }, + "AxelarTransceiver": { + "salt": "AXELAR_TRANSCEIVER v1.1.0", + "deployer": "0xba76c6980428A0b10CFC5d8ccb61949677A61233", + "implementation": "0xa1ebb6a4b856df8bf6c3aca88a9115a9ab3b2e02", + "address": "0x723AEAD29acee7E9281C32D11eA4ed0070c41B13", + "TransceiverStructs": "0x27a3daf3b243104e9b0afae6b56026a416b852c9", + "wstETH token": "0x26c5e01524d2E6280A48F2c50fF6De7e52E9611C", + "NttManager": "0x6981F5621691CBfE3DdD524dE71076b79F0A0278", + "wormholeChainId": 4 } }, "explorer": { diff --git a/axelar-chains-config/info/testnet.json b/axelar-chains-config/info/testnet.json index bd0d5b8d..128e3f39 100644 --- a/axelar-chains-config/info/testnet.json +++ b/axelar-chains-config/info/testnet.json @@ -94,6 +94,16 @@ "deployer": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", "implementation": "0xA852412D2d91fE05d790934B6E64C3C351fAB54f", "address": "0x83a93500d23Fbc3e82B410aD07A6a9F7A0670D66" + }, + "AxelarTransceiver": { + "salt": "Transceiver 1.1.0", + "deployer": "0xc28a80699B5914a29465971E6ac5a40370C4f29b", + "implementation": "0xcc6e5c994de73e8a115263b1b512e29b2026df55", + "address": "0xaa8267908e8d2BEfeB601f88A7Cf3ec148039423", + "TransceiverStructs": "0x1ed363be5e925e0f0741207f3f9a48c366d26aba", + "wstETH token": "0xB82381A3fBD3FaFA77B3a7bE693342618240067b", + "NttManager": "0x8B715EAf61A7DdF61C67d5D46687c796D1f47146", + "wormholeChainId": 10002 } }, "explorer": { @@ -558,6 +568,16 @@ "deployer": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", "implementation": "0xA852412D2d91fE05d790934B6E64C3C351fAB54f", "address": "0x83a93500d23Fbc3e82B410aD07A6a9F7A0670D66" + }, + "AxelarTransceiver": { + "salt": "Transceiver 1.1.0", + "deployer": "0xc28a80699B5914a29465971E6ac5a40370C4f29b", + "implementation": "0x4fe90d921e279f149ee7c7e1a79ee75803e846b1", + "address": "0xaa8267908e8d2BEfeB601f88A7Cf3ec148039423", + "TransceiverStructs": "0xeecf56798cfc9e927a83f98b0112484623cf175a", + "wstETH token": "0x0B15635FCF5316EdFD2a9A0b0dC3700aeA4D09E6", + "NttManager": "0x66Cb5a992570EF01b522Bc59A056a64A84Bd0aAa", + "wormholeChainId": 4 } }, "explorer": { From 9eb7341088cc0a2fd55e76377cd9b2a14f0989e9 Mon Sep 17 00:00:00 2001 From: Milap Sheth <milap@interoplabs.io> Date: Thu, 18 Jul 2024 15:42:57 -0400 Subject: [PATCH 21/44] refactor(sui): rename pubkey to pub_key for weighted signer type (#307) --- sui/README.md | 2 +- sui/deploy-gateway.js | 10 +++++----- sui/gateway.js | 6 +++--- sui/types-utils.js | 2 +- sui/utils.js | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/sui/README.md b/sui/README.md index 4fb3e275..48d14aef 100644 --- a/sui/README.md +++ b/sui/README.md @@ -68,7 +68,7 @@ node sui/deploy-gateway.js --signers wallet --nonce test - You can also provide a JSON object with a full signer set: ```bash -node sui/deploy-gateway.js -e testnet --signers '{"signers": [{"pubkey": "0x020194ead85b350d90472117e6122cf1764d93bf17d6de4b51b03d19afc4d6302b", "weight": 1}], "threshold": 1, "nonce": "0x0000000000000000000000000000000000000000000000000000000000000000"}' +node sui/deploy-gateway.js -e testnet --signers '{"signers": [{"pub_key": "0x020194ead85b350d90472117e6122cf1764d93bf17d6de4b51b03d19afc4d6302b", "weight": 1}], "threshold": 1, "nonce": "0x0000000000000000000000000000000000000000000000000000000000000000"}' ``` Deploy the Gas Service package: diff --git a/sui/deploy-gateway.js b/sui/deploy-gateway.js index 6d28f0e1..4c849f42 100644 --- a/sui/deploy-gateway.js +++ b/sui/deploy-gateway.js @@ -15,15 +15,15 @@ const { getAmplifierSigners, loadSuiConfig, deployPackage } = require('./utils') async function getSigners(keypair, config, chain, options) { if (options.signers === 'wallet') { - const pubkey = keypair.getPublicKey().toRawBytes(); - printInfo('Using wallet pubkey as the signer for the gateway', hexlify(pubkey)); + const pubKey = keypair.getPublicKey().toRawBytes(); + printInfo('Using wallet pubkey as the signer for the gateway', hexlify(pubKey)); if (keypair.getKeyScheme() !== 'Secp256k1') { throw new Error('Only Secp256k1 pubkeys are supported by the gateway'); } return { - signers: [{ pubkey, weight: 1 }], + signers: [{ pub_key: pubKey, weight: 1 }], threshold: 1, nonce: options.nonce ? keccak256(toUtf8Bytes(options.nonce)) : HashZero, }; @@ -32,8 +32,8 @@ async function getSigners(keypair, config, chain, options) { const signers = JSON.parse(options.signers); return { - signers: signers.signers.map(({ pubkey, weight }) => { - return { pubkey: arrayify(pubkey), weight }; + signers: signers.signers.map(({ pub_key: pubKey, weight }) => { + return { pub_key: arrayify(pubKey), weight }; }), threshold: signers.threshold, nonce: arrayify(signers.nonce) || HashZero, diff --git a/sui/gateway.js b/sui/gateway.js index 0078d20e..f5b7818e 100644 --- a/sui/gateway.js +++ b/sui/gateway.js @@ -35,7 +35,7 @@ function getProofSigners(keypair, options) { } return { - signers: [{ pubkey: keypair.getPublicKey().toRawBytes(), weight: 1 }], + signers: [{ pub_key: keypair.getPublicKey().toRawBytes(), weight: 1 }], threshold: 1, nonce: options.currentNonce ? keccak256(toUtf8Bytes(options.currentNonce)) : HashZero, }; @@ -44,8 +44,8 @@ function getProofSigners(keypair, options) { const proof = JSON.parse(options.proof); return { - signers: proof.signers.signers.map(({ pubkey, weight }) => { - return { pubkey: arrayify(pubkey), weight }; + signers: proof.signers.signers.map(({ pub_key: pubKey, weight }) => { + return { pub_key: arrayify(pubKey), weight }; }), threshold: proof.signers.threshold, nonce: arrayify(proof.signers.nonce) || HashZero, diff --git a/sui/types-utils.js b/sui/types-utils.js index 5f2c0a4b..b8c3c98e 100644 --- a/sui/types-utils.js +++ b/sui/types-utils.js @@ -13,7 +13,7 @@ const addressStruct = bcs.bytes(32).transform({ }); const signerStruct = bcs.struct('WeightedSigner', { - pubkey: bcs.vector(bcs.u8()), + pub_key: bcs.vector(bcs.u8()), weight: bcs.u128(), }); diff --git a/sui/utils.js b/sui/utils.js index 9b9e760d..e46aedcb 100644 --- a/sui/utils.js +++ b/sui/utils.js @@ -20,10 +20,10 @@ const getAmplifierSigners = async (config, chain) => { const weightedSigners = signers .map((signer) => ({ - pubkey: arrayify(`0x${signer.pub_key.ecdsa}`), + pub_key: arrayify(`0x${signer.pub_key.ecdsa}`), weight: Number(signer.weight), })) - .sort((a, b) => hexlify(a.pubkey).localeCompare(hexlify(b.pubkey))); + .sort((a, b) => hexlify(a.pub_key).localeCompare(hexlify(b.pub_key))); return { signers: weightedSigners, From a46acfb2187d262a8d6d44a9f55d2ce09656ce82 Mon Sep 17 00:00:00 2001 From: re1ro <rma4ok@gmail.com> Date: Sun, 21 Jul 2024 23:52:14 -0400 Subject: [PATCH 22/44] fix(stellar): u128 signature weight (#309) --- stellar/deploy-contract.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stellar/deploy-contract.js b/stellar/deploy-contract.js index a392641c..033bd774 100644 --- a/stellar/deploy-contract.js +++ b/stellar/deploy-contract.js @@ -29,10 +29,10 @@ function getInitializeArgs(chain, contractName, wallet, options) { signers: [ { signer: Address.fromString(wallet.publicKey()).toBuffer(), - weight: new ScInt(1, { type: 'u256' }), + weight: new ScInt(1, { type: 'u128' }), }, ], - threshold: new ScInt(1, { type: 'u256' }), + threshold: new ScInt(1, { type: 'u128' }), nonce: Buffer.alloc(32), }); From bb9c89c08fbf54bfd5188f0e5538f71689694597 Mon Sep 17 00:00:00 2001 From: Milap Sheth <milap@interoplabs.io> Date: Mon, 22 Jul 2024 02:11:25 -0400 Subject: [PATCH 23/44] chore(evm): remove unused scripts (#310) --- evm/README.md | 32 ++- evm/deploy-amplifier-gateway.js | 6 +- evm/deploy-const-address-deployer.js | 136 ----------- evm/deploy-contract.js | 8 +- evm/deploy-create3-deployer.js | 102 --------- evm/deploy-gateway-v4.3.x.js | 331 --------------------------- evm/deploy-gateway-v6.2.x.js | 7 +- evm/deploy-upgradable.js | 18 +- evm/index.js | 12 +- evm/utils.js | 2 +- 10 files changed, 48 insertions(+), 606 deletions(-) delete mode 100644 evm/deploy-const-address-deployer.js delete mode 100644 evm/deploy-create3-deployer.js delete mode 100644 evm/deploy-gateway-v4.3.x.js diff --git a/evm/README.md b/evm/README.md index 1de0df4a..c27a8ea9 100644 --- a/evm/README.md +++ b/evm/README.md @@ -9,11 +9,23 @@ By default the version of contracts specified in `package.json` will be used for Add the deployer private key in `.env` folder (see `.example.env` for reference). -## AxelarGateway +## Deployer Factories -Deploy the gateway contract. +EVM contracts can be deployed using one of 3 supported deployment methods: -`node evm/deploy-gateway-v6.2.x.js -e testnet -n ethereum` +- `create`: Standard nonce based contract deployment +- `create2`: Contract deployment using `CREATE2` opcode, the deployed address is deterministic based on the sender address, contract bytecode, and the salt +- `create3`: Contract deployment using the CREATE3 technique, the deployed address is deterministic based only on the sender address, and the salt. The dependency on the contract bytecode is removed, but as a result, you can't trust that the contract bytecode is the same across chains. + +A tutorial can be found [here](https://www.axelar.network/blog/same-address-cross-chain-tutorial). + +Factories have already been deployed on Axelar connected EVM chains. You can deploy your own factories via the following: + +```bash +node evm/deploy-contract.js -c Create2Deployer -m create + +node evm/deploy-contract.js -c Create3Deployer -m create2 +``` ## Axelar Amplifier Gateway @@ -23,6 +35,12 @@ Deploy the Axelar Amplifier Gateway contract. This is the required gateway contr For debugging, you can deploy a gateway with the wallet set as the signer using `--keyID`. An owner can be set via `--owner` as well. It'll default to the deployer and can be transferred to governance later. +## Axelar Gateway (legacy connection) + +Deploy the original Axelar gateway contract for legacy consensus-based connection. Set the governance and mint limiter via the `--governance` and `--mintLimiter` flags. + +`node evm/deploy-gateway-v6.2.x.js -e testnet -n ethereum` + ## Gateway Upgrade 1. When upgrading the gateway, the proxy contract will be reused. @@ -160,13 +178,13 @@ node evm/contracts-deployment-test.js -e testnet -n fantom -y --deployDepositSer ### Prerequisites -- Clone the repo containing the contract source code. +- Clone the repo containing the contract source code. ```bash git clone https://github.com/axelarnetwork/axelar-cgp-solidity.git ``` -- Checkout to the version of contracts to verify in the directory provided to the command before compiling artifacts used by the command. +- Checkout to the version of contracts to verify in the directory provided to the command before compiling artifacts used by the command. ```bash git checkout vX.Y.Z @@ -176,14 +194,14 @@ npm ci npm run build ``` -- Update `.hardhat.config.js` to have `chains` and `keys` to point to the current repo. +- Update `.hardhat.config.js` to have `chains` and `keys` to point to the current repo. ```javascript const chains = require(`../axelar-contract-deployments/axelar-chains-config/info/${env}.json`); const keys = readJSON(`../axelar-contract-deployments/keys.json`); ``` -- `keys.json` is expected to be in the format described [here](./.example.keys.json). +- `keys.json` is expected to be in the format described [here](./.example.keys.json). You can generate the explorer API key via creating an account on the explorer. ### Example diff --git a/evm/deploy-amplifier-gateway.js b/evm/deploy-amplifier-gateway.js index 2c9c4a54..a0b0bb10 100644 --- a/evm/deploy-amplifier-gateway.js +++ b/evm/deploy-amplifier-gateway.js @@ -28,6 +28,7 @@ const { getWeightedSigners, getContractJSON, getDeployedAddress, + getDeployOptions, } = require('./utils'); const { calculateDomainSeparator, isValidCosmosAddress } = require('../cosmwasm/utils'); const { addExtendedOptions } = require('./cli-utils'); @@ -119,10 +120,7 @@ async function deploy(config, chain, options) { const gasOptions = await getGasOptions(chain, options, contractName); const gatewayFactory = new ContractFactory(AxelarAmplifierGateway.abi, AxelarAmplifierGateway.bytecode, wallet); - - const deployerContract = - options.deployMethod === 'create3' ? chain.contracts.Create3Deployer?.address : chain.contracts.ConstAddressDeployer?.address; - const salt = options.salt || 'AxelarAmplifierGateway'; + const { deployerContract, salt } = getDeployOptions(options.deployMethod, options.salt || 'AxelarAmplifierGateway', chain); let gateway; let proxyAddress; diff --git a/evm/deploy-const-address-deployer.js b/evm/deploy-const-address-deployer.js deleted file mode 100644 index e187b842..00000000 --- a/evm/deploy-const-address-deployer.js +++ /dev/null @@ -1,136 +0,0 @@ -'use strict'; - -const { ethers } = require('hardhat'); -const { Wallet, getDefaultProvider, ContractFactory } = ethers; -const { Command, Option } = require('commander'); -const chalk = require('chalk'); - -const { printInfo, writeJSON, predictAddressCreate, deployCreate, getGasOptions, prompt } = require('./utils'); -const { addExtendedOptions } = require('./cli-utils'); -const contractJson = require('@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/deploy/ConstAddressDeployer.sol/ConstAddressDeployer.json'); -const contractName = 'ConstAddressDeployer'; - -async function deployConstAddressDeployer(wallet, chain, options = {}, verifyOptions = null) { - printInfo('Deployer address', wallet.address); - - const contracts = chain.contracts; - - if (!contracts[contractName]) { - contracts[contractName] = {}; - } - - const contractConfig = contracts[contractName]; - - const provider = wallet.provider; - const expectedAddress = contractConfig.address ? contractConfig.address : await predictAddressCreate(wallet.address, 0); - - if (!options.force && (await provider.getCode(expectedAddress)) !== '0x') { - console.log(`ConstAddressDeployer already deployed at address ${expectedAddress}`); - contractConfig.address = expectedAddress; - contractConfig.deployer = wallet.address; - return; - } - - const nonce = await provider.getTransactionCount(wallet.address); - - if (nonce !== 0 && !options.ignore) { - throw new Error(`Nonce value must be zero.`); - } - - const balance = await provider.getBalance(wallet.address); - - if (balance.lte(0)) { - throw new Error(`Deployer account has no funds.`); - } - - console.log(`Deployer has ${balance / 1e18} ${chalk.green(chain.tokenSymbol)} and nonce ${nonce} on ${chain.name}.`); - - const gasOptions = await getGasOptions(chain, options, contractName); - - const constAddressDeployerAddress = await predictAddressCreate(wallet.address, nonce); - printInfo('ConstAddressDeployer will be deployed to', constAddressDeployerAddress); - - if (options.predictOnly || prompt(`Does this match any existing deployments? Proceed with deployment on ${chain.name}?`, options.yes)) { - return; - } - - if (!gasOptions.gasLimit) { - const contractFactory = new ContractFactory(contractJson.abi, contractJson.bytecode, wallet); - const tx = contractFactory.getDeployTransaction(); - gasOptions.gasLimit = Math.floor((await wallet.provider.estimateGas(tx)) * 1.5); - } - - if (!gasOptions.gasPrice) { - gasOptions.gasPrice = Math.floor((await wallet.provider.getGasPrice()) * 1.2); - } - - const requiredBalance = gasOptions.gasLimit * gasOptions.gasPrice; - - if (!options.ignore && balance < requiredBalance) { - await (await wallet.sendTransaction({ to: wallet.address, value: requiredBalance - balance })).wait(); - } - - const contract = await deployCreate(wallet, contractJson, [], gasOptions, verifyOptions); - - contractConfig.address = contract.address; - contractConfig.deployer = wallet.address; - - printInfo(`${chain.name} | ConstAddressDeployer:`, contractConfig.address); -} - -async function main(options) { - const config = require(`${__dirname}/../axelar-chains-config/info/${options.env === 'local' ? 'testnet' : options.env}.json`); - - const chains = options.chainNames.split(',').map((str) => str.trim()); - - for (const chainName of chains) { - if (config.chains[chainName.toLowerCase()] === undefined) { - throw new Error(`Chain ${chainName} is not defined in the info file`); - } - } - - for (const chainName of chains) { - const chain = config.chains[chainName.toLowerCase()]; - - let wallet; - - if (options.env === 'local') { - const [funder] = await ethers.getSigners(); - wallet = new Wallet(options.privateKey, funder.provider); - await (await funder.sendTransaction({ to: wallet.address, value: BigInt(1e21) })).wait(); - } else { - const provider = getDefaultProvider(chain.rpc); - wallet = new Wallet(options.privateKey, provider); - } - - const verifyOptions = options.verify ? { env: options.env, chain: chain.name } : null; - await deployConstAddressDeployer( - wallet, - config.chains[chainName.toLowerCase()], - { yes: options.yes, force: options.force, ignore: options.ignore }, - verifyOptions, - ); - writeJSON(config, `${__dirname}/../axelar-chains-config/info/${options.env}.json`); - } -} - -if (require.main === module) { - const program = new Command(); - - program.name('deploy-const-address-deployer').description('Deploy const address deployer'); - - addExtendedOptions(program, { predictOnly: true }); - - program.addOption(new Option('-i, --ignore', 'ignore the nonce value check')); - program.addOption(new Option('-f, --force', 'proceed with contract deployment even if address already returns a bytecode')); - - program.action((options) => { - main(options); - }); - - program.parse(); -} else { - module.exports = { - deployConstAddressDeployer, - }; -} diff --git a/evm/deploy-contract.js b/evm/deploy-contract.js index 8690e92b..eaef46ed 100644 --- a/evm/deploy-contract.js +++ b/evm/deploy-contract.js @@ -25,6 +25,7 @@ const { mainProcessor, isContract, getContractJSON, + getDeployOptions, } = require('./utils'); const { addExtendedOptions } = require('./cli-utils'); @@ -249,12 +250,7 @@ async function processCommand(config, chain, options) { printInfo(`Constructor args for chain ${chain.name}`, constructorArgs); - const salt = options.salt || contractName; - let deployerContract = deployMethod === 'create3' ? contracts.Create3Deployer?.address : contracts.ConstAddressDeployer?.address; - - if (deployMethod === 'create') { - deployerContract = null; - } + const { deployerContract, salt } = getDeployOptions(deployMethod, options.salt || contractName, chain); const predictedAddress = await getDeployedAddress(wallet.address, deployMethod, { salt, diff --git a/evm/deploy-create3-deployer.js b/evm/deploy-create3-deployer.js deleted file mode 100644 index 6e29b576..00000000 --- a/evm/deploy-create3-deployer.js +++ /dev/null @@ -1,102 +0,0 @@ -'use strict'; - -const { ethers } = require('hardhat'); -const { Wallet, getDefaultProvider } = ethers; -const { predictContractConstant } = require('@axelar-network/axelar-gmp-sdk-solidity'); -const { Command } = require('commander'); -const chalk = require('chalk'); - -const { printInfo, writeJSON, deployCreate2, getGasOptions, prompt } = require('./utils'); -const { addExtendedOptions } = require('./cli-utils'); -const contractJson = require('@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/deploy/Create3Deployer.sol/Create3Deployer.json'); -const { deployConstAddressDeployer } = require('./deploy-const-address-deployer'); -const contractName = 'Create3Deployer'; - -async function deployCreate3Deployer(wallet, chain, provider, options = {}, verifyOptions = null) { - printInfo('Deployer address', wallet.address); - - console.log( - `Deployer has ${(await wallet.provider.getBalance(wallet.address)) / 1e18} ${chalk.green( - chain.tokenSymbol, - )} and nonce ${await wallet.provider.getTransactionCount(wallet.address)} on ${chain.name}.`, - ); - - const contracts = chain.contracts; - - if (!contracts[contractName]) { - contracts[contractName] = {}; - } - - const contractConfig = contracts[contractName]; - const gasOptions = await getGasOptions(chain, options, contractName); - - const salt = options.salt || contractName; - printInfo('Create3 deployer deployment salt', salt); - - const constAddressDeployer = contracts.ConstAddressDeployer.address; - - const create3DeployerAddress = await predictContractConstant(constAddressDeployer, wallet, contractJson, salt); - printInfo('Create3 deployer will be deployed to', create3DeployerAddress); - - if (options.predictOnly || prompt(`Does this match any existing deployments? Proceed with deployment on ${chain.name}?`, options.yes)) { - return; - } - - const contract = await deployCreate2(constAddressDeployer, wallet, contractJson, [], salt, gasOptions.gasLimit, verifyOptions); - - contractConfig.salt = salt; - contractConfig.address = contract.address; - contractConfig.deployer = wallet.address; - - printInfo(`${chain.name} | ConstAddressDeployer:`, constAddressDeployer); - printInfo(`${chain.name} | Create3Deployer`, contractConfig.address); -} - -async function main(options) { - const config = require(`${__dirname}/../axelar-chains-config/info/${options.env === 'local' ? 'testnet' : options.env}.json`); - - const chains = options.chainNames.split(',').map((str) => str.trim()); - - for (const chainName of chains) { - if (config.chains[chainName.toLowerCase()] === undefined) { - throw new Error(`Chain ${chainName} is not defined in the info file`); - } - } - - for (const chainName of chains) { - const chain = config.chains[chainName.toLowerCase()]; - const verifyOptions = options.verify ? { env: options.env, chain: chain.name, only: options.verify } : null; - - let wallet; - let provider; - - if (options.env === 'local') { - const [funder] = await ethers.getSigners(); - wallet = new Wallet(options.privateKey, funder.provider); - await (await funder.sendTransaction({ to: wallet.address, value: BigInt(1e21) })).wait(); - await deployConstAddressDeployer(wallet, config.chains[chains[0].toLowerCase()]); - } else { - provider = getDefaultProvider(chain.rpc); - wallet = new Wallet(options.privateKey, provider); - } - - await deployCreate3Deployer(wallet, chain, provider, { salt: options.salt, yes: options.yes }, verifyOptions); - writeJSON(config, `${__dirname}/../axelar-chains-config/info/${options.env}.json`); - } -} - -if (require.main === module) { - const program = new Command(); - - program.name('deploy-create3-deployer').description('Deploy create3 deployer'); - - addExtendedOptions(program, { salt: true, predictOnly: true }); - - program.action((options) => { - main(options); - }); - - program.parse(); -} else { - module.exports = { deployCreate3Deployer }; -} diff --git a/evm/deploy-gateway-v4.3.x.js b/evm/deploy-gateway-v4.3.x.js deleted file mode 100644 index 1e4ab5fa..00000000 --- a/evm/deploy-gateway-v4.3.x.js +++ /dev/null @@ -1,331 +0,0 @@ -'use strict'; - -const { - printObj, - getBytecodeHash, - verifyContract, - printInfo, - printWarn, - printError, - getEVMAddresses, - saveConfig, - loadConfig, - printWalletInfo, - isAddressArray, - isNumber, - prompt, - getGasOptions, -} = require('./utils'); -const { addExtendedOptions } = require('./cli-utils'); -const { ethers } = require('hardhat'); -const { - getContractFactory, - Wallet, - utils: { defaultAbiCoder, getContractAddress }, - getDefaultProvider, -} = ethers; -const { Command, Option } = require('commander'); - -async function getAuthParams(config, chain) { - const { addresses, weights, threshold, keyID } = await getEVMAddresses(config, chain); - printObj(JSON.stringify({ status: 'latest', keyID, addresses, weights, threshold })); - const paramsAuth = [defaultAbiCoder.encode(['address[]', 'uint256[]', 'uint256'], [addresses, weights, threshold])]; - return paramsAuth; -} - -function getProxyParams(adminAddresses, adminThreshold) { - const admins = JSON.parse(adminAddresses); - return defaultAbiCoder.encode(['address[]', 'uint8', 'bytes'], [admins, adminThreshold, '0x']); -} - -async function deploy(config, options) { - const { privateKey, skipExisting, adminAddresses, adminThreshold, verify, yes, predictOnly } = options; - const chainName = options.chainName.toLowerCase(); - - const contractName = 'AxelarGateway'; - - const chain = config.chains[chainName] || { contracts: {}, name: chainName, id: chainName, rpc: options.rpc, tokenSymbol: 'ETH' }; - const rpc = options.rpc || chain.rpc; - const provider = getDefaultProvider(rpc); - - const wallet = new Wallet(privateKey).connect(provider); - - await printWalletInfo(wallet); - - if (chain.contracts[contractName] === undefined) { - chain.contracts[contractName] = {}; - } - - const contractConfig = chain.contracts[contractName]; - const transactionCount = await wallet.getTransactionCount(); - const proxyAddress = getContractAddress({ - from: wallet.address, - nonce: transactionCount + 3, - }); - printInfo('Predicted proxy address', proxyAddress); - - const gasOptions = await getGasOptions(chain, options, contractName); - - printInfo('Is verification enabled?', verify ? 'y' : 'n'); - printInfo('Skip existing contracts?', skipExisting ? 'y' : 'n'); - - const gatewayFactory = await getContractFactory('AxelarGateway', wallet); - const authFactory = await getContractFactory('AxelarAuthWeighted', wallet); - const tokenDeployerFactory = await getContractFactory('TokenDeployer', wallet); - const gatewayProxyFactory = await getContractFactory('AxelarGatewayProxy', wallet); - - if (!adminAddresses || !isAddressArray(JSON.parse(adminAddresses))) { - printError('Invalid admin addresses', `${adminAddresses}`); - return; - } - - if (!adminThreshold || !isNumber(parseInt(adminThreshold))) { - printError('Invalid admin threshold', `${adminThreshold}`); - return; - } - - let gateway; - let auth; - let tokenDeployer; - let implementation; - const contractsToVerify = []; - - if (predictOnly || prompt(`Does derived address match existing gateway deployments? Proceed with deployment on ${chain.name}?`, yes)) { - return; - } - - contractConfig.deployer = wallet.address; - - if (skipExisting && contractConfig.authModule) { - auth = authFactory.attach(contractConfig.authModule); - } else { - printInfo(`Deploying auth contract`); - - const params = await getAuthParams(config, chain.axelarId); - printInfo('Auth deployment args', params); - - auth = await authFactory.deploy(params, gasOptions); - await auth.deployTransaction.wait(chain.confirmations); - - contractsToVerify.push({ - address: auth.address, - params: [params], - }); - } - - if (skipExisting && contractConfig.tokenDeployer) { - tokenDeployer = tokenDeployerFactory.attach(contractConfig.tokenDeployer); - } else { - printInfo(`Deploying token deployer contract`); - - tokenDeployer = await tokenDeployerFactory.deploy(gasOptions); - await tokenDeployer.deployTransaction.wait(chain.confirmations); - - contractsToVerify.push({ - address: tokenDeployer.address, - params: [], - }); - } - - printInfo('Auth address', auth.address); - printInfo('Token Deployer address', tokenDeployer.address); - - printInfo(`Deploying gateway implementation contract`); - printInfo('Gateway Implementation args', `${auth.address},${tokenDeployer.address}`); - - if (skipExisting && contractConfig.implementation) { - implementation = gatewayFactory.attach(contractConfig.implementation); - } else { - implementation = await gatewayFactory.deploy(auth.address, tokenDeployer.address, gasOptions); - await implementation.deployTransaction.wait(chain.confirmations); - } - - printInfo('Gateway Implementation', implementation.address); - - const implementationCodehash = await getBytecodeHash(implementation, chainName); - printInfo('Gateway Implementation codehash', implementationCodehash); - - contractsToVerify.push({ - address: implementation.address, - params: [auth.address, tokenDeployer.address], - }); - - if (skipExisting && contractConfig.address) { - gateway = gatewayFactory.attach(contractConfig.address); - } else { - const params = getProxyParams(adminAddresses, adminThreshold); - printInfo(`Deploying gateway proxy contract`); - printInfo(`Proxy deployment args`, `${implementation.address},${params}`); - - const gatewayProxy = await gatewayProxyFactory.deploy(implementation.address, params, gasOptions); - await gatewayProxy.deployTransaction.wait(chain.confirmations); - - printInfo('Gateway Proxy', gatewayProxy.address); - - gateway = gatewayFactory.attach(gatewayProxy.address); - - contractsToVerify.push({ - address: gatewayProxy.address, - params: [implementation.address, params], - }); - } - - if (!(skipExisting && contractConfig.address)) { - printInfo('Transferring auth ownership'); - await auth.transferOwnership(gateway.address, gasOptions).then((tx) => tx.wait(chain.confirmations)); - printInfo('Transferred auth ownership. All done!'); - } - - var error = false; - const epoch = await gateway.adminEpoch(); - const admins = `${await gateway.admins(epoch)}`.split(','); - printInfo(`Existing admins ${admins}`); - const encodedAdmins = JSON.parse(adminAddresses); - - if (`${admins}` !== `${encodedAdmins}`) { - printError(`ERROR: Retrieved admins are different:`); - printError(` Actual: ${admins}`); - printError(` Expected: ${encodedAdmins}`); - error = true; - } - - const authModule = await gateway.authModule(); - - if (authModule !== auth.address) { - printError(`ERROR: Auth module retrieved from gateway ${authModule} doesn't match deployed contract ${auth.address}`); - error = true; - } - - const tokenDeployerAddress = await gateway.tokenDeployer(); - - if (tokenDeployerAddress !== tokenDeployer.address) { - printError( - `ERROR: Token deployer retrieved from gateway ${tokenDeployerAddress} doesn't match deployed contract ${tokenDeployer.address}`, - ); - error = true; - } - - const authOwner = await auth.owner(); - - if (authOwner !== gateway.address) { - printError(`ERROR: Auth module owner is set to ${authOwner} instead of proxy address ${gateway.address}`); - error = true; - } - - const gatewayImplementation = await gateway.implementation(); - - if (gatewayImplementation !== implementation.address) { - printError( - `ERROR: Implementation contract retrieved from gateway ${gatewayImplementation} doesn't match deployed contract ${implementation.address}`, - ); - error = true; - } - - if (error) { - printError('Deployment status', 'FAILED'); - return; - } - - contractConfig.address = gateway.address; - contractConfig.implementation = implementation.address; - contractConfig.implementationCodehash = implementationCodehash; - contractConfig.authModule = auth.address; - contractConfig.tokenDeployer = tokenDeployer.address; - - printInfo('Deployment status', 'SUCCESS'); - - saveConfig(config, options.env); - - if (verify) { - // Verify contracts at the end to avoid deployment failures in the middle - for (const contract of contractsToVerify) { - await verifyContract(options.env, chain.name, contract.address, contract.params); - } - - printInfo('Verified all contracts!'); - } -} - -async function upgrade(config, options) { - const { chainName, privateKey, yes } = options; - - const contractName = 'AxelarGateway'; - - const chain = config.chains[chainName] || { contracts: {}, name: chainName, id: chainName, rpc: options.rpc, tokenSymbol: 'ETH' }; - const rpc = options.rpc || chain.rpc; - const provider = getDefaultProvider(rpc); - - const wallet = new Wallet(privateKey).connect(provider); - await printWalletInfo(wallet); - - const contractConfig = chain.contracts[contractName]; - - const gatewayFactory = await getContractFactory('AxelarGateway', wallet); - const gateway = gatewayFactory.attach(contractConfig.address); - const implementationCodehash = await getBytecodeHash(contractConfig.implementation, chainName, provider); - const setupParams = '0x'; - - printInfo('Gateway Proxy', gateway.address); - printInfo('Current implementation', await gateway.implementation()); - printInfo('Upgrading to implementation', contractConfig.implementation); - printInfo('Implementation codehash', implementationCodehash); - - const gasOptions = await getGasOptions(chain, options, contractName); - - if (prompt(`Proceed with upgrade on ${chain.name}?`, yes)) { - return; - } - - const tx = await gateway.upgrade(contractConfig.implementation, implementationCodehash, setupParams, gasOptions); - printInfo('Upgrade transaction', tx.hash); - - await tx.wait(chain.confirmations); - - const newImplementation = await gateway.implementation(); - printInfo('New implementation', newImplementation); - - if (newImplementation !== contractConfig.implementation) { - printWarn('Implementation not upgraded yet!'); - return; - } - - printInfo('Upgraded to', newImplementation); -} - -async function main(options) { - const config = loadConfig(options.env); - - if (!options.upgrade) { - await deploy(config, options); - } else { - await upgrade(config, options); - } - - saveConfig(config, options.env); -} - -async function programHandler() { - const program = new Command(); - - program.name('deploy-gateway-v4.3.x').description('Deploy gateway v4.3.x'); - - addExtendedOptions(program, { skipExisting: true, upgrade: true, predictOnly: true }); - - program.addOption(new Option('-r, --rpc <rpc>', 'chain rpc url').env('URL')); - program.addOption(new Option('-a, --adminAddresses <adminAddresses>', 'admin addresses').env('ADMIN_ADDRESSES')); - program.addOption(new Option('-t, --adminThreshold <adminThreshold>', 'admin threshold').env('ADMIN_THRESHOLD')); - - program.action((options) => { - main(options); - }); - - program.parse(); -} - -if (require.main === module) { - programHandler(); -} - -module.exports = { - deployGatewayv4: deploy, -}; diff --git a/evm/deploy-gateway-v6.2.x.js b/evm/deploy-gateway-v6.2.x.js index 314fec41..1bff3f0d 100644 --- a/evm/deploy-gateway-v6.2.x.js +++ b/evm/deploy-gateway-v6.2.x.js @@ -27,6 +27,7 @@ const { isContract, deployContract, getGasOptions, + getDeployOptions, } = require('./utils'); const { addExtendedOptions } = require('./cli-utils'); const { storeSignedTx, signTransaction, getWallet } = require('./sign-utils.js'); @@ -134,9 +135,7 @@ async function deploy(config, chain, options) { const authFactory = new ContractFactory(AxelarAuthWeighted.abi, AxelarAuthWeighted.bytecode, wallet); const tokenDeployerFactory = new ContractFactory(TokenDeployer.abi, TokenDeployer.bytecode, wallet); const gatewayProxyFactory = new ContractFactory(AxelarGatewayProxy.abi, AxelarGatewayProxy.bytecode, wallet); - - const deployerContract = - options.deployMethod === 'create3' ? chain.contracts.Create3Deployer?.address : chain.contracts.ConstAddressDeployer?.address; + const { deployerContract } = getDeployOptions(options.deployMethod, options.salt || 'AxelarGateway v6.2', chain); let gateway; let auth; @@ -553,5 +552,5 @@ if (require.main === module) { } module.exports = { - deployGatewayv6: deploy, + deployLegacyGateway: deploy, }; diff --git a/evm/deploy-upgradable.js b/evm/deploy-upgradable.js index dfc9801d..4ade9fba 100644 --- a/evm/deploy-upgradable.js +++ b/evm/deploy-upgradable.js @@ -12,7 +12,16 @@ const IUpgradable = require('@axelar-network/axelar-gmp-sdk-solidity/interfaces/ const { Command, Option } = require('commander'); const { deployUpgradable, deployCreate2Upgradable, deployCreate3Upgradable, upgradeUpgradable } = require('./upgradable'); -const { printInfo, printError, printWalletInfo, getDeployedAddress, prompt, getGasOptions, mainProcessor } = require('./utils'); +const { + printInfo, + printError, + printWalletInfo, + getDeployedAddress, + prompt, + getGasOptions, + getDeployOptions, + mainProcessor, +} = require('./utils'); const { addExtendedOptions } = require('./cli-utils'); function getProxy(wallet, proxyAddress) { @@ -135,12 +144,7 @@ async function processCommand(_, chain, options) { const implArgs = await getImplementationArgs(contractName, contracts, options); const gasOptions = await getGasOptions(chain, options, contractName); printInfo(`Implementation args for chain ${chain.name}`, implArgs); - const salt = options.salt || contractName; - let deployerContract = deployMethod === 'create3' ? contracts.Create3Deployer?.address : contracts.ConstAddressDeployer?.address; - - if (deployMethod === 'create') { - deployerContract = null; - } + const { deployerContract, salt } = getDeployOptions(deployMethod, options.salt || contractName, chain); if (upgrade) { if (!contractConfig.address) { diff --git a/evm/index.js b/evm/index.js index 8a335d80..9df5072a 100644 --- a/evm/index.js +++ b/evm/index.js @@ -2,10 +2,8 @@ const { printObj, readJSON, writeJSON, importNetworks, verifyContract, getBytecodeHash } = require('./utils'); const { deployITS } = require('./deploy-its'); -const { deployConstAddressDeployer } = require('./deploy-const-address-deployer'); -const { deployCreate3Deployer } = require('./deploy-create3-deployer'); -const { deployGatewayv4 } = require('./deploy-gateway-v4.3.x'); -const { deployGatewayv5 } = require('./deploy-gateway-v5.0.x'); +const { deployAmplifierGateway } = require('./deploy-amplifier-gateway'); +const { deployLegacyGateway } = require('./deploy-gateway-v6.2.x'); module.exports = { printObj, @@ -14,9 +12,7 @@ module.exports = { importNetworks, verifyContract, getBytecodeHash, - deployConstAddressDeployer, - deployCreate3Deployer, deployITS, - deployGatewayv4, - deployGatewayv5, + deployAmplifierGateway, + deployLegacyGateway, }; diff --git a/evm/utils.js b/evm/utils.js index 8510a7ff..4b93b38a 100644 --- a/evm/utils.js +++ b/evm/utils.js @@ -521,7 +521,7 @@ const getDeployOptions = (deployMethod, salt, chain) => { } if (deployMethod === 'create2') { - deployer = chain.contracts.ConstAddressDeployer?.address; + deployer = chain.contracts.ConstAddressDeployer?.address || chain.contracts.Create2Deployer?.address; } else { deployer = chain.contracts.Create3Deployer?.address; } From ca7fa92e07e16e91963437fb68c8029ae70ed0db Mon Sep 17 00:00:00 2001 From: eguajardo <edwin@axelar.network> Date: Mon, 22 Jul 2024 18:49:48 -0600 Subject: [PATCH 24/44] feat(amplifier): add instantiation governance proposal (#299) --- cosmwasm/README.md | 52 ++++ cosmwasm/deploy-contract.js | 404 +--------------------------- cosmwasm/submit-proposal.js | 137 +++++++++- cosmwasm/utils.js | 508 ++++++++++++++++++++++++++++++++++-- 4 files changed, 670 insertions(+), 431 deletions(-) diff --git a/cosmwasm/README.md b/cosmwasm/README.md index cfded868..bbc5a2fd 100644 --- a/cosmwasm/README.md +++ b/cosmwasm/README.md @@ -133,3 +133,55 @@ To deploy with a constant address using instantiate2, pass the `--instantiate2` To upload the contract and compute the expected address without instantiating, pass `--instantiate2` and `-u`. This will write the contract address and the code id to the config file. A salt can be passed with `-s`. If no salt is passed but a salt is needed for constant address deployment, the contract name will be used as a salt. Pass `-r` to skip the upload step, and reuse the previous code id (specified in the config). + +### Deploying through governance proposals + +On networks where only governance is allowed to upload bytecode or instantiate, the script `submit-proposal` can be used to submit a governance proposal. + +``` +node submit-proposal.js -m [mnemonic] -a [path to contract artifacts] -c [contract name] -e [environment] -n [chain name] --proposalType [store|instantiate] -t [proposal title] -d [proposal description] -r [run as account] --deposit [deposit] +``` + +### Uploading bytecode through governance + +Example usage: + +``` +node cosmwasm/submit-proposal.js --proposalType store -c ServiceRegistry -t "Proposal title" -d "Proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 +``` + +By default, only governance will be able to instantiate the bytecode. To allow other addresses to instantiate the bytecode, pass `--instantiateAddresses [address1],[address2],[addressN]`. + +For transparency and security, it's strongly recommended to include the `--source` and `--builder` options in your proposal: + +- `--source`: Code Source URL is a valid absolute HTTPS URI to the contract's source code. +- `--builder`: Builder is a valid docker image name with tag, such as "cosmwasm/workspace-optimizer-arm64:0.16.0" + +These options enable voters to independently verify that the proposed bytecode matches the public source code. For example: `--source "https://github.com/axelarnetwork/axelar-amplifier/tree/service-registry-v0.4.1/contracts/service-registry" --builder "cosmwasm/workspace-optimizer-arm64:0.16.0"` + +After a store code proposal is accepted, the code id can be retrieved using the command `axelard q wasm list-code` + +### Instantiating through governance + +Prerequisites: Submit a proposal to upload the bytecode as described in the previous section and update `codeId` in the json config manually. TODO: create a script to automate this process. + +Example usage: + +``` +node cosmwasm/submit-proposal.js --proposalType instantiate -c ServiceRegistry -t "Proposal title" -d "Proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 +``` + +Note: The rules for chain name specification and the use of `--instantiate2` as described in the "Deploy the contracts" and "Constant Address Deployment" sections above also apply when instantiating through governance. Refer to those sections for details on omitting chain names for certain contracts and using `--instantiate2` for address prediction. + +Order of execution to satisfy dependencies: +1. `node cosmwasm/submit-proposal.js --proposalType instantiate -c Router -t "Router roposal title" -d "Router proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 --predictOnly` +2. `node cosmwasm/submit-proposal.js --proposalType instantiate -c NexusGateway -t "NexusGateway roposal title" -d "NexusGateway proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 --predictOnly` +3. `node cosmwasm/submit-proposal.js --proposalType instantiate -c NexusGateway -t "NexusGateway roposal title" -d "NexusGateway proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 -y` +4. `node cosmwasm/submit-proposal.js --proposalType instantiate -c Router -t "Router roposal title" -d "Router proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 -y` +5. `node cosmwasm/submit-proposal.js --proposalType instantiate -c ServiceRegistry -t "ServiceRegistry roposal title" -d "ServiceRegistry proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 -y` +6. `node cosmwasm/submit-proposal.js --proposalType instantiate -c Rewards -t "Rewards roposal title" -d "Rewards proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 -y` +7. `node cosmwasm/submit-proposal.js --proposalType instantiate -c Coordinator -t "Coordinator roposal title" -d "Coordinator proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 -y` +8. `node cosmwasm/submit-proposal.js --proposalType instantiate -c Multisig -t "Multisig roposal title" -d "Multisig proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 -y` +9. `node cosmwasm/submit-proposal.js --proposalType instantiate -c VotingVerifier -t "VotingVerifier roposal title" -d "VotingVerifier proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 -y -n "avalanche"` +10. `node cosmwasm/submit-proposal.js --proposalType instantiate -c Gateway -t "Gateway roposal title" -d "Gateway proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 -y -n "avalanche"` +11. `node cosmwasm/submit-proposal.js --proposalType instantiate -c MultisigProver -t "MultisigProver roposal title" -d "MultisigProver proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 -y -n "avalanche"` diff --git a/cosmwasm/deploy-contract.js b/cosmwasm/deploy-contract.js index 5397d3ec..28f9c811 100644 --- a/cosmwasm/deploy-contract.js +++ b/cosmwasm/deploy-contract.js @@ -3,399 +3,19 @@ require('dotenv').config(); const { isNil } = require('lodash'); -const { - printInfo, - loadConfig, - saveConfig, - isString, - isStringArray, - isKeccak256Hash, - isNumber, - prompt, - toBigNumberString, -} = require('../evm/utils'); +const { printInfo, loadConfig, saveConfig, prompt } = require('../evm/utils'); const { prepareWallet, prepareClient, + getChains, uploadContract, instantiateContract, - isValidCosmosAddress, - calculateDomainSeparator, + makeInstantiateMsg, governanceAddress, } = require('./utils'); const { Command, Option } = require('commander'); -const validateAddress = (address) => { - return isString(address) && isValidCosmosAddress(address); -}; - -const makeCoordinatorInstantiateMsg = ({ governanceAddress }) => { - if (!validateAddress(governanceAddress)) { - throw new Error('Missing or invalid Coordinator.governanceAddress in axelar info'); - } - - return { governance_address: governanceAddress }; -}; - -const makeServiceRegistryInstantiateMsg = ({ governanceAccount }) => { - if (!validateAddress(governanceAccount)) { - throw new Error('Missing or invalid ServiceRegistry.governanceAccount in axelar info'); - } - - return { governance_account: governanceAccount }; -}; - -const makeMultisigInstantiateMsg = ({ adminAddress, governanceAddress, blockExpiry }, { Rewards: { address: rewardsAddress } }) => { - if (!validateAddress(adminAddress)) { - throw new Error('Missing or invalid Multisig.adminAddress in axelar info'); - } - - if (!validateAddress(governanceAddress)) { - throw new Error('Missing or invalid Multisig.governanceAddress in axelar info'); - } - - if (!validateAddress(rewardsAddress)) { - throw new Error('Missing or invalid Rewards.address in axelar info'); - } - - if (!isNumber(blockExpiry)) { - throw new Error(`Missing or invalid Multisig.blockExpiry in axelar info`); - } - - return { - admin_address: adminAddress, - governance_address: governanceAddress, - rewards_address: rewardsAddress, - block_expiry: toBigNumberString(blockExpiry), - }; -}; - -const makeRewardsInstantiateMsg = ({ governanceAddress, rewardsDenom, params }) => { - if (!validateAddress(governanceAddress)) { - throw new Error('Missing or invalid Rewards.governanceAddress in axelar info'); - } - - if (!isString(rewardsDenom)) { - throw new Error('Missing or invalid Rewards.rewardsDenom in axelar info'); - } - - return { governance_address: governanceAddress, rewards_denom: rewardsDenom, params }; -}; - -const makeRouterInstantiateMsg = ({ adminAddress, governanceAddress }, { NexusGateway: { address: nexusGateway } }) => { - if (!validateAddress(adminAddress)) { - throw new Error('Missing or invalid Router.adminAddress in axelar info'); - } - - if (!validateAddress(governanceAddress)) { - throw new Error('Missing or invalid Router.governanceAddress in axelar info'); - } - - if (!validateAddress(nexusGateway)) { - throw new Error('Missing or invalid NexusGateway.address in axelar info'); - } - - return { admin_address: adminAddress, governance_address: governanceAddress, nexus_gateway: nexusGateway }; -}; - -const makeNexusGatewayInstantiateMsg = ({ nexus }, { Router: { address: router } }) => { - if (!validateAddress(nexus)) { - throw new Error('Missing or invalid NexusGateway.nexus in axelar info'); - } - - if (!validateAddress(router)) { - throw new Error('Missing or invalid Router.address in axelar info'); - } - - return { nexus, router }; -}; - -const makeVotingVerifierInstantiateMsg = ( - contractConfig, - { ServiceRegistry: { address: serviceRegistryAddress }, Rewards: { address: rewardsAddress } }, - { id: chainId }, -) => { - const { - [chainId]: { governanceAddress, serviceName, sourceGatewayAddress, votingThreshold, blockExpiry, confirmationHeight, msgIdFormat }, - } = contractConfig; - - if (!validateAddress(serviceRegistryAddress)) { - throw new Error('Missing or invalid ServiceRegistry.address in axelar info'); - } - - if (!validateAddress(rewardsAddress)) { - throw new Error('Missing or invalid Rewards.address in axelar info'); - } - - if (!validateAddress(governanceAddress)) { - throw new Error(`Missing or invalid VotingVerifier[${chainId}].governanceAddress in axelar info`); - } - - if (!isString(serviceName)) { - throw new Error(`Missing or invalid VotingVerifier[${chainId}].serviceName in axelar info`); - } - - if (!isString(sourceGatewayAddress)) { - throw new Error(`Missing or invalid VotingVerifier[${chainId}].sourceGatewayAddress in axelar info`); - } - - if (!isStringArray(votingThreshold)) { - throw new Error(`Missing or invalid VotingVerifier[${chainId}].votingThreshold in axelar info`); - } - - if (!isNumber(blockExpiry)) { - throw new Error(`Missing or invalid VotingVerifier[${chainId}].blockExpiry in axelar info`); - } - - if (!isNumber(confirmationHeight)) { - throw new Error(`Missing or invalid VotingVerifier[${chainId}].confirmationHeight in axelar info`); - } - - if (!isString(msgIdFormat)) { - throw new Error(`Missing or invalid VotingVerifier[${chainId}].msgIdFormat in axelar info`); - } - - return { - service_registry_address: serviceRegistryAddress, - rewards_address: rewardsAddress, - governance_address: governanceAddress, - service_name: serviceName, - source_gateway_address: sourceGatewayAddress, - voting_threshold: votingThreshold, - block_expiry: blockExpiry, - confirmation_height: confirmationHeight, - source_chain: chainId, - msg_id_format: msgIdFormat, - }; -}; - -const makeGatewayInstantiateMsg = ({ Router: { address: routerAddress }, VotingVerifier }, { id: chainId }) => { - const { - [chainId]: { address: verifierAddress }, - } = VotingVerifier; - - if (!validateAddress(routerAddress)) { - throw new Error('Missing or invalid Router.address in axelar info'); - } - - if (!validateAddress(verifierAddress)) { - throw new Error(`Missing or invalid VotingVerifier[${chainId}].address in axelar info`); - } - - return { router_address: routerAddress, verifier_address: verifierAddress }; -}; - -const makeMultisigProverInstantiateMsg = (config, chainName) => { - const { - axelar: { contracts, chainId: axelarChainId }, - chains: { [chainName]: chainConfig }, - } = config; - - const { axelarId: chainId } = chainConfig; - - const { - Router: { address: routerAddress }, - Coordinator: { address: coordinatorAddress }, - Multisig: { address: multisigAddress }, - ServiceRegistry: { address: serviceRegistryAddress }, - VotingVerifier: { - [chainId]: { address: verifierAddress }, - }, - Gateway: { - [chainId]: { address: gatewayAddress }, - }, - MultisigProver: contractConfig, - } = contracts; - const { - [chainId]: { - adminAddress, - governanceAddress, - domainSeparator, - signingThreshold, - serviceName, - verifierSetDiffThreshold, - encoder, - keyType, - }, - } = contractConfig; - - if (!isString(chainId)) { - throw new Error(`Missing or invalid axelar ID for chain ${chainName}`); - } - - if (!validateAddress(routerAddress)) { - throw new Error('Missing or invalid Router.address in axelar info'); - } - - if (!isString(axelarChainId)) { - throw new Error(`Missing or invalid chain ID`); - } - - const separator = domainSeparator || calculateDomainSeparator(chainId, routerAddress, axelarChainId); - contractConfig[chainId].domainSeparator = separator; - - if (!validateAddress(adminAddress)) { - throw new Error(`Missing or invalid MultisigProver[${chainId}].adminAddress in axelar info`); - } - - if (!validateAddress(governanceAddress)) { - throw new Error(`Missing or invalid MultisigProver[${chainId}].governanceAddress in axelar info`); - } - - if (!validateAddress(gatewayAddress)) { - throw new Error(`Missing or invalid Gateway[${chainId}].address in axelar info`); - } - - if (!validateAddress(coordinatorAddress)) { - throw new Error('Missing or invalid Coordinator.address in axelar info'); - } - - if (!validateAddress(multisigAddress)) { - throw new Error('Missing or invalid Multisig.address in axelar info'); - } - - if (!validateAddress(serviceRegistryAddress)) { - throw new Error('Missing or invalid ServiceRegistry.address in axelar info'); - } - - if (!validateAddress(verifierAddress)) { - throw new Error(`Missing or invalid VotingVerifier[${chainId}].address in axelar info`); - } - - if (!isKeccak256Hash(separator)) { - throw new Error(`Invalid MultisigProver[${chainId}].domainSeparator in axelar info`); - } - - if (!isStringArray(signingThreshold)) { - throw new Error(`Missing or invalid MultisigProver[${chainId}].signingThreshold in axelar info`); - } - - if (!isString(serviceName)) { - throw new Error(`Missing or invalid MultisigProver[${chainId}].serviceName in axelar info`); - } - - if (!isNumber(verifierSetDiffThreshold)) { - throw new Error(`Missing or invalid MultisigProver[${chainId}].verifierSetDiffThreshold in axelar info`); - } - - if (!isString(encoder)) { - throw new Error(`Missing or invalid MultisigProver[${chainId}].encoder in axelar info`); - } - - if (!isString(keyType)) { - throw new Error(`Missing or invalid MultisigProver[${chainId}].keyType in axelar info`); - } - - return { - admin_address: adminAddress, - governance_address: governanceAddress, - gateway_address: gatewayAddress, - coordinator_address: coordinatorAddress, - multisig_address: multisigAddress, - service_registry_address: serviceRegistryAddress, - voting_verifier_address: verifierAddress, - domain_separator: separator.replace('0x', ''), - signing_threshold: signingThreshold, - service_name: serviceName, - chain_name: chainId, - verifier_set_diff_threshold: verifierSetDiffThreshold, - encoder, - key_type: keyType, - }; -}; - -const makeInstantiateMsg = (contractName, chainName, config) => { - const { - axelar: { contracts }, - chains: { [chainName]: chainConfig }, - } = config; - - const { [contractName]: contractConfig } = contracts; - - const { codeId } = contractConfig; - - if (!isNumber(codeId)) { - throw new Error('Code Id is not defined'); - } - - switch (contractName) { - case 'Coordinator': { - if (chainConfig) { - throw new Error('Coordinator does not support chainNames option'); - } - - return makeCoordinatorInstantiateMsg(contractConfig); - } - - case 'ServiceRegistry': { - if (chainConfig) { - throw new Error('ServiceRegistry does not support chainNames option'); - } - - return makeServiceRegistryInstantiateMsg(contractConfig); - } - - case 'Multisig': { - if (chainConfig) { - throw new Error('Multisig does not support chainNames option'); - } - - return makeMultisigInstantiateMsg(contractConfig, contracts); - } - - case 'Rewards': { - if (chainConfig) { - throw new Error('Rewards does not support chainNames option'); - } - - return makeRewardsInstantiateMsg(contractConfig); - } - - case 'Router': { - if (chainConfig) { - throw new Error('Router does not support chainNames option'); - } - - return makeRouterInstantiateMsg(contractConfig, contracts); - } - - case 'NexusGateway': { - if (chainConfig) { - throw new Error('NexusGateway does not support chainNames option'); - } - - return makeNexusGatewayInstantiateMsg(contractConfig, contracts); - } - - case 'VotingVerifier': { - if (!chainConfig) { - throw new Error('VotingVerifier requires chainNames option'); - } - - return makeVotingVerifierInstantiateMsg(contractConfig, contracts, chainConfig); - } - - case 'Gateway': { - if (!chainConfig) { - throw new Error('Gateway requires chainNames option'); - } - - return makeGatewayInstantiateMsg(contracts, chainConfig); - } - - case 'MultisigProver': { - if (!chainConfig) { - throw new Error('MultisigProver requires chainNames option'); - } - - return makeMultisigProverInstantiateMsg(config, chainName); - } - } - - throw new Error(`${contractName} is not supported.`); -}; - const upload = (client, wallet, chainName, config, options) => { const { reuseCodeId, contractName } = options; const { @@ -460,24 +80,10 @@ const instantiate = (client, wallet, chainName, config, options) => { }; const main = async (options) => { - const { env, chainNames, uploadOnly, yes, instantiate2 } = options; + const { env, uploadOnly, yes } = options; const config = loadConfig(env); - let chains = chainNames.split(',').map((str) => str.trim()); - - if (chainNames === 'all') { - chains = Object.keys(config.chains); - } - - if (chains.length !== 1 && instantiate2) { - throw new Error('Cannot pass --instantiate2 with more than one chain'); - } - - const undefinedChain = chains.find((chain) => !config.chains[chain.toLowerCase()] && chain !== 'none'); - - if (undefinedChain) { - throw new Error(`Chain ${undefinedChain} is not defined in the info file`); - } + const chains = getChains(config, options); await prepareWallet(options) .then((wallet) => prepareClient(config, wallet)) diff --git a/cosmwasm/submit-proposal.js b/cosmwasm/submit-proposal.js index 49dfdd3c..dd09d2c7 100644 --- a/cosmwasm/submit-proposal.js +++ b/cosmwasm/submit-proposal.js @@ -2,11 +2,50 @@ require('dotenv').config(); -const { prepareWallet, prepareClient, submitStoreCodeProposal } = require('./utils'); -const { saveConfig, loadConfig, printInfo } = require('../evm/utils'); +const { + prepareWallet, + prepareClient, + getChains, + decodeProposalAttributes, + encodeStoreCodeProposal, + encodeInstantiateProposal, + encodeInstantiate2Proposal, + submitProposal, + makeInstantiateMsg, + instantiate2AddressForProposal, + governanceAddress, +} = require('./utils'); +const { saveConfig, loadConfig, printInfo, prompt } = require('../evm/utils'); +const { StoreCodeProposal, InstantiateContractProposal, InstantiateContract2Proposal } = require('cosmjs-types/cosmwasm/wasm/v1/proposal'); const { Command, Option } = require('commander'); +const updateContractConfig = (contractConfig, chainConfig, key, value) => { + if (chainConfig) { + contractConfig[chainConfig.axelarId] = { + ...contractConfig[chainConfig.axelarId], + [key]: value, + }; + } else { + contractConfig[key] = value; + } +}; + +const predictAndUpdateAddress = (client, contractConfig, chainConfig, options, contractName, chainName) => { + return instantiate2AddressForProposal(client, contractConfig, options).then((contractAddress) => { + updateContractConfig(contractConfig, chainConfig, 'address', contractAddress); + + return contractAddress; + }); +}; + +const printProposal = (proposal, proposalType) => { + printInfo( + `Encoded ${proposal.typeUrl}`, + JSON.stringify(decodeProposalAttributes(proposalType.toJSON(proposalType.decode(proposal.value))), null, 2), + ); +}; + const storeCode = (client, wallet, config, options) => { const { contractName } = options; const { @@ -15,20 +54,95 @@ const storeCode = (client, wallet, config, options) => { }, } = config; - submitStoreCodeProposal(client, wallet, config, options).then((proposalId) => { + const proposal = encodeStoreCodeProposal(options); + + printProposal(proposal, StoreCodeProposal); + + if (prompt(`Proceed with proposal submission?`, options.yes)) { + return Promise.resolve(); + } + + return submitProposal(client, wallet, config, options, proposal).then((proposalId) => { printInfo('Proposal submitted', proposalId); contractConfig.storeCodeProposalId = proposalId; }); }; +const instantiate = (client, wallet, config, options, chainName) => { + const { contractName, instantiate2, predictOnly } = options; + const { + axelar: { + contracts: { [contractName]: contractConfig }, + }, + chains: { [chainName]: chainConfig }, + } = config; + + if (predictOnly) { + return predictAndUpdateAddress(client, contractConfig, chainConfig, options, contractName, chainName); + } + + const initMsg = makeInstantiateMsg(contractName, chainName, config); + + let proposal; + + if (instantiate2) { + proposal = encodeInstantiate2Proposal(config, options, initMsg); + printProposal(proposal, InstantiateContract2Proposal); + } else { + proposal = encodeInstantiateProposal(config, options, initMsg); + printProposal(proposal, InstantiateContractProposal); + } + + if (prompt(`Proceed with proposal submission?`, options.yes)) { + return Promise.resolve(); + } + + return submitProposal(client, wallet, config, options, proposal).then((proposalId) => { + printInfo('Proposal submitted', proposalId); + + updateContractConfig(contractConfig, chainConfig, 'instantiateProposalId', proposalId); + + if (instantiate2) { + return predictAndUpdateAddress(client, contractConfig, chainConfig, options, contractName, chainName); + } + }); +}; + const main = async (options) => { - const { env } = options; + const { env, proposalType, contractName } = options; const config = loadConfig(env); await prepareWallet(options) .then((wallet) => prepareClient(config, wallet)) - .then(({ wallet, client }) => storeCode(client, wallet, config, options)) + .then(({ wallet, client }) => { + switch (proposalType) { + case 'store': + return storeCode(client, wallet, config, options); + + case 'instantiate': { + const chains = getChains(config, options); + + return chains.reduce((promise, chain) => { + return promise.then(() => + instantiate(client, wallet, config, options, chain.toLowerCase()).then((contractAddress) => { + if (contractAddress) { + printInfo( + `Predicted address for ${ + chain.toLowerCase() === 'none' ? '' : chain.toLowerCase().concat(' ') + }${contractName}. Address`, + contractAddress, + ); + } + }), + ); + }, Promise.resolve()); + } + + default: + throw new Error('Invalid proposal type'); + } + }) .then(() => saveConfig(config, env)); }; @@ -47,15 +161,26 @@ const programHandler = () => { program.addOption(new Option('-m, --mnemonic <mnemonic>', 'mnemonic').makeOptionMandatory(true).env('MNEMONIC')); program.addOption(new Option('-a, --artifactPath <artifactPath>', 'artifact path').makeOptionMandatory(true).env('ARTIFACT_PATH')); program.addOption(new Option('-c, --contractName <contractName>', 'contract name').makeOptionMandatory(true)); + program.addOption(new Option('-n, --chainNames <chainNames>', 'chain names').default('none')); + program.addOption(new Option('-s, --salt <salt>', 'salt for instantiate2. defaults to contract name').env('SALT')); + program.addOption( + new Option('--admin <address>', 'when instantiating contract, set an admin address. Defaults to governance module account').default( + governanceAddress, + ), + ); + program.addOption(new Option('--instantiate2', 'use instantiate2 for constant address deployment')); program.addOption(new Option('--aarch64', 'aarch64').env('AARCH64').default(false)); program.addOption(new Option('-y, --yes', 'skip prompt confirmation').env('YES')); program.addOption(new Option('-t, --title <title>', 'title of proposal').makeOptionMandatory(true)); program.addOption(new Option('-d, --description <description>', 'description of proposal').makeOptionMandatory(true)); program.addOption(new Option('--deposit <deposit>', 'the proposal deposit').makeOptionMandatory(true)); - program.addOption(new Option('-r, --runAs <runAs>', 'the address that will execute the message').makeOptionMandatory(true)); + program.addOption( + new Option('--proposalType <proposalType>', 'proposal type').choices(['store', 'instantiate']).makeOptionMandatory(true), + ); + program.addOption(new Option('--predictOnly', 'output the predicted changes only').env('PREDICT_ONLY')); program.addOption(new Option('--source <source>', "a valid HTTPS URI to the contract's source code")); program.addOption( diff --git a/cosmwasm/utils.js b/cosmwasm/utils.js index 4067c07c..fe8c30fb 100644 --- a/cosmwasm/utils.js +++ b/cosmwasm/utils.js @@ -1,5 +1,6 @@ 'use strict'; +const zlib = require('zlib'); const { ethers } = require('hardhat'); const { utils: { keccak256 }, @@ -11,9 +12,9 @@ const { calculateFee, GasPrice } = require('@cosmjs/stargate'); const { instantiate2Address, SigningCosmWasmClient } = require('@cosmjs/cosmwasm-stargate'); const { DirectSecp256k1HdWallet } = require('@cosmjs/proto-signing'); const { MsgSubmitProposal } = require('cosmjs-types/cosmos/gov/v1beta1/tx'); -const { StoreCodeProposal } = require('cosmjs-types/cosmwasm/wasm/v1/proposal'); +const { StoreCodeProposal, InstantiateContractProposal, InstantiateContract2Proposal } = require('cosmjs-types/cosmwasm/wasm/v1/proposal'); const { AccessType } = require('cosmjs-types/cosmwasm/wasm/v1/types'); -const { getSaltFromKey } = require('../evm/utils'); +const { getSaltFromKey, isString, isStringArray, isKeccak256Hash, isNumber, toBigNumberString } = require('../evm/utils'); const { normalizeBech32 } = require('@cosmjs/encoding'); const governanceAddress = 'axelar10d07y265gmmuvt4z0w9aw880jnsr700j7v9daj'; @@ -41,6 +42,28 @@ const fromHex = (str) => new Uint8Array(Buffer.from(str.replace('0x', ''), 'hex' const calculateDomainSeparator = (chain, router, network) => keccak256(Buffer.from(`${chain}${router}${network}`)); +const getSalt = (salt, contractName, chainNames) => fromHex(getSaltFromKey(salt || contractName.concat(chainNames))); + +const getChains = (config, { chainNames, instantiate2 }) => { + let chains = chainNames.split(',').map((str) => str.trim()); + + if (chainNames === 'all') { + chains = Object.keys(config.chains); + } + + if (chains.length !== 1 && instantiate2) { + throw new Error('Cannot pass --instantiate2 with more than one chain'); + } + + const undefinedChain = chains.find((chain) => !config.chains[chain.toLowerCase()] && chain !== 'none'); + + if (undefinedChain) { + throw new Error(`Chain ${undefinedChain} is not defined in the info file`); + } + + return chains; +}; + const uploadContract = async (client, wallet, config, options) => { const { artifactPath, contractName, instantiate2, salt, aarch64, chainNames } = options; return wallet @@ -55,12 +78,7 @@ const uploadContract = async (client, wallet, config, options) => { }) .then(({ account, checksum, codeId }) => { const address = instantiate2 - ? instantiate2Address( - fromHex(checksum), - account.address, - fromHex(getSaltFromKey(salt || contractName.concat(chainNames))), - 'axelar', - ) + ? instantiate2Address(fromHex(checksum), account.address, getSalt(salt, contractName, chainNames), 'axelar') : null; return { codeId, address }; @@ -82,7 +100,7 @@ const instantiateContract = (client, wallet, initMsg, config, { contractName, sa ? client.instantiate2( account.address, contractConfig.codeId, - fromHex(getSaltFromKey(salt || contractName.concat(chainNames))), + getSalt(salt, contractName, chainNames), initMsg, contractName, initFee, @@ -95,6 +113,382 @@ const instantiateContract = (client, wallet, initMsg, config, { contractName, sa .then(({ contractAddress }) => contractAddress); }; +const validateAddress = (address) => { + return isString(address) && isValidCosmosAddress(address); +}; + +const makeCoordinatorInstantiateMsg = ({ governanceAddress }) => { + if (!validateAddress(governanceAddress)) { + throw new Error('Missing or invalid Coordinator.governanceAddress in axelar info'); + } + + return { governance_address: governanceAddress }; +}; + +const makeServiceRegistryInstantiateMsg = ({ governanceAccount }) => { + if (!validateAddress(governanceAccount)) { + throw new Error('Missing or invalid ServiceRegistry.governanceAccount in axelar info'); + } + + return { governance_account: governanceAccount }; +}; + +const makeMultisigInstantiateMsg = ({ adminAddress, governanceAddress, blockExpiry }, { Rewards: { address: rewardsAddress } }) => { + if (!validateAddress(adminAddress)) { + throw new Error('Missing or invalid Multisig.adminAddress in axelar info'); + } + + if (!validateAddress(governanceAddress)) { + throw new Error('Missing or invalid Multisig.governanceAddress in axelar info'); + } + + if (!validateAddress(rewardsAddress)) { + throw new Error('Missing or invalid Rewards.address in axelar info'); + } + + if (!isNumber(blockExpiry)) { + throw new Error(`Missing or invalid Multisig.blockExpiry in axelar info`); + } + + return { + admin_address: adminAddress, + governance_address: governanceAddress, + rewards_address: rewardsAddress, + block_expiry: toBigNumberString(blockExpiry), + }; +}; + +const makeRewardsInstantiateMsg = ({ governanceAddress, rewardsDenom, params }) => { + if (!validateAddress(governanceAddress)) { + throw new Error('Missing or invalid Rewards.governanceAddress in axelar info'); + } + + if (!isString(rewardsDenom)) { + throw new Error('Missing or invalid Rewards.rewardsDenom in axelar info'); + } + + return { governance_address: governanceAddress, rewards_denom: rewardsDenom, params }; +}; + +const makeRouterInstantiateMsg = ({ adminAddress, governanceAddress }, { NexusGateway: { address: nexusGateway } }) => { + if (!validateAddress(adminAddress)) { + throw new Error('Missing or invalid Router.adminAddress in axelar info'); + } + + if (!validateAddress(governanceAddress)) { + throw new Error('Missing or invalid Router.governanceAddress in axelar info'); + } + + if (!validateAddress(nexusGateway)) { + throw new Error('Missing or invalid NexusGateway.address in axelar info'); + } + + return { admin_address: adminAddress, governance_address: governanceAddress, nexus_gateway: nexusGateway }; +}; + +const makeNexusGatewayInstantiateMsg = ({ nexus }, { Router: { address: router } }) => { + if (!validateAddress(nexus)) { + throw new Error('Missing or invalid NexusGateway.nexus in axelar info'); + } + + if (!validateAddress(router)) { + throw new Error('Missing or invalid Router.address in axelar info'); + } + + return { nexus, router }; +}; + +const makeVotingVerifierInstantiateMsg = ( + contractConfig, + { ServiceRegistry: { address: serviceRegistryAddress }, Rewards: { address: rewardsAddress } }, + { id: chainId }, +) => { + const { + [chainId]: { governanceAddress, serviceName, sourceGatewayAddress, votingThreshold, blockExpiry, confirmationHeight, msgIdFormat }, + } = contractConfig; + + if (!validateAddress(serviceRegistryAddress)) { + throw new Error('Missing or invalid ServiceRegistry.address in axelar info'); + } + + if (!validateAddress(rewardsAddress)) { + throw new Error('Missing or invalid Rewards.address in axelar info'); + } + + if (!validateAddress(governanceAddress)) { + throw new Error(`Missing or invalid VotingVerifier[${chainId}].governanceAddress in axelar info`); + } + + if (!isString(serviceName)) { + throw new Error(`Missing or invalid VotingVerifier[${chainId}].serviceName in axelar info`); + } + + if (!isString(sourceGatewayAddress)) { + throw new Error(`Missing or invalid VotingVerifier[${chainId}].sourceGatewayAddress in axelar info`); + } + + if (!isStringArray(votingThreshold)) { + throw new Error(`Missing or invalid VotingVerifier[${chainId}].votingThreshold in axelar info`); + } + + if (!isNumber(blockExpiry)) { + throw new Error(`Missing or invalid VotingVerifier[${chainId}].blockExpiry in axelar info`); + } + + if (!isNumber(confirmationHeight)) { + throw new Error(`Missing or invalid VotingVerifier[${chainId}].confirmationHeight in axelar info`); + } + + if (!isString(msgIdFormat)) { + throw new Error(`Missing or invalid VotingVerifier[${chainId}].msgIdFormat in axelar info`); + } + + return { + service_registry_address: serviceRegistryAddress, + rewards_address: rewardsAddress, + governance_address: governanceAddress, + service_name: serviceName, + source_gateway_address: sourceGatewayAddress, + voting_threshold: votingThreshold, + block_expiry: blockExpiry, + confirmation_height: confirmationHeight, + source_chain: chainId, + msg_id_format: msgIdFormat, + }; +}; + +const makeGatewayInstantiateMsg = ({ Router: { address: routerAddress }, VotingVerifier }, { id: chainId }) => { + const { + [chainId]: { address: verifierAddress }, + } = VotingVerifier; + + if (!validateAddress(routerAddress)) { + throw new Error('Missing or invalid Router.address in axelar info'); + } + + if (!validateAddress(verifierAddress)) { + throw new Error(`Missing or invalid VotingVerifier[${chainId}].address in axelar info`); + } + + return { router_address: routerAddress, verifier_address: verifierAddress }; +}; + +const makeMultisigProverInstantiateMsg = (config, chainName) => { + const { + axelar: { contracts, chainId: axelarChainId }, + chains: { [chainName]: chainConfig }, + } = config; + + const { axelarId: chainId } = chainConfig; + + const { + Router: { address: routerAddress }, + Coordinator: { address: coordinatorAddress }, + Multisig: { address: multisigAddress }, + ServiceRegistry: { address: serviceRegistryAddress }, + VotingVerifier: { + [chainId]: { address: verifierAddress }, + }, + Gateway: { + [chainId]: { address: gatewayAddress }, + }, + MultisigProver: contractConfig, + } = contracts; + const { + [chainId]: { + adminAddress, + governanceAddress, + domainSeparator, + signingThreshold, + serviceName, + verifierSetDiffThreshold, + encoder, + keyType, + }, + } = contractConfig; + + if (!isString(chainId)) { + throw new Error(`Missing or invalid axelar ID for chain ${chainName}`); + } + + if (!validateAddress(routerAddress)) { + throw new Error('Missing or invalid Router.address in axelar info'); + } + + if (!isString(axelarChainId)) { + throw new Error(`Missing or invalid chain ID`); + } + + const separator = domainSeparator || calculateDomainSeparator(chainId, routerAddress, axelarChainId); + contractConfig[chainId].domainSeparator = separator; + + if (!validateAddress(adminAddress)) { + throw new Error(`Missing or invalid MultisigProver[${chainId}].adminAddress in axelar info`); + } + + if (!validateAddress(governanceAddress)) { + throw new Error(`Missing or invalid MultisigProver[${chainId}].governanceAddress in axelar info`); + } + + if (!validateAddress(gatewayAddress)) { + throw new Error(`Missing or invalid Gateway[${chainId}].address in axelar info`); + } + + if (!validateAddress(coordinatorAddress)) { + throw new Error('Missing or invalid Coordinator.address in axelar info'); + } + + if (!validateAddress(multisigAddress)) { + throw new Error('Missing or invalid Multisig.address in axelar info'); + } + + if (!validateAddress(serviceRegistryAddress)) { + throw new Error('Missing or invalid ServiceRegistry.address in axelar info'); + } + + if (!validateAddress(verifierAddress)) { + throw new Error(`Missing or invalid VotingVerifier[${chainId}].address in axelar info`); + } + + if (!isKeccak256Hash(separator)) { + throw new Error(`Invalid MultisigProver[${chainId}].domainSeparator in axelar info`); + } + + if (!isStringArray(signingThreshold)) { + throw new Error(`Missing or invalid MultisigProver[${chainId}].signingThreshold in axelar info`); + } + + if (!isString(serviceName)) { + throw new Error(`Missing or invalid MultisigProver[${chainId}].serviceName in axelar info`); + } + + if (!isNumber(verifierSetDiffThreshold)) { + throw new Error(`Missing or invalid MultisigProver[${chainId}].verifierSetDiffThreshold in axelar info`); + } + + if (!isString(encoder)) { + throw new Error(`Missing or invalid MultisigProver[${chainId}].encoder in axelar info`); + } + + if (!isString(keyType)) { + throw new Error(`Missing or invalid MultisigProver[${chainId}].keyType in axelar info`); + } + + return { + admin_address: adminAddress, + governance_address: governanceAddress, + gateway_address: gatewayAddress, + coordinator_address: coordinatorAddress, + multisig_address: multisigAddress, + service_registry_address: serviceRegistryAddress, + voting_verifier_address: verifierAddress, + domain_separator: separator.replace('0x', ''), + signing_threshold: signingThreshold, + service_name: serviceName, + chain_name: chainId, + verifier_set_diff_threshold: verifierSetDiffThreshold, + encoder, + key_type: keyType, + }; +}; + +const makeInstantiateMsg = (contractName, chainName, config) => { + const { + axelar: { contracts }, + chains: { [chainName]: chainConfig }, + } = config; + + const { [contractName]: contractConfig } = contracts; + + const { codeId } = contractConfig; + + if (!isNumber(codeId)) { + throw new Error('Code Id is not defined'); + } + + switch (contractName) { + case 'Coordinator': { + if (chainConfig) { + throw new Error('Coordinator does not support chainNames option'); + } + + return makeCoordinatorInstantiateMsg(contractConfig); + } + + case 'ServiceRegistry': { + if (chainConfig) { + throw new Error('ServiceRegistry does not support chainNames option'); + } + + return makeServiceRegistryInstantiateMsg(contractConfig); + } + + case 'Multisig': { + if (chainConfig) { + throw new Error('Multisig does not support chainNames option'); + } + + return makeMultisigInstantiateMsg(contractConfig, contracts); + } + + case 'Rewards': { + if (chainConfig) { + throw new Error('Rewards does not support chainNames option'); + } + + return makeRewardsInstantiateMsg(contractConfig); + } + + case 'Router': { + if (chainConfig) { + throw new Error('Router does not support chainNames option'); + } + + return makeRouterInstantiateMsg(contractConfig, contracts); + } + + case 'NexusGateway': { + if (chainConfig) { + throw new Error('NexusGateway does not support chainNames option'); + } + + return makeNexusGatewayInstantiateMsg(contractConfig, contracts); + } + + case 'VotingVerifier': { + if (!chainConfig) { + throw new Error('VotingVerifier requires chainNames option'); + } + + return makeVotingVerifierInstantiateMsg(contractConfig, contracts, chainConfig); + } + + case 'Gateway': { + if (!chainConfig) { + throw new Error('Gateway requires chainNames option'); + } + + return makeGatewayInstantiateMsg(contracts, chainConfig); + } + + case 'MultisigProver': { + if (!chainConfig) { + throw new Error('MultisigProver requires chainNames option'); + } + + return makeMultisigProverInstantiateMsg(config, chainName); + } + } + + throw new Error(`${contractName} is not supported.`); +}; + +const instantiate2AddressForProposal = (client, contractConfig, { contractName, salt, chainNames, runAs }) => { + return client + .getCodeDetails(contractConfig.codeId) + .then(({ checksum }) => instantiate2Address(fromHex(checksum), runAs, getSalt(salt, contractName, chainNames), 'axelar')); +}; + const getInstantiatePermission = (accessType, addresses) => { return { permission: accessType, @@ -102,8 +496,18 @@ const getInstantiatePermission = (accessType, addresses) => { }; }; -const encodeStoreCodeProposal = (options) => { - const { artifactPath, contractName, aarch64, title, description, runAs, source, builder, instantiateAddresses } = options; +const getSubmitProposalParams = (options) => { + const { title, description, runAs } = options; + + return { + title, + description, + runAs, + }; +}; + +const getStoreCodeParams = (options) => { + const { artifactPath, contractName, aarch64, source, builder, instantiateAddresses } = options; const wasm = readFileSync(`${artifactPath}/${pascalToSnake(contractName)}${aarch64 ? '-aarch64' : ''}.wasm`); @@ -118,16 +522,41 @@ const encodeStoreCodeProposal = (options) => { ? getInstantiatePermission(AccessType.ACCESS_TYPE_ANY_OF_ADDRESSES, instantiateAddresses) : getInstantiatePermission(AccessType.ACCESS_TYPE_NOBODY, ''); - const proposal = StoreCodeProposal.fromPartial({ - title, - description, - runAs, - wasmByteCode: wasm, + return { + ...getSubmitProposalParams(options), + wasmByteCode: zlib.gzipSync(wasm), source, builder, codeHash, instantiatePermission, - }); + }; +}; + +const getInstantiateContractParams = (config, options, msg) => { + const { contractName, admin } = options; + + const contractConfig = config.axelar.contracts[contractName]; + + return { + ...getSubmitProposalParams(options), + admin, + codeId: contractConfig.codeId, // TODO: get codeId from previous proposal + label: contractName, + msg: Buffer.from(JSON.stringify(msg)), + }; +}; + +const getInstantiateContract2Params = (config, options, msg) => { + const { contractName, salt, chainNames } = options; + + return { + ...getInstantiateContractParams(config, options, msg), + salt: getSalt(salt, contractName, chainNames), + }; +}; + +const encodeStoreCodeProposal = (options) => { + const proposal = StoreCodeProposal.fromPartial(getStoreCodeParams(options)); return { typeUrl: '/cosmwasm.wasm.v1.StoreCodeProposal', @@ -135,6 +564,32 @@ const encodeStoreCodeProposal = (options) => { }; }; +const decodeProposalAttributes = (proposalJson) => { + if (proposalJson.msg) { + proposalJson.msg = JSON.parse(atob(proposalJson.msg)); + } + + return proposalJson; +}; + +const encodeInstantiateProposal = (config, options, msg) => { + const proposal = InstantiateContractProposal.fromPartial(getInstantiateContractParams(config, options, msg)); + + return { + typeUrl: '/cosmwasm.wasm.v1.InstantiateContractProposal', + value: Uint8Array.from(InstantiateContractProposal.encode(proposal).finish()), + }; +}; + +const encodeInstantiate2Proposal = (config, options, msg) => { + const proposal = InstantiateContract2Proposal.fromPartial(getInstantiateContract2Params(config, options, msg)); + + return { + typeUrl: '/cosmwasm.wasm.v1.InstantiateContract2Proposal', + value: Uint8Array.from(InstantiateContract2Proposal.encode(proposal).finish()), + }; +}; + const encodeSubmitProposal = (content, config, options, proposer) => { const { axelar: { tokenSymbol }, @@ -161,27 +616,28 @@ const submitProposal = (client, wallet, config, options, content) => { const submitProposalMsg = encodeSubmitProposal(content, config, options, account.address); - const storeFee = gasLimit === 'auto' ? 'auto' : calculateFee(gasLimit, GasPrice.fromString(gasPrice)); - return client.signAndBroadcast(account.address, [submitProposalMsg], storeFee, ''); + const fee = gasLimit === 'auto' ? 'auto' : calculateFee(gasLimit, GasPrice.fromString(gasPrice)); + return client.signAndBroadcast(account.address, [submitProposalMsg], fee, ''); }) .then( ({ events }) => events.find(({ type }) => type === 'submit_proposal').attributes.find(({ key }) => key === 'proposal_id').value, ); }; -const submitStoreCodeProposal = (client, wallet, config, options) => { - const content = encodeStoreCodeProposal(options); - - return submitProposal(client, wallet, config, options, content); -}; - module.exports = { governanceAddress, prepareWallet, prepareClient, calculateDomainSeparator, + getChains, uploadContract, instantiateContract, - submitStoreCodeProposal, + makeInstantiateMsg, + instantiate2AddressForProposal, + decodeProposalAttributes, + encodeStoreCodeProposal, + encodeInstantiateProposal, + encodeInstantiate2Proposal, + submitProposal, isValidCosmosAddress, }; From ed94803463b6d9fb0c98be9dc15214dbaa85142c Mon Sep 17 00:00:00 2001 From: Milap Sheth <milap@interoplabs.io> Date: Mon, 22 Jul 2024 21:42:18 -0400 Subject: [PATCH 25/44] feat(evm): deploy ITS contracts to immutable (#313) --- axelar-chains-config/info/mainnet.json | 24 ++++++++++++++--- axelar-chains-config/info/testnet.json | 26 ++++++++++++++++--- axelar-chains-config/package-lock.json | 5 ++-- axelar-chains-config/package.json | 2 +- .../src/utils/verifyContract.js | 2 +- package-lock.json | 4 +-- package.json | 2 +- 7 files changed, 49 insertions(+), 16 deletions(-) diff --git a/axelar-chains-config/info/mainnet.json b/axelar-chains-config/info/mainnet.json index cb02b7ce..b3419d65 100644 --- a/axelar-chains-config/info/mainnet.json +++ b/axelar-chains-config/info/mainnet.json @@ -639,7 +639,7 @@ "id": "binance", "axelarId": "binance", "chainId": 56, - "rpc": "https://1rpc.io/bnb", + "rpc": "https://bscrpc.com", "tokenSymbol": "BNB", "wrappedSymbol": "WBNB", "contracts": { @@ -2040,9 +2040,6 @@ "implementation": "0x5aE753f0A558617133bd1ccd98374E222e015763", "deployer": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC" }, - "InterchainTokenService": { - "skip": true - }, "InterchainGovernance": { "address": "0x35dFacdE7B4b80e156e69b1291D12EA51ce123BD", "minimumTimeDelay": 604800, @@ -2091,6 +2088,25 @@ "codehash": "0xf0ad66defbe082df243d4d274e626f557f97579c5c9e19f33d8093d6160808b7", "predeployCodehash": "0x73fc31262c4bad113c79439fd231281201c7c7d45b50328bd86bccf37684bf92", "salt": "Create3Deployer" + }, + "InterchainTokenService": { + "salt": "ITS v1.2.4", + "deployer": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", + "proxySalt": "ITS v1.0.0", + "tokenManagerDeployer": "0x44dDBDD2c6CC9c5e0F4555620c06b1411F99Dc03", + "interchainToken": "0x2f8102DeA2caaee1Ec5Fe67754F828353C4c180F", + "interchainTokenDeployer": "0xCE014b2DCB26d77d4e8206A7EF5e33985E442d38", + "tokenManager": "0x81a0545091864617E7037171FdfcBbdCFE3aeb23", + "tokenHandler": "0x07715674F74c560200c7C95430673180812fCE73", + "implementation": "0x6d59D9360BDAe406614b7E61c53F43a03198A4ef", + "predeployCodehash": "0x08a4a556c4db879b4f24104d13a8baf86915d58b12c81b382dfea2a82d2856cf", + "address": "0xB5FB4BE02232B1bBA4dC8f81dc24C26980dE9e3C" + }, + "InterchainTokenFactory": { + "deployer": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", + "salt": "ITS Factory v1.0.0", + "implementation": "0xA852412D2d91fE05d790934B6E64C3C351fAB54f", + "address": "0x83a93500d23Fbc3e82B410aD07A6a9F7A0670D66" } }, "gasOptions": { diff --git a/axelar-chains-config/info/testnet.json b/axelar-chains-config/info/testnet.json index 128e3f39..fa1e7db1 100644 --- a/axelar-chains-config/info/testnet.json +++ b/axelar-chains-config/info/testnet.json @@ -1117,7 +1117,23 @@ "deployer": "0x5b593E7b1725dc6FcbbFe80b2415B19153F94A85" }, "InterchainTokenService": { - "skip": true + "salt": "ITS v1.2.4", + "deployer": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", + "proxySalt": "ITS v1.0.0", + "tokenManagerDeployer": "0x44dDBDD2c6CC9c5e0F4555620c06b1411F99Dc03", + "interchainToken": "0x2f8102DeA2caaee1Ec5Fe67754F828353C4c180F", + "interchainTokenDeployer": "0xCE014b2DCB26d77d4e8206A7EF5e33985E442d38", + "tokenManager": "0x81a0545091864617E7037171FdfcBbdCFE3aeb23", + "tokenHandler": "0x07715674F74c560200c7C95430673180812fCE73", + "implementation": "0x6d59D9360BDAe406614b7E61c53F43a03198A4ef", + "predeployCodehash": "0x08a4a556c4db879b4f24104d13a8baf86915d58b12c81b382dfea2a82d2856cf", + "address": "0xB5FB4BE02232B1bBA4dC8f81dc24C26980dE9e3C" + }, + "InterchainTokenFactory": { + "deployer": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", + "salt": "ITS Factory v1.0.0", + "implementation": "0xA852412D2d91fE05d790934B6E64C3C351fAB54f", + "address": "0x83a93500d23Fbc3e82B410aD07A6a9F7A0670D66" } }, "gasOptions": { @@ -1899,7 +1915,7 @@ "id": "polygon-sepolia", "axelarId": "polygon-sepolia", "chainId": 80002, - "rpc": "https://polygon-amoy.blockpi.network/v1/rpc/public", + "rpc": "https://rpc-amoy.polygon.technology", "tokenSymbol": "MATIC", "confirmations": 2, "contracts": { @@ -1997,7 +2013,8 @@ "api": "https://api-amoy.polygonscan.com/api" }, "gasOptions": { - "gasLimit": 6000000 + "gasLimit": 6000000, + "gasPriceAdjustment": 1.5 }, "finality": "finalized", "approxFinalityWaitTime": 1 @@ -2104,7 +2121,8 @@ "api": "https://api-sepolia.lineascan.build/api" }, "gasOptions": { - "gasLimit": 7000000 + "gasLimit": 7000000, + "gasPriceAdjustment": 1.4 }, "confirmations": 1, "finality": "400", diff --git a/axelar-chains-config/package-lock.json b/axelar-chains-config/package-lock.json index 8a3a6e95..54fe5eca 100644 --- a/axelar-chains-config/package-lock.json +++ b/axelar-chains-config/package-lock.json @@ -1,12 +1,12 @@ { "name": "@axelar-network/axelar-chains-config", - "version": "1.3.0", + "version": "1.4.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@axelar-network/axelar-chains-config", - "version": "1.3.0", + "version": "1.4.0", "license": "MIT", "dependencies": { "@ethersproject/keccak256": "^5.7.0", @@ -2318,4 +2318,3 @@ } } } - diff --git a/axelar-chains-config/package.json b/axelar-chains-config/package.json index 55772c56..18faa1f8 100644 --- a/axelar-chains-config/package.json +++ b/axelar-chains-config/package.json @@ -1,6 +1,6 @@ { "name": "@axelar-network/axelar-chains-config", - "version": "1.3.0", + "version": "1.4.0", "description": "A utility to get chain information from Axelar", "main": "src/index.js", "types": "dist/index.d.ts", diff --git a/axelar-chains-config/src/utils/verifyContract.js b/axelar-chains-config/src/utils/verifyContract.js index ab8fe4b9..45812107 100644 --- a/axelar-chains-config/src/utils/verifyContract.js +++ b/axelar-chains-config/src/utils/verifyContract.js @@ -31,7 +31,7 @@ const verifyContract = (env, chain, contract, args, options = {}) => { execSync(cmd, { stdio: ['inherit', 'pipe', 'pipe'] }); console.log('Verified!'); } catch (error) { - if (error.message.includes('Reason: Already Verified')) { + if (error.message.toLowerCase().includes('already verified')) { console.log(`Contract ${contract} is already verified on ${chain.toLowerCase()}.`); } else { throw new Error(`An error occurred while trying to verify ${contract} on ${chain.toLowerCase()}:\n${error}`); diff --git a/package-lock.json b/package-lock.json index 227f614a..eae224f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@axelar-network/axelar-contract-deployments", - "version": "1.3.0", + "version": "1.4.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@axelar-network/axelar-contract-deployments", - "version": "1.3.0", + "version": "1.4.0", "license": "MIT", "dependencies": { "@0xpolygonhermez/zkevm-commonjs": "github:0xpolygonhermez/zkevm-commonjs#v1.0.0", diff --git a/package.json b/package.json index ddc89f29..2f5d1907 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@axelar-network/axelar-contract-deployments", - "version": "1.3.0", + "version": "1.4.0", "description": "Axelar contract deployment scripts", "main": "index.js", "scripts": { From 887ffb993ed0d7afdcc9cca9d5132e1940a30f27 Mon Sep 17 00:00:00 2001 From: npty <78221556+npty@users.noreply.github.com> Date: Tue, 23 Jul 2024 15:03:31 +0700 Subject: [PATCH 26/44] chore: use axelar-cgp-sui 0.3.0 and sui sdk 1.x (#315) Co-authored-by: Milap Sheth <milap@interoplabs.io> --- package-lock.json | 77 ++++++++++++++++++++---------------------- package.json | 4 +-- sui/deploy-contract.js | 7 ++-- sui/deploy-gateway.js | 17 +++++++--- sui/deploy-test.js | 4 +-- sui/deploy-utils.js | 6 ++-- sui/faucet.js | 2 +- sui/gas-service.js | 12 +++---- sui/gateway.js | 10 +++--- sui/multisig.js | 2 +- sui/sign-utils.js | 26 +++++++------- sui/transfer-object.js | 8 ++--- sui/types-utils.js | 2 +- 13 files changed, 90 insertions(+), 87 deletions(-) diff --git a/package-lock.json b/package-lock.json index eae224f3..9d4574b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,12 +11,12 @@ "dependencies": { "@0xpolygonhermez/zkevm-commonjs": "github:0xpolygonhermez/zkevm-commonjs#v1.0.0", "@axelar-network/axelar-cgp-solidity": "6.3.1", - "@axelar-network/axelar-cgp-sui": "https://github.com/axelarnetwork/axelar-cgp-sui.git", + "@axelar-network/axelar-cgp-sui": "^0.3.0", "@axelar-network/axelar-gmp-sdk-solidity": "5.9.0", "@axelar-network/interchain-token-service": "1.2.4", "@cosmjs/cosmwasm-stargate": "^0.32.1", "@ledgerhq/hw-app-eth": "6.32.2", - "@mysten/sui.js": "^0.54.1", + "@mysten/sui": "^1.3.0", "@stellar/stellar-sdk": "^12.0.0-rc3", "axios": "^1.6.2", "path": "^0.12.7" @@ -172,13 +172,13 @@ } }, "node_modules/@axelar-network/axelar-cgp-sui": { - "version": "0.1.0", - "resolved": "git+ssh://git@github.com/axelarnetwork/axelar-cgp-sui.git#44336e556e3e9e0fd36bfa854bf88573abc1461a", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@axelar-network/axelar-cgp-sui/-/axelar-cgp-sui-0.3.0.tgz", + "integrity": "sha512-zHhtmT4L1WmOEhL8gjsZKAE+b7EGC+OIIMZTVoXVrK/NRldEoPW6356hGvyGIaWM6UzyxNh2o+JU2jj0C/avaw==", "hasInstallScript": true, - "license": "MIT", "dependencies": { "@cosmjs/cosmwasm-stargate": "^0.32.2", - "@mysten/sui.js": "^0.54.1", + "@mysten/sui": "^1.3.0", "@types/tmp": "^0.2.6", "child_process": "^1.0.2", "ethers": "^5.0.0", @@ -1583,36 +1583,36 @@ } }, "node_modules/@mysten/bcs": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/@mysten/bcs/-/bcs-0.11.1.tgz", - "integrity": "sha512-xP85isNSYUCHd3O/g+TmZYmg4wK6cU8q/n/MebkIGP4CYVJZz2wU/G24xIZ3wI+0iTop4dfgA5kYrg/DQKCUzA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@mysten/bcs/-/bcs-1.0.3.tgz", + "integrity": "sha512-fc2xDj8eteP18zCNr6WStlE0Hxi7kYeY9yAzAN8oyz5EYOLas0JwScR9pAd9VR61BfIThJ+5vxQ6K7Y22lHDVQ==", "dependencies": { - "bs58": "^5.0.0" + "bs58": "^6.0.0" } }, - "node_modules/@mysten/sui.js": { - "version": "0.54.1", - "resolved": "https://registry.npmjs.org/@mysten/sui.js/-/sui.js-0.54.1.tgz", - "integrity": "sha512-TSmGIX7U9O/uS9EKIQdv7/S69KTbBhMJVelXCafJE6IJw8iB9cN9uLu0+uklkBSDrbRmLSEY70jMr3uRFjReIg==", + "node_modules/@mysten/sui": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@mysten/sui/-/sui-1.3.0.tgz", + "integrity": "sha512-KBEM+nzY30i+S1meWage5jU+upNBGSrZxY5v+oz68gj1VluldWwiaf/LtcZ3RnMcnNtkyMkeYpDL9eiMxTBTbQ==", "dependencies": { "@graphql-typed-document-node/core": "^3.2.0", - "@mysten/bcs": "0.11.1", - "@noble/curves": "^1.1.0", - "@noble/hashes": "^1.3.1", - "@scure/bip32": "^1.3.1", - "@scure/bip39": "^1.2.1", + "@mysten/bcs": "1.0.3", + "@noble/curves": "^1.4.2", + "@noble/hashes": "^1.4.0", + "@scure/bip32": "^1.4.0", + "@scure/bip39": "^1.3.0", "@suchipi/femver": "^1.0.0", "bech32": "^2.0.0", - "gql.tada": "^1.7.0", - "graphql": "^16.8.1", - "superstruct": "^1.0.3", - "tweetnacl": "^1.0.3" + "gql.tada": "^1.8.2", + "graphql": "^16.9.0", + "tweetnacl": "^1.0.3", + "valibot": "^0.36.0" }, "engines": { - "node": ">=16" + "node": ">=18" } }, - "node_modules/@mysten/sui.js/node_modules/bech32": { + "node_modules/@mysten/sui/node_modules/bech32": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" @@ -3484,9 +3484,9 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/base-x": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz", - "integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==" + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.0.tgz", + "integrity": "sha512-sMW3VGSX1QWVFA6l8U62MLKz29rRfpTlYdCqLdpLo1/Yd4zZwSbnUaDfciIAowAqvq7YFnWq9hrhdg1KYgc1lQ==" }, "node_modules/base32.js": { "version": "0.1.0", @@ -3689,11 +3689,11 @@ "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" }, "node_modules/bs58": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz", - "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", + "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", "dependencies": { - "base-x": "^4.0.0" + "base-x": "^5.0.0" } }, "node_modules/bs58check": { @@ -10719,14 +10719,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/superstruct": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-1.0.4.tgz", - "integrity": "sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ==", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -11578,6 +11570,11 @@ "dev": true, "peer": true }, + "node_modules/valibot": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-0.36.0.tgz", + "integrity": "sha512-CjF1XN4sUce8sBK9TixrDqFM7RwNkuXdJu174/AwmQUB62QbCQADg5lLe8ldBalFgtj1uKj+pKwDJiNo4Mn+eQ==" + }, "node_modules/vue-template-compiler": { "version": "2.7.16", "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz", diff --git a/package.json b/package.json index 2f5d1907..1341cd3d 100644 --- a/package.json +++ b/package.json @@ -24,12 +24,12 @@ "dependencies": { "@0xpolygonhermez/zkevm-commonjs": "github:0xpolygonhermez/zkevm-commonjs#v1.0.0", "@axelar-network/axelar-cgp-solidity": "6.3.1", - "@axelar-network/axelar-cgp-sui": "https://github.com/axelarnetwork/axelar-cgp-sui.git", + "@axelar-network/axelar-cgp-sui": "^0.3.0", "@axelar-network/axelar-gmp-sdk-solidity": "5.9.0", "@axelar-network/interchain-token-service": "1.2.4", "@cosmjs/cosmwasm-stargate": "^0.32.1", "@ledgerhq/hw-app-eth": "6.32.2", - "@mysten/sui.js": "^0.54.1", + "@mysten/sui": "^1.3.0", "@stellar/stellar-sdk": "^12.0.0-rc3", "axios": "^1.6.2", "path": "^0.12.7" diff --git a/sui/deploy-contract.js b/sui/deploy-contract.js index 8692bf1b..802bfa1b 100644 --- a/sui/deploy-contract.js +++ b/sui/deploy-contract.js @@ -1,10 +1,9 @@ const { saveConfig, printInfo } = require('../evm/utils'); const { Command, Argument, Option } = require('commander'); -const { publishPackage, updateMoveToml } = require('@axelar-network/axelar-cgp-sui/scripts/publish-package'); - +const { updateMoveToml } = require('@axelar-network/axelar-cgp-sui'); const { addBaseOptions } = require('./cli-utils'); const { getWallet, printWalletInfo } = require('./sign-utils'); -const { loadSuiConfig, findPublishedObject } = require('./utils'); +const { loadSuiConfig, findPublishedObject, deployPackage } = require('./utils'); // Add more contracts here to support more modules deployment const contractMap = { @@ -25,7 +24,7 @@ async function processCommand(contractName, config, chain, options) { chain.contracts[contractName] = {}; } - const published = await publishPackage(packageName, client, keypair); + const published = await deployPackage(packageName, client, keypair); const packageId = published.packageId; updateMoveToml(packageName, packageId); diff --git a/sui/deploy-gateway.js b/sui/deploy-gateway.js index 4c849f42..bec033f8 100644 --- a/sui/deploy-gateway.js +++ b/sui/deploy-gateway.js @@ -1,7 +1,7 @@ const { saveConfig, prompt, printInfo } = require('../evm/utils'); const { Command, Option } = require('commander'); -const { TransactionBlock } = require('@mysten/sui.js/transactions'); -const { bcs } = require('@mysten/sui.js/bcs'); +const { Transaction } = require('@mysten/sui/transactions'); +const { bcs } = require('@mysten/sui/bcs'); const { ethers } = require('hardhat'); const { utils: { arrayify, hexlify, toUtf8Bytes, keccak256 }, @@ -53,7 +53,7 @@ async function processCommand(config, chain, options) { } const contractConfig = chain.contracts.axelar_gateway; - const { minimumRotationDelay, domainSeparator } = options; + const { minimumRotationDelay, previousSignerRetention, domainSeparator } = options; const signers = await getSigners(keypair, config, chain, options); const operator = options.operator || keypair.toSuiAddress(); @@ -73,7 +73,7 @@ async function processCommand(config, chain, options) { }) .toBytes(); - const tx = new TransactionBlock(); + const tx = new Transaction(); const separator = tx.moveCall({ target: `${packageId}::bytes32::new`, @@ -86,7 +86,8 @@ async function processCommand(config, chain, options) { tx.object(creatorCap.objectId), tx.pure.address(operator), separator, - tx.pure(minimumRotationDelay), + tx.pure.u64(minimumRotationDelay), + tx.pure.u64(previousSignerRetention), tx.pure(bcs.vector(bcs.u8()).serialize(encodedSigners).toBytes()), tx.object('0x6'), ], @@ -103,6 +104,7 @@ async function processCommand(config, chain, options) { contractConfig.domainSeparator = domainSeparator; contractConfig.operator = operator; contractConfig.minimumRotationDelay = minimumRotationDelay; + contractConfig.previousSignerRetention = previousSignerRetention; printInfo('Gateway deployed', JSON.stringify(contractConfig, null, 2)); } @@ -124,6 +126,11 @@ if (require.main === module) { program.addOption(new Option('--signers <signers>', 'JSON with the initial signer set').env('SIGNERS')); program.addOption(new Option('--operator <operator>', 'operator for the gateway (defaults to the deployer address)').env('OPERATOR')); program.addOption(new Option('--minimumRotationDelay <minimumRotationDelay>', 'minium delay for signer rotations (in ms)').default(0)); + program.addOption( + new Option('--previousSignerRetention <previousSignerRetention>', 'number of previous signers to retain in the gateway').default( + 15, + ), + ); program.addOption(new Option('--domainSeparator <domainSeparator>', 'domain separator').default(HashZero)); program.addOption(new Option('--nonce <nonce>', 'nonce for the signer (defaults to HashZero)')); diff --git a/sui/deploy-test.js b/sui/deploy-test.js index 10c7cafd..1c019bd2 100644 --- a/sui/deploy-test.js +++ b/sui/deploy-test.js @@ -1,6 +1,6 @@ const { saveConfig, prompt, printInfo } = require('../evm/utils'); const { Command, Option } = require('commander'); -const { TransactionBlock } = require('@mysten/sui.js/transactions'); +const { Transaction } = require('@mysten/sui/transactions'); const { ethers } = require('hardhat'); const { constants: { HashZero }, @@ -33,7 +33,7 @@ async function processCommand(config, chain, options) { const singleton = published.publishTxn.objectChanges.find((change) => change.objectType === `${published.packageId}::test::Singleton`); - const tx = new TransactionBlock(); + const tx = new Transaction(); tx.moveCall({ target: `${published.packageId}::test::register_transaction`, diff --git a/sui/deploy-utils.js b/sui/deploy-utils.js index a6f53db6..dcd31db8 100644 --- a/sui/deploy-utils.js +++ b/sui/deploy-utils.js @@ -1,6 +1,6 @@ const { Command, Option } = require('commander'); const { TxBuilder, updateMoveToml } = require('@axelar-network/axelar-cgp-sui'); -const { bcs } = require('@mysten/sui.js/bcs'); +const { bcs } = require('@mysten/sui/bcs'); const { fromB64, toB64 } = require('@mysten/bcs'); const { saveConfig, printInfo, validateParameters, prompt, writeJSON } = require('../evm/utils'); const { addBaseOptions } = require('./cli-utils'); @@ -44,7 +44,7 @@ async function upgradePackage(client, keypair, packageName, packageConfig, build if (offline) { options.txBytes = txBytes; } else { - const signature = (await keypair.signTransactionBlock(txBytes)).signature; + const signature = (await keypair.signTransaction(txBytes)).signature; const result = await client.executeTransactionBlock({ transactionBlock: txBytes, signature, @@ -78,7 +78,7 @@ async function deployPackage(chain, client, keypair, packageName, packageConfig, return; } - const signature = (await keypair.signTransactionBlock(txBytes)).signature; + const signature = (await keypair.signTransaction(txBytes)).signature; const publishTxn = await client.executeTransactionBlock({ transactionBlock: txBytes, signature, diff --git a/sui/faucet.js b/sui/faucet.js index 48dc4ae6..47fbc171 100644 --- a/sui/faucet.js +++ b/sui/faucet.js @@ -1,7 +1,7 @@ 'use strict'; const { addBaseOptions } = require('./cli-utils'); -const { requestSuiFromFaucetV0, getFaucetHost } = require('@mysten/sui.js/faucet'); +const { requestSuiFromFaucetV0, getFaucetHost } = require('@mysten/sui/faucet'); const { getWallet, printWalletInfo } = require('./sign-utils'); const { Command } = require('commander'); const { saveConfig, loadConfig, printInfo } = require('../evm/utils'); diff --git a/sui/gas-service.js b/sui/gas-service.js index fec7fb5f..c3cce96a 100644 --- a/sui/gas-service.js +++ b/sui/gas-service.js @@ -1,7 +1,7 @@ const { saveConfig, printInfo, printError } = require('../evm/utils'); const { Command } = require('commander'); -const { TransactionBlock } = require('@mysten/sui.js/transactions'); -const { bcs } = require('@mysten/sui.js/bcs'); +const { Transaction } = require('@mysten/sui/transactions'); +const { bcs } = require('@mysten/sui/bcs'); const { gasServiceStruct } = require('./types-utils'); const { loadSuiConfig, getBcsBytesByObjectId } = require('./utils'); const { ethers } = require('hardhat'); @@ -24,7 +24,7 @@ async function payGas(keypair, client, gasServiceConfig, args, options) { const [destinationChain, destinationAddress, channelId, payload] = args; const unitAmount = options.amount; - const tx = new TransactionBlock(); + const tx = new Transaction(); const [coin] = tx.splitCoins(tx.gas, [unitAmount]); tx.moveCall({ @@ -57,7 +57,7 @@ async function addGas(keypair, client, gasServiceConfig, args, options) { const [messageId] = args; const unitAmount = options.amount; - const tx = new TransactionBlock(); + const tx = new Transaction(); const [coin] = tx.splitCoins(tx.gas, [unitAmount]); tx.moveCall({ @@ -94,7 +94,7 @@ async function collectGas(keypair, client, gasServiceConfig, args, options) { return; } - const tx = new TransactionBlock(); + const tx = new Transaction(); tx.moveCall({ target: `${gasServicePackageId}::gas_service::collect_gas`, @@ -130,7 +130,7 @@ async function refund(keypair, client, gasServiceConfig, args, options) { return; } - const tx = new TransactionBlock(); + const tx = new Transaction(); tx.moveCall({ target: `${gasServicePackageId}::gas_service::refund`, arguments: [ diff --git a/sui/gateway.js b/sui/gateway.js index f5b7818e..d49fa04d 100644 --- a/sui/gateway.js +++ b/sui/gateway.js @@ -1,7 +1,7 @@ const { saveConfig, printInfo } = require('../evm/utils'); const { Command, Option } = require('commander'); -const { TransactionBlock } = require('@mysten/sui.js/transactions'); -const { bcs } = require('@mysten/sui.js/bcs'); +const { Transaction } = require('@mysten/sui/transactions'); +const { bcs } = require('@mysten/sui/bcs'); const { ethers } = require('hardhat'); const { utils: { arrayify, keccak256, toUtf8Bytes }, @@ -109,7 +109,7 @@ async function callContract(keypair, client, config, chain, args, options) { let channel = options.channel; - const tx = new TransactionBlock(); + const tx = new Transaction(); // Create a temporary channel if one wasn't provided if (!options.channel) { @@ -165,7 +165,7 @@ async function approveMessages(keypair, client, config, chain, args, options) { const encodedProof = getProof(keypair, COMMAND_TYPE_APPROVE_MESSAGES, encodedMessages, contractConfig, options); - const tx = new TransactionBlock(); + const tx = new Transaction(); tx.moveCall({ target: `${packageId}::gateway::approve_messages`, @@ -200,7 +200,7 @@ async function rotateSigners(keypair, client, config, chain, args, options) { const encodedProof = getProof(keypair, COMMAND_TYPE_ROTATE_SIGNERS, encodedSigners, contractConfig, options); - const tx = new TransactionBlock(); + const tx = new Transaction(); tx.moveCall({ target: `${packageId}::gateway::rotate_signers`, diff --git a/sui/multisig.js b/sui/multisig.js index 50d390c9..d7ac4098 100644 --- a/sui/multisig.js +++ b/sui/multisig.js @@ -74,7 +74,7 @@ async function combineSignature(client, chain, options) { const txBlockBytes = fromB64(txBytes); const combinedSignature = multiSigPublicKey.combinePartialSignatures(signatureArray); - const isValid = await multiSigPublicKey.verifyTransactionBlock(txBlockBytes, combinedSignature); + const isValid = await multiSigPublicKey.verifyTransaction(txBlockBytes, combinedSignature); if (!isValid) { throw new Error(`Verification failed for message [${txBytes}]`); diff --git a/sui/sign-utils.js b/sui/sign-utils.js index 34e67033..5cf91fba 100644 --- a/sui/sign-utils.js +++ b/sui/sign-utils.js @@ -1,12 +1,12 @@ 'use strict'; -const { verifyTransactionBlock } = require('@mysten/sui.js/verify'); -const { decodeSuiPrivateKey } = require('@mysten/sui.js/cryptography'); -const { Ed25519Keypair, Ed25519PublicKey } = require('@mysten/sui.js/keypairs/ed25519'); -const { MultiSigPublicKey } = require('@mysten/sui.js/multisig'); -const { Secp256k1Keypair, Secp256k1PublicKey } = require('@mysten/sui.js/keypairs/secp256k1'); -const { Secp256r1Keypair, Secp256r1PublicKey } = require('@mysten/sui.js/keypairs/secp256r1'); -const { SuiClient, getFullnodeUrl } = require('@mysten/sui.js/client'); +const { verifyTransaction } = require('@mysten/sui/verify'); +const { decodeSuiPrivateKey } = require('@mysten/sui/cryptography'); +const { Ed25519Keypair, Ed25519PublicKey } = require('@mysten/sui/keypairs/ed25519'); +const { MultiSigPublicKey } = require('@mysten/sui/multisig'); +const { Secp256k1Keypair, Secp256k1PublicKey } = require('@mysten/sui/keypairs/secp256k1'); +const { Secp256r1Keypair, Secp256r1PublicKey } = require('@mysten/sui/keypairs/secp256r1'); +const { SuiClient, getFullnodeUrl } = require('@mysten/sui/client'); const { fromB64, fromHEX } = require('@mysten/bcs'); const { printInfo } = require('../evm/utils'); const { ethers } = require('hardhat'); @@ -96,8 +96,8 @@ function getRawPrivateKey(keypair) { } async function broadcast(client, keypair, tx) { - return await client.signAndExecuteTransactionBlock({ - transactionBlock: tx, + return await client.signAndExecuteTransaction({ + transaction: tx, signer: keypair, options: { showEffects: true, @@ -120,11 +120,11 @@ async function broadcastSignature(client, txBytes, signature) { } async function signTransactionBlockBytes(keypair, client, txBytes, options) { - const serializedSignature = (await keypair.signTransactionBlock(txBytes)).signature; + const serializedSignature = (await keypair.signTransaction(txBytes)).signature; let publicKey; try { - publicKey = await verifyTransactionBlock(txBytes, serializedSignature); + publicKey = await verifyTransaction(txBytes, serializedSignature); } catch { throw new Error(`Cannot verify tx signature`); } @@ -145,7 +145,7 @@ async function signTransactionBlockBytes(keypair, client, txBytes, options) { } } -async function signTransactionBlock(chain, txDetails, options) { +async function signTransaction(chain, txDetails, options) { const { txBlock, buildOptions = {} } = txDetails; const [keypair, client] = getWallet(chain, options); @@ -231,7 +231,7 @@ module.exports = { getRawPrivateKey, broadcast, broadcastSignature, - signTransactionBlock, + signTransaction, getMultisig, getWrappedPublicKey, signTransactionBlockBytes, diff --git a/sui/transfer-object.js b/sui/transfer-object.js index c1532ff1..abb27c42 100644 --- a/sui/transfer-object.js +++ b/sui/transfer-object.js @@ -1,4 +1,4 @@ -const { TransactionBlock } = require('@mysten/sui.js/transactions'); +const { Transaction } = require('@mysten/sui/transactions'); const { Command, Option } = require('commander'); const { printInfo, validateParameters } = require('../evm/utils'); const { addExtendedOptions } = require('./cli-utils'); @@ -37,10 +37,10 @@ async function processCommand(chain, options) { isKeccak256Hash: { objectId }, }); - const tx = new TransactionBlock(); - tx.transferObjects([`${objectId}`], tx.pure(recipient)); + const tx = new Transaction(); + tx.transferObjects([`${objectId}`], tx.pure.address(recipient)); - const result = await client.signAndExecuteTransactionBlock({ + const result = await client.signAndExecuteTransaction({ transactionBlock: tx, signer: keypair, options: { diff --git a/sui/types-utils.js b/sui/types-utils.js index b8c3c98e..d1861075 100644 --- a/sui/types-utils.js +++ b/sui/types-utils.js @@ -1,6 +1,6 @@ 'use strict'; -const { bcs } = require('@mysten/sui.js/bcs'); +const { bcs } = require('@mysten/sui/bcs'); const { fromHEX, toHEX } = require('@mysten/bcs'); const { ethers } = require('hardhat'); const { From 8657b87568aa3be74967f857fd4416d95bda2c81 Mon Sep 17 00:00:00 2001 From: eguajardo <edwin@axelar.network> Date: Tue, 23 Jul 2024 08:32:13 -0600 Subject: [PATCH 27/44] feat(amplifier): allow to automatically fetch the code id from the network when submitting an instantiation proposal (#308) Co-authored-by: haiyizxx <haiyizxx@gmail.com> --- cosmwasm/README.md | 22 ++++++++++++---------- cosmwasm/submit-proposal.js | 33 +++++++++++++++++++++++++++++++-- cosmwasm/utils.js | 14 +++++++++----- 3 files changed, 52 insertions(+), 17 deletions(-) diff --git a/cosmwasm/README.md b/cosmwasm/README.md index bbc5a2fd..9edd08fb 100644 --- a/cosmwasm/README.md +++ b/cosmwasm/README.md @@ -168,20 +168,22 @@ Prerequisites: Submit a proposal to upload the bytecode as described in the prev Example usage: ``` -node cosmwasm/submit-proposal.js --proposalType instantiate -c ServiceRegistry -t "Proposal title" -d "Proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 +node cosmwasm/submit-proposal.js --proposalType instantiate -c ServiceRegistry -t "Proposal title" -d "Proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --fetchCodeId ``` +Use the option `--fetchCodeId` to retrieve and update the code id from the network by comparing the code hash of the uploaded bytecode with the code hash submitted through the store code proposal mentioned in the previous section. + Note: The rules for chain name specification and the use of `--instantiate2` as described in the "Deploy the contracts" and "Constant Address Deployment" sections above also apply when instantiating through governance. Refer to those sections for details on omitting chain names for certain contracts and using `--instantiate2` for address prediction. Order of execution to satisfy dependencies: 1. `node cosmwasm/submit-proposal.js --proposalType instantiate -c Router -t "Router roposal title" -d "Router proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 --predictOnly` 2. `node cosmwasm/submit-proposal.js --proposalType instantiate -c NexusGateway -t "NexusGateway roposal title" -d "NexusGateway proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 --predictOnly` -3. `node cosmwasm/submit-proposal.js --proposalType instantiate -c NexusGateway -t "NexusGateway roposal title" -d "NexusGateway proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 -y` -4. `node cosmwasm/submit-proposal.js --proposalType instantiate -c Router -t "Router roposal title" -d "Router proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 -y` -5. `node cosmwasm/submit-proposal.js --proposalType instantiate -c ServiceRegistry -t "ServiceRegistry roposal title" -d "ServiceRegistry proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 -y` -6. `node cosmwasm/submit-proposal.js --proposalType instantiate -c Rewards -t "Rewards roposal title" -d "Rewards proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 -y` -7. `node cosmwasm/submit-proposal.js --proposalType instantiate -c Coordinator -t "Coordinator roposal title" -d "Coordinator proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 -y` -8. `node cosmwasm/submit-proposal.js --proposalType instantiate -c Multisig -t "Multisig roposal title" -d "Multisig proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 -y` -9. `node cosmwasm/submit-proposal.js --proposalType instantiate -c VotingVerifier -t "VotingVerifier roposal title" -d "VotingVerifier proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 -y -n "avalanche"` -10. `node cosmwasm/submit-proposal.js --proposalType instantiate -c Gateway -t "Gateway roposal title" -d "Gateway proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 -y -n "avalanche"` -11. `node cosmwasm/submit-proposal.js --proposalType instantiate -c MultisigProver -t "MultisigProver roposal title" -d "MultisigProver proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 -y -n "avalanche"` +3. `node cosmwasm/submit-proposal.js --proposalType instantiate -c NexusGateway -t "NexusGateway roposal title" -d "NexusGateway proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 --fetchCodeId -y` +4. `node cosmwasm/submit-proposal.js --proposalType instantiate -c Router -t "Router roposal title" -d "Router proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 --fetchCodeId -y` +5. `node cosmwasm/submit-proposal.js --proposalType instantiate -c ServiceRegistry -t "ServiceRegistry roposal title" -d "ServiceRegistry proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 --fetchCodeId -y` +6. `node cosmwasm/submit-proposal.js --proposalType instantiate -c Rewards -t "Rewards roposal title" -d "Rewards proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 --fetchCodeId -y` +7. `node cosmwasm/submit-proposal.js --proposalType instantiate -c Coordinator -t "Coordinator roposal title" -d "Coordinator proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 --fetchCodeId -y` +8. `node cosmwasm/submit-proposal.js --proposalType instantiate -c Multisig -t "Multisig roposal title" -d "Multisig proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 --fetchCodeId -y` +9. `node cosmwasm/submit-proposal.js --proposalType instantiate -c VotingVerifier -t "VotingVerifier roposal title" -d "VotingVerifier proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 --fetchCodeId -y -n "avalanche"` +10. `node cosmwasm/submit-proposal.js --proposalType instantiate -c Gateway -t "Gateway roposal title" -d "Gateway proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 --fetchCodeId -y -n "avalanche"` +11. `node cosmwasm/submit-proposal.js --proposalType instantiate -c MultisigProver -t "MultisigProver roposal title" -d "MultisigProver proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 --fetchCodeId -y -n "avalanche"` diff --git a/cosmwasm/submit-proposal.js b/cosmwasm/submit-proposal.js index dd09d2c7..7c14ce62 100644 --- a/cosmwasm/submit-proposal.js +++ b/cosmwasm/submit-proposal.js @@ -2,9 +2,12 @@ require('dotenv').config(); +const { createHash } = require('crypto'); + const { prepareWallet, prepareClient, + readWasmFile, getChains, decodeProposalAttributes, encodeStoreCodeProposal, @@ -66,11 +69,31 @@ const storeCode = (client, wallet, config, options) => { printInfo('Proposal submitted', proposalId); contractConfig.storeCodeProposalId = proposalId; + contractConfig.storeCodeProposalCodeHash = createHash('sha256').update(readWasmFile(options)).digest().toString('hex'); }); }; -const instantiate = (client, wallet, config, options, chainName) => { - const { contractName, instantiate2, predictOnly } = options; +const fetchAndUpdateCodeId = async (client, contractConfig) => { + const codes = await client.getCodes(); // TODO: create custom function to retrieve codes more efficiently and with pagination + let codeId; + + // most likely to be near the end, so we iterate backwards. We also get the latest if there are multiple + for (let i = codes.length - 1; i >= 0; i--) { + if (codes[i].checksum.toUpperCase() === contractConfig.storeCodeProposalCodeHash.toUpperCase()) { + codeId = codes[i].id; + break; + } + } + + if (!codeId) { + throw new Error('codeId not found on network for the given codeHash'); + } + + contractConfig.codeId = codeId; +}; + +const instantiate = async (client, wallet, config, options, chainName) => { + const { contractName, instantiate2, predictOnly, fetchCodeId } = options; const { axelar: { contracts: { [contractName]: contractConfig }, @@ -82,6 +105,10 @@ const instantiate = (client, wallet, config, options, chainName) => { return predictAndUpdateAddress(client, contractConfig, chainConfig, options, contractName, chainName); } + if (fetchCodeId) { + await fetchAndUpdateCodeId(client, contractConfig); + } + const initMsg = makeInstantiateMsg(contractName, chainName, config); let proposal; @@ -190,6 +217,8 @@ const programHandler = () => { new Option('-i, --instantiateAddresses <instantiateAddresses>', 'comma separated list of addresses allowed to instantiate'), ); + program.addOption(new Option('--fetchCodeId', 'fetch code id from the chain by comparing to the uploaded code hash')); + program.action((options) => { main(options); }); diff --git a/cosmwasm/utils.js b/cosmwasm/utils.js index fe8c30fb..cdcceab3 100644 --- a/cosmwasm/utils.js +++ b/cosmwasm/utils.js @@ -44,6 +44,9 @@ const calculateDomainSeparator = (chain, router, network) => keccak256(Buffer.fr const getSalt = (salt, contractName, chainNames) => fromHex(getSaltFromKey(salt || contractName.concat(chainNames))); +const readWasmFile = ({ artifactPath, contractName, aarch64 }) => + readFileSync(`${artifactPath}/${pascalToSnake(contractName)}${aarch64 ? '-aarch64' : ''}.wasm`); + const getChains = (config, { chainNames, instantiate2 }) => { let chains = chainNames.split(',').map((str) => str.trim()); @@ -65,11 +68,11 @@ const getChains = (config, { chainNames, instantiate2 }) => { }; const uploadContract = async (client, wallet, config, options) => { - const { artifactPath, contractName, instantiate2, salt, aarch64, chainNames } = options; + const { contractName, instantiate2, salt, chainNames } = options; return wallet .getAccounts() .then(([account]) => { - const wasm = readFileSync(`${artifactPath}/${pascalToSnake(contractName)}${aarch64 ? '-aarch64' : ''}.wasm`); + const wasm = readWasmFile(options); const { axelar: { gasPrice, gasLimit }, } = config; @@ -507,9 +510,9 @@ const getSubmitProposalParams = (options) => { }; const getStoreCodeParams = (options) => { - const { artifactPath, contractName, aarch64, source, builder, instantiateAddresses } = options; + const { source, builder, instantiateAddresses } = options; - const wasm = readFileSync(`${artifactPath}/${pascalToSnake(contractName)}${aarch64 ? '-aarch64' : ''}.wasm`); + const wasm = readWasmFile(options); let codeHash; @@ -540,7 +543,7 @@ const getInstantiateContractParams = (config, options, msg) => { return { ...getSubmitProposalParams(options), admin, - codeId: contractConfig.codeId, // TODO: get codeId from previous proposal + codeId: contractConfig.codeId, label: contractName, msg: Buffer.from(JSON.stringify(msg)), }; @@ -629,6 +632,7 @@ module.exports = { prepareWallet, prepareClient, calculateDomainSeparator, + readWasmFile, getChains, uploadContract, instantiateContract, From 6cf8ce2beee52996179275820cd60112d0e2ccbe Mon Sep 17 00:00:00 2001 From: eguajardo <edwin@axelar.network> Date: Tue, 23 Jul 2024 10:54:51 -0600 Subject: [PATCH 28/44] feat(amplifier): support for execute message through governance (#312) --- cosmwasm/README.md | 11 ++++++++ cosmwasm/submit-proposal.js | 50 ++++++++++++++++++++++++++++++++++--- cosmwasm/utils.js | 33 +++++++++++++++++++++++- 3 files changed, 90 insertions(+), 4 deletions(-) diff --git a/cosmwasm/README.md b/cosmwasm/README.md index 9edd08fb..ffdf22b7 100644 --- a/cosmwasm/README.md +++ b/cosmwasm/README.md @@ -187,3 +187,14 @@ Order of execution to satisfy dependencies: 9. `node cosmwasm/submit-proposal.js --proposalType instantiate -c VotingVerifier -t "VotingVerifier roposal title" -d "VotingVerifier proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 --fetchCodeId -y -n "avalanche"` 10. `node cosmwasm/submit-proposal.js --proposalType instantiate -c Gateway -t "Gateway roposal title" -d "Gateway proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 --fetchCodeId -y -n "avalanche"` 11. `node cosmwasm/submit-proposal.js --proposalType instantiate -c MultisigProver -t "MultisigProver roposal title" -d "MultisigProver proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 --fetchCodeId -y -n "avalanche"` + + +### Execute a contract through governance proposal + +To submit a governance proposal to execute a contract, use the `submit-proposal` script with the `--proposalType execute` option. The `--msg` option should be used to pass the execute message. + +Example usage: + +``` +node cosmwasm/submit-proposal.js --proposalType execute -c Router -t "Proposal title" -d "Proposal description" --deposit 100000000 --msg '{"register_chain":{"chain":"avalanche","gateway_address":"axelar17cnq5hujmkf2lr2c5hatqmhzlvwm365rqc5ugryphxeftavjef9q89zxvp","msg_id_format":"hex_tx_hash_and_event_index"}}' +``` \ No newline at end of file diff --git a/cosmwasm/submit-proposal.js b/cosmwasm/submit-proposal.js index 7c14ce62..bfab471d 100644 --- a/cosmwasm/submit-proposal.js +++ b/cosmwasm/submit-proposal.js @@ -13,13 +13,19 @@ const { encodeStoreCodeProposal, encodeInstantiateProposal, encodeInstantiate2Proposal, + encodeExecuteContractProposal, submitProposal, makeInstantiateMsg, instantiate2AddressForProposal, governanceAddress, } = require('./utils'); const { saveConfig, loadConfig, printInfo, prompt } = require('../evm/utils'); -const { StoreCodeProposal, InstantiateContractProposal, InstantiateContract2Proposal } = require('cosmjs-types/cosmwasm/wasm/v1/proposal'); +const { + StoreCodeProposal, + InstantiateContractProposal, + InstantiateContract2Proposal, + ExecuteContractProposal, +} = require('cosmjs-types/cosmwasm/wasm/v1/proposal'); const { Command, Option } = require('commander'); @@ -136,6 +142,30 @@ const instantiate = async (client, wallet, config, options, chainName) => { }); }; +const execute = (client, wallet, config, options, chainName) => { + const { contractName } = options; + const { + axelar: { + contracts: { [contractName]: contractConfig }, + }, + chains: { [chainName]: chainConfig }, + } = config; + + const proposal = encodeExecuteContractProposal(config, options, chainName); + + printProposal(proposal, ExecuteContractProposal); + + if (prompt(`Proceed with proposal submission?`, options.yes)) { + return Promise.resolve(); + } + + return submitProposal(client, wallet, config, options, proposal).then((proposalId) => { + printInfo('Proposal submitted', proposalId); + + updateContractConfig(contractConfig, chainConfig, 'executeProposalId', proposalId); + }); +}; + const main = async (options) => { const { env, proposalType, contractName } = options; const config = loadConfig(env); @@ -166,6 +196,14 @@ const main = async (options) => { }, Promise.resolve()); } + case 'execute': { + const chains = getChains(config, options); + + return chains.reduce((promise, chain) => { + return promise.then(() => execute(client, wallet, config, options, chain.toLowerCase())); + }, Promise.resolve()); + } + default: throw new Error('Invalid proposal type'); } @@ -203,9 +241,13 @@ const programHandler = () => { program.addOption(new Option('-t, --title <title>', 'title of proposal').makeOptionMandatory(true)); program.addOption(new Option('-d, --description <description>', 'description of proposal').makeOptionMandatory(true)); program.addOption(new Option('--deposit <deposit>', 'the proposal deposit').makeOptionMandatory(true)); - program.addOption(new Option('-r, --runAs <runAs>', 'the address that will execute the message').makeOptionMandatory(true)); program.addOption( - new Option('--proposalType <proposalType>', 'proposal type').choices(['store', 'instantiate']).makeOptionMandatory(true), + new Option('-r, --runAs <runAs>', 'the address that will execute the message. Defaults to governance address').default( + governanceAddress, + ), + ); + program.addOption( + new Option('--proposalType <proposalType>', 'proposal type').choices(['store', 'instantiate', 'execute']).makeOptionMandatory(true), ); program.addOption(new Option('--predictOnly', 'output the predicted changes only').env('PREDICT_ONLY')); @@ -219,6 +261,8 @@ const programHandler = () => { program.addOption(new Option('--fetchCodeId', 'fetch code id from the chain by comparing to the uploaded code hash')); + program.addOption(new Option('--msg <msg>', 'json encoded message to submit with an execute contract proposal')); + program.action((options) => { main(options); }); diff --git a/cosmwasm/utils.js b/cosmwasm/utils.js index cdcceab3..9ec88847 100644 --- a/cosmwasm/utils.js +++ b/cosmwasm/utils.js @@ -12,7 +12,12 @@ const { calculateFee, GasPrice } = require('@cosmjs/stargate'); const { instantiate2Address, SigningCosmWasmClient } = require('@cosmjs/cosmwasm-stargate'); const { DirectSecp256k1HdWallet } = require('@cosmjs/proto-signing'); const { MsgSubmitProposal } = require('cosmjs-types/cosmos/gov/v1beta1/tx'); -const { StoreCodeProposal, InstantiateContractProposal, InstantiateContract2Proposal } = require('cosmjs-types/cosmwasm/wasm/v1/proposal'); +const { + StoreCodeProposal, + InstantiateContractProposal, + InstantiateContract2Proposal, + ExecuteContractProposal, +} = require('cosmjs-types/cosmwasm/wasm/v1/proposal'); const { AccessType } = require('cosmjs-types/cosmwasm/wasm/v1/types'); const { getSaltFromKey, isString, isStringArray, isKeccak256Hash, isNumber, toBigNumberString } = require('../evm/utils'); const { normalizeBech32 } = require('@cosmjs/encoding'); @@ -558,6 +563,22 @@ const getInstantiateContract2Params = (config, options, msg) => { }; }; +const getExecuteContractParams = (config, options, chainName) => { + const { contractName, msg } = options; + const { + axelar: { + contracts: { [contractName]: contractConfig }, + }, + chains: { [chainName]: chainConfig }, + } = config; + + return { + ...getSubmitProposalParams(options), + contract: chainConfig ? contractConfig[chainConfig.axelarId].address : contractConfig.address, + msg: Buffer.from(msg), + }; +}; + const encodeStoreCodeProposal = (options) => { const proposal = StoreCodeProposal.fromPartial(getStoreCodeParams(options)); @@ -593,6 +614,15 @@ const encodeInstantiate2Proposal = (config, options, msg) => { }; }; +const encodeExecuteContractProposal = (config, options, chainName) => { + const proposal = ExecuteContractProposal.fromPartial(getExecuteContractParams(config, options, chainName)); + + return { + typeUrl: '/cosmwasm.wasm.v1.ExecuteContractProposal', + value: Uint8Array.from(ExecuteContractProposal.encode(proposal).finish()), + }; +}; + const encodeSubmitProposal = (content, config, options, proposer) => { const { axelar: { tokenSymbol }, @@ -642,6 +672,7 @@ module.exports = { encodeStoreCodeProposal, encodeInstantiateProposal, encodeInstantiate2Proposal, + encodeExecuteContractProposal, submitProposal, isValidCosmosAddress, }; From faf97ac35624bba2285f3d1e40f893885ea7f9e2 Mon Sep 17 00:00:00 2001 From: eguajardo <edwin@axelar.network> Date: Tue, 23 Jul 2024 11:15:50 -0600 Subject: [PATCH 29/44] feat(amplifier): add proposal type storeInstantiate (#314) --- cosmwasm/README.md | 13 ++++++++ cosmwasm/deploy-contract.js | 6 +++- cosmwasm/submit-proposal.js | 60 +++++++++++++++++++++++++++++++++++-- cosmwasm/utils.js | 28 +++++++++++++---- 4 files changed, 98 insertions(+), 9 deletions(-) diff --git a/cosmwasm/README.md b/cosmwasm/README.md index ffdf22b7..5afff41d 100644 --- a/cosmwasm/README.md +++ b/cosmwasm/README.md @@ -188,6 +188,19 @@ Order of execution to satisfy dependencies: 10. `node cosmwasm/submit-proposal.js --proposalType instantiate -c Gateway -t "Gateway roposal title" -d "Gateway proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 --fetchCodeId -y -n "avalanche"` 11. `node cosmwasm/submit-proposal.js --proposalType instantiate -c MultisigProver -t "MultisigProver roposal title" -d "MultisigProver proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 --instantiate2 --fetchCodeId -y -n "avalanche"` +### Uploading and instantiating in one step + +The proposal type `storeInstantiate` allows uploading and instantiating in one step. However, there are a couple of caveats to be aware of: + +1. There is no support for `instantiate2` in this proposal type. This means that the contract address will not be known until the proposal is executed. + +2. Since governance proposals are executed asynchronously, both the codeId and contract address are not immediately available. Querying the network for the correct values could be tricky if multiple proposals are executed together. + +Example usage: + +``` +node cosmwasm/submit-proposal.js --proposalType storeInstantiate -c ServiceRegistry -t "ServiceRegistry proposal title" -d "ServiceRegistry proposal description" -r $RUN_AS_ACCOUNT --deposit 100000000 +``` ### Execute a contract through governance proposal diff --git a/cosmwasm/deploy-contract.js b/cosmwasm/deploy-contract.js index 28f9c811..16015bdc 100644 --- a/cosmwasm/deploy-contract.js +++ b/cosmwasm/deploy-contract.js @@ -3,7 +3,7 @@ require('dotenv').config(); const { isNil } = require('lodash'); -const { printInfo, loadConfig, saveConfig, prompt } = require('../evm/utils'); +const { isNumber, printInfo, loadConfig, saveConfig, prompt } = require('../evm/utils'); const { prepareWallet, prepareClient, @@ -64,6 +64,10 @@ const instantiate = (client, wallet, chainName, config, options) => { chains: { [chainName]: chainConfig }, } = config; + if (!isNumber(contractConfig.codeId)) { + throw new Error('Code Id is not defined'); + } + const initMsg = makeInstantiateMsg(contractName, chainName, config); return instantiateContract(client, wallet, initMsg, config, options).then((contractAddress) => { if (chainConfig) { diff --git a/cosmwasm/submit-proposal.js b/cosmwasm/submit-proposal.js index bfab471d..43365668 100644 --- a/cosmwasm/submit-proposal.js +++ b/cosmwasm/submit-proposal.js @@ -11,6 +11,7 @@ const { getChains, decodeProposalAttributes, encodeStoreCodeProposal, + encodeStoreInstantiateProposal, encodeInstantiateProposal, encodeInstantiate2Proposal, encodeExecuteContractProposal, @@ -19,9 +20,10 @@ const { instantiate2AddressForProposal, governanceAddress, } = require('./utils'); -const { saveConfig, loadConfig, printInfo, prompt } = require('../evm/utils'); +const { isNumber, saveConfig, loadConfig, printInfo, prompt } = require('../evm/utils'); const { StoreCodeProposal, + StoreAndInstantiateContractProposal, InstantiateContractProposal, InstantiateContract2Proposal, ExecuteContractProposal, @@ -79,7 +81,41 @@ const storeCode = (client, wallet, config, options) => { }); }; +const storeInstantiate = (client, wallet, config, options, chainName) => { + const { contractName, instantiate2 } = options; + const { + axelar: { + contracts: { [contractName]: contractConfig }, + }, + chains: { [chainName]: chainConfig }, + } = config; + + if (instantiate2) { + throw new Error('instantiate2 not supported for storeInstantiate'); + } + + const initMsg = makeInstantiateMsg(contractName, chainName, config); + + const proposal = encodeStoreInstantiateProposal(config, options, initMsg); + printProposal(proposal, StoreAndInstantiateContractProposal); + + if (prompt(`Proceed with proposal submission?`, options.yes)) { + return Promise.resolve(); + } + + return submitProposal(client, wallet, config, options, proposal).then((proposalId) => { + printInfo('Proposal submitted', proposalId); + + updateContractConfig(contractConfig, chainConfig, 'storeInstantiateProposalId', proposalId); + contractConfig.storeCodeProposalCodeHash = createHash('sha256').update(readWasmFile(options)).digest().toString('hex'); + }); +}; + const fetchAndUpdateCodeId = async (client, contractConfig) => { + if (!contractConfig.storeCodeProposalCodeHash) { + throw new Error('storeCodeProposalCodeHash not found in contract config'); + } + const codes = await client.getCodes(); // TODO: create custom function to retrieve codes more efficiently and with pagination let codeId; @@ -113,6 +149,8 @@ const instantiate = async (client, wallet, config, options, chainName) => { if (fetchCodeId) { await fetchAndUpdateCodeId(client, contractConfig); + } else if (!isNumber(contractConfig.codeId)) { + throw new Error('Code Id is not defined'); } const initMsg = makeInstantiateMsg(contractName, chainName, config); @@ -170,6 +208,14 @@ const main = async (options) => { const { env, proposalType, contractName } = options; const config = loadConfig(env); + if (config.axelar.contracts === undefined) { + config.axelar.contracts = {}; + } + + if (config.axelar.contracts[contractName] === undefined) { + config.axelar.contracts[contractName] = {}; + } + await prepareWallet(options) .then((wallet) => prepareClient(config, wallet)) .then(({ wallet, client }) => { @@ -177,6 +223,14 @@ const main = async (options) => { case 'store': return storeCode(client, wallet, config, options); + case 'storeInstantiate': { + const chains = getChains(config, options); + + return chains.reduce((promise, chain) => { + return promise.then(() => storeInstantiate(client, wallet, config, options, chain.toLowerCase())); + }, Promise.resolve()); + } + case 'instantiate': { const chains = getChains(config, options); @@ -247,7 +301,9 @@ const programHandler = () => { ), ); program.addOption( - new Option('--proposalType <proposalType>', 'proposal type').choices(['store', 'instantiate', 'execute']).makeOptionMandatory(true), + new Option('--proposalType <proposalType>', 'proposal type') + .choices(['store', 'storeInstantiate', 'instantiate', 'execute']) + .makeOptionMandatory(true), ); program.addOption(new Option('--predictOnly', 'output the predicted changes only').env('PREDICT_ONLY')); diff --git a/cosmwasm/utils.js b/cosmwasm/utils.js index 9ec88847..701fbd2c 100644 --- a/cosmwasm/utils.js +++ b/cosmwasm/utils.js @@ -14,6 +14,7 @@ const { DirectSecp256k1HdWallet } = require('@cosmjs/proto-signing'); const { MsgSubmitProposal } = require('cosmjs-types/cosmos/gov/v1beta1/tx'); const { StoreCodeProposal, + StoreAndInstantiateContractProposal, InstantiateContractProposal, InstantiateContract2Proposal, ExecuteContractProposal, @@ -408,12 +409,6 @@ const makeInstantiateMsg = (contractName, chainName, config) => { const { [contractName]: contractConfig } = contracts; - const { codeId } = contractConfig; - - if (!isNumber(codeId)) { - throw new Error('Code Id is not defined'); - } - switch (contractName) { case 'Coordinator': { if (chainConfig) { @@ -540,6 +535,17 @@ const getStoreCodeParams = (options) => { }; }; +const getStoreInstantiateParams = (config, options, msg) => { + const { contractName, admin } = options; + + return { + ...getStoreCodeParams(options), + admin, + label: contractName, + msg: Buffer.from(JSON.stringify(msg)), + }; +}; + const getInstantiateContractParams = (config, options, msg) => { const { contractName, admin } = options; @@ -588,6 +594,15 @@ const encodeStoreCodeProposal = (options) => { }; }; +const encodeStoreInstantiateProposal = (config, options, msg) => { + const proposal = StoreAndInstantiateContractProposal.fromPartial(getStoreInstantiateParams(config, options, msg)); + + return { + typeUrl: '/cosmwasm.wasm.v1.StoreAndInstantiateContractProposal', + value: Uint8Array.from(StoreAndInstantiateContractProposal.encode(proposal).finish()), + }; +}; + const decodeProposalAttributes = (proposalJson) => { if (proposalJson.msg) { proposalJson.msg = JSON.parse(atob(proposalJson.msg)); @@ -670,6 +685,7 @@ module.exports = { instantiate2AddressForProposal, decodeProposalAttributes, encodeStoreCodeProposal, + encodeStoreInstantiateProposal, encodeInstantiateProposal, encodeInstantiate2Proposal, encodeExecuteContractProposal, From 812f5ae109bcacc1bb51d7367417b962ff10977f Mon Sep 17 00:00:00 2001 From: Milap Sheth <milap@interoplabs.io> Date: Wed, 24 Jul 2024 02:05:10 -0400 Subject: [PATCH 30/44] fix!: don't add extra newline to json (#317) --- axelar-chains-config/info/devnet-amplifier.json | 1 - axelar-chains-config/info/devnet-verifiers.json | 1 - axelar-chains-config/info/mainnet.json | 1 - axelar-chains-config/info/stagenet.json | 1 - axelar-chains-config/info/testnet.json | 1 - evm/.example.keys.json | 1 - evm/legacy/ConstAddressDeployer.json | 1 - evm/nonces.json | 1 - package.json | 2 +- 9 files changed, 1 insertion(+), 9 deletions(-) diff --git a/axelar-chains-config/info/devnet-amplifier.json b/axelar-chains-config/info/devnet-amplifier.json index ddf9f00b..d7aec440 100644 --- a/axelar-chains-config/info/devnet-amplifier.json +++ b/axelar-chains-config/info/devnet-amplifier.json @@ -455,4 +455,3 @@ "gasLimit": "auto" } } - diff --git a/axelar-chains-config/info/devnet-verifiers.json b/axelar-chains-config/info/devnet-verifiers.json index 99c60685..1eae143d 100644 --- a/axelar-chains-config/info/devnet-verifiers.json +++ b/axelar-chains-config/info/devnet-verifiers.json @@ -549,4 +549,3 @@ "gasLimit": "auto" } } - diff --git a/axelar-chains-config/info/mainnet.json b/axelar-chains-config/info/mainnet.json index b3419d65..3ce19c90 100644 --- a/axelar-chains-config/info/mainnet.json +++ b/axelar-chains-config/info/mainnet.json @@ -2386,4 +2386,3 @@ "axelarscanApi": "https://api.axelarscan.io" } } - diff --git a/axelar-chains-config/info/stagenet.json b/axelar-chains-config/info/stagenet.json index eaa88190..e0555542 100644 --- a/axelar-chains-config/info/stagenet.json +++ b/axelar-chains-config/info/stagenet.json @@ -641,4 +641,3 @@ "axelarscanApi": "https://testnet.api.axelarscan.io" } } - diff --git a/axelar-chains-config/info/testnet.json b/axelar-chains-config/info/testnet.json index fa1e7db1..d0682901 100644 --- a/axelar-chains-config/info/testnet.json +++ b/axelar-chains-config/info/testnet.json @@ -2164,4 +2164,3 @@ "axelarscanApi": "https://testnet.api.axelarscan.io" } } - diff --git a/evm/.example.keys.json b/evm/.example.keys.json index a6d17fe5..f08c51e9 100644 --- a/evm/.example.keys.json +++ b/evm/.example.keys.json @@ -12,4 +12,3 @@ "private key 2" ] } - diff --git a/evm/legacy/ConstAddressDeployer.json b/evm/legacy/ConstAddressDeployer.json index bcca9805..94463ed7 100644 --- a/evm/legacy/ConstAddressDeployer.json +++ b/evm/legacy/ConstAddressDeployer.json @@ -131,4 +131,3 @@ "linkReferences": {}, "deployedLinkReferences": {} } - diff --git a/evm/nonces.json b/evm/nonces.json index 5a48ccee..501a8b85 100644 --- a/evm/nonces.json +++ b/evm/nonces.json @@ -164,4 +164,3 @@ } } } - diff --git a/package.json b/package.json index 1341cd3d..0806781b 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "lint": "eslint --fix '**/*.js'", - "prettier": "prettier --write '**/*.js' 'axelar-chains-config/info/*.json' 'package.json' 'evm/**/*.json' '.github/**/*.yaml' && find axelar-chains-config/info evm -name \"*.json\" -type f -print0 | xargs -0 -I {} sh -c 'echo \"\" >> \"{}\"'" + "prettier": "prettier --write '**/*.js' 'axelar-chains-config/info/*.json' 'package.json' 'evm/**/*.json' '.github/**/*.yaml'" }, "repository": { "type": "git", From 26810f1cf0686d4d99e0b1b6c7c1fa89493ada7f Mon Sep 17 00:00:00 2001 From: Milap Sheth <milap@interoplabs.io> Date: Wed, 24 Jul 2024 02:17:03 -0400 Subject: [PATCH 31/44] chore(evm): transfer ownership of testnet operators (#318) --- axelar-chains-config/info/testnet.json | 38 +++++++++++++------------- evm/balances.js | 2 +- evm/operators.js | 2 +- evm/send-tokens.js | 4 --- evm/utils.js | 4 +-- 5 files changed, 23 insertions(+), 27 deletions(-) diff --git a/axelar-chains-config/info/testnet.json b/axelar-chains-config/info/testnet.json index d0682901..21f7734b 100644 --- a/axelar-chains-config/info/testnet.json +++ b/axelar-chains-config/info/testnet.json @@ -63,7 +63,7 @@ "salt": "Multisig v5.5" }, "Operators": { - "owner": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", + "owner": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", "address": "0x7F83F5cA2AE4206AbFf8a3C3668e88ce5F11C0B5", "deployer": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", "deploymentMethod": "create2", @@ -191,7 +191,7 @@ "salt": "InterchainProposalSender v1.2" }, "Operators": { - "owner": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", + "owner": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", "address": "0x7F83F5cA2AE4206AbFf8a3C3668e88ce5F11C0B5", "deployer": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", "deploymentMethod": "create2", @@ -307,7 +307,7 @@ "salt": "InterchainProposalSender v1.2" }, "Operators": { - "owner": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", + "owner": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", "address": "0x7F83F5cA2AE4206AbFf8a3C3668e88ce5F11C0B5", "deployer": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", "deploymentMethod": "create2", @@ -404,7 +404,7 @@ "salt": "InterchainProposalSender v1.2" }, "Operators": { - "owner": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", + "owner": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", "address": "0x7F83F5cA2AE4206AbFf8a3C3668e88ce5F11C0B5", "deployer": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", "deploymentMethod": "create2", @@ -520,7 +520,7 @@ "salt": "InterchainProposalSender v1.2" }, "Operators": { - "owner": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", + "owner": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", "address": "0x7F83F5cA2AE4206AbFf8a3C3668e88ce5F11C0B5", "deployer": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", "deploymentMethod": "create2", @@ -658,7 +658,7 @@ "salt": "InterchainProposalSender v1.2" }, "Operators": { - "owner": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", + "owner": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", "address": "0x7F83F5cA2AE4206AbFf8a3C3668e88ce5F11C0B5", "deployer": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", "deploymentMethod": "create2", @@ -753,7 +753,7 @@ "salt": "InterchainProposalSender v1.2" }, "Operators": { - "owner": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", + "owner": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", "address": "0x7F83F5cA2AE4206AbFf8a3C3668e88ce5F11C0B5", "deployer": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", "deploymentMethod": "create2", @@ -861,7 +861,7 @@ "salt": "InterchainProposalSender v1.2" }, "Operators": { - "owner": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", + "owner": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", "address": "0x7F83F5cA2AE4206AbFf8a3C3668e88ce5F11C0B5", "deployer": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", "deploymentMethod": "create2", @@ -962,7 +962,7 @@ "address": "0x98B2920D53612483F91F12Ed7754E51b4A77919e" }, "Operators": { - "owner": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", + "owner": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", "address": "0x7F83F5cA2AE4206AbFf8a3C3668e88ce5F11C0B5", "deployer": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", "deploymentMethod": "create2", @@ -1102,7 +1102,7 @@ "salt": "Multisig v5.5" }, "Operators": { - "owner": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", + "owner": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", "address": "0x7F83F5cA2AE4206AbFf8a3C3668e88ce5F11C0B5", "deployer": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", "deploymentMethod": "create2", @@ -1212,7 +1212,7 @@ "salt": "Multisig v5.5" }, "Operators": { - "owner": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", + "owner": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", "address": "0x7F83F5cA2AE4206AbFf8a3C3668e88ce5F11C0B5", "deployer": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", "deploymentMethod": "create2", @@ -1321,7 +1321,7 @@ "salt": "Multisig v5.5" }, "Operators": { - "owner": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", + "owner": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", "address": "0x7F83F5cA2AE4206AbFf8a3C3668e88ce5F11C0B5", "deployer": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", "deploymentMethod": "create2", @@ -1425,7 +1425,7 @@ "deployer": "0x5b593E7b1725dc6FcbbFe80b2415B19153F94A85" }, "Operators": { - "owner": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", + "owner": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", "address": "0x7F83F5cA2AE4206AbFf8a3C3668e88ce5F11C0B5", "deployer": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", "deploymentMethod": "create2", @@ -1537,7 +1537,7 @@ "salt": "Multisig v5.5" }, "Operators": { - "owner": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", + "owner": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", "address": "0x7F83F5cA2AE4206AbFf8a3C3668e88ce5F11C0B5", "deployer": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", "deploymentMethod": "create2", @@ -1650,7 +1650,7 @@ "salt": "Multisig v5.5" }, "Operators": { - "owner": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", + "owner": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", "address": "0x7F83F5cA2AE4206AbFf8a3C3668e88ce5F11C0B5", "deployer": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", "deploymentMethod": "create2", @@ -1763,7 +1763,7 @@ "salt": "Multisig v5.5" }, "Operators": { - "owner": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", + "owner": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", "address": "0x7F83F5cA2AE4206AbFf8a3C3668e88ce5F11C0B5", "deployer": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", "deploymentMethod": "create2", @@ -1873,7 +1873,7 @@ "salt": "AxelarGateway v6.2" }, "Operators": { - "owner": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", + "owner": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", "address": "0x7F83F5cA2AE4206AbFf8a3C3668e88ce5F11C0B5", "deployer": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", "deploymentMethod": "create2", @@ -1973,7 +1973,7 @@ "salt": "Multisig v5.5" }, "Operators": { - "owner": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", + "owner": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", "address": "0x7F83F5cA2AE4206AbFf8a3C3668e88ce5F11C0B5", "deployer": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", "deploymentMethod": "create2", @@ -2081,7 +2081,7 @@ "salt": "Multisig v5.5" }, "Operators": { - "owner": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", + "owner": "0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05", "address": "0x7F83F5cA2AE4206AbFf8a3C3668e88ce5F11C0B5", "deployer": "0xB8Cd93C83A974649D76B1c19f311f639e62272BC", "deploymentMethod": "create2", diff --git a/evm/balances.js b/evm/balances.js index 8c06934c..23c5563b 100644 --- a/evm/balances.js +++ b/evm/balances.js @@ -11,7 +11,7 @@ async function processCommand(_, chain, options) { const provider = getDefaultProvider(chain.rpc); const wallet = await getWallet(options.privateKey, provider); - await printWalletInfo(wallet, options); + await printWalletInfo(wallet, options, chain); } async function main(options) { diff --git a/evm/operators.js b/evm/operators.js index 48e2a7c7..7ad5f68e 100644 --- a/evm/operators.js +++ b/evm/operators.js @@ -83,7 +83,7 @@ async function processCommand(config, chain, options) { } const isOperator = await operatorsContract.isOperator(operatorAddress); - printInfo(`Is ${operatorAddress} an operator?`, `${isOperator}`); + printInfo(`Is ${operatorAddress} an operator on ${chain.name}?`, `${isOperator}`); break; } diff --git a/evm/send-tokens.js b/evm/send-tokens.js index 21ef5c2a..1c032919 100644 --- a/evm/send-tokens.js +++ b/evm/send-tokens.js @@ -67,10 +67,6 @@ async function processCommand(_, chain, options) { ...gasOptions, }; - if (!offline && chain.name.toLowerCase() === 'binance') { - tx.gasPrice = (await provider.getGasPrice()) * 1.2; - } - const { baseTx, signedTx } = await signTransaction(wallet, chain, tx, options); if (offline) { diff --git a/evm/utils.js b/evm/utils.js index 4b93b38a..73951ab5 100644 --- a/evm/utils.js +++ b/evm/utils.js @@ -707,7 +707,7 @@ function saveParallelExecutionConfig(config, env, chain) { writeJSON(config, `${__dirname}/../chains-info/${env}-${chain}.json`); } -async function printWalletInfo(wallet, options = {}) { +async function printWalletInfo(wallet, options = {}, chain = {}) { let balance = 0; const address = await wallet.getAddress(); printInfo('Wallet address', address); @@ -718,7 +718,7 @@ async function printWalletInfo(wallet, options = {}) { if (balance.isZero()) { printError('Wallet balance', '0'); } else { - printInfo('Wallet balance', `${balance / 1e18}`); + printInfo('Wallet balance', `${balance / 1e18} ${chain.tokenSymbol || ''}`); } printInfo('Wallet nonce', (await wallet.provider.getTransactionCount(address)).toString()); From 320d4aabd0108983e9aa69dd45b0fb560e1c7a99 Mon Sep 17 00:00:00 2001 From: Milap Sheth <milap@interoplabs.io> Date: Wed, 24 Jul 2024 17:52:09 -0400 Subject: [PATCH 32/44] chore(evm): update gmp-sdk dep (#319) --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9d4574b4..2a218821 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@0xpolygonhermez/zkevm-commonjs": "github:0xpolygonhermez/zkevm-commonjs#v1.0.0", "@axelar-network/axelar-cgp-solidity": "6.3.1", "@axelar-network/axelar-cgp-sui": "^0.3.0", - "@axelar-network/axelar-gmp-sdk-solidity": "5.9.0", + "@axelar-network/axelar-gmp-sdk-solidity": "5.10.0", "@axelar-network/interchain-token-service": "1.2.4", "@cosmjs/cosmwasm-stargate": "^0.32.1", "@ledgerhq/hw-app-eth": "6.32.2", @@ -191,9 +191,9 @@ } }, "node_modules/@axelar-network/axelar-gmp-sdk-solidity": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/@axelar-network/axelar-gmp-sdk-solidity/-/axelar-gmp-sdk-solidity-5.9.0.tgz", - "integrity": "sha512-BarUqOln3m5jnvBo+LF6ARWwbRXqek93dDtCgIevKGl+Be2JcNOaBB32Bg2LOOBnpOKJBvJq1SI2ZoGurBQ4Qg==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@axelar-network/axelar-gmp-sdk-solidity/-/axelar-gmp-sdk-solidity-5.10.0.tgz", + "integrity": "sha512-s8SImALvYB+5AeiT3tbfWNBI2Mhqw1x91i/zM3DNpVUCnAR2HKtsB9T84KnUn/OJjOVgb4h0lv7q9smeYniRPw==", "engines": { "node": ">=18" } diff --git a/package.json b/package.json index 0806781b..dce55b4c 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "@0xpolygonhermez/zkevm-commonjs": "github:0xpolygonhermez/zkevm-commonjs#v1.0.0", "@axelar-network/axelar-cgp-solidity": "6.3.1", "@axelar-network/axelar-cgp-sui": "^0.3.0", - "@axelar-network/axelar-gmp-sdk-solidity": "5.9.0", + "@axelar-network/axelar-gmp-sdk-solidity": "5.10.0", "@axelar-network/interchain-token-service": "1.2.4", "@cosmjs/cosmwasm-stargate": "^0.32.1", "@ledgerhq/hw-app-eth": "6.32.2", From 763ceb39938b0abb8f07dd5df44e23ae13ef747f Mon Sep 17 00:00:00 2001 From: Milap Sheth <milap@interoplabs.io> Date: Wed, 24 Jul 2024 17:53:54 -0400 Subject: [PATCH 33/44] chore(evm): remove polygon zkevm support (#320) --- .../src/utils/getBytecodeHash.js | 4 +- evm/utils.js | 4 +- package-lock.json | 831 ++---------------- package.json | 1 - 4 files changed, 60 insertions(+), 780 deletions(-) diff --git a/axelar-chains-config/src/utils/getBytecodeHash.js b/axelar-chains-config/src/utils/getBytecodeHash.js index dd0a6fdd..6856f967 100644 --- a/axelar-chains-config/src/utils/getBytecodeHash.js +++ b/axelar-chains-config/src/utils/getBytecodeHash.js @@ -28,9 +28,7 @@ async function getBytecodeHash(contractObject, chain = '', provider = null) { } if (chain.toLowerCase() === 'polygon-zkevm') { - throw new Error( - "polygon-zkevm is not supported. Use getBytecodeHash from axelar-contract-deployments that handles polygon-zkevm's hash function", - ); + throw new Error('polygon-zkevm uses a custom bytecode hash derivation and is not supported'); } return keccak256(bytecode); diff --git a/evm/utils.js b/evm/utils.js index 73951ab5..e28bcadd 100644 --- a/evm/utils.js +++ b/evm/utils.js @@ -14,7 +14,6 @@ const http = require('http'); const fs = require('fs'); const path = require('path'); const { outputJsonSync } = require('fs-extra'); -const zkevm = require('@0xpolygonhermez/zkevm-commonjs'); const readlineSync = require('readline-sync'); const chalk = require('chalk'); const { @@ -497,8 +496,7 @@ async function getBytecodeHash(contractObject, chain = '', provider = null) { } if (chain.toLowerCase() === 'polygon-zkevm') { - const codehash = zkevm.smtUtils.hashContractBytecode(bytecode); - return codehash; + throw new Error('polygon-zkevm uses a custom bytecode hash derivation and is not supported'); } return keccak256(bytecode); diff --git a/package-lock.json b/package-lock.json index 2a218821..1c33be51 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,6 @@ "version": "1.4.0", "license": "MIT", "dependencies": { - "@0xpolygonhermez/zkevm-commonjs": "github:0xpolygonhermez/zkevm-commonjs#v1.0.0", "@axelar-network/axelar-cgp-solidity": "6.3.1", "@axelar-network/axelar-cgp-sui": "^0.3.0", "@axelar-network/axelar-gmp-sdk-solidity": "5.10.0", @@ -67,22 +66,6 @@ "typescript": "^5.0.0" } }, - "node_modules/@0xpolygonhermez/zkevm-commonjs": { - "version": "1.0.0", - "resolved": "git+ssh://git@github.com/0xpolygonhermez/zkevm-commonjs.git#34f72fe9f7a4c3c45965742476a87148c9e05c0f", - "license": "pending", - "dependencies": { - "@ethereumjs/block": "^3.6.2", - "@ethereumjs/tx": "^3.4.0", - "@polygon-hermez/common": "2.6.4", - "@polygon-hermez/vm": "5.7.30", - "ethereumjs-util": "^7.1.4", - "ethers": "^5.5.4", - "ffjavascript": "^0.2.55", - "lodash": "^4.17.21", - "pg": "^8.7.1" - } - }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", @@ -495,53 +478,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@ethereumjs/block": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/@ethereumjs/block/-/block-3.6.3.tgz", - "integrity": "sha512-CegDeryc2DVKnDkg5COQrE0bJfw/p0v3GBk2W5/Dj5dOVfEmb50Ux0GLnSPypooLnfqjwFaorGuT9FokWB3GRg==", - "dependencies": { - "@ethereumjs/common": "^2.6.5", - "@ethereumjs/tx": "^3.5.2", - "ethereumjs-util": "^7.1.5", - "merkle-patricia-tree": "^4.2.4" - } - }, - "node_modules/@ethereumjs/blockchain": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/@ethereumjs/blockchain/-/blockchain-5.5.3.tgz", - "integrity": "sha512-bi0wuNJ1gw4ByNCV56H0Z4Q7D+SxUbwyG12Wxzbvqc89PXLRNR20LBcSUZRKpN0+YCPo6m0XZL/JLio3B52LTw==", - "dependencies": { - "@ethereumjs/block": "^3.6.2", - "@ethereumjs/common": "^2.6.4", - "@ethereumjs/ethash": "^1.1.0", - "debug": "^4.3.3", - "ethereumjs-util": "^7.1.5", - "level-mem": "^5.0.1", - "lru-cache": "^5.1.1", - "semaphore-async-await": "^1.5.1" - } - }, - "node_modules/@ethereumjs/common": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.6.5.tgz", - "integrity": "sha512-lRyVQOeCDaIVtgfbowla32pzeDv2Obr8oR8Put5RdUBNRGr1VGPGQNGP6elWIpgK3YdpzqTOh4GyUGOureVeeA==", - "dependencies": { - "crc-32": "^1.2.0", - "ethereumjs-util": "^7.1.5" - } - }, - "node_modules/@ethereumjs/ethash": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@ethereumjs/ethash/-/ethash-1.1.0.tgz", - "integrity": "sha512-/U7UOKW6BzpA+Vt+kISAoeDie1vAvY4Zy2KF5JJb+So7+1yKmJeJEHOGSnQIj330e9Zyl3L5Nae6VZyh2TJnAA==", - "dependencies": { - "@ethereumjs/block": "^3.5.0", - "@types/levelup": "^4.3.0", - "buffer-xor": "^2.0.1", - "ethereumjs-util": "^7.1.1", - "miller-rabin": "^4.0.0" - } - }, "node_modules/@ethereumjs/rlp": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz", @@ -555,15 +491,6 @@ "node": ">=14" } }, - "node_modules/@ethereumjs/tx": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.5.2.tgz", - "integrity": "sha512-gQDNJWKrSDGu2w7w0PzVXVBNMzb7wwdDOmOqczmhNjqFxFuIbhVJDwiGEnxFNC2/b8ifcZzY7MLcluizohRzNw==", - "dependencies": { - "@ethereumjs/common": "^2.6.4", - "ethereumjs-util": "^7.1.5" - } - }, "node_modules/@ethereumjs/util": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-8.1.0.tgz", @@ -2230,84 +2157,6 @@ "web3-core-helpers": "^1.8.2" } }, - "node_modules/@polygon-hermez/common": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@polygon-hermez/common/-/common-2.6.4.tgz", - "integrity": "sha512-ZGl/K1MaXHaDagqKCqkQgCRu9EfJ+mbK+t4GeVnDywMYGCyi7jF1u71Pyh4Rch3XFd/8rW/eVL4x4jkGwN16JQ==", - "dependencies": { - "crc-32": "^1.2.0", - "ethereumjs-util": "^7.1.4" - } - }, - "node_modules/@polygon-hermez/vm": { - "version": "5.7.30", - "resolved": "https://registry.npmjs.org/@polygon-hermez/vm/-/vm-5.7.30.tgz", - "integrity": "sha512-HxmrGuRpYsgwd4rnvYNQ4OR77OKdAbUsAD1Z6PoEvV18NHsMv6JGpMnvnSAseiCBCyqTHjnFqWynoQ1nl0Qr6g==", - "dependencies": { - "@ethereumjs/block": "^3.6.1", - "@ethereumjs/blockchain": "^5.5.1", - "@ethereumjs/common": "^2.6.2", - "@ethereumjs/tx": "^3.5.0", - "@polygon-hermez/zkevm-commonjs": "github:hermeznetwork/zkevm-commonjs#v0.5.0.1", - "async-eventemitter": "^0.2.4", - "core-js-pure": "^3.0.1", - "debug": "^4.3.3", - "ethereumjs-util": "^7.1.4", - "ethers": "^5.6.2", - "functional-red-black-tree": "^1.0.1", - "lodash": "^4.17.21", - "mcl-wasm": "^0.7.1", - "merkle-patricia-tree": "^4.2.3", - "rustbn.js": "~0.2.0" - } - }, - "node_modules/@polygon-hermez/zkevm-commonjs": { - "name": "@0xpolygonhermez/zkevm-commonjs", - "version": "0.5.0.1", - "resolved": "git+ssh://git@github.com/hermeznetwork/zkevm-commonjs.git#3ee798329f567fa19b7c4f1ffbcf3d91cf5bf273", - "license": "pending", - "dependencies": { - "@ethereumjs/block": "^3.6.2", - "@ethereumjs/tx": "^3.4.0", - "@polygon-hermez/common": "2.6.3", - "@polygon-hermez/vm": "5.7.27", - "ethereumjs-util": "^7.1.4", - "ethers": "^5.5.4", - "ffjavascript": "^0.2.55", - "lodash": "^4.17.21" - } - }, - "node_modules/@polygon-hermez/zkevm-commonjs/node_modules/@polygon-hermez/common": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/@polygon-hermez/common/-/common-2.6.3.tgz", - "integrity": "sha512-wLaod6WPquUm2sEE65XCiP4SFuJ8q3bd54Sb3h1yFZRr0MBx9GO8Rmr8Cmvj+EoQU9zJWJmZDp9aUcPWiA+uoA==", - "dependencies": { - "crc-32": "^1.2.0", - "ethereumjs-util": "^7.1.4" - } - }, - "node_modules/@polygon-hermez/zkevm-commonjs/node_modules/@polygon-hermez/vm": { - "version": "5.7.27", - "resolved": "https://registry.npmjs.org/@polygon-hermez/vm/-/vm-5.7.27.tgz", - "integrity": "sha512-7jjHP+GmixFEJv89i4S9JENf2bjs/y7kgZ6Jozy6UAhOvcjL+tobyZrrNvDWlNjzjxc/iu3mz3t3M3Ebp1qMBg==", - "dependencies": { - "@ethereumjs/block": "^3.6.1", - "@ethereumjs/blockchain": "^5.5.1", - "@ethereumjs/common": "^2.6.2", - "@ethereumjs/tx": "^3.5.0", - "@polygon-hermez/zkevm-commonjs": "github:hermeznetwork/zkevm-commonjs#v0.0.26", - "async-eventemitter": "^0.2.4", - "core-js-pure": "^3.0.1", - "debug": "^4.3.3", - "ethereumjs-util": "^7.1.4", - "ethers": "^5.6.2", - "functional-red-black-tree": "^1.0.1", - "lodash": "^4.17.21", - "mcl-wasm": "^0.7.1", - "merkle-patricia-tree": "^4.2.3", - "rustbn.js": "~0.2.0" - } - }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -2645,15 +2494,11 @@ "node": ">=10" } }, - "node_modules/@types/abstract-leveldown": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/@types/abstract-leveldown/-/abstract-leveldown-7.2.5.tgz", - "integrity": "sha512-/2B0nQF4UdupuxeKTJA2+Rj1D+uDemo6P4kMwKCpbfpnzeVaWSELTsAw4Lxn3VJD6APtRrZOCuYo+4nHUQfTfg==" - }, "node_modules/@types/bn.js": { "version": "5.1.5", "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.5.tgz", "integrity": "sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A==", + "dev": true, "dependencies": { "@types/node": "*" } @@ -2718,21 +2563,6 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, - "node_modules/@types/level-errors": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/level-errors/-/level-errors-3.0.2.tgz", - "integrity": "sha512-gyZHbcQ2X5hNXf/9KS2qGEmgDe9EN2WDM3rJ5Ele467C0nA1sLhtmv1bZiPMDYfAYCfPWft0uQIaTvXbASSTRA==" - }, - "node_modules/@types/levelup": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@types/levelup/-/levelup-4.3.3.tgz", - "integrity": "sha512-K+OTIjJcZHVlZQN1HmU64VtrC0jC3dXWQozuEIR9zVvltIk90zaGPM2AgT+fIkChpzHhFE3YnvFLCbLtzAmexA==", - "dependencies": { - "@types/abstract-leveldown": "*", - "@types/level-errors": "*", - "@types/node": "*" - } - }, "node_modules/@types/long": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", @@ -2770,6 +2600,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.2.tgz", "integrity": "sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==", + "dev": true, "dependencies": { "@types/node": "*" } @@ -2808,6 +2639,7 @@ "version": "4.0.6", "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.6.tgz", "integrity": "sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==", + "dev": true, "dependencies": { "@types/node": "*" } @@ -2830,17 +2662,17 @@ "dev": true }, "node_modules/@volar/language-core": { - "version": "2.4.0-alpha.16", - "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.0-alpha.16.tgz", - "integrity": "sha512-oOTnIZlx0P/idFwVw+W0NbzKDtZAQMzXSdIFfTePCKcXlb4Ys12GaGkx8NF9dsvPYV3nbv3ZsSxnkZWBmNKd7A==", + "version": "2.4.0-alpha.18", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.0-alpha.18.tgz", + "integrity": "sha512-JAYeJvYQQROmVRtSBIczaPjP3DX4QW1fOqW1Ebs0d3Y3EwSNRglz03dSv0Dm61dzd0Yx3WgTW3hndDnTQqgmyg==", "dependencies": { - "@volar/source-map": "2.4.0-alpha.16" + "@volar/source-map": "2.4.0-alpha.18" } }, "node_modules/@volar/source-map": { - "version": "2.4.0-alpha.16", - "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.0-alpha.16.tgz", - "integrity": "sha512-sL9vNG7iR2hiKZor7UkD5Sufu3QCia4cbp2gX/nGRNSdaPbhOpdAoavwlBm0PrVkpiA19NZuavZoobD8krviFg==" + "version": "2.4.0-alpha.18", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.0-alpha.18.tgz", + "integrity": "sha512-MTeCV9MUwwsH0sNFiZwKtFrrVZUK6p8ioZs3xFzHc2cvDXHWlYN3bChdQtwKX+FY2HG6H3CfAu1pKijolzIQ8g==" }, "node_modules/@vue/compiler-core": { "version": "3.4.32", @@ -2864,11 +2696,11 @@ } }, "node_modules/@vue/language-core": { - "version": "2.0.26", - "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.0.26.tgz", - "integrity": "sha512-/lt6SfQ3O1yDAhPsnLv9iSUgXd1dMHqUm/t3RctfqjuwQf1LnftZ414X3UBn6aXT4MiwXWtbNJ4Z0NZWwDWgJQ==", + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.0.28.tgz", + "integrity": "sha512-0z4tyCCaqqPbdyz0T4yTFQeLpCo4TOM/ZHAC3geGLHeCiFAjVbROB9PiEtrXR1AoLObqUPFHSmKZeWtEMssSqw==", "dependencies": { - "@volar/language-core": "~2.4.0-alpha.15", + "@volar/language-core": "~2.4.0-alpha.18", "@vue/compiler-dom": "^3.4.0", "@vue/shared": "^3.4.0", "computeds": "^0.0.1", @@ -2945,55 +2777,6 @@ "node": ">=12" } }, - "node_modules/abstract-leveldown": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.3.0.tgz", - "integrity": "sha512-TU5nlYgta8YrBMNpc9FwQzRbiXsj49gsALsXadbGHt9CROPzX5fB0rWDR5mtdpOOKa5XqRFpbj1QroPAoPzVjQ==", - "dependencies": { - "buffer": "^5.5.0", - "immediate": "^3.2.3", - "level-concat-iterator": "~2.0.0", - "level-supports": "~1.0.0", - "xtend": "~4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/abstract-leveldown/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/abstract-leveldown/node_modules/level-supports": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-1.0.1.tgz", - "integrity": "sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg==", - "dependencies": { - "xtend": "^4.0.2" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/acorn": { "version": "8.12.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", @@ -3404,22 +3187,6 @@ "node": ">=8" } }, - "node_modules/async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "dependencies": { - "lodash": "^4.17.14" - } - }, - "node_modules/async-eventemitter": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/async-eventemitter/-/async-eventemitter-0.2.4.tgz", - "integrity": "sha512-pd20BwL7Yt1zwDFy+8MX8F1+WCT8aQeKj0kQnTrH9WaeRETlRamVhD0JtRPmrV4GfOJ2F9CvdQkZeZhnh2TuHw==", - "dependencies": { - "async": "^2.4.0" - } - }, "node_modules/async-retry": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", @@ -3596,7 +3363,8 @@ "node_modules/blakejs": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", - "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==" + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", + "dev": true }, "node_modules/bn.js": { "version": "5.2.1", @@ -3674,6 +3442,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, "dependencies": { "buffer-xor": "^1.0.3", "cipher-base": "^1.0.0", @@ -3686,7 +3455,8 @@ "node_modules/browserify-aes/node_modules/buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true }, "node_modules/bs58": { "version": "6.0.0", @@ -3700,6 +3470,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "dev": true, "dependencies": { "bs58": "^4.0.0", "create-hash": "^1.1.0", @@ -3710,6 +3481,7 @@ "version": "3.0.10", "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.10.tgz", "integrity": "sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==", + "dev": true, "dependencies": { "safe-buffer": "^5.0.1" } @@ -3718,6 +3490,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "dev": true, "dependencies": { "base-x": "^3.0.2" } @@ -3751,14 +3524,6 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "node_modules/buffer-xor": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-2.0.2.tgz", - "integrity": "sha512-eHslX0bin3GB+Lx2p7lEYRShRewuNZL3fUl4qlVJGGiwoPGftmt8JQgk2Y9Ji5/01TnVDo33E5b5O3vUB1HdqQ==", - "dependencies": { - "safe-buffer": "^5.1.1" - } - }, "node_modules/bufferutil": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz", @@ -3986,6 +3751,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, "dependencies": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -4386,16 +4152,6 @@ "node": ">= 0.6" } }, - "node_modules/core-js-pure": { - "version": "3.37.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.37.1.tgz", - "integrity": "sha512-J/r5JTHSmzTxbiYYrzXg9w1VpqrYt+gexenBE9pugeyhwPZTAEJddyiReJWsLO6uNQ8xJZFbod6XC7KKwatCiA==", - "hasInstallScript": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -4412,6 +4168,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, "bin": { "crc32": "bin/crc32.njs" }, @@ -4423,6 +4180,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, "dependencies": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -4435,6 +4193,7 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, "dependencies": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", @@ -4584,6 +4343,7 @@ "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -4655,67 +4415,6 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "node_modules/deferred-leveldown": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-5.3.0.tgz", - "integrity": "sha512-a59VOT+oDy7vtAbLRCZwWgxu2BaCfd5Hk7wxJd48ei7I+nsg8Orlb9CLG0PMZienk9BSUKgeAqkO2+Lw+1+Ukw==", - "dependencies": { - "abstract-leveldown": "~6.2.1", - "inherits": "^2.0.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/deferred-leveldown/node_modules/abstract-leveldown": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz", - "integrity": "sha512-BsLm5vFMRUrrLeCcRc+G0t2qOaTzpoJQLOubq2XM72eNpjF5UdU5o/5NvlNhx95XHcAvcl8OMXr4mlg/fRgUXQ==", - "dependencies": { - "buffer": "^5.5.0", - "immediate": "^3.2.3", - "level-concat-iterator": "~2.0.0", - "level-supports": "~1.0.0", - "xtend": "~4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/deferred-leveldown/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/deferred-leveldown/node_modules/level-supports": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-1.0.1.tgz", - "integrity": "sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg==", - "dependencies": { - "xtend": "^4.0.2" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -4867,20 +4566,6 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "node_modules/encoding-down": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-6.3.0.tgz", - "integrity": "sha512-QKrV0iKR6MZVJV08QY0wp1e7vF6QbhnbQhb07bwpEyuz4uZiZgPlEGdkCROuFkUwdxlFaiPIhjyarH1ee/3vhw==", - "dependencies": { - "abstract-leveldown": "^6.2.1", - "inherits": "^2.0.3", - "level-codec": "^9.0.0", - "level-errors": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -4923,17 +4608,6 @@ "node": ">=6" } }, - "node_modules/errno": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", - "dependencies": { - "prr": "~1.0.1" - }, - "bin": { - "errno": "cli.js" - } - }, "node_modules/es-abstract": { "version": "1.23.3", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", @@ -5776,6 +5450,7 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, "dependencies": { "@types/pbkdf2": "^3.0.0", "@types/secp256k1": "^4.0.1", @@ -5798,6 +5473,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", + "dev": true, "hasInstallScript": true, "dependencies": { "elliptic": "^6.5.4", @@ -5852,6 +5528,8 @@ "version": "7.1.5", "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "peer": true, "dependencies": { "@types/bn.js": "^5.1.0", "bn.js": "^5.1.2", @@ -5984,6 +5662,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, "dependencies": { "md5.js": "^1.3.4", "safe-buffer": "^5.1.1" @@ -6078,16 +5757,6 @@ "reusify": "^1.0.4" } }, - "node_modules/ffjavascript": { - "version": "0.2.63", - "resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.2.63.tgz", - "integrity": "sha512-dBgdsfGks58b66JnUZeZpGxdMIDQ4QsD3VYlRJyFVrKQHb2kJy4R2gufx5oetrTxXPT+aEjg0dOvOLg1N0on4A==", - "dependencies": { - "wasmbuilder": "0.0.16", - "wasmcurves": "0.2.2", - "web-worker": "1.2.0" - } - }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -6304,7 +5973,8 @@ "node_modules/functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==" + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true }, "node_modules/functions-have-names": { "version": "1.2.3", @@ -7086,6 +6756,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, "dependencies": { "inherits": "^2.0.4", "readable-stream": "^3.6.0", @@ -7249,11 +6920,6 @@ "node": ">= 4" } }, - "node_modules/immediate": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz", - "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==" - }, "node_modules/immutable": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.6.tgz", @@ -7860,6 +7526,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz", "integrity": "sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==", + "dev": true, "hasInstallScript": true, "dependencies": { "node-addon-api": "^2.0.0", @@ -7916,96 +7583,6 @@ "url": "https://opencollective.com/level" } }, - "node_modules/level-codec": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-9.0.2.tgz", - "integrity": "sha512-UyIwNb1lJBChJnGfjmO0OR+ezh2iVu1Kas3nvBS/BzGnx79dv6g7unpKIDNPMhfdTEGoc7mC8uAu51XEtX+FHQ==", - "dependencies": { - "buffer": "^5.6.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/level-codec/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/level-concat-iterator": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-2.0.1.tgz", - "integrity": "sha512-OTKKOqeav2QWcERMJR7IS9CUo1sHnke2C0gkSmcR7QuEtFNLLzHQAvnMw8ykvEcv0Qtkg0p7FOwP1v9e5Smdcw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/level-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-2.0.1.tgz", - "integrity": "sha512-UVprBJXite4gPS+3VznfgDSU8PTRuVX0NXwoWW50KLxd2yw4Y1t2JUR5In1itQnudZqRMT9DlAM3Q//9NCjCFw==", - "dependencies": { - "errno": "~0.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/level-iterator-stream": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-4.0.2.tgz", - "integrity": "sha512-ZSthfEqzGSOMWoUGhTXdX9jv26d32XJuHz/5YnuHZzH6wldfWMOVwI9TBtKcya4BKTyTt3XVA0A3cF3q5CY30Q==", - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "^3.4.0", - "xtend": "^4.0.2" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/level-mem": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/level-mem/-/level-mem-5.0.1.tgz", - "integrity": "sha512-qd+qUJHXsGSFoHTziptAKXoLX87QjR7v2KMbqncDXPxQuCdsQlzmyX+gwrEHhlzn08vkf8TyipYyMmiC6Gobzg==", - "dependencies": { - "level-packager": "^5.0.3", - "memdown": "^5.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/level-packager": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/level-packager/-/level-packager-5.1.1.tgz", - "integrity": "sha512-HMwMaQPlTC1IlcwT3+swhqf/NUO+ZhXVz6TY1zZIIZlIR0YSn8GtAAWmIvKjNY16ZkEg/JcpAuQskxsXqC0yOQ==", - "dependencies": { - "encoding-down": "^6.3.0", - "levelup": "^4.3.2" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/level-supports": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-4.0.1.tgz", @@ -8028,45 +7605,6 @@ "node": ">=12" } }, - "node_modules/level-ws": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/level-ws/-/level-ws-2.0.0.tgz", - "integrity": "sha512-1iv7VXx0G9ec1isqQZ7y5LmoZo/ewAsyDHNA8EFDW5hqH2Kqovm33nSFkSdnLLAK+I5FlT+lo5Cw9itGe+CpQA==", - "dependencies": { - "inherits": "^2.0.3", - "readable-stream": "^3.1.0", - "xtend": "^4.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/levelup": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/levelup/-/levelup-4.4.0.tgz", - "integrity": "sha512-94++VFO3qN95cM/d6eBXvd894oJE0w3cInq9USsyQzzoJxmiYzPAocNcuGCPGGjoXqDVJcr3C1jzt1TSjyaiLQ==", - "dependencies": { - "deferred-leveldown": "~5.3.0", - "level-errors": "~2.0.0", - "level-iterator-stream": "~4.0.0", - "level-supports": "~1.0.0", - "xtend": "~4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/levelup/node_modules/level-supports": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-1.0.1.tgz", - "integrity": "sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg==", - "dependencies": { - "xtend": "^4.0.2" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -8117,7 +7655,8 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true }, "node_modules/lodash.camelcase": { "version": "4.3.0", @@ -8203,15 +7742,11 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, "dependencies": { "yallist": "^3.0.2" } }, - "node_modules/ltgt": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz", - "integrity": "sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA==" - }, "node_modules/magic-string": { "version": "0.30.10", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", @@ -8239,6 +7774,7 @@ "version": "0.7.9", "resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.7.9.tgz", "integrity": "sha512-iJIUcQWA88IJB/5L15GnJVnSQJmf/YaxxV6zRavv83HILHaJQb6y0iFyDMdDO0gN8X37tdxmAOrH/P8B6RB8sQ==", + "dev": true, "engines": { "node": ">=8.9.0" } @@ -8247,6 +7783,7 @@ "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, "dependencies": { "hash-base": "^3.0.0", "inherits": "^2.0.1", @@ -8259,76 +7796,6 @@ "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", "peer": true }, - "node_modules/memdown": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/memdown/-/memdown-5.1.0.tgz", - "integrity": "sha512-B3J+UizMRAlEArDjWHTMmadet+UKwHd3UjMgGBkZcKAxAYVPS9o0Yeiha4qvz7iGiL2Sb3igUft6p7nbFWctpw==", - "dependencies": { - "abstract-leveldown": "~6.2.1", - "functional-red-black-tree": "~1.0.1", - "immediate": "~3.2.3", - "inherits": "~2.0.1", - "ltgt": "~2.2.0", - "safe-buffer": "~5.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/memdown/node_modules/abstract-leveldown": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz", - "integrity": "sha512-BsLm5vFMRUrrLeCcRc+G0t2qOaTzpoJQLOubq2XM72eNpjF5UdU5o/5NvlNhx95XHcAvcl8OMXr4mlg/fRgUXQ==", - "dependencies": { - "buffer": "^5.5.0", - "immediate": "^3.2.3", - "level-concat-iterator": "~2.0.0", - "level-supports": "~1.0.0", - "xtend": "~4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/memdown/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/memdown/node_modules/immediate": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.2.3.tgz", - "integrity": "sha512-RrGCXRm/fRVqMIhqXrGEX9rRADavPiDFSoMb/k64i9XMk8uH4r/Omi5Ctierj6XzNecwDbO4WuFbDD1zmpl3Tg==" - }, - "node_modules/memdown/node_modules/level-supports": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-1.0.1.tgz", - "integrity": "sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg==", - "dependencies": { - "xtend": "^4.0.2" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/memory-level": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/memory-level/-/memory-level-1.0.0.tgz", @@ -8362,19 +7829,6 @@ "node": ">= 8" } }, - "node_modules/merkle-patricia-tree": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/merkle-patricia-tree/-/merkle-patricia-tree-4.2.4.tgz", - "integrity": "sha512-eHbf/BG6eGNsqqfbLED9rIqbsF4+sykEaBn6OLNs71tjclbMcMOk1tEPmJKcNcNCLkvbpY/lwyOlizWsqPNo8w==", - "dependencies": { - "@types/levelup": "^4.3.0", - "ethereumjs-util": "^7.1.4", - "level-mem": "^5.0.1", - "level-ws": "^2.0.0", - "readable-stream": "^3.6.0", - "semaphore-async-await": "^1.5.1" - } - }, "node_modules/micro-ftch": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/micro-ftch/-/micro-ftch-0.3.1.tgz", @@ -8396,23 +7850,6 @@ "node": ">=8.6" } }, - "node_modules/miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "dependencies": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "bin": { - "miller-rabin": "bin/miller-rabin" - } - }, - "node_modules/miller-rabin/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -8612,7 +8049,8 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, "node_modules/muggle-string": { "version": "0.4.1", @@ -8680,7 +8118,8 @@ "node_modules/node-addon-api": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", - "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==" + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", + "dev": true }, "node_modules/node-emoji": { "version": "1.11.0", @@ -9117,6 +8556,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dev": true, "dependencies": { "create-hash": "^1.1.2", "create-hmac": "^1.1.4", @@ -9148,87 +8588,6 @@ "@types/estree": "^1.0.0" } }, - "node_modules/pg": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.12.0.tgz", - "integrity": "sha512-A+LHUSnwnxrnL/tZ+OLfqR1SxLN3c/pgDztZ47Rpbsd4jUytsTtwQo/TLPRzPJMp/1pbhYVhH9cuSZLAajNfjQ==", - "dependencies": { - "pg-connection-string": "^2.6.4", - "pg-pool": "^3.6.2", - "pg-protocol": "^1.6.1", - "pg-types": "^2.1.0", - "pgpass": "1.x" - }, - "engines": { - "node": ">= 8.0.0" - }, - "optionalDependencies": { - "pg-cloudflare": "^1.1.1" - }, - "peerDependencies": { - "pg-native": ">=3.0.1" - }, - "peerDependenciesMeta": { - "pg-native": { - "optional": true - } - } - }, - "node_modules/pg-cloudflare": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", - "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", - "optional": true - }, - "node_modules/pg-connection-string": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.4.tgz", - "integrity": "sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==" - }, - "node_modules/pg-int8": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", - "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/pg-pool": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.2.tgz", - "integrity": "sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==", - "peerDependencies": { - "pg": ">=8.0" - } - }, - "node_modules/pg-protocol": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.1.tgz", - "integrity": "sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==" - }, - "node_modules/pg-types": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", - "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", - "dependencies": { - "pg-int8": "1.0.1", - "postgres-array": "~2.0.0", - "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.4", - "postgres-interval": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pgpass": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", - "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", - "dependencies": { - "split2": "^4.1.0" - } - }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -9260,41 +8619,6 @@ "node": ">= 0.4" } }, - "node_modules/postgres-array": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", - "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/postgres-bytea": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", - "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-date": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", - "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-interval": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", - "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", - "dependencies": { - "xtend": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/prebuild-install": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", @@ -9400,11 +8724,6 @@ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, - "node_modules/prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==" - }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -9517,6 +8836,7 @@ "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -9737,6 +9057,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, "dependencies": { "hash-base": "^3.0.0", "inherits": "^2.0.1" @@ -9746,6 +9067,7 @@ "version": "2.2.7", "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", + "dev": true, "dependencies": { "bn.js": "^5.2.0" }, @@ -9802,7 +9124,8 @@ "node_modules/rustbn.js": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/rustbn.js/-/rustbn.js-0.2.0.tgz", - "integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==" + "integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==", + "dev": true }, "node_modules/rxjs": { "version": "7.8.1", @@ -10033,14 +9356,6 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==" }, - "node_modules/semaphore-async-await": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/semaphore-async-await/-/semaphore-async-await-1.5.1.tgz", - "integrity": "sha512-b/ptP11hETwYWpeilHXXQiV5UJNJl7ZWWooKRE5eBIYWoom6dZ0SluCIdCtKycsMtZgKWE01/qAw6jblw1YVhg==", - "engines": { - "node": ">=4.1" - } - }, "node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -10096,7 +9411,8 @@ "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true }, "node_modules/setprototypeof": { "version": "1.2.0", @@ -10550,14 +9866,6 @@ "node": ">=0.10.0" } }, - "node_modules/split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "engines": { - "node": ">= 10.x" - } - }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -10599,6 +9907,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, "dependencies": { "safe-buffer": "~5.2.0" } @@ -11547,7 +10856,8 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true }, "node_modules/util/node_modules/inherits": { "version": "2.0.3", @@ -11584,24 +10894,6 @@ "he": "^1.2.0" } }, - "node_modules/wasmbuilder": { - "version": "0.0.16", - "resolved": "https://registry.npmjs.org/wasmbuilder/-/wasmbuilder-0.0.16.tgz", - "integrity": "sha512-Qx3lEFqaVvp1cEYW7Bfi+ebRJrOiwz2Ieu7ZG2l7YyeSJIok/reEQCQCuicj/Y32ITIJuGIM9xZQppGx5LrQdA==" - }, - "node_modules/wasmcurves": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/wasmcurves/-/wasmcurves-0.2.2.tgz", - "integrity": "sha512-JRY908NkmKjFl4ytnTu5ED6AwPD+8VJ9oc94kdq7h5bIwbj0L4TDJ69mG+2aLs2SoCmGfqIesMWTEJjtYsoQXQ==", - "dependencies": { - "wasmbuilder": "0.0.16" - } - }, - "node_modules/web-worker": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.2.0.tgz", - "integrity": "sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==" - }, "node_modules/web3-core": { "version": "1.10.4", "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.10.4.tgz", @@ -12020,14 +11312,6 @@ "symbol-observable": "^2.0.3" } }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "engines": { - "node": ">=0.4" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -12050,7 +11334,8 @@ "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true }, "node_modules/yargs": { "version": "16.2.0", diff --git a/package.json b/package.json index dce55b4c..4e2fea74 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,6 @@ }, "homepage": "https://github.com/axelarnetwork/axelar-contract-deployments#readme", "dependencies": { - "@0xpolygonhermez/zkevm-commonjs": "github:0xpolygonhermez/zkevm-commonjs#v1.0.0", "@axelar-network/axelar-cgp-solidity": "6.3.1", "@axelar-network/axelar-cgp-sui": "^0.3.0", "@axelar-network/axelar-gmp-sdk-solidity": "5.10.0", From 63ebcc322a9136d829bc47a0a9fa463e96a04754 Mon Sep 17 00:00:00 2001 From: jcs47 <11947034+jcs47@users.noreply.github.com> Date: Thu, 25 Jul 2024 19:43:09 +0100 Subject: [PATCH 34/44] chore: update instantiation for voting verifier (#321) --- cosmwasm/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cosmwasm/utils.js b/cosmwasm/utils.js index 701fbd2c..f35c7553 100644 --- a/cosmwasm/utils.js +++ b/cosmwasm/utils.js @@ -259,7 +259,7 @@ const makeVotingVerifierInstantiateMsg = ( service_name: serviceName, source_gateway_address: sourceGatewayAddress, voting_threshold: votingThreshold, - block_expiry: blockExpiry, + block_expiry: toBigNumberString(blockExpiry), confirmation_height: confirmationHeight, source_chain: chainId, msg_id_format: msgIdFormat, From 598a7da736e9bc1971dac9ed651ef7f499e473c4 Mon Sep 17 00:00:00 2001 From: npty <78221556+npty@users.noreply.github.com> Date: Fri, 26 Jul 2024 14:57:06 +0700 Subject: [PATCH 35/44] feat(sui): add test gmp command (#301) Co-authored-by: Milap Sheth <milap@interoplabs.io> --- sui/README.md | 12 ++- sui/deploy-contract.js | 3 - sui/deploy-test.js | 32 +++---- sui/docs/gmp.md | 63 +++++++++++++ sui/gas-service.js | 4 +- sui/gmp.js | 201 +++++++++++++++++++++++++++++++++++++++++ sui/types-utils.js | 30 ++++++ 7 files changed, 321 insertions(+), 24 deletions(-) create mode 100644 sui/docs/gmp.md create mode 100644 sui/gmp.js diff --git a/sui/README.md b/sui/README.md index 48d14aef..980e6521 100644 --- a/sui/README.md +++ b/sui/README.md @@ -121,32 +121,36 @@ node sui/gateway.js rotate --signers wallet --proof wallet --currentNonce test - Use the same nonce for `--currentNonce` as the `--nonce` when deploying the gateway. - ### Multisig To create a Multisig, follow the documentation [here](https://docs.sui.io/guides/developer/cryptography/multisig). Get test SUI coins to your multisig address via a faucet: + ```bash sui client faucet --address <multisig address> ``` Get public keys for all wallets: + ```bash sui keytool list ``` Get private key of wallet using wallet alias or address: + ```bash sui keytool export --key-identity <alias/wallet address> ``` Get tx data for testing: + ```bash sui client transfer-sui --to <recipient address> --amount 1 --sui-coin-object-id <sui coin object id> --serialize-unsigned-transaction --gas-budget 77047880 ``` To get sui coin object id + ```bash sui client gas <multisig address> ``` @@ -158,6 +162,7 @@ node sui/multisig.js --txBlockPath <path to unsigned tx block> --signatureFilePa ``` example txBlock file: + ``` { "bytes": "AAACACBC5cSnnYJrDEn9nSW1BDzPLLAbUJbYOeJnUgYl/b90..." @@ -181,6 +186,7 @@ node sui/multisig.js --txBlockPath <path to unsigned tx block> --action execute use --multisigKey `multisigKey` to override existing multisig info in chains config example for adding multisig info to chains config: + ``` { "sui": { @@ -207,6 +213,10 @@ example for adding multisig info to chains config: } ``` +GMP Demo: + +Follow the instructions [here](docs/gmp.md) + ## Troubleshooting 1. Move build error during the deployment step diff --git a/sui/deploy-contract.js b/sui/deploy-contract.js index 802bfa1b..e97113cd 100644 --- a/sui/deploy-contract.js +++ b/sui/deploy-contract.js @@ -1,6 +1,5 @@ const { saveConfig, printInfo } = require('../evm/utils'); const { Command, Argument, Option } = require('commander'); -const { updateMoveToml } = require('@axelar-network/axelar-cgp-sui'); const { addBaseOptions } = require('./cli-utils'); const { getWallet, printWalletInfo } = require('./sign-utils'); const { loadSuiConfig, findPublishedObject, deployPackage } = require('./utils'); @@ -27,8 +26,6 @@ async function processCommand(contractName, config, chain, options) { const published = await deployPackage(packageName, client, keypair); const packageId = published.packageId; - updateMoveToml(packageName, packageId); - const contractObject = findPublishedObject(published, packageName, contractName); const gasCollectorCapObject = findPublishedObject(published, packageName, 'GasCollectorCap'); diff --git a/sui/deploy-test.js b/sui/deploy-test.js index 1c019bd2..3f8feb51 100644 --- a/sui/deploy-test.js +++ b/sui/deploy-test.js @@ -1,15 +1,18 @@ const { saveConfig, prompt, printInfo } = require('../evm/utils'); -const { Command, Option } = require('commander'); +const { Command } = require('commander'); +const { loadSuiConfig, deployPackage, getBcsBytesByObjectId } = require('./utils'); +const { singletonStruct } = require('./types-utils'); const { Transaction } = require('@mysten/sui/transactions'); -const { ethers } = require('hardhat'); -const { - constants: { HashZero }, -} = ethers; -const { loadSuiConfig, deployPackage } = require('./utils'); - const { addBaseOptions } = require('./cli-utils'); const { getWallet, printWalletInfo, broadcast } = require('./sign-utils'); +// Parse bcs bytes from singleton object to get channel id +async function getChannelId(client, singletonObjectId) { + const bcsBytes = await getBcsBytesByObjectId(client, singletonObjectId); + const data = singletonStruct.parse(bcsBytes); + return '0x' + data.channel.id; +} + async function processCommand(config, chain, options) { const [keypair, client] = getWallet(chain, options); @@ -42,8 +45,10 @@ async function processCommand(config, chain, options) { await broadcast(client, keypair, tx); + const channelId = await getChannelId(client, singleton.objectId); + chain.contracts.test.address = published.packageId; - chain.contracts.test.objects = { singleton: singleton.objectId }; + chain.contracts.test.objects = { singleton: singleton.objectId, channelId }; printInfo('Test package deployed', JSON.stringify(chain.contracts.test, null, 2)); } @@ -58,19 +63,10 @@ async function mainProcessor(options, processor) { if (require.main === module) { const program = new Command(); - program.name('deploy-gateway').description('Deploys/publishes the Sui gateway'); + program.name('deploy-test').description('Deploys/publishes the test module'); addBaseOptions(program); - program.addOption(new Option('--signers <signers>', 'JSON with the initial signer set').env('SIGNERS')); - program.addOption(new Option('--operator <operator>', 'operator for the gateway (defaults to the deployer address)')); - program.addOption( - new Option('--minimumRotationDelay <minimumRotationDelay>', 'minium delay for signer rotations (in ms)').default( - 24 * 60 * 60 * 1000, - ), - ); // 1 day (in ms) - program.addOption(new Option('--domainSeparator <domainSeparator>', 'domain separator').default(HashZero)); - program.action((options) => { mainProcessor(options, processCommand); }); diff --git a/sui/docs/gmp.md b/sui/docs/gmp.md new file mode 100644 index 00000000..77529797 --- /dev/null +++ b/sui/docs/gmp.md @@ -0,0 +1,63 @@ +# GMP Demo + +This document provides a step-by-step guide to execute GMP flow on the SUI network. + +## Prerequisites + +- Deploy gateway contract `node sui/deploy-gateway.js --signers wallet` +- Deploy gas service contract `node sui/deploy-contract.js GasService` +- Deploy test contract `node sui/deploy-test.js` + +## Usage + +### Send Command (Outgoing) + +Send a messsage from SUI to the destination chain. + +Example: +```bash +# node sui/gmp.js sendCall <destChain> <destContractAddress> <feeAmount> <payload> +node sui/gmp.js sendCall ethereum 0x6f24A47Fc8AE5441Eb47EFfC3665e70e69Ac3F05 0.1 0x1234 +``` + +Note: +- `feeAmount` is the amount of SUI coins to be sent to the destination chain. The amount is in full units. For example, `0.1` means 0.1 SUI coins. + +### Execute Command (Incoming) + +Execute a message from the source chain at SUI application module. + +1. Approve the incoming message + +```bash +# node sui/gateway.js approve --proof ...... <source> <messageId> <sourceAddress> <destinationId> <payloadHash> +node sui/gateway.js approve --proof wallet ethereum 0x32034b47cb29d162d9d803cc405356f4ac0ec07fe847ace431385fe8acf3e6e5-2 0x4F4495243837681061C4743b74B3eEdf548D56A5 0x6ce0d81b412abca2770eddb1549c9fcff721889c3aab1203dc93866db22ecc4b 0x56570de287d73cd1cb6092bb8fdee6173974955fdef345ae579ee9f475ea7432 +``` + +Note: +- `destinationId` is the channel id of test module. It can be retrieved from test module deployment output. +- `payloadHash` is the keccak256 hash of the payload. The payloadHash in the example `(0x565...7432)` is the hash of `0x1234`. + +2. Execute the incoming message + +This command will execute the message to the deployed test contract. +```bash +# node sui/gmp.js execute <source> <messageId> <sourceAddress> <payload> + +# Example +node sui/gmp.js execute ethereum 0x32034b47cb29d162d9d803cc405356f4ac0ec07fe847ace431385fe8acf3e6e5-2 0x4F4495243837681061C4743b74B3eEdf548D56A5 0x1234 +``` + +This command will execute the message to the contract that associated with the given `channelId` + +```bash +# node sui/gmp.js execute <source> <messageId> <sourceAddress> <payload> --channelId <channelId> + +# Example +node sui/gmp.js execute ethereum 0x32034b47cb29d162d9d803cc405356f4ac0ec07fe847ace431385fe8acf3e6e5-2 0x4F4495243837681061C4743b74B3eEdf548D56A5 0x1234 --channelId 0xcd5d203ea2cf1139af83939e3f74114a31fe682cc90f73a0d2647956bc3e5acf +``` + + +Note: +- `source`, `sourceAddress` and `messageId` needed to be matched with the approve command. +- `payload` must be associated with the `payloadHash` in the approve command. diff --git a/sui/gas-service.js b/sui/gas-service.js index c3cce96a..a3dc5a13 100644 --- a/sui/gas-service.js +++ b/sui/gas-service.js @@ -18,8 +18,8 @@ async function payGas(keypair, client, gasServiceConfig, args, options) { const gasServicePackageId = gasServiceConfig.address; + const { params } = options; const refundAddress = options.refundAddress || walletAddress; - const params = options.params || '0x'; const [destinationChain, destinationAddress, channelId, payload] = args; const unitAmount = options.amount; @@ -51,8 +51,8 @@ async function addGas(keypair, client, gasServiceConfig, args, options) { const gasServicePackageId = gasServiceConfig.address; + const { params } = options; const refundAddress = options.refundAddress || walletAddress; - const params = options.params || '0x'; const [messageId] = args; const unitAmount = options.amount; diff --git a/sui/gmp.js b/sui/gmp.js new file mode 100644 index 00000000..87730567 --- /dev/null +++ b/sui/gmp.js @@ -0,0 +1,201 @@ +const { saveConfig, printInfo } = require('../evm/utils'); +const { Command } = require('commander'); +const { Transaction } = require('@mysten/sui/transactions'); +const { bcs } = require('@mysten/sui/bcs'); +const { loadSuiConfig, getBcsBytesByObjectId } = require('./utils'); +const { ethers } = require('hardhat'); +const { + utils: { arrayify }, +} = ethers; + +const { addBaseOptions, addOptionsToCommands } = require('./cli-utils'); +const { getUnitAmount } = require('./amount-utils.js'); +const { getWallet, printWalletInfo, broadcast } = require('./sign-utils'); +const { discoveryStruct } = require('./types-utils.js'); + +async function sendCommand(keypair, client, contracts, args, options) { + const [destinationChain, destinationAddress, feeAmount, payload] = args; + const params = options.params; + + const [testConfig, gasServiceConfig] = contracts; + const gasServicePackageId = gasServiceConfig.address; + const singletonObjectId = testConfig.objects.singleton; + const channelId = testConfig.objects.channelId; + + const unitAmount = getUnitAmount(feeAmount); + const walletAddress = keypair.toSuiAddress(); + const refundAddress = options.refundAddress || walletAddress; + + const tx = new Transaction(); + const [coin] = tx.splitCoins(tx.gas, [unitAmount]); + + tx.moveCall({ + target: `${testConfig.address}::test::send_call`, + arguments: [ + tx.object(singletonObjectId), + tx.pure(bcs.string().serialize(destinationChain).toBytes()), + tx.pure(bcs.string().serialize(destinationAddress).toBytes()), + tx.pure(bcs.vector(bcs.u8()).serialize(arrayify(payload)).toBytes()), + ], + }); + + if (gasServiceConfig) { + tx.moveCall({ + target: `${gasServicePackageId}::gas_service::pay_gas`, + arguments: [ + tx.object(gasServiceConfig.objects.GasService), + coin, // Coin<SUI> + tx.pure.address(channelId), // Channel address + tx.pure(bcs.string().serialize(destinationChain).toBytes()), // Destination chain + tx.pure(bcs.string().serialize(destinationAddress).toBytes()), // Destination address + tx.pure(bcs.vector(bcs.u8()).serialize(arrayify(payload)).toBytes()), // Payload + tx.pure.address(refundAddress), // Refund address + tx.pure(bcs.vector(bcs.u8()).serialize(arrayify(params)).toBytes()), // Params + ], + }); + } + + const receipt = await broadcast(client, keypair, tx); + + printInfo('Call sent', receipt.digest); +} + +async function execute(keypair, client, contracts, args, options) { + const [testConfig, , axelarGatewayConfig] = contracts; + + const [sourceChain, messageId, sourceAddress, payload] = args; + + const gatewayObjectId = axelarGatewayConfig.objects.gateway; + const discoveryObjectId = axelarGatewayConfig.objects.relayerDiscovery; + + // Get the channel id from the options or use the channel id from the deployed test contract object. + const channelId = options.channelId || testConfig.objects.channelId; + + if (!channelId) { + throw new Error('Please provide either a channel id (--channelId) or deploy the test contract'); + } + + // Get Discovery table id from discovery object + const tableBcsBytes = await getBcsBytesByObjectId(client, discoveryObjectId); + const { fields } = discoveryStruct.parse(tableBcsBytes); + const tableId = fields.id; + + // Get the transaction list from the discovery table + const tableResult = await client.getDynamicFields({ + parentId: tableId, + }); + const transactionList = tableResult.data; + + // Find the transaction with associated channel id + const transaction = transactionList.find((row) => row.name.value === channelId); + + if (!transaction) { + throw new Error(`Transaction not found for channel ${channelId}`); + } + + // Get the transaction object from the object id + const txObject = await client.getObject({ + id: transaction.objectId, + options: { + showContent: true, + }, + }); + + // Extract the fields from the transaction object + const txFields = txObject.data.content.fields.value.fields.move_calls[0].fields; + + const tx = new Transaction(); + + // Take the approved message from the gateway contract. + // Note: The message needed to be approved first. + const approvedMessage = tx.moveCall({ + target: `${axelarGatewayConfig.address}::gateway::take_approved_message`, + arguments: [ + tx.object(gatewayObjectId), + tx.pure(bcs.string().serialize(sourceChain).toBytes()), + tx.pure(bcs.string().serialize(messageId).toBytes()), + tx.pure(bcs.string().serialize(sourceAddress).toBytes()), + tx.pure.address(channelId), + tx.pure(bcs.vector(bcs.u8()).serialize(arrayify(payload)).toBytes()), + ], + }); + + const { module_name: moduleName, name, package_id: packageId } = txFields.function.fields; + + // Build the arguments for the move call + // There're 5 types of arguments as mentioned in the following link https://github.com/axelarnetwork/axelar-cgp-sui/blob/72579e5c7735da61d215bd712627edad562cb82a/src/bcs.ts#L44-L49 + const txArgs = txFields.arguments.map(([argType, ...arg]) => { + if (argType === 0) { + return tx.object(Buffer.from(arg).toString('hex')); + } else if (argType === 1) { + // TODO: handle pures followed by the bcs encoded form of the pure + throw new Error('Not implemented yet'); + } else if (argType === 2) { + return approvedMessage; + } else if (argType === 3) { + // TODO: handle the payload of the contract call (to be passed into the intermediate function) + throw new Error('Not implemented yet'); + } else if (argType === 4) { + // TODO: handle an argument returned from a previous move call, followed by a u8 specified which call to get the return of (0 for the first transaction AFTER the one that gets ApprovedMessage out), and then another u8 specifying which argument to input. + throw new Error('Not implemented yet'); + } + + throw new Error(`Unknown argument type: ${argType}`); + }); + + // Execute the move call dynamically based on the transaction object + tx.moveCall({ + target: `${packageId}::${moduleName}::${name}`, + arguments: txArgs, + }); + + const receipt = await broadcast(client, keypair, tx); + + printInfo('Call executed', receipt.digest); +} + +async function processCommand(command, chain, args, options) { + const [keypair, client] = getWallet(chain, options); + + await printWalletInfo(keypair, client, chain, options); + + const contracts = [chain.contracts.test, chain.contracts.GasService, chain.contracts.axelar_gateway]; + + await command(keypair, client, contracts, args, options); +} + +async function mainProcessor(command, options, args, processor) { + const config = loadSuiConfig(options.env); + await processor(command, config.sui, args, options); + saveConfig(config, options.env); +} + +if (require.main === module) { + const program = new Command(); + program.name('gmp').description('Example of SUI gmp commands'); + + const sendCallProgram = new Command() + .name('sendCall') + .description('Send gmp contract call') + .command('sendCall <destChain> <destContractAddress> <feeAmount> <payload>') + .option('--params <params>', 'GMP call params. Default is empty.', '0x') + .action((destChain, destContractAddress, feeAmount, payload, options) => { + mainProcessor(sendCommand, options, [destChain, destContractAddress, feeAmount, payload], processCommand); + }); + + const executeCommand = new Command() + .name('execute') + .description('Execute gmp contract call') + .option('--channelId <channelId>', 'Channel id for the destination contract') + .command('execute <sourceChain> <messageId> <sourceAddress> <payload>') + .action((sourceChain, messageId, sourceAddress, payload, options) => { + mainProcessor(execute, options, [sourceChain, messageId, sourceAddress, payload], processCommand); + }); + + program.addCommand(sendCallProgram); + program.addCommand(executeCommand); + + addOptionsToCommands(program, addBaseOptions); + + program.parse(); +} diff --git a/sui/types-utils.js b/sui/types-utils.js index d1861075..a4c61757 100644 --- a/sui/types-utils.js +++ b/sui/types-utils.js @@ -47,6 +47,14 @@ const messageStruct = bcs.struct('Message', { payload_hash: bytes32Struct, }); +const approvedMessageStruct = bcs.struct('ApprovedMessage', { + source_chain: bcs.string(), + message_id: bcs.string(), + source_address: bcs.string(), + destination_id: addressStruct, + payload: bcs.vector(bcs.u8()), +}); + const proofStruct = bcs.struct('Proof', { signers: signersStruct, signatures: bcs.vector(bcs.vector(bcs.u8())), @@ -57,6 +65,24 @@ const gasServiceStruct = bcs.struct('GasService', { balance: bcs.u64(), }); +const channelStruct = bcs.struct('Channel', { + id: UID, +}); + +const singletonStruct = bcs.struct('Singleton', { + id: UID, + channel: channelStruct, +}); + +const discoveryTable = bcs.struct('DiscoveryTable', { + id: UID, +}); + +const discoveryStruct = bcs.struct('Discovery', { + id: UID, + fields: discoveryTable, +}); + module.exports = { addressStruct, signerStruct, @@ -64,6 +90,10 @@ module.exports = { signersStruct, messageToSignStruct, messageStruct, + approvedMessageStruct, proofStruct, gasServiceStruct, + channelStruct, + singletonStruct, + discoveryStruct, }; From 14654c3dcc88ce9e728a7c0db68aadde705cfd15 Mon Sep 17 00:00:00 2001 From: npty <78221556+npty@users.noreply.github.com> Date: Sun, 28 Jul 2024 05:11:24 +0700 Subject: [PATCH 36/44] chore(evm): refactor evm utils (#322) --- common/cli-utils.js | 87 ++++++++++++ common/index.js | 4 + common/utils.js | 314 ++++++++++++++++++++++++++++++++++++++++++ evm/cli-utils.js | 86 +----------- evm/utils.js | 328 ++++---------------------------------------- 5 files changed, 429 insertions(+), 390 deletions(-) create mode 100644 common/cli-utils.js create mode 100644 common/index.js create mode 100644 common/utils.js diff --git a/common/cli-utils.js b/common/cli-utils.js new file mode 100644 index 00000000..88fbc4a9 --- /dev/null +++ b/common/cli-utils.js @@ -0,0 +1,87 @@ +'use strict'; + +require('dotenv').config(); + +const { Option } = require('commander'); + +const addBaseOptions = (program, options = {}) => { + program.addOption( + new Option('-e, --env <env>', 'environment') + .choices(['local', 'devnet', 'devnet-amplifier', 'devnet-verifiers', 'stagenet', 'testnet', 'mainnet']) + .default('testnet') + .makeOptionMandatory(true) + .env('ENV'), + ); + program.addOption(new Option('-y, --yes', 'skip deployment prompt confirmation').env('YES')); + program.addOption(new Option('--parallel', 'run script parallely wrt chains')); + program.addOption(new Option('--saveChainSeparately', 'save chain info separately')); + program.addOption(new Option('--gasOptions <gasOptions>', 'gas options cli override')); + + if (!options.ignoreChainNames) { + program.addOption( + new Option('-n, --chainNames <chainNames>', 'chains to run the script over').makeOptionMandatory(true).env('CHAINS'), + ); + program.addOption(new Option('--skipChains <skipChains>', 'chains to skip over')); + program.addOption( + new Option( + '--startFromChain <startFromChain>', + 'start from a specific chain onwards in the config, useful when a cmd fails for an intermediate chain', + ), + ); + } + + if (!options.ignorePrivateKey) { + program.addOption(new Option('-p, --privateKey <privateKey>', 'private key').makeOptionMandatory(true).env('PRIVATE_KEY')); + } + + if (options.address) { + program.addOption(new Option('-a, --address <address>', 'override address')); + } + + return program; +}; + +const addExtendedOptions = (program, options = {}) => { + addBaseOptions(program, options); + + program.addOption(new Option('-v, --verify', 'verify the deployed contract on the explorer').env('VERIFY')); + + if (options.artifactPath) { + program.addOption(new Option('--artifactPath <artifactPath>', 'artifact path')); + } + + if (options.contractName) { + program.addOption(new Option('-c, --contractName <contractName>', 'contract name').makeOptionMandatory(true)); + } + + if (options.deployMethod) { + program.addOption( + new Option('-m, --deployMethod <deployMethod>', 'deployment method') + .choices(['create', 'create2', 'create3']) + .default(options.deployMethod), + ); + } + + if (options.salt) { + program.addOption(new Option('-s, --salt <salt>', 'salt to use for create2 deployment').env('SALT')); + } + + if (options.skipExisting) { + program.addOption(new Option('-x, --skipExisting', 'skip existing if contract was already deployed on chain').env('SKIP_EXISTING')); + } + + if (options.upgrade) { + program.addOption(new Option('-u, --upgrade', 'upgrade a deployed contract').env('UPGRADE')); + } + + if (options.predictOnly) { + program.addOption(new Option('--predictOnly', 'output the predicted changes only').env('PREDICT_ONLY')); + } + + return program; +}; + +module.exports = { + addBaseOptions, + addExtendedOptions, +}; diff --git a/common/index.js b/common/index.js new file mode 100644 index 00000000..ceab4806 --- /dev/null +++ b/common/index.js @@ -0,0 +1,4 @@ +module.exports = { + ...require('./cli-utils'), + ...require('./utils'), +}; diff --git a/common/utils.js b/common/utils.js new file mode 100644 index 00000000..2c2a85c2 --- /dev/null +++ b/common/utils.js @@ -0,0 +1,314 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const { outputJsonSync } = require('fs-extra'); +const chalk = require('chalk'); +const https = require('https'); +const http = require('http'); +const readlineSync = require('readline-sync'); + +function loadConfig(env) { + return require(`${__dirname}/../axelar-chains-config/info/${env}.json`); +} + +function saveConfig(config, env) { + writeJSON(config, `${__dirname}/../axelar-chains-config/info/${env}.json`); +} + +const writeJSON = (data, name) => { + outputJsonSync(name, data, { + spaces: 2, + EOL: '\n', + }); +}; + +const printInfo = (msg, info = '', colour = chalk.green) => { + if (info) { + console.log(`${msg}: ${colour(info)}\n`); + } else { + console.log(`${msg}\n`); + } +}; + +const printWarn = (msg, info = '') => { + if (info) { + msg = `${msg}: ${info}`; + } + + console.log(`${chalk.italic.yellow(msg)}\n`); +}; + +const printError = (msg, info = '') => { + if (info) { + msg = `${msg}: ${info}`; + } + + console.log(`${chalk.bold.red(msg)}\n`); +}; + +function printLog(log) { + console.log(JSON.stringify({ log }, null, 2)); +} + +const isNonEmptyString = (arg) => { + return typeof arg === 'string' && arg !== ''; +}; + +const isString = (arg) => { + return typeof arg === 'string'; +}; + +const isStringArray = (arr) => Array.isArray(arr) && arr.every(isString); + +const isNumber = (arg) => { + return Number.isInteger(arg); +}; + +const isValidNumber = (arg) => { + return !isNaN(parseInt(arg)) && isFinite(arg); +}; + +const isValidDecimal = (arg) => { + return !isNaN(parseFloat(arg)) && isFinite(arg); +}; + +const isNumberArray = (arr) => { + if (!Array.isArray(arr)) { + return false; + } + + for (const item of arr) { + if (!isNumber(item)) { + return false; + } + } + + return true; +}; + +const isNonEmptyStringArray = (arr) => { + if (!Array.isArray(arr)) { + return false; + } + + for (const item of arr) { + if (typeof item !== 'string') { + return false; + } + } + + return true; +}; + +function copyObject(obj) { + return JSON.parse(JSON.stringify(obj)); +} + +const httpGet = (url) => { + return new Promise((resolve, reject) => { + (url.startsWith('https://') ? https : http).get(url, (res) => { + const { statusCode } = res; + const contentType = res.headers['content-type']; + let error; + + if (statusCode !== 200 && statusCode !== 301) { + error = new Error('Request Failed.\n' + `Request: ${url}\nStatus Code: ${statusCode}`); + } else if (!/^application\/json/.test(contentType)) { + error = new Error('Invalid content-type.\n' + `Expected application/json but received ${contentType}`); + } + + if (error) { + res.resume(); + reject(error); + return; + } + + res.setEncoding('utf8'); + let rawData = ''; + res.on('data', (chunk) => { + rawData += chunk; + }); + res.on('end', () => { + try { + const parsedData = JSON.parse(rawData); + resolve(parsedData); + } catch (e) { + reject(e); + } + }); + }); + }); +}; + +const httpPost = async (url, data) => { + const response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + }); + return response.json(); +}; + +/** + * Parses the input string into an array of arguments, recognizing and converting + * to the following types: boolean, number, array, and string. + * + * @param {string} args - The string of arguments to parse. + * + * @returns {Array} - An array containing parsed arguments. + * + * @example + * const input = "hello true 123 [1,2,3]"; + * const output = parseArgs(input); + * console.log(output); // Outputs: [ 'hello', true, 123, [ 1, 2, 3] ] + */ +const parseArgs = (args) => { + return args + .split(/\s+/) + .filter((item) => item !== '') + .map((arg) => { + if (arg.startsWith('[') && arg.endsWith(']')) { + return JSON.parse(arg); + } else if (arg === 'true') { + return true; + } else if (arg === 'false') { + return false; + } else if (!isNaN(arg) && !arg.startsWith('0x')) { + return Number(arg); + } + + return arg; + }); +}; + +function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +function timeout(prom, time, exception) { + let timer; + + // Racing the promise with a timer + // If the timer resolves first, the promise is rejected with the exception + return Promise.race([prom, new Promise((resolve, reject) => (timer = setTimeout(reject, time, exception)))]).finally(() => + clearTimeout(timer), + ); +} + +/** + * Validate if the input string matches the time format YYYY-MM-DDTHH:mm:ss + * + * @param {string} timeString - The input time string. + * @return {boolean} - Returns true if the format matches, false otherwise. + */ +function isValidTimeFormat(timeString) { + const regex = /^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|1\d|2\d|3[01])T(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d$/; + + if (timeString === '0') { + return true; + } + + return regex.test(timeString); +} + +const dateToEta = (utcTimeString) => { + if (utcTimeString === '0') { + return 0; + } + + const date = new Date(utcTimeString + 'Z'); + + if (isNaN(date.getTime())) { + throw new Error(`Invalid date format provided: ${utcTimeString}`); + } + + return Math.floor(date.getTime() / 1000); +}; + +const etaToDate = (timestamp) => { + const date = new Date(timestamp * 1000); + + if (isNaN(date.getTime())) { + throw new Error(`Invalid timestamp provided: ${timestamp}`); + } + + return date.toISOString().slice(0, 19); +}; + +const getCurrentTimeInSeconds = () => { + const now = new Date(); + const currentTimeInSecs = Math.floor(now.getTime() / 1000); + return currentTimeInSecs; +}; + +/** + * Prompt the user for confirmation + * @param {string} question Prompt question + * @param {boolean} yes If true, skip the prompt + * @returns {boolean} Returns true if the prompt was skipped, false otherwise + */ +const prompt = (question, yes = false) => { + // skip the prompt if yes was passed + if (yes) { + return false; + } + + const answer = readlineSync.question(`${question} ${chalk.green('(y/n)')} `); + console.log(); + + return answer !== 'y'; +}; + +function findProjectRoot(startDir) { + let currentDir = startDir; + + while (currentDir !== path.parse(currentDir).root) { + const potentialPackageJson = path.join(currentDir, 'package.json'); + + if (fs.existsSync(potentialPackageJson)) { + return currentDir; + } + + currentDir = path.resolve(currentDir, '..'); + } + + throw new Error('Unable to find project root'); +} + +function toBigNumberString(number) { + return Math.ceil(number).toLocaleString('en', { useGrouping: false }); +} + +module.exports = { + loadConfig, + saveConfig, + writeJSON, + printInfo, + printWarn, + printError, + printLog, + isNonEmptyString, + isString, + isStringArray, + isNumber, + isValidNumber, + isValidDecimal, + isNumberArray, + isNonEmptyStringArray, + isValidTimeFormat, + copyObject, + httpGet, + httpPost, + parseArgs, + sleep, + dateToEta, + etaToDate, + getCurrentTimeInSeconds, + prompt, + findProjectRoot, + toBigNumberString, + timeout, +}; diff --git a/evm/cli-utils.js b/evm/cli-utils.js index 88fbc4a9..070c799d 100644 --- a/evm/cli-utils.js +++ b/evm/cli-utils.js @@ -1,87 +1,3 @@ -'use strict'; - -require('dotenv').config(); - -const { Option } = require('commander'); - -const addBaseOptions = (program, options = {}) => { - program.addOption( - new Option('-e, --env <env>', 'environment') - .choices(['local', 'devnet', 'devnet-amplifier', 'devnet-verifiers', 'stagenet', 'testnet', 'mainnet']) - .default('testnet') - .makeOptionMandatory(true) - .env('ENV'), - ); - program.addOption(new Option('-y, --yes', 'skip deployment prompt confirmation').env('YES')); - program.addOption(new Option('--parallel', 'run script parallely wrt chains')); - program.addOption(new Option('--saveChainSeparately', 'save chain info separately')); - program.addOption(new Option('--gasOptions <gasOptions>', 'gas options cli override')); - - if (!options.ignoreChainNames) { - program.addOption( - new Option('-n, --chainNames <chainNames>', 'chains to run the script over').makeOptionMandatory(true).env('CHAINS'), - ); - program.addOption(new Option('--skipChains <skipChains>', 'chains to skip over')); - program.addOption( - new Option( - '--startFromChain <startFromChain>', - 'start from a specific chain onwards in the config, useful when a cmd fails for an intermediate chain', - ), - ); - } - - if (!options.ignorePrivateKey) { - program.addOption(new Option('-p, --privateKey <privateKey>', 'private key').makeOptionMandatory(true).env('PRIVATE_KEY')); - } - - if (options.address) { - program.addOption(new Option('-a, --address <address>', 'override address')); - } - - return program; -}; - -const addExtendedOptions = (program, options = {}) => { - addBaseOptions(program, options); - - program.addOption(new Option('-v, --verify', 'verify the deployed contract on the explorer').env('VERIFY')); - - if (options.artifactPath) { - program.addOption(new Option('--artifactPath <artifactPath>', 'artifact path')); - } - - if (options.contractName) { - program.addOption(new Option('-c, --contractName <contractName>', 'contract name').makeOptionMandatory(true)); - } - - if (options.deployMethod) { - program.addOption( - new Option('-m, --deployMethod <deployMethod>', 'deployment method') - .choices(['create', 'create2', 'create3']) - .default(options.deployMethod), - ); - } - - if (options.salt) { - program.addOption(new Option('-s, --salt <salt>', 'salt to use for create2 deployment').env('SALT')); - } - - if (options.skipExisting) { - program.addOption(new Option('-x, --skipExisting', 'skip existing if contract was already deployed on chain').env('SKIP_EXISTING')); - } - - if (options.upgrade) { - program.addOption(new Option('-u, --upgrade', 'upgrade a deployed contract').env('UPGRADE')); - } - - if (options.predictOnly) { - program.addOption(new Option('--predictOnly', 'output the predicted changes only').env('PREDICT_ONLY')); - } - - return program; -}; - module.exports = { - addBaseOptions, - addExtendedOptions, + ...require('../common/cli-utils'), }; diff --git a/evm/utils.js b/evm/utils.js index e28bcadd..d9e8c058 100644 --- a/evm/utils.js +++ b/evm/utils.js @@ -9,13 +9,31 @@ const { getDefaultProvider, BigNumber, } = ethers; -const https = require('https'); -const http = require('http'); const fs = require('fs'); const path = require('path'); -const { outputJsonSync } = require('fs-extra'); -const readlineSync = require('readline-sync'); const chalk = require('chalk'); +const { + loadConfig, + saveConfig, + isNonEmptyString, + isNonEmptyStringArray, + isNumber, + isNumberArray, + isString, + isValidNumber, + isValidTimeFormat, + printInfo, + isValidDecimal, + copyObject, + printError, + printWarn, + writeJSON, + httpGet, + httpPost, + sleep, + findProjectRoot, + timeout, +} = require('../common'); const { create3DeployContract, deployContractConstant, @@ -122,138 +140,6 @@ const deployCreate3 = async ( return contract; }; -const printInfo = (msg, info = '', colour = chalk.green) => { - if (info) { - console.log(`${msg}: ${colour(info)}\n`); - } else { - console.log(`${msg}\n`); - } -}; - -const printWarn = (msg, info = '') => { - if (info) { - msg = `${msg}: ${info}`; - } - - console.log(`${chalk.italic.yellow(msg)}\n`); -}; - -const printError = (msg, info = '') => { - if (info) { - msg = `${msg}: ${info}`; - } - - console.log(`${chalk.bold.red(msg)}\n`); -}; - -function printLog(log) { - console.log(JSON.stringify({ log }, null, 2)); -} - -const writeJSON = (data, name) => { - outputJsonSync(name, data, { - spaces: 2, - EOL: '\n', - }); -}; - -const httpGet = (url) => { - return new Promise((resolve, reject) => { - (url.startsWith('https://') ? https : http).get(url, (res) => { - const { statusCode } = res; - const contentType = res.headers['content-type']; - let error; - - if (statusCode !== 200 && statusCode !== 301) { - error = new Error('Request Failed.\n' + `Request: ${url}\nStatus Code: ${statusCode}`); - } else if (!/^application\/json/.test(contentType)) { - error = new Error('Invalid content-type.\n' + `Expected application/json but received ${contentType}`); - } - - if (error) { - res.resume(); - reject(error); - return; - } - - res.setEncoding('utf8'); - let rawData = ''; - res.on('data', (chunk) => { - rawData += chunk; - }); - res.on('end', () => { - try { - const parsedData = JSON.parse(rawData); - resolve(parsedData); - } catch (e) { - reject(e); - } - }); - }); - }); -}; - -const httpPost = async (url, data) => { - const response = await fetch(url, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(data), - }); - return response.json(); -}; - -const isNonEmptyString = (arg) => { - return typeof arg === 'string' && arg !== ''; -}; - -const isString = (arg) => { - return typeof arg === 'string'; -}; - -const isStringArray = (arr) => Array.isArray(arr) && arr.every(isString); - -const isNumber = (arg) => { - return Number.isInteger(arg); -}; - -const isValidNumber = (arg) => { - return !isNaN(parseInt(arg)) && isFinite(arg); -}; - -const isValidDecimal = (arg) => { - return !isNaN(parseFloat(arg)) && isFinite(arg); -}; - -const isNumberArray = (arr) => { - if (!Array.isArray(arr)) { - return false; - } - - for (const item of arr) { - if (!isNumber(item)) { - return false; - } - } - - return true; -}; - -const isNonEmptyStringArray = (arr) => { - if (!Array.isArray(arr)) { - return false; - } - - for (const item of arr) { - if (typeof item !== 'string') { - return false; - } - } - - return true; -}; - const isAddressArray = (arr) => { if (!Array.isArray(arr)) return false; @@ -280,12 +166,6 @@ const isBytes32Array = (arr) => { return true; }; -const getCurrentTimeInSeconds = () => { - const now = new Date(); - const currentTimeInSecs = Math.floor(now.getTime() / 1000); - return currentTimeInSecs; -}; - /** * Determines if a given input is a valid keccak256 hash. * @@ -344,22 +224,6 @@ function isValidAddress(address, allowZeroAddress) { return isAddress(address); } -/** - * Validate if the input string matches the time format YYYY-MM-DDTHH:mm:ss - * - * @param {string} timeString - The input time string. - * @return {boolean} - Returns true if the format matches, false otherwise. - */ -function isValidTimeFormat(timeString) { - const regex = /^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|1\d|2\d|3[01])T(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d$/; - - if (timeString === '0') { - return true; - } - - return regex.test(timeString); -} - // Validate if the input privateKey is correct function isValidPrivateKey(privateKey) { // Check if it's a valid hexadecimal string @@ -431,38 +295,6 @@ function validateParameters(parameters) { } } -/** - * Parses the input string into an array of arguments, recognizing and converting - * to the following types: boolean, number, array, and string. - * - * @param {string} args - The string of arguments to parse. - * - * @returns {Array} - An array containing parsed arguments. - * - * @example - * const input = "hello true 123 [1,2,3]"; - * const output = parseArgs(input); - * console.log(output); // Outputs: [ 'hello', true, 123, [ 1, 2, 3] ] - */ -const parseArgs = (args) => { - return args - .split(/\s+/) - .filter((item) => item !== '') - .map((arg) => { - if (arg.startsWith('[') && arg.endsWith(']')) { - return JSON.parse(arg); - } else if (arg === 'true') { - return true; - } else if (arg === 'false') { - return false; - } else if (!isNaN(arg) && !arg.startsWith('0x')) { - return Number(arg); - } - - return arg; - }); -}; - /** * Compute bytecode hash for a deployed contract or contract factory as it would appear on-chain. * Some chains don't use keccak256 for their state representation, which is taken into account by this function. @@ -685,22 +517,10 @@ const getAmplifierKeyAddresses = async (config, chain) => { return { addresses: weightedAddresses, threshold: verifierSet.threshold, created_at: verifierSet.created_at, verifierSetId }; }; -function sleep(ms) { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -function loadConfig(env) { - return require(`${__dirname}/../axelar-chains-config/info/${env}.json`); -} - function loadParallelExecutionConfig(env, chain) { return require(`${__dirname}/../chains-info/${env}-${chain}.json`); } -function saveConfig(config, env) { - writeJSON(config, `${__dirname}/../axelar-chains-config/info/${env}.json`); -} - function saveParallelExecutionConfig(config, env, chain) { writeJSON(config, `${__dirname}/../chains-info/${env}-${chain}.json`); } @@ -806,30 +626,6 @@ const deployContract = async ( } }; -const dateToEta = (utcTimeString) => { - if (utcTimeString === '0') { - return 0; - } - - const date = new Date(utcTimeString + 'Z'); - - if (isNaN(date.getTime())) { - throw new Error(`Invalid date format provided: ${utcTimeString}`); - } - - return Math.floor(date.getTime() / 1000); -}; - -const etaToDate = (timestamp) => { - const date = new Date(timestamp * 1000); - - if (isNaN(date.getTime())) { - throw new Error(`Invalid timestamp provided: ${timestamp}`); - } - - return date.toISOString().slice(0, 19); -}; - /** * Check if a specific event was emitted in a transaction receipt. * @@ -844,10 +640,6 @@ function wasEventEmitted(receipt, contract, eventName) { return receipt.logs.some((log) => log.topics[0] === event.topics[0]); } -function copyObject(obj) { - return JSON.parse(JSON.stringify(obj)); -} - const mainProcessor = async (options, processCommand, save = true, catchErr = false) => { if (!options.env) { throw new Error('Environment was not provided'); @@ -987,24 +779,6 @@ const mainProcessor = async (options, processCommand, save = true, catchErr = fa } }; -/** - * Prompt the user for confirmation - * @param {string} question Prompt question - * @param {boolean} yes If true, skip the prompt - * @returns {boolean} Returns true if the prompt was skipped, false otherwise - */ -const prompt = (question, yes = false) => { - // skip the prompt if yes was passed - if (yes) { - return false; - } - - const answer = readlineSync.question(`${question} ${chalk.green('(y/n)')} `); - console.log(); - - return answer !== 'y'; -}; - function getConfigByChainId(chainId, config) { for (const chain of Object.values(config.chains)) { if (chain.chainId === chainId) { @@ -1015,22 +789,6 @@ function getConfigByChainId(chainId, config) { throw new Error(`Chain with chainId ${chainId} not found in the config`); } -function findProjectRoot(startDir) { - let currentDir = startDir; - - while (currentDir !== path.parse(currentDir).root) { - const potentialPackageJson = path.join(currentDir, 'package.json'); - - if (fs.existsSync(potentialPackageJson)) { - return currentDir; - } - - currentDir = path.resolve(currentDir, '..'); - } - - throw new Error('Unable to find project root'); -} - function findContractPath(dir, contractName) { const files = fs.readdirSync(dir); @@ -1184,20 +942,6 @@ function isValidChain(config, chainName) { } } -function toBigNumberString(number) { - return Math.ceil(number).toLocaleString('en', { useGrouping: false }); -} - -function timeout(prom, time, exception) { - let timer; - - // Racing the promise with a timer - // If the timer resolves first, the promise is rejected with the exception - return Promise.race([prom, new Promise((resolve, reject) => (timer = setTimeout(reject, time, exception)))]).finally(() => - clearTimeout(timer), - ); -} - async function relayTransaction(options, chain, contract, method, params, nativeValue = 0, gasOptions = {}, expectedEvent = null) { if (options.relayerAPI) { const result = await httpPost(options.relayerAPI, { @@ -1270,55 +1014,31 @@ async function getWeightedSigners(config, chain, options) { } module.exports = { + ...require('../common/utils'), deployCreate, deployCreate2, deployCreate3, deployContract, - writeJSON, - copyObject, - httpGet, - httpPost, printObj, - printLog, - printInfo, - printWarn, - printError, getBytecodeHash, predictAddressCreate, getDeployedAddress, - isString, - isNonEmptyString, - isStringArray, - isNumber, - isValidNumber, - isValidDecimal, - isNumberArray, - isNonEmptyStringArray, isAddressArray, isKeccak256Hash, isValidCalldata, isValidBytesAddress, validateParameters, - parseArgs, getProxy, getEVMBatch, getEVMAddresses, getConfigByChainId, - sleep, - loadConfig, - saveConfig, printWalletInfo, - isValidTimeFormat, - dateToEta, - etaToDate, - getCurrentTimeInSeconds, wasEventEmitted, isContract, isValidAddress, isValidPrivateKey, isValidTokenId, verifyContract, - prompt, mainProcessor, getContractPath, getContractJSON, @@ -1327,8 +1047,6 @@ module.exports = { getSaltFromKey, getDeployOptions, isValidChain, - toBigNumberString, - timeout, getAmplifierKeyAddresses, getContractConfig, relayTransaction, From 78b4174ed0cc588a651ab8afd8f781f252a0af10 Mon Sep 17 00:00:00 2001 From: Blockchain Guy <ayusht11@outlook.com> Date: Mon, 29 Jul 2024 20:52:28 +0530 Subject: [PATCH 37/44] feat: add script to upgrade sui gateway (#306) Co-authored-by: npty <nptytn2@gmail.com> Co-authored-by: npty <78221556+npty@users.noreply.github.com> --- package-lock.json | 136 +++++++++++------------ package.json | 2 +- sui/README.md | 26 ++++- sui/deploy-contract.js | 243 ++++++++++++++++++++++++++++++++++------- sui/deploy-gateway.js | 146 ------------------------- sui/deploy-utils.js | 31 ++++-- sui/multisig.js | 34 ++++-- sui/sign-utils.js | 4 +- sui/utils.js | 19 +++- 9 files changed, 352 insertions(+), 289 deletions(-) delete mode 100644 sui/deploy-gateway.js diff --git a/package-lock.json b/package-lock.json index 1c33be51..55b67d22 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT", "dependencies": { "@axelar-network/axelar-cgp-solidity": "6.3.1", - "@axelar-network/axelar-cgp-sui": "^0.3.0", + "@axelar-network/axelar-cgp-sui": "0.3.0", "@axelar-network/axelar-gmp-sdk-solidity": "5.10.0", "@axelar-network/interchain-token-service": "1.2.4", "@cosmjs/cosmwasm-stargate": "^0.32.1", @@ -54,9 +54,9 @@ } }, "node_modules/@0no-co/graphqlsp": { - "version": "1.12.11", - "resolved": "https://registry.npmjs.org/@0no-co/graphqlsp/-/graphqlsp-1.12.11.tgz", - "integrity": "sha512-vLja9r7L6BBXwxW86Wyi5z5hjTHscH7qoQooy+MXHkM9srBB6ZuesYZq5DQ/+SErQrFyaxeY+hwv2qBAksxriw==", + "version": "1.12.12", + "resolved": "https://registry.npmjs.org/@0no-co/graphqlsp/-/graphqlsp-1.12.12.tgz", + "integrity": "sha512-BmCAc/q3tQcIwXxKoxubYaB23s2fWMMmNGSlY9mgQvWiReBS8ZutPZSf11OADfwTv1J1JIazU6q6OFX+cEp8PQ==", "dependencies": { "@gql.tada/internal": "^1.0.0", "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0" @@ -1368,20 +1368,20 @@ } }, "node_modules/@ledgerhq/devices": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/@ledgerhq/devices/-/devices-8.4.0.tgz", - "integrity": "sha512-TUrMlWZJ+5AFp2lWMw4rGQoU+WtjIqlFX5SzQDL9phaUHrt4TFierAGHsaj5+tUHudhD4JhIaLI2cn1NOyq5NQ==", + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/@ledgerhq/devices/-/devices-8.4.2.tgz", + "integrity": "sha512-oWNTp3jCMaEvRHsXNYE/yo+PFMgXAJGFHLOU1UdE4/fYkniHbD9wdxwyZrZvrxr9hNw4/9wHiThyITwPtMzG7g==", "dependencies": { - "@ledgerhq/errors": "^6.17.0", + "@ledgerhq/errors": "^6.18.0", "@ledgerhq/logs": "^6.12.0", "rxjs": "^7.8.1", "semver": "^7.3.5" } }, "node_modules/@ledgerhq/errors": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/@ledgerhq/errors/-/errors-6.17.0.tgz", - "integrity": "sha512-xnOVpy/gUUkusEORdr2Qhw3Vd0MGfjyVGgkGR9Ck6FXE26OIdIQ3tNmG5BdZN+gwMMFJJVxxS4/hr0taQfZ43w==" + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@ledgerhq/errors/-/errors-6.18.0.tgz", + "integrity": "sha512-L3jQWAGyooxRDk/MRlW2v4Ji9+kloBtdmz9wBkHaj2j0n+05rweJSV3GHw9oye1BYMbVFqFffmT4H3hlXlCasw==" }, "node_modules/@ledgerhq/hw-app-eth": { "version": "6.32.2", @@ -1409,36 +1409,36 @@ } }, "node_modules/@ledgerhq/hw-transport": { - "version": "6.31.0", - "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport/-/hw-transport-6.31.0.tgz", - "integrity": "sha512-BY1poLk8vlJdIYngp8Zfaa/V9n14dqgt1G7iNetVRhJVFEKp9EYONeC3x6q/N7x81LUpzBk6M+T+s46Z4UiXHw==", + "version": "6.31.2", + "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport/-/hw-transport-6.31.2.tgz", + "integrity": "sha512-B27UIzMzm2IXPGYnEB95R7eHxpXBkTBHh6MUJJQZVknt8LilEz1tfpTYUdzAKDGQ+Z5MZyYb01Eh3Zqm3kn3uw==", "dependencies": { - "@ledgerhq/devices": "^8.4.0", - "@ledgerhq/errors": "^6.17.0", + "@ledgerhq/devices": "^8.4.2", + "@ledgerhq/errors": "^6.18.0", "@ledgerhq/logs": "^6.12.0", "events": "^3.3.0" } }, "node_modules/@ledgerhq/hw-transport-mocker": { - "version": "6.29.0", - "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-mocker/-/hw-transport-mocker-6.29.0.tgz", - "integrity": "sha512-SbS4SvbMcpNquUsvN4Gd0bTi7ohySqIDMHFf2YLhYBRu1HviU3TG/p4zoFrJcFUiIX2/wOmUdHsWtaQFdMVGyQ==", + "version": "6.29.2", + "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-mocker/-/hw-transport-mocker-6.29.2.tgz", + "integrity": "sha512-s+YcMy0Bna6r1Sm6qiawrd8FBE6AJhUTIUqBxP9n7OuzaIGKdf/Y++16PWfNE1rBuzplbzBDRBLAa4XnQ8uCEA==", "dependencies": { - "@ledgerhq/hw-transport": "^6.31.0", + "@ledgerhq/hw-transport": "^6.31.2", "@ledgerhq/logs": "^6.12.0", "rxjs": "^7.8.1" } }, "node_modules/@ledgerhq/hw-transport-node-hid": { - "version": "6.29.1", - "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-node-hid/-/hw-transport-node-hid-6.29.1.tgz", - "integrity": "sha512-l+zAfsE0uvo2/Wni0TSW+n6HoFmZdPH6ukrjPocY6jvbhcaxhpbK7ERvDpnZMir/pHwsDoAsvwPY/0sFRBf7bw==", + "version": "6.29.3", + "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-node-hid/-/hw-transport-node-hid-6.29.3.tgz", + "integrity": "sha512-4ruOXRuZvWI6HijFng9xjg7hT4Y4MY+IThsKXKE6ndZ6oEkHXzCwfTI8gPkQvHwnmCrPmeL/PMOTWMgffjgJvQ==", "dev": true, "dependencies": { - "@ledgerhq/devices": "^8.4.0", - "@ledgerhq/errors": "^6.17.0", - "@ledgerhq/hw-transport": "^6.31.0", - "@ledgerhq/hw-transport-node-hid-noevents": "^6.30.1", + "@ledgerhq/devices": "^8.4.2", + "@ledgerhq/errors": "^6.18.0", + "@ledgerhq/hw-transport": "^6.31.2", + "@ledgerhq/hw-transport-node-hid-noevents": "^6.30.3", "@ledgerhq/logs": "^6.12.0", "lodash": "^4.17.21", "node-hid": "2.1.2", @@ -1446,14 +1446,14 @@ } }, "node_modules/@ledgerhq/hw-transport-node-hid-noevents": { - "version": "6.30.1", - "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-node-hid-noevents/-/hw-transport-node-hid-noevents-6.30.1.tgz", - "integrity": "sha512-9Mb5vDBXfSaRhfl0U2DnJLN4FgosfQopkzjzZYYHT3+s9XMot4WN/eWWbv5Ksx5qsV8RLQ77dewFFomNthm/vQ==", + "version": "6.30.3", + "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-node-hid-noevents/-/hw-transport-node-hid-noevents-6.30.3.tgz", + "integrity": "sha512-rYnHmWaGFKiQOhdRgr7xm767fLOl2yKv95vG+FNztDjKZBOj8RfH9K0S4eNVilqxGSW7ad3H5XlpfSTzgC5eIQ==", "dev": true, "dependencies": { - "@ledgerhq/devices": "^8.4.0", - "@ledgerhq/errors": "^6.17.0", - "@ledgerhq/hw-transport": "^6.31.0", + "@ledgerhq/devices": "^8.4.2", + "@ledgerhq/errors": "^6.18.0", + "@ledgerhq/hw-transport": "^6.31.2", "@ledgerhq/logs": "^6.12.0", "node-hid": "2.1.2" } @@ -2375,16 +2375,16 @@ } }, "node_modules/@stellar/js-xdr": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@stellar/js-xdr/-/js-xdr-3.1.1.tgz", - "integrity": "sha512-3gnPjAz78htgqsNEDkEsKHKosV2BF2iZkoHCNxpmZwUxiPsw+2VaXMed8RRMe0rGk3d5GZe7RrSba8zV80J3Ag==" + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@stellar/js-xdr/-/js-xdr-3.1.2.tgz", + "integrity": "sha512-VVolPL5goVEIsvuGqDc5uiKxV03lzfWdvYg1KikvwheDmTBO68CKDji3bAZ/kppZrx5iTA8z3Ld5yuytcvhvOQ==" }, "node_modules/@stellar/stellar-base": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-12.0.1.tgz", - "integrity": "sha512-g6c27MNsDgEdUmoNQJn7zCWoCY50WHt0OIIOq3PhWaJRtUaT++qs1Jpb8+1bny2GmhtfRGOfPUFSyQBuHT9Mvg==", + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-12.1.0.tgz", + "integrity": "sha512-pWwn+XWP5NotmIteZNuJzHeNn9DYSqH3lsYbtFUoSYy1QegzZdi9D8dK6fJ2fpBAnf/rcDjHgHOw3gtHaQFVbg==", "dependencies": { - "@stellar/js-xdr": "^3.1.1", + "@stellar/js-xdr": "^3.1.2", "base32.js": "^0.1.0", "bignumber.js": "^9.1.2", "buffer": "^6.0.3", @@ -2396,11 +2396,11 @@ } }, "node_modules/@stellar/stellar-sdk": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/@stellar/stellar-sdk/-/stellar-sdk-12.1.0.tgz", - "integrity": "sha512-Va0hu9SaPezmMbO5eMwL5D15Wrx1AGWRtxayUDRWV2Fr3ynY58mvCZS1vsgNQ4kE8MZe3nBVKv6T9Kzqwgx1PQ==", + "version": "12.2.0", + "resolved": "https://registry.npmjs.org/@stellar/stellar-sdk/-/stellar-sdk-12.2.0.tgz", + "integrity": "sha512-Wy5sDOqb5JvAC76f4sQIV6Pe3JNyZb0PuyVNjwt3/uWsjtxRkFk6s2yTHTefBLWoR+mKxDjO7QfzhycF1v8FXQ==", "dependencies": { - "@stellar/stellar-base": "^12.0.1", + "@stellar/stellar-base": "^12.1.0", "axios": "^1.7.2", "bignumber.js": "^9.1.2", "eventsource": "^2.0.2", @@ -2589,9 +2589,9 @@ "peer": true }, "node_modules/@types/node": { - "version": "20.14.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz", - "integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==", + "version": "20.14.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.12.tgz", + "integrity": "sha512-r7wNXakLeSsGT0H1AU863vS2wa5wBOK4bWMjZz2wj+8nBx+m5PeIn0k8AloSLpRuiwdRQZwarZqHE4FNArPuJQ==", "dependencies": { "undici-types": "~5.26.4" } @@ -2675,24 +2675,24 @@ "integrity": "sha512-MTeCV9MUwwsH0sNFiZwKtFrrVZUK6p8ioZs3xFzHc2cvDXHWlYN3bChdQtwKX+FY2HG6H3CfAu1pKijolzIQ8g==" }, "node_modules/@vue/compiler-core": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.32.tgz", - "integrity": "sha512-8tCVWkkLe/QCWIsrIvExUGnhYCAOroUs5dzhSoKL5w4MJS8uIYiou+pOPSVIOALOQ80B0jBs+Ri+kd5+MBnCDw==", + "version": "3.4.34", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.34.tgz", + "integrity": "sha512-Z0izUf32+wAnQewjHu+pQf1yw00EGOmevl1kE+ljjjMe7oEfpQ+BI3/JNK7yMB4IrUsqLDmPecUrpj3mCP+yJQ==", "dependencies": { "@babel/parser": "^7.24.7", - "@vue/shared": "3.4.32", + "@vue/shared": "3.4.34", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-dom": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.32.tgz", - "integrity": "sha512-PbSgt9KuYo4fyb90dynuPc0XFTfFPs3sCTbPLOLlo+PrUESW1gn/NjSsUvhR+mI2AmmEzexwYMxbHDldxSOr2A==", + "version": "3.4.34", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.34.tgz", + "integrity": "sha512-3PUOTS1h5cskdOJMExCu2TInXuM0j60DRPpSCJDqOCupCfUZCJoyQmKtRmA8EgDNZ5kcEE7vketamRZfrEuVDw==", "dependencies": { - "@vue/compiler-core": "3.4.32", - "@vue/shared": "3.4.32" + "@vue/compiler-core": "3.4.34", + "@vue/shared": "3.4.34" } }, "node_modules/@vue/language-core": { @@ -2741,9 +2741,9 @@ } }, "node_modules/@vue/shared": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.32.tgz", - "integrity": "sha512-ep4mF1IVnX/pYaNwxwOpJHyBtOMKWoKZMbnUyd+z0udqIxLUh7YCCd/JfDna8aUrmnG9SFORyIq2HzEATRrQsg==" + "version": "3.4.34", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.34.tgz", + "integrity": "sha512-x5LmiRLpRsd9KTjAB8MPKf0CDPMcuItjP0gbNqFCIgL1I8iYp4zglhj9w9FPCdIbHG2M91RVeIbArFfFTz9I3A==" }, "node_modules/abbrev": { "version": "1.0.9", @@ -6921,9 +6921,9 @@ } }, "node_modules/immutable": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.6.tgz", - "integrity": "sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", + "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==", "dev": true }, "node_modules/import-fresh": { @@ -7941,9 +7941,9 @@ } }, "node_modules/mocha": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.6.0.tgz", - "integrity": "sha512-hxjt4+EEB0SA0ZDygSS015t65lJw/I2yRCS3Ae+SJ5FrbzrXgfYwJr96f0OvIXdj7h4lv/vLCrH3rkiuizFSvw==", + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.0.tgz", + "integrity": "sha512-v8/rBWr2VO5YkspYINnvu81inSz2y3ODJrhO175/Exzor1RcEZZkizgE2A+w/CAXXoESS8Kys5E62dOHGHzULA==", "dev": true, "dependencies": { "ansi-colors": "^4.1.3", @@ -10697,9 +10697,9 @@ } }, "node_modules/typescript": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", - "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", "peer": true, "bin": { "tsc": "bin/tsc", diff --git a/package.json b/package.json index 4e2fea74..01379e8c 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "homepage": "https://github.com/axelarnetwork/axelar-contract-deployments#readme", "dependencies": { "@axelar-network/axelar-cgp-solidity": "6.3.1", - "@axelar-network/axelar-cgp-sui": "^0.3.0", + "@axelar-network/axelar-cgp-sui": "0.3.0", "@axelar-network/axelar-gmp-sdk-solidity": "5.10.0", "@axelar-network/interchain-token-service": "1.2.4", "@cosmjs/cosmwasm-stargate": "^0.32.1", diff --git a/sui/README.md b/sui/README.md index 980e6521..0ea2275c 100644 --- a/sui/README.md +++ b/sui/README.md @@ -54,27 +54,45 @@ Deploy the gateway package: - By querying the signer set from the Amplifier contract (this only works if Amplifier contracts have been setup): ```bash -node sui/deploy-gateway.js +node sui/deploy-contract.js deploy axelar_gateway ``` +Note: the `minimumRotationDelay` is in `seconds` unit. The default value is `24 * 60 * 60` (1 day). + Use `--help` flag to see other setup params that can be overridden. - For testing convenience, you can use the secp256k1 wallet as the signer set for the gateway. ```bash -node sui/deploy-gateway.js --signers wallet --nonce test +node sui/deploy-contract.js deploy axelar_gateway --signers wallet --nonce test ``` - You can also provide a JSON object with a full signer set: ```bash -node sui/deploy-gateway.js -e testnet --signers '{"signers": [{"pub_key": "0x020194ead85b350d90472117e6122cf1764d93bf17d6de4b51b03d19afc4d6302b", "weight": 1}], "threshold": 1, "nonce": "0x0000000000000000000000000000000000000000000000000000000000000000"}' +node sui/deploy-contract.js deploy axelar_gateway -e testnet --signers '{"signers": [{"pub_key": "0x020194ead85b350d90472117e6122cf1764d93bf17d6de4b51b03d19afc4d6302b", "weight": 1}], "threshold": 1, "nonce": "0x0000000000000000000000000000000000000000000000000000000000000000"}' ``` +Upgrading Gateway: + +To update the gateway run the following command: + +```bash +node sui/deploy-contract.js upgrade axelar_gateway <policy> +``` + +policy should be one of the following: + +- `any_upgrade`: Allow any upgrade. +- `code_upgrade`: Upgrade policy to just add code. https://docs.sui.io/references/framework/sui-framework/package#function-only_additive_upgrades +- `dep_upgrade`: Upgrade policy to just change dependencies. https://docs.sui.io/references/framework/sui-framework/package#function-only_dep_upgrades + +Provide `--txFilePath` with `--offline` to generate tx data file for offline signing. + Deploy the Gas Service package: ```bash -node sui/deploy-contract.js GasService +node sui/deploy-contract.js deploy gas_service ``` Deploy the test GMP package: diff --git a/sui/deploy-contract.js b/sui/deploy-contract.js index e97113cd..eb562f56 100644 --- a/sui/deploy-contract.js +++ b/sui/deploy-contract.js @@ -1,71 +1,232 @@ -const { saveConfig, printInfo } = require('../evm/utils'); -const { Command, Argument, Option } = require('commander'); +const { Command, Option } = require('commander'); +const { updateMoveToml, TxBuilder } = require('@axelar-network/axelar-cgp-sui'); +const { ethers } = require('hardhat'); +const { toB64 } = require('@mysten/sui/utils'); +const { bcs } = require('@mysten/sui/bcs'); +const { Transaction } = require('@mysten/sui/transactions'); +const { + utils: { arrayify, hexlify, toUtf8Bytes, keccak256 }, + constants: { HashZero }, +} = ethers; +const { saveConfig, printInfo, validateParameters, writeJSON } = require('../evm/utils'); const { addBaseOptions } = require('./cli-utils'); -const { getWallet, printWalletInfo } = require('./sign-utils'); -const { loadSuiConfig, findPublishedObject, deployPackage } = require('./utils'); - -// Add more contracts here to support more modules deployment -const contractMap = { - GasService: { - packageName: 'gas_service', - }, -}; - -async function processCommand(contractName, config, chain, options) { - const contract = contractMap[contractName]; - const packageName = options.packageName || contract.packageName; - - const [keypair, client] = getWallet(chain, options); +const { getWallet, printWalletInfo, broadcast } = require('./sign-utils'); +const { loadSuiConfig, getAmplifierSigners, deployPackage, getObjectIdsByObjectTypes } = require('./utils'); +const { bytes32Struct, signersStruct } = require('./types-utils'); +const { upgradePackage } = require('./deploy-utils'); +const { suiPackageAddress, suiClockAddress } = require('./utils'); + +async function getSigners(keypair, config, chain, options) { + if (options.signers === 'wallet') { + const pubKey = keypair.getPublicKey().toRawBytes(); + printInfo('Using wallet pubkey as the signer for the gateway', hexlify(pubKey)); + + if (keypair.getKeyScheme() !== 'Secp256k1') { + throw new Error('Only Secp256k1 pubkeys are supported by the gateway'); + } + + return { + signers: [{ pub_key: pubKey, weight: 1 }], + threshold: 1, + nonce: options.nonce ? keccak256(toUtf8Bytes(options.nonce)) : HashZero, + }; + } else if (options.signers) { + printInfo('Using provided signers', options.signers); + + const signers = JSON.parse(options.signers); + return { + signers: signers.signers.map(({ pub_key: pubKey, weight }) => { + return { pub_key: arrayify(pubKey), weight }; + }), + threshold: signers.threshold, + nonce: arrayify(signers.nonce) || HashZero, + }; + } - await printWalletInfo(keypair, client, chain, options); + return getAmplifierSigners(config, chain); +} +async function deploy(keypair, client, contractName, config, chain, options) { if (!chain.contracts[contractName]) { chain.contracts[contractName] = {}; } - const published = await deployPackage(packageName, client, keypair); - const packageId = published.packageId; + const { packageId, publishTxn } = await deployPackage(contractName, client, keypair, options); - const contractObject = findPublishedObject(published, packageName, contractName); - const gasCollectorCapObject = findPublishedObject(published, packageName, 'GasCollectorCap'); + printInfo('Publish transaction digest: ', publishTxn.digest); const contractConfig = chain.contracts[contractName]; contractConfig.address = packageId; - contractConfig.objects = { - [contractName]: contractObject.objectId, - }; + contractConfig.objects = {}; switch (contractName) { - case 'GasService': - contractConfig.objects.GasCollectorCap = gasCollectorCapObject.objectId; + case 'gas_service': { + const [GasService, GasCollectorCap] = getObjectIdsByObjectTypes(publishTxn, [ + `${packageId}::gas_service::GasService`, + `${packageId}::gas_service::GasCollectorCap`, + ]); + contractConfig.objects = { GasService, GasCollectorCap }; + break; + } + + case 'axelar_gateway': { + const { minimumRotationDelay, domainSeparator, policy, previousSigners } = options; + const operator = options.operator || keypair.toSuiAddress(); + const signers = await getSigners(keypair, config, chain, options); + + validateParameters({ isNonEmptyString: { previousSigners, minimumRotationDelay }, isKeccak256Hash: { domainSeparator } }); + + const [creatorCap, relayerDiscovery, upgradeCap] = getObjectIdsByObjectTypes(publishTxn, [ + `${packageId}::gateway::CreatorCap`, + `${packageId}::discovery::RelayerDiscovery`, + `${suiPackageAddress}::package::UpgradeCap`, + ]); + + const encodedSigners = signersStruct + .serialize({ + ...signers, + nonce: bytes32Struct.serialize(signers.nonce).toBytes(), + }) + .toBytes(); + + const tx = new Transaction(); + + const separator = tx.moveCall({ + target: `${packageId}::bytes32::new`, + arguments: [tx.pure(arrayify(domainSeparator))], + }); + + tx.moveCall({ + target: `${packageId}::gateway::setup`, + arguments: [ + tx.object(creatorCap), + tx.pure.address(operator), + separator, + tx.pure.u64(minimumRotationDelay), + tx.pure.u64(options.previousSigners), + tx.pure(bcs.vector(bcs.u8()).serialize(encodedSigners).toBytes()), + tx.object(suiClockAddress), + ], + }); + + if (policy !== 'any_upgrade') { + const upgradeType = policy === 'code_upgrade' ? 'only_additive_upgrades' : 'only_dep_upgrades'; + + tx.moveCall({ + target: `${suiPackageAddress}::package::${upgradeType}`, + arguments: [tx.object(upgradeCap)], + }); + } + + const result = await broadcast(client, keypair, tx); + + printInfo('Setup transaction digest', result.digest); + + const [gateway] = getObjectIdsByObjectTypes(result, [`${packageId}::gateway::Gateway`]); + + contractConfig.objects = { + gateway, + relayerDiscovery, + upgradeCap, + }; + contractConfig.domainSeparator = domainSeparator; + contractConfig.operator = operator; + contractConfig.minimumRotationDelay = minimumRotationDelay; break; - default: + } + + default: { throw new Error(`${contractName} is not supported.`); + } } printInfo(`${contractName} deployed`, JSON.stringify(contractConfig, null, 2)); } -async function mainProcessor(contractName, options, processor) { +async function upgrade(keypair, client, contractName, policy, config, chain, options) { + const { packageDependencies } = options; + options.policy = policy; + + if (!chain.contracts[contractName]) { + throw new Error(`Cannot find specified contract: ${contractName}`); + } + + const contractsConfig = chain.contracts; + const packageConfig = contractsConfig?.[contractName]; + + validateParameters({ isNonEmptyString: { contractName } }); + + if (packageDependencies) { + for (const dependencies of packageDependencies) { + const packageId = contractsConfig[dependencies]?.address; + updateMoveToml(dependencies, packageId); + } + } + + const builder = new TxBuilder(client); + await upgradePackage(client, keypair, contractName, packageConfig, builder, options); +} + +async function mainProcessor(args, options, processor) { const config = loadSuiConfig(options.env); - await processor(contractName, config, config.sui, options); + const [keypair, client] = getWallet(config.sui, options); + await printWalletInfo(keypair, client, config.sui, options); + await processor(keypair, client, ...args, config, config.sui, options); saveConfig(config, options.env); + + if (options.offline) { + const { txFilePath } = options; + validateParameters({ isNonEmptyString: { txFilePath } }); + + const txB64Bytes = toB64(options.txBytes); + + writeJSON({ message: options.offlineMessage, status: 'PENDING', unsignedTx: txB64Bytes }, txFilePath); + printInfo(`Unsigned transaction`, txFilePath); + } } if (require.main === module) { const program = new Command(); - program - .name('deploy-contract') - .addOption(new Option('--packageName <packageName>', 'Package name to deploy')) - .addArgument(new Argument('<contractName>', 'Contract name to deploy').choices(Object.keys(contractMap))) - .description('Deploy SUI modules'); - - addBaseOptions(program); - - program.action((contractName, options) => { - mainProcessor(contractName, options, processCommand); - }); + program.name('deploy-contract').description('Deploy/Upgrade packages'); + + const deployCmd = program + .name('deploy') + .description('Deploy a Sui package') + .command('deploy <contractName>') + .addOption(new Option('--signers <signers>', 'JSON with the initial signer set').env('SIGNERS')) + .addOption(new Option('--operator <operator>', 'operator for the gateway (defaults to the deployer address)').env('OPERATOR')) + .addOption( + new Option('--minimumRotationDelay <minimumRotationDelay>', 'minium delay for signer rotations (in second)') + .default(24 * 60 * 60) + .parseArg((val) => parseInt(val) * 1000), + ) + .addOption(new Option('--domainSeparator <domainSeparator>', 'domain separator')) + .addOption(new Option('--nonce <nonce>', 'nonce for the signer (defaults to HashZero)')) + .addOption(new Option('--previousSigners <previousSigners>', 'number of previous signers to retain').default('15')) + .addOption( + new Option('--policy <policy>', 'upgrade policy for upgrade cap: For example, use "any_upgrade" to allow all types of upgrades') + .choices(['any_upgrade', 'code_upgrade', 'dep_upgrade']) + .default('any_upgrade'), + ) + .action((contractName, options) => { + mainProcessor([contractName], options, deploy); + }); + + const upgradeCmd = program + .name('upgrade') + .description('Upgrade a Sui package') + .command('upgrade <contractName> <policy>') + .addOption(new Option('--sender <sender>', 'transaction sender')) + .addOption(new Option('--digest <digest>', 'digest hash for upgrade')) + .addOption(new Option('--offline', 'store tx block for sign')) + .addOption(new Option('--txFilePath <file>', 'unsigned transaction will be stored')) + .action((contractName, policy, options) => { + mainProcessor([contractName, policy], options, upgrade); + }); + + addBaseOptions(deployCmd); + addBaseOptions(upgradeCmd); program.parse(); } diff --git a/sui/deploy-gateway.js b/sui/deploy-gateway.js deleted file mode 100644 index bec033f8..00000000 --- a/sui/deploy-gateway.js +++ /dev/null @@ -1,146 +0,0 @@ -const { saveConfig, prompt, printInfo } = require('../evm/utils'); -const { Command, Option } = require('commander'); -const { Transaction } = require('@mysten/sui/transactions'); -const { bcs } = require('@mysten/sui/bcs'); -const { ethers } = require('hardhat'); -const { - utils: { arrayify, hexlify, toUtf8Bytes, keccak256 }, - constants: { HashZero }, -} = ethers; - -const { addBaseOptions } = require('./cli-utils'); -const { getWallet, printWalletInfo, broadcast } = require('./sign-utils'); -const { bytes32Struct, signersStruct } = require('./types-utils'); -const { getAmplifierSigners, loadSuiConfig, deployPackage } = require('./utils'); - -async function getSigners(keypair, config, chain, options) { - if (options.signers === 'wallet') { - const pubKey = keypair.getPublicKey().toRawBytes(); - printInfo('Using wallet pubkey as the signer for the gateway', hexlify(pubKey)); - - if (keypair.getKeyScheme() !== 'Secp256k1') { - throw new Error('Only Secp256k1 pubkeys are supported by the gateway'); - } - - return { - signers: [{ pub_key: pubKey, weight: 1 }], - threshold: 1, - nonce: options.nonce ? keccak256(toUtf8Bytes(options.nonce)) : HashZero, - }; - } else if (options.signers) { - printInfo('Using provided signers', options.signers); - - const signers = JSON.parse(options.signers); - return { - signers: signers.signers.map(({ pub_key: pubKey, weight }) => { - return { pub_key: arrayify(pubKey), weight }; - }), - threshold: signers.threshold, - nonce: arrayify(signers.nonce) || HashZero, - }; - } - - return getAmplifierSigners(config, chain); -} - -async function processCommand(config, chain, options) { - const [keypair, client] = getWallet(chain, options); - - await printWalletInfo(keypair, client, chain, options); - - if (!chain.contracts.axelar_gateway) { - chain.contracts.axelar_gateway = {}; - } - - const contractConfig = chain.contracts.axelar_gateway; - const { minimumRotationDelay, previousSignerRetention, domainSeparator } = options; - const signers = await getSigners(keypair, config, chain, options); - const operator = options.operator || keypair.toSuiAddress(); - - if (prompt(`Proceed with deployment on ${chain.name}?`, options.yes)) { - return; - } - - const { packageId, publishTxn } = await deployPackage('axelar_gateway', client, keypair); - - const creatorCap = publishTxn.objectChanges.find((change) => change.objectType === `${packageId}::gateway::CreatorCap`); - const relayerDiscovery = publishTxn.objectChanges.find((change) => change.objectType === `${packageId}::discovery::RelayerDiscovery`); - - const encodedSigners = signersStruct - .serialize({ - ...signers, - nonce: bytes32Struct.serialize(signers.nonce).toBytes(), - }) - .toBytes(); - - const tx = new Transaction(); - - const separator = tx.moveCall({ - target: `${packageId}::bytes32::new`, - arguments: [tx.pure(arrayify(domainSeparator))], - }); - - tx.moveCall({ - target: `${packageId}::gateway::setup`, - arguments: [ - tx.object(creatorCap.objectId), - tx.pure.address(operator), - separator, - tx.pure.u64(minimumRotationDelay), - tx.pure.u64(previousSignerRetention), - tx.pure(bcs.vector(bcs.u8()).serialize(encodedSigners).toBytes()), - tx.object('0x6'), - ], - }); - const result = await broadcast(client, keypair, tx); - - const gateway = result.objectChanges.find((change) => change.objectType === `${packageId}::gateway::Gateway`); - - contractConfig.address = packageId; - contractConfig.objects = { - gateway: gateway.objectId, - relayerDiscovery: relayerDiscovery.objectId, - }; - contractConfig.domainSeparator = domainSeparator; - contractConfig.operator = operator; - contractConfig.minimumRotationDelay = minimumRotationDelay; - contractConfig.previousSignerRetention = previousSignerRetention; - - printInfo('Gateway deployed', JSON.stringify(contractConfig, null, 2)); -} - -async function mainProcessor(options, processor) { - const config = loadSuiConfig(options.env); - - await processor(config, config.sui, options); - saveConfig(config, options.env); -} - -if (require.main === module) { - const program = new Command(); - - program.name('deploy-gateway').description('Deploys/publishes the Sui gateway'); - - addBaseOptions(program); - - program.addOption(new Option('--signers <signers>', 'JSON with the initial signer set').env('SIGNERS')); - program.addOption(new Option('--operator <operator>', 'operator for the gateway (defaults to the deployer address)').env('OPERATOR')); - program.addOption(new Option('--minimumRotationDelay <minimumRotationDelay>', 'minium delay for signer rotations (in ms)').default(0)); - program.addOption( - new Option('--previousSignerRetention <previousSignerRetention>', 'number of previous signers to retain in the gateway').default( - 15, - ), - ); - program.addOption(new Option('--domainSeparator <domainSeparator>', 'domain separator').default(HashZero)); - program.addOption(new Option('--nonce <nonce>', 'nonce for the signer (defaults to HashZero)')); - - program.action((options) => { - mainProcessor(options, processCommand); - }); - - program.parse(); -} - -module.exports = { - getSigners, -}; diff --git a/sui/deploy-utils.js b/sui/deploy-utils.js index dcd31db8..fc46e5ff 100644 --- a/sui/deploy-utils.js +++ b/sui/deploy-utils.js @@ -1,40 +1,42 @@ const { Command, Option } = require('commander'); const { TxBuilder, updateMoveToml } = require('@axelar-network/axelar-cgp-sui'); -const { bcs } = require('@mysten/sui/bcs'); +const { bcs } = require('@mysten/bcs'); const { fromB64, toB64 } = require('@mysten/bcs'); const { saveConfig, printInfo, validateParameters, prompt, writeJSON } = require('../evm/utils'); const { addBaseOptions } = require('./cli-utils'); const { getWallet } = require('./sign-utils'); -const { loadSuiConfig } = require('./utils'); +const { loadSuiConfig, getObjectIdsByObjectTypes, suiPackageAddress } = require('./utils'); async function upgradePackage(client, keypair, packageName, packageConfig, builder, options) { const { modules, dependencies, digest } = await builder.getContractBuild(packageName); const { policy, offline } = options; const sender = options.sender || keypair.toSuiAddress(); - const suiPackageId = '0x2'; - const upgradeCap = packageConfig.objects?.UpgradeCap; + if (!['any_upgrade', 'code_upgrade', 'dep_upgrade'].includes(policy)) { + throw new Error(`Unknown upgrade policy: ${policy}. Supported policies: any_upgrade, code_upgrade, dep_upgrade`); + } + + const upgradeCap = packageConfig.objects?.upgradeCap; const digestHash = options.digest ? fromB64(options.digest) : digest; validateParameters({ isNonEmptyString: { upgradeCap, policy }, isNonEmptyStringArray: { modules, dependencies } }); const tx = builder.tx; const cap = tx.object(upgradeCap); - const ticket = tx.moveCall({ - target: `${suiPackageId}::package::authorize_upgrade`, - arguments: [cap, tx.pure(policy), tx.pure(bcs.vector(bcs.u8()).serialize(digestHash).toBytes())], + target: `${suiPackageAddress}::package::authorize_upgrade`, + arguments: [cap, tx.pure.u8(policy), tx.pure(bcs.vector(bcs.u8()).serialize(digestHash).toBytes())], }); const receipt = tx.upgrade({ modules, dependencies, - packageId: packageConfig.address, + package: packageConfig.address, ticket, }); tx.moveCall({ - target: `${suiPackageId}::package::commit_upgrade`, + target: `${suiPackageAddress}::package::commit_upgrade`, arguments: [cap, receipt], }); @@ -43,6 +45,7 @@ async function upgradePackage(client, keypair, packageName, packageConfig, build if (offline) { options.txBytes = txBytes; + options.offlineMessage = `Transaction to upgrade ${packageName}`; } else { const signature = (await keypair.signTransaction(txBytes)).signature; const result = await client.executeTransactionBlock({ @@ -57,7 +60,10 @@ async function upgradePackage(client, keypair, packageName, packageConfig, build const packageId = (result.objectChanges?.filter((a) => a.type === 'published') ?? [])[0].packageId; packageConfig.address = packageId; - printInfo('Transaction result', JSON.stringify(result, null, 2)); + const [upgradeCap] = getObjectIdsByObjectTypes(result, ['0x2::package::UpgradeCap']); + packageConfig.objects.upgradeCap = upgradeCap; + + printInfo('Transaction digest', JSON.stringify(result.digest, null, 2)); printInfo(`${packageName} upgraded`, packageId); } } @@ -175,3 +181,8 @@ if (require.main === module) { program.parse(); } + +module.exports = { + upgradePackage, + deployPackage, +}; diff --git a/sui/multisig.js b/sui/multisig.js index d7ac4098..403bae2b 100644 --- a/sui/multisig.js +++ b/sui/multisig.js @@ -8,14 +8,19 @@ const { printInfo, validateParameters } = require('../evm/utils'); async function signTx(keypair, client, options) { const txFileData = getSignedTx(options.txBlockPath); - const txData = txFileData?.bytes; + const txData = txFileData?.unsignedTx; validateParameters({ isNonEmptyString: { txData } }); const encodedTxBytes = fromB64(txData); - const { signature, publicKey } = await signTransactionBlockBytes(keypair, client, encodedTxBytes, options); - return { signature, publicKey, txBytes: txData }; + if (options.offline) { + const { signature, publicKey } = await signTransactionBlockBytes(keypair, client, encodedTxBytes, options); + return { ...txFileData, signedTx: signature, publicKey }; + } + + await signTransactionBlockBytes(keypair, client, encodedTxBytes, options); + return {}; } async function executeCombinedSignature(client, options) { @@ -30,12 +35,12 @@ async function executeCombinedSignature(client, options) { } const fileData = getSignedTx(combinedSignPath); - const txData = fileData.txBytes; + const txData = fileData.unsignedTx; validateParameters({ isNonEmptyString: { txData } }); const encodedTxBytes = fromB64(txData); - const combinedSignatureBytes = fileData.signature; + const combinedSignatureBytes = fileData.signedTx; if (!combinedSignatureBytes) { throw new Error(`No signature specified in [${combinedSignPath}]`); @@ -59,16 +64,16 @@ async function combineSignature(client, chain, options) { const signatureArray = []; const firstSignData = getSignedTx(signatures[0]); - const txBytes = firstSignData.txBytes; + const txBytes = firstSignData.unsignedTx; for (const file of signatures) { const fileData = getSignedTx(file); - if (fileData.txBytes !== txBytes) { + if (fileData.unsignedTx !== txBytes) { throw new Error(`Transaction bytes mismatch with file [${file}]`); } - signatureArray.push(fileData.signature); + signatureArray.push(fileData.signedTx); } const txBlockBytes = fromB64(txBytes); @@ -85,9 +90,10 @@ async function combineSignature(client, chain, options) { printInfo('Transaction result', JSON.stringify(txResult)); } else { const data = { - signature: combinedSignature, + message: firstSignData.message, + signedTx: combinedSignature, status: 'PENDING', - txBytes, + unsignedTx: txBytes, }; return data; } @@ -121,14 +127,18 @@ async function processCommand(chain, options) { } if (options.offline) { - const { signatureFilePath } = options; + let { signatureFilePath } = options; + + if (options.action === 'combine') { + signatureFilePath = options.txBlockPath; + } if (!signatureFilePath) { throw new Error('No filePath provided'); } storeSignedTx(signatureFilePath, fileData); - printInfo(`The signed signature is`, fileData.signature); + printInfo(`The signed signature is`, fileData.signedTx); } } diff --git a/sui/sign-utils.js b/sui/sign-utils.js index 5cf91fba..1dfeb2b5 100644 --- a/sui/sign-utils.js +++ b/sui/sign-utils.js @@ -1,6 +1,6 @@ 'use strict'; -const { verifyTransaction } = require('@mysten/sui/verify'); +const { verifyTransactionSignature } = require('@mysten/sui/verify'); const { decodeSuiPrivateKey } = require('@mysten/sui/cryptography'); const { Ed25519Keypair, Ed25519PublicKey } = require('@mysten/sui/keypairs/ed25519'); const { MultiSigPublicKey } = require('@mysten/sui/multisig'); @@ -124,7 +124,7 @@ async function signTransactionBlockBytes(keypair, client, txBytes, options) { let publicKey; try { - publicKey = await verifyTransaction(txBytes, serializedSignature); + publicKey = await verifyTransactionSignature(txBytes, serializedSignature); } catch { throw new Error(`Cannot verify tx signature`); } diff --git a/sui/utils.js b/sui/utils.js index e46aedcb..f42f833e 100644 --- a/sui/utils.js +++ b/sui/utils.js @@ -10,6 +10,9 @@ const { fromB64 } = require('@mysten/bcs'); const { CosmWasmClient } = require('@cosmjs/cosmwasm-stargate'); const { updateMoveToml, copyMovePackage, TxBuilder } = require('@axelar-network/axelar-cgp-sui'); +const suiPackageAddress = '0x2'; +const suiClockAddress = '0x6'; + const getAmplifierSigners = async (config, chain) => { const client = await CosmWasmClient.connect(config.axelar.rpc); const { id: verifierSetId, verifier_set: verifierSet } = await client.queryContractSmart( @@ -77,15 +80,21 @@ const deployPackage = async (packageName, client, keypair, options = {}) => { return { packageId, publishTxn }; }; -const findPublishedObject = (published, packageName, contractName) => { - const packageId = published.packageId; - return published.publishTxn.objectChanges.find((change) => change.objectType === `${packageId}::${packageName}::${contractName}`); -}; +const getObjectIdsByObjectTypes = (txn, objectTypes) => + objectTypes.map((objectType) => { + const objectId = txn.objectChanges.find((change) => change.objectType === objectType)?.objectId; + + if (!objectId) { + throw new Error(`No object found for type: ${objectType}`); + } + }); module.exports = { + suiPackageAddress, + suiClockAddress, getAmplifierSigners, getBcsBytesByObjectId, loadSuiConfig, deployPackage, - findPublishedObject, + getObjectIdsByObjectTypes, }; From c19b30e0ba780c117b0351cde0c7d0ced7f9a6fb Mon Sep 17 00:00:00 2001 From: eguajardo <edwin@axelar.network> Date: Mon, 29 Jul 2024 15:26:57 -0600 Subject: [PATCH 38/44] feat(amplifier): add support for fetchCodeId option to non-governance scripts (#316) Co-authored-by: Talal Ashraf <talal@interoplabs.io> --- cosmwasm/deploy-contract.js | 15 ++++++++++----- cosmwasm/submit-proposal.js | 26 ++------------------------ cosmwasm/utils.js | 24 ++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 29 deletions(-) diff --git a/cosmwasm/deploy-contract.js b/cosmwasm/deploy-contract.js index 16015bdc..92a19e79 100644 --- a/cosmwasm/deploy-contract.js +++ b/cosmwasm/deploy-contract.js @@ -8,6 +8,7 @@ const { prepareWallet, prepareClient, getChains, + fetchCodeIdFromCodeHash, uploadContract, instantiateContract, makeInstantiateMsg, @@ -17,7 +18,7 @@ const { const { Command, Option } = require('commander'); const upload = (client, wallet, chainName, config, options) => { - const { reuseCodeId, contractName } = options; + const { reuseCodeId, contractName, fetchCodeId } = options; const { axelar: { contracts: { [contractName]: contractConfig }, @@ -25,7 +26,7 @@ const upload = (client, wallet, chainName, config, options) => { chains: { [chainName]: chainConfig }, } = config; - if (!reuseCodeId || isNil(contractConfig.codeId)) { + if (!fetchCodeId && (!reuseCodeId || isNil(contractConfig.codeId))) { printInfo('Uploading contract binary'); return uploadContract(client, wallet, config, options) @@ -55,8 +56,8 @@ const upload = (client, wallet, chainName, config, options) => { return Promise.resolve({ wallet, client }); }; -const instantiate = (client, wallet, chainName, config, options) => { - const { contractName } = options; +const instantiate = async (client, wallet, chainName, config, options) => { + const { contractName, fetchCodeId } = options; const { axelar: { contracts: { [contractName]: contractConfig }, @@ -64,7 +65,9 @@ const instantiate = (client, wallet, chainName, config, options) => { chains: { [chainName]: chainConfig }, } = config; - if (!isNumber(contractConfig.codeId)) { + if (fetchCodeId) { + contractConfig.codeId = await fetchCodeIdFromCodeHash(client, contractConfig); + } else if (!isNumber(contractConfig.codeId)) { throw new Error('Code Id is not defined'); } @@ -137,6 +140,8 @@ const programHandler = () => { program.addOption(new Option('--aarch64', 'aarch64').env('AARCH64').default(false)); program.addOption(new Option('-y, --yes', 'skip deployment prompt confirmation').env('YES')); + program.addOption(new Option('--fetchCodeId', 'fetch code id from the chain by comparing to the uploaded code hash')); + program.action((options) => { main(options); }); diff --git a/cosmwasm/submit-proposal.js b/cosmwasm/submit-proposal.js index 43365668..e6a42b7b 100644 --- a/cosmwasm/submit-proposal.js +++ b/cosmwasm/submit-proposal.js @@ -9,6 +9,7 @@ const { prepareClient, readWasmFile, getChains, + fetchCodeIdFromCodeHash, decodeProposalAttributes, encodeStoreCodeProposal, encodeStoreInstantiateProposal, @@ -111,29 +112,6 @@ const storeInstantiate = (client, wallet, config, options, chainName) => { }); }; -const fetchAndUpdateCodeId = async (client, contractConfig) => { - if (!contractConfig.storeCodeProposalCodeHash) { - throw new Error('storeCodeProposalCodeHash not found in contract config'); - } - - const codes = await client.getCodes(); // TODO: create custom function to retrieve codes more efficiently and with pagination - let codeId; - - // most likely to be near the end, so we iterate backwards. We also get the latest if there are multiple - for (let i = codes.length - 1; i >= 0; i--) { - if (codes[i].checksum.toUpperCase() === contractConfig.storeCodeProposalCodeHash.toUpperCase()) { - codeId = codes[i].id; - break; - } - } - - if (!codeId) { - throw new Error('codeId not found on network for the given codeHash'); - } - - contractConfig.codeId = codeId; -}; - const instantiate = async (client, wallet, config, options, chainName) => { const { contractName, instantiate2, predictOnly, fetchCodeId } = options; const { @@ -148,7 +126,7 @@ const instantiate = async (client, wallet, config, options, chainName) => { } if (fetchCodeId) { - await fetchAndUpdateCodeId(client, contractConfig); + contractConfig.codeId = await fetchCodeIdFromCodeHash(client, contractConfig); } else if (!isNumber(contractConfig.codeId)) { throw new Error('Code Id is not defined'); } diff --git a/cosmwasm/utils.js b/cosmwasm/utils.js index f35c7553..59ebcf32 100644 --- a/cosmwasm/utils.js +++ b/cosmwasm/utils.js @@ -486,6 +486,29 @@ const makeInstantiateMsg = (contractName, chainName, config) => { throw new Error(`${contractName} is not supported.`); }; +const fetchCodeIdFromCodeHash = async (client, contractConfig) => { + if (!contractConfig.storeCodeProposalCodeHash) { + throw new Error('storeCodeProposalCodeHash not found in contract config'); + } + + const codes = await client.getCodes(); // TODO: create custom function to retrieve codes more efficiently and with pagination + let codeId; + + // most likely to be near the end, so we iterate backwards. We also get the latest if there are multiple + for (let i = codes.length - 1; i >= 0; i--) { + if (codes[i].checksum.toUpperCase() === contractConfig.storeCodeProposalCodeHash.toUpperCase()) { + codeId = codes[i].id; + break; + } + } + + if (!codeId) { + throw new Error('codeId not found on network for the given codeHash'); + } + + return codeId; +}; + const instantiate2AddressForProposal = (client, contractConfig, { contractName, salt, chainNames, runAs }) => { return client .getCodeDetails(contractConfig.codeId) @@ -682,6 +705,7 @@ module.exports = { uploadContract, instantiateContract, makeInstantiateMsg, + fetchCodeIdFromCodeHash, instantiate2AddressForProposal, decodeProposalAttributes, encodeStoreCodeProposal, From 03bf47839462a92381684279c2edea852dca2183 Mon Sep 17 00:00:00 2001 From: jcs47 <11947034+jcs47@users.noreply.github.com> Date: Tue, 30 Jul 2024 02:28:15 +0100 Subject: [PATCH 39/44] chore(amplifier): add `address_format` to instantiation message for voting verifier contract (#324) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: João Sousa <joaosousa@Joaos-MBP.home> --- cosmwasm/utils.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/cosmwasm/utils.js b/cosmwasm/utils.js index 59ebcf32..884e82fd 100644 --- a/cosmwasm/utils.js +++ b/cosmwasm/utils.js @@ -213,7 +213,16 @@ const makeVotingVerifierInstantiateMsg = ( { id: chainId }, ) => { const { - [chainId]: { governanceAddress, serviceName, sourceGatewayAddress, votingThreshold, blockExpiry, confirmationHeight, msgIdFormat }, + [chainId]: { + governanceAddress, + serviceName, + sourceGatewayAddress, + votingThreshold, + blockExpiry, + confirmationHeight, + msgIdFormat, + addressFormat, + }, } = contractConfig; if (!validateAddress(serviceRegistryAddress)) { @@ -252,6 +261,10 @@ const makeVotingVerifierInstantiateMsg = ( throw new Error(`Missing or invalid VotingVerifier[${chainId}].msgIdFormat in axelar info`); } + if (!isString(addressFormat)) { + throw new Error(`Missing or invalid VotingVerifier[${chainId}].addressFormat in axelar info`); + } + return { service_registry_address: serviceRegistryAddress, rewards_address: rewardsAddress, @@ -263,6 +276,7 @@ const makeVotingVerifierInstantiateMsg = ( confirmation_height: confirmationHeight, source_chain: chainId, msg_id_format: msgIdFormat, + address_format: addressFormat, }; }; From 71c829b87d59210bd2f054e6b56516a2528f9293 Mon Sep 17 00:00:00 2001 From: npty <78221556+npty@users.noreply.github.com> Date: Tue, 30 Jul 2024 20:37:58 +0700 Subject: [PATCH 40/44] chore(sui): use common utils instead of evm utils (#325) --- common/utils.js | 51 +++++++++++++++++++++++++++++++++++++++++ sui/deploy-test.js | 2 +- sui/deploy-utils.js | 2 +- sui/faucet.js | 2 +- sui/gas-service.js | 2 +- sui/gateway.js | 2 +- sui/generate-keypair.js | 2 +- sui/gmp.js | 2 +- sui/multisig.js | 2 +- sui/sign-utils.js | 2 +- sui/transfer-object.js | 2 +- sui/utils.js | 4 +++- 12 files changed, 64 insertions(+), 11 deletions(-) diff --git a/common/utils.js b/common/utils.js index 2c2a85c2..c5eb3231 100644 --- a/common/utils.js +++ b/common/utils.js @@ -198,6 +198,24 @@ function timeout(prom, time, exception) { ); } +/** + * Determines if a given input is a valid keccak256 hash. + * + * @param {string} input - The string to validate. + * @returns {boolean} - Returns true if the input is a valid keccak256 hash, false otherwise. + */ +function isKeccak256Hash(input) { + // Ensure it's a string of 66 characters length and starts with '0x' + if (typeof input !== 'string' || input.length !== 66 || input.slice(0, 2) !== '0x') { + return false; + } + + // Ensure all characters after the '0x' prefix are hexadecimal (0-9, a-f, A-F) + const hexPattern = /^[a-fA-F0-9]{64}$/; + + return hexPattern.test(input.slice(2)); +} + /** * Validate if the input string matches the time format YYYY-MM-DDTHH:mm:ss * @@ -214,6 +232,37 @@ function isValidTimeFormat(timeString) { return regex.test(timeString); } +const validationFunctions = { + isNonEmptyString, + isNumber, + isValidNumber, + isValidDecimal, + isNumberArray, + isKeccak256Hash, + isString, + isNonEmptyStringArray, + isValidTimeFormat, +}; + +function validateParameters(parameters) { + for (const [validatorFunctionString, paramsObj] of Object.entries(parameters)) { + const validatorFunction = validationFunctions[validatorFunctionString]; + + if (typeof validatorFunction !== 'function') { + throw new Error(`Validator function ${validatorFunction} is not defined`); + } + + for (const paramKey of Object.keys(paramsObj)) { + const paramValue = paramsObj[paramKey]; + const isValid = validatorFunction(paramValue); + + if (!isValid) { + throw new Error(`Input validation failed for ${validatorFunctionString} with parameter ${paramKey}: ${paramValue}`); + } + } + } +} + const dateToEta = (utcTimeString) => { if (utcTimeString === '0') { return 0; @@ -290,6 +339,7 @@ module.exports = { printWarn, printError, printLog, + isKeccak256Hash, isNonEmptyString, isString, isStringArray, @@ -311,4 +361,5 @@ module.exports = { findProjectRoot, toBigNumberString, timeout, + validateParameters, }; diff --git a/sui/deploy-test.js b/sui/deploy-test.js index 3f8feb51..8b0db9e9 100644 --- a/sui/deploy-test.js +++ b/sui/deploy-test.js @@ -1,4 +1,4 @@ -const { saveConfig, prompt, printInfo } = require('../evm/utils'); +const { saveConfig, prompt, printInfo } = require('../common/utils'); const { Command } = require('commander'); const { loadSuiConfig, deployPackage, getBcsBytesByObjectId } = require('./utils'); const { singletonStruct } = require('./types-utils'); diff --git a/sui/deploy-utils.js b/sui/deploy-utils.js index fc46e5ff..3c594116 100644 --- a/sui/deploy-utils.js +++ b/sui/deploy-utils.js @@ -2,7 +2,7 @@ const { Command, Option } = require('commander'); const { TxBuilder, updateMoveToml } = require('@axelar-network/axelar-cgp-sui'); const { bcs } = require('@mysten/bcs'); const { fromB64, toB64 } = require('@mysten/bcs'); -const { saveConfig, printInfo, validateParameters, prompt, writeJSON } = require('../evm/utils'); +const { saveConfig, printInfo, validateParameters, prompt, writeJSON } = require('../common/utils'); const { addBaseOptions } = require('./cli-utils'); const { getWallet } = require('./sign-utils'); const { loadSuiConfig, getObjectIdsByObjectTypes, suiPackageAddress } = require('./utils'); diff --git a/sui/faucet.js b/sui/faucet.js index 47fbc171..0bdb52b5 100644 --- a/sui/faucet.js +++ b/sui/faucet.js @@ -4,7 +4,7 @@ const { addBaseOptions } = require('./cli-utils'); const { requestSuiFromFaucetV0, getFaucetHost } = require('@mysten/sui/faucet'); const { getWallet, printWalletInfo } = require('./sign-utils'); const { Command } = require('commander'); -const { saveConfig, loadConfig, printInfo } = require('../evm/utils'); +const { saveConfig, loadConfig, printInfo } = require('../common/utils'); async function processCommand(config, chain, options) { const [keypair, client] = getWallet(chain, options); diff --git a/sui/gas-service.js b/sui/gas-service.js index a3dc5a13..1a6ba290 100644 --- a/sui/gas-service.js +++ b/sui/gas-service.js @@ -1,4 +1,4 @@ -const { saveConfig, printInfo, printError } = require('../evm/utils'); +const { saveConfig, printInfo, printError } = require('../common/utils'); const { Command } = require('commander'); const { Transaction } = require('@mysten/sui/transactions'); const { bcs } = require('@mysten/sui/bcs'); diff --git a/sui/gateway.js b/sui/gateway.js index d49fa04d..a26ef9ec 100644 --- a/sui/gateway.js +++ b/sui/gateway.js @@ -1,4 +1,4 @@ -const { saveConfig, printInfo } = require('../evm/utils'); +const { saveConfig, printInfo } = require('../common/utils'); const { Command, Option } = require('commander'); const { Transaction } = require('@mysten/sui/transactions'); const { bcs } = require('@mysten/sui/bcs'); diff --git a/sui/generate-keypair.js b/sui/generate-keypair.js index 8d091570..e9a76322 100644 --- a/sui/generate-keypair.js +++ b/sui/generate-keypair.js @@ -3,7 +3,7 @@ const { addBaseOptions } = require('./cli-utils'); const { generateKeypair, getRawPrivateKey } = require('./sign-utils'); const { Command, Option } = require('commander'); -const { saveConfig, loadConfig, printInfo } = require('../evm/utils'); +const { saveConfig, loadConfig, printInfo } = require('../common/utils'); const { ethers } = require('hardhat'); const { hexlify } = ethers.utils; diff --git a/sui/gmp.js b/sui/gmp.js index 87730567..a1bf4a96 100644 --- a/sui/gmp.js +++ b/sui/gmp.js @@ -1,4 +1,4 @@ -const { saveConfig, printInfo } = require('../evm/utils'); +const { saveConfig, printInfo } = require('../common/utils'); const { Command } = require('commander'); const { Transaction } = require('@mysten/sui/transactions'); const { bcs } = require('@mysten/sui/bcs'); diff --git a/sui/multisig.js b/sui/multisig.js index 403bae2b..9d69414d 100644 --- a/sui/multisig.js +++ b/sui/multisig.js @@ -4,7 +4,7 @@ const { addBaseOptions } = require('./cli-utils'); const { getWallet, getMultisig, signTransactionBlockBytes, broadcastSignature } = require('./sign-utils'); const { getSignedTx, storeSignedTx } = require('../evm/sign-utils'); const { loadSuiConfig } = require('./utils'); -const { printInfo, validateParameters } = require('../evm/utils'); +const { printInfo, validateParameters } = require('../common/utils'); async function signTx(keypair, client, options) { const txFileData = getSignedTx(options.txBlockPath); diff --git a/sui/sign-utils.js b/sui/sign-utils.js index 1dfeb2b5..c8aeee4c 100644 --- a/sui/sign-utils.js +++ b/sui/sign-utils.js @@ -8,7 +8,7 @@ const { Secp256k1Keypair, Secp256k1PublicKey } = require('@mysten/sui/keypairs/s const { Secp256r1Keypair, Secp256r1PublicKey } = require('@mysten/sui/keypairs/secp256r1'); const { SuiClient, getFullnodeUrl } = require('@mysten/sui/client'); const { fromB64, fromHEX } = require('@mysten/bcs'); -const { printInfo } = require('../evm/utils'); +const { printInfo } = require('../common/utils'); const { ethers } = require('hardhat'); const { utils: { hexlify }, diff --git a/sui/transfer-object.js b/sui/transfer-object.js index abb27c42..1d58ee6f 100644 --- a/sui/transfer-object.js +++ b/sui/transfer-object.js @@ -1,6 +1,6 @@ const { Transaction } = require('@mysten/sui/transactions'); const { Command, Option } = require('commander'); -const { printInfo, validateParameters } = require('../evm/utils'); +const { printInfo, validateParameters } = require('../common/utils'); const { addExtendedOptions } = require('./cli-utils'); const { getWallet, printWalletInfo } = require('./sign-utils'); const { loadSuiConfig } = require('./utils'); diff --git a/sui/utils.js b/sui/utils.js index f42f833e..e019d1fe 100644 --- a/sui/utils.js +++ b/sui/utils.js @@ -1,7 +1,7 @@ 'use strict'; const { ethers } = require('hardhat'); -const { loadConfig } = require('../evm/utils'); +const { loadConfig } = require('../common/utils'); const { BigNumber, utils: { arrayify, hexlify }, @@ -87,6 +87,8 @@ const getObjectIdsByObjectTypes = (txn, objectTypes) => if (!objectId) { throw new Error(`No object found for type: ${objectType}`); } + + return objectId; }); module.exports = { From 35df60a804127e3864cfb7cd552b3a84f8a451b3 Mon Sep 17 00:00:00 2001 From: Milap Sheth <milap@interoplabs.io> Date: Tue, 30 Jul 2024 20:34:55 -0400 Subject: [PATCH 41/44] fix(cosmwasm): persist code id when predicting contract address (#326) --- cosmwasm/submit-proposal.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cosmwasm/submit-proposal.js b/cosmwasm/submit-proposal.js index e6a42b7b..ccbd21ac 100644 --- a/cosmwasm/submit-proposal.js +++ b/cosmwasm/submit-proposal.js @@ -121,16 +121,16 @@ const instantiate = async (client, wallet, config, options, chainName) => { chains: { [chainName]: chainConfig }, } = config; - if (predictOnly) { - return predictAndUpdateAddress(client, contractConfig, chainConfig, options, contractName, chainName); - } - if (fetchCodeId) { contractConfig.codeId = await fetchCodeIdFromCodeHash(client, contractConfig); } else if (!isNumber(contractConfig.codeId)) { throw new Error('Code Id is not defined'); } + if (predictOnly) { + return predictAndUpdateAddress(client, contractConfig, chainConfig, options, contractName, chainName); + } + const initMsg = makeInstantiateMsg(contractName, chainName, config); let proposal; From cd3c91301a50c391ea339f16b73cd8155bafef2d Mon Sep 17 00:00:00 2001 From: npty <78221556+npty@users.noreply.github.com> Date: Thu, 1 Aug 2024 11:36:33 +0700 Subject: [PATCH 42/44] feat(sui): support all contract deployment in deploy-contract script (#323) --- common/utils.js | 81 +++++- evm/deploy-amplifier-gateway.js | 44 +--- package-lock.json | 3 +- package.json | 3 +- sui/README.md | 18 +- sui/deploy-contract.js | 442 ++++++++++++++++++++------------ sui/deploy-test.js | 6 +- sui/deploy-utils.js | 172 +++---------- sui/gas-service.js | 5 +- sui/gateway.js | 4 +- sui/gmp.js | 9 +- sui/multisig.js | 4 +- sui/transfer-object.js | 4 +- sui/utils.js | 85 ++++-- 14 files changed, 496 insertions(+), 384 deletions(-) diff --git a/common/utils.js b/common/utils.js index c5eb3231..e6819154 100644 --- a/common/utils.js +++ b/common/utils.js @@ -7,9 +7,27 @@ const chalk = require('chalk'); const https = require('https'); const http = require('http'); const readlineSync = require('readline-sync'); +const { CosmWasmClient } = require('@cosmjs/cosmwasm-stargate'); +const { ethers } = require('hardhat'); +const { + utils: { keccak256, hexlify }, +} = ethers; +const { normalizeBech32 } = require('@cosmjs/encoding'); function loadConfig(env) { - return require(`${__dirname}/../axelar-chains-config/info/${env}.json`); + const config = require(`${__dirname}/../axelar-chains-config/info/${env}.json`); + + if (!config.sui) { + config.sui = { + networkType: env === 'local' ? 'localnet' : env, + name: 'Sui', + contracts: { + AxelarGateway: {}, + }, + }; + } + + return config; } function saveConfig(config, env) { @@ -331,6 +349,66 @@ function toBigNumberString(number) { return Math.ceil(number).toLocaleString('en', { useGrouping: false }); } +const isValidCosmosAddress = (str) => { + try { + normalizeBech32(str); + + return true; + } catch (error) { + return false; + } +}; + +async function getDomainSeparator(config, chain, options) { + // Allow any domain separator for local deployments or `0x` if not provided + if (options.env === 'local') { + return options.domainSeparator || ethers.constants.HashZero; + } + + if (isKeccak256Hash(options.domainSeparator)) { + // return the domainSeparator for debug deployments + return options.domainSeparator; + } + + const { + axelar: { contracts, chainId }, + } = config; + const { + Router: { address: routerAddress }, + } = contracts; + + if (!isString(chain.axelarId)) { + throw new Error(`missing or invalid axelar ID for chain ${chain.name}`); + } + + if (!isString(routerAddress) || !isValidCosmosAddress(routerAddress)) { + throw new Error(`missing or invalid router address`); + } + + if (!isString(chainId)) { + throw new Error(`missing or invalid chain ID`); + } + + printInfo(`Retrieving domain separator for ${chain.name} from Axelar network`); + const domainSeparator = hexlify((await getContractConfig(config, chain.axelarId)).domain_separator); + const expectedDomainSeparator = calculateDomainSeparator(chain.axelarId, routerAddress, chainId); + + if (domainSeparator !== expectedDomainSeparator) { + throw new Error(`unexpected domain separator (want ${expectedDomainSeparator}, got ${domainSeparator})`); + } + + return domainSeparator; +} + +const getContractConfig = async (config, chain) => { + const key = Buffer.from('config'); + const client = await CosmWasmClient.connect(config.axelar.rpc); + const value = await client.queryContractRaw(config.axelar.contracts.MultisigProver[chain].address, key); + return JSON.parse(Buffer.from(value).toString('ascii')); +}; + +const calculateDomainSeparator = (chain, router, network) => keccak256(Buffer.from(`${chain}${router}${network}`)); + module.exports = { loadConfig, saveConfig, @@ -362,4 +440,5 @@ module.exports = { toBigNumberString, timeout, validateParameters, + getDomainSeparator, }; diff --git a/evm/deploy-amplifier-gateway.js b/evm/deploy-amplifier-gateway.js index a0b0bb10..419dbfff 100644 --- a/evm/deploy-amplifier-gateway.js +++ b/evm/deploy-amplifier-gateway.js @@ -7,7 +7,7 @@ const { ContractFactory, Contract, Wallet, - utils: { defaultAbiCoder, keccak256, hexlify }, + utils: { defaultAbiCoder, keccak256 }, getDefaultProvider, } = ethers; @@ -22,15 +22,12 @@ const { mainProcessor, deployContract, getGasOptions, - isKeccak256Hash, - getContractConfig, - isString, getWeightedSigners, getContractJSON, getDeployedAddress, getDeployOptions, + getDomainSeparator, } = require('./utils'); -const { calculateDomainSeparator, isValidCosmosAddress } = require('../cosmwasm/utils'); const { addExtendedOptions } = require('./cli-utils'); const { storeSignedTx, signTransaction, getWallet } = require('./sign-utils.js'); @@ -38,43 +35,6 @@ const { WEIGHTED_SIGNERS_TYPE, encodeWeightedSigners } = require('@axelar-networ const AxelarAmplifierGatewayProxy = require('@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/gateway/AxelarAmplifierGatewayProxy.sol/AxelarAmplifierGatewayProxy.json'); const AxelarAmplifierGateway = require('@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/gateway/AxelarAmplifierGateway.sol/AxelarAmplifierGateway.json'); -async function getDomainSeparator(config, chain, options) { - printInfo(`Retrieving domain separator for ${chain.name} from Axelar network`); - - if (isKeccak256Hash(options.domainSeparator)) { - // return the domainSeparator for debug deployments - return options.domainSeparator; - } - - const { - axelar: { contracts, chainId }, - } = config; - const { - Router: { address: routerAddress }, - } = contracts; - - if (!isString(chain.axelarId)) { - throw new Error(`missing or invalid axelar ID for chain ${chain.name}`); - } - - if (!isString(routerAddress) || !isValidCosmosAddress(routerAddress)) { - throw new Error(`missing or invalid router address`); - } - - if (!isString(chainId)) { - throw new Error(`missing or invalid chain ID`); - } - - const domainSeparator = hexlify((await getContractConfig(config, chain.axelarId)).domain_separator); - const expectedDomainSeparator = calculateDomainSeparator(chain.axelarId, routerAddress, chainId); - - if (domainSeparator !== expectedDomainSeparator) { - throw new Error(`unexpected domain separator (want ${expectedDomainSeparator}, got ${domainSeparator})`); - } - - return domainSeparator; -} - async function getSetupParams(config, chain, operator, options) { const { signers: signerSets, verifierSetId } = await getWeightedSigners(config, chain, options); printInfo('Setup params', JSON.stringify([operator, signerSets], null, 2)); diff --git a/package-lock.json b/package-lock.json index 55b67d22..296d788b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,8 @@ "@mysten/sui": "^1.3.0", "@stellar/stellar-sdk": "^12.0.0-rc3", "axios": "^1.6.2", - "path": "^0.12.7" + "path": "^0.12.7", + "toml": "^3.0.0" }, "devDependencies": { "@ledgerhq/hw-transport-node-hid": "^6.27.21", diff --git a/package.json b/package.json index 01379e8c..bcdb007e 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,8 @@ "@mysten/sui": "^1.3.0", "@stellar/stellar-sdk": "^12.0.0-rc3", "axios": "^1.6.2", - "path": "^0.12.7" + "path": "^0.12.7", + "toml": "^3.0.0" }, "devDependencies": { "@ledgerhq/hw-transport-node-hid": "^6.27.21", diff --git a/sui/README.md b/sui/README.md index 0ea2275c..2cc6c789 100644 --- a/sui/README.md +++ b/sui/README.md @@ -54,7 +54,7 @@ Deploy the gateway package: - By querying the signer set from the Amplifier contract (this only works if Amplifier contracts have been setup): ```bash -node sui/deploy-contract.js deploy axelar_gateway +node sui/deploy-contract.js deploy AxelarGateway ``` Note: the `minimumRotationDelay` is in `seconds` unit. The default value is `24 * 60 * 60` (1 day). @@ -64,13 +64,13 @@ Use `--help` flag to see other setup params that can be overridden. - For testing convenience, you can use the secp256k1 wallet as the signer set for the gateway. ```bash -node sui/deploy-contract.js deploy axelar_gateway --signers wallet --nonce test +node sui/deploy-contract.js deploy AxelarGateway --signers wallet --nonce test ``` - You can also provide a JSON object with a full signer set: ```bash -node sui/deploy-contract.js deploy axelar_gateway -e testnet --signers '{"signers": [{"pub_key": "0x020194ead85b350d90472117e6122cf1764d93bf17d6de4b51b03d19afc4d6302b", "weight": 1}], "threshold": 1, "nonce": "0x0000000000000000000000000000000000000000000000000000000000000000"}' +node sui/deploy-contract.js deploy AxelarGateway -e testnet --signers '{"signers": [{"pub_key": "0x020194ead85b350d90472117e6122cf1764d93bf17d6de4b51b03d19afc4d6302b", "weight": 1}], "threshold": 1, "nonce": "0x0000000000000000000000000000000000000000000000000000000000000000"}' ``` Upgrading Gateway: @@ -78,7 +78,7 @@ Upgrading Gateway: To update the gateway run the following command: ```bash -node sui/deploy-contract.js upgrade axelar_gateway <policy> +node sui/deploy-contract.js upgrade AxelarGateway <policy> ``` policy should be one of the following: @@ -92,13 +92,19 @@ Provide `--txFilePath` with `--offline` to generate tx data file for offline sig Deploy the Gas Service package: ```bash -node sui/deploy-contract.js deploy gas_service +node sui/deploy-contract.js deploy GasService ``` Deploy the test GMP package: ```bash -node sui/deploy-test.js +node sui/deploy-contract.js deploy Test +``` + +Deploy the Operators package: + +```bash +node sui/deploy-contract.js deploy Operators ``` Call Contract: diff --git a/sui/deploy-contract.js b/sui/deploy-contract.js index eb562f56..af002165 100644 --- a/sui/deploy-contract.js +++ b/sui/deploy-contract.js @@ -5,156 +5,236 @@ const { toB64 } = require('@mysten/sui/utils'); const { bcs } = require('@mysten/sui/bcs'); const { Transaction } = require('@mysten/sui/transactions'); const { - utils: { arrayify, hexlify, toUtf8Bytes, keccak256 }, - constants: { HashZero }, + utils: { arrayify }, } = ethers; -const { saveConfig, printInfo, validateParameters, writeJSON } = require('../evm/utils'); -const { addBaseOptions } = require('./cli-utils'); +const { saveConfig, printInfo, validateParameters, writeJSON, getDomainSeparator, loadConfig } = require('../common'); +const { addBaseOptions, addOptionsToCommands } = require('./cli-utils'); const { getWallet, printWalletInfo, broadcast } = require('./sign-utils'); -const { loadSuiConfig, getAmplifierSigners, deployPackage, getObjectIdsByObjectTypes } = require('./utils'); const { bytes32Struct, signersStruct } = require('./types-utils'); -const { upgradePackage } = require('./deploy-utils'); -const { suiPackageAddress, suiClockAddress } = require('./utils'); - -async function getSigners(keypair, config, chain, options) { - if (options.signers === 'wallet') { - const pubKey = keypair.getPublicKey().toRawBytes(); - printInfo('Using wallet pubkey as the signer for the gateway', hexlify(pubKey)); - - if (keypair.getKeyScheme() !== 'Secp256k1') { - throw new Error('Only Secp256k1 pubkeys are supported by the gateway'); - } - - return { - signers: [{ pub_key: pubKey, weight: 1 }], - threshold: 1, - nonce: options.nonce ? keccak256(toUtf8Bytes(options.nonce)) : HashZero, - }; - } else if (options.signers) { - printInfo('Using provided signers', options.signers); - - const signers = JSON.parse(options.signers); - return { - signers: signers.signers.map(({ pub_key: pubKey, weight }) => { - return { pub_key: arrayify(pubKey), weight }; - }), - threshold: signers.threshold, - nonce: arrayify(signers.nonce) || HashZero, - }; - } - - return getAmplifierSigners(config, chain); +const { upgradePackage, UPGRADE_POLICIES } = require('./deploy-utils'); +const { + getSigners, + deployPackage, + getObjectIdsByObjectTypes, + suiPackageAddress, + suiClockAddress, + readMovePackageName, + getChannelId, +} = require('./utils'); + +/** + * Move Package Directories + * + * This array contains the names of Move package directories located in: + * `node_modules/@axelar-network/axelar-cgp-sui/move` + * + * Each string in this array corresponds to a folder name within that path. + * + * To deploy a new package: + * 1. Add the new package's folder name to this array + * 2. Ensure the corresponding folder exists in the specified path + * + */ +const PACKAGE_DIRS = ['gas_service', 'test', 'axelar_gateway', 'operators']; + +/** + * Post-Deployment Functions Mapping + * + * This object maps each package name to a post-deployment function. + */ +const POST_DEPLOY_FUNCTIONS = { + GasService: postDeployGasService, + Test: postDeployTest, + Operators: postDeployOperators, + AxelarGateway: postDeployAxelarGateway, +}; + +/** + * Command Options Mapping + * + * This object maps each package name to a function that returns an array of command options. + */ +const CMD_OPTIONS = { + AxelarGateway: () => [...DEPLOY_CMD_OPTIONS, ...GATEWAY_CMD_OPTIONS], + GasService: () => DEPLOY_CMD_OPTIONS, + Test: () => DEPLOY_CMD_OPTIONS, + Operators: () => DEPLOY_CMD_OPTIONS, +}; + +/** + * Supported Move Packages + * + * Maps each directory in PACKAGE_DIRS to an object containing: + * - packageName: Read from 'Move.toml' in the directory + * - packageDir: The directory name + * + */ +const supportedPackages = PACKAGE_DIRS.map((dir) => ({ + packageName: readMovePackageName(dir), + packageDir: dir, +})); + +/** + * Post-Deployment Functions + * + * This section defines functions to be executed after package deployment. + * These functions serve purposes such as: + * 1. Updating chain configuration with newly deployed object IDs + * 2. Submitting additional transactions for contract setup + * + * Define post-deployment functions for each supported package below. + */ + +async function postDeployGasService(published, args) { + const { chain } = args; + const [gasCollectorCapObjectId, gasServiceObjectId] = getObjectIdsByObjectTypes(published.publishTxn, [ + `${published.packageId}::gas_service::GasCollectorCap`, + `${published.packageId}::gas_service::GasService`, + ]); + chain.contracts.GasService.objects = { + GasCollectorCap: gasCollectorCapObjectId, + GasService: gasServiceObjectId, + }; } -async function deploy(keypair, client, contractName, config, chain, options) { - if (!chain.contracts[contractName]) { - chain.contracts[contractName] = {}; - } +async function postDeployTest(published, args) { + const { chain, config, options } = args; + const [keypair, client] = getWallet(chain, options); + const relayerDiscovery = config.sui.contracts.AxelarGateway?.objects?.RelayerDiscovery; - const { packageId, publishTxn } = await deployPackage(contractName, client, keypair, options); + const [singletonObjectId] = getObjectIdsByObjectTypes(published.publishTxn, [`${published.packageId}::test::Singleton`]); + const channelId = await getChannelId(client, singletonObjectId); + chain.contracts.Test.objects = { Singleton: singletonObjectId, ChannelId: channelId }; - printInfo('Publish transaction digest: ', publishTxn.digest); + const tx = new Transaction(); + tx.moveCall({ + target: `${published.packageId}::test::register_transaction`, + arguments: [tx.object(relayerDiscovery), tx.object(singletonObjectId)], + }); - const contractConfig = chain.contracts[contractName]; - contractConfig.address = packageId; - contractConfig.objects = {}; + const registerTx = await broadcast(client, keypair, tx); - switch (contractName) { - case 'gas_service': { - const [GasService, GasCollectorCap] = getObjectIdsByObjectTypes(publishTxn, [ - `${packageId}::gas_service::GasService`, - `${packageId}::gas_service::GasCollectorCap`, - ]); - contractConfig.objects = { GasService, GasCollectorCap }; - break; - } - - case 'axelar_gateway': { - const { minimumRotationDelay, domainSeparator, policy, previousSigners } = options; - const operator = options.operator || keypair.toSuiAddress(); - const signers = await getSigners(keypair, config, chain, options); - - validateParameters({ isNonEmptyString: { previousSigners, minimumRotationDelay }, isKeccak256Hash: { domainSeparator } }); - - const [creatorCap, relayerDiscovery, upgradeCap] = getObjectIdsByObjectTypes(publishTxn, [ - `${packageId}::gateway::CreatorCap`, - `${packageId}::discovery::RelayerDiscovery`, - `${suiPackageAddress}::package::UpgradeCap`, - ]); + printInfo('Register transaction', registerTx.digest); +} - const encodedSigners = signersStruct - .serialize({ - ...signers, - nonce: bytes32Struct.serialize(signers.nonce).toBytes(), - }) - .toBytes(); +async function postDeployOperators(published, args) { + const { chain } = args; + const [operatorsObjectId, ownerCapObjectId] = getObjectIdsByObjectTypes(published.publishTxn, [ + `${published.packageId}::operators::Operators`, + `${published.packageId}::operators::OwnerCap`, + ]); + chain.contracts.Operators.objects = { + Operators: operatorsObjectId, + OwnerCap: ownerCapObjectId, + }; +} - const tx = new Transaction(); +async function postDeployAxelarGateway(published, args) { + const { keypair, client, config, chain, options } = args; + const { packageId, publishTxn } = published; + const { minimumRotationDelay, policy, previousSigners } = options; + const operator = options.operator || keypair.toSuiAddress(); + const signers = await getSigners(keypair, config, chain, options); + const domainSeparator = await getDomainSeparator(config, chain, options); + + validateParameters({ + isNonEmptyString: { previousSigners }, + isValidNumber: { minimumRotationDelay }, + }); + + const [creatorCap, relayerDiscovery, upgradeCap] = getObjectIdsByObjectTypes(publishTxn, [ + `${packageId}::gateway::CreatorCap`, + `${packageId}::discovery::RelayerDiscovery`, + `${suiPackageAddress}::package::UpgradeCap`, + ]); + + const encodedSigners = signersStruct + .serialize({ + ...signers, + nonce: bytes32Struct.serialize(signers.nonce).toBytes(), + }) + .toBytes(); + + const tx = new Transaction(); + + const separator = tx.moveCall({ + target: `${packageId}::bytes32::new`, + arguments: [tx.pure(arrayify(domainSeparator))], + }); + + tx.moveCall({ + target: `${packageId}::gateway::setup`, + arguments: [ + tx.object(creatorCap), + tx.pure.address(operator), + separator, + tx.pure.u64(minimumRotationDelay), + tx.pure.u64(options.previousSigners), + tx.pure(bcs.vector(bcs.u8()).serialize(encodedSigners).toBytes()), + tx.object(suiClockAddress), + ], + }); + + if (policy !== 'any_upgrade') { + const upgradeType = UPGRADE_POLICIES[policy]; + tx.moveCall({ + target: `${suiPackageAddress}::package::${upgradeType}`, + arguments: [tx.object(upgradeCap)], + }); + } - const separator = tx.moveCall({ - target: `${packageId}::bytes32::new`, - arguments: [tx.pure(arrayify(domainSeparator))], - }); + const result = await broadcast(client, keypair, tx); - tx.moveCall({ - target: `${packageId}::gateway::setup`, - arguments: [ - tx.object(creatorCap), - tx.pure.address(operator), - separator, - tx.pure.u64(minimumRotationDelay), - tx.pure.u64(options.previousSigners), - tx.pure(bcs.vector(bcs.u8()).serialize(encodedSigners).toBytes()), - tx.object(suiClockAddress), - ], - }); + printInfo('Setup Gateway', result.digest); - if (policy !== 'any_upgrade') { - const upgradeType = policy === 'code_upgrade' ? 'only_additive_upgrades' : 'only_dep_upgrades'; + const [gateway] = getObjectIdsByObjectTypes(result, [`${packageId}::gateway::Gateway`]); - tx.moveCall({ - target: `${suiPackageAddress}::package::${upgradeType}`, - arguments: [tx.object(upgradeCap)], - }); - } + // Update chain configuration + chain.contracts.AxelarGateway = { + objects: { + Gateway: gateway, + RelayerDiscovery: relayerDiscovery, + UpgradeCap: upgradeCap, + }, + domainSeparator, + operator, + minimumRotationDelay, + }; +} - const result = await broadcast(client, keypair, tx); +async function deploy(keypair, client, supportedContract, config, chain, options) { + const { packageDir, packageName } = supportedContract; - printInfo('Setup transaction digest', result.digest); + // Deploy package + const published = await deployPackage(packageDir, client, keypair, options); - const [gateway] = getObjectIdsByObjectTypes(result, [`${packageId}::gateway::Gateway`]); + printInfo(`Deployed ${packageName}`, published.publishTxn.digest); - contractConfig.objects = { - gateway, - relayerDiscovery, - upgradeCap, - }; - contractConfig.domainSeparator = domainSeparator; - contractConfig.operator = operator; - contractConfig.minimumRotationDelay = minimumRotationDelay; - break; - } + // Update chain configuration with deployed contract address + chain.contracts[packageName] = { + address: published.packageId, + }; - default: { - throw new Error(`${contractName} is not supported.`); - } - } + // Execute post-deployment function + const executePostDeploymentFn = POST_DEPLOY_FUNCTIONS[packageName]; + executePostDeploymentFn(published, { keypair, client, config, chain, options }); - printInfo(`${contractName} deployed`, JSON.stringify(contractConfig, null, 2)); + printInfo(`${packageName} Configuration Updated`, JSON.stringify(chain.contracts[packageName], null, 2)); } -async function upgrade(keypair, client, contractName, policy, config, chain, options) { +async function upgrade(keypair, client, supportedPackage, policy, config, chain, options) { const { packageDependencies } = options; + const { packageName } = supportedPackage; options.policy = policy; - if (!chain.contracts[contractName]) { - throw new Error(`Cannot find specified contract: ${contractName}`); + if (!chain.contracts[packageName]) { + throw new Error(`Cannot find specified contract: ${packageName}`); } const contractsConfig = chain.contracts; - const packageConfig = contractsConfig?.[contractName]; + const contractConfig = contractsConfig?.[packageName]; - validateParameters({ isNonEmptyString: { contractName } }); + validateParameters({ isNonEmptyString: { packageName } }); if (packageDependencies) { for (const dependencies of packageDependencies) { @@ -164,11 +244,11 @@ async function upgrade(keypair, client, contractName, policy, config, chain, opt } const builder = new TxBuilder(client); - await upgradePackage(client, keypair, contractName, packageConfig, builder, options); + await upgradePackage(client, keypair, supportedPackage, contractConfig, builder, options); } async function mainProcessor(args, options, processor) { - const config = loadSuiConfig(options.env); + const config = loadConfig(options.env); const [keypair, client] = getWallet(config.sui, options); await printWalletInfo(keypair, client, config.sui, options); await processor(keypair, client, ...args, config, config.sui, options); @@ -185,48 +265,90 @@ async function mainProcessor(args, options, processor) { } } +/** + * Command Options + * + * This section defines options for the command that are specific to each package. + */ + +// Common deploy command options for all packages +const DEPLOY_CMD_OPTIONS = [ + new Option('--policy <policy>', 'upgrade policy for upgrade cap: For example, use "any_upgrade" to allow all types of upgrades') + .choices(['any_upgrade', 'code_upgrade', 'dep_upgrade']) + .default('any_upgrade'), +]; + +// Gateway deploy command options +const GATEWAY_CMD_OPTIONS = [ + new Option('--signers <signers>', 'JSON with the initial signer set').env('SIGNERS'), + new Option('--operator <operator>', 'operator for the gateway (defaults to the deployer address)').env('OPERATOR'), + new Option('--minimumRotationDelay <minimumRotationDelay>', 'minium delay for signer rotations (in second)') + .argParser((val) => parseInt(val) * 1000) + .default(24 * 60 * 60), + new Option('--domainSeparator <domainSeparator>', 'domain separator'), + new Option('--nonce <nonce>', 'nonce for the signer (defaults to HashZero)'), + new Option('--previousSigners <previousSigners>', 'number of previous signers to retain').default('15'), +]; + +const addDeployOptions = (program) => { + // Get the package name from the program name + const packageName = program.name(); + + // Find the corresponding options for the package + const options = CMD_OPTIONS[packageName](); + + // Add the options to the program + options.forEach((option) => program.addOption(option)); + + return program; +}; + if (require.main === module) { - const program = new Command(); - - program.name('deploy-contract').description('Deploy/Upgrade packages'); - - const deployCmd = program - .name('deploy') - .description('Deploy a Sui package') - .command('deploy <contractName>') - .addOption(new Option('--signers <signers>', 'JSON with the initial signer set').env('SIGNERS')) - .addOption(new Option('--operator <operator>', 'operator for the gateway (defaults to the deployer address)').env('OPERATOR')) - .addOption( - new Option('--minimumRotationDelay <minimumRotationDelay>', 'minium delay for signer rotations (in second)') - .default(24 * 60 * 60) - .parseArg((val) => parseInt(val) * 1000), - ) - .addOption(new Option('--domainSeparator <domainSeparator>', 'domain separator')) - .addOption(new Option('--nonce <nonce>', 'nonce for the signer (defaults to HashZero)')) - .addOption(new Option('--previousSigners <previousSigners>', 'number of previous signers to retain').default('15')) - .addOption( - new Option('--policy <policy>', 'upgrade policy for upgrade cap: For example, use "any_upgrade" to allow all types of upgrades') - .choices(['any_upgrade', 'code_upgrade', 'dep_upgrade']) - .default('any_upgrade'), - ) - .action((contractName, options) => { - mainProcessor([contractName], options, deploy); - }); + // 1st level command + const program = new Command('deploy-contract').description('Deploy/Upgrade packages'); + + // 2nd level commands + const deployCmd = new Command('deploy').description('Deploy a Sui package'); + const upgradeCmd = new Command('upgrade').description('Upgrade a Sui package'); + + // 3rd level commands for `deploy` + const deployContractCmds = supportedPackages.map((supportedPackage) => { + const { packageName } = supportedPackage; + const command = new Command(packageName).description(`Deploy ${packageName} contract`); - const upgradeCmd = program - .name('upgrade') - .description('Upgrade a Sui package') - .command('upgrade <contractName> <policy>') - .addOption(new Option('--sender <sender>', 'transaction sender')) - .addOption(new Option('--digest <digest>', 'digest hash for upgrade')) - .addOption(new Option('--offline', 'store tx block for sign')) - .addOption(new Option('--txFilePath <file>', 'unsigned transaction will be stored')) - .action((contractName, policy, options) => { - mainProcessor([contractName, policy], options, upgrade); + return addDeployOptions(command).action((options) => { + mainProcessor([supportedPackage], options, deploy); }); + }); + + // Add 3rd level commands to 2nd level command `deploy` + deployContractCmds.forEach((cmd) => deployCmd.addCommand(cmd)); + + // 3rd level commands for `upgrade` + const upgradeContractCmds = supportedPackages.map((supportedPackage) => { + const { packageName } = supportedPackage; + return new Command(packageName) + .description(`Upgrade ${packageName} contract`) + .command(`${packageName} <policy>`) + .addOption(new Option('--sender <sender>', 'transaction sender')) + .addOption(new Option('--digest <digest>', 'digest hash for upgrade')) + .addOption(new Option('--offline', 'store tx block for sign')) + .addOption(new Option('--txFilePath <file>', 'unsigned transaction will be stored')) + .action((policy, options) => { + mainProcessor([supportedPackage, policy], options, upgrade); + }); + }); + + // Add 3rd level commands to 2nd level command `upgrade` + upgradeContractCmds.forEach((cmd) => upgradeCmd.addCommand(cmd)); + + // Add base options to all 2nd and 3rd level commands + addOptionsToCommands(deployCmd, addBaseOptions); + addOptionsToCommands(upgradeCmd, addBaseOptions); - addBaseOptions(deployCmd); - addBaseOptions(upgradeCmd); + // Add 2nd level commands to 1st level command + program.addCommand(deployCmd); + program.addCommand(upgradeCmd); program.parse(); } diff --git a/sui/deploy-test.js b/sui/deploy-test.js index 8b0db9e9..9ab7bc77 100644 --- a/sui/deploy-test.js +++ b/sui/deploy-test.js @@ -1,6 +1,6 @@ -const { saveConfig, prompt, printInfo } = require('../common/utils'); +const { loadConfig, saveConfig, prompt, printInfo } = require('../common/utils'); const { Command } = require('commander'); -const { loadSuiConfig, deployPackage, getBcsBytesByObjectId } = require('./utils'); +const { deployPackage, getBcsBytesByObjectId } = require('./utils'); const { singletonStruct } = require('./types-utils'); const { Transaction } = require('@mysten/sui/transactions'); const { addBaseOptions } = require('./cli-utils'); @@ -54,7 +54,7 @@ async function processCommand(config, chain, options) { } async function mainProcessor(options, processor) { - const config = loadSuiConfig(options.env); + const config = loadConfig(options.env); await processor(config, config.sui, options); saveConfig(config, options.env); diff --git a/sui/deploy-utils.js b/sui/deploy-utils.js index 3c594116..0dd21568 100644 --- a/sui/deploy-utils.js +++ b/sui/deploy-utils.js @@ -1,25 +1,35 @@ -const { Command, Option } = require('commander'); -const { TxBuilder, updateMoveToml } = require('@axelar-network/axelar-cgp-sui'); const { bcs } = require('@mysten/bcs'); -const { fromB64, toB64 } = require('@mysten/bcs'); -const { saveConfig, printInfo, validateParameters, prompt, writeJSON } = require('../common/utils'); -const { addBaseOptions } = require('./cli-utils'); -const { getWallet } = require('./sign-utils'); -const { loadSuiConfig, getObjectIdsByObjectTypes, suiPackageAddress } = require('./utils'); - -async function upgradePackage(client, keypair, packageName, packageConfig, builder, options) { - const { modules, dependencies, digest } = await builder.getContractBuild(packageName); - const { policy, offline } = options; - const sender = options.sender || keypair.toSuiAddress(); +const { fromB64 } = require('@mysten/bcs'); +const { printInfo, validateParameters } = require('../common/utils'); +const { getObjectIdsByObjectTypes, suiPackageAddress } = require('./utils'); +const UPGRADE_POLICIES = { + code_upgrade: 'only_additive_upgrades', + dependency_upgrade: 'only_dep_upgrades', +}; - if (!['any_upgrade', 'code_upgrade', 'dep_upgrade'].includes(policy)) { - throw new Error(`Unknown upgrade policy: ${policy}. Supported policies: any_upgrade, code_upgrade, dep_upgrade`); +function getUpgradePolicyId(policy) { + switch (policy) { + case 'any_upgrade': + return 0; + case 'code_upgrade': + return 128; + case 'dep_upgrade': + return 192; + default: + throw new Error(`Unknown upgrade policy: ${policy}. Supported policies: any_upgrade, code_upgrade, dep_upgrade`); } +} - const upgradeCap = packageConfig.objects?.upgradeCap; +async function upgradePackage(client, keypair, packageToUpgrade, contractConfig, builder, options) { + const { packageDir, packageName } = packageToUpgrade; + const { modules, dependencies, digest } = await builder.getContractBuild(packageDir); + const { offline } = options; + const sender = options.sender || keypair.toSuiAddress(); + const upgradeCap = contractConfig.objects?.UpgradeCap; const digestHash = options.digest ? fromB64(options.digest) : digest; + const policy = getUpgradePolicyId(options.policy); - validateParameters({ isNonEmptyString: { upgradeCap, policy }, isNonEmptyStringArray: { modules, dependencies } }); + validateParameters({ isNonEmptyString: { upgradeCap }, isNonEmptyStringArray: { modules, dependencies } }); const tx = builder.tx; const cap = tx.object(upgradeCap); @@ -31,7 +41,7 @@ async function upgradePackage(client, keypair, packageName, packageConfig, build const receipt = tx.upgrade({ modules, dependencies, - package: packageConfig.address, + package: contractConfig.address, ticket, }); @@ -45,7 +55,7 @@ async function upgradePackage(client, keypair, packageName, packageConfig, build if (offline) { options.txBytes = txBytes; - options.offlineMessage = `Transaction to upgrade ${packageName}`; + options.offlineMessage = `Transaction to upgrade ${packageDir}`; } else { const signature = (await keypair.signTransaction(txBytes)).signature; const result = await client.executeTransactionBlock({ @@ -59,130 +69,16 @@ async function upgradePackage(client, keypair, packageName, packageConfig, build }); const packageId = (result.objectChanges?.filter((a) => a.type === 'published') ?? [])[0].packageId; - packageConfig.address = packageId; - const [upgradeCap] = getObjectIdsByObjectTypes(result, ['0x2::package::UpgradeCap']); - packageConfig.objects.upgradeCap = upgradeCap; - - printInfo('Transaction digest', JSON.stringify(result.digest, null, 2)); - printInfo(`${packageName} upgraded`, packageId); - } -} - -async function deployPackage(chain, client, keypair, packageName, packageConfig, builder, options) { - const { offline, sender } = options; - - const address = sender || keypair.toSuiAddress(); - await builder.publishPackageAndTransferCap(packageName, address); - const tx = builder.tx; - tx.setSender(address); - const txBytes = await tx.build({ client }); - - if (offline) { - options.txBytes = txBytes; - } else { - if (prompt(`Proceed with deployment on ${chain.name}?`, options.yes)) { - return; - } - - const signature = (await keypair.signTransaction(txBytes)).signature; - const publishTxn = await client.executeTransactionBlock({ - transactionBlock: txBytes, - signature, - options: { - showEffects: true, - showObjectChanges: true, - showEvents: true, - }, - }); - - packageConfig.address = (publishTxn.objectChanges?.find((a) => a.type === 'published') ?? []).packageId; - const objectChanges = publishTxn.objectChanges.filter((object) => object.type === 'created'); - packageConfig.objects = {}; - - for (const object of objectChanges) { - const array = object.objectType.split('::'); - const objectName = array[array.length - 1]; - - if (objectName) { - packageConfig.objects[objectName] = object.objectId; - } - } + contractConfig.address = packageId; + const [upgradeCap] = getObjectIdsByObjectTypes(result, [`${suiPackageAddress}::package::UpgradeCap`]); + contractConfig.objects.UpgradeCap = upgradeCap; - printInfo(`${packageName} deployed`, JSON.stringify(packageConfig, null, 2)); + printInfo('Transaction Digest', JSON.stringify(result.digest, null, 2)); + printInfo(`${packageName} Upgraded Address`, packageId); } } -async function processCommand(chain, options) { - const [keypair, client] = getWallet(chain, options); - const { upgrade, packageName, packageDependencies, offline, txFilePath } = options; - - printInfo('Wallet address', keypair.toSuiAddress()); - - if (!chain.contracts[packageName]) { - chain.contracts[packageName] = {}; - } - - const contractsConfig = chain.contracts; - const packageConfig = contractsConfig?.[packageName]; - - validateParameters({ isNonEmptyString: { packageName } }); - - if (packageDependencies) { - for (const dependencies of packageDependencies) { - const packageId = contractsConfig[dependencies]?.address; - updateMoveToml(dependencies, packageId); - } - } - - const builder = new TxBuilder(client); - - if (upgrade) { - await upgradePackage(client, keypair, packageName, packageConfig, builder, options); - } else { - await deployPackage(chain, client, keypair, packageName, packageConfig, builder, options); - } - - if (offline) { - validateParameters({ isNonEmptyString: { txFilePath } }); - - const txB64Bytes = toB64(options.txBytes); - - writeJSON({ status: 'PENDING', bytes: txB64Bytes }, txFilePath); - printInfo(`The unsigned transaction is`, txB64Bytes); - } -} - -async function mainProcessor(options, processor) { - const config = loadSuiConfig(options.env); - - await processor(config.sui, options); - saveConfig(config, options.env); -} - -if (require.main === module) { - const program = new Command(); - - program.name('deploy-upgrade').description('Deploy/Upgrade the Sui package'); - - addBaseOptions(program); - - program.addOption(new Option('--packageName <packageName>', 'package name to deploy/upgrade')); - program.addOption(new Option('--packageDependencies [packageDependencies...]', 'array of package dependencies')); - program.addOption(new Option('--upgrade', 'deploy or upgrade')); - program.addOption(new Option('--policy <policy>', 'new policy to upgrade')); - program.addOption(new Option('--sender <sender>', 'transaction sender')); - program.addOption(new Option('--digest <digest>', 'digest hash for upgrade')); - program.addOption(new Option('--offline', 'store tx block for sign')); - program.addOption(new Option('--txFilePath <file>', 'unsigned transaction will be stored')); - - program.action((options) => { - mainProcessor(options, processCommand); - }); - - program.parse(); -} - module.exports = { + UPGRADE_POLICIES, upgradePackage, - deployPackage, }; diff --git a/sui/gas-service.js b/sui/gas-service.js index 1a6ba290..4b81be71 100644 --- a/sui/gas-service.js +++ b/sui/gas-service.js @@ -2,8 +2,9 @@ const { saveConfig, printInfo, printError } = require('../common/utils'); const { Command } = require('commander'); const { Transaction } = require('@mysten/sui/transactions'); const { bcs } = require('@mysten/sui/bcs'); +const { loadConfig } = require('../common/utils'); const { gasServiceStruct } = require('./types-utils'); -const { loadSuiConfig, getBcsBytesByObjectId } = require('./utils'); +const { getBcsBytesByObjectId } = require('./utils'); const { ethers } = require('hardhat'); const { getFormattedAmount } = require('./amount-utils'); const { @@ -160,7 +161,7 @@ async function processCommand(command, chain, args, options) { } async function mainProcessor(options, args, processor, command) { - const config = loadSuiConfig(options.env); + const config = loadConfig(options.env); await processor(command, config.sui, args, options); saveConfig(config, options.env); } diff --git a/sui/gateway.js b/sui/gateway.js index a26ef9ec..d46721de 100644 --- a/sui/gateway.js +++ b/sui/gateway.js @@ -8,10 +8,10 @@ const { constants: { HashZero }, } = ethers; +const { loadConfig } = require('../common/utils'); const { addBaseOptions } = require('./cli-utils'); const { getWallet, printWalletInfo, getRawPrivateKey, broadcast } = require('./sign-utils'); const { bytes32Struct, signersStruct, messageToSignStruct, messageStruct, proofStruct } = require('./types-utils'); -const { loadSuiConfig } = require('./utils'); const { getSigners } = require('./deploy-gateway'); const secp256k1 = require('secp256k1'); @@ -218,7 +218,7 @@ async function rotateSigners(keypair, client, config, chain, args, options) { } async function mainProcessor(processor, args, options) { - const config = loadSuiConfig(options.env); + const config = loadConfig(options.env); const [keypair, client] = getWallet(config.sui, options); await printWalletInfo(keypair, client, config.sui, options); diff --git a/sui/gmp.js b/sui/gmp.js index a1bf4a96..5c3ab2a5 100644 --- a/sui/gmp.js +++ b/sui/gmp.js @@ -2,7 +2,8 @@ const { saveConfig, printInfo } = require('../common/utils'); const { Command } = require('commander'); const { Transaction } = require('@mysten/sui/transactions'); const { bcs } = require('@mysten/sui/bcs'); -const { loadSuiConfig, getBcsBytesByObjectId } = require('./utils'); +const { getBcsBytesByObjectId } = require('./utils'); +const { loadConfig } = require('../common/utils'); const { ethers } = require('hardhat'); const { utils: { arrayify }, @@ -65,8 +66,8 @@ async function execute(keypair, client, contracts, args, options) { const [sourceChain, messageId, sourceAddress, payload] = args; - const gatewayObjectId = axelarGatewayConfig.objects.gateway; - const discoveryObjectId = axelarGatewayConfig.objects.relayerDiscovery; + const gatewayObjectId = axelarGatewayConfig.objects.Gateway; + const discoveryObjectId = axelarGatewayConfig.objects.RelayerDiscovery; // Get the channel id from the options or use the channel id from the deployed test contract object. const channelId = options.channelId || testConfig.objects.channelId; @@ -165,7 +166,7 @@ async function processCommand(command, chain, args, options) { } async function mainProcessor(command, options, args, processor) { - const config = loadSuiConfig(options.env); + const config = loadConfig(options.env); await processor(command, config.sui, args, options); saveConfig(config, options.env); } diff --git a/sui/multisig.js b/sui/multisig.js index 9d69414d..2571ac8d 100644 --- a/sui/multisig.js +++ b/sui/multisig.js @@ -3,7 +3,7 @@ const { fromB64 } = require('@mysten/bcs'); const { addBaseOptions } = require('./cli-utils'); const { getWallet, getMultisig, signTransactionBlockBytes, broadcastSignature } = require('./sign-utils'); const { getSignedTx, storeSignedTx } = require('../evm/sign-utils'); -const { loadSuiConfig } = require('./utils'); +const { loadConfig } = require('../common/utils'); const { printInfo, validateParameters } = require('../common/utils'); async function signTx(keypair, client, options) { @@ -143,7 +143,7 @@ async function processCommand(chain, options) { } async function mainProcessor(options, processor) { - const config = loadSuiConfig(options.env); + const config = loadConfig(options.env); await processor(config.sui, options); } diff --git a/sui/transfer-object.js b/sui/transfer-object.js index 1d58ee6f..10919e00 100644 --- a/sui/transfer-object.js +++ b/sui/transfer-object.js @@ -3,7 +3,7 @@ const { Command, Option } = require('commander'); const { printInfo, validateParameters } = require('../common/utils'); const { addExtendedOptions } = require('./cli-utils'); const { getWallet, printWalletInfo } = require('./sign-utils'); -const { loadSuiConfig } = require('./utils'); +const { loadConfig } = require('../common/utils'); async function processCommand(chain, options) { const [keypair, client] = getWallet(chain, options); @@ -54,7 +54,7 @@ async function processCommand(chain, options) { } async function mainProcessor(options, processor) { - const config = loadSuiConfig(options.env); + const config = loadConfig(options.env); await processor(config.sui, options); } diff --git a/sui/utils.js b/sui/utils.js index e019d1fe..eac07a8a 100644 --- a/sui/utils.js +++ b/sui/utils.js @@ -1,14 +1,18 @@ 'use strict'; const { ethers } = require('hardhat'); -const { loadConfig } = require('../common/utils'); +const toml = require('toml'); +const { printInfo, printError } = require('../common/utils'); const { BigNumber, - utils: { arrayify, hexlify }, + utils: { arrayify, hexlify, toUtf8Bytes, keccak256 }, + constants: { HashZero }, } = ethers; +const fs = require('fs'); const { fromB64 } = require('@mysten/bcs'); const { CosmWasmClient } = require('@cosmjs/cosmwasm-stargate'); const { updateMoveToml, copyMovePackage, TxBuilder } = require('@axelar-network/axelar-cgp-sui'); +const { singletonStruct } = require('./types-utils'); const suiPackageAddress = '0x2'; const suiClockAddress = '0x6'; @@ -48,23 +52,6 @@ const getBcsBytesByObjectId = async (client, objectId) => { return fromB64(response.data.bcs.bcsBytes); }; -const loadSuiConfig = (env) => { - const config = loadConfig(env); - const suiEnv = env === 'local' ? 'localnet' : env; - - if (!config.sui) { - config.sui = { - networkType: suiEnv, - name: 'Sui', - contracts: { - axelar_gateway: {}, - }, - }; - } - - return config; -}; - const deployPackage = async (packageName, client, keypair, options = {}) => { const compileDir = `${__dirname}/move`; @@ -80,6 +67,24 @@ const deployPackage = async (packageName, client, keypair, options = {}) => { return { packageId, publishTxn }; }; +const findPublishedObject = (published, packageDir, contractName) => { + const packageId = published.packageId; + return published.publishTxn.objectChanges.find((change) => change.objectType === `${packageId}::${packageDir}::${contractName}`); +}; + +const readMovePackageName = (moveDir) => { + try { + const moveToml = fs.readFileSync(`${__dirname}/../node_modules/@axelar-network/axelar-cgp-sui/move/${moveDir}/Move.toml`, 'utf8'); + + const { package: movePackage } = toml.parse(moveToml); + + return movePackage.name; + } catch (err) { + printError('Error reading TOML file'); + throw err; + } +}; + const getObjectIdsByObjectTypes = (txn, objectTypes) => objectTypes.map((objectType) => { const objectId = txn.objectChanges.find((change) => change.objectType === objectType)?.objectId; @@ -91,12 +96,52 @@ const getObjectIdsByObjectTypes = (txn, objectTypes) => return objectId; }); +// Parse bcs bytes from singleton object which is created when the Test contract is deployed +const getChannelId = async (client, singletonObjectId) => { + const bcsBytes = await getBcsBytesByObjectId(client, singletonObjectId); + const data = singletonStruct.parse(bcsBytes); + return '0x' + data.channel.id; +}; + +const getSigners = async (keypair, config, chain, options) => { + if (options.signers === 'wallet') { + const pubKey = keypair.getPublicKey().toRawBytes(); + printInfo('Using wallet pubkey as the signer for the gateway', hexlify(pubKey)); + + if (keypair.getKeyScheme() !== 'Secp256k1') { + throw new Error('Only Secp256k1 pubkeys are supported by the gateway'); + } + + return { + signers: [{ pub_key: pubKey, weight: 1 }], + threshold: 1, + nonce: options.nonce ? keccak256(toUtf8Bytes(options.nonce)) : HashZero, + }; + } else if (options.signers) { + printInfo('Using provided signers', options.signers); + + const signers = JSON.parse(options.signers); + return { + signers: signers.signers.map(({ pub_key: pubKey, weight }) => { + return { pub_key: arrayify(pubKey), weight }; + }), + threshold: signers.threshold, + nonce: arrayify(signers.nonce) || HashZero, + }; + } + + return getAmplifierSigners(config, chain); +}; + module.exports = { suiPackageAddress, suiClockAddress, getAmplifierSigners, getBcsBytesByObjectId, - loadSuiConfig, deployPackage, + findPublishedObject, + readMovePackageName, getObjectIdsByObjectTypes, + getChannelId, + getSigners, }; From a674c8700ba49f9891e10fb03adecf687e2978db Mon Sep 17 00:00:00 2001 From: npty <78221556+npty@users.noreply.github.com> Date: Thu, 1 Aug 2024 18:52:01 +0700 Subject: [PATCH 43/44] chore: cleanup deploy script pr (#327) --- common/utils.js | 14 +---------- sui/README.md | 4 ++- sui/deploy-contract.js | 56 ++++++++++++++++++------------------------ 3 files changed, 28 insertions(+), 46 deletions(-) diff --git a/common/utils.js b/common/utils.js index e6819154..71ce7284 100644 --- a/common/utils.js +++ b/common/utils.js @@ -15,19 +15,7 @@ const { const { normalizeBech32 } = require('@cosmjs/encoding'); function loadConfig(env) { - const config = require(`${__dirname}/../axelar-chains-config/info/${env}.json`); - - if (!config.sui) { - config.sui = { - networkType: env === 'local' ? 'localnet' : env, - name: 'Sui', - contracts: { - AxelarGateway: {}, - }, - }; - } - - return config; + return require(`${__dirname}/../axelar-chains-config/info/${env}.json`); } function saveConfig(config, env) { diff --git a/sui/README.md b/sui/README.md index 2cc6c789..c66108cd 100644 --- a/sui/README.md +++ b/sui/README.md @@ -34,7 +34,9 @@ If you want to run against a local Sui network, then create a `axelar-chains-con "tokenSymbol": "SUI", "rpc": "http://127.0.0.1:9000", "faucetUrl": "http://127.0.0.1:9123", - "contracts": {} + "contracts": { + "AxelarGateway": {} + } } } ``` diff --git a/sui/deploy-contract.js b/sui/deploy-contract.js index af002165..a5fbb3ca 100644 --- a/sui/deploy-contract.js +++ b/sui/deploy-contract.js @@ -38,27 +38,21 @@ const { const PACKAGE_DIRS = ['gas_service', 'test', 'axelar_gateway', 'operators']; /** - * Post-Deployment Functions Mapping - * - * This object maps each package name to a post-deployment function. + * Package Mapping Object for Command Options and Post-Deployment Functions */ -const POST_DEPLOY_FUNCTIONS = { - GasService: postDeployGasService, - Test: postDeployTest, - Operators: postDeployOperators, - AxelarGateway: postDeployAxelarGateway, -}; - -/** - * Command Options Mapping - * - * This object maps each package name to a function that returns an array of command options. - */ -const CMD_OPTIONS = { - AxelarGateway: () => [...DEPLOY_CMD_OPTIONS, ...GATEWAY_CMD_OPTIONS], - GasService: () => DEPLOY_CMD_OPTIONS, - Test: () => DEPLOY_CMD_OPTIONS, - Operators: () => DEPLOY_CMD_OPTIONS, +const PACKAGE_CONFIGS = { + cmdOptions: { + AxelarGateway: () => GATEWAY_CMD_OPTIONS, + GasService: () => [], + Test: () => [], + Operators: () => [], + }, + postDeployFunctions: { + AxelarGateway: postDeployAxelarGateway, + GasService: postDeployGasService, + Test: postDeployTest, + Operators: postDeployOperators, + }, }; /** @@ -85,8 +79,7 @@ const supportedPackages = PACKAGE_DIRS.map((dir) => ({ * Define post-deployment functions for each supported package below. */ -async function postDeployGasService(published, args) { - const { chain } = args; +async function postDeployGasService(published, keypair, client, config, chain, options) { const [gasCollectorCapObjectId, gasServiceObjectId] = getObjectIdsByObjectTypes(published.publishTxn, [ `${published.packageId}::gas_service::GasCollectorCap`, `${published.packageId}::gas_service::GasService`, @@ -97,9 +90,7 @@ async function postDeployGasService(published, args) { }; } -async function postDeployTest(published, args) { - const { chain, config, options } = args; - const [keypair, client] = getWallet(chain, options); +async function postDeployTest(published, keypair, client, config, chain, options) { const relayerDiscovery = config.sui.contracts.AxelarGateway?.objects?.RelayerDiscovery; const [singletonObjectId] = getObjectIdsByObjectTypes(published.publishTxn, [`${published.packageId}::test::Singleton`]); @@ -117,8 +108,7 @@ async function postDeployTest(published, args) { printInfo('Register transaction', registerTx.digest); } -async function postDeployOperators(published, args) { - const { chain } = args; +async function postDeployOperators(published, keypair, client, config, chain, options) { const [operatorsObjectId, ownerCapObjectId] = getObjectIdsByObjectTypes(published.publishTxn, [ `${published.packageId}::operators::Operators`, `${published.packageId}::operators::OwnerCap`, @@ -129,8 +119,7 @@ async function postDeployOperators(published, args) { }; } -async function postDeployAxelarGateway(published, args) { - const { keypair, client, config, chain, options } = args; +async function postDeployAxelarGateway(published, keypair, client, config, chain, options) { const { packageId, publishTxn } = published; const { minimumRotationDelay, policy, previousSigners } = options; const operator = options.operator || keypair.toSuiAddress(); @@ -216,8 +205,8 @@ async function deploy(keypair, client, supportedContract, config, chain, options }; // Execute post-deployment function - const executePostDeploymentFn = POST_DEPLOY_FUNCTIONS[packageName]; - executePostDeploymentFn(published, { keypair, client, config, chain, options }); + const executePostDeploymentFn = PACKAGE_CONFIGS.postDeployFunctions[packageName]; + await executePostDeploymentFn(published, keypair, client, config, chain, options); printInfo(`${packageName} Configuration Updated`, JSON.stringify(chain.contracts[packageName], null, 2)); } @@ -295,11 +284,14 @@ const addDeployOptions = (program) => { const packageName = program.name(); // Find the corresponding options for the package - const options = CMD_OPTIONS[packageName](); + const options = PACKAGE_CONFIGS.cmdOptions[packageName](); // Add the options to the program options.forEach((option) => program.addOption(option)); + // Add the base deploy options to the program + DEPLOY_CMD_OPTIONS.forEach((option) => program.addOption(option)); + return program; }; From fedbfeed03ac4618b1de769191612cc91abef0a1 Mon Sep 17 00:00:00 2001 From: Foivos <foivos@umich.edu> Date: Thu, 1 Aug 2024 19:08:41 +0300 Subject: [PATCH 44/44] feat: add deployments for its and squid (#328) Co-authored-by: Milap Sheth <milap@interoplabs.io> --- sui/README.md | 24 +++++++++++++++++++ sui/deploy-contract.js | 53 ++++++++++++++++++++++++++++++++++++++---- sui/deploy-test.js | 4 ++-- sui/types-utils.js | 37 +++++++++++++++++++++++++++++ sui/utils.js | 20 +++++++++++++--- 5 files changed, 129 insertions(+), 9 deletions(-) diff --git a/sui/README.md b/sui/README.md index c66108cd..9df6c507 100644 --- a/sui/README.md +++ b/sui/README.md @@ -109,6 +109,30 @@ Deploy the Operators package: node sui/deploy-contract.js deploy Operators ``` +Deploy the Abi package: + +```bash +node sui/deploy-contract.js deploy Abi +``` + +Deploy the Governance package (requires `abi` and `axelar_gateway`): + +```bash +node sui/deploy-contract.js deploy Governance +``` + +Deploy the ITS package (requires `abi`, `axelar_gateway` and `goverannce`): + +```bash +node sui/deploy-contract.js deploy ITS +``` + +Deploy the Squid package (requires `abi`, `axelar_gateway`, `goverannce` and `its`): + +```bash +node sui/deploy-contract.js deploy Squid +``` + Call Contract: ```bash diff --git a/sui/deploy-contract.js b/sui/deploy-contract.js index a5fbb3ca..af3e6fad 100644 --- a/sui/deploy-contract.js +++ b/sui/deploy-contract.js @@ -19,7 +19,9 @@ const { suiPackageAddress, suiClockAddress, readMovePackageName, - getChannelId, + getSingletonChannelId, + getItsChannelId, + getSquidChannelId, } = require('./utils'); /** @@ -35,7 +37,7 @@ const { * 2. Ensure the corresponding folder exists in the specified path * */ -const PACKAGE_DIRS = ['gas_service', 'test', 'axelar_gateway', 'operators']; +const PACKAGE_DIRS = ['gas_service', 'test', 'axelar_gateway', 'operators', 'abi', 'governance', 'its', 'squid']; /** * Package Mapping Object for Command Options and Post-Deployment Functions @@ -46,12 +48,20 @@ const PACKAGE_CONFIGS = { GasService: () => [], Test: () => [], Operators: () => [], + Abi: () => [], + Governance: () => [], + ITS: () => [], + Squid: () => [], }, postDeployFunctions: { AxelarGateway: postDeployAxelarGateway, GasService: postDeployGasService, Test: postDeployTest, Operators: postDeployOperators, + Abi: {}, + Governance: {}, + ITS: postDeployIts, + Squid: postDeploySquid, }, }; @@ -94,7 +104,7 @@ async function postDeployTest(published, keypair, client, config, chain, options const relayerDiscovery = config.sui.contracts.AxelarGateway?.objects?.RelayerDiscovery; const [singletonObjectId] = getObjectIdsByObjectTypes(published.publishTxn, [`${published.packageId}::test::Singleton`]); - const channelId = await getChannelId(client, singletonObjectId); + const channelId = await getSingletonChannelId(client, singletonObjectId); chain.contracts.Test.objects = { Singleton: singletonObjectId, ChannelId: channelId }; const tx = new Transaction(); @@ -191,6 +201,42 @@ async function postDeployAxelarGateway(published, keypair, client, config, chain }; } +async function postDeployIts(published, keypair, client, config, chain, options) { + const relayerDiscovery = config.sui.contracts.AxelarGateway?.objects?.RelayerDiscovery; + + const [itsObjectId] = getObjectIdsByObjectTypes(published.publishTxn, [`${published.packageId}::its::ITS`]); + const channelId = await getItsChannelId(client, itsObjectId); + chain.contracts.ITS.objects = { ITS: itsObjectId, ChannelId: channelId }; + + const tx = new Transaction(); + tx.moveCall({ + target: `${published.packageId}::discovery::register_transaction`, + arguments: [tx.object(itsObjectId), tx.object(relayerDiscovery)], + }); + + const registerTx = await broadcast(client, keypair, tx); + + printInfo('Register transaction', registerTx.digest); +} + +async function postDeploySquid(published, keypair, client, config, chain, options) { + const relayerDiscovery = config.sui.contracts.AxelarGateway?.objects?.RelayerDiscovery; + + const [squidObjectId] = getObjectIdsByObjectTypes(published.publishTxn, [`${published.packageId}::squid::Squid`]); + const channelId = await getSquidChannelId(client, squidObjectId); + chain.contracts.Squid.objects = { Squid: squidObjectId, ChannelId: channelId }; + + const tx = new Transaction(); + tx.moveCall({ + target: `${published.packageId}::discovery::register_transaction`, + arguments: [tx.object(squidObjectId), tx.object(chain.contracts.ITS.objects.ITS), tx.object(relayerDiscovery)], + }); + + const registerTx = await broadcast(client, keypair, tx); + + printInfo('Register transaction', registerTx.digest); +} + async function deploy(keypair, client, supportedContract, config, chain, options) { const { packageDir, packageName } = supportedContract; @@ -282,7 +328,6 @@ const GATEWAY_CMD_OPTIONS = [ const addDeployOptions = (program) => { // Get the package name from the program name const packageName = program.name(); - // Find the corresponding options for the package const options = PACKAGE_CONFIGS.cmdOptions[packageName](); diff --git a/sui/deploy-test.js b/sui/deploy-test.js index 9ab7bc77..407f2823 100644 --- a/sui/deploy-test.js +++ b/sui/deploy-test.js @@ -7,7 +7,7 @@ const { addBaseOptions } = require('./cli-utils'); const { getWallet, printWalletInfo, broadcast } = require('./sign-utils'); // Parse bcs bytes from singleton object to get channel id -async function getChannelId(client, singletonObjectId) { +async function getSingletonChannelId(client, singletonObjectId) { const bcsBytes = await getBcsBytesByObjectId(client, singletonObjectId); const data = singletonStruct.parse(bcsBytes); return '0x' + data.channel.id; @@ -45,7 +45,7 @@ async function processCommand(config, chain, options) { await broadcast(client, keypair, tx); - const channelId = await getChannelId(client, singleton.objectId); + const channelId = await getSingletonChannelId(client, singleton.objectId); chain.contracts.test.address = published.packageId; chain.contracts.test.objects = { singleton: singleton.objectId, channelId }; diff --git a/sui/types-utils.js b/sui/types-utils.js index a4c61757..cd90d4ff 100644 --- a/sui/types-utils.js +++ b/sui/types-utils.js @@ -83,6 +83,41 @@ const discoveryStruct = bcs.struct('Discovery', { fields: discoveryTable, }); +const tableStruct = bcs.struct('Table', { + id: UID, + size: bcs.U64, +}); + +const bagStruct = bcs.struct('Bag', { + id: UID, + size: bcs.U64, +}); + +const interchainAddressTrackerStruct = bcs.struct('InterchainAddressTracker', { + trusted_addresses: tableStruct, +}); + +const itsStruct = bcs.struct('ITS', { + id: UID, + channel: channelStruct, + address_tracker: interchainAddressTrackerStruct, + unregistered_coin_types: tableStruct, + unregistered_coin_info: bagStruct, + registered_coin_types: tableStruct, + registered_coins: bagStruct, + relayer_discovery_id: UID, +}); + +const coinBagStrcut = bcs.struct('CoinBag', { + bag: bagStruct, +}); + +const squidStruct = bcs.struct('Squid', { + id: UID, + channel: channelStruct, + coin_bag: coinBagStrcut, +}); + module.exports = { addressStruct, signerStruct, @@ -96,4 +131,6 @@ module.exports = { channelStruct, singletonStruct, discoveryStruct, + itsStruct, + squidStruct, }; diff --git a/sui/utils.js b/sui/utils.js index eac07a8a..1ef47c8c 100644 --- a/sui/utils.js +++ b/sui/utils.js @@ -12,7 +12,7 @@ const fs = require('fs'); const { fromB64 } = require('@mysten/bcs'); const { CosmWasmClient } = require('@cosmjs/cosmwasm-stargate'); const { updateMoveToml, copyMovePackage, TxBuilder } = require('@axelar-network/axelar-cgp-sui'); -const { singletonStruct } = require('./types-utils'); +const { singletonStruct, itsStruct, squidStruct } = require('./types-utils'); const suiPackageAddress = '0x2'; const suiClockAddress = '0x6'; @@ -97,12 +97,24 @@ const getObjectIdsByObjectTypes = (txn, objectTypes) => }); // Parse bcs bytes from singleton object which is created when the Test contract is deployed -const getChannelId = async (client, singletonObjectId) => { +const getSingletonChannelId = async (client, singletonObjectId) => { const bcsBytes = await getBcsBytesByObjectId(client, singletonObjectId); const data = singletonStruct.parse(bcsBytes); return '0x' + data.channel.id; }; +const getItsChannelId = async (client, itsObjectId) => { + const bcsBytes = await getBcsBytesByObjectId(client, itsObjectId); + const data = itsStruct.parse(bcsBytes); + return '0x' + data.channel.id; +}; + +const getSquidChannelId = async (client, squidObjectId) => { + const bcsBytes = await getBcsBytesByObjectId(client, squidObjectId); + const data = squidStruct.parse(bcsBytes); + return '0x' + data.channel.id; +}; + const getSigners = async (keypair, config, chain, options) => { if (options.signers === 'wallet') { const pubKey = keypair.getPublicKey().toRawBytes(); @@ -142,6 +154,8 @@ module.exports = { findPublishedObject, readMovePackageName, getObjectIdsByObjectTypes, - getChannelId, + getSingletonChannelId, + getItsChannelId, + getSquidChannelId, getSigners, };