diff --git a/packages/fast-usdc/src/exos/advancer.js b/packages/fast-usdc/src/exos/advancer.js index f5a9f8afd09..f244ced3884 100644 --- a/packages/fast-usdc/src/exos/advancer.js +++ b/packages/fast-usdc/src/exos/advancer.js @@ -116,6 +116,7 @@ export const prepareAdvancerKit = ( * notifyFacet: import('./settler.js').SettlerKit['notify']; * borrowerFacet: LiquidityPoolKit['borrower']; * poolAccount: HostInterface>; + * intermediateRecipient: ChainAddress; * }} config */ config => harden(config), @@ -187,12 +188,20 @@ export const prepareAdvancerKit = ( * @param {AdvancerVowCtx & { tmpSeat: ZCFSeat }} ctx */ onFulfilled(result, ctx) { - const { poolAccount } = this.state; + const { poolAccount, intermediateRecipient } = this.state; const { destination, advanceAmount, ...detail } = ctx; - const transferV = E(poolAccount).transfer(destination, { - denom: usdc.denom, - value: advanceAmount.value, - }); + const transferV = E(poolAccount).transfer( + destination, + { + denom: usdc.denom, + value: advanceAmount.value, + }, + { + forwardOpts: { + intermediateRecipient, + }, + }, + ); return watch(transferV, this.facets.transferHandler, { destination, advanceAmount, @@ -250,6 +259,7 @@ export const prepareAdvancerKit = ( notifyFacet: M.remotable(), borrowerFacet: M.remotable(), poolAccount: M.remotable(), + intermediateRecipient: ChainAddressShape, }), }, ); diff --git a/packages/fast-usdc/src/exos/settler.js b/packages/fast-usdc/src/exos/settler.js index 72f1e1f9626..035c288cabd 100644 --- a/packages/fast-usdc/src/exos/settler.js +++ b/packages/fast-usdc/src/exos/settler.js @@ -1,5 +1,6 @@ import { AmountMath } from '@agoric/ertp'; import { assertAllDefined, makeTracer } from '@agoric/internal'; +import { ChainAddressShape } from '@agoric/orchestration'; import { atob } from '@endo/base64'; import { E } from '@endo/far'; import { M } from '@endo/patterns'; @@ -93,6 +94,7 @@ export const prepareSettler = ( * remoteDenom: Denom; * repayer: LiquidityPoolKit['repayer']; * settlementAccount: HostInterface> + * intermediateRecipient: ChainAddress; * }} config */ config => { @@ -255,7 +257,7 @@ export const prepareSettler = ( * @param {string} EUD */ forward(txHash, sender, fullValue, EUD) { - const { settlementAccount } = this.state; + const { settlementAccount, intermediateRecipient } = this.state; const dest = chainHub.makeChainAddress(EUD); @@ -263,6 +265,11 @@ export const prepareSettler = ( const txfrV = E(settlementAccount).transfer( dest, AmountMath.make(USDC, fullValue), + { + forwardOpts: { + intermediateRecipient, + }, + }, ); void vowTools.watch(txfrV, this.facets.transferHandler, { txHash, @@ -305,6 +312,7 @@ export const prepareSettler = ( sourceChannel: M.string(), remoteDenom: M.string(), mintedEarly: M.remotable('mintedEarly'), + intermediateRecipient: ChainAddressShape, }), }, ); diff --git a/packages/fast-usdc/src/fast-usdc.contract.js b/packages/fast-usdc/src/fast-usdc.contract.js index aa799e101d2..eb91487bbc4 100644 --- a/packages/fast-usdc/src/fast-usdc.contract.js +++ b/packages/fast-usdc/src/fast-usdc.contract.js @@ -140,7 +140,7 @@ export const contract = async (zcf, privateArgs, zone, tools) => { 'test of forcing evidence', ); - const { makeLocalAccount } = orchestrateAll(flows, {}); + const { makeLocalAccount, makeNobleAccount } = orchestrateAll(flows, {}); const creatorFacet = zone.exo('Fast USDC Creator', undefined, { /** @type {(operatorId: string) => Promise>} */ @@ -214,7 +214,7 @@ export const contract = async (zcf, privateArgs, zone, tools) => { privateArgs.assetInfo, ); } - + const nobleAccountV = zone.makeOnce('NobleAccount', () => makeNobleAccount()); const feedKit = zone.makeOnce('Feed Kit', () => makeFeedKit()); const poolAccountV = zone.makeOnce('PoolAccount', () => makeLocalAccount()); @@ -222,10 +222,18 @@ export const contract = async (zcf, privateArgs, zone, tools) => { makeLocalAccount(), ); // when() is OK here since this clearly resolves promptly. - /** @type {HostInterface>[]} */ - const [poolAccount, settlementAccount] = await vowTools.when( - vowTools.all([poolAccountV, settleAccountV]), + /** @type {[HostInterface>, HostInterface>, HostInterface>]} */ + const [nobleAccount, poolAccount, settlementAccount] = await vowTools.when( + vowTools.all([nobleAccountV, poolAccountV, settleAccountV]), + ); + trace('settlementAccount', settlementAccount); + trace('poolAccount', poolAccount); + trace('nobleAccount', nobleAccount); + + const intermediateRecipient = await vowTools.when( + E(nobleAccount).getAddress(), ); + trace('intermediateRecipient', intermediateRecipient); const [_agoric, _noble, agToNoble] = await vowTools.when( chainHub.getChainsAndConnection('agoric', 'noble'), @@ -235,6 +243,7 @@ export const contract = async (zcf, privateArgs, zone, tools) => { sourceChannel: agToNoble.transferChannel.counterPartyChannelId, remoteDenom: 'uusdc', settlementAccount, + intermediateRecipient, }); const advancer = zone.makeOnce('Advancer', () => @@ -242,6 +251,7 @@ export const contract = async (zcf, privateArgs, zone, tools) => { borrowerFacet: poolKit.borrower, notifyFacet: settlerKit.notify, poolAccount, + intermediateRecipient, }), ); // Connect evidence stream to advancer diff --git a/packages/fast-usdc/src/fast-usdc.flows.js b/packages/fast-usdc/src/fast-usdc.flows.js index 9f330a4c905..a9aedd6228e 100644 --- a/packages/fast-usdc/src/fast-usdc.flows.js +++ b/packages/fast-usdc/src/fast-usdc.flows.js @@ -11,3 +11,13 @@ export const makeLocalAccount = async orch => { return agoricChain.makeAccount(); }; harden(makeLocalAccount); + +/** + * @satisfies {OrchestrationFlow} + * @param {Orchestrator} orch + */ +export const makeNobleAccount = async orch => { + const nobleChain = await orch.getChain('noble'); + return nobleChain.makeAccount(); +}; +harden(makeNobleAccount); diff --git a/packages/fast-usdc/test/exos/advancer.test.ts b/packages/fast-usdc/test/exos/advancer.test.ts index 0921fb4838f..818554dacca 100644 --- a/packages/fast-usdc/test/exos/advancer.test.ts +++ b/packages/fast-usdc/test/exos/advancer.test.ts @@ -14,7 +14,7 @@ import { prepareStatusManager } from '../../src/exos/status-manager.js'; import { makeFeeTools } from '../../src/utils/fees.js'; import { addressTools } from '../../src/utils/address.js'; import { commonSetup } from '../supports.js'; -import { MockCctpTxEvidences } from '../fixtures.js'; +import { MockCctpTxEvidences, intermediateRecipient } from '../fixtures.js'; import { makeTestFeeConfig, makeTestLogger, @@ -113,6 +113,7 @@ const createTestExtensions = (t, common: CommonSetup) => { borrowerFacet: mockBorrowerF, notifyFacet: mockNotifyF, poolAccount: mockAccounts.mockPoolAccount.account, + intermediateRecipient, }); return { @@ -221,6 +222,7 @@ test('updates status to OBSERVED on insufficient pool funds', async t => { borrowerFacet: mockBorrowerErrorF, notifyFacet: mockNotifyF, poolAccount: mockPoolAccount.account, + intermediateRecipient, }); const mockEvidence = MockCctpTxEvidences.AGORIC_PLUS_DYDX(); diff --git a/packages/fast-usdc/test/exos/settler.test.ts b/packages/fast-usdc/test/exos/settler.test.ts index c970f55eaed..f900c7cd191 100644 --- a/packages/fast-usdc/test/exos/settler.test.ts +++ b/packages/fast-usdc/test/exos/settler.test.ts @@ -9,7 +9,11 @@ import { prepareSettler } 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'; -import { MockCctpTxEvidences, MockVTransferEvents } from '../fixtures.js'; +import { + MockCctpTxEvidences, + MockVTransferEvents, + intermediateRecipient, +} from '../fixtures.js'; import { makeTestLogger, prepareMockOrchAccounts } from '../mocks.js'; import { commonSetup } from '../supports.js'; @@ -87,6 +91,7 @@ const makeTestContext = async t => { fetchedChainInfo.agoric.connections['noble-1'].transferChannel .counterPartyChannelId, remoteDenom: 'uusdc', + intermediateRecipient, }); const simulate = harden({ @@ -280,6 +285,15 @@ test('slow path: forward to EUD; remove pending tx', async t => { value: 'osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men', }, usdc.units(150), + { + forwardOpts: { + intermediateRecipient: { + chainId: 'noble-1', + encoding: 'bech32', + value: 'noble1test', + }, + }, + }, ], ]); diff --git a/packages/fast-usdc/test/fast-usdc.contract.test.ts b/packages/fast-usdc/test/fast-usdc.contract.test.ts index a2fb779be97..c622acd50a7 100644 --- a/packages/fast-usdc/test/fast-usdc.contract.test.ts +++ b/packages/fast-usdc/test/fast-usdc.contract.test.ts @@ -97,6 +97,7 @@ const startContract = async ( const makeTestContext = async (t: ExecutionContext) => { const common = await commonSetup(t); + await E(common.mocks.ibcBridge).setAddressPrefix('noble'); const startKit = await startContract(common, 2); @@ -405,7 +406,7 @@ const makeCustomer = ( const [ibcTransferMsg] = lm.messages; // support advances to noble + other chains const receiver = - ibcTransferMsg.receiver === 'pfm' + ibcTransferMsg.receiver === 'noble1test' // intermediateRecipient value ? JSON.parse(ibcTransferMsg.memo).forward.receiver : ibcTransferMsg.receiver; return ( diff --git a/packages/fast-usdc/test/fixtures.ts b/packages/fast-usdc/test/fixtures.ts index 32af6aa2126..cbd83ccb657 100644 --- a/packages/fast-usdc/test/fixtures.ts +++ b/packages/fast-usdc/test/fixtures.ts @@ -1,6 +1,7 @@ import type { VTransferIBCEvent } from '@agoric/vats'; import { buildVTransferEvent } from '@agoric/orchestration/tools/ibc-mocks.js'; import fetchedChainInfo from '@agoric/orchestration/src/fetched-chain-info.js'; +import type { ChainAddress } from '@agoric/orchestration'; import type { CctpTxEvidence } from '../src/types.js'; const mockScenarios = [ @@ -141,3 +142,9 @@ export const MockVTransferEvents: Record< MockCctpTxEvidences.AGORIC_UNKNOWN_EUD().aux.recipientAddress, }), }; + +export const intermediateRecipient: ChainAddress = harden({ + chainId: 'noble-1', + value: 'noble1test', + encoding: 'bech32', +}); diff --git a/packages/fast-usdc/test/snapshots/fast-usdc.contract.test.ts.md b/packages/fast-usdc/test/snapshots/fast-usdc.contract.test.ts.md index 72890a09ece..1c6fe4d0433 100644 --- a/packages/fast-usdc/test/snapshots/fast-usdc.contract.test.ts.md +++ b/packages/fast-usdc/test/snapshots/fast-usdc.contract.test.ts.md @@ -588,6 +588,7 @@ Generated by [AVA](https://avajs.dev). withdrawHandler: Object @Alleged: Liquidity Pool withdrawHandler {}, }, 'Liquidity Pool_kindHandle': 'Alleged: kind', + NobleAccount: 'Vow', 'Operator Kit_kindHandle': 'Alleged: kind', PendingTxs: {}, PoolAccount: 'Vow', @@ -601,6 +602,9 @@ Generated by [AVA](https://avajs.dev). makeLocalAccount: { asyncFlow_kindHandle: 'Alleged: kind', }, + makeNobleAccount: { + asyncFlow_kindHandle: 'Alleged: kind', + }, }, pending: {}, vstorage: { @@ -620,6 +624,10 @@ Generated by [AVA](https://avajs.dev). pending: false, value: Object @Alleged: LocalChainFacade public {}, }, + noble: { + pending: false, + value: Object @Alleged: RemoteChainFacade public {}, + }, }, ibcTools: { IBCTransferSenderKit_kindHandle: 'Alleged: kind', diff --git a/packages/fast-usdc/test/snapshots/fast-usdc.contract.test.ts.snap b/packages/fast-usdc/test/snapshots/fast-usdc.contract.test.ts.snap index c289cbdd0bb..09943c2591d 100644 Binary files a/packages/fast-usdc/test/snapshots/fast-usdc.contract.test.ts.snap and b/packages/fast-usdc/test/snapshots/fast-usdc.contract.test.ts.snap differ