Skip to content

Commit

Permalink
add proposal type storeInstantiate
Browse files Browse the repository at this point in the history
  • Loading branch information
eguajardo committed Jul 23, 2024
1 parent 0dd064d commit 6d9cd8c
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 11 deletions.
14 changes: 14 additions & 0 deletions cosmwasm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,17 @@ 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"`

### 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
```
6 changes: 5 additions & 1 deletion cosmwasm/deploy-contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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) {
Expand Down
54 changes: 51 additions & 3 deletions cosmwasm/submit-proposal.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,21 @@ const {
getChains,
decodeProposalAttributes,
encodeStoreCodeProposal,
encodeStoreInstantiateProposal,
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 { isNumber, saveConfig, loadConfig, printInfo, prompt } = require('../evm/utils');
const {
StoreCodeProposal,
StoreAndInstantiateContractProposal,
InstantiateContractProposal,
InstantiateContract2Proposal,
} = require('cosmjs-types/cosmwasm/wasm/v1/proposal');

const { Command, Option } = require('commander');

Expand Down Expand Up @@ -73,6 +79,36 @@ 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) => {
const codes = await client.getCodes(); // TODO: create custom function to retrieve codes more efficiently and with pagination
let codeId;
Expand Down Expand Up @@ -107,6 +143,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);
Expand Down Expand Up @@ -147,6 +185,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);

Expand Down Expand Up @@ -205,7 +251,9 @@ const programHandler = () => {
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('--proposalType <proposalType>', 'proposal type')
.choices(['store', 'storeInstantiate', 'instantiate'])
.makeOptionMandatory(true),
);
program.addOption(new Option('--predictOnly', 'output the predicted changes only').env('PREDICT_ONLY'));

Expand Down
34 changes: 27 additions & 7 deletions cosmwasm/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
StoreAndInstantiateContractProposal,
InstantiateContractProposal,
InstantiateContract2Proposal,
} = 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');
Expand Down Expand Up @@ -403,12 +408,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) {
Expand Down Expand Up @@ -535,6 +534,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;

Expand Down Expand Up @@ -567,6 +577,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));
Expand Down Expand Up @@ -640,6 +659,7 @@ module.exports = {
instantiate2AddressForProposal,
decodeProposalAttributes,
encodeStoreCodeProposal,
encodeStoreInstantiateProposal,
encodeInstantiateProposal,
encodeInstantiate2Proposal,
submitProposal,
Expand Down

0 comments on commit 6d9cd8c

Please sign in to comment.