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. - 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/src/exos/advancer.js b/packages/fast-usdc/src/exos/advancer.js index dc2a66be816..1708b0193d8 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({ + notifier: M.remotable(), + borrower: M.remotable(), + poolAccount: M.remotable(), + intermediateRecipient: M.opt(ChainAddressShape), + settlementAddress: M.opt(ChainAddressShape), +}); + /** * @param {Zone} zone * @param {AdvancerKitPowers} caps @@ -114,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; @@ -165,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, ); @@ -178,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); @@ -249,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); } @@ -263,37 +271,31 @@ 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); }, }, }, { - 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/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/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', diff --git a/packages/fast-usdc/src/exos/settler.js b/packages/fast-usdc/src/exos/settler.js index d04ec78063e..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. * @@ -45,6 +92,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 @@ -81,7 +138,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(), @@ -148,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); @@ -206,7 +238,7 @@ export const prepareSettler = ( } }, }, - notify: { + notifier: { /** * @param {object} ctx * @param {EvmHash} ctx.txHash @@ -337,21 +369,11 @@ 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, }, ); }; 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/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/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/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 ce6f8448793..00cb4779cc4 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, @@ -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, @@ -109,7 +112,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 +145,8 @@ const createTestExtensions = (t, common: CommonSetup) => { }); const advancer = makeAdvancer({ - borrowerFacet: mockBorrowerF, - notifyFacet: mockNotifyF, + borrower: mockBorrowerF, + notifier: mockNotifyF, poolAccount: mockAccounts.mockPoolAccount.account, intermediateRecipient, settlementAddress, @@ -189,6 +192,10 @@ test.beforeEach(async t => { }; }); +test('stateShape', t => { + t.snapshot(stateShape); +}); + test('updates status to ADVANCING in happy path', async t => { const { extensions: { @@ -276,8 +283,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, @@ -599,8 +606,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, @@ -691,8 +698,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/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/settler.test.ts b/packages/fast-usdc/test/exos/settler.test.ts index 4bed4311dae..a18e57a687f 100644 --- a/packages/fast-usdc/test/exos/settler.test.ts +++ b/packages/fast-usdc/test/exos/settler.test.ts @@ -1,13 +1,21 @@ 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 { 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'; @@ -45,7 +53,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'), @@ -54,9 +62,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, @@ -83,7 +91,7 @@ const makeTestContext = async t => { zcf, withdrawToSeat: mockWithdrawToSeat, feeConfig: common.commonPrivateArgs.feeConfig, - vowTools: common.bootstrap.vowTools, + vowTools: common.utils.vowTools, chainHub, log, }); @@ -96,7 +104,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(), @@ -141,7 +149,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 @@ -180,7 +188,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; }, }); @@ -211,6 +219,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, @@ -230,7 +242,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( @@ -331,7 +343,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( @@ -410,7 +422,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( @@ -491,7 +503,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()); @@ -563,7 +575,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; @@ -617,7 +629,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'); @@ -683,7 +695,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( @@ -729,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'], + ]); +}); 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..8f795a6e31b --- /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 + + { + borrower: 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: [], + }, + }, + ], + }, + notifier: 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 00000000000..b807bae2ec4 Binary files /dev/null and b/packages/fast-usdc/test/exos/snapshots/advancer.test.ts.snap differ 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 00000000000..7b6d637be92 Binary files /dev/null and b/packages/fast-usdc/test/exos/snapshots/liquidity-pool.test.ts.snap differ diff --git a/packages/fast-usdc/test/exos/snapshots/settler.test.ts.md b/packages/fast-usdc/test/exos/snapshots/settler.test.ts.md new file mode 100644 index 00000000000..2ac29525e21 --- /dev/null +++ b/packages/fast-usdc/test/exos/snapshots/settler.test.ts.md @@ -0,0 +1,63 @@ +# Snapshot report for `test/exos/settler.test.ts` + +The actual snapshot is saved in `settler.test.ts.snap`. + +Generated by [AVA](https://avajs.dev). + +## stateShape + +> 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 00000000000..51f80fcb163 Binary files /dev/null and b/packages/fast-usdc/test/exos/snapshots/settler.test.ts.snap differ 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 00000000000..093a925906c Binary files /dev/null and b/packages/fast-usdc/test/exos/snapshots/status-manager.test.ts.snap differ 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 00000000000..e46b33e65eb Binary files /dev/null and b/packages/fast-usdc/test/exos/snapshots/transaction-feed.test.ts.snap differ 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'); 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/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, }, }; }; 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; 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} */ 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);