diff --git a/src/query/compute.ts b/src/query/compute.ts index a627bc4e..3a62d785 100644 --- a/src/query/compute.ts +++ b/src/query/compute.ts @@ -210,7 +210,7 @@ export class ComputeQuerier { } catch (err) { try { const errorMessageRgx = - /encrypted: (.+?): (?:instantiate|execute|query) contract failed/g; + /encrypted: (.+?): (?:instantiate|execute|query|reply to|migrate) contract failed/g; const rgxMatches = errorMessageRgx.exec(err.message); if (rgxMatches == null || rgxMatches?.length != 2) { throw err; diff --git a/src/secret_network_client.ts b/src/secret_network_client.ts index d74883ea..a6c51267 100644 --- a/src/secret_network_client.ts +++ b/src/secret_network_client.ts @@ -1251,7 +1251,7 @@ export class SecretNetworkClient { } else if (txResp.code !== 0 && rawLog !== "") { try { const errorMessageRgx = - /; message index: (\d+):(?: dispatch: submessages:)* encrypted: (.+?): (?:instantiate|execute|query|reply to) contract failed/g; + /; message index: (\d+):(?: dispatch: submessages:)* encrypted: (.+?): (?:instantiate|execute|query|reply to|migrate) contract failed/g; const rgxMatches = errorMessageRgx.exec(rawLog); if (rgxMatches?.length === 3) { const encryptedError = fromBase64(rgxMatches[2]); diff --git a/test/ibc-hooks-contract/src/contract.rs b/test/ibc-hooks-contract/src/contract.rs index f10438ca..d8b7ac1a 100644 --- a/test/ibc-hooks-contract/src/contract.rs +++ b/test/ibc-hooks-contract/src/contract.rs @@ -1,9 +1,9 @@ use cosmwasm_std::{ entry_point, to_binary, CosmosMsg, DepsMut, Env, IbcMsg, IbcTimeout, MessageInfo, Response, - StdResult, + StdError, StdResult, }; -use crate::msg::{IBCLifecycleComplete, Msg}; +use crate::msg::{IBCLifecycleComplete, MigrateMsg, Msg}; #[entry_point] pub fn instantiate( @@ -93,9 +93,12 @@ pub fn execute(_deps: DepsMut, env: Env, info: MessageInfo, msg: Msg) -> StdResu } #[entry_point] -pub fn migrate(_deps: DepsMut, env: Env, msg: Msg) -> StdResult { - Ok(Response::default().add_attributes(vec![ - ("migrate.env", format!("{:?}", env)), - ("migrate.msg", format!("{:?}", msg)), - ])) +pub fn migrate(_deps: DepsMut, env: Env, msg: MigrateMsg) -> StdResult { + match msg { + MigrateMsg::Nop {} => Ok(Response::default().add_attributes(vec![ + ("migrate.env", format!("{:?}", env)), + ("migrate.msg", format!("{:?}", msg)), + ])), + MigrateMsg::StdError {} => Err(StdError::generic_err("std error")), + } } diff --git a/test/ibc-hooks-contract/src/msg.rs b/test/ibc-hooks-contract/src/msg.rs index 68910584..56b11b21 100644 --- a/test/ibc-hooks-contract/src/msg.rs +++ b/test/ibc-hooks-contract/src/msg.rs @@ -43,3 +43,10 @@ pub enum IBCLifecycleComplete { sequence: u64, }, } + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum MigrateMsg { + Nop {}, + StdError {}, +} diff --git a/test/ibc-hooks.wasm.gz b/test/ibc-hooks.wasm.gz index ccbc2b7f..4042c307 100644 Binary files a/test/ibc-hooks.wasm.gz and b/test/ibc-hooks.wasm.gz differ diff --git a/test/test.ts b/test/test.ts index dc77a386..09ed12fe 100644 --- a/test/test.ts +++ b/test/test.ts @@ -1652,6 +1652,232 @@ describe("tx.compute", () => { ]); }); + test("MsgMigrateContract VmError", async () => { + const { secretjs } = accounts[0]; + + const code_id = await storeSnip20Ibc(secretjs, secretjs.address); + + const { code_hash } = await secretjs.query.compute.codeHashByCodeId({ + code_id, + }); + + let tx = await secretjs.tx.compute.instantiateContract( + { + sender: secretjs.address, + admin: secretjs.address, + code_id, + code_hash, + init_msg: { + name: "Secret SCRT", + admin: secretjs.address, + symbol: "SSCRT", + decimals: 6, + initial_balances: [{ address: secretjs.address, amount: "1" }], + prng_seed: "eW8=", + config: { + public_total_supply: true, + enable_deposit: true, + enable_redeem: true, + enable_mint: false, + enable_burn: false, + }, + supported_denoms: ["uscrt"], + }, + label: `label-${Date.now()}`, + init_funds: [], + }, + { + broadcastCheckIntervalMs: 100, + gasLimit: 5_000_000, + }, + ); + checkInstantiateSuccess(tx); + + const contract_address = MsgInstantiateContractResponse.decode( + tx.data[0], + ).address; + + const { contract_info } = await secretjs.query.compute.contractInfo({ + contract_address, + }); + + expect(contract_info?.admin).toBe(secretjs.address); + + const initHeight = String(tx.height); + + tx = await secretjs.tx.compute.storeCode( + { + sender: secretjs.address, + wasm_byte_code: fs.readFileSync( + `${__dirname}/ibc-hooks.wasm.gz`, + ) as Uint8Array, + source: "", + builder: "", + }, + { + broadcastCheckIntervalMs: 100, + gasLimit: 5_000_000, + }, + ); + if (tx.code !== TxResultCode.Success) { + console.error(tx.rawLog); + } + expect(tx.code).toBe(TxResultCode.Success); + + const new_code_id = MsgStoreCodeResponse.decode(tx.data[0]).code_id; + const { code_hash: new_code_hash } = + await secretjs.query.compute.codeHashByCodeId({ + code_id: new_code_id, + }); + + tx = await secretjs.tx.compute.migrateContract( + { + sender: secretjs.address, + contract_address, + code_id: new_code_id, + code_hash: new_code_hash, + msg: { yolo: {} }, + }, + { + broadcastCheckIntervalMs: 100, + gasLimit: 5_000_000, + }, + ); + + expect(tx.rawLog).toEqual( + "failed to execute message; message index: 0: Error parsing into type ibc_hooks_contract::msg::Msg: unknown variant `yolo`, expected one of `nop`, `wrap_deposit`, `ibc_transfer`, `ibc_lifecycle_complete`: execute contract failed", + ); + + const { entries } = await secretjs.query.compute.contractHistory({ + contract_address, + }); + + expect(entries).toStrictEqual([ + { + code_id: code_id, + msg: '{"name":"Secret SCRT","admin":"secret1ap26qrlp8mcq2pg6r47w43l0y8zkqm8a450s03","symbol":"SSCRT","decimals":6,"initial_balances":[{"address":"secret1ap26qrlp8mcq2pg6r47w43l0y8zkqm8a450s03","amount":"1"}],"prng_seed":"eW8=","config":{"public_total_supply":true,"enable_deposit":true,"enable_redeem":true,"enable_mint":false,"enable_burn":false},"supported_denoms":["uscrt"]}', + operation: "CONTRACT_CODE_HISTORY_OPERATION_TYPE_INIT", + updated: { + block_height: initHeight, + tx_index: "0", + }, + }, + ]); + }); + + test("MsgMigrateContract StdError", async () => { + const { secretjs } = accounts[0]; + + const code_id = await storeSnip20Ibc(secretjs, secretjs.address); + + const { code_hash } = await secretjs.query.compute.codeHashByCodeId({ + code_id, + }); + + let tx = await secretjs.tx.compute.instantiateContract( + { + sender: secretjs.address, + admin: secretjs.address, + code_id, + code_hash, + init_msg: { + name: "Secret SCRT", + admin: secretjs.address, + symbol: "SSCRT", + decimals: 6, + initial_balances: [{ address: secretjs.address, amount: "1" }], + prng_seed: "eW8=", + config: { + public_total_supply: true, + enable_deposit: true, + enable_redeem: true, + enable_mint: false, + enable_burn: false, + }, + supported_denoms: ["uscrt"], + }, + label: `label-${Date.now()}`, + init_funds: [], + }, + { + broadcastCheckIntervalMs: 100, + gasLimit: 5_000_000, + }, + ); + checkInstantiateSuccess(tx); + + const contract_address = MsgInstantiateContractResponse.decode( + tx.data[0], + ).address; + + const { contract_info } = await secretjs.query.compute.contractInfo({ + contract_address, + }); + + expect(contract_info?.admin).toBe(secretjs.address); + + const initHeight = String(tx.height); + + tx = await secretjs.tx.compute.storeCode( + { + sender: secretjs.address, + wasm_byte_code: fs.readFileSync( + `${__dirname}/ibc-hooks.wasm.gz`, + ) as Uint8Array, + source: "", + builder: "", + }, + { + broadcastCheckIntervalMs: 100, + gasLimit: 5_000_000, + }, + ); + if (tx.code !== TxResultCode.Success) { + console.error(tx.rawLog); + } + expect(tx.code).toBe(TxResultCode.Success); + + const new_code_id = MsgStoreCodeResponse.decode(tx.data[0]).code_id; + const { code_hash: new_code_hash } = + await secretjs.query.compute.codeHashByCodeId({ + code_id: new_code_id, + }); + + tx = await secretjs.tx.compute.migrateContract( + { + sender: secretjs.address, + contract_address, + code_id: new_code_id, + code_hash: new_code_hash, + msg: { std_error: {} }, + }, + { + broadcastCheckIntervalMs: 100, + gasLimit: 5_000_000, + }, + ); + + expect(tx.rawLog).toEqual( + "failed to execute message; message index: 0: Generic error: std error: migrate contract failed", + ); + + const { entries } = await secretjs.query.compute.contractHistory({ + contract_address, + }); + + expect(entries).toStrictEqual([ + { + code_id: code_id, + msg: '{"name":"Secret SCRT","admin":"secret1ap26qrlp8mcq2pg6r47w43l0y8zkqm8a450s03","symbol":"SSCRT","decimals":6,"initial_balances":[{"address":"secret1ap26qrlp8mcq2pg6r47w43l0y8zkqm8a450s03","amount":"1"}],"prng_seed":"eW8=","config":{"public_total_supply":true,"enable_deposit":true,"enable_redeem":true,"enable_mint":false,"enable_burn":false},"supported_denoms":["uscrt"]}', + operation: "CONTRACT_CODE_HISTORY_OPERATION_TYPE_INIT", + updated: { + block_height: initHeight, + tx_index: "0", + }, + }, + ]); + }); + test("MsgUpdateAdmin", async () => { const { secretjs } = accounts[0];