Skip to content

Commit

Permalink
feat(cosmwasm): add subcommand to register a chain on ITS hub through…
Browse files Browse the repository at this point in the history
… governance proposal (#449)
  • Loading branch information
eguajardo authored Nov 27, 2024
1 parent cdf95ec commit bc93634
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 2 deletions.
11 changes: 11 additions & 0 deletions common/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,16 @@ const getMultisigProof = async (config, chain, multisigSessionId) => {

const calculateDomainSeparator = (chain, router, network) => keccak256(Buffer.from(`${chain}${router}${network}`));

const getItsEdgeContract = (chainConfig) => {
const itsEdgeContract = chainConfig.contracts.InterchainTokenService?.address || chainConfig.contracts.ITS?.objects?.ChannelId;

if (!itsEdgeContract) {
throw new Error(`Missing ITS edge contract for chain ${chainConfig.name}`);
}

return itsEdgeContract;
};

module.exports = {
loadConfig,
saveConfig,
Expand Down Expand Up @@ -478,4 +488,5 @@ module.exports = {
getAmplifierContractOnchainConfig,
getSaltFromKey,
calculateDomainSeparator,
getItsEdgeContract,
};
37 changes: 37 additions & 0 deletions cosmwasm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,43 @@ Example usage:
node cosmwasm/submit-proposal.js 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"}}'
```

### Register chain on ITS Hub through governance proposal

To submit a governance proposal to register an ITS chain, use the `submit-proposal` script with the `its-hub-register-chains <chains...>` command. The `chains` argument is used to pass a list of chains to register on ITS hub.

**Prerequisites**: ITS hub contract configuration in json file must include the following attributes per chain:

| Attribute | Description | EVM | Sui |
| --------------------------- | ------------------------------------------------------------------------------------------ | --- | --- |
| `maxUintBits` | Number of bits for the chain's maximum uint representation | 256 | 64 |
| `maxDecimalsWhenTruncating` | Maximum decimal places allowed when truncating ITS token amounts transferred to this chain | 255 | 6 |

For EVM chains, the values above are used by default if not specified explicitly.

Example configuration:

```
"axelar": {
"contracts": {
...
"InterchainTokenService": {
...
"some-sui-chain": {
"maxUintBits": 64,
"maxDecimalsWhenTruncating": 6,
}
}
...
}
}
```

Example usage:

```
node cosmwasm/submit-proposal.js its-hub-register-chains avalanche-fuji sui-test2 -t "Proposal title" -d "Proposal description" --deposit 100000000 -r $RUN_AS_ACCOUNT
```

### Submit a proposal to change a parameter

To submit a governance proposal to change a parameter, use the `submit-proposal` script with the `paramChange` command. The `--changes` option should be used to pass a JSON string representing an array of parameter changes.
Expand Down
39 changes: 37 additions & 2 deletions cosmwasm/submit-proposal.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const {
getAmplifierBaseContractConfig,
getAmplifierContractConfig,
updateCodeId,
getChainTruncationParams,
decodeProposalAttributes,
encodeStoreCodeProposal,
encodeStoreInstantiateProposal,
Expand All @@ -27,7 +28,7 @@ const {
submitProposal,
makeInstantiateMsg,
} = require('./utils');
const { saveConfig, loadConfig, printInfo, prompt } = require('../common');
const { saveConfig, loadConfig, printInfo, prompt, getChainConfig, getItsEdgeContract } = require('../common');
const {
StoreCodeProposal,
StoreAndInstantiateContractProposal,
Expand Down Expand Up @@ -167,6 +168,30 @@ const execute = async (client, wallet, config, options) => {
await callSubmitProposal(client, wallet, config, options, proposal);
};

const registerItsChain = async (client, wallet, config, options) => {
const chains = options.chains.map((chain) => {
const chainConfig = getChainConfig(config, chain);
const { maxUintBits, maxDecimalsWhenTruncating } = getChainTruncationParams(config, chainConfig);

const itsEdgeContract = getItsEdgeContract(chainConfig);

return {
chain: chainConfig.axelarId,
its_edge_contract: itsEdgeContract,
truncation: {
max_uint: (2n ** BigInt(maxUintBits) - 1n).toString(),
max_decimals_when_truncating: maxDecimalsWhenTruncating,
},
};
});

await execute(client, wallet, config, {
...options,
contractName: 'InterchainTokenService',
msg: `{ "register_chains": { "chains": ${JSON.stringify(chains)} } }`,
});
};

const paramChange = async (client, wallet, config, options) => {
const proposal = encodeParameterChangeProposal(options);

Expand Down Expand Up @@ -256,12 +281,22 @@ const programHandler = () => {

const executeCmd = program
.command('execute')
.description('Submit a execute wasm contract proposal')
.description('Submit an execute wasm contract proposal')
.action((options) => {
mainProcessor(execute, options);
});
addAmplifierOptions(executeCmd, { contractOptions: true, executeProposalOptions: true, proposalOptions: true, runAs: true });

const registerItsChainCmd = program
.command('its-hub-register-chains')
.description('Submit an execute wasm contract proposal to register an ITS chain')
.argument('<chains...>', 'list of chains to register on ITS hub')
.action((chains, options) => {
options.chains = chains;
mainProcessor(registerItsChain, options);
});
addAmplifierOptions(registerItsChainCmd, { registerItsChainOptions: true, proposalOptions: true, runAs: true });

const paramChangeCmd = program
.command('paramChange')
.description('Submit a parameter change proposal')
Expand Down
23 changes: 23 additions & 0 deletions cosmwasm/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,13 @@ const {
getChainConfig,
getSaltFromKey,
calculateDomainSeparator,
validateParameters,
} = require('../common');
const { normalizeBech32 } = require('@cosmjs/encoding');

const DEFAULT_MAX_UINT_BITS_EVM = 256;
const DEFAULT_MAX_DECIMALS_WHEN_TRUNCATING_EVM = 255;

const governanceAddress = 'axelar10d07y265gmmuvt4z0w9aw880jnsr700j7v9daj';

const prepareWallet = async ({ mnemonic }) => await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, { prefix: 'axelar' });
Expand Down Expand Up @@ -606,6 +610,24 @@ const fetchCodeIdFromCodeHash = async (client, contractBaseConfig) => {
return codeId;
};

const getChainTruncationParams = (config, chainConfig) => {
const key = chainConfig.axelarId.toLowerCase();
const chainTruncationParams = config.axelar.contracts.InterchainTokenService[key];

let maxUintBits = chainTruncationParams?.maxUintBits;
let maxDecimalsWhenTruncating = chainTruncationParams?.maxDecimalsWhenTruncating;

// set EVM default values
if (chainConfig.chainType === 'evm') {
maxUintBits = maxUintBits || DEFAULT_MAX_UINT_BITS_EVM;
maxDecimalsWhenTruncating = maxDecimalsWhenTruncating || DEFAULT_MAX_DECIMALS_WHEN_TRUNCATING_EVM;
}

validateParameters({ isValidNumber: { maxUintBits, maxDecimalsWhenTruncating } });

return { maxUintBits, maxDecimalsWhenTruncating };
};

const getInstantiatePermission = (accessType, addresses) => {
return {
permission: accessType,
Expand Down Expand Up @@ -840,6 +862,7 @@ module.exports = {
instantiateContract,
makeInstantiateMsg,
fetchCodeIdFromCodeHash,
getChainTruncationParams,
decodeProposalAttributes,
encodeStoreCodeProposal,
encodeStoreInstantiateProposal,
Expand Down

0 comments on commit bc93634

Please sign in to comment.