From fce80b57cf269efd600fdc0fccbc0d425c4a334c Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 28 Jan 2025 14:31:02 -0800 Subject: [PATCH 01/10] refactor: cli utils under cli/ --- packages/fast-usdc/src/cli/cli.js | 2 +- packages/fast-usdc/src/cli/config-commands.js | 2 +- packages/fast-usdc/src/cli/config.js | 2 +- packages/fast-usdc/src/cli/transfer.js | 10 +++++----- packages/fast-usdc/src/{ => cli}/util/agoric.js | 0 packages/fast-usdc/src/{ => cli}/util/bank.js | 0 packages/fast-usdc/src/{ => cli}/util/cctp.js | 0 packages/fast-usdc/src/{ => cli}/util/file.js | 0 packages/fast-usdc/src/{ => cli}/util/noble.js | 0 packages/fast-usdc/test/util/file.test.ts | 2 +- 10 files changed, 9 insertions(+), 9 deletions(-) rename packages/fast-usdc/src/{ => cli}/util/agoric.js (100%) rename packages/fast-usdc/src/{ => cli}/util/bank.js (100%) rename packages/fast-usdc/src/{ => cli}/util/cctp.js (100%) rename packages/fast-usdc/src/{ => cli}/util/file.js (100%) rename packages/fast-usdc/src/{ => cli}/util/noble.js (100%) diff --git a/packages/fast-usdc/src/cli/cli.js b/packages/fast-usdc/src/cli/cli.js index 18acb636fe9..133716b7f5c 100644 --- a/packages/fast-usdc/src/cli/cli.js +++ b/packages/fast-usdc/src/cli/cli.js @@ -13,7 +13,7 @@ import { addConfigCommands } from './config-commands.js'; import { addOperatorCommands } from './operator-commands.js'; import * as configLib from './config.js'; import transferLib from './transfer.js'; -import { makeFile } from '../util/file.js'; +import { makeFile } from './util/file.js'; import { addLPCommands } from './lp-commands.js'; const packageJson = JSON.parse( diff --git a/packages/fast-usdc/src/cli/config-commands.js b/packages/fast-usdc/src/cli/config-commands.js index e2f39d6f7d0..50e6360b3d7 100644 --- a/packages/fast-usdc/src/cli/config-commands.js +++ b/packages/fast-usdc/src/cli/config-commands.js @@ -1,6 +1,6 @@ /** * @import {Command} from 'commander'; - * @import {File} from '../util/file.js'; + * @import {File} from './util/file.js'; * @import * as ConfigHelpers from './config.js'; */ /** diff --git a/packages/fast-usdc/src/cli/config.js b/packages/fast-usdc/src/cli/config.js index c59e6c8fc13..1395874dd0d 100644 --- a/packages/fast-usdc/src/cli/config.js +++ b/packages/fast-usdc/src/cli/config.js @@ -23,7 +23,7 @@ import { stdin as input, stdout as output } from 'node:process'; }} ConfigOpts */ -/** @import { File } from '../util/file' */ +/** @import { File } from './util/file' */ export const init = async ( /** @type {File} */ configFile, diff --git a/packages/fast-usdc/src/cli/transfer.js b/packages/fast-usdc/src/cli/transfer.js index 31b8e212f65..ee122fb2c94 100644 --- a/packages/fast-usdc/src/cli/transfer.js +++ b/packages/fast-usdc/src/cli/transfer.js @@ -7,16 +7,16 @@ import { pickEndpoint, } from '@agoric/client-utils'; import { encodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js'; -import { queryFastUSDCLocalChainAccount } from '../util/agoric.js'; -import { depositForBurn, makeProvider } from '../util/cctp.js'; +import { queryFastUSDCLocalChainAccount } from './util/agoric.js'; +import { depositForBurn, makeProvider } from './util/cctp.js'; import { makeSigner, queryForwardingAccount, registerFwdAccount, -} from '../util/noble.js'; -import { queryUSDCBalance } from '../util/bank.js'; +} from './util/noble.js'; +import { queryUSDCBalance } from './util/bank.js'; -/** @import { File } from '../util/file' */ +/** @import { File } from './util/file' */ /** @import { VStorage } from '@agoric/client-utils' */ /** @import { SigningStargateClient } from '@cosmjs/stargate' */ /** @import { JsonRpcProvider as ethProvider } from 'ethers' */ diff --git a/packages/fast-usdc/src/util/agoric.js b/packages/fast-usdc/src/cli/util/agoric.js similarity index 100% rename from packages/fast-usdc/src/util/agoric.js rename to packages/fast-usdc/src/cli/util/agoric.js diff --git a/packages/fast-usdc/src/util/bank.js b/packages/fast-usdc/src/cli/util/bank.js similarity index 100% rename from packages/fast-usdc/src/util/bank.js rename to packages/fast-usdc/src/cli/util/bank.js diff --git a/packages/fast-usdc/src/util/cctp.js b/packages/fast-usdc/src/cli/util/cctp.js similarity index 100% rename from packages/fast-usdc/src/util/cctp.js rename to packages/fast-usdc/src/cli/util/cctp.js diff --git a/packages/fast-usdc/src/util/file.js b/packages/fast-usdc/src/cli/util/file.js similarity index 100% rename from packages/fast-usdc/src/util/file.js rename to packages/fast-usdc/src/cli/util/file.js diff --git a/packages/fast-usdc/src/util/noble.js b/packages/fast-usdc/src/cli/util/noble.js similarity index 100% rename from packages/fast-usdc/src/util/noble.js rename to packages/fast-usdc/src/cli/util/noble.js diff --git a/packages/fast-usdc/test/util/file.test.ts b/packages/fast-usdc/test/util/file.test.ts index c95f3790da0..cbd2076eebb 100644 --- a/packages/fast-usdc/test/util/file.test.ts +++ b/packages/fast-usdc/test/util/file.test.ts @@ -1,5 +1,5 @@ import test from 'ava'; -import { makeFile } from '../../src/util/file.js'; +import { makeFile } from '../../src/cli/util/file.js'; const makeReadMock = (content: string) => { let filePathRead: string; From 84738424bbe119242ef53b7283d357da287bcb22 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 28 Jan 2025 17:42:10 -0800 Subject: [PATCH 02/10] feat: RecorderKitShape --- packages/zoe/src/contractSupport/recorder.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/zoe/src/contractSupport/recorder.js b/packages/zoe/src/contractSupport/recorder.js index 620fb04619d..53f1db07c47 100644 --- a/packages/zoe/src/contractSupport/recorder.js +++ b/packages/zoe/src/contractSupport/recorder.js @@ -262,3 +262,9 @@ export const prepareMockRecorderKitMakers = () => { storageNode: makeFakeStorage('mock recorder storage'), }; }; + +export const RecorderKitShape = { + recorder: M.remotable(), + subscriber: M.remotable(), +}; +harden(RecorderKitShape); From 1c4d97508edb45c6035796037d32051c120441f1 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 28 Jan 2025 15:35:01 -0800 Subject: [PATCH 03/10] chore: stateShape for liquidity-pool --- packages/fast-usdc/src/exos/liquidity-pool.js | 22 ++- .../test/exos/liquidity-pool.test.ts | 7 + .../exos/snapshots/liquidity-pool.test.ts.md | 169 ++++++++++++++++++ .../snapshots/liquidity-pool.test.ts.snap | Bin 0 -> 941 bytes 4 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 packages/fast-usdc/test/exos/liquidity-pool.test.ts create mode 100644 packages/fast-usdc/test/exos/snapshots/liquidity-pool.test.ts.md create mode 100644 packages/fast-usdc/test/exos/snapshots/liquidity-pool.test.ts.snap diff --git a/packages/fast-usdc/src/exos/liquidity-pool.js b/packages/fast-usdc/src/exos/liquidity-pool.js index e2bff5ec5df..c8867fbdc4d 100644 --- a/packages/fast-usdc/src/exos/liquidity-pool.js +++ b/packages/fast-usdc/src/exos/liquidity-pool.js @@ -1,8 +1,9 @@ -import { AmountMath, AmountShape } from '@agoric/ertp'; +import { AmountMath, AmountShape, RatioShape } from '@agoric/ertp'; import { makeRecorderTopic, + RecorderKitShape, TopicsRecordShape, -} from '@agoric/zoe/src/contractSupport/topics.js'; +} from '@agoric/zoe/src/contractSupport/index.js'; import { SeatShape } from '@agoric/zoe/src/typeGuards.js'; import { M } from '@endo/patterns'; import { Fail, q } from '@endo/errors'; @@ -48,6 +49,22 @@ const { add, isGTE, makeEmpty } = AmountMath; * }} RepayPaymentKWR */ +export const stateShape = harden({ + encumberedBalance: AmountShape, + feeSeat: M.remotable(), + poolStats: M.record(), + poolMetricsRecorderKit: RecorderKitShape, + poolSeat: M.remotable(), + PoolShares: M.remotable(), + proposalShapes: { + deposit: M.pattern(), + withdraw: M.pattern(), + withdrawFees: M.pattern(), + }, + shareMint: M.remotable(), + shareWorth: RatioShape, +}); + /** * @param {Zone} zone * @param {ZCF} zcf @@ -384,6 +401,7 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => { finish: ({ facets: { external } }) => { void external.publishPoolMetrics(); }, + stateShape, }, ); }; diff --git a/packages/fast-usdc/test/exos/liquidity-pool.test.ts b/packages/fast-usdc/test/exos/liquidity-pool.test.ts new file mode 100644 index 00000000000..52dd675f808 --- /dev/null +++ b/packages/fast-usdc/test/exos/liquidity-pool.test.ts @@ -0,0 +1,7 @@ +import { test } from '@agoric/zoe/tools/prepare-test-env-ava.js'; + +import { stateShape } from '../../src/exos/liquidity-pool.js'; + +test('stateShape', t => { + t.snapshot(stateShape); +}); diff --git a/packages/fast-usdc/test/exos/snapshots/liquidity-pool.test.ts.md b/packages/fast-usdc/test/exos/snapshots/liquidity-pool.test.ts.md new file mode 100644 index 00000000000..e14a761b88f --- /dev/null +++ b/packages/fast-usdc/test/exos/snapshots/liquidity-pool.test.ts.md @@ -0,0 +1,169 @@ +# Snapshot report for `test/exos/liquidity-pool.test.ts` + +The actual snapshot is saved in `liquidity-pool.test.ts.snap`. + +Generated by [AVA](https://avajs.dev). + +## stateShape + +> Snapshot 1 + + { + PoolShares: Object @match:kind { + payload: 'remotable', + }, + encumberedBalance: { + brand: Object @match:remotable { + payload: { + label: 'Brand', + }, + }, + value: Object @match:or { + payload: [ + Object @match:nat { + payload: [], + }, + Object @match:setOf { + payload: [ + Object @match:any { + payload: undefined, + }, + ], + }, + Object @match:arrayOf { + payload: [ + Object @match:key { + payload: undefined, + }, + ], + }, + Object @match:bagOf { + payload: [ + Object @match:any { + payload: undefined, + }, + Object @match:any { + payload: undefined, + }, + ], + }, + ], + }, + }, + feeSeat: Object @match:kind { + payload: 'remotable', + }, + poolMetricsRecorderKit: { + recorder: Object @match:kind { + payload: 'remotable', + }, + subscriber: Object @match:kind { + payload: 'remotable', + }, + }, + poolSeat: Object @match:kind { + payload: 'remotable', + }, + poolStats: Object @match:recordOf { + payload: [ + Object @match:any { + payload: undefined, + }, + Object @match:any { + payload: undefined, + }, + ], + }, + proposalShapes: { + deposit: Object @match:pattern { + payload: undefined, + }, + withdraw: Object @match:pattern { + payload: undefined, + }, + withdrawFees: Object @match:pattern { + payload: undefined, + }, + }, + shareMint: Object @match:kind { + payload: 'remotable', + }, + shareWorth: { + denominator: { + brand: Object @match:remotable { + payload: { + label: 'Brand', + }, + }, + value: Object @match:or { + payload: [ + Object @match:nat { + payload: [], + }, + Object @match:setOf { + payload: [ + Object @match:any { + payload: undefined, + }, + ], + }, + Object @match:arrayOf { + payload: [ + Object @match:key { + payload: undefined, + }, + ], + }, + Object @match:bagOf { + payload: [ + Object @match:any { + payload: undefined, + }, + Object @match:any { + payload: undefined, + }, + ], + }, + ], + }, + }, + numerator: { + brand: Object @match:remotable { + payload: { + label: 'Brand', + }, + }, + value: Object @match:or { + payload: [ + Object @match:nat { + payload: [], + }, + Object @match:setOf { + payload: [ + Object @match:any { + payload: undefined, + }, + ], + }, + Object @match:arrayOf { + payload: [ + Object @match:key { + payload: undefined, + }, + ], + }, + Object @match:bagOf { + payload: [ + Object @match:any { + payload: undefined, + }, + Object @match:any { + payload: undefined, + }, + ], + }, + ], + }, + }, + }, + } diff --git a/packages/fast-usdc/test/exos/snapshots/liquidity-pool.test.ts.snap b/packages/fast-usdc/test/exos/snapshots/liquidity-pool.test.ts.snap new file mode 100644 index 0000000000000000000000000000000000000000..7b6d637be92a2a0b775456b4c03906a1a0f60376 GIT binary patch literal 941 zcmV;e15*4!RzVO3?9NQwx*qhP7pa$?_OvH0Vh>AObp`D~ z@n!PXNjH;(tAW}UQEg}^`Py|ma2!i&kc#s}Mp?9&G_a@mluiNb$ z!h89?|KjWGj z2joQ*K3^2s=9E{WR@fy2i$p%znZ=?K$#I_Xd?FO(D}&;139%`-RKPa|uv!*Hc2dYH zozyRiNl_)D+DJ9;w!sS;UU$M@2GUoEkOr~^FVSmc$6hFVOed_2817v!!xz|#(J#sO-(?BV-}y6gZ~9pFp5;E{W# zg+L>$5bMG&`EFM5q_epavqJJX6N=81**`h^W_xkP^F-agYucBo)gWS zb&9VVoIxV;VwUDy7FzU&2H4McW}?ziK4cL~nWOOE)08;6c?qX#V_V)xtX-@UGp0w>ZiHc{e=ZrU!iM0ec?s zi??WvzhKQ6wA5Y?(BWk~7FoADu7^AXxvGO-yIz8x?qxu<)+}|eakF%k`uBRk`#np2 z5K&(Tkn^?ycB2Q}w3%T<1I?_3?7j=^#~$#r&0X$d_2MweK|8KX~SsxABSvVHxSqO-&1;Bb>Ilk1T&hy8veK`-C*L&WZ P2Xp=dnm~E(s|Wx9j{??q literal 0 HcmV?d00001 From b7f9bc3ae9d31d4a0cc603a913e033dc61fe085e Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 28 Jan 2025 15:35:10 -0800 Subject: [PATCH 04/10] chore: stateShape for status-manager --- packages/fast-usdc/src/exos/status-manager.js | 7 ++++++ .../exos/snapshots/status-manager.test.ts.md | 21 ++++++++++++++++++ .../snapshots/status-manager.test.ts.snap | Bin 0 -> 276 bytes .../test/exos/status-manager.test.ts | 6 ++++- 4 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 packages/fast-usdc/test/exos/snapshots/status-manager.test.ts.md create mode 100644 packages/fast-usdc/test/exos/snapshots/status-manager.test.ts.snap diff --git a/packages/fast-usdc/src/exos/status-manager.js b/packages/fast-usdc/src/exos/status-manager.js index 9a38e185d24..715e4185b1b 100644 --- a/packages/fast-usdc/src/exos/status-manager.js +++ b/packages/fast-usdc/src/exos/status-manager.js @@ -53,6 +53,12 @@ const pendingTxKeyOf = evidence => { * }} StatusManagerPowers */ +export const stateShape = harden({ + pendingSettleTxs: M.remotable(), + seenTxs: M.remotable(), + storedCompletedTxs: M.remotable(), +}); + /** * The `StatusManager` keeps track of Pending and Seen Transactions * via {@link PendingTxStatus} states, aiding in coordination between the `Advancer` @@ -408,6 +414,7 @@ export const prepareStatusManager = ( return pendingSettleTxs.get(key); }, }, + { stateShape }, ); }; harden(prepareStatusManager); diff --git a/packages/fast-usdc/test/exos/snapshots/status-manager.test.ts.md b/packages/fast-usdc/test/exos/snapshots/status-manager.test.ts.md new file mode 100644 index 00000000000..bc3d2d60fbe --- /dev/null +++ b/packages/fast-usdc/test/exos/snapshots/status-manager.test.ts.md @@ -0,0 +1,21 @@ +# Snapshot report for `test/exos/status-manager.test.ts` + +The actual snapshot is saved in `status-manager.test.ts.snap`. + +Generated by [AVA](https://avajs.dev). + +## stateShape + +> Snapshot 1 + + { + pendingSettleTxs: Object @match:kind { + payload: 'remotable', + }, + seenTxs: Object @match:kind { + payload: 'remotable', + }, + storedCompletedTxs: Object @match:kind { + payload: 'remotable', + }, + } diff --git a/packages/fast-usdc/test/exos/snapshots/status-manager.test.ts.snap b/packages/fast-usdc/test/exos/snapshots/status-manager.test.ts.snap new file mode 100644 index 0000000000000000000000000000000000000000..093a925906c611b9a0d5e6152626734cac1a243b GIT binary patch literal 276 zcmV+v0qg!jRzVR~Qu_u4vJG zC-!-f_8*G~00000000ABjxkQdKomr097qCEU`;p+1)}2s6rrI(T6;g($$EE{{Sr{- z98}>jR8&+P2gQ=3C{ujR*F0%v`%?K>ukz+gv{f(5tX5^w*d%QZHsvO2-fW$-YM;mv zCfJEnp4Yw4oe%F918B(J?N0RRA>(0SYd literal 0 HcmV?d00001 diff --git a/packages/fast-usdc/test/exos/status-manager.test.ts b/packages/fast-usdc/test/exos/status-manager.test.ts index 2f2ebcf25c1..97cbc344b50 100644 --- a/packages/fast-usdc/test/exos/status-manager.test.ts +++ b/packages/fast-usdc/test/exos/status-manager.test.ts @@ -1,12 +1,12 @@ import type { TestFn } from 'ava'; import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js'; -import type { StorageNode } from '@agoric/internal/src/lib-chainStorage.js'; import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js'; import { defaultMarshaller } from '@agoric/internal/src/storage-test-utils.js'; import { PendingTxStatus } from '../../src/constants.js'; import { prepareStatusManager, + stateShape, type StatusManager, } from '../../src/exos/status-manager.js'; import { commonSetup, provideDurableZone } from '../supports.js'; @@ -21,6 +21,10 @@ type TestContext = { const test = anyTest as TestFn; +test('stateShape', t => { + t.snapshot(stateShape); +}); + test.beforeEach(async t => { const common = await commonSetup(t); const zone = provideDurableZone('status-test'); From 93fb29e38962de9ff47ba964a284395536671a50 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 28 Jan 2025 15:27:53 -0800 Subject: [PATCH 05/10] test: stateShapes --- packages/fast-usdc/src/exos/advancer.js | 16 +++-- packages/fast-usdc/src/exos/settler.js | 20 +++--- .../fast-usdc/src/exos/transaction-feed.js | 7 ++ packages/fast-usdc/test/exos/advancer.test.ts | 6 +- packages/fast-usdc/test/exos/settler.test.ts | 10 ++- .../test/exos/snapshots/advancer.test.ts.md | 57 ++++++++++++++++ .../test/exos/snapshots/advancer.test.ts.snap | Bin 0 -> 542 bytes .../test/exos/snapshots/settler.test.ts.md | 63 ++++++++++++++++++ .../test/exos/snapshots/settler.test.ts.snap | Bin 0 -> 695 bytes .../snapshots/transaction-feed.test.ts.md | 21 ++++++ .../snapshots/transaction-feed.test.ts.snap | Bin 0 -> 262 bytes .../test/exos/transaction-feed.test.ts | 5 ++ packages/internal/src/testing-utils.js | 2 +- 13 files changed, 188 insertions(+), 19 deletions(-) create mode 100644 packages/fast-usdc/test/exos/snapshots/advancer.test.ts.md create mode 100644 packages/fast-usdc/test/exos/snapshots/advancer.test.ts.snap create mode 100644 packages/fast-usdc/test/exos/snapshots/settler.test.ts.md create mode 100644 packages/fast-usdc/test/exos/snapshots/settler.test.ts.snap create mode 100644 packages/fast-usdc/test/exos/snapshots/transaction-feed.test.ts.md create mode 100644 packages/fast-usdc/test/exos/snapshots/transaction-feed.test.ts.snap diff --git a/packages/fast-usdc/src/exos/advancer.js b/packages/fast-usdc/src/exos/advancer.js index dc2a66be816..3985f1fb1fa 100644 --- a/packages/fast-usdc/src/exos/advancer.js +++ b/packages/fast-usdc/src/exos/advancer.js @@ -81,6 +81,14 @@ const AdvancerKitI = harden({ * }} AdvancerVowCtx */ +export const stateShape = harden({ + notifyFacet: M.remotable(), + borrowerFacet: M.remotable(), + poolAccount: M.remotable(), + intermediateRecipient: M.opt(ChainAddressShape), + settlementAddress: M.opt(ChainAddressShape), +}); + /** * @param {Zone} zone * @param {AdvancerKitPowers} caps @@ -287,13 +295,7 @@ export const prepareAdvancerKit = ( }, }, { - stateShape: harden({ - notifyFacet: M.remotable(), - borrowerFacet: M.remotable(), - poolAccount: M.remotable(), - settlementAddress: ChainAddressShape, - intermediateRecipient: M.opt(ChainAddressShape), - }), + stateShape, }, ); }; diff --git a/packages/fast-usdc/src/exos/settler.js b/packages/fast-usdc/src/exos/settler.js index d04ec78063e..d9ac921f363 100644 --- a/packages/fast-usdc/src/exos/settler.js +++ b/packages/fast-usdc/src/exos/settler.js @@ -45,6 +45,16 @@ export const makeAdvanceDetailsShape = USDC => txHash: EvmHashShape, }); +export const stateShape = harden({ + repayer: M.remotable('Repayer'), + settlementAccount: M.remotable('Account'), + registration: M.or(M.undefined(), M.remotable('Registration')), + sourceChannel: M.string(), + remoteDenom: M.string(), + mintedEarly: M.remotable('mintedEarly'), + intermediateRecipient: M.opt(ChainAddressShape), +}); + /** * @param {Zone} zone * @param {object} caps @@ -337,15 +347,7 @@ export const prepareSettler = ( }, }, { - stateShape: harden({ - repayer: M.remotable('Repayer'), - settlementAccount: M.remotable('Account'), - registration: M.or(M.undefined(), M.remotable('Registration')), - sourceChannel: M.string(), - remoteDenom: M.string(), - mintedEarly: M.remotable('mintedEarly'), - intermediateRecipient: M.opt(ChainAddressShape), - }), + stateShape, }, ); }; diff --git a/packages/fast-usdc/src/exos/transaction-feed.js b/packages/fast-usdc/src/exos/transaction-feed.js index a57de4aba50..4c0bfa9a565 100644 --- a/packages/fast-usdc/src/exos/transaction-feed.js +++ b/packages/fast-usdc/src/exos/transaction-feed.js @@ -59,6 +59,12 @@ const allRisksIdentified = (riskStores, txHash) => { return [...setOfRisks.values()].sort(); }; +export const stateShape = { + operators: M.remotable(), + pending: M.remotable(), + risks: M.remotable(), +}; + /** * @param {Zone} zone * @param {ZCF} zcf @@ -245,6 +251,7 @@ export const prepareTransactionFeedKit = (zone, zcf) => { getEvidenceSubscriber: () => subscriber, }, }, + { stateShape }, ); }; harden(prepareTransactionFeedKit); diff --git a/packages/fast-usdc/test/exos/advancer.test.ts b/packages/fast-usdc/test/exos/advancer.test.ts index ce6f8448793..ab20b1ca40d 100644 --- a/packages/fast-usdc/test/exos/advancer.test.ts +++ b/packages/fast-usdc/test/exos/advancer.test.ts @@ -15,7 +15,7 @@ import type { TestFn } from 'ava'; import { makeTracer } from '@agoric/internal'; import { M, mustMatch } from '@endo/patterns'; import { PendingTxStatus } from '../../src/constants.js'; -import { prepareAdvancer } from '../../src/exos/advancer.js'; +import { prepareAdvancer, stateShape } from '../../src/exos/advancer.js'; import { makeAdvanceDetailsShape, type SettlerKit, @@ -189,6 +189,10 @@ test.beforeEach(async t => { }; }); +test('stateShape', t => { + t.snapshot(stateShape); +}); + test('updates status to ADVANCING in happy path', async t => { const { extensions: { diff --git a/packages/fast-usdc/test/exos/settler.test.ts b/packages/fast-usdc/test/exos/settler.test.ts index 4bed4311dae..eb6e1713c49 100644 --- a/packages/fast-usdc/test/exos/settler.test.ts +++ b/packages/fast-usdc/test/exos/settler.test.ts @@ -7,7 +7,11 @@ import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js'; import fetchedChainInfo from '@agoric/orchestration/src/fetched-chain-info.js'; import type { Zone } from '@agoric/zone'; import { PendingTxStatus, TxStatus } from '../../src/constants.js'; -import { prepareSettler, type SettlerKit } from '../../src/exos/settler.js'; +import { + prepareSettler, + stateShape, + type SettlerKit, +} from '../../src/exos/settler.js'; import { prepareStatusManager } from '../../src/exos/status-manager.js'; import type { CctpTxEvidence } from '../../src/types.js'; import { makeFeeTools } from '../../src/utils/fees.js'; @@ -211,6 +215,10 @@ const test = anyTest as TestFn>>; test.beforeEach(async t => (t.context = await makeTestContext(t))); +test('stateShape', t => { + t.snapshot(stateShape); +}); + test('happy path: disburse to LPs; StatusManager removes tx', async t => { const { common, diff --git a/packages/fast-usdc/test/exos/snapshots/advancer.test.ts.md b/packages/fast-usdc/test/exos/snapshots/advancer.test.ts.md new file mode 100644 index 00000000000..d704f0b6013 --- /dev/null +++ b/packages/fast-usdc/test/exos/snapshots/advancer.test.ts.md @@ -0,0 +1,57 @@ +# Snapshot report for `test/exos/advancer.test.ts` + +The actual snapshot is saved in `advancer.test.ts.snap`. + +Generated by [AVA](https://avajs.dev). + +## stateShape + +> Snapshot 1 + + { + borrowerFacet: Object @match:kind { + payload: 'remotable', + }, + intermediateRecipient: Object @match:or { + payload: [ + Object @match:kind { + payload: 'undefined', + }, + { + chainId: Object @match:string { + payload: [], + }, + encoding: Object @match:string { + payload: [], + }, + value: Object @match:string { + payload: [], + }, + }, + ], + }, + notifyFacet: Object @match:kind { + payload: 'remotable', + }, + poolAccount: Object @match:kind { + payload: 'remotable', + }, + settlementAddress: Object @match:or { + payload: [ + Object @match:kind { + payload: 'undefined', + }, + { + chainId: Object @match:string { + payload: [], + }, + encoding: Object @match:string { + payload: [], + }, + value: Object @match:string { + payload: [], + }, + }, + ], + }, + } diff --git a/packages/fast-usdc/test/exos/snapshots/advancer.test.ts.snap b/packages/fast-usdc/test/exos/snapshots/advancer.test.ts.snap new file mode 100644 index 0000000000000000000000000000000000000000..4c1c2b5b8030afbf8efa0ae1e555938dbe26d99e GIT binary patch literal 542 zcmV+(0^$8ZRzV<5!&OLbF-Q z9yVk>W1Sw)um3S@!ou2on5K5Ns(jXfNyX0PJZ0mCSypmYE&PdsfD>x@5eapt%B7PB z$J%7xQ$*r30bklunNYNp+R_VSkf_gy#3cb&?V{awQ6EI00rpAM{dNj9&#lVp_io8k z>(nUcTE0j0t6{J%Xy8z6!x7250=O@L$70o4Ff2H zZI6hB- Snapshot 1 + + { + intermediateRecipient: Object @match:or { + payload: [ + Object @match:kind { + payload: 'undefined', + }, + { + chainId: Object @match:string { + payload: [], + }, + encoding: Object @match:string { + payload: [], + }, + value: Object @match:string { + payload: [], + }, + }, + ], + }, + mintedEarly: Object @match:remotable { + payload: { + label: 'mintedEarly', + }, + }, + registration: Object @match:or { + payload: [ + Object @match:kind { + payload: 'undefined', + }, + Object @match:remotable { + payload: { + label: 'Registration', + }, + }, + ], + }, + remoteDenom: Object @match:string { + payload: [], + }, + repayer: Object @match:remotable { + payload: { + label: 'Repayer', + }, + }, + settlementAccount: Object @match:remotable { + payload: { + label: 'Account', + }, + }, + sourceChannel: Object @match:string { + payload: [], + }, + } diff --git a/packages/fast-usdc/test/exos/snapshots/settler.test.ts.snap b/packages/fast-usdc/test/exos/snapshots/settler.test.ts.snap new file mode 100644 index 0000000000000000000000000000000000000000..51f80fcb163861b0f156dc0986707230b2319954 GIT binary patch literal 695 zcmV;o0!aNqRzV_N6Ei66(SNL(2fHWnwBH0T_URg%Js<5>h_^6Dz3aCOAhD@O0LD_wIhr?|FZ{ zlceERzVk}zSSNBb*Fwu%UD20uu0%iYraIr*k0PPPoyvKRDvlrW$Xf+)6F?4N7r+64 z&j5}9R0&w3NmcSZSH{WE2Z6+cJ#%u~gd7 z)=IQm@0b@|7g;hi;G+^)&*Vm&>rCi4RR(=s-kQl?s^vAQ(w+eiN?n&WC@^htKl4@Y+<^Bfianha7m!Plj?=vP=w#k5<0#o5}Y$@Pb>DFH8p4 zBmRy9A35;F(yQ5e-#GBy*7I#WR&jv3W6^?1+9HU7YD5bNN$vG)$}$)3;&Xt9XYR;;2EGn^j|@Y4Z&7dYoy zTii)gS|G>hUvYs|n_Qm}*(p~a#bxxqFi??PkCiO)#ZA8MxutxCT@kArkpZ5T08gqg zjbgQ7kY^>t-4@9}mh$@2ot{_r)&)M;(^LYg7t`cAi`7P{edDGdy1Z98 dncb#2-?iSJ_`iA+4XBnH@Efrk1O{0K0042oMM?kw literal 0 HcmV?d00001 diff --git a/packages/fast-usdc/test/exos/snapshots/transaction-feed.test.ts.md b/packages/fast-usdc/test/exos/snapshots/transaction-feed.test.ts.md new file mode 100644 index 00000000000..447e9312665 --- /dev/null +++ b/packages/fast-usdc/test/exos/snapshots/transaction-feed.test.ts.md @@ -0,0 +1,21 @@ +# Snapshot report for `test/exos/transaction-feed.test.ts` + +The actual snapshot is saved in `transaction-feed.test.ts.snap`. + +Generated by [AVA](https://avajs.dev). + +## stateShape + +> Snapshot 1 + + { + operators: Object @match:kind { + payload: 'remotable', + }, + pending: Object @match:kind { + payload: 'remotable', + }, + risks: Object @match:kind { + payload: 'remotable', + }, + } diff --git a/packages/fast-usdc/test/exos/snapshots/transaction-feed.test.ts.snap b/packages/fast-usdc/test/exos/snapshots/transaction-feed.test.ts.snap new file mode 100644 index 0000000000000000000000000000000000000000..e46b33e65eba4877ce3379397d4bd43b4d87b254 GIT binary patch literal 262 zcmV+h0r~zxRzV3;MW)iZ**n3O<3N1|fD zmNvdm6d#KS00000000ABjy+DpKoo>$oIi*Zuoccifw%)j3TU6b54^GCU3p(anTm5H zN1&pj;yT;`*%BdQiqS}4@y+46Y(v$g{ZY+ZtJ`E^x~V0qPo2b62TS{db7J!JJ;4G) zc){r{fO`Os03v`j=LP2vrPczSRa0O1lEAkD%&9G+$FGJK`Ec9ta?`LQcwR66E z8NtUHnDst2Y4B&C0KWcvvx3W=SXJLOzH_5H2eaQ^fdsFyX7;C&*EWbdz3O!rOv+Y& M04RBU=^Ft60Fo?o-T(jq literal 0 HcmV?d00001 diff --git a/packages/fast-usdc/test/exos/transaction-feed.test.ts b/packages/fast-usdc/test/exos/transaction-feed.test.ts index f05a78af9a3..77c32a76e49 100644 --- a/packages/fast-usdc/test/exos/transaction-feed.test.ts +++ b/packages/fast-usdc/test/exos/transaction-feed.test.ts @@ -5,6 +5,7 @@ import { deeplyFulfilledObject } from '@agoric/internal'; import { makeHeapZone } from '@agoric/zone'; import { prepareTransactionFeedKit, + stateShape, type TransactionFeedKit, } from '../../src/exos/transaction-feed.js'; import { MockCctpTxEvidences } from '../fixtures.js'; @@ -27,6 +28,10 @@ const makeOperators = (feedKit: TransactionFeedKit) => { return deeplyFulfilledObject(harden(operators)); }; +test('stateShape', t => { + t.snapshot(stateShape); +}); + test('facets', t => { const kit = makeFeedKit(); t.deepEqual(Object.keys(kit).sort(), ['creator', 'operatorPowers', 'public']); diff --git a/packages/internal/src/testing-utils.js b/packages/internal/src/testing-utils.js index 5e2b8e9ce5e..bf75e7e93d0 100644 --- a/packages/internal/src/testing-utils.js +++ b/packages/internal/src/testing-utils.js @@ -28,7 +28,7 @@ const stringOrTag = value => { }; /** * @param {MapStore} store - * @returns {object} tree of the contents of the store + * @returns {object} tree of the contents of the store */ export const inspectMapStore = store => { /** @type {Record} */ From f3f97416957b26d77c6bd06006ba5d3a0715e15a Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 28 Jan 2025 14:41:34 -0800 Subject: [PATCH 06/10] chore: simplify stored cap names --- packages/fast-usdc/src/exos/advancer.js | 30 +++++++++--------- packages/fast-usdc/src/exos/settler.js | 10 +++--- packages/fast-usdc/src/fast-usdc.contract.js | 4 +-- packages/fast-usdc/test/exos/advancer.test.ts | 18 +++++------ packages/fast-usdc/test/exos/settler.test.ts | 20 ++++++------ .../test/exos/snapshots/advancer.test.ts.md | 4 +-- .../test/exos/snapshots/advancer.test.ts.snap | Bin 542 -> 540 bytes 7 files changed, 42 insertions(+), 44 deletions(-) diff --git a/packages/fast-usdc/src/exos/advancer.js b/packages/fast-usdc/src/exos/advancer.js index 3985f1fb1fa..1708b0193d8 100644 --- a/packages/fast-usdc/src/exos/advancer.js +++ b/packages/fast-usdc/src/exos/advancer.js @@ -82,8 +82,8 @@ const AdvancerKitI = harden({ */ export const stateShape = harden({ - notifyFacet: M.remotable(), - borrowerFacet: M.remotable(), + notifier: M.remotable(), + borrower: M.remotable(), poolAccount: M.remotable(), intermediateRecipient: M.opt(ChainAddressShape), settlementAddress: M.opt(ChainAddressShape), @@ -122,8 +122,8 @@ export const prepareAdvancerKit = ( AdvancerKitI, /** * @param {{ - * notifyFacet: import('./settler.js').SettlerKit['notify']; - * borrowerFacet: LiquidityPoolKit['borrower']; + * notifier: import('./settler.js').SettlerKit['notifier']; + * borrower: LiquidityPoolKit['borrower']; * poolAccount: HostInterface>; * settlementAddress: ChainAddress; * intermediateRecipient?: ChainAddress; @@ -173,9 +173,9 @@ export const prepareAdvancerKit = ( const destination = chainHub.makeChainAddress(EUD); const fullAmount = toAmount(evidence.tx.amount); - const { borrowerFacet, notifyFacet, poolAccount } = this.state; + const { borrower, notifier, poolAccount } = this.state; // do not advance if we've already received a mint/settlement - const mintedEarly = notifyFacet.checkMintedEarly( + const mintedEarly = notifier.checkMintedEarly( evidence, destination, ); @@ -186,7 +186,7 @@ export const prepareAdvancerKit = ( const { zcfSeat: tmpSeat } = zcf.makeEmptySeatKit(); // throws if the pool has insufficient funds - borrowerFacet.borrow(tmpSeat, advanceAmount); + borrower.borrow(tmpSeat, advanceAmount); // this cannot throw since `.isSeen()` is called in the same turn statusManager.advance(evidence); @@ -257,9 +257,9 @@ export const prepareAdvancerKit = ( error, ); try { - const { borrowerFacet, notifyFacet } = this.state; - notifyFacet.notifyAdvancingResult(restCtx, false); - borrowerFacet.returnToPool(tmpSeat, advanceAmount); + const { borrower, notifier } = this.state; + notifier.notifyAdvancingResult(restCtx, false); + borrower.returnToPool(tmpSeat, advanceAmount); } catch (e) { log('🚨 deposit to localOrchAccount failure recovery failed', e); } @@ -271,26 +271,26 @@ export const prepareAdvancerKit = ( * @param {AdvancerVowCtx} ctx */ onFulfilled(result, ctx) { - const { notifyFacet } = this.state; + const { notifier } = this.state; const { advanceAmount, destination, ...detail } = ctx; log('Advance succeeded', { advanceAmount, destination }); // During development, due to a bug, this call threw. // The failure was silent (no diagnostics) due to: // - #10576 Vows do not report unhandled rejections // For now, the advancer kit relies on consistency between - // notifyFacet, statusManager, and callers of handleTransactionEvent(). + // notify, statusManager, and callers of handleTransactionEvent(). // TODO: revisit #10576 during #10510 - notifyFacet.notifyAdvancingResult({ destination, ...detail }, true); + notifier.notifyAdvancingResult({ destination, ...detail }, true); }, /** * @param {Error} error * @param {AdvancerVowCtx} ctx */ onRejected(error, ctx) { - const { notifyFacet } = this.state; + const { notifier } = this.state; log('Advance failed', error); const { advanceAmount: _, ...restCtx } = ctx; - notifyFacet.notifyAdvancingResult(restCtx, false); + notifier.notifyAdvancingResult(restCtx, false); }, }, }, diff --git a/packages/fast-usdc/src/exos/settler.js b/packages/fast-usdc/src/exos/settler.js index d9ac921f363..901ca394474 100644 --- a/packages/fast-usdc/src/exos/settler.js +++ b/packages/fast-usdc/src/exos/settler.js @@ -91,7 +91,7 @@ export const prepareSettler = ( tap: M.interface('SettlerTapI', { receiveUpcall: M.call(M.record()).returns(M.promise()), }), - notify: M.interface('SettlerNotifyI', { + notifier: M.interface('SettlerNotifyI', { notifyAdvancingResult: M.call( makeAdvanceDetailsShape(USDC), M.boolean(), @@ -216,7 +216,7 @@ export const prepareSettler = ( } }, }, - notify: { + notifier: { /** * @param {object} ctx * @param {EvmHash} ctx.txHash @@ -353,7 +353,5 @@ export const prepareSettler = ( }; harden(prepareSettler); -/** - * XXX consider using pickFacet (do we have pickFacets?) - * @typedef {ReturnType>} SettlerKit - */ +// Expose the whole kit because the contract needs `creatorFacet` and the Advancer needs `notifier` +/** @typedef {ReturnType>} SettlerKit */ diff --git a/packages/fast-usdc/src/fast-usdc.contract.js b/packages/fast-usdc/src/fast-usdc.contract.js index 28c05d44124..7c24f601523 100644 --- a/packages/fast-usdc/src/fast-usdc.contract.js +++ b/packages/fast-usdc/src/fast-usdc.contract.js @@ -284,8 +284,8 @@ export const contract = async (zcf, privateArgs, zone, tools) => { const advancer = zone.makeOnce('Advancer', () => makeAdvancer({ - borrowerFacet: poolKit.borrower, - notifyFacet: settlerKit.notify, + borrower: poolKit.borrower, + notifier: settlerKit.notifier, poolAccount, settlementAddress, }), diff --git a/packages/fast-usdc/test/exos/advancer.test.ts b/packages/fast-usdc/test/exos/advancer.test.ts index ab20b1ca40d..9381c20ccab 100644 --- a/packages/fast-usdc/test/exos/advancer.test.ts +++ b/packages/fast-usdc/test/exos/advancer.test.ts @@ -109,7 +109,7 @@ const createTestExtensions = (t, common: CommonSetup) => { zcf: mockZCF, }); - type NotifyArgs = Parameters; + type NotifyArgs = Parameters; const notifyAdvancingResultCalls: NotifyArgs[] = []; const mockNotifyF = Far('Settler Notify Facet', { notifyAdvancingResult: (...args: NotifyArgs) => { @@ -142,8 +142,8 @@ const createTestExtensions = (t, common: CommonSetup) => { }); const advancer = makeAdvancer({ - borrowerFacet: mockBorrowerF, - notifyFacet: mockNotifyF, + borrower: mockBorrowerF, + notifier: mockNotifyF, poolAccount: mockAccounts.mockPoolAccount.account, intermediateRecipient, settlementAddress, @@ -280,8 +280,8 @@ test('updates status to OBSERVED on insufficient pool funds', async t => { // make a new advancer that intentionally throws const advancer = makeAdvancer({ - borrowerFacet: mockBorrowerFacet, - notifyFacet: mockNotifyF, + borrower: mockBorrowerFacet, + notifier: mockNotifyF, poolAccount: mockPoolAccount.account, intermediateRecipient, settlementAddress, @@ -603,8 +603,8 @@ test('alerts if `returnToPool` fallback fails', async t => { // make a new advancer that intentionally throws during returnToPool const advancer = makeAdvancer({ - borrowerFacet: mockBorrowerFacet, - notifyFacet: mockNotifyF, + borrower: mockBorrowerFacet, + notifier: mockNotifyF, poolAccount: mockPoolAccount.account, intermediateRecipient, settlementAddress, @@ -695,8 +695,8 @@ test('no status update if `checkMintedEarly` returns true', async t => { }); const advancer = makeAdvancer({ - borrowerFacet: mockBorrowerF, - notifyFacet: mockNotifyF, + borrower: mockBorrowerF, + notifier: mockNotifyF, poolAccount: mockPoolAccount.account, intermediateRecipient, settlementAddress, diff --git a/packages/fast-usdc/test/exos/settler.test.ts b/packages/fast-usdc/test/exos/settler.test.ts index eb6e1713c49..7c200475e2a 100644 --- a/packages/fast-usdc/test/exos/settler.test.ts +++ b/packages/fast-usdc/test/exos/settler.test.ts @@ -100,7 +100,7 @@ const makeTestContext = async t => { intermediateRecipient, }); - const makeSimulate = (notifyFacet: SettlerKit['notify']) => { + const makeSimulate = (notifier: SettlerKit['notifier']) => { const makeEvidence = (evidence?: CctpTxEvidence): CctpTxEvidence => harden({ ...MockCctpTxEvidences.AGORIC_PLUS_OSMO(), @@ -145,7 +145,7 @@ const makeTestContext = async t => { const { Advanced, AdvanceFailed } = TxStatus; t.log(`Simulate ${success ? Advanced : AdvanceFailed}`); const info = makeNotifyInfo(evidence); - notifyFacet.notifyAdvancingResult(info, success); + notifier.notifyAdvancingResult(info, success); }, /** * start and finish advance successfully @@ -184,7 +184,7 @@ const makeTestContext = async t => { const cctpTxEvidence = makeEvidence(evidence); const { destination, forwardingAddress, fullAmount, txHash } = makeNotifyInfo(cctpTxEvidence); - notifyFacet.checkMintedEarly(cctpTxEvidence, destination); + notifier.checkMintedEarly(cctpTxEvidence, destination); return cctpTxEvidence; }, }); @@ -238,7 +238,7 @@ test('happy path: disburse to LPs; StatusManager removes tx', async t => { settlementAccount: accounts.settlement.account, ...defaultSettlerParams, }); - const simulate = makeSimulate(settler.notify); + const simulate = makeSimulate(settler.notifier); const cctpTxEvidence = simulate.advance(); t.deepEqual( statusManager.lookupPending( @@ -339,7 +339,7 @@ test('slow path: forward to EUD; remove pending tx', async t => { settlementAccount: accounts.settlement.account, ...defaultSettlerParams, }); - const simulate = makeSimulate(settler.notify); + const simulate = makeSimulate(settler.notifier); const cctpTxEvidence = simulate.observe(); t.deepEqual( statusManager.lookupPending( @@ -418,7 +418,7 @@ test('skip advance: forward to EUD; remove pending tx', async t => { ...defaultSettlerParams, }); - const simulate = makeSimulate(settler.notify); + const simulate = makeSimulate(settler.notifier); const cctpTxEvidence = simulate.skipAdvance(['TOO_LARGE_AMOUNT']); t.deepEqual( statusManager.lookupPending( @@ -499,7 +499,7 @@ test('Settlement for unknown transaction (minted early)', async t => { settlementAccount: accounts.settlement.account, ...defaultSettlerParams, }); - const simulate = makeSimulate(settler.notify); + const simulate = makeSimulate(settler.notifier); t.log('Simulate incoming IBC settlement'); void settler.tap.receiveUpcall(MockVTransferEvents.AGORIC_PLUS_OSMO()); @@ -571,7 +571,7 @@ test('Settlement for Advancing transaction (advance succeeds)', async t => { settlementAccount: accounts.settlement.account, ...defaultSettlerParams, }); - const simulate = makeSimulate(settler.notify); + const simulate = makeSimulate(settler.notifier); const cctpTxEvidence = simulate.startAdvance(); const { forwardingAddress, amount } = cctpTxEvidence.tx; @@ -625,7 +625,7 @@ test('Settlement for Advancing transaction (advance fails)', async t => { settlementAccount: accounts.settlement.account, ...defaultSettlerParams, }); - const simulate = makeSimulate(settler.notify); + const simulate = makeSimulate(settler.notifier); const cctpTxEvidence = simulate.startAdvance(); t.log('Simulate incoming IBC settlement'); @@ -691,7 +691,7 @@ test('slow path, and forward fails (terminal state)', async t => { settlementAccount: accounts.settlement.account, ...defaultSettlerParams, }); - const simulate = makeSimulate(settler.notify); + const simulate = makeSimulate(settler.notifier); const cctpTxEvidence = simulate.observe(); t.deepEqual( statusManager.lookupPending( diff --git a/packages/fast-usdc/test/exos/snapshots/advancer.test.ts.md b/packages/fast-usdc/test/exos/snapshots/advancer.test.ts.md index d704f0b6013..8f795a6e31b 100644 --- a/packages/fast-usdc/test/exos/snapshots/advancer.test.ts.md +++ b/packages/fast-usdc/test/exos/snapshots/advancer.test.ts.md @@ -9,7 +9,7 @@ Generated by [AVA](https://avajs.dev). > Snapshot 1 { - borrowerFacet: Object @match:kind { + borrower: Object @match:kind { payload: 'remotable', }, intermediateRecipient: Object @match:or { @@ -30,7 +30,7 @@ Generated by [AVA](https://avajs.dev). }, ], }, - notifyFacet: Object @match:kind { + notifier: Object @match:kind { payload: 'remotable', }, poolAccount: Object @match:kind { diff --git a/packages/fast-usdc/test/exos/snapshots/advancer.test.ts.snap b/packages/fast-usdc/test/exos/snapshots/advancer.test.ts.snap index 4c1c2b5b8030afbf8efa0ae1e555938dbe26d99e..b807bae2ec43acfd02fcf58a9e1f81eb7687cf1c 100644 GIT binary patch literal 540 zcmV+%0^|KbRzVo8mi2CWI@`LSH67t+hqgdsCZ;yvw**l zUtFkn4IhgL00000000AxlCf?RK@f)j+0C6dHi_>Pcm@hYMS-9IIii3HDO407t?$P1 zCg#LRtIF`Q(BtR(tyXScY4(Zkh8isA;4Oep04@O>P@Gcy zbbP{@Ct6>VBmwP#BG5k3PXO0Rf})hv*j1H#%~c?M`bTaU>$#e7ZnWnk&P-|8`XIa0 zk}2!FnV8iB_gZ97I#-Oc%*|J24_h#;+53WLZ2c(DE3WG+Ut&strH&7gQh%m>Hobpp zY#zKQ67LE4*p(s!Aat=tU)JdB3Mmrb1n^yS(uuaEzw=7~zXgy=;Fj!^#G8wkgvCoh@&83T zw>eLY<5!&OLbF-Q z9yVk>W1Sw)um3S@!ou2on5K5Ns(jXfNyX0PJZ0mCSypmYE&PdsfD>x@5eapt%B7PB z$J%7xQ$*r30bklunNYNp+R_VSkf_gy#3cb&?V{awQ6EI00rpAM{dNj9&#lVp_io8k z>(nUcTE0j0t6{J%Xy8z6!x7250=O@L$70o4Ff2H zZI6hB- Date: Tue, 28 Jan 2025 16:18:27 -0800 Subject: [PATCH 07/10] refactor: name beta-fast-usdc proposal --- .../proposals/{f:fast-usdc => b:beta-fast-usdc}/.gitignore | 0 .../proposals/{f:fast-usdc => b:beta-fast-usdc}/.yarnrc.yml | 0 a3p-integration/proposals/b:beta-fast-usdc/README.md | 3 +++ .../{f:fast-usdc => b:beta-fast-usdc}/package.json | 0 .../proposals/{f:fast-usdc => b:beta-fast-usdc}/test.sh | 0 .../{f:fast-usdc => b:beta-fast-usdc}/test/deploy.test.js | 0 .../test/operators.test.js | 0 .../{f:fast-usdc => b:beta-fast-usdc}/test/test-cli.sh | 0 .../proposals/{f:fast-usdc => b:beta-fast-usdc}/yarn.lock | 0 a3p-integration/proposals/f:fast-usdc/README.md | 6 ------ 10 files changed, 3 insertions(+), 6 deletions(-) rename a3p-integration/proposals/{f:fast-usdc => b:beta-fast-usdc}/.gitignore (100%) rename a3p-integration/proposals/{f:fast-usdc => b:beta-fast-usdc}/.yarnrc.yml (100%) create mode 100644 a3p-integration/proposals/b:beta-fast-usdc/README.md rename a3p-integration/proposals/{f:fast-usdc => b:beta-fast-usdc}/package.json (100%) rename a3p-integration/proposals/{f:fast-usdc => b:beta-fast-usdc}/test.sh (100%) rename a3p-integration/proposals/{f:fast-usdc => b:beta-fast-usdc}/test/deploy.test.js (100%) rename a3p-integration/proposals/{f:fast-usdc => b:beta-fast-usdc}/test/operators.test.js (100%) rename a3p-integration/proposals/{f:fast-usdc => b:beta-fast-usdc}/test/test-cli.sh (100%) rename a3p-integration/proposals/{f:fast-usdc => b:beta-fast-usdc}/yarn.lock (100%) delete mode 100644 a3p-integration/proposals/f:fast-usdc/README.md diff --git a/a3p-integration/proposals/f:fast-usdc/.gitignore b/a3p-integration/proposals/b:beta-fast-usdc/.gitignore similarity index 100% rename from a3p-integration/proposals/f:fast-usdc/.gitignore rename to a3p-integration/proposals/b:beta-fast-usdc/.gitignore diff --git a/a3p-integration/proposals/f:fast-usdc/.yarnrc.yml b/a3p-integration/proposals/b:beta-fast-usdc/.yarnrc.yml similarity index 100% rename from a3p-integration/proposals/f:fast-usdc/.yarnrc.yml rename to a3p-integration/proposals/b:beta-fast-usdc/.yarnrc.yml diff --git a/a3p-integration/proposals/b:beta-fast-usdc/README.md b/a3p-integration/proposals/b:beta-fast-usdc/README.md new file mode 100644 index 00000000000..f3db47c5b64 --- /dev/null +++ b/a3p-integration/proposals/b:beta-fast-usdc/README.md @@ -0,0 +1,3 @@ +# proposal for deploying a beta of Fast USDC + +Because this runs before `n:upgrade-next` its base image isn't a build of the local agoric-sdk. So it can't use `yarn link` to get `@agoric/fast-usdc` from the source tree. Instead it sources the packages from NPM using `dev` to get the latest master builds. diff --git a/a3p-integration/proposals/f:fast-usdc/package.json b/a3p-integration/proposals/b:beta-fast-usdc/package.json similarity index 100% rename from a3p-integration/proposals/f:fast-usdc/package.json rename to a3p-integration/proposals/b:beta-fast-usdc/package.json diff --git a/a3p-integration/proposals/f:fast-usdc/test.sh b/a3p-integration/proposals/b:beta-fast-usdc/test.sh similarity index 100% rename from a3p-integration/proposals/f:fast-usdc/test.sh rename to a3p-integration/proposals/b:beta-fast-usdc/test.sh diff --git a/a3p-integration/proposals/f:fast-usdc/test/deploy.test.js b/a3p-integration/proposals/b:beta-fast-usdc/test/deploy.test.js similarity index 100% rename from a3p-integration/proposals/f:fast-usdc/test/deploy.test.js rename to a3p-integration/proposals/b:beta-fast-usdc/test/deploy.test.js diff --git a/a3p-integration/proposals/f:fast-usdc/test/operators.test.js b/a3p-integration/proposals/b:beta-fast-usdc/test/operators.test.js similarity index 100% rename from a3p-integration/proposals/f:fast-usdc/test/operators.test.js rename to a3p-integration/proposals/b:beta-fast-usdc/test/operators.test.js diff --git a/a3p-integration/proposals/f:fast-usdc/test/test-cli.sh b/a3p-integration/proposals/b:beta-fast-usdc/test/test-cli.sh similarity index 100% rename from a3p-integration/proposals/f:fast-usdc/test/test-cli.sh rename to a3p-integration/proposals/b:beta-fast-usdc/test/test-cli.sh diff --git a/a3p-integration/proposals/f:fast-usdc/yarn.lock b/a3p-integration/proposals/b:beta-fast-usdc/yarn.lock similarity index 100% rename from a3p-integration/proposals/f:fast-usdc/yarn.lock rename to a3p-integration/proposals/b:beta-fast-usdc/yarn.lock diff --git a/a3p-integration/proposals/f:fast-usdc/README.md b/a3p-integration/proposals/f:fast-usdc/README.md deleted file mode 100644 index 1169b747921..00000000000 --- a/a3p-integration/proposals/f:fast-usdc/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# proposal for deploying fast-usdc - -Note that this will run after upgrade-next but for iteration speed it runs before n:upgrade-next in the build sequence. - -A consequence of this is that it can't use `yarn link` to get `@agoric/fast-usdc` because it's not in the base image. Instead it sources the packages from NPM using `dev` to get the latest master builds. - From 570031f5ba927ff4714c6e3a884ead661aaf69e0 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 28 Jan 2025 16:37:45 -0800 Subject: [PATCH 08/10] docs: obsolete TODO --- packages/fast-usdc/src/exos/operator-kit.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/fast-usdc/src/exos/operator-kit.js b/packages/fast-usdc/src/exos/operator-kit.js index eb221c71d92..dde1d9090d5 100644 --- a/packages/fast-usdc/src/exos/operator-kit.js +++ b/packages/fast-usdc/src/exos/operator-kit.js @@ -90,8 +90,6 @@ export const prepareOperatorKit = (zone, staticPowers) => */ async SubmitEvidence(evidence, riskAssessment) { const { operator } = this.facets; - // TODO(bootstrap integration): cause this call to throw and confirm that it - // shows up in the the smart-wallet UpdateRecord `error` property operator.submitEvidence(evidence, riskAssessment); return staticPowers.makeInertInvitation( 'evidence was pushed in the invitation maker call', From 947cca22a15a9c1da1a9b322440e7b4f2b1d9eeb Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 28 Jan 2025 16:49:59 -0800 Subject: [PATCH 09/10] test: make fake bootstrap more credible --- packages/fast-usdc/test/exos/advancer.test.ts | 19 +++++++++++-------- packages/fast-usdc/test/exos/settler.test.ts | 8 ++++---- packages/fast-usdc/test/supports.ts | 6 ++---- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/packages/fast-usdc/test/exos/advancer.test.ts b/packages/fast-usdc/test/exos/advancer.test.ts index 9381c20ccab..00cb4779cc4 100644 --- a/packages/fast-usdc/test/exos/advancer.test.ts +++ b/packages/fast-usdc/test/exos/advancer.test.ts @@ -48,10 +48,10 @@ type CommonSetup = Awaited>; const createTestExtensions = (t, common: CommonSetup) => { const { - bootstrap: { rootZone, vowTools }, facadeServices: { chainHub }, brands: { usdc }, commonPrivateArgs: { storageNode }, + utils: { contractZone, vowTools }, } = common; const { log, inspectLogs } = makeTestLogger(t.log); @@ -61,16 +61,19 @@ const createTestExtensions = (t, common: CommonSetup) => { chainHub.registerChain('osmosis', fetchedChainInfo.osmosis); const statusManager = prepareStatusManager( - rootZone.subZone('status-manager'), + contractZone.subZone('status-manager'), storageNode.makeChildNode('txns'), { marshaller: common.commonPrivateArgs.marshaller }, ); - const mockAccounts = prepareMockOrchAccounts(rootZone.subZone('accounts'), { - vowTools, - log: t.log, - usdc, - }); + const mockAccounts = prepareMockOrchAccounts( + contractZone.subZone('accounts'), + { + vowTools, + log: t.log, + usdc, + }, + ); const mockZCF = Far('MockZCF', { makeEmptySeatKit: () => ({ zcfSeat: Far('MockZCFSeat', {}) }), @@ -94,7 +97,7 @@ const createTestExtensions = (t, common: CommonSetup) => { }); const feeConfig = makeTestFeeConfig(usdc); - const makeAdvancer = prepareAdvancer(rootZone.subZone('advancer'), { + const makeAdvancer = prepareAdvancer(contractZone.subZone('advancer'), { chainHub, feeConfig, localTransfer: mockZoeTools.localTransfer, diff --git a/packages/fast-usdc/test/exos/settler.test.ts b/packages/fast-usdc/test/exos/settler.test.ts index 7c200475e2a..8941c458b7b 100644 --- a/packages/fast-usdc/test/exos/settler.test.ts +++ b/packages/fast-usdc/test/exos/settler.test.ts @@ -49,7 +49,7 @@ const mockZcf = (zone: Zone) => { const makeTestContext = async t => { const common = await commonSetup(t); - const { rootZone: zone } = common.bootstrap; + const { contractZone: zone } = common.utils; const { log, inspectLogs } = makeTestLogger(t.log); const statusManager = prepareStatusManager( zone.subZone('status-manager'), @@ -58,9 +58,9 @@ const makeTestContext = async t => { ); const { zcf, callLog } = mockZcf(zone.subZone('Mock ZCF')); - const { rootZone, vowTools } = common.bootstrap; + const { vowTools } = common.utils; const { usdc } = common.brands; - const mockAccounts = prepareMockOrchAccounts(rootZone.subZone('accounts'), { + const mockAccounts = prepareMockOrchAccounts(zone.subZone('accounts'), { vowTools, log: t.log, usdc, @@ -87,7 +87,7 @@ const makeTestContext = async t => { zcf, withdrawToSeat: mockWithdrawToSeat, feeConfig: common.commonPrivateArgs.feeConfig, - vowTools: common.bootstrap.vowTools, + vowTools: common.utils.vowTools, chainHub, log, }); diff --git a/packages/fast-usdc/test/supports.ts b/packages/fast-usdc/test/supports.ts index 6983f5a709d..16a28e026f0 100644 --- a/packages/fast-usdc/test/supports.ts +++ b/packages/fast-usdc/test/supports.ts @@ -229,11 +229,7 @@ export const commonSetup = async (t: ExecutionContext) => { timer, localchain, cosmosInterchainService, - // TODO remove; bootstrap doesn't have a zone - rootZone: rootZone.subZone('contract'), storage, - // TODO remove; bootstrap doesn't have vowTools - vowTools, }, brands: { usdc: usdcSansMint, @@ -263,11 +259,13 @@ export const commonSetup = async (t: ExecutionContext) => { timerService: timer, }, utils: { + contractZone: rootZone.subZone('contract'), pourPayment, inspectLocalBridge: () => harden([...localBridgeMessages]), inspectDibcBridge: () => E(ibcBridge).inspectDibcBridge(), inspectBankBridge: () => harden([...bankBridgeMessages]), transmitTransferAck, + vowTools, }, }; }; From 450b953b1eb55585b291ea49e8f80601d5de4884 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 28 Jan 2025 17:32:06 -0800 Subject: [PATCH 10/10] feat: error handling for bad event packets --- packages/fast-usdc/src/exos/settler.js | 82 ++++++++++------- packages/fast-usdc/test/exos/settler.test.ts | 95 +++++++++++++++++++- 2 files changed, 146 insertions(+), 31 deletions(-) diff --git a/packages/fast-usdc/src/exos/settler.js b/packages/fast-usdc/src/exos/settler.js index 901ca394474..d9d64ea73da 100644 --- a/packages/fast-usdc/src/exos/settler.js +++ b/packages/fast-usdc/src/exos/settler.js @@ -19,7 +19,7 @@ import { * @import {Amount, Brand, NatValue, Payment} from '@agoric/ertp'; * @import {Denom, OrchestrationAccount, ChainHub, ChainAddress} from '@agoric/orchestration'; * @import {WithdrawToSeat} from '@agoric/orchestration/src/utils/zoe-tools' - * @import {IBCChannelID, VTransferIBCEvent} from '@agoric/vats'; + * @import {IBCChannelID, IBCPacket, VTransferIBCEvent} from '@agoric/vats'; * @import {Zone} from '@agoric/zone'; * @import {HostOf, HostInterface} from '@agoric/async-flow'; * @import {TargetRegistration} from '@agoric/vats/src/bridge-target.js'; @@ -27,6 +27,53 @@ import { * @import {StatusManager} from './status-manager.js'; */ +/** + * @param {IBCPacket} data + * @param {string} remoteDenom + * @returns {{ nfa: NobleAddress, amount: bigint, EUD: string } | {error: object[]}} + */ +const decodeEventPacket = ({ data }, remoteDenom) => { + // NB: may not be a FungibleTokenPacketData or even JSON + /** @type {FungibleTokenPacketData} */ + let tx; + try { + tx = JSON.parse(atob(data)); + } catch (e) { + return { error: ['could not parse packet data', data] }; + } + + // given the sourceChannel check, we can be certain of this cast + const nfa = /** @type {NobleAddress} */ (tx.sender); + + if (tx.denom !== remoteDenom) { + const { denom: actual } = tx; + return { error: ['unexpected denom', { actual, expected: remoteDenom }] }; + } + + let EUD; + try { + ({ EUD } = decodeAddressHook(tx.receiver).query); + if (!EUD) { + return { error: ['no EUD parameter', tx.receiver] }; + } + if (typeof EUD !== 'string') { + return { error: ['EUD is not a string', EUD] }; + } + } catch (e) { + return { error: ['no query params', tx.receiver] }; + } + + let amount; + try { + amount = BigInt(tx.amount); + } catch (e) { + return { error: ['invalid amount', tx.amount] }; + } + + return { nfa, amount, EUD }; +}; +harden(decodeEventPacket); + /** * NOTE: not meant to be parsable. * @@ -158,38 +205,13 @@ export const prepareSettler = ( return; } - // TODO: why is it safe to cast this without a runtime check? - const tx = /** @type {FungibleTokenPacketData} */ ( - JSON.parse(atob(packet.data)) - ); - - // given the sourceChannel check, we can be certain of this cast - const nfa = /** @type {NobleAddress} */ (tx.sender); - - if (tx.denom !== remoteDenom) { - const { denom: actual } = tx; - log('unexpected denom', { actual, expected: remoteDenom }); - return; - } - - let EUD; - try { - ({ EUD } = decodeAddressHook(tx.receiver).query); - if (!EUD) { - log('no EUD parameter', tx.receiver); - return; - } - if (typeof EUD !== 'string') { - log('EUD is not a string', EUD); - return; - } - } catch (e) { - log('no query params', tx.receiver); + const decoded = decodeEventPacket(event.packet, remoteDenom); + if ('error' in decoded) { + log('invalid event packet', decoded.error); return; } - const amount = BigInt(tx.amount); // TODO: what if this throws? - + const { nfa, amount, EUD } = decoded; const { self } = this.facets; const found = statusManager.dequeueStatus(nfa, amount); log('dequeued', found, 'for', nfa, amount); diff --git a/packages/fast-usdc/test/exos/settler.test.ts b/packages/fast-usdc/test/exos/settler.test.ts index 8941c458b7b..a18e57a687f 100644 --- a/packages/fast-usdc/test/exos/settler.test.ts +++ b/packages/fast-usdc/test/exos/settler.test.ts @@ -1,10 +1,14 @@ import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js'; import type { TestFn } from 'ava'; -import { decodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js'; +import { + decodeAddressHook, + encodeAddressHook, +} from '@agoric/cosmic-proto/address-hooks.js'; import { defaultMarshaller } from '@agoric/internal/src/storage-test-utils.js'; import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js'; import fetchedChainInfo from '@agoric/orchestration/src/fetched-chain-info.js'; +import { buildVTransferEvent } from '@agoric/orchestration/tools/ibc-mocks.js'; import type { Zone } from '@agoric/zone'; import { PendingTxStatus, TxStatus } from '../../src/constants.js'; import { @@ -737,3 +741,92 @@ test('slow path, and forward fails (terminal state)', async t => { test.todo('creator facet methods'); test.todo('ignored packets'); + +test('bad packet data', async t => { + const { makeSettler, defaultSettlerParams, repayer, accounts, inspectLogs } = + t.context; + const settler = makeSettler({ + repayer, + settlementAccount: accounts.settlement.account, + ...defaultSettlerParams, + }); + + await settler.tap.receiveUpcall( + buildVTransferEvent({ sourceChannel: 'channel-21' }), + ); + t.deepEqual(inspectLogs().at(-1), [ + 'invalid event packet', + ['unexpected denom', { actual: 'uatom', expected: 'uusdc' }], + ]); + + await settler.tap.receiveUpcall( + buildVTransferEvent({ sourceChannel: 'channel-21', denom: 'uusdc' }), + ); + t.deepEqual(inspectLogs().at(-1), [ + 'invalid event packet', + ['no query params', 'agoric1fakeLCAAddress'], + ]); + + await settler.tap.receiveUpcall( + buildVTransferEvent({ + sourceChannel: 'channel-21', + denom: 'uusdc', + receiver: encodeAddressHook( + // valid but meaningless address + 'agoric1c9gyu460lu70rtcdp95vummd6032psmpdx7wdy', + {}, + ), + }), + ); + t.deepEqual(inspectLogs().at(-1), [ + 'invalid event packet', + [ + 'no EUD parameter', + 'agoric10rchps2sfet5lleu7xhs6ztgeehkm5lz5rpkz0cqzs95zdge', + ], + ]); + + await settler.tap.receiveUpcall( + buildVTransferEvent({ + sourceChannel: 'channel-21', + denom: 'uusdc', + receiver: encodeAddressHook( + // valid but meaningless address + 'agoric1c9gyu460lu70rtcdp95vummd6032psmpdx7wdy', + { EUD: 'cosmos1foo' }, + ), + // @ts-expect-error intentionally bad + amount: 'bad', + }), + ); + t.deepEqual(inspectLogs().at(-1), [ + 'invalid event packet', + ['invalid amount', 'bad'], + ]); + + const goodEvent = buildVTransferEvent({ + sourceChannel: 'channel-21', + denom: 'uusdc', + receiver: encodeAddressHook( + // valid but meaningless address + 'agoric1c9gyu460lu70rtcdp95vummd6032psmpdx7wdy', + { EUD: 'cosmos1foo' }, + ), + }); + await settler.tap.receiveUpcall(goodEvent); + t.deepEqual(inspectLogs().at(-1), [ + '⚠️ tap: minted before observed', + 'cosmos1AccAddress', + 10n, + ]); + + const badJson = { + ...goodEvent, + packet: { ...goodEvent.packet, data: 'not json' }, + }; + await settler.tap.receiveUpcall(badJson); + t.deepEqual(inspectLogs().at(-1), [ + 'invalid event packet', + ['could not parse packet data', 'not json'], + ]); +});