From 7a9da24bc9a9c2d0278c95de86e58c1995c63c15 Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Tue, 3 Sep 2024 12:08:14 -0400 Subject: [PATCH] test: e2e tests of `cosmosOrchAccount` `getBalance` and `getBalances` --- .../test/account-balance-queries.test.ts | 193 ++++++++++++++++++ multichain-testing/test/chain-queries.test.ts | 2 +- 2 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 multichain-testing/test/account-balance-queries.test.ts diff --git a/multichain-testing/test/account-balance-queries.test.ts b/multichain-testing/test/account-balance-queries.test.ts new file mode 100644 index 000000000000..ad3ea59a9905 --- /dev/null +++ b/multichain-testing/test/account-balance-queries.test.ts @@ -0,0 +1,193 @@ +import anyTest from '@endo/ses-ava/prepare-endo.js'; +import type { TestFn } from 'ava'; +import type { CosmosChainInfo } from '@agoric/orchestration'; +import { + commonSetup, + SetupContextWithWallets, + chainConfig, +} from './support.js'; +import { makeDoOffer } from '../tools/e2e-tools.js'; +import chainInfo from '../starship-chain-info.js'; + +const test = anyTest as TestFn; + +const accounts = ['osmosis', 'cosmoshub', 'agoric']; + +const contractName = 'queryFlows'; +const contractBuilder = + '../packages/builders/scripts/testing/start-query-flows.js'; + +test.before(async t => { + const { deleteTestKeys, setupTestKeys, ...rest } = await commonSetup(t); + deleteTestKeys(accounts).catch(); + const wallets = await setupTestKeys(accounts); + t.context = { ...rest, wallets, deleteTestKeys }; + const { startContract } = rest; + await startContract(contractName, contractBuilder); +}); + +test.after(async t => { + const { deleteTestKeys } = t.context; + deleteTestKeys(accounts); +}); + +const queryAccountBalances = test.macro({ + title: (_, chainName: string) => `Query Account Balances on ${chainName}`, + exec: async (t, chainName: string) => { + const config = chainConfig[chainName]; + if (!config) return t.fail(`Unknown chain: ${chainName}`); + const { + wallets, + provisionSmartWallet, + vstorageClient, + retryUntilCondition, + } = t.context; + + const agoricAddr = wallets[chainName]; + const wdUser1 = await provisionSmartWallet(agoricAddr, { + BLD: 100n, + IST: 100n, + }); + t.log(`provisioning agoric smart wallet for ${agoricAddr}`); + + const doOffer = makeDoOffer(wdUser1); + t.log(`${chainName} makeAccountAndGetBalancesQuery offer`); + const offerId = `${chainName}-makeAccountAndGetBalancesQuery-${Date.now()}`; + + await doOffer({ + id: offerId, + invitationSpec: { + source: 'agoricContract', + instancePath: [contractName], + callPipe: [['makeAccountAndGetBalancesQueryInvitation']], + }, + offerArgs: { chainName }, + proposal: {}, + }); + + const offerResult = await retryUntilCondition( + () => vstorageClient.queryData(`published.wallet.${agoricAddr}`), + ({ status }) => status.id === offerId && (status.result || status.error), + `${offerId} offer result is in vstorage`, + { + maxRetries: 15, + }, + ); + t.log('Account Balances Query Offer Result', offerResult); + + const { icqEnabled } = (chainInfo as Record)[ + chainName + ]; + t.log( + icqEnabled + ? 'ICQ Enabled expecting offer result.' + : 'ICQ Disabled expecting offer error', + ); + + const { + status: { result, error }, + } = offerResult; + if (icqEnabled) { + t.is(error, undefined, 'No error observed for supported chain'); + const balances = JSON.parse(result); + t.truthy(balances, 'Result is parsed successfully'); + t.true(Array.isArray(balances), 'Balances is an array'); + t.is(balances.length, 0, 'Balances are empty'); + } else { + t.truthy(error, 'Error observed for unsupported chain'); + t.regex( + error, + /Queries not available for chain/i, + 'Correct error message for unsupported chain', + ); + } + }, +}); + +const queryAccountBalance = test.macro({ + title: (_, chainName: string) => `Query Account Balance on ${chainName}`, + exec: async (t, chainName: string) => { + const config = chainConfig[chainName]; + if (!config) return t.fail(`Unknown chain: ${chainName}`); + const { + wallets, + provisionSmartWallet, + vstorageClient, + retryUntilCondition, + useChain, + } = t.context; + + const { + chainInfo: { + chain: { staking }, + }, + } = useChain(chainName); + const denom = staking?.staking_tokens?.[0].denom; + if (!denom) throw Error(`no denom for ${chainName}`); + + const agoricAddr = wallets[chainName]; + const wdUser1 = await provisionSmartWallet(agoricAddr, { + BLD: 100n, + IST: 100n, + }); + t.log(`provisioning agoric smart wallet for ${agoricAddr}`); + + const doOffer = makeDoOffer(wdUser1); + t.log(`${chainName} makeAccountAndGetBalanceQuery offer`); + const offerId = `${chainName}-makeAccountAndGetBalanceQuery-${Date.now()}`; + + await doOffer({ + id: offerId, + invitationSpec: { + source: 'agoricContract', + instancePath: [contractName], + callPipe: [['makeAccountAndGetBalanceQueryInvitation']], + }, + offerArgs: { chainName, denom }, + proposal: {}, + }); + + const offerResult = await retryUntilCondition( + () => vstorageClient.queryData(`published.wallet.${agoricAddr}`), + ({ status }) => status.id === offerId && (status.result || status.error), + `${offerId} offer result is in vstorage`, + { + maxRetries: 25, // wait about 90s for: 1) ica conn, 2) icq conn, 3) query + }, + ); + t.log('Account Balance Query Offer Result', offerResult); + const { icqEnabled } = (chainInfo as Record)[ + chainName + ]; + t.log( + icqEnabled + ? 'ICQ Enabled, expecting offer result.' + : 'ICQ Disabled, expecting offer error', + ); + + const { + status: { result, error }, + } = offerResult; + if (icqEnabled) { + t.is(error, undefined, 'No error observed for supported chain'); + const parsedBalance = JSON.parse(result); + t.truthy(parsedBalance, 'Result is parsed successfully'); + + t.truthy(parsedBalance, 'Balance object exists'); + t.is(parsedBalance.denom, denom, 'Correct denom in balance'); + t.is(parsedBalance.value, '[0n]', 'Balance amount is 0n'); + } else { + t.truthy(error, 'Error observed for unsupported chain'); + t.regex( + error, + /Queries not available for chain/i, + 'Correct error message for unsupported chain', + ); + } + }, +}); + +test.serial(queryAccountBalances, 'osmosis'); +test.serial(queryAccountBalances, 'cosmoshub'); +test.serial(queryAccountBalance, 'osmosis'); +test.serial(queryAccountBalance, 'cosmoshub'); diff --git a/multichain-testing/test/chain-queries.test.ts b/multichain-testing/test/chain-queries.test.ts index 239a86520b90..70d5e73bbf43 100644 --- a/multichain-testing/test/chain-queries.test.ts +++ b/multichain-testing/test/chain-queries.test.ts @@ -110,7 +110,7 @@ const queryICQChain = test.macro({ const offerResult = await retryUntilCondition( () => vstorageClient.queryData(`published.wallet.${agoricAddr}`), ({ status }) => status.id === offerId && (status.result || status.error), - `${offerId} continuing invitation is in vstorage`, + `${offerId} offer result is in vstorage`, { maxRetries: 15, },