diff --git a/packages/boot/test/fast-usdc/fast-usdc.test.ts b/packages/boot/test/fast-usdc/fast-usdc.test.ts index fe4b367de3f..0853f6b183b 100644 --- a/packages/boot/test/fast-usdc/fast-usdc.test.ts +++ b/packages/boot/test/fast-usdc/fast-usdc.test.ts @@ -160,7 +160,34 @@ test.serial('writes fee config to vstorage', async t => { await documentStorageSchema(t, storage, doc); }); -test.serial('makes usdc advance', async t => { +test.serial('writes pool metrics to vstorage', async t => { + const { storage } = t.context; + const doc = { + node: 'fastUsdc.poolMetrics', + owner: 'FastUSC LiquidityPool exo', + showValue: v => defaultMarshaller.fromCapData(JSON.parse(v)), + }; + await documentStorageSchema(t, storage, doc); +}); + +test.serial('writes account addresses to vstorage', async t => { + const { storage } = t.context; + const doc = { + node: 'fastUsdc', + showValue: JSON.parse, + pattern: /published\.fastUsdc\.(feeConfig|feedPolicy|poolMetrics)/, + replacement: '', + note: `Under "published", the "fastUsdc" node is delegated to FastUSDC contract. + Note: published.fastUsdc.[settleAcctAddr], published.fastUsdc.[poolAcctAddr], + and published.fastUsdc.[intermediateAcctAddr] are published by @agoric/orchestration + via 'withOrchestration' and (local|cosmos)-orch-account-kit.js. + `, + }; + + await documentStorageSchema(t, storage, doc); +}); + +test.skip('makes usdc advance', async t => { const { walletFactoryDriver: wd, storage, diff --git a/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.md b/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.md index 1441f49490d..4b19508a1d9 100644 --- a/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.md +++ b/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.md @@ -72,6 +72,93 @@ Generated by [AVA](https://avajs.dev). ], ] +## writes pool metrics to vstorage + +> Under "published", the "fastUsdc.poolMetrics" node is delegated to FastUSC LiquidityPool exo. +> The example below illustrates the schema of the data published there. +> +> See also board marshalling conventions (_to appear_). + + [ + [ + 'published.fastUsdc.poolMetrics', + { + encumberedBalance: { + brand: Object @Alleged: USDC brand {}, + value: 0n, + }, + shareWorth: { + denominator: { + brand: Object @Alleged: PoolShares brand {}, + value: 1n, + }, + numerator: { + brand: Object @Alleged: USDC brand {}, + value: 1n, + }, + }, + totalBorrows: { + brand: Object @Alleged: USDC brand {}, + value: 0n, + }, + totalContractFees: { + brand: Object @Alleged: USDC brand {}, + value: 0n, + }, + totalPoolFees: { + brand: Object @Alleged: USDC brand {}, + value: 0n, + }, + totalRepays: { + brand: Object @Alleged: USDC brand {}, + value: 0n, + }, + }, + ], + ] + +## writes account addresses to vstorage + +> Under "published", the "fastUsdc" node is delegated to FastUSDC contract. +> Note: published.fastUsdc.[settleAcctAddr], published.fastUsdc.[poolAcctAddr], +> and published.fastUsdc.[intermediateAcctAddr] are published by @agoric/orchestration +> via 'withOrchestration' and (local|cosmos)-orch-account-kit.js. +> +> The example below illustrates the schema of the data published there. +> +> See also board marshalling conventions (_to appear_). + + [ + [ + 'published.fastUsdc', + { + poolAccount: 'agoric1fakeLCAAddress', + settlementAccount: 'agoric1fakeLCAAddress1', + }, + ], + [ + 'published.fastUsdc.agoric1fakeLCAAddress', + { + body: '#""', + slots: [], + }, + ], + [ + 'published.fastUsdc.agoric1fakeLCAAddress1', + { + body: '#""', + slots: [], + }, + ], + [ + 'published.fastUsdc.noble1test', + { + body: '#{"localAddress":"/ibc-port/icacontroller-1/ordered/{\\"version\\":\\"ics27-1\\",\\"controllerConnectionId\\":\\"connection-72\\",\\"hostConnectionId\\":\\"connection-40\\",\\"address\\":\\"noble1test\\",\\"encoding\\":\\"proto3\\",\\"txType\\":\\"sdk_multi_msg\\"}/ibc-channel/channel-1","remoteAddress":"/ibc-hop/connection-72/ibc-port/icahost/ordered/{\\"version\\":\\"ics27-1\\",\\"controllerConnectionId\\":\\"connection-72\\",\\"hostConnectionId\\":\\"connection-40\\",\\"address\\":\\"noble1test\\",\\"encoding\\":\\"proto3\\",\\"txType\\":\\"sdk_multi_msg\\"}/ibc-channel/channel-1"}', + slots: [], + }, + ], + ] + ## makes usdc advance > Under "published", the "fastUsdc.status" node is delegated to the statuses of fast USDC transfers identified by their tx hashes. diff --git a/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.snap b/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.snap index 820fa8ddbf3..0245ac61053 100644 Binary files a/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.snap and b/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.snap differ diff --git a/packages/fast-usdc/src/fast-usdc.contract.js b/packages/fast-usdc/src/fast-usdc.contract.js index 734bd423a3c..ff9f08c5000 100644 --- a/packages/fast-usdc/src/fast-usdc.contract.js +++ b/packages/fast-usdc/src/fast-usdc.contract.js @@ -12,6 +12,7 @@ import { import { makeZoeTools } from '@agoric/orchestration/src/utils/zoe-tools.js'; import { provideSingleton } from '@agoric/zoe/src/contractSupport/durability.js'; import { prepareRecorderKitMakers } from '@agoric/zoe/src/contractSupport/recorder.js'; +import { Fail } from '@endo/errors'; import { E } from '@endo/far'; import { M } from '@endo/patterns'; import { prepareAdvancer } from './exos/advancer.js'; @@ -27,10 +28,11 @@ const trace = makeTracer('FastUsdc'); const STATUS_NODE = 'status'; const FEE_NODE = 'feeConfig'; +const ADDRESSES_BAGGAGE_KEY = 'addresses'; /** * @import {HostInterface} from '@agoric/async-flow'; - * @import {CosmosChainInfo, Denom, DenomDetail, OrchestrationAccount} from '@agoric/orchestration'; + * @import {ChainAddress, CosmosChainInfo, Denom, DenomDetail, OrchestrationAccount} from '@agoric/orchestration'; * @import {OrchestrationPowers, OrchestrationTools} from '@agoric/orchestration/src/utils/start-helper.js'; * @import {Remote} from '@agoric/internal'; * @import {Marshaller, StorageNode} from '@agoric/internal/src/lib-chainStorage.js' @@ -53,10 +55,11 @@ export const meta = { privateArgsShape: { // @ts-expect-error TypedPattern not recognized as record ...OrchestrationPowersShape, + assetInfo: M.arrayOf([DenomShape, DenomDetailShape]), + chainInfo: M.recordOf(M.string(), CosmosChainInfoShape), feeConfig: FeeConfigShape, marshaller: M.remotable(), - chainInfo: M.recordOf(M.string(), CosmosChainInfoShape), - assetInfo: M.arrayOf([DenomShape, DenomDetailShape]), + poolMetricsNode: M.remotable(), }, }; harden(meta); @@ -72,13 +75,25 @@ const publishFeeConfig = async (node, marshaller, feeConfig) => { return E(feeNode).setValue(JSON.stringify(value)); }; +/** + * @param {Remote} contractNode + * @param {{ + * poolAccount: ChainAddress['value']; + * settlementAccount: ChainAddress['value']; + * }} addresses + */ +const publishAddresses = (contractNode, addresses) => { + return E(contractNode).setValue(JSON.stringify(addresses)); +}; + /** * @param {ZCF} zcf * @param {OrchestrationPowers & { - * marshaller: Marshaller; - * feeConfig: FeeConfig; - * chainInfo: Record; * assetInfo: [Denom, DenomDetail & { brandKey?: string}][]; + * chainInfo: Record; + * feeConfig: FeeConfig; + * marshaller: Marshaller; + * poolMetricsNode: Remote; * }} privateArgs * @param {Zone} zone * @param {OrchestrationTools} tools @@ -160,6 +175,23 @@ export const contract = async (zcf, privateArgs, zone, tools) => { ); }); }, + async publishAddresses() { + !baggage.has(ADDRESSES_BAGGAGE_KEY) || Fail`Addresses already published`; + const [poolAccountAddress, settlementAccountAddress] = + await vowTools.when( + vowTools.all([ + E(poolAccount).getAddress(), + E(settlementAccount).getAddress(), + ]), + ); + const addresses = harden({ + poolAccount: poolAccountAddress.value, + settlementAccount: settlementAccountAddress.value, + }); + baggage.init(ADDRESSES_BAGGAGE_KEY, addresses); + await publishAddresses(storageNode, addresses); + return addresses; + }, }); const publicFacet = zone.exo('Fast USDC Public', undefined, { @@ -186,6 +218,13 @@ export const contract = async (zcf, privateArgs, zone, tools) => { getPublicTopics() { return poolKit.public.getPublicTopics(); }, + getStaticInfo() { + baggage.has(ADDRESSES_BAGGAGE_KEY) || + Fail`no addresses. creator must 'publishAddresses' first`; + return harden({ + [ADDRESSES_BAGGAGE_KEY]: baggage.get(ADDRESSES_BAGGAGE_KEY), + }); + }, }); // ^^^ Define all kinds above this line. Keep remote calls below. vvv @@ -213,7 +252,7 @@ export const contract = async (zcf, privateArgs, zone, tools) => { ); const poolKit = zone.makeOnce('Liquidity Pool kit', () => - makeLiquidityPoolKit(shareMint, privateArgs.storageNode), + makeLiquidityPoolKit(shareMint, privateArgs.poolMetricsNode), ); /** Chain, connection, and asset info can only be registered once */ diff --git a/packages/fast-usdc/src/fast-usdc.start.js b/packages/fast-usdc/src/fast-usdc.start.js index 915df4e9cb3..2815569d2ed 100644 --- a/packages/fast-usdc/src/fast-usdc.start.js +++ b/packages/fast-usdc/src/fast-usdc.start.js @@ -78,6 +78,7 @@ const publishDisplayInfo = async (brand, { board, chainStorage }) => { }; const FEED_POLICY = 'feedPolicy'; +const POOL_METRICS = 'poolMetrics'; /** * @param {ERef} node @@ -175,6 +176,7 @@ export const startFastUSDC = async ( chainStorage, }, ); + const poolMetricsNode = await E(storageNode).makeChildNode(POOL_METRICS); const privateArgs = await deeplyFulfilledObject( harden({ @@ -182,6 +184,7 @@ export const startFastUSDC = async ( feeConfig, localchain, orchestrationService: cosmosInterchainService, + poolMetricsNode, storageNode, timerService, marshaller, @@ -224,6 +227,8 @@ export const startFastUSDC = async ( produceInstance.reset(); produceInstance.resolve(instance); + const addresses = await E(kit.creatorFacet).publishAddresses(); + trace('contract orch account addresses', addresses); if (!net.noNoble) { const addr = await E(kit.creatorFacet).connectToNoble(); trace('noble intermediate recipient', addr); diff --git a/packages/fast-usdc/test/fast-usdc.contract.test.ts b/packages/fast-usdc/test/fast-usdc.contract.test.ts index 665ed382320..872bffc2c0a 100644 --- a/packages/fast-usdc/test/fast-usdc.contract.test.ts +++ b/packages/fast-usdc/test/fast-usdc.contract.test.ts @@ -86,6 +86,7 @@ const startContract = async ( ), ); await E(startKit.creatorFacet).connectToNoble(); + await E(startKit.creatorFacet).publishAddresses(); return { ...startKit, @@ -179,6 +180,18 @@ test('baggage', async t => { t.snapshot(tree, 'contract baggage after start'); }); +test('getStaticInfo', async t => { + const { startKit } = t.context; + const { publicFacet } = startKit; + + t.deepEqual(await E(publicFacet).getStaticInfo(), { + addresses: { + poolAccount: 'agoric1fakeLCAAddress', + settlementAccount: 'agoric1fakeLCAAddress1', + }, + }); +}); + const purseOf = (issuer: Issuer, { pourPayment }) => async (value: bigint) => { diff --git a/packages/fast-usdc/test/supports.ts b/packages/fast-usdc/test/supports.ts index 7a64bcf2ff2..7106b0e948a 100644 --- a/packages/fast-usdc/test/supports.ts +++ b/packages/fast-usdc/test/supports.ts @@ -233,6 +233,7 @@ export const commonSetup = async (t: ExecutionContext) => { localchain, orchestrationService: cosmosInterchainService, storageNode: storage.rootNode, + poolMetricsNode: storage.rootNode.makeChildNode('poolMetrics'), marshaller, timerService: timer, feeConfig: makeTestFeeConfig(usdc),