From 092056be6609b4309282436288e99b63321c58b7 Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Thu, 12 Dec 2024 22:59:47 -0500 Subject: [PATCH 1/3] test: advance and settle as a macro - include `agoric` and `noble` EUD destinations --- .../test/fast-usdc/fast-usdc.test.ts | 225 +++++++++--------- 1 file changed, 116 insertions(+), 109 deletions(-) diff --git a/multichain-testing/test/fast-usdc/fast-usdc.test.ts b/multichain-testing/test/fast-usdc/fast-usdc.test.ts index 8997384e031..103948a4118 100644 --- a/multichain-testing/test/fast-usdc/fast-usdc.test.ts +++ b/multichain-testing/test/fast-usdc/fast-usdc.test.ts @@ -34,7 +34,7 @@ const accounts = [...keys(oracleMnemonics), 'lp']; const contractName = 'fastUsdc'; const contractBuilder = '../packages/builders/scripts/fast-usdc/init-fast-usdc.js'; -const LP_DEPOSIT_AMOUNT = 10_000_000n; +const LP_DEPOSIT_AMOUNT = 8_000n * 10n ** 6n; test.before(async t => { const { setupTestKeys, ...common } = await commonSetup(t); @@ -79,7 +79,7 @@ test.before(async t => { // save an LP in test context const lpUser = await provisionSmartWallet(wallets['lp'], { - USDC: 100n, + USDC: 8_000n, BLD: 100n, }); @@ -187,129 +187,136 @@ test.serial('lp deposits', async t => { ); }); -test.serial('advance and settlement', async t => { - const { - nobleTools, - nobleAgoricChannelId, - oracleWds, - retryUntilCondition, - useChain, - usdcOnOsmosis, - vstorageClient, - } = t.context; - - // EUD wallet on osmosis - const eudWallet = await createWallet(useChain('osmosis').chain.bech32_prefix); - const EUD = (await eudWallet.getAccounts())[0].address; - - // parameterize agoric address - const { settlementAccount } = await vstorageClient.queryData( - `published.${contractName}`, - ); - t.log('settlementAccount address', settlementAccount); +const advanceAndSettleScenario = test.macro({ + title: (_, mintAmt: bigint, eudChain: string) => + `advance ${mintAmt} uusdc to ${eudChain} and settle`, + exec: async (t, mintAmt: bigint, eudChain: string) => { + const { + nobleTools, + nobleAgoricChannelId, + oracleWds, + retryUntilCondition, + useChain, + usdcOnOsmosis, + vstorageClient, + } = t.context; + + // EUD wallet on the specified chain + const eudWallet = await createWallet( + useChain(eudChain).chain.bech32_prefix, + ); + const EUD = (await eudWallet.getAccounts())[0].address; + t.log(`EUD wallet created: ${EUD}`); - const recipientAddress = encodeAddressHook(settlementAccount, { EUD }); - t.log('recipientAddress', recipientAddress); + // parameterize agoric address + const { settlementAccount } = await vstorageClient.queryData( + `published.${contractName}`, + ); + t.log('settlementAccount address', settlementAccount); - // register forwarding address on noble - const txRes = nobleTools.registerForwardingAcct( - nobleAgoricChannelId, - recipientAddress, - ); - t.is(txRes?.code, 0, 'registered forwarding account'); + const recipientAddress = encodeAddressHook(settlementAccount, { EUD }); + t.log('recipientAddress', recipientAddress); - const { address: userForwardingAddr } = nobleTools.queryForwardingAddress( - nobleAgoricChannelId, - recipientAddress, - ); - t.log('got forwardingAddress', userForwardingAddr); - - const mintAmount = 800_000n; - - // TODO export CctpTxEvidence type - const evidence = harden({ - blockHash: - '0x90d7343e04f8160892e94f02d6a9b9f255663ed0ac34caca98544c8143fee665', - blockNumber: 21037663n, - txHash: `0xc81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff3875527617${makeRandomDigits(makeRandomNumber(), 2n)}`, - tx: { - amount: mintAmount, - forwardingAddress: userForwardingAddr, - }, - aux: { - forwardingChannel: nobleAgoricChannelId, + // register forwarding address on noble + const txRes = nobleTools.registerForwardingAcct( + nobleAgoricChannelId, recipientAddress, - }, - chainId: 42161, - }); - - console.log('User initiates evm mint', evidence.txHash); - - // submit evidences - await Promise.all( - oracleWds.map(makeDoOffer).map((doOffer, i) => - doOffer({ - id: `${Date.now()}-evm-evidence`, - invitationSpec: { - source: 'continuing', - previousOffer: toOracleOfferId(i), - invitationMakerName: 'SubmitEvidence', - invitationArgs: [evidence], - }, - proposal: {}, - }), - ), - ); - - const queryClient = makeQueryClient( - await useChain('osmosis').getRestEndpoint(), - ); + ); + t.is(txRes?.code, 0, 'registered forwarding account'); - await t.notThrowsAsync(() => - retryUntilCondition( - () => queryClient.queryBalance(EUD, usdcOnOsmosis), - ({ balance }) => !!balance?.amount && BigInt(balance.amount) < mintAmount, - `${EUD} advance available from fast-usdc`, - { - // this resolves quickly, so _decrease_ the interval so the timing is more apparent - retryIntervalMs: 500, + const { address: userForwardingAddr } = nobleTools.queryForwardingAddress( + nobleAgoricChannelId, + recipientAddress, + ); + t.log('got forwardingAddress', userForwardingAddr); + + // TODO export CctpTxEvidence type + const evidence = harden({ + blockHash: + '0x90d7343e04f8160892e94f02d6a9b9f255663ed0ac34caca98544c8143fee665', + blockNumber: 21037663n, + txHash: `0xc81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff3875527617${makeRandomDigits(makeRandomNumber(), 2n)}`, + tx: { + amount: mintAmt, + forwardingAddress: userForwardingAddr, }, - ), - ); + aux: { + forwardingChannel: nobleAgoricChannelId, + recipientAddress, + }, + chainId: 42161, + }); + + console.log('User initiates evm mint:', evidence.txHash); + + // submit evidences + await Promise.all( + oracleWds.map(makeDoOffer).map((doOffer, i) => + doOffer({ + id: `${Date.now()}-evm-evidence`, + invitationSpec: { + source: 'continuing', + previousOffer: toOracleOfferId(i), + invitationMakerName: 'SubmitEvidence', + invitationArgs: [evidence], + }, + proposal: {}, + }), + ), + ); - const queryTxStatus = async () => - vstorageClient.queryData( - `published.${contractName}.status.${evidence.txHash}`, + const queryClient = makeQueryClient( + await useChain(eudChain).getRestEndpoint(), ); - const assertTxStatus = async (status: string) => - t.notThrowsAsync(() => + await t.notThrowsAsync(() => retryUntilCondition( - () => queryTxStatus(), - txStatus => { - console.log('tx status', txStatus); - return txStatus === status; - }, - `${evidence.txHash} is ${status}`, + () => queryClient.queryBalance(EUD, usdcOnOsmosis), + ({ balance }) => !!balance?.amount && BigInt(balance.amount) < mintAmt, + `${EUD} advance available from fast-usdc`, + // this resolves quickly, so _decrease_ the interval so the timing is more apparent + { retryIntervalMs: 500 }, ), ); - await assertTxStatus('ADVANCED'); - console.log('Advance completed, waiting for mint...'); - - nobleTools.mockCctpMint(mintAmount, userForwardingAddr); - await t.notThrowsAsync(() => - retryUntilCondition( - () => vstorageClient.queryData(`published.${contractName}.poolMetrics`), - ({ encumberedBalance }) => - encumberedBalance && isEmpty(encumberedBalance), - 'encumberedBalance returns to 0', - ), - ); + const queryTxStatus = async () => + vstorageClient.queryData( + `published.${contractName}.status.${evidence.txHash}`, + ); + + const assertTxStatus = async (status: string) => + t.notThrowsAsync(() => + retryUntilCondition( + () => queryTxStatus(), + txStatus => { + console.log('tx status', txStatus); + return txStatus === status; + }, + `${evidence.txHash} is ${status}`, + ), + ); + + await assertTxStatus('ADVANCED'); + console.log('Advance completed, waiting for mint...'); + + nobleTools.mockCctpMint(mintAmt, userForwardingAddr); + await t.notThrowsAsync(() => + retryUntilCondition( + () => vstorageClient.queryData(`published.${contractName}.poolMetrics`), + ({ encumberedBalance }) => + encumberedBalance && isEmpty(encumberedBalance), + 'encumberedBalance returns to 0', + ), + ); - await assertTxStatus('DISBURSED'); + await assertTxStatus('DISBURSED'); + }, }); +test.serial(advanceAndSettleScenario, LP_DEPOSIT_AMOUNT / 4n, 'osmosis'); +test.serial(advanceAndSettleScenario, LP_DEPOSIT_AMOUNT / 8n, 'noble'); +test.serial(advanceAndSettleScenario, LP_DEPOSIT_AMOUNT / 5n, 'agoric'); + test.serial('lp withdraws', async t => { const { lpUser, From 1eb9eb163775ac03e3a1e049cc21aa702e11ad17 Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Thu, 12 Dec 2024 23:32:20 -0500 Subject: [PATCH 2/3] chore: "oracles accept" handles already accepted invs - mainly to facilitate active development; allows test to be run more than once --- .../test/fast-usdc/fast-usdc.test.ts | 34 ++++++++++++++++--- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/multichain-testing/test/fast-usdc/fast-usdc.test.ts b/multichain-testing/test/fast-usdc/fast-usdc.test.ts index 103948a4118..92b493fdccd 100644 --- a/multichain-testing/test/fast-usdc/fast-usdc.test.ts +++ b/multichain-testing/test/fast-usdc/fast-usdc.test.ts @@ -103,13 +103,33 @@ const toOracleOfferId = (idx: number) => `oracle${idx + 1}-accept`; test.serial('oracles accept', async t => { const { oracleWds, retryUntilCondition, vstorageClient, wallets } = t.context; + const brands = await vstorageClient.queryData('published.agoricNames.brand'); + const { Invitation } = Object.fromEntries(brands); - const instances = await vstorageClient.queryData( - 'published.agoricNames.instance', - ); - const instance = fromEntries(instances)[contractName]; + const description = 'oracle operator invitation'; + + // ensure we have an unused (or used) oracle invitation in each purse + let hasAccepted = false; + for (const name of keys(oracleMnemonics)) { + const { offerToUsedInvitation, purses } = await vstorageClient.queryData( + `published.wallet.${wallets[name]}.current`, + ); + const { value: invitations } = balancesFromPurses(purses)[Invitation]; + const hasInvitation = invitations.some(x => x.description === description); + const usedInvitation = offerToUsedInvitation?.[0]?.[0] === `${name}-accept`; + t.log({ name, hasInvitation, usedInvitation }); + t.true(hasInvitation || usedInvitation, 'has or accepted invitation'); + if (usedInvitation) hasAccepted = true; + } + // if the oracles have already accepted, skip the rest of the test this is + // primarily to facilitate active development but could support testing on + // images where operator invs are already accepted + if (hasAccepted) return t.pass(); // accept oracle operator invitations + const instance = fromEntries( + await vstorageClient.queryData('published.agoricNames.instance'), + )[contractName]; await Promise.all( oracleWds.map(makeDoOffer).map((doOffer, i) => doOffer({ @@ -117,7 +137,7 @@ test.serial('oracles accept', async t => { invitationSpec: { source: 'purse', instance, - description: 'oracle operator invitation', // TODO export/import INVITATION_MAKERS_DESC + description, }, proposal: {}, }), @@ -387,3 +407,7 @@ test.serial('lp withdraws', async t => { ), ); }); + +test.todo('insufficient LP funds; forward path'); +test.todo('mint while Advancing; still Disbursed'); +test.todo('transfer failed (e.g. to cosmos, not in env)'); From 4ce154090fc3340e6685104c576fa702bfc184d4 Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Mon, 16 Dec 2024 17:07:27 -0600 Subject: [PATCH 3/3] test(acceptance): skip make proposal and vote; seems flaky --- a3p-integration/proposals/z:acceptance/governance.test.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/a3p-integration/proposals/z:acceptance/governance.test.js b/a3p-integration/proposals/z:acceptance/governance.test.js index 353590370eb..eaad279754d 100644 --- a/a3p-integration/proposals/z:acceptance/governance.test.js +++ b/a3p-integration/proposals/z:acceptance/governance.test.js @@ -16,7 +16,10 @@ const governanceAddresses = [GOV4ADDR, GOV2ADDR, GOV1ADDR]; const delay = ms => new Promise(resolve => setTimeout(() => resolve(undefined), ms)); -test.serial( +const testSkipXXX = test.skip; // same lenth as test.serial to avoid reformatting all lines + +// z:acceptance governance fails/flakes: No quorum #10708 +testSkipXXX( 'economic committee can make governance proposal and vote on it', async t => { const { waitUntil } = makeTimerUtils({ setTimeout });