From 02c111b7e6a54528186e37f5408d1a41462e5526 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 17 Dec 2024 07:38:23 -0800 Subject: [PATCH 1/6] feat: storage-test-utils report missing data --- packages/internal/src/storage-test-utils.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/internal/src/storage-test-utils.js b/packages/internal/src/storage-test-utils.js index 6babcb12223..15774a7ec01 100644 --- a/packages/internal/src/storage-test-utils.js +++ b/packages/internal/src/storage-test-utils.js @@ -209,7 +209,9 @@ export const makeFakeStorageKit = (rootPath, rootOptions) => { */ const getValues = path => { assert(resolvedOptions.sequence); - const wrapper = JSON.parse(data.get(path)); + const nodeData = data.get(path); + assert(nodeData, `no data at path ${path}`); + const wrapper = JSON.parse(nodeData); return wrapper.values; }; From 12627eeecb98e1509620da211b5148f63979eb41 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 17 Dec 2024 07:30:49 -0800 Subject: [PATCH 2/6] test: DRY setup of status-manager test --- .../test/exos/status-manager.test.ts | 97 ++++++------------- 1 file changed, 29 insertions(+), 68 deletions(-) diff --git a/packages/fast-usdc/test/exos/status-manager.test.ts b/packages/fast-usdc/test/exos/status-manager.test.ts index 14c45185fa8..7322fe0aeea 100644 --- a/packages/fast-usdc/test/exos/status-manager.test.ts +++ b/packages/fast-usdc/test/exos/status-manager.test.ts @@ -1,16 +1,21 @@ 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 } from '../../src/exos/status-manager.js'; +import { + prepareStatusManager, + type StatusManager, +} from '../../src/exos/status-manager.js'; import { commonSetup, provideDurableZone } from '../supports.js'; import { MockCctpTxEvidences } from '../fixtures.js'; import type { CctpTxEvidence } from '../../src/types.js'; type Common = Awaited>; type TestContext = { - txnsNode: ERef; + statusManager: StatusManager; storage: Common['bootstrap']['storage']; }; @@ -18,18 +23,21 @@ const test = anyTest as TestFn; test.beforeEach(async t => { const common = await commonSetup(t); + const zone = provideDurableZone('status-test'); + const txnsNode = common.commonPrivateArgs.storageNode.makeChildNode('txns'); + const statusManager = prepareStatusManager( + zone.subZone('status-manager'), + txnsNode, + { marshaller: defaultMarshaller }, + ); t.context = { - txnsNode: common.commonPrivateArgs.storageNode.makeChildNode('txns'), + statusManager, storage: common.bootstrap.storage, }; }); test('advance creates new entry with ADVANCED status', t => { - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); statusManager.advance(evidence); @@ -43,11 +51,7 @@ test('advance creates new entry with ADVANCED status', t => { }); test('ADVANCED transactions are published to vstorage', async t => { - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); statusManager.advance(evidence); @@ -61,11 +65,7 @@ test('ADVANCED transactions are published to vstorage', async t => { }); test('observe creates new entry with OBSERVED status', t => { - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); statusManager.observe(evidence); @@ -78,11 +78,7 @@ test('observe creates new entry with OBSERVED status', t => { }); test('OBSERVED transactions are published to vstorage', async t => { - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); statusManager.observe(evidence); @@ -95,11 +91,8 @@ test('OBSERVED transactions are published to vstorage', async t => { }); test('cannot process same tx twice', t => { - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; + const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); statusManager.advance(evidence); @@ -118,11 +111,7 @@ test('cannot process same tx twice', t => { }); test('isSeen checks if a tx has been processed', t => { - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; const e1 = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); t.false(statusManager.hasBeenObserved(e1)); @@ -136,11 +125,7 @@ test('isSeen checks if a tx has been processed', t => { }); test('dequeueStatus removes entries from PendingTxs', t => { - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; const e1 = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); const e2 = MockCctpTxEvidences.AGORIC_PLUS_DYDX(); @@ -188,11 +173,7 @@ test('dequeueStatus removes entries from PendingTxs', t => { }); test('cannot advanceOutcome without ADVANCING entry', t => { - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; const e1 = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); const advanceOutcomeFn = () => statusManager.advanceOutcome(e1.tx.forwardingAddress, e1.tx.amount, true); @@ -217,11 +198,7 @@ test('cannot advanceOutcome without ADVANCING entry', t => { test('advanceOutcome transitions to ADVANCED and ADVANCE_FAILED', async t => { const { storage } = t.context; - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; const e1 = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); const e2 = MockCctpTxEvidences.AGORIC_PLUS_DYDX(); @@ -255,11 +232,7 @@ test('advanceOutcome transitions to ADVANCED and ADVANCE_FAILED', async t => { }); test('dequeueStatus returns undefined when nothing is settleable', t => { - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; const e1 = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); t.is( @@ -269,11 +242,7 @@ test('dequeueStatus returns undefined when nothing is settleable', t => { }); test('dequeueStatus returns first (earliest) matched entry', async t => { - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); // advance two txs @@ -366,20 +335,12 @@ test('dequeueStatus returns first (earliest) matched entry', async t => { }); test('lookupPending returns empty array when presented a key it has not seen', t => { - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; t.deepEqual(statusManager.lookupPending('noble123', 1n), []); }); test('StatusManagerKey logic handles addresses with hyphens', t => { - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; const evidence: CctpTxEvidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); evidence.tx.forwardingAddress = 'noble1-foo'; From 8c5bf8501ab3f810493b4487a5b5401c04a58ab2 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 17 Dec 2024 07:45:02 -0800 Subject: [PATCH 3/6] test: quieter advancer test --- packages/fast-usdc/test/exos/advancer.test.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/fast-usdc/test/exos/advancer.test.ts b/packages/fast-usdc/test/exos/advancer.test.ts index 7f118598f88..384d3547c6e 100644 --- a/packages/fast-usdc/test/exos/advancer.test.ts +++ b/packages/fast-usdc/test/exos/advancer.test.ts @@ -12,6 +12,7 @@ import { type ZoeTools } from '@agoric/orchestration/src/utils/zoe-tools.js'; import { q } from '@endo/errors'; import { Far } from '@endo/pass-style'; import type { TestFn } from 'ava'; +import { makeTracer } from '@agoric/internal'; import { PendingTxStatus } from '../../src/constants.js'; import { prepareAdvancer } from '../../src/exos/advancer.js'; import type { SettlerKit } from '../../src/exos/settler.js'; @@ -26,6 +27,8 @@ import { } from '../mocks.js'; import { commonSetup } from '../supports.js'; +const trace = makeTracer('AdvancerTest', false); + const LOCAL_DENOM = `ibc/${denomHash({ denom: 'uusdc', channelId: @@ -74,7 +77,7 @@ const createTestExtensions = (t, common: CommonSetup) => { }; const mockZoeTools = Far('MockZoeTools', { localTransfer(...args: Parameters) { - console.log('ZoeTools.localTransfer called with', args); + trace('ZoeTools.localTransfer called with', args); return localTransferVK.vow; }, }); @@ -99,7 +102,7 @@ const createTestExtensions = (t, common: CommonSetup) => { const notifyAdvancingResultCalls: NotifyArgs[] = []; const mockNotifyF = Far('Settler Notify Facet', { notifyAdvancingResult: (...args: NotifyArgs) => { - console.log('Settler.notifyAdvancingResult called with', args); + trace('Settler.notifyAdvancingResult called with', args); notifyAdvancingResultCalls.push(args); }, }); From 28cc2f69a7ec6ad9357bbc325f036c7fd4c5249f Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 17 Dec 2024 07:08:25 -0800 Subject: [PATCH 4/6] refactor: inline publishStatus --- packages/fast-usdc/src/exos/status-manager.js | 39 ++++++++----------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/packages/fast-usdc/src/exos/status-manager.js b/packages/fast-usdc/src/exos/status-manager.js index 588126a3b73..af15d95b4cc 100644 --- a/packages/fast-usdc/src/exos/status-manager.js +++ b/packages/fast-usdc/src/exos/status-manager.js @@ -102,12 +102,23 @@ export const prepareStatusManager = ( /** * @param {EvmHash} txId * @param {TransactionRecord} record + * @returns {Promise} */ - const publishTxnRecord = (txId, record) => { + const publishTxnRecord = async (txId, record) => { const txNode = E(txnsNode).makeChildNode(txId, { sequence: true, // avoid overwriting other output in the block }); - void E(txNode).setValue( + + // XXX awkward for publish* to update a store, but it's temporary + if (record.status && TerminalTxStatus[record.status]) { + // UNTIL https://github.com/Agoric/agoric-sdk/issues/7405 + // Queue it for deletion later because if we deleted it now the earlier + // writes in this block would be wiped. For now we keep track of what to + // delete when we know it'll be another block. + storedCompletedTxs.add(txId); + } + + await E(txNode).setValue( JSON.stringify(pureDataMarshaller.toCapData(record)), ); }; @@ -124,22 +135,6 @@ export const prepareStatusManager = ( ); }; - /** - * @param {CctpTxEvidence['txHash']} hash - * @param {TxStatus} status - */ - const publishStatus = (hash, status) => { - // Don't await, just writing to vstorage. - void publishTxnRecord(hash, harden({ status })); - if (TerminalTxStatus[status]) { - // UNTIL https://github.com/Agoric/agoric-sdk/issues/7405 - // Queue it for deletion later because if we deleted it now the earlier - // writes in this block would be wiped. For now we keep track of what to - // delete when we know it'll be another block. - storedCompletedTxs.add(hash); - } - }; - /** * Ensures that `txHash+chainId` has not been processed * and adds entry to `seenTxs` set. @@ -164,7 +159,7 @@ export const prepareStatusManager = ( publishEvidence(txHash, evidence); if (status !== PendingTxStatus.Observed) { // publishEvidence publishes Observed - publishStatus(txHash, status); + void publishTxnRecord(txHash, harden({ status })); } }; @@ -187,7 +182,7 @@ export const prepareStatusManager = ( ]; const txpost = { ...tx, status }; pendingTxs.set(key, harden([...prefix, txpost, ...suffix])); - publishStatus(tx.txHash, status); + void publishTxnRecord(tx.txHash, harden({ status })); } return zone.exo( @@ -315,7 +310,7 @@ export const prepareStatusManager = ( * @param {EvmHash} txHash */ disbursed(txHash) { - publishStatus(txHash, TxStatus.Disbursed); + void publishTxnRecord(txHash, harden({ status: TxStatus.Disbursed })); }, /** @@ -327,7 +322,7 @@ export const prepareStatusManager = ( */ forwarded(txHash, nfa, amount) { if (txHash) { - publishStatus(txHash, TxStatus.Forwarded); + void publishTxnRecord(txHash, harden({ status: TxStatus.Forwarded })); } else { // TODO store (early) `Minted` transactions to check against incoming evidence log( From e3f49bef04ae889ad5716e3c370080fdddb0bf36 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 17 Dec 2024 07:40:20 -0800 Subject: [PATCH 5/6] refactor: full marshaller --- packages/fast-usdc/src/exos/status-manager.js | 16 +++++++++------- packages/fast-usdc/src/fast-usdc.contract.js | 1 + packages/fast-usdc/test/exos/advancer.test.ts | 13 ++++++++----- packages/fast-usdc/test/exos/settler.test.ts | 5 +++-- packages/fast-usdc/test/supports.ts | 9 ++------- 5 files changed, 23 insertions(+), 21 deletions(-) diff --git a/packages/fast-usdc/src/exos/status-manager.js b/packages/fast-usdc/src/exos/status-manager.js index af15d95b4cc..0e597348f83 100644 --- a/packages/fast-usdc/src/exos/status-manager.js +++ b/packages/fast-usdc/src/exos/status-manager.js @@ -1,14 +1,14 @@ -import { M } from '@endo/patterns'; -import { Fail, makeError, q } from '@endo/errors'; +import { makeTracer } from '@agoric/internal'; import { appendToStoredArray } from '@agoric/store/src/stores/store-utils.js'; +import { Fail, makeError, q } from '@endo/errors'; import { E } from '@endo/eventual-send'; -import { makeTracer, pureDataMarshaller } from '@agoric/internal'; +import { M } from '@endo/patterns'; +import { PendingTxStatus, TerminalTxStatus, TxStatus } from '../constants.js'; import { CctpTxEvidenceShape, EvmHashShape, PendingTxShape, } from '../type-guards.js'; -import { PendingTxStatus, TerminalTxStatus, TxStatus } from '../constants.js'; /** * @import {MapStore, SetStore} from '@agoric/store'; @@ -48,6 +48,7 @@ const pendingTxKeyOf = evidence => { /** * @typedef {{ * log?: LogFn; + * marshaller: ERef; * }} StatusManagerPowers */ @@ -66,6 +67,7 @@ export const prepareStatusManager = ( zone, txnsNode, { + marshaller, log = makeTracer('Advancer', true), } = /** @type {StatusManagerPowers} */ ({}), ) => { @@ -118,9 +120,9 @@ export const prepareStatusManager = ( storedCompletedTxs.add(txId); } - await E(txNode).setValue( - JSON.stringify(pureDataMarshaller.toCapData(record)), - ); + const capData = await E(marshaller).toCapData(record); + + await E(txNode).setValue(JSON.stringify(capData)); }; /** diff --git a/packages/fast-usdc/src/fast-usdc.contract.js b/packages/fast-usdc/src/fast-usdc.contract.js index 80f8c4a6df1..b9629bb05c3 100644 --- a/packages/fast-usdc/src/fast-usdc.contract.js +++ b/packages/fast-usdc/src/fast-usdc.contract.js @@ -112,6 +112,7 @@ export const contract = async (zcf, privateArgs, zone, tools) => { const statusManager = prepareStatusManager( zone, E(storageNode).makeChildNode(TXNS_NODE), + { marshaller }, ); const { USDC } = terms.brands; diff --git a/packages/fast-usdc/test/exos/advancer.test.ts b/packages/fast-usdc/test/exos/advancer.test.ts index 384d3547c6e..4bb122220df 100644 --- a/packages/fast-usdc/test/exos/advancer.test.ts +++ b/packages/fast-usdc/test/exos/advancer.test.ts @@ -53,6 +53,7 @@ const createTestExtensions = (t, common: CommonSetup) => { const statusManager = prepareStatusManager( rootZone.subZone('status-manager'), storageNode.makeChildNode('txns'), + { marshaller: common.commonPrivateArgs.marshaller }, ); const mockAccounts = prepareMockOrchAccounts(rootZone.subZone('accounts'), { @@ -170,7 +171,7 @@ test.beforeEach(async t => { test('updates status to ADVANCING in happy path', async t => { const { extensions: { - services: { advancer, feeTools, statusManager }, + services: { advancer, feeTools }, helpers: { inspectLogs, inspectNotifyCalls }, mocks: { mockPoolAccount, resolveLocalTransferV }, }, @@ -238,7 +239,7 @@ test('updates status to OBSERVED on insufficient pool funds', async t => { brands: { usdc }, bootstrap: { storage }, extensions: { - services: { makeAdvancer, statusManager }, + services: { makeAdvancer }, helpers: { inspectLogs }, mocks: { mockPoolAccount, mockNotifyF }, }, @@ -286,13 +287,14 @@ test('updates status to OBSERVED if makeChainAddress fails', async t => { const { bootstrap: { storage }, extensions: { - services: { advancer, statusManager }, + services: { advancer }, helpers: { inspectLogs }, }, } = t.context; const evidence = MockCctpTxEvidences.AGORIC_UNKNOWN_EUD(); await advancer.handleTransactionEvent(evidence); + await eventLoopIteration(); t.deepEqual( storage.getDeserialized(`fun.txns.${evidence.txHash}`), @@ -313,7 +315,7 @@ test('calls notifyAdvancingResult (AdvancedFailed) on failed transfer', async t const { bootstrap: { storage }, extensions: { - services: { advancer, feeTools, statusManager }, + services: { advancer, feeTools }, helpers: { inspectLogs, inspectNotifyCalls }, mocks: { mockPoolAccount, resolveLocalTransferV }, }, @@ -366,7 +368,7 @@ test('updates status to OBSERVED if pre-condition checks fail', async t => { const { bootstrap: { storage }, extensions: { - services: { advancer, statusManager }, + services: { advancer }, helpers: { inspectLogs }, }, } = t.context; @@ -374,6 +376,7 @@ test('updates status to OBSERVED if pre-condition checks fail', async t => { const evidence = MockCctpTxEvidences.AGORIC_NO_PARAMS(); await advancer.handleTransactionEvent(evidence); + await eventLoopIteration(); t.deepEqual( storage.getDeserialized(`fun.txns.${evidence.txHash}`), diff --git a/packages/fast-usdc/test/exos/settler.test.ts b/packages/fast-usdc/test/exos/settler.test.ts index f23f90702d4..bedcf3f6065 100644 --- a/packages/fast-usdc/test/exos/settler.test.ts +++ b/packages/fast-usdc/test/exos/settler.test.ts @@ -4,6 +4,7 @@ import type { TestFn } from 'ava'; 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 { defaultMarshaller } from '@agoric/internal/src/storage-test-utils.js'; import { PendingTxStatus } from '../../src/constants.js'; import { prepareSettler } from '../../src/exos/settler.js'; import { prepareStatusManager } from '../../src/exos/status-manager.js'; @@ -48,7 +49,7 @@ const makeTestContext = async t => { const statusManager = prepareStatusManager( zone.subZone('status-manager'), common.commonPrivateArgs.storageNode.makeChildNode('txns'), - { log }, + { marshaller: defaultMarshaller, log }, ); const { zcf, callLog } = mockZcf(zone.subZone('Mock ZCF')); @@ -239,7 +240,7 @@ test('happy path: disburse to LPs; StatusManager removes tx', async t => { { evidence: cctpTxEvidence, status: 'OBSERVED' }, { status: 'ADVANCING' }, { status: 'ADVANCED' }, - { status: 'DISBURSED' }, + { split: expectedSplit, status: 'DISBURSED' }, ]); // Check deletion of DISBURSED transactions diff --git a/packages/fast-usdc/test/supports.ts b/packages/fast-usdc/test/supports.ts index 8ecdc66bdb6..984352b3c07 100644 --- a/packages/fast-usdc/test/supports.ts +++ b/packages/fast-usdc/test/supports.ts @@ -1,7 +1,6 @@ import { makeIssuerKit } from '@agoric/ertp'; import { VTRANSFER_IBC_EVENT } from '@agoric/internal/src/action-types.js'; import { - defaultMarshaller, defaultSerializer, makeFakeStorageKit, } from '@agoric/internal/src/storage-test-utils.js'; @@ -28,10 +27,7 @@ import { makeWellKnownSpaces } from '@agoric/vats/src/core/utils.js'; import { prepareLocalChainTools } from '@agoric/vats/src/localchain.js'; import { prepareTransferTools } from '@agoric/vats/src/transfer.js'; import { makeFakeBankManagerKit } from '@agoric/vats/tools/bank-utils.js'; -import { - makeFakeBoard, - pureDataMarshaller, -} from '@agoric/vats/tools/board-utils.js'; +import { makeFakeBoard } from '@agoric/vats/tools/board-utils.js'; import { makeFakeLocalchainBridge, makeFakeTransferBridge, @@ -44,7 +40,6 @@ import { makeHeapZone, type Zone } from '@agoric/zone'; import { makeDurableZone } from '@agoric/zone/durable.js'; import { E } from '@endo/far'; import type { ExecutionContext } from 'ava'; -import type { PureData } from '@endo/pass-style'; import { makeTestFeeConfig } from './mocks.js'; export { @@ -156,7 +151,7 @@ export const commonSetup = async (t: ExecutionContext) => { transfer: transferMiddleware, }); const timer = buildZoeManualTimer(t.log); - const marshaller = makeFakeBoard().getReadonlyMarshaller(); + const marshaller = makeFakeBoard().getPublishingMarshaller(); const storage = makeFakeStorageKit( 'fun', // Fast USDC Node ); From 884697238ad5f8a112ed24616b10c3b3a94af737 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 17 Dec 2024 07:14:41 -0800 Subject: [PATCH 6/6] feat: record fee split in transaction --- packages/fast-usdc/src/exos/settler.js | 2 +- packages/fast-usdc/src/exos/status-manager.js | 13 ++++++++++--- packages/fast-usdc/src/types.ts | 2 ++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/fast-usdc/src/exos/settler.js b/packages/fast-usdc/src/exos/settler.js index 727e02bfbb0..fc6708eedee 100644 --- a/packages/fast-usdc/src/exos/settler.js +++ b/packages/fast-usdc/src/exos/settler.js @@ -260,7 +260,7 @@ export const prepareSettler = ( repayer.repay(settlingSeat, split); // update status manager, marking tx `SETTLED` - statusManager.disbursed(txHash); + statusManager.disbursed(txHash, split); }, /** * @param {EvmHash} txHash diff --git a/packages/fast-usdc/src/exos/status-manager.js b/packages/fast-usdc/src/exos/status-manager.js index 0e597348f83..6f264fd8997 100644 --- a/packages/fast-usdc/src/exos/status-manager.js +++ b/packages/fast-usdc/src/exos/status-manager.js @@ -1,5 +1,6 @@ import { makeTracer } from '@agoric/internal'; import { appendToStoredArray } from '@agoric/store/src/stores/store-utils.js'; +import { AmountKeywordRecordShape } from '@agoric/zoe/src/typeGuards.js'; import { Fail, makeError, q } from '@endo/errors'; import { E } from '@endo/eventual-send'; import { M } from '@endo/patterns'; @@ -209,7 +210,9 @@ export const prepareStatusManager = ( M.undefined(), ), ), - disbursed: M.call(EvmHashShape).returns(M.undefined()), + disbursed: M.call(EvmHashShape, AmountKeywordRecordShape).returns( + M.undefined(), + ), forwarded: M.call(M.opt(EvmHashShape), M.string(), M.nat()).returns( M.undefined(), ), @@ -310,9 +313,13 @@ export const prepareStatusManager = ( * Mark a transaction as `DISBURSED` * * @param {EvmHash} txHash + * @param {import('./liquidity-pool.js').RepayAmountKWR} split */ - disbursed(txHash) { - void publishTxnRecord(txHash, harden({ status: TxStatus.Disbursed })); + disbursed(txHash, split) { + void publishTxnRecord( + txHash, + harden({ split, status: TxStatus.Disbursed }), + ); }, /** diff --git a/packages/fast-usdc/src/types.ts b/packages/fast-usdc/src/types.ts index 0d3701e9d82..44f9669613d 100644 --- a/packages/fast-usdc/src/types.ts +++ b/packages/fast-usdc/src/types.ts @@ -9,6 +9,7 @@ import type { Amount } from '@agoric/ertp'; import type { CopyRecord, Passable } from '@endo/pass-style'; import type { PendingTxStatus, TxStatus } from './constants.js'; import type { FastUsdcTerms } from './fast-usdc.contract.js'; +import type { RepayAmountKWR } from './exos/liquidity-pool.js'; export type EvmHash = `0x${string}`; export type EvmAddress = `0x${string & { length: 40 }}`; @@ -40,6 +41,7 @@ export interface CctpTxEvidence { */ export interface TransactionRecord extends CopyRecord { evidence?: CctpTxEvidence; + split?: RepayAmountKWR; status: TxStatus; }