diff --git a/packages/fast-usdc/test/fast-usdc.contract.test.ts b/packages/fast-usdc/test/fast-usdc.contract.test.ts index d9b6912ee7d..f2cdd2698e2 100644 --- a/packages/fast-usdc/test/fast-usdc.contract.test.ts +++ b/packages/fast-usdc/test/fast-usdc.contract.test.ts @@ -24,7 +24,7 @@ import { import type { Instance } from '@agoric/zoe/src/zoeService/utils.js'; import { setUpZoeForTest } from '@agoric/zoe/tools/setup-zoe.js'; import { E } from '@endo/far'; -import { objectMap } from '@endo/patterns'; +import { matches, objectMap } from '@endo/patterns'; import path from 'path'; import type { ScopedBridgeManager } from '@agoric/vats'; import { makePromiseKit } from '@endo/promise-kit'; @@ -36,6 +36,7 @@ import { addressTools } from '../src/utils/address.js'; import { makeFeeTools } from '../src/utils/fees.js'; import { MockCctpTxEvidences } from './fixtures.js'; import { commonSetup } from './supports.js'; +import { PoolMetricsShape } from '../src/type-guards.js'; const dirname = path.dirname(new URL(import.meta.url).pathname); @@ -618,6 +619,9 @@ const makeCustomer = ( ) => { const evidence = sent.shift(); if (!evidence) throw t.fail('nothing sent'); + + // C3 - Contract MUST calculate AdvanceAmount by ... + // Mostly, see unit tests for calculateAdvance, calculateSplit const toReceive = forward ? { value: evidence.tx.amount } : feeTools.calculateAdvance(AmountMath.make(USDC, evidence.tx.amount)); @@ -630,6 +634,7 @@ const makeCustomer = ( const { EUD } = addressTools.getQueryParams( evidence.aux.recipientAddress, ); + const myMsg = local.find(lm => { if (lm.type !== 'VLOCALCHAIN_EXECUTE_TX') return false; const [ibcTransferMsg] = lm.messages; @@ -644,10 +649,14 @@ const makeCustomer = ( throw t.fail(`no MsgTransfer to ${EUD}`); } const [ibcTransferMsg] = myMsg.messages; - t.deepEqual(ibcTransferMsg.token, { - amount: String(toReceive.value), - denom: uusdcOnAgoric, - }); + // C4 - Contract MUST release funds to the end user destination address + // in response to invocation by the off-chain watcher that + // an acceptable Fast USDC Transaction has been initiated. + t.deepEqual( + ibcTransferMsg.token, + { amount: String(toReceive.value), denom: uusdcOnAgoric }, + 'C4', + ); t.log(who, 'sees', ibcTransferMsg.token, 'sent to', EUD); // TODO #10445 expect PFM memo @@ -683,7 +692,20 @@ test.serial('OCW operators redeem invitations and start watching', async t => { // TODO: replace test.serial() with promise synchronization? -test.serial('customer tries before LPs provide liquidity', async t => { +test.serial('STORY09: Fast USDC off: insufficient liquidity', async t => { + const { + common: { + commonPrivateArgs: { feeConfig }, + }, + evm: { cctp, txPub }, + startKit: { metricsSub }, + } = t.context; + const early = makeCustomer('Unice', cctp, txPub.publisher, feeConfig, t); + const available = await early.checkPoolAvailable(5_000_000n, metricsSub); + t.false(available); +}); + +test.serial('C20 - customer tries before LPs provide liquidity', async t => { const { common: { commonPrivateArgs: { feeConfig }, @@ -708,7 +730,7 @@ test.serial('customer tries before LPs provide liquidity', async t => { // fulfilled" in the test output. }); -test.serial('LPs deposit USDC', async t => { +test.serial('C25 - LPs deposit USDC', async t => { const { startKit: { zoe, instance, metricsSub }, common: { @@ -718,6 +740,7 @@ test.serial('LPs deposit USDC', async t => { sync, } = t.context; const usdcPurse = purseOf(usdc.issuer, utils); + // C25 - MUST support multiple liquidity providers const lp = { lp50: makeLP('Logan', usdcPurse(50_000_000n), zoe, instance, t), lp200: makeLP('Larry', usdcPurse(200_000_000n), zoe, instance, t), @@ -743,7 +766,7 @@ test.serial('LPs deposit USDC', async t => { t.deepEqual(poolBalance, make(usdc.brand, 250_000_000n + balance0.value)); }); -test.serial('advancing happy path for 100 USDC', async t => { +test.serial('STORY01: advancing happy path for 100 USDC', async t => { const { common: { brands: { usdc }, @@ -804,6 +827,10 @@ test.serial('advancing happy path for 100 USDC', async t => { await mint(sent1); + // C8 - "Contract MUST be able to initialize settlement process when Noble mints USDC." + // The metrics are a useful proxy, but the contract could lie. + // The real test of whether the contract turns minted funds into liquidity is + // the ability to advance the funds (in later tests). const split = calculateSplit(usdc.make(sent1.tx.amount)); t.like( await E(metricsSub) @@ -824,20 +851,44 @@ test.serial('advancing happy path for 100 USDC', async t => { ); }); -test.serial('LP withdraws part; collects fees on 100 USDC', async t => { +test.todo( + 'PERF: Target: settlement completes in a few minutes (after USDC is minted)', +); + +// most likely in exo unit tests +test.todo( + 'C21 - Contract MUST log / timestamp each step in the transaction flow', +); + +test.serial('STORY03: see accounting metrics', async t => { const { - sync, common: { brands: { usdc }, - commonPrivateArgs: { feeConfig }, }, + startKit: { metricsSub }, } = t.context; + const { value: metrics } = await E(metricsSub).getUpdateSince(); - const { calculateSplit } = makeFeeTools(feeConfig); - const split = calculateSplit(usdc.make(100_000_000n)); + t.log(metrics); + t.true(matches(metrics, PoolMetricsShape)); +}); +test.todo('document metrics storage schema'); +test.todo('get metrics from vstorage'); + +test.serial('STORY05: LP collects fees on 100 USDC', async t => { + const { + sync, + common: { + brands: { usdc }, + }, + } = t.context; const lp = await sync.lp.promise; const got = await E(lp.lp200).withdraw(0.5); // redeem 1/2 my shares + + // C3 - Contract MUST calculate ... + // Mostly, see unit tests for calculateAdvance, calculateSplit + // TODO: add a feeTools unit test for the magic number below. t.deepEqual(got, add(usdc.units(100), usdc.make(691_200n))); await E(lp.lp200).deposit(100_000_000n); // put all but the fees back in @@ -879,6 +930,13 @@ test.serial('racers', async t => { await Promise.all([mint(sent1), mint(sent2), mint(sent3)]); }); +// advancedEarly stuff +test.todo( + 'C12 - Contract MUST only pay back the Pool only if they started the advance before USDC is minted', +); + +test.todo('C18 - forward - MUST log and alert these incidents'); + test.serial('Settlement for unknown transaction (operator down)', async t => { const { sync,