Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(sui)!: support sui amplifier deployment #342

Merged
merged 12 commits into from
Aug 27, 2024
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,9 @@
Install dependencies via
`npm ci`

[EVM deployment instructions](./evm/README.md)
## Deployment Instructions

- [EVM](./evm/README.md)
- [Cosmwasm](./cosmwasm/README.md)
- [Sui](./sui/README.md)
- [Stellar](./stellar/README.md)
46 changes: 39 additions & 7 deletions common/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const readlineSync = require('readline-sync');
const { CosmWasmClient } = require('@cosmjs/cosmwasm-stargate');
const { ethers } = require('hardhat');
const {
utils: { keccak256, hexlify },
utils: { keccak256, hexlify, defaultAbiCoder },
} = ethers;
const { normalizeBech32 } = require('@cosmjs/encoding');

Expand Down Expand Up @@ -347,6 +347,17 @@ const isValidCosmosAddress = (str) => {
}
};

const getSaltFromKey = (key) => {
return keccak256(defaultAbiCoder.encode(['string'], [key.toString()]));
};

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'));
};

async function getDomainSeparator(config, chain, options) {
// Allow any domain separator for local deployments or `0x` if not provided
if (options.env === 'local') {
Expand Down Expand Up @@ -377,22 +388,38 @@ async function getDomainSeparator(config, chain, options) {
throw new Error(`missing or invalid chain ID`);
}

const expectedDomainSeparator = calculateDomainSeparator(chain.axelarId, routerAddress, chainId);

if (options.domainSeparator === 'offline') {
printInfo('Computed domain separator offline');
return expectedDomainSeparator;
}

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;
return expectedDomainSeparator;
}

const getContractConfig = async (config, chain) => {
const key = Buffer.from('config');
const getChainConfig = (config, chainName) => {
const chainConfig = config.chains[chainName] || config[chainName];

if (!chainConfig) {
throw new Error(`Chain ${chainName} not found in config`);
}

return chainConfig;
};

const getMultisigProof = async (config, chain, multisigSessionId) => {
const query = { proof: { multisig_session_id: `${multisigSessionId}` } };
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 value = await client.queryContractSmart(config.axelar.contracts.MultisigProver[chain].address, query);
return value;
};

const calculateDomainSeparator = (chain, router, network) => keccak256(Buffer.from(`${chain}${router}${network}`));
Expand Down Expand Up @@ -429,4 +456,9 @@ module.exports = {
timeout,
validateParameters,
getDomainSeparator,
getChainConfig,
getMultisigProof,
getContractConfig,
getSaltFromKey,
calculateDomainSeparator,
};
6 changes: 3 additions & 3 deletions cosmwasm/deploy-contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ require('dotenv').config();
const { isNil } = require('lodash');

const { CHAIN_ENVIRONMENTS } = require('../common');
const { isNumber, printInfo, loadConfig, saveConfig, prompt } = require('../evm/utils');
const { isNumber, printInfo, loadConfig, saveConfig, prompt, getChainConfig } = require('../evm/utils');
const {
prepareWallet,
prepareClient,
Expand All @@ -24,8 +24,8 @@ const upload = (client, wallet, chainName, config, options) => {
axelar: {
contracts: { [contractName]: contractConfig },
},
chains: { [chainName]: chainConfig },
} = config;
const chainConfig = chainName === 'none' ? undefined : getChainConfig(config, chainName);

if (!fetchCodeId && (!reuseCodeId || isNil(contractConfig.codeId))) {
printInfo('Uploading contract binary');
Expand Down Expand Up @@ -53,7 +53,7 @@ const upload = (client, wallet, chainName, config, options) => {
.then(() => ({ wallet, client }));
}

printInfo('Skipping upload. Reusing previously uploaded binary');
printInfo('Skipping upload. Reusing previously uploaded bytecode');
return Promise.resolve({ wallet, client });
};

Expand Down
2 changes: 1 addition & 1 deletion cosmwasm/submit-proposal.js
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ const programHandler = () => {
.env('ENV'),
);
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('-a, --artifactPath <artifactPath>', 'artifact path').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'));

Expand Down
35 changes: 17 additions & 18 deletions cosmwasm/utils.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
'use strict';

const zlib = require('zlib');
const { ethers } = require('hardhat');
const {
utils: { keccak256 },
} = ethers;
const { createHash } = require('crypto');

const { readFileSync } = require('fs');
Expand All @@ -20,7 +16,16 @@ const {
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 {
isString,
isStringArray,
isKeccak256Hash,
isNumber,
toBigNumberString,
getChainConfig,
getSaltFromKey,
calculateDomainSeparator,
} = require('../common');
const { normalizeBech32 } = require('@cosmjs/encoding');

const governanceAddress = 'axelar10d07y265gmmuvt4z0w9aw880jnsr700j7v9daj';
Expand All @@ -46,8 +51,6 @@ const isValidCosmosAddress = (str) => {

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 getLabel = ({ contractName, label }) => label || contractName;
Expand All @@ -66,11 +69,7 @@ const getChains = (config, { chainNames, 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`);
}
chains.every((chain) => chain === 'none' || getChainConfig(config, chain));
milapsheth marked this conversation as resolved.
Show resolved Hide resolved

return chains;
};
Expand Down Expand Up @@ -216,7 +215,7 @@ const makeNexusGatewayInstantiateMsg = ({ nexus }, { Router: { address: router }
const makeVotingVerifierInstantiateMsg = (
contractConfig,
{ ServiceRegistry: { address: serviceRegistryAddress }, Rewards: { address: rewardsAddress } },
{ id: chainId },
{ axelarId: chainId },
) => {
const {
[chainId]: {
Expand Down Expand Up @@ -286,7 +285,7 @@ const makeVotingVerifierInstantiateMsg = (
};
};

const makeGatewayInstantiateMsg = ({ Router: { address: routerAddress }, VotingVerifier }, { id: chainId }) => {
const makeGatewayInstantiateMsg = ({ Router: { address: routerAddress }, VotingVerifier }, { axelarId: chainId }) => {
const {
[chainId]: { address: verifierAddress },
} = VotingVerifier;
Expand All @@ -305,8 +304,8 @@ const makeGatewayInstantiateMsg = ({ Router: { address: routerAddress }, VotingV
const makeMultisigProverInstantiateMsg = (config, chainName) => {
const {
axelar: { contracts, chainId: axelarChainId },
chains: { [chainName]: chainConfig },
} = config;
const chainConfig = getChainConfig(config, chainName);

const { axelarId: chainId } = chainConfig;

Expand Down Expand Up @@ -424,8 +423,8 @@ const makeMultisigProverInstantiateMsg = (config, chainName) => {
const makeInstantiateMsg = (contractName, chainName, config) => {
const {
axelar: { contracts },
chains: { [chainName]: chainConfig },
} = config;
const chainConfig = getChainConfig(config, chainName);

const { [contractName]: contractConfig } = contracts;

Expand Down Expand Up @@ -618,12 +617,12 @@ const getExecuteContractParams = (config, options, chainName) => {
axelar: {
contracts: { [contractName]: contractConfig },
},
chains: { [chainName]: chainConfig },
} = config;
const chainConfig = getChainConfig(config, chainName);

return {
...getSubmitProposalParams(options),
contract: chainConfig ? contractConfig[chainConfig.axelarId].address : contractConfig.address,
contract: contractConfig[chainConfig.axelarId]?.address || contractConfig.address,
msg: Buffer.from(msg),
};
};
Expand Down
13 changes: 1 addition & 12 deletions evm/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const {
sleep,
findProjectRoot,
timeout,
getSaltFromKey,
} = require('../common');
const {
create3DeployContract,
Expand All @@ -48,10 +49,6 @@ const IDeployer = require('@axelar-network/axelar-gmp-sdk-solidity/interfaces/ID
const { exec } = require('child_process');
const { verifyContract } = require(`${__dirname}/../axelar-chains-config`);

const getSaltFromKey = (key) => {
return keccak256(defaultAbiCoder.encode(['string'], [key.toString()]));
};

const deployCreate = async (wallet, contractJson, args = [], options = {}, verifyOptions = null, chain = {}) => {
const factory = new ContractFactory(contractJson.abi, contractJson.bytecode, wallet);

Expand Down Expand Up @@ -493,13 +490,6 @@ const getEVMAddresses = async (config, chain, options = {}) => {
return { addresses, weights, threshold, keyID: evmAddresses.key_id };
};

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 getAmplifierKeyAddresses = async (config, chain) => {
const client = await CosmWasmClient.connect(config.axelar.rpc);
const { id: verifierSetId, verifier_set: verifierSet } = await client.queryContractSmart(
Expand Down Expand Up @@ -1062,7 +1052,6 @@ module.exports = {
getDeployOptions,
isValidChain,
getAmplifierKeyAddresses,
getContractConfig,
relayTransaction,
getDeploymentTx,
getWeightedSigners,
Expand Down
18 changes: 9 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions sui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,11 @@ node sui/gateway.js rotate --signers wallet --proof wallet --currentNonce test -

Use the same nonce for `--currentNonce` as the `--nonce` when deploying the gateway.

To submit a proof constructed on Amplifier, run the following with the multisig session id,
```bash
node sui/gateway.js submitProof [multisig session id]
```

### Multisig

To create a Multisig, follow the documentation [here](https://docs.sui.io/guides/developer/cryptography/multisig).
Expand Down
9 changes: 7 additions & 2 deletions sui/deploy-contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ async function postDeployAxelarGateway(published, keypair, client, config, chain

// Update chain configuration
chain.contracts.AxelarGateway = {
address: packageId,
objects: {
Gateway: gateway,
RelayerDiscovery: relayerDiscovery,
Expand Down Expand Up @@ -248,7 +249,8 @@ async function deploy(keypair, client, supportedContract, config, chain, options
// Deploy package
const published = await deployPackage(packageDir, client, keypair, options);

printInfo(`Deployed ${packageName}`, published.publishTxn.digest);
printInfo(`Deployed ${packageName} Package`, published.packageId);
printInfo(`Deployed ${packageName} Tx`, published.publishTxn.digest);

// Update chain configuration with deployed contract address
chain.contracts[packageName] = {
Expand Down Expand Up @@ -325,7 +327,10 @@ const GATEWAY_CMD_OPTIONS = [
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(
'--domainSeparator <domainSeparator>',
'domain separator (pass in the keccak256 hash value OR "offline" meaning that its computed locally)',
),
new Option('--nonce <nonce>', 'nonce for the signer (defaults to HashZero)'),
new Option('--previousSigners <previousSigners>', 'number of previous signers to retain').default('15'),
];
Expand Down
Loading
Loading