From c7f7a250e37f9d7a8edb622a6d43023e4cb4b435 Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Sun, 15 Dec 2024 15:47:06 -0600 Subject: [PATCH 01/21] refactor(fast-usdc): ContractMeta, Permit Factor out metainfo so that generic .start.js can get it without getting the whole contract. --- packages/fast-usdc/src/fast-usdc.contract.js | 22 +----- .../fast-usdc/src/fast-usdc.contract.meta.js | 68 +++++++++++++++++++ packages/fast-usdc/src/fast-usdc.start.js | 40 +---------- 3 files changed, 73 insertions(+), 57 deletions(-) create mode 100644 packages/fast-usdc/src/fast-usdc.contract.meta.js diff --git a/packages/fast-usdc/src/fast-usdc.contract.js b/packages/fast-usdc/src/fast-usdc.contract.js index ff9f08c5000..81c568b9dae 100644 --- a/packages/fast-usdc/src/fast-usdc.contract.js +++ b/packages/fast-usdc/src/fast-usdc.contract.js @@ -2,10 +2,6 @@ import { AssetKind } from '@agoric/ertp'; import { makeTracer } from '@agoric/internal'; import { observeIteration, subscribeEach } from '@agoric/notifier'; import { - CosmosChainInfoShape, - DenomDetailShape, - DenomShape, - OrchestrationPowersShape, registerChainsAndAssets, withOrchestration, } from '@agoric/orchestration'; @@ -14,14 +10,13 @@ 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'; import { prepareLiquidityPoolKit } from './exos/liquidity-pool.js'; import { prepareSettler } from './exos/settler.js'; import { prepareStatusManager } from './exos/status-manager.js'; import { prepareTransactionFeedKit } from './exos/transaction-feed.js'; +import { meta } from './fast-usdc.contract.meta.js'; import * as flows from './fast-usdc.flows.js'; -import { FastUSDCTermsShape, FeeConfigShape } from './type-guards.js'; import { defineInertInvitation } from './utils/zoe.js'; const trace = makeTracer('FastUsdc'); @@ -48,20 +43,7 @@ const ADDRESSES_BAGGAGE_KEY = 'addresses'; * }} FastUsdcTerms */ -/** @type {ContractMeta} */ -export const meta = { - // @ts-expect-error TypedPattern not recognized as record - customTermsShape: FastUSDCTermsShape, - 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(), - poolMetricsNode: M.remotable(), - }, -}; +export { meta }; harden(meta); /** diff --git a/packages/fast-usdc/src/fast-usdc.contract.meta.js b/packages/fast-usdc/src/fast-usdc.contract.meta.js new file mode 100644 index 00000000000..1dea4ecf0b2 --- /dev/null +++ b/packages/fast-usdc/src/fast-usdc.contract.meta.js @@ -0,0 +1,68 @@ +/** ContractMeta, Permit for Fast USDC */ +import { + CosmosChainInfoShape, + DenomDetailShape, + DenomShape, + OrchestrationPowersShape, +} from '@agoric/orchestration'; +import { M } from '@endo/patterns'; +import { FastUSDCTermsShape, FeeConfigShape } from './type-guards.js'; + +/** + * @import {FastUsdcSF} from './fast-usdc.contract.js'; + */ + +/** @type {ContractMeta} */ +export const meta = { + // @ts-expect-error TypedPattern not recognized as record + customTermsShape: FastUSDCTermsShape, + 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(), + poolMetricsNode: M.remotable(), + }, +}; +harden(meta); + +/** + * @import {BootstrapManifestPermit} from '@agoric/vats/src/core/lib-boot.js'; + */ + +/** @satisfies {BootstrapManifestPermit} */ +export const permit = { + produce: { + fastUsdcKit: true, + }, + consume: { + chainStorage: true, + chainTimerService: true, + localchain: true, + cosmosInterchainService: true, + + // limited distribution durin MN2: contract installation + startUpgradable: true, + zoe: true, // only getTerms() is needed. XXX should be split? + + // widely shared: name services + agoricNames: true, + namesByAddress: true, + board: true, + }, + issuer: { + produce: { FastLP: true }, // UNTIL #10432 + }, + brand: { + produce: { FastLP: true }, // UNTIL #10432 + }, + instance: { + produce: { fastUsdc: true }, + }, + installation: { + consume: { fastUsdc: true }, + }, +}; +harden(permit); diff --git a/packages/fast-usdc/src/fast-usdc.start.js b/packages/fast-usdc/src/fast-usdc.start.js index 2815569d2ed..4f9f6e6cacf 100644 --- a/packages/fast-usdc/src/fast-usdc.start.js +++ b/packages/fast-usdc/src/fast-usdc.start.js @@ -14,6 +14,7 @@ import { FeedPolicyShape, } from './type-guards.js'; import { fromExternalConfig } from './utils/config-marshal.js'; +import { permit } from './fast-usdc.contract.meta.js'; /** * @import {DepositFacet} from '@agoric/ertp/src/types.js' @@ -252,43 +253,8 @@ export const getManifestForFastUSDC = ( ) => { return { /** @type {BootstrapManifest} */ - manifest: { - [startFastUSDC.name]: { - produce: { - fastUsdcKit: true, - }, - consume: { - chainStorage: true, - chainTimerService: true, - localchain: true, - cosmosInterchainService: true, - - // limited distribution durin MN2: contract installation - startUpgradable: true, - zoe: true, // only getTerms() is needed. XXX should be split? - - // widely shared: name services - agoricNames: true, - namesByAddress: true, - board: true, - }, - issuer: { - produce: { FastLP: true }, // UNTIL #10432 - }, - brand: { - produce: { FastLP: true }, // UNTIL #10432 - }, - instance: { - produce: { fastUsdc: true }, - }, - installation: { - consume: { fastUsdc: true }, - }, - }, - }, - installations: { - fastUsdc: restoreRef(installKeys.fastUsdc), - }, + manifest: { [startFastUSDC.name]: permit }, + installations: { [contractName]: restoreRef(installKeys[contractName]) }, options, }; }; From 9ee1b6de560c243d3ec343eef135dc032483c2c0 Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Sun, 15 Dec 2024 16:28:59 -0600 Subject: [PATCH 02/21] refactor(fast-usdc): oracles -> makeAdminRole --- .../fast-usdc/src/fast-usdc.contract.meta.js | 5 +- packages/fast-usdc/src/fast-usdc.start.js | 90 ++++++++++++------- 2 files changed, 63 insertions(+), 32 deletions(-) diff --git a/packages/fast-usdc/src/fast-usdc.contract.meta.js b/packages/fast-usdc/src/fast-usdc.contract.meta.js index 1dea4ecf0b2..cbd2184894e 100644 --- a/packages/fast-usdc/src/fast-usdc.contract.meta.js +++ b/packages/fast-usdc/src/fast-usdc.contract.meta.js @@ -12,7 +12,7 @@ import { FastUSDCTermsShape, FeeConfigShape } from './type-guards.js'; * @import {FastUsdcSF} from './fast-usdc.contract.js'; */ -/** @type {ContractMeta} */ +/** @satisfies {ContractMeta} */ export const meta = { // @ts-expect-error TypedPattern not recognized as record customTermsShape: FastUSDCTermsShape, @@ -25,6 +25,9 @@ export const meta = { marshaller: M.remotable(), poolMetricsNode: M.remotable(), }, + adminRoles: { + oracles: 'makeOperatorInvitation', + }, }; harden(meta); diff --git a/packages/fast-usdc/src/fast-usdc.start.js b/packages/fast-usdc/src/fast-usdc.start.js index 4f9f6e6cacf..f300f9063a0 100644 --- a/packages/fast-usdc/src/fast-usdc.start.js +++ b/packages/fast-usdc/src/fast-usdc.start.js @@ -7,14 +7,14 @@ import { import { Fail } from '@endo/errors'; import { E } from '@endo/far'; import { makeMarshal } from '@endo/marshal'; -import { M } from '@endo/patterns'; +import { M, mustMatch } from '@endo/patterns'; import { FastUSDCTermsShape, FeeConfigShape, FeedPolicyShape, } from './type-guards.js'; import { fromExternalConfig } from './utils/config-marshal.js'; -import { permit } from './fast-usdc.contract.meta.js'; +import { meta, permit } from './fast-usdc.contract.meta.js'; /** * @import {DepositFacet} from '@agoric/ertp/src/types.js' @@ -28,6 +28,8 @@ import { permit } from './fast-usdc.contract.meta.js'; * @import {FeedPolicy, FastUSDCConfig} from './types.js' */ +const { entries, fromEntries, keys, values } = Object; // XXX move up + const trace = makeTracer('FUSD-Start', true); const contractName = 'fastUsdc'; @@ -90,6 +92,46 @@ const publishFeedPolicy = async (node, policy) => { await E(feedPolicy).setValue(JSON.stringify(policy)); }; +/** + * @param {string} role + * @param {ERef} namesByAddress + * @param {Record} nameToAddress + */ +const makeAdminRole = (role, namesByAddress, nameToAddress) => { + const lookup = async () => { + trace('look up deposit facets for', role); + return deeplyFulfilledObject( + objectMap(nameToAddress, async address => { + /** @type {DepositFacet} */ + const depositFacet = await E(namesByAddress).lookup( + address, + 'depositFacet', + ); + return depositFacet; + }), + ); + }; + const lookupP = lookup(); + + return harden({ + lookup: () => lookupP, + /** @param {(addr: string) => Promise} makeInvitation */ + send: async makeInvitation => { + const oracleDepositFacets = await lookupP; + await Promise.all( + entries(oracleDepositFacets).map(async ([name, depositFacet]) => { + const address = nameToAddress[name]; + trace('making invitation for', role, name, address); + const toWatch = await makeInvitation(address); + + const amt = await E(depositFacet).receive(toWatch); + trace('sent', amt, 'to', role, name); + }), + ); + }, + }); +}; + /** * @typedef { PromiseSpaceOf<{ * fastUsdcKit: FastUSDCKit @@ -106,7 +148,7 @@ const publishFeedPolicy = async (node, policy) => { */ /** - * @throws if oracle smart wallets are not yet provisioned + * @throws if admin role smart wallets are not yet provisioned * * @param {BootstrapPowers & FastUSDCCorePowers } powers * @param {{ options: LegibleCapData }} config @@ -142,32 +184,25 @@ export const startFastUSDC = async ( ) => { trace('startFastUSDC'); - await null; /** @type {Issuer<'nat'>} */ const USDCissuer = await E(agoricNames).lookup('issuer', 'USDC'); - const brands = harden({ - USDC: await E(USDCissuer).getBrand(), - }); - - const { terms, oracles, feeConfig, feedPolicy, ...net } = fromExternalConfig( + const xVatContext = await E(E(agoricNames).lookup('brand')).entries(); + const internalConfig = fromExternalConfig( config.options, - brands, + xVatContext, FastUSDCConfigShape, ); + const { terms, feeConfig, feedPolicy, ...net } = internalConfig; trace('using terms', terms); trace('using fee config', feeConfig); - trace('look up oracle deposit facets'); - const oracleDepositFacets = await deeplyFulfilledObject( - objectMap(oracles, async address => { - /** @type {DepositFacet} */ - const depositFacet = await E(namesByAddress).lookup( - address, - 'depositFacet', - ); - return depositFacet; - }), - ); + const adminRoles = objectMap(meta?.adminRoles || {}, (_method, role) => { + const nameToAddress = internalConfig[role]; + mustMatch(nameToAddress, M.recordOf(M.string(), M.string())); + return makeAdminRole(role, namesByAddress, nameToAddress); + }); + + await Promise.all(values(adminRoles).map(r => r.lookup())); const { storageNode, marshaller } = await makePublishingStorageKit( contractName, @@ -214,16 +249,9 @@ export const startFastUSDC = async ( produceShareBrand.resolve(shareBrand); await publishDisplayInfo(shareBrand, { board, chainStorage }); - await Promise.all( - Object.entries(oracleDepositFacets).map(async ([name, depositFacet]) => { - const address = oracles[name]; - trace('making invitation for', name, address); - const toWatch = await E(creatorFacet).makeOperatorInvitation(address); - - const amt = await E(depositFacet).receive(toWatch); - trace('sent', amt, 'to', name); - }), - ); + for (const [role, method] of entries(meta.adminRoles)) { + await adminRoles[role].send(addr => E(creatorFacet)[method](addr)); + } produceInstance.reset(); produceInstance.resolve(instance); From 166f2b0d17ce846b77e3936a9108a7f80927ab50 Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Sun, 15 Dec 2024 16:32:37 -0600 Subject: [PATCH 03/21] refactor(fast-usdc): superfluous kit. in kit.creatorFacet --- packages/fast-usdc/src/fast-usdc.start.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/fast-usdc/src/fast-usdc.start.js b/packages/fast-usdc/src/fast-usdc.start.js index f300f9063a0..ac77d98acf9 100644 --- a/packages/fast-usdc/src/fast-usdc.start.js +++ b/packages/fast-usdc/src/fast-usdc.start.js @@ -256,10 +256,10 @@ export const startFastUSDC = async ( produceInstance.reset(); produceInstance.resolve(instance); - const addresses = await E(kit.creatorFacet).publishAddresses(); + const addresses = await E(creatorFacet).publishAddresses(); trace('contract orch account addresses', addresses); if (!net.noNoble) { - const addr = await E(kit.creatorFacet).connectToNoble(); + const addr = await E(creatorFacet).connectToNoble(); trace('noble intermediate recipient', addr); } trace('startFastUSDC done', instance); From 6f8c96210a4a3be8ec03695174a422c25b68f55c Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Sun, 15 Dec 2024 16:45:54 -0600 Subject: [PATCH 04/21] refactor(fast-usdc): .start: generic issuer / brand handling --- .../fast-usdc/src/fast-usdc.contract.meta.js | 1 + packages/fast-usdc/src/fast-usdc.start.js | 45 +++++++++++-------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/packages/fast-usdc/src/fast-usdc.contract.meta.js b/packages/fast-usdc/src/fast-usdc.contract.meta.js index cbd2184894e..139aa07ddda 100644 --- a/packages/fast-usdc/src/fast-usdc.contract.meta.js +++ b/packages/fast-usdc/src/fast-usdc.contract.meta.js @@ -56,6 +56,7 @@ export const permit = { board: true, }, issuer: { + consume: { USDC: true }, produce: { FastLP: true }, // UNTIL #10432 }, brand: { diff --git a/packages/fast-usdc/src/fast-usdc.start.js b/packages/fast-usdc/src/fast-usdc.start.js index ac77d98acf9..f902920245b 100644 --- a/packages/fast-usdc/src/fast-usdc.start.js +++ b/packages/fast-usdc/src/fast-usdc.start.js @@ -167,25 +167,19 @@ export const startFastUSDC = async ( startUpgradable, zoe, }, - issuer: { - produce: { FastLP: produceShareIssuer }, - }, - brand: { - produce: { FastLP: produceShareBrand }, - }, + issuer: { produce: produceIssuer }, + brand: { produce: produceBrand }, installation: { - consume: { fastUsdc }, + consume: { [contractName]: installation }, }, instance: { - produce: { fastUsdc: produceInstance }, + produce: { [contractName]: produceInstance }, }, }, config, ) => { trace('startFastUSDC'); - /** @type {Issuer<'nat'>} */ - const USDCissuer = await E(agoricNames).lookup('issuer', 'USDC'); const xVatContext = await E(E(agoricNames).lookup('brand')).entries(); const internalConfig = fromExternalConfig( config.options, @@ -229,10 +223,16 @@ export const startFastUSDC = async ( }), ); + const permittedIssuers = keys(permit?.issuer?.consume || {}); + const agoricIssuers = await E(E(agoricNames).lookup('issuer')).entries(); + const issuerKeywordRecord = fromEntries( + agoricIssuers.filter(([n, _v]) => permittedIssuers.includes(n)), + ); + const kit = await E(startUpgradable)({ label: contractName, - installation: fastUsdc, - issuerKeywordRecord: harden({ USDC: USDCissuer }), + installation, + issuerKeywordRecord, terms, privateArgs, }); @@ -241,13 +241,20 @@ export const startFastUSDC = async ( await publishFeedPolicy(storageNode, feedPolicy); - const { - issuers: { PoolShares: shareIssuer }, - brands: { PoolShares: shareBrand }, - } = await E(zoe).getTerms(instance); - produceShareIssuer.resolve(shareIssuer); - produceShareBrand.resolve(shareBrand); - await publishDisplayInfo(shareBrand, { board, chainStorage }); + const newIssuerNames = keys(permit?.issuer?.produce || {}).filter( + n => permit?.brand?.produce?.[n], + ); + if (newIssuerNames.length > 0) { + const { issuers, brands } = await E(zoe).getTerms(instance); + for (const name of newIssuerNames) { + console.log('new well-known Issuer, Brand:', name); + produceIssuer[name].reset(); + produceIssuer[name].resolve(issuers[name]); + produceBrand[name].reset(); + produceBrand[name].resolve(brands[name]); + await publishDisplayInfo(brands[name], { board, chainStorage }); + } + } for (const [role, method] of entries(meta.adminRoles)) { await adminRoles[role].send(addr => E(creatorFacet)[method](addr)); From e169b766bdef31762c2eac4f9bd4667916de99b8 Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Sun, 15 Dec 2024 17:19:40 -0600 Subject: [PATCH 05/21] refactor(fast-usdc): FastUSDCConfigShape -> meta.deployConfigShape --- .../fast-usdc/src/fast-usdc.contract.meta.js | 24 +++++++++++++++---- packages/fast-usdc/src/fast-usdc.start.js | 23 +----------------- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/packages/fast-usdc/src/fast-usdc.contract.meta.js b/packages/fast-usdc/src/fast-usdc.contract.meta.js index 139aa07ddda..54b37091074 100644 --- a/packages/fast-usdc/src/fast-usdc.contract.meta.js +++ b/packages/fast-usdc/src/fast-usdc.contract.meta.js @@ -6,12 +6,29 @@ import { OrchestrationPowersShape, } from '@agoric/orchestration'; import { M } from '@endo/patterns'; -import { FastUSDCTermsShape, FeeConfigShape } from './type-guards.js'; +import { + FastUSDCTermsShape, + FeeConfigShape, + FeedPolicyShape, +} from './type-guards.js'; /** + * @import {BootstrapManifestPermit} from '@agoric/vats/src/core/lib-boot.js'; + * @import {TypedPattern} from '@agoric/internal' * @import {FastUsdcSF} from './fast-usdc.contract.js'; + * @import {FastUSDCConfig} from './types.js' */ +/** @type {TypedPattern} */ +export const FastUSDCConfigShape = M.splitRecord({ + terms: FastUSDCTermsShape, + oracles: M.recordOf(M.string(), M.string()), + feeConfig: FeeConfigShape, + feedPolicy: FeedPolicyShape, + chainInfo: M.recordOf(M.string(), CosmosChainInfoShape), + assetInfo: M.arrayOf([DenomShape, DenomDetailShape]), +}); + /** @satisfies {ContractMeta} */ export const meta = { // @ts-expect-error TypedPattern not recognized as record @@ -25,16 +42,13 @@ export const meta = { marshaller: M.remotable(), poolMetricsNode: M.remotable(), }, + deployConfigShape: FastUSDCConfigShape, adminRoles: { oracles: 'makeOperatorInvitation', }, }; harden(meta); -/** - * @import {BootstrapManifestPermit} from '@agoric/vats/src/core/lib-boot.js'; - */ - /** @satisfies {BootstrapManifestPermit} */ export const permit = { produce: { diff --git a/packages/fast-usdc/src/fast-usdc.start.js b/packages/fast-usdc/src/fast-usdc.start.js index f902920245b..3d4c3fee9ab 100644 --- a/packages/fast-usdc/src/fast-usdc.start.js +++ b/packages/fast-usdc/src/fast-usdc.start.js @@ -1,24 +1,13 @@ import { deeplyFulfilledObject, makeTracer, objectMap } from '@agoric/internal'; -import { - CosmosChainInfoShape, - DenomDetailShape, - DenomShape, -} from '@agoric/orchestration'; import { Fail } from '@endo/errors'; import { E } from '@endo/far'; import { makeMarshal } from '@endo/marshal'; import { M, mustMatch } from '@endo/patterns'; -import { - FastUSDCTermsShape, - FeeConfigShape, - FeedPolicyShape, -} from './type-guards.js'; import { fromExternalConfig } from './utils/config-marshal.js'; import { meta, permit } from './fast-usdc.contract.meta.js'; /** * @import {DepositFacet} from '@agoric/ertp/src/types.js' - * @import {TypedPattern} from '@agoric/internal' * @import {Instance, StartParams} from '@agoric/zoe/src/zoeService/utils' * @import {Board} from '@agoric/vats' * @import {ManifestBundleRef} from '@agoric/deploy-script-support/src/externalTypes.js' @@ -34,16 +23,6 @@ const trace = makeTracer('FUSD-Start', true); const contractName = 'fastUsdc'; -/** @type {TypedPattern} */ -export const FastUSDCConfigShape = M.splitRecord({ - terms: FastUSDCTermsShape, - oracles: M.recordOf(M.string(), M.string()), - feeConfig: FeeConfigShape, - feedPolicy: FeedPolicyShape, - chainInfo: M.recordOf(M.string(), CosmosChainInfoShape), - assetInfo: M.arrayOf([DenomShape, DenomDetailShape]), -}); - /** * XXX Shouldn't the bridge or board vat handle this? * @@ -184,7 +163,7 @@ export const startFastUSDC = async ( const internalConfig = fromExternalConfig( config.options, xVatContext, - FastUSDCConfigShape, + meta.deployConfigShape, ); const { terms, feeConfig, feedPolicy, ...net } = internalConfig; trace('using terms', terms); From 72fda582819ef4119a1a8e5e25c059ac660f2d62 Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Sun, 15 Dec 2024 17:24:14 -0600 Subject: [PATCH 06/21] chore(builders): FastUSDCConfigShape moved to .meta --- packages/builders/scripts/fast-usdc/init-fast-usdc.js | 6 ++---- packages/fast-usdc/src/fast-usdc.start.js | 6 +++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/builders/scripts/fast-usdc/init-fast-usdc.js b/packages/builders/scripts/fast-usdc/init-fast-usdc.js index fade01cea83..624fe675d0b 100644 --- a/packages/builders/scripts/fast-usdc/init-fast-usdc.js +++ b/packages/builders/scripts/fast-usdc/init-fast-usdc.js @@ -1,10 +1,8 @@ // @ts-check import { makeHelpers } from '@agoric/deploy-script-support'; import { AmountMath } from '@agoric/ertp'; -import { - FastUSDCConfigShape, - getManifestForFastUSDC, -} from '@agoric/fast-usdc/src/fast-usdc.start.js'; +import { getManifestForFastUSDC } from '@agoric/fast-usdc/src/fast-usdc.start.js'; +import { FastUSDCConfigShape } from '@agoric/fast-usdc/src/fast-usdc.contract.meta.js'; import { toExternalConfig } from '@agoric/fast-usdc/src/utils/config-marshal.js'; import { configurations } from '@agoric/fast-usdc/src/utils/deploy-config.js'; import { diff --git a/packages/fast-usdc/src/fast-usdc.start.js b/packages/fast-usdc/src/fast-usdc.start.js index 3d4c3fee9ab..29638b7b850 100644 --- a/packages/fast-usdc/src/fast-usdc.start.js +++ b/packages/fast-usdc/src/fast-usdc.start.js @@ -14,7 +14,7 @@ import { meta, permit } from './fast-usdc.contract.meta.js'; * @import {BootstrapManifest} from '@agoric/vats/src/core/lib-boot.js' * @import {LegibleCapData} from './utils/config-marshal.js' * @import {FastUsdcSF} from './fast-usdc.contract.js' - * @import {FeedPolicy, FastUSDCConfig} from './types.js' + * @import {FeedPolicy, FastUSDCConfig as ContractConfig} from './types.js' */ const { entries, fromEntries, keys, values } = Object; // XXX move up @@ -130,7 +130,7 @@ const makeAdminRole = (role, namesByAddress, nameToAddress) => { * @throws if admin role smart wallets are not yet provisioned * * @param {BootstrapPowers & FastUSDCCorePowers } powers - * @param {{ options: LegibleCapData }} config + * @param {{ options: LegibleCapData }} config */ export const startFastUSDC = async ( { @@ -258,7 +258,7 @@ harden(startFastUSDC); * }} utils * @param {{ * installKeys: { fastUsdc: ERef }; - * options: LegibleCapData; + * options: LegibleCapData; * }} param1 */ export const getManifestForFastUSDC = ( From ce274495d64897e12d4351b15cb002273ea9d99d Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Sun, 15 Dec 2024 17:25:01 -0600 Subject: [PATCH 07/21] refactor(fast-usdc): contractName = meta.name --- packages/fast-usdc/src/fast-usdc.contract.meta.js | 5 +++-- packages/fast-usdc/src/fast-usdc.start.js | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/fast-usdc/src/fast-usdc.contract.meta.js b/packages/fast-usdc/src/fast-usdc.contract.meta.js index 54b37091074..27aa141da61 100644 --- a/packages/fast-usdc/src/fast-usdc.contract.meta.js +++ b/packages/fast-usdc/src/fast-usdc.contract.meta.js @@ -30,7 +30,8 @@ export const FastUSDCConfigShape = M.splitRecord({ }); /** @satisfies {ContractMeta} */ -export const meta = { +export const meta = /** @type {const} */ ({ + name: 'fastUsdc', // @ts-expect-error TypedPattern not recognized as record customTermsShape: FastUSDCTermsShape, privateArgsShape: { @@ -46,7 +47,7 @@ export const meta = { adminRoles: { oracles: 'makeOperatorInvitation', }, -}; +}); harden(meta); /** @satisfies {BootstrapManifestPermit} */ diff --git a/packages/fast-usdc/src/fast-usdc.start.js b/packages/fast-usdc/src/fast-usdc.start.js index 29638b7b850..222d48053ad 100644 --- a/packages/fast-usdc/src/fast-usdc.start.js +++ b/packages/fast-usdc/src/fast-usdc.start.js @@ -21,7 +21,7 @@ const { entries, fromEntries, keys, values } = Object; // XXX move up const trace = makeTracer('FUSD-Start', true); -const contractName = 'fastUsdc'; +const contractName = meta.name; /** * XXX Shouldn't the bridge or board vat handle this? From 6b21321ad18a875ff67a5c97a86fcbb0172731fc Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Sun, 15 Dec 2024 17:26:20 -0600 Subject: [PATCH 08/21] refactor(fast-usdc): generic start tracer --- packages/fast-usdc/src/fast-usdc.contract.meta.js | 1 + packages/fast-usdc/src/fast-usdc.start.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/fast-usdc/src/fast-usdc.contract.meta.js b/packages/fast-usdc/src/fast-usdc.contract.meta.js index 27aa141da61..cf0546b93c8 100644 --- a/packages/fast-usdc/src/fast-usdc.contract.meta.js +++ b/packages/fast-usdc/src/fast-usdc.contract.meta.js @@ -32,6 +32,7 @@ export const FastUSDCConfigShape = M.splitRecord({ /** @satisfies {ContractMeta} */ export const meta = /** @type {const} */ ({ name: 'fastUsdc', + abbr: 'FUSD', // for tracer(s) // @ts-expect-error TypedPattern not recognized as record customTermsShape: FastUSDCTermsShape, privateArgsShape: { diff --git a/packages/fast-usdc/src/fast-usdc.start.js b/packages/fast-usdc/src/fast-usdc.start.js index 222d48053ad..a59056a71ba 100644 --- a/packages/fast-usdc/src/fast-usdc.start.js +++ b/packages/fast-usdc/src/fast-usdc.start.js @@ -19,10 +19,10 @@ import { meta, permit } from './fast-usdc.contract.meta.js'; const { entries, fromEntries, keys, values } = Object; // XXX move up -const trace = makeTracer('FUSD-Start', true); - const contractName = meta.name; +const trace = makeTracer(`${meta.abbr}-Start`, true); + /** * XXX Shouldn't the bridge or board vat handle this? * From fd178295b94ff2b0f747d14e665a6f52ec855c1b Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Sun, 15 Dec 2024 18:28:07 -0600 Subject: [PATCH 09/21] refactor(fast-usdc): makePrivateArgs .start -> .meta --- .../fast-usdc/src/fast-usdc.contract.meta.js | 67 +++++++++++++++++++ packages/fast-usdc/src/fast-usdc.start.js | 22 +++--- 2 files changed, 77 insertions(+), 12 deletions(-) diff --git a/packages/fast-usdc/src/fast-usdc.contract.meta.js b/packages/fast-usdc/src/fast-usdc.contract.meta.js index cf0546b93c8..bc8eabd0240 100644 --- a/packages/fast-usdc/src/fast-usdc.contract.meta.js +++ b/packages/fast-usdc/src/fast-usdc.contract.meta.js @@ -5,6 +5,7 @@ import { DenomShape, OrchestrationPowersShape, } from '@agoric/orchestration'; +import { E } from '@endo/far'; import { M } from '@endo/patterns'; import { FastUSDCTermsShape, @@ -15,6 +16,8 @@ import { /** * @import {BootstrapManifestPermit} from '@agoric/vats/src/core/lib-boot.js'; * @import {TypedPattern} from '@agoric/internal' + * @import {Marshaller} from '@agoric/internal/src/lib-chainStorage.js' + * @import {OrchestrationPowers} from '@agoric/orchestration'; * @import {FastUsdcSF} from './fast-usdc.contract.js'; * @import {FastUSDCConfig} from './types.js' */ @@ -86,3 +89,67 @@ export const permit = { }, }; harden(permit); + +const POOL_METRICS = 'poolMetrics'; + +/** + * + * @param {OrchestrationPowers} orchestrationPowers + * @param {Marshaller} marshaller + * @param {FastUSDCConfig} config + * @param {(...args: any[]) => void} trace + * @returns {Promise['1']>} + */ +export const makePrivateArgs = async ( + orchestrationPowers, + marshaller, + config, + trace, +) => { + const { storageNode } = orchestrationPowers; + const poolMetricsNode = await E(storageNode).makeChildNode(POOL_METRICS); + const { feeConfig } = config; + trace('using fee config', feeConfig); + + return harden({ + ...orchestrationPowers, + feeConfig, + poolMetricsNode, + marshaller, + chainInfo: config.chainInfo, + assetInfo: config.assetInfo, + }); +}; +harden(makePrivateArgs); + +const { fromEntries, keys } = Object; + +/** + * possible generic form of makePrivateArgs + * + * TODO: figure out type safety + * + * @param {OrchestrationPowers} orchestrationPowers + * @param {import('@endo/pass-style').CopyRecord} internalConfig + */ +export const customPrivateArgs = (orchestrationPowers, internalConfig) => { + const extraNodeKeys = keys(meta.privateArgsShape).filter( + prop => prop !== 'storageNode' && prop.endsWith('Node'), + ); + const { storageNode } = orchestrationPowers; + const extraNodeArgs = fromEntries( + extraNodeKeys.map(key => [ + key, + E(storageNode).makeChildNode(key.slice(0, -'Node'.length)), + ]), + ); + const configKeys = keys(meta.privateArgsShape).filter( + key => + key in internalConfig && + !(key in orchestrationPowers || key in extraNodeArgs), + ); + const configArgs = fromEntries( + configKeys.map(key => [key, internalConfig[key]]), + ); + return harden({ ...extraNodeArgs, ...configArgs }); +}; diff --git a/packages/fast-usdc/src/fast-usdc.start.js b/packages/fast-usdc/src/fast-usdc.start.js index a59056a71ba..898ad2379ef 100644 --- a/packages/fast-usdc/src/fast-usdc.start.js +++ b/packages/fast-usdc/src/fast-usdc.start.js @@ -3,8 +3,8 @@ import { Fail } from '@endo/errors'; import { E } from '@endo/far'; import { makeMarshal } from '@endo/marshal'; import { M, mustMatch } from '@endo/patterns'; +import { makePrivateArgs, meta, permit } from './fast-usdc.contract.meta.js'; import { fromExternalConfig } from './utils/config-marshal.js'; -import { meta, permit } from './fast-usdc.contract.meta.js'; /** * @import {DepositFacet} from '@agoric/ertp/src/types.js' @@ -60,7 +60,6 @@ const publishDisplayInfo = async (brand, { board, chainStorage }) => { }; const FEED_POLICY = 'feedPolicy'; -const POOL_METRICS = 'poolMetrics'; /** * @param {ERef} node @@ -165,9 +164,8 @@ export const startFastUSDC = async ( xVatContext, meta.deployConfigShape, ); - const { terms, feeConfig, feedPolicy, ...net } = internalConfig; + const { terms, feedPolicy, ...net } = internalConfig; trace('using terms', terms); - trace('using fee config', feeConfig); const adminRoles = objectMap(meta?.adminRoles || {}, (_method, role) => { const nameToAddress = internalConfig[role]; @@ -185,22 +183,22 @@ export const startFastUSDC = async ( chainStorage, }, ); - const poolMetricsNode = await E(storageNode).makeChildNode(POOL_METRICS); - const privateArgs = await deeplyFulfilledObject( + const orchestrationPowers = await deeplyFulfilledObject( harden({ - agoricNames, - feeConfig, localchain, orchestrationService: cosmosInterchainService, - poolMetricsNode, storageNode, timerService, - marshaller, - chainInfo: net.chainInfo, - assetInfo: net.assetInfo, + agoricNames, }), ); + const privateArgs = await makePrivateArgs( + orchestrationPowers, + marshaller, + internalConfig, + trace, + ); const permittedIssuers = keys(permit?.issuer?.consume || {}); const agoricIssuers = await E(E(agoricNames).lookup('issuer')).entries(); From 06451276ea86358e1ba9a1e646eda43ad90441ca Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Sun, 15 Dec 2024 19:04:34 -0600 Subject: [PATCH 10/21] chore(fast-usdc): punt generic customPrivateArgs --- .../fast-usdc/src/fast-usdc.contract.meta.js | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/packages/fast-usdc/src/fast-usdc.contract.meta.js b/packages/fast-usdc/src/fast-usdc.contract.meta.js index bc8eabd0240..5799a0f2e01 100644 --- a/packages/fast-usdc/src/fast-usdc.contract.meta.js +++ b/packages/fast-usdc/src/fast-usdc.contract.meta.js @@ -121,35 +121,3 @@ export const makePrivateArgs = async ( }); }; harden(makePrivateArgs); - -const { fromEntries, keys } = Object; - -/** - * possible generic form of makePrivateArgs - * - * TODO: figure out type safety - * - * @param {OrchestrationPowers} orchestrationPowers - * @param {import('@endo/pass-style').CopyRecord} internalConfig - */ -export const customPrivateArgs = (orchestrationPowers, internalConfig) => { - const extraNodeKeys = keys(meta.privateArgsShape).filter( - prop => prop !== 'storageNode' && prop.endsWith('Node'), - ); - const { storageNode } = orchestrationPowers; - const extraNodeArgs = fromEntries( - extraNodeKeys.map(key => [ - key, - E(storageNode).makeChildNode(key.slice(0, -'Node'.length)), - ]), - ); - const configKeys = keys(meta.privateArgsShape).filter( - key => - key in internalConfig && - !(key in orchestrationPowers || key in extraNodeArgs), - ); - const configArgs = fromEntries( - configKeys.map(key => [key, internalConfig[key]]), - ); - return harden({ ...extraNodeArgs, ...configArgs }); -}; From 05d5d2bde3fce3b52ab62764c960168ff1cdc7aa Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Sun, 15 Dec 2024 18:57:33 -0600 Subject: [PATCH 11/21] refactor(fast-usdc): CorePowers .start -> .meta --- .../fast-usdc/src/fast-usdc.contract.meta.js | 16 +++++++++++++++ packages/fast-usdc/src/fast-usdc.start.js | 20 ++----------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/fast-usdc/src/fast-usdc.contract.meta.js b/packages/fast-usdc/src/fast-usdc.contract.meta.js index 5799a0f2e01..b9a89609c95 100644 --- a/packages/fast-usdc/src/fast-usdc.contract.meta.js +++ b/packages/fast-usdc/src/fast-usdc.contract.meta.js @@ -14,6 +14,7 @@ import { } from './type-guards.js'; /** + * @import {Instance, StartParams} from '@agoric/zoe/src/zoeService/utils' * @import {BootstrapManifestPermit} from '@agoric/vats/src/core/lib-boot.js'; * @import {TypedPattern} from '@agoric/internal' * @import {Marshaller} from '@agoric/internal/src/lib-chainStorage.js' @@ -54,6 +55,21 @@ export const meta = /** @type {const} */ ({ }); harden(meta); +/** + * @typedef { PromiseSpaceOf<{ + * fastUsdcKit: FastUSDCKit + * }> & { + * installation: PromiseSpaceOf<{ fastUsdc: Installation }>; + * instance: PromiseSpaceOf<{ fastUsdc: Instance }>; + * issuer: PromiseSpaceOf<{ FastLP: Issuer }>; + * brand: PromiseSpaceOf<{ FastLP: Brand }>; + * }} FastUSDCCorePowers + * + * @typedef {StartedInstanceKitWithLabel & { + * privateArgs: StartParams['privateArgs']; + * }} FastUSDCKit + */ + /** @satisfies {BootstrapManifestPermit} */ export const permit = { produce: { diff --git a/packages/fast-usdc/src/fast-usdc.start.js b/packages/fast-usdc/src/fast-usdc.start.js index 898ad2379ef..2c85f662ef3 100644 --- a/packages/fast-usdc/src/fast-usdc.start.js +++ b/packages/fast-usdc/src/fast-usdc.start.js @@ -8,13 +8,12 @@ import { fromExternalConfig } from './utils/config-marshal.js'; /** * @import {DepositFacet} from '@agoric/ertp/src/types.js' - * @import {Instance, StartParams} from '@agoric/zoe/src/zoeService/utils' * @import {Board} from '@agoric/vats' * @import {ManifestBundleRef} from '@agoric/deploy-script-support/src/externalTypes.js' * @import {BootstrapManifest} from '@agoric/vats/src/core/lib-boot.js' * @import {LegibleCapData} from './utils/config-marshal.js' - * @import {FastUsdcSF} from './fast-usdc.contract.js' * @import {FeedPolicy, FastUSDCConfig as ContractConfig} from './types.js' + * @import {FastUSDCCorePowers as CorePowers} from './fast-usdc.contract.meta.js'; */ const { entries, fromEntries, keys, values } = Object; // XXX move up @@ -110,25 +109,10 @@ const makeAdminRole = (role, namesByAddress, nameToAddress) => { }); }; -/** - * @typedef { PromiseSpaceOf<{ - * fastUsdcKit: FastUSDCKit - * }> & { - * installation: PromiseSpaceOf<{ fastUsdc: Installation }>; - * instance: PromiseSpaceOf<{ fastUsdc: Instance }>; - * issuer: PromiseSpaceOf<{ FastLP: Issuer }>; - * brand: PromiseSpaceOf<{ FastLP: Brand }>; - * }} FastUSDCCorePowers - * - * @typedef {StartedInstanceKitWithLabel & { - * privateArgs: StartParams['privateArgs']; - * }} FastUSDCKit - */ - /** * @throws if admin role smart wallets are not yet provisioned * - * @param {BootstrapPowers & FastUSDCCorePowers } powers + * @param {BootstrapPowers & CorePowers } powers * @param {{ options: LegibleCapData }} config */ export const startFastUSDC = async ( From 5f68fb4dbd741f56871aa52a8e8f42f0bd97a19c Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Sun, 15 Dec 2024 18:50:30 -0600 Subject: [PATCH 12/21] refactor(fast-usdc): produce._name_Kit generic --- packages/fast-usdc/src/fast-usdc.start.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/fast-usdc/src/fast-usdc.start.js b/packages/fast-usdc/src/fast-usdc.start.js index 2c85f662ef3..6a74ccd478a 100644 --- a/packages/fast-usdc/src/fast-usdc.start.js +++ b/packages/fast-usdc/src/fast-usdc.start.js @@ -117,7 +117,7 @@ const makeAdminRole = (role, namesByAddress, nameToAddress) => { */ export const startFastUSDC = async ( { - produce: { fastUsdcKit }, + produce, consume: { agoricNames, namesByAddress, @@ -197,7 +197,7 @@ export const startFastUSDC = async ( terms, privateArgs, }); - fastUsdcKit.resolve(harden({ ...kit, privateArgs })); + produce[`${contractName}Kit`].resolve(harden({ ...kit, privateArgs })); const { instance, creatorFacet } = kit; await publishFeedPolicy(storageNode, feedPolicy); From 8e9c6e8832381dca820100a8045a1a8f6189920e Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Sun, 15 Dec 2024 19:10:18 -0600 Subject: [PATCH 13/21] refactor(fast-usdc): startFastUSDC -> startOrchContract --- packages/fast-usdc/src/fast-usdc.start.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/fast-usdc/src/fast-usdc.start.js b/packages/fast-usdc/src/fast-usdc.start.js index 6a74ccd478a..e20512a2bc8 100644 --- a/packages/fast-usdc/src/fast-usdc.start.js +++ b/packages/fast-usdc/src/fast-usdc.start.js @@ -115,7 +115,7 @@ const makeAdminRole = (role, namesByAddress, nameToAddress) => { * @param {BootstrapPowers & CorePowers } powers * @param {{ options: LegibleCapData }} config */ -export const startFastUSDC = async ( +export const startOrchContract = async ( { produce, consume: { @@ -140,7 +140,7 @@ export const startFastUSDC = async ( }, config, ) => { - trace('startFastUSDC'); + trace('startOrchContract'); const xVatContext = await E(E(agoricNames).lookup('brand')).entries(); const internalConfig = fromExternalConfig( @@ -230,9 +230,9 @@ export const startFastUSDC = async ( const addr = await E(creatorFacet).connectToNoble(); trace('noble intermediate recipient', addr); } - trace('startFastUSDC done', instance); + trace('startOrchContract done', instance); }; -harden(startFastUSDC); +harden(startOrchContract); /** * @param {{ @@ -249,7 +249,7 @@ export const getManifestForFastUSDC = ( ) => { return { /** @type {BootstrapManifest} */ - manifest: { [startFastUSDC.name]: permit }, + manifest: { [startOrchContract.name]: permit }, installations: { [contractName]: restoreRef(installKeys[contractName]) }, options, }; From a2f6c89d78acad87773ffb36ea0b59a90587a0bd Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Sun, 15 Dec 2024 20:03:16 -0600 Subject: [PATCH 14/21] refactor(fast-usdc): finishDeploy reconsider ExtraCorePowers: infer from permit --- .../fast-usdc/src/fast-usdc.contract.meta.js | 59 +++++++++++------- packages/fast-usdc/src/fast-usdc.start.js | 62 +++++++++++-------- 2 files changed, 74 insertions(+), 47 deletions(-) diff --git a/packages/fast-usdc/src/fast-usdc.contract.meta.js b/packages/fast-usdc/src/fast-usdc.contract.meta.js index b9a89609c95..7e85288f693 100644 --- a/packages/fast-usdc/src/fast-usdc.contract.meta.js +++ b/packages/fast-usdc/src/fast-usdc.contract.meta.js @@ -14,13 +14,13 @@ import { } from './type-guards.js'; /** - * @import {Instance, StartParams} from '@agoric/zoe/src/zoeService/utils' + * @import {StartParams} from '@agoric/zoe/src/zoeService/utils' * @import {BootstrapManifestPermit} from '@agoric/vats/src/core/lib-boot.js'; - * @import {TypedPattern} from '@agoric/internal' + * @import {TypedPattern, Remote} from '@agoric/internal' * @import {Marshaller} from '@agoric/internal/src/lib-chainStorage.js' * @import {OrchestrationPowers} from '@agoric/orchestration'; * @import {FastUsdcSF} from './fast-usdc.contract.js'; - * @import {FastUSDCConfig} from './types.js' + * @import {FeedPolicy, FastUSDCConfig} from './types.js' */ /** @type {TypedPattern} */ @@ -55,23 +55,8 @@ export const meta = /** @type {const} */ ({ }); harden(meta); -/** - * @typedef { PromiseSpaceOf<{ - * fastUsdcKit: FastUSDCKit - * }> & { - * installation: PromiseSpaceOf<{ fastUsdc: Installation }>; - * instance: PromiseSpaceOf<{ fastUsdc: Instance }>; - * issuer: PromiseSpaceOf<{ FastLP: Issuer }>; - * brand: PromiseSpaceOf<{ FastLP: Brand }>; - * }} FastUSDCCorePowers - * - * @typedef {StartedInstanceKitWithLabel & { - * privateArgs: StartParams['privateArgs']; - * }} FastUSDCKit - */ - /** @satisfies {BootstrapManifestPermit} */ -export const permit = { +export const permit = /** @type {const} */ ({ produce: { fastUsdcKit: true, }, @@ -103,7 +88,7 @@ export const permit = { installation: { consume: { fastUsdc: true }, }, -}; +}); harden(permit); const POOL_METRICS = 'poolMetrics'; @@ -114,7 +99,7 @@ const POOL_METRICS = 'poolMetrics'; * @param {Marshaller} marshaller * @param {FastUSDCConfig} config * @param {(...args: any[]) => void} trace - * @returns {Promise['1']>} + * @returns {Promise['privateArgs']>} */ export const makePrivateArgs = async ( orchestrationPowers, @@ -137,3 +122,35 @@ export const makePrivateArgs = async ( }); }; harden(makePrivateArgs); + +const FEED_POLICY = 'feedPolicy'; + +/** + * @param {Remote} node + * @param {FeedPolicy} policy + */ +const publishFeedPolicy = async (node, policy) => { + const feedPolicy = E(node).makeChildNode(FEED_POLICY); + await E(feedPolicy).setValue(JSON.stringify(policy)); +}; + +/** + * @param {FastUSDCConfig} config + * @param {StartedInstanceKit & + * { privateArgs: StartParams['privateArgs'] } + * } kit + * @param {(...args: any[]) => void} trace + */ +export const finishDeploy = async (config, kit, trace) => { + const { storageNode } = kit.privateArgs; + const { feedPolicy } = config; + await publishFeedPolicy(storageNode, feedPolicy); + + const { creatorFacet } = kit; + const addresses = await E(creatorFacet).publishAddresses(); + trace('contract orch account addresses', addresses); + if (!config.noNoble) { + const addr = await E(creatorFacet).connectToNoble(); + trace('noble intermediate recipient', addr); + } +}; diff --git a/packages/fast-usdc/src/fast-usdc.start.js b/packages/fast-usdc/src/fast-usdc.start.js index e20512a2bc8..3782a74b3ca 100644 --- a/packages/fast-usdc/src/fast-usdc.start.js +++ b/packages/fast-usdc/src/fast-usdc.start.js @@ -3,22 +3,31 @@ import { Fail } from '@endo/errors'; import { E } from '@endo/far'; import { makeMarshal } from '@endo/marshal'; import { M, mustMatch } from '@endo/patterns'; -import { makePrivateArgs, meta, permit } from './fast-usdc.contract.meta.js'; +import { + finishDeploy, + makePrivateArgs, + meta, + permit, +} from './fast-usdc.contract.meta.js'; import { fromExternalConfig } from './utils/config-marshal.js'; /** + * @import {Instance, StartParams, StartedInstanceKit} from '@agoric/zoe/src/zoeService/utils' * @import {DepositFacet} from '@agoric/ertp/src/types.js' * @import {Board} from '@agoric/vats' * @import {ManifestBundleRef} from '@agoric/deploy-script-support/src/externalTypes.js' * @import {BootstrapManifest} from '@agoric/vats/src/core/lib-boot.js' * @import {LegibleCapData} from './utils/config-marshal.js' - * @import {FeedPolicy, FastUSDCConfig as ContractConfig} from './types.js' - * @import {FastUSDCCorePowers as CorePowers} from './fast-usdc.contract.meta.js'; + * + * TODO: re-export these from .meta with generic names + * @import {FastUSDCConfig as ContractConfig} from './types.js' + * @import {FastUsdcSF as TheSF} from './fast-usdc.contract.js'; */ const { entries, fromEntries, keys, values } = Object; // XXX move up const contractName = meta.name; +/** @typedef {typeof meta.name} TheContractName */ const trace = makeTracer(`${meta.abbr}-Start`, true); @@ -58,17 +67,6 @@ const publishDisplayInfo = async (brand, { board, chainStorage }) => { await E(node).setValue(JSON.stringify(aux)); }; -const FEED_POLICY = 'feedPolicy'; - -/** - * @param {ERef} node - * @param {FeedPolicy} policy - */ -const publishFeedPolicy = async (node, policy) => { - const feedPolicy = E(node).makeChildNode(FEED_POLICY); - await E(feedPolicy).setValue(JSON.stringify(policy)); -}; - /** * @param {string} role * @param {ERef} namesByAddress @@ -109,10 +107,25 @@ const makeAdminRole = (role, namesByAddress, nameToAddress) => { }); }; +/** + * @typedef { typeof permit.issuer.produce } PermittedIssuers + * @typedef { PromiseSpaceOf> & { + * installation: PromiseSpaceOf>>; + * instance: PromiseSpaceOf>>; + * issuer: PromiseSpaceOf>; + * brand: PromiseSpaceOf>; + * }} ExtraCorePowers + * + * @typedef {StartedInstanceKit & { + * label: string, + * privateArgs: StartParams['privateArgs']; + * }} TheContractKit + */ + /** * @throws if admin role smart wallets are not yet provisioned * - * @param {BootstrapPowers & CorePowers } powers + * @param {BootstrapPowers & ExtraCorePowers } powers * @param {{ options: LegibleCapData }} config */ export const startOrchContract = async ( @@ -148,7 +161,7 @@ export const startOrchContract = async ( xVatContext, meta.deployConfigShape, ); - const { terms, feedPolicy, ...net } = internalConfig; + const { terms } = internalConfig; trace('using terms', terms); const adminRoles = objectMap(meta?.adminRoles || {}, (_method, role) => { @@ -197,10 +210,10 @@ export const startOrchContract = async ( terms, privateArgs, }); - produce[`${contractName}Kit`].resolve(harden({ ...kit, privateArgs })); const { instance, creatorFacet } = kit; - - await publishFeedPolicy(storageNode, feedPolicy); + /** @type {TheContractKit} */ + const fullKit = harden({ ...kit, privateArgs }); + produce[`${contractName}Kit`].resolve(fullKit); const newIssuerNames = keys(permit?.issuer?.produce || {}).filter( n => permit?.brand?.produce?.[n], @@ -221,15 +234,11 @@ export const startOrchContract = async ( await adminRoles[role].send(addr => E(creatorFacet)[method](addr)); } + await finishDeploy(internalConfig, fullKit, trace); + produceInstance.reset(); produceInstance.resolve(instance); - const addresses = await E(creatorFacet).publishAddresses(); - trace('contract orch account addresses', addresses); - if (!net.noNoble) { - const addr = await E(creatorFacet).connectToNoble(); - trace('noble intermediate recipient', addr); - } trace('startOrchContract done', instance); }; harden(startOrchContract); @@ -239,10 +248,11 @@ harden(startOrchContract); * restoreRef: (b: ERef) => Promise; * }} utils * @param {{ - * installKeys: { fastUsdc: ERef }; + * installKeys: Record>; * options: LegibleCapData; * }} param1 */ +// TODO: rename to getManifestForOrchContract export const getManifestForFastUSDC = ( { restoreRef }, { installKeys, options }, From fbbdeaa73b1ba87542bc957806db3fc4798f0c0f Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Sun, 15 Dec 2024 20:14:24 -0600 Subject: [PATCH 15/21] refactor(fast-usdc): adminRoles type --- packages/fast-usdc/src/fast-usdc.contract.meta.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/fast-usdc/src/fast-usdc.contract.meta.js b/packages/fast-usdc/src/fast-usdc.contract.meta.js index 7e85288f693..bdcb1983761 100644 --- a/packages/fast-usdc/src/fast-usdc.contract.meta.js +++ b/packages/fast-usdc/src/fast-usdc.contract.meta.js @@ -49,6 +49,7 @@ export const meta = /** @type {const} */ ({ poolMetricsNode: M.remotable(), }, deployConfigShape: FastUSDCConfigShape, + /** @type {Record['creatorFacet']>} */ adminRoles: { oracles: 'makeOperatorInvitation', }, From 7fe9e53c40bf5456b99e229f20b8b69cf6262c2d Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Sun, 15 Dec 2024 20:31:34 -0600 Subject: [PATCH 16/21] refactor(fast-usdc): factor out typical permit stuff --- .../fast-usdc/src/fast-usdc.contract.meta.js | 51 ++++++++++--------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/packages/fast-usdc/src/fast-usdc.contract.meta.js b/packages/fast-usdc/src/fast-usdc.contract.meta.js index bdcb1983761..c344e40db79 100644 --- a/packages/fast-usdc/src/fast-usdc.contract.meta.js +++ b/packages/fast-usdc/src/fast-usdc.contract.meta.js @@ -57,25 +57,36 @@ export const meta = /** @type {const} */ ({ harden(meta); /** @satisfies {BootstrapManifestPermit} */ -export const permit = /** @type {const} */ ({ - produce: { - fastUsdcKit: true, - }, - consume: { - chainStorage: true, - chainTimerService: true, - localchain: true, - cosmosInterchainService: true, +const orchPermit = /** @type {const} */ ({ + localchain: true, + cosmosInterchainService: true, + chainStorage: true, + chainTimerService: true, + agoricNames: true, - // limited distribution durin MN2: contract installation - startUpgradable: true, - zoe: true, // only getTerms() is needed. XXX should be split? + // for publishing Brands and other remote object references + board: true, - // widely shared: name services - agoricNames: true, - namesByAddress: true, - board: true, - }, + // limited distribution durin MN2: contract installation + startUpgradable: true, + zoe: true, // only getTerms() is needed. XXX should be split? +}); + +/** + * to find deposit facets for admin invitations + * + * @satisfies {BootstrapManifestPermit} + */ +const adminPermit = /** @type {const} */ ({ + namesByAddress: true, +}); + +/** @satisfies {BootstrapManifestPermit} */ +export const permit = /** @type {const} */ ({ + produce: { [`${meta.name}Kit`]: true }, + consume: { ...orchPermit, ...adminPermit }, + instance: { produce: { [meta.name]: true } }, + installation: { consume: { [meta.name]: true } }, issuer: { consume: { USDC: true }, produce: { FastLP: true }, // UNTIL #10432 @@ -83,12 +94,6 @@ export const permit = /** @type {const} */ ({ brand: { produce: { FastLP: true }, // UNTIL #10432 }, - instance: { - produce: { fastUsdc: true }, - }, - installation: { - consume: { fastUsdc: true }, - }, }); harden(permit); From 63136aec325824e807dc979e112f11d034c19f89 Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Tue, 17 Dec 2024 00:42:59 -0600 Subject: [PATCH 17/21] WIP: generic startOrch --- .../fast-usdc/src/fast-usdc.contract.meta.js | 25 ++- packages/fast-usdc/src/fast-usdc.start.js | 205 +++++++++++++++++- 2 files changed, 228 insertions(+), 2 deletions(-) diff --git a/packages/fast-usdc/src/fast-usdc.contract.meta.js b/packages/fast-usdc/src/fast-usdc.contract.meta.js index c344e40db79..85ac6a6e2d3 100644 --- a/packages/fast-usdc/src/fast-usdc.contract.meta.js +++ b/packages/fast-usdc/src/fast-usdc.contract.meta.js @@ -12,6 +12,7 @@ import { FeeConfigShape, FeedPolicyShape, } from './type-guards.js'; +import { startOrchContractG } from './fast-usdc.start.js'; /** * @import {StartParams} from '@agoric/zoe/src/zoeService/utils' @@ -23,6 +24,11 @@ import { * @import {FeedPolicy, FastUSDCConfig} from './types.js' */ +/** + * @import {LegibleCapData} from './utils/config-marshal.js' + * @import {CorePowersG} from './fast-usdc.start.js'; + */ + /** @type {TypedPattern} */ export const FastUSDCConfigShape = M.splitRecord({ terms: FastUSDCTermsShape, @@ -147,7 +153,7 @@ const publishFeedPolicy = async (node, policy) => { * } kit * @param {(...args: any[]) => void} trace */ -export const finishDeploy = async (config, kit, trace) => { +export const finishDeploy = async (config, kit, trace = console.log) => { const { storageNode } = kit.privateArgs; const { feedPolicy } = config; await publishFeedPolicy(storageNode, feedPolicy); @@ -160,3 +166,20 @@ export const finishDeploy = async (config, kit, trace) => { trace('noble intermediate recipient', addr); } }; + +/** + * @param {BootstrapPowers & CorePowersG<'fastUsdc', FastUsdcSF, typeof permit>} permitted + * @param {{ options: LegibleCapData }} config + */ +const startFastUSDC = async (permitted, config) => { + const { config: conf, kit } = await startOrchContractG( + meta, + permit, + makePrivateArgs, + permitted, + config, + ); + // TODO: inline finishDeploy? + // TODO: make a tracer? + await finishDeploy(conf, kit); +}; diff --git a/packages/fast-usdc/src/fast-usdc.start.js b/packages/fast-usdc/src/fast-usdc.start.js index 3782a74b3ca..6fb4d48f99c 100644 --- a/packages/fast-usdc/src/fast-usdc.start.js +++ b/packages/fast-usdc/src/fast-usdc.start.js @@ -12,7 +12,10 @@ import { import { fromExternalConfig } from './utils/config-marshal.js'; /** - * @import {Instance, StartParams, StartedInstanceKit} from '@agoric/zoe/src/zoeService/utils' + * @import {CopyRecord} from '@endo/pass-style'; + * @import {TypedPattern} from '@agoric/internal'; + * @import {OrchestrationPowers} from '@agoric/orchestration'; + * @import {ContractStartFunction, Instance, StartParams, StartedInstanceKit} from '@agoric/zoe/src/zoeService/utils' * @import {DepositFacet} from '@agoric/ertp/src/types.js' * @import {Board} from '@agoric/vats' * @import {ManifestBundleRef} from '@agoric/deploy-script-support/src/externalTypes.js' @@ -122,6 +125,206 @@ const makeAdminRole = (role, namesByAddress, nameToAddress) => { * }} TheContractKit */ +/** + * @template {{}} T + * @param {T} obj + * @param {(entry: [k: K, v: T[K]], index: number, es: [PropertyKey, unknown][]) => Partial} pred + * @returns {Partial} + */ +const objectFilter = (obj, pred) => { + /** @type {Partial} */ + // @ts-expect-error pred type too narrow + const found = harden(fromEntries(entries(obj).filter(pred))); + return found; +}; + +/** + * @template {PermitG} P + * @param {Pick} consume + * @param {P} permitG + */ +export const permittedIssuers = async ({ agoricNames }, permitG) => { + const permittedKeys = keys(permitG?.issuer?.consume || {}); + const agoricIssuers = await E(E(agoricNames).lookup('issuer')).entries(); + /** @type {Record} */ + // @ts-expect-error by construction + const issuerKeywordRecord = fromEntries( + agoricIssuers.filter(([n, _v]) => permittedKeys.includes(n)), + ); + return issuerKeywordRecord; +}; + +/** + * @template {string} CN contract name + * @template {ContractStartFunction} SF typeof start + * @template {CopyRecord} CFG + * @typedef {ContractMeta & {name: CN} & { + * adminRoles?: Record['creatorFacet']>, + * deployConfigShape?: TypedPattern, + * }} ContractMetaG + */ + +/** + * @template {ContractStartFunction} SF typeof start + * @typedef {StartedInstanceKit & { + * label: string, + * privateArgs: Parameters[1]; + * }} UpgradeKit + * + */ + +/** + * @typedef {BootstrapManifest & + * { issuer: BootstrapManifest} & + * { brand: BootstrapManifest } + * } PermitG generic permit constraints + */ + +/** + * @template {string} CN contract name + * @template {ContractStartFn} SF typeof start + * @template {PermitG} P permit + * @typedef { PromiseSpaceOf>> & { + * installation: PromiseSpaceOf>>; + * instance: PromiseSpaceOf>>; + * issuer: PromiseSpaceOf>; + * brand: PromiseSpaceOf>; + * }} CorePowersG + */ + +/** + * @template {ContractStartFn} SF typeof start + * @template {CopyRecord} CFG + * @typedef {(op: OrchestrationPowers, m: Marshaller, cfg: CFG, log: typeof trace) => Parameters[1]} MakePrivateArgs + */ + +/** + * @throws if admin role smart wallets are not yet provisioned + * + * @template {string} CN contract name + * @template {ContractStartFn} SF typeof start + * @template {CopyRecord} CFG + * @template {PermitG} P permit + * @param {ContractMetaG} metaG + * @param {P} permitG + * @param {MakePrivateArgs} makePrivateArgsG + * @param {CorePowersG & BootstrapPowers} powers + * @param {{ options: LegibleCapData }} config + */ +export const startOrchContractG = async ( + metaG, + permitG, + makePrivateArgsG, + { + produce, + consume, + issuer: { produce: produceIssuer }, + brand: { produce: produceBrand }, + installation: { + consume: { [metaG.name]: installation }, + }, + instance: { + produce: { [metaG.name]: produceInstance }, + }, + }, + config, +) => { + trace('startOrchContract'); + + const issuerKeywordRecord = await permittedIssuers(consume, permitG); + + const { agoricNames, board } = consume; + const xVatContext = await E(E(agoricNames).lookup('brand')).entries(); + const internalConfig = fromExternalConfig( + config.options, + xVatContext, + metaG.deployConfigShape, + ); + const { terms } = internalConfig; + trace('using terms', terms); + + const adminRoles = objectMap(metaG?.adminRoles || {}, (_method, role) => { + const nameToAddress = internalConfig[role]; + mustMatch(nameToAddress, M.recordOf(M.string(), M.string())); + return makeAdminRole( + /** @type {string} */ (role), // XXX tsc gets confused? + consume.namesByAddress, + nameToAddress, + ); + }); + + await Promise.all(values(adminRoles).map(r => r.lookup())); + + /** @type {{ chainStorage: Promise}} */ + // @ts-expect-error Promise case is vestigial + const { chainStorage } = consume; + const { storageNode, marshaller } = await makePublishingStorageKit( + meta.name, + { board, chainStorage }, + ); + + const { + chainTimerService: timerService, + localchain, + cosmosInterchainService, + } = consume; + const orchestrationPowers = await deeplyFulfilledObject( + harden({ + localchain, + orchestrationService: cosmosInterchainService, + storageNode, + timerService, + agoricNames, + }), + ); + const privateArgs = await makePrivateArgsG( + orchestrationPowers, + marshaller, + internalConfig, + trace, + ); + + const { startUpgradable, zoe } = consume; + const kit = await E(startUpgradable)({ + label: metaG.name, + installation, + issuerKeywordRecord, + terms, + privateArgs, + }); + const { instance, creatorFacet } = kit; + /** @type {UpgradeKit} */ + const fullKit = harden({ ...kit, privateArgs }); + // @ts-expect-error XXX tsc gets confused? + produce[`${metaG.name}Kit`].resolve(fullKit); + + const newIssuerNames = keys(permit?.issuer?.produce || {}).filter( + n => permit?.brand?.produce?.[n], + ); + if (newIssuerNames.length > 0) { + const { issuers, brands } = await E(zoe).getTerms(instance); + for (const name of newIssuerNames) { + console.log('new well-known Issuer, Brand:', name); + produceIssuer[name].reset(); + produceIssuer[name].resolve(issuers[name]); + produceBrand[name].reset(); + produceBrand[name].resolve(brands[name]); + await publishDisplayInfo(brands[name], { board, chainStorage }); + } + } + + for (const [role, method] of entries(meta.adminRoles)) { + await adminRoles[role].send(addr => E(creatorFacet)[method](addr)); + } + + produceInstance.reset(); + produceInstance.resolve(instance); + + trace('startOrchContract done', instance); + return { config: internalConfig, kit }; +}; +harden(startOrchContractG); + /** * @throws if admin role smart wallets are not yet provisioned * From f82d8bb9d1acd1482aa745fffe8881a5c77117eb Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Tue, 17 Dec 2024 01:53:24 -0600 Subject: [PATCH 18/21] WIP: more generic start --- .../fast-usdc/src/fast-usdc.contract.meta.js | 123 +---- packages/fast-usdc/src/fast-usdc.start.js | 495 ++---------------- packages/fast-usdc/src/orch.start.js | 356 +++++++++++++ 3 files changed, 416 insertions(+), 558 deletions(-) create mode 100644 packages/fast-usdc/src/orch.start.js diff --git a/packages/fast-usdc/src/fast-usdc.contract.meta.js b/packages/fast-usdc/src/fast-usdc.contract.meta.js index 85ac6a6e2d3..47e59658f6d 100644 --- a/packages/fast-usdc/src/fast-usdc.contract.meta.js +++ b/packages/fast-usdc/src/fast-usdc.contract.meta.js @@ -5,18 +5,18 @@ import { DenomShape, OrchestrationPowersShape, } from '@agoric/orchestration'; -import { E } from '@endo/far'; import { M } from '@endo/patterns'; import { FastUSDCTermsShape, FeeConfigShape, FeedPolicyShape, } from './type-guards.js'; -import { startOrchContractG } from './fast-usdc.start.js'; +import { adminPermit, orchPermit } from './orch.start.js'; /** * @import {StartParams} from '@agoric/zoe/src/zoeService/utils' - * @import {BootstrapManifestPermit} from '@agoric/vats/src/core/lib-boot.js'; + * @import {BootstrapManifest, BootstrapManifestPermit} from '@agoric/vats/src/core/lib-boot.js'; + * @import {ManifestBundleRef} from '@agoric/deploy-script-support/src/externalTypes.js' * @import {TypedPattern, Remote} from '@agoric/internal' * @import {Marshaller} from '@agoric/internal/src/lib-chainStorage.js' * @import {OrchestrationPowers} from '@agoric/orchestration'; @@ -26,7 +26,7 @@ import { startOrchContractG } from './fast-usdc.start.js'; /** * @import {LegibleCapData} from './utils/config-marshal.js' - * @import {CorePowersG} from './fast-usdc.start.js'; + * @import {CorePowersG} from './orch.start.js'; */ /** @type {TypedPattern} */ @@ -62,124 +62,13 @@ export const meta = /** @type {const} */ ({ }); harden(meta); -/** @satisfies {BootstrapManifestPermit} */ -const orchPermit = /** @type {const} */ ({ - localchain: true, - cosmosInterchainService: true, - chainStorage: true, - chainTimerService: true, - agoricNames: true, - - // for publishing Brands and other remote object references - board: true, - - // limited distribution durin MN2: contract installation - startUpgradable: true, - zoe: true, // only getTerms() is needed. XXX should be split? -}); - -/** - * to find deposit facets for admin invitations - * - * @satisfies {BootstrapManifestPermit} - */ -const adminPermit = /** @type {const} */ ({ - namesByAddress: true, -}); - /** @satisfies {BootstrapManifestPermit} */ export const permit = /** @type {const} */ ({ produce: { [`${meta.name}Kit`]: true }, consume: { ...orchPermit, ...adminPermit }, instance: { produce: { [meta.name]: true } }, installation: { consume: { [meta.name]: true } }, - issuer: { - consume: { USDC: true }, - produce: { FastLP: true }, // UNTIL #10432 - }, - brand: { - produce: { FastLP: true }, // UNTIL #10432 - }, + issuer: { produce: { FastLP: true }, consume: { USDC: true } }, + brand: { produce: { FastLP: true } }, }); harden(permit); - -const POOL_METRICS = 'poolMetrics'; - -/** - * - * @param {OrchestrationPowers} orchestrationPowers - * @param {Marshaller} marshaller - * @param {FastUSDCConfig} config - * @param {(...args: any[]) => void} trace - * @returns {Promise['privateArgs']>} - */ -export const makePrivateArgs = async ( - orchestrationPowers, - marshaller, - config, - trace, -) => { - const { storageNode } = orchestrationPowers; - const poolMetricsNode = await E(storageNode).makeChildNode(POOL_METRICS); - const { feeConfig } = config; - trace('using fee config', feeConfig); - - return harden({ - ...orchestrationPowers, - feeConfig, - poolMetricsNode, - marshaller, - chainInfo: config.chainInfo, - assetInfo: config.assetInfo, - }); -}; -harden(makePrivateArgs); - -const FEED_POLICY = 'feedPolicy'; - -/** - * @param {Remote} node - * @param {FeedPolicy} policy - */ -const publishFeedPolicy = async (node, policy) => { - const feedPolicy = E(node).makeChildNode(FEED_POLICY); - await E(feedPolicy).setValue(JSON.stringify(policy)); -}; - -/** - * @param {FastUSDCConfig} config - * @param {StartedInstanceKit & - * { privateArgs: StartParams['privateArgs'] } - * } kit - * @param {(...args: any[]) => void} trace - */ -export const finishDeploy = async (config, kit, trace = console.log) => { - const { storageNode } = kit.privateArgs; - const { feedPolicy } = config; - await publishFeedPolicy(storageNode, feedPolicy); - - const { creatorFacet } = kit; - const addresses = await E(creatorFacet).publishAddresses(); - trace('contract orch account addresses', addresses); - if (!config.noNoble) { - const addr = await E(creatorFacet).connectToNoble(); - trace('noble intermediate recipient', addr); - } -}; - -/** - * @param {BootstrapPowers & CorePowersG<'fastUsdc', FastUsdcSF, typeof permit>} permitted - * @param {{ options: LegibleCapData }} config - */ -const startFastUSDC = async (permitted, config) => { - const { config: conf, kit } = await startOrchContractG( - meta, - permit, - makePrivateArgs, - permitted, - config, - ); - // TODO: inline finishDeploy? - // TODO: make a tracer? - await finishDeploy(conf, kit); -}; diff --git a/packages/fast-usdc/src/fast-usdc.start.js b/packages/fast-usdc/src/fast-usdc.start.js index 6fb4d48f99c..c8bae7482c6 100644 --- a/packages/fast-usdc/src/fast-usdc.start.js +++ b/packages/fast-usdc/src/fast-usdc.start.js @@ -1,469 +1,82 @@ -import { deeplyFulfilledObject, makeTracer, objectMap } from '@agoric/internal'; -import { Fail } from '@endo/errors'; +/** ContractMeta, Permit for Fast USDC */ import { E } from '@endo/far'; -import { makeMarshal } from '@endo/marshal'; -import { M, mustMatch } from '@endo/patterns'; -import { - finishDeploy, - makePrivateArgs, - meta, - permit, -} from './fast-usdc.contract.meta.js'; -import { fromExternalConfig } from './utils/config-marshal.js'; +import { makeTracer } from '@agoric/internal/src/debug.js'; +import { meta, permit } from './fast-usdc.contract.meta.js'; +import { makeGetManifest, startOrchContract } from './orch.start.js'; /** - * @import {CopyRecord} from '@endo/pass-style'; - * @import {TypedPattern} from '@agoric/internal'; + * @import {Marshaller} from '@agoric/internal/src/lib-chainStorage.js' * @import {OrchestrationPowers} from '@agoric/orchestration'; - * @import {ContractStartFunction, Instance, StartParams, StartedInstanceKit} from '@agoric/zoe/src/zoeService/utils' - * @import {DepositFacet} from '@agoric/ertp/src/types.js' - * @import {Board} from '@agoric/vats' - * @import {ManifestBundleRef} from '@agoric/deploy-script-support/src/externalTypes.js' - * @import {BootstrapManifest} from '@agoric/vats/src/core/lib-boot.js' - * @import {LegibleCapData} from './utils/config-marshal.js' - * - * TODO: re-export these from .meta with generic names - * @import {FastUSDCConfig as ContractConfig} from './types.js' - * @import {FastUsdcSF as TheSF} from './fast-usdc.contract.js'; - */ - -const { entries, fromEntries, keys, values } = Object; // XXX move up - -const contractName = meta.name; -/** @typedef {typeof meta.name} TheContractName */ - -const trace = makeTracer(`${meta.abbr}-Start`, true); - -/** - * XXX Shouldn't the bridge or board vat handle this? * - * @param {string} path - * @param {{ - * chainStorage: ERef; - * board: ERef; - * }} io - */ -const makePublishingStorageKit = async (path, { chainStorage, board }) => { - const storageNode = await E(chainStorage).makeChildNode(path); - - const marshaller = await E(board).getPublishingMarshaller(); - return { storageNode, marshaller }; -}; - -const BOARD_AUX = 'boardAux'; -const marshalData = makeMarshal(_val => Fail`data only`); -/** - * @param {Brand} brand - * @param {Pick} powers - */ -const publishDisplayInfo = async (brand, { board, chainStorage }) => { - // chainStorage type includes undefined, which doesn't apply here. - // @ts-expect-error UNTIL https://github.com/Agoric/agoric-sdk/issues/8247 - const boardAux = E(chainStorage).makeChildNode(BOARD_AUX); - const [id, displayInfo, allegedName] = await Promise.all([ - E(board).getId(brand), - E(brand).getDisplayInfo(), - E(brand).getAllegedName(), - ]); - const node = E(boardAux).makeChildNode(id); - const aux = marshalData.toCapData(harden({ allegedName, displayInfo })); - await E(node).setValue(JSON.stringify(aux)); -}; - -/** - * @param {string} role - * @param {ERef} namesByAddress - * @param {Record} nameToAddress - */ -const makeAdminRole = (role, namesByAddress, nameToAddress) => { - const lookup = async () => { - trace('look up deposit facets for', role); - return deeplyFulfilledObject( - objectMap(nameToAddress, async address => { - /** @type {DepositFacet} */ - const depositFacet = await E(namesByAddress).lookup( - address, - 'depositFacet', - ); - return depositFacet; - }), - ); - }; - const lookupP = lookup(); - - return harden({ - lookup: () => lookupP, - /** @param {(addr: string) => Promise} makeInvitation */ - send: async makeInvitation => { - const oracleDepositFacets = await lookupP; - await Promise.all( - entries(oracleDepositFacets).map(async ([name, depositFacet]) => { - const address = nameToAddress[name]; - trace('making invitation for', role, name, address); - const toWatch = await makeInvitation(address); - - const amt = await E(depositFacet).receive(toWatch); - trace('sent', amt, 'to', role, name); - }), - ); - }, - }); -}; - -/** - * @typedef { typeof permit.issuer.produce } PermittedIssuers - * @typedef { PromiseSpaceOf> & { - * installation: PromiseSpaceOf>>; - * instance: PromiseSpaceOf>>; - * issuer: PromiseSpaceOf>; - * brand: PromiseSpaceOf>; - * }} ExtraCorePowers - * - * @typedef {StartedInstanceKit & { - * label: string, - * privateArgs: StartParams['privateArgs']; - * }} TheContractKit - */ - -/** - * @template {{}} T - * @param {T} obj - * @param {(entry: [k: K, v: T[K]], index: number, es: [PropertyKey, unknown][]) => Partial} pred - * @returns {Partial} - */ -const objectFilter = (obj, pred) => { - /** @type {Partial} */ - // @ts-expect-error pred type too narrow - const found = harden(fromEntries(entries(obj).filter(pred))); - return found; -}; - -/** - * @template {PermitG} P - * @param {Pick} consume - * @param {P} permitG - */ -export const permittedIssuers = async ({ agoricNames }, permitG) => { - const permittedKeys = keys(permitG?.issuer?.consume || {}); - const agoricIssuers = await E(E(agoricNames).lookup('issuer')).entries(); - /** @type {Record} */ - // @ts-expect-error by construction - const issuerKeywordRecord = fromEntries( - agoricIssuers.filter(([n, _v]) => permittedKeys.includes(n)), - ); - return issuerKeywordRecord; -}; - -/** - * @template {string} CN contract name - * @template {ContractStartFunction} SF typeof start - * @template {CopyRecord} CFG - * @typedef {ContractMeta & {name: CN} & { - * adminRoles?: Record['creatorFacet']>, - * deployConfigShape?: TypedPattern, - * }} ContractMetaG - */ - -/** - * @template {ContractStartFunction} SF typeof start - * @typedef {StartedInstanceKit & { - * label: string, - * privateArgs: Parameters[1]; - * }} UpgradeKit + * XXX these 2 could/should be down in the platform somewhere + * @import {LegibleCapData} from './utils/config-marshal.js' + * @import {CorePowersG} from './orch.start.js'; * + * @import {FastUsdcSF} from './fast-usdc.contract.js'; + * @import {FastUSDCConfig} from './types.js' */ -/** - * @typedef {BootstrapManifest & - * { issuer: BootstrapManifest} & - * { brand: BootstrapManifest } - * } PermitG generic permit constraints - */ - -/** - * @template {string} CN contract name - * @template {ContractStartFn} SF typeof start - * @template {PermitG} P permit - * @typedef { PromiseSpaceOf>> & { - * installation: PromiseSpaceOf>>; - * instance: PromiseSpaceOf>>; - * issuer: PromiseSpaceOf>; - * brand: PromiseSpaceOf>; - * }} CorePowersG - */ +const POOL_METRICS = 'poolMetrics'; +const FEED_POLICY = 'feedPolicy'; -/** - * @template {ContractStartFn} SF typeof start - * @template {CopyRecord} CFG - * @typedef {(op: OrchestrationPowers, m: Marshaller, cfg: CFG, log: typeof trace) => Parameters[1]} MakePrivateArgs - */ +const trace = makeTracer(`FUSDC-Start`, true); /** - * @throws if admin role smart wallets are not yet provisioned * - * @template {string} CN contract name - * @template {ContractStartFn} SF typeof start - * @template {CopyRecord} CFG - * @template {PermitG} P permit - * @param {ContractMetaG} metaG - * @param {P} permitG - * @param {MakePrivateArgs} makePrivateArgsG - * @param {CorePowersG & BootstrapPowers} powers - * @param {{ options: LegibleCapData }} config + * @param {OrchestrationPowers} orchestrationPowers + * @param {Marshaller} marshaller + * @param {FastUSDCConfig} config + * @returns {Promise[1]>} */ -export const startOrchContractG = async ( - metaG, - permitG, - makePrivateArgsG, - { - produce, - consume, - issuer: { produce: produceIssuer }, - brand: { produce: produceBrand }, - installation: { - consume: { [metaG.name]: installation }, - }, - instance: { - produce: { [metaG.name]: produceInstance }, - }, - }, +export const makePrivateArgs = async ( + orchestrationPowers, + marshaller, config, ) => { - trace('startOrchContract'); - - const issuerKeywordRecord = await permittedIssuers(consume, permitG); - - const { agoricNames, board } = consume; - const xVatContext = await E(E(agoricNames).lookup('brand')).entries(); - const internalConfig = fromExternalConfig( - config.options, - xVatContext, - metaG.deployConfigShape, - ); - const { terms } = internalConfig; - trace('using terms', terms); - - const adminRoles = objectMap(metaG?.adminRoles || {}, (_method, role) => { - const nameToAddress = internalConfig[role]; - mustMatch(nameToAddress, M.recordOf(M.string(), M.string())); - return makeAdminRole( - /** @type {string} */ (role), // XXX tsc gets confused? - consume.namesByAddress, - nameToAddress, - ); - }); - - await Promise.all(values(adminRoles).map(r => r.lookup())); + const { feeConfig, chainInfo, assetInfo } = config; + trace('using fee config', feeConfig); - /** @type {{ chainStorage: Promise}} */ - // @ts-expect-error Promise case is vestigial - const { chainStorage } = consume; - const { storageNode, marshaller } = await makePublishingStorageKit( - meta.name, - { board, chainStorage }, - ); + const { storageNode } = orchestrationPowers; + const poolMetricsNode = await E(storageNode).makeChildNode(POOL_METRICS); - const { - chainTimerService: timerService, - localchain, - cosmosInterchainService, - } = consume; - const orchestrationPowers = await deeplyFulfilledObject( - harden({ - localchain, - orchestrationService: cosmosInterchainService, - storageNode, - timerService, - agoricNames, - }), - ); - const privateArgs = await makePrivateArgsG( - orchestrationPowers, + return harden({ + ...orchestrationPowers, + feeConfig, + poolMetricsNode, marshaller, - internalConfig, - trace, - ); - - const { startUpgradable, zoe } = consume; - const kit = await E(startUpgradable)({ - label: metaG.name, - installation, - issuerKeywordRecord, - terms, - privateArgs, + chainInfo, + assetInfo, }); - const { instance, creatorFacet } = kit; - /** @type {UpgradeKit} */ - const fullKit = harden({ ...kit, privateArgs }); - // @ts-expect-error XXX tsc gets confused? - produce[`${metaG.name}Kit`].resolve(fullKit); - - const newIssuerNames = keys(permit?.issuer?.produce || {}).filter( - n => permit?.brand?.produce?.[n], - ); - if (newIssuerNames.length > 0) { - const { issuers, brands } = await E(zoe).getTerms(instance); - for (const name of newIssuerNames) { - console.log('new well-known Issuer, Brand:', name); - produceIssuer[name].reset(); - produceIssuer[name].resolve(issuers[name]); - produceBrand[name].reset(); - produceBrand[name].resolve(brands[name]); - await publishDisplayInfo(brands[name], { board, chainStorage }); - } - } - - for (const [role, method] of entries(meta.adminRoles)) { - await adminRoles[role].send(addr => E(creatorFacet)[method](addr)); - } - - produceInstance.reset(); - produceInstance.resolve(instance); - - trace('startOrchContract done', instance); - return { config: internalConfig, kit }; }; -harden(startOrchContractG); +harden(makePrivateArgs); /** - * @throws if admin role smart wallets are not yet provisioned - * - * @param {BootstrapPowers & ExtraCorePowers } powers - * @param {{ options: LegibleCapData }} config + * @param {BootstrapPowers & CorePowersG<'fastUsdc', FastUsdcSF, typeof permit>} permitted + * @param {{ options: LegibleCapData }} configStruct */ -export const startOrchContract = async ( - { - produce, - consume: { - agoricNames, - namesByAddress, - board, - chainStorage, - chainTimerService: timerService, - localchain, - cosmosInterchainService, - startUpgradable, - zoe, - }, - issuer: { produce: produceIssuer }, - brand: { produce: produceBrand }, - installation: { - consume: { [contractName]: installation }, - }, - instance: { - produce: { [contractName]: produceInstance }, - }, - }, - config, -) => { - trace('startOrchContract'); - - const xVatContext = await E(E(agoricNames).lookup('brand')).entries(); - const internalConfig = fromExternalConfig( - config.options, - xVatContext, - meta.deployConfigShape, +export const startFastUSDC = async (permitted, configStruct) => { + const { config, kit } = await startOrchContract( + meta, + permit, + makePrivateArgs, + permitted, + configStruct, ); - const { terms } = internalConfig; - trace('using terms', terms); - const adminRoles = objectMap(meta?.adminRoles || {}, (_method, role) => { - const nameToAddress = internalConfig[role]; - mustMatch(nameToAddress, M.recordOf(M.string(), M.string())); - return makeAdminRole(role, namesByAddress, nameToAddress); - }); - - await Promise.all(values(adminRoles).map(r => r.lookup())); - - const { storageNode, marshaller } = await makePublishingStorageKit( - contractName, - { - board, - // @ts-expect-error Promise case is vestigial - chainStorage, - }, - ); - - const orchestrationPowers = await deeplyFulfilledObject( - harden({ - localchain, - orchestrationService: cosmosInterchainService, - storageNode, - timerService, - agoricNames, - }), - ); - const privateArgs = await makePrivateArgs( - orchestrationPowers, - marshaller, - internalConfig, - trace, - ); - - const permittedIssuers = keys(permit?.issuer?.consume || {}); - const agoricIssuers = await E(E(agoricNames).lookup('issuer')).entries(); - const issuerKeywordRecord = fromEntries( - agoricIssuers.filter(([n, _v]) => permittedIssuers.includes(n)), - ); - - const kit = await E(startUpgradable)({ - label: contractName, - installation, - issuerKeywordRecord, - terms, - privateArgs, - }); - const { instance, creatorFacet } = kit; - /** @type {TheContractKit} */ - const fullKit = harden({ ...kit, privateArgs }); - produce[`${contractName}Kit`].resolve(fullKit); - - const newIssuerNames = keys(permit?.issuer?.produce || {}).filter( - n => permit?.brand?.produce?.[n], - ); - if (newIssuerNames.length > 0) { - const { issuers, brands } = await E(zoe).getTerms(instance); - for (const name of newIssuerNames) { - console.log('new well-known Issuer, Brand:', name); - produceIssuer[name].reset(); - produceIssuer[name].resolve(issuers[name]); - produceBrand[name].reset(); - produceBrand[name].resolve(brands[name]); - await publishDisplayInfo(brands[name], { board, chainStorage }); - } - } - - for (const [role, method] of entries(meta.adminRoles)) { - await adminRoles[role].send(addr => E(creatorFacet)[method](addr)); + const { storageNode } = kit.privateArgs; + const { feedPolicy } = config; + const policyNode = E(storageNode).makeChildNode(FEED_POLICY); + await E(policyNode).setValue(JSON.stringify(feedPolicy)); + + const { creatorFacet } = kit; + const addresses = await E(creatorFacet).publishAddresses(); + trace('contract orch account addresses', addresses); + if (!config.noNoble) { + const addr = await E(creatorFacet).connectToNoble(); + trace('noble intermediate recipient', addr); } - - await finishDeploy(internalConfig, fullKit, trace); - - produceInstance.reset(); - produceInstance.resolve(instance); - - trace('startOrchContract done', instance); }; -harden(startOrchContract); -/** - * @param {{ - * restoreRef: (b: ERef) => Promise; - * }} utils - * @param {{ - * installKeys: Record>; - * options: LegibleCapData; - * }} param1 - */ -// TODO: rename to getManifestForOrchContract -export const getManifestForFastUSDC = ( - { restoreRef }, - { installKeys, options }, -) => { - return { - /** @type {BootstrapManifest} */ - manifest: { [startOrchContract.name]: permit }, - installations: { [contractName]: restoreRef(installKeys[contractName]) }, - options, - }; -}; +// XXX hm... we need to preserve the function name. +export const getManifestForFastUSDC = (u, d) => + makeGetManifest(startFastUSDC, permit, meta.name)(u, d); diff --git a/packages/fast-usdc/src/orch.start.js b/packages/fast-usdc/src/orch.start.js new file mode 100644 index 00000000000..a6669d6899d --- /dev/null +++ b/packages/fast-usdc/src/orch.start.js @@ -0,0 +1,356 @@ +import { deeplyFulfilledObject, makeTracer, objectMap } from '@agoric/internal'; +import { Fail } from '@endo/errors'; +import { E } from '@endo/far'; +import { makeMarshal } from '@endo/marshal'; +import { M, mustMatch } from '@endo/patterns'; +import { fromExternalConfig } from './utils/config-marshal.js'; + +/** + * @import {CopyRecord} from '@endo/pass-style'; + * @import {TypedPattern} from '@agoric/internal'; + * @import {ManifestBundleRef} from '@agoric/deploy-script-support/src/externalTypes.js' + * @import {OrchestrationPowers} from '@agoric/orchestration'; + * @import {ContractStartFunction, Instance, StartedInstanceKit} from '@agoric/zoe/src/zoeService/utils' + * @import {DepositFacet} from '@agoric/ertp/src/types.js' + * @import {Board} from '@agoric/vats' + * @import {BootstrapManifest} from '@agoric/vats/src/core/lib-boot.js' + * @import {BootstrapManifestPermit} from '@agoric/vats/src/core/lib-boot.js'; + * @import {LegibleCapData} from './utils/config-marshal.js' + */ + +const { entries, fromEntries, keys, values } = Object; // XXX move up + +const trace = makeTracer(`ORCH-Start`, true); + +/** + * XXX Shouldn't the bridge or board vat handle this? + * + * @param {string} path + * @param {{ + * chainStorage: ERef; + * board: ERef; + * }} io + */ +const makePublishingStorageKit = async (path, { chainStorage, board }) => { + const storageNode = await E(chainStorage).makeChildNode(path); + + const marshaller = await E(board).getPublishingMarshaller(); + return { storageNode, marshaller }; +}; + +const BOARD_AUX = 'boardAux'; +const marshalData = makeMarshal(_val => Fail`data only`); +/** + * @param {Brand} brand + * @param {Pick} powers + */ +const publishDisplayInfo = async (brand, { board, chainStorage }) => { + // chainStorage type includes undefined, which doesn't apply here. + // @ts-expect-error UNTIL https://github.com/Agoric/agoric-sdk/issues/8247 + const boardAux = E(chainStorage).makeChildNode(BOARD_AUX); + const [id, displayInfo, allegedName] = await Promise.all([ + E(board).getId(brand), + E(brand).getDisplayInfo(), + E(brand).getAllegedName(), + ]); + const node = E(boardAux).makeChildNode(id); + const aux = marshalData.toCapData(harden({ allegedName, displayInfo })); + await E(node).setValue(JSON.stringify(aux)); +}; + +/** + * @param {string} role + * @param {ERef} namesByAddress + * @param {Record} nameToAddress + */ +const makeAdminRole = (role, namesByAddress, nameToAddress) => { + const lookup = async () => { + trace('look up deposit facets for', role); + return deeplyFulfilledObject( + objectMap(nameToAddress, async address => { + /** @type {DepositFacet} */ + const depositFacet = await E(namesByAddress).lookup( + address, + 'depositFacet', + ); + return depositFacet; + }), + ); + }; + const lookupP = lookup(); + + return harden({ + lookup: () => lookupP, + /** @param {(addr: string) => Promise} makeInvitation */ + send: async makeInvitation => { + const oracleDepositFacets = await lookupP; + await Promise.all( + entries(oracleDepositFacets).map(async ([name, depositFacet]) => { + const address = nameToAddress[name]; + trace('making invitation for', role, name, address); + const toWatch = await makeInvitation(address); + + const amt = await E(depositFacet).receive(toWatch); + trace('sent', amt, 'to', role, name); + }), + ); + }, + }); +}; + +/** + * @template {{}} T + * @param {T} obj + * @param {(entry: [k: K, v: T[K]], index: number, es: [PropertyKey, unknown][]) => Partial} pred + * @returns {Partial} + */ +const objectFilter = (obj, pred) => { + /** @type {Partial} */ + // @ts-expect-error pred type too narrow + const found = harden(fromEntries(entries(obj).filter(pred))); + return found; +}; + +/** + * @template {PermitG} P + * @param {BootstrapPowers['consume']['agoricNames']} agoricNames + * @param {P} permitG + */ +export const permittedIssuers = async (agoricNames, permitG) => { + const permittedKeys = keys(permitG?.issuer?.consume || {}); + const agoricIssuers = await E(E(agoricNames).lookup('issuer')).entries(); + /** @type {Record} */ + // @ts-expect-error by construction + const issuerKeywordRecord = fromEntries( + agoricIssuers.filter(([n, _v]) => permittedKeys.includes(n)), + ); + return issuerKeywordRecord; +}; + +/** + * @template {string} CN contract name + * @template {ContractStartFunction} SF typeof start + * @template {CopyRecord} CFG + * @typedef {ContractMeta & {name: CN} & { + * adminRoles?: Record['creatorFacet']>, + * deployConfigShape?: TypedPattern, + * }} ContractMetaG + */ + +/** + * @template {ContractStartFunction} SF typeof start + * @typedef {StartedInstanceKit & { + * label: string, + * privateArgs: Parameters[1]; + * }} UpgradeKit + * + */ + +/** + * @typedef {BootstrapManifest & + * { issuer: BootstrapManifest} & + * { brand: BootstrapManifest } + * } PermitG generic permit constraints + */ + +/** + * @template {string} CN contract name + * @template {ContractStartFn} SF typeof start + * @template {PermitG} P permit + * @typedef { PromiseSpaceOf>> & { + * installation: PromiseSpaceOf>>; + * instance: PromiseSpaceOf>>; + * issuer: PromiseSpaceOf>; + * brand: PromiseSpaceOf>; + * }} CorePowersG + */ + +/** + * @template {ContractStartFn} SF typeof start + * @template {CopyRecord} CFG + * @typedef {(op: OrchestrationPowers, m: Marshaller, cfg: CFG) => Parameters[1]} MakePrivateArgs + */ + +/** + * @throws if admin role smart wallets are not yet provisioned + * + * @template {string} CN contract name + * @template {ContractStartFn} SF typeof start + * @template {CopyRecord} CFG + * @template {PermitG} P permit + * @param {ContractMetaG} metaG generic metadata + * @param {P} permitG + * @param {MakePrivateArgs} makePrivateArgs + * @param {CorePowersG & BootstrapPowers} powers + * @param {{ options: LegibleCapData }} configStruct + */ +export const startOrchContract = async ( + metaG, + permitG, + makePrivateArgs, + { + produce, + consume, + issuer: { produce: produceIssuer }, + brand: { produce: produceBrand }, + installation: { + consume: { [metaG.name]: installation }, + }, + instance: { + produce: { [metaG.name]: produceInstance }, + }, + }, + configStruct, +) => { + trace('startOrchContract'); + + const { agoricNames } = consume; + const issuerKeywordRecord = await permittedIssuers(agoricNames, permitG); + + const xVatContext = await E(E(agoricNames).lookup('brand')).entries(); + const config = fromExternalConfig( + configStruct.options, + xVatContext, + metaG.deployConfigShape, + ); + const { terms } = config; + trace('using terms', terms); + + const adminRoles = objectMap(metaG?.adminRoles || {}, (_method, role) => { + const nameToAddress = config[role]; + mustMatch(nameToAddress, M.recordOf(M.string(), M.string())); + return makeAdminRole( + /** @type {string} */ (role), // XXX tsc gets confused? + consume.namesByAddress, + nameToAddress, + ); + }); + + await Promise.all(values(adminRoles).map(r => r.lookup())); + + /** @type {{ chainStorage: Promise}} */ + // @ts-expect-error Promise case is vestigial + const { chainStorage, board } = consume; + const { storageNode, marshaller } = await makePublishingStorageKit( + metaG.name, + { board, chainStorage }, + ); + + const { + chainTimerService: timerService, + localchain, + cosmosInterchainService, + } = consume; + const orchestrationPowers = await deeplyFulfilledObject( + harden({ + localchain, + orchestrationService: cosmosInterchainService, + storageNode, + timerService, + agoricNames, + }), + ); + const privateArgs = await makePrivateArgs( + orchestrationPowers, + marshaller, + config, + ); + + const { startUpgradable, zoe } = consume; + const kit = await E(startUpgradable)({ + label: metaG.name, + installation, + issuerKeywordRecord, + terms, + privateArgs, + }); + const { instance, creatorFacet } = kit; + /** @type {UpgradeKit} */ + const fullKit = harden({ ...kit, privateArgs }); + // @ts-expect-error XXX tsc gets confused? + produce[`${metaG.name}Kit`].resolve(fullKit); + + const newIssuerNames = keys(permitG?.issuer?.produce || {}).filter( + n => permitG?.brand?.produce?.[n], + ); + if (newIssuerNames.length > 0) { + const { issuers, brands } = await E(zoe).getTerms(instance); + for (const name of newIssuerNames) { + console.log('new well-known Issuer, Brand:', name); + produceIssuer[name].reset(); + produceIssuer[name].resolve(issuers[name]); + produceBrand[name].reset(); + produceBrand[name].resolve(brands[name]); + await publishDisplayInfo(brands[name], { board, chainStorage }); + } + } + + for (const [role, method] of entries(metaG.adminRoles || {})) { + await adminRoles[role].send(addr => E(creatorFacet)[method](addr)); + } + + produceInstance.reset(); + produceInstance.resolve(instance); + + trace('startOrchContract done', instance); + return { config, kit: fullKit }; +}; +harden(startOrchContract); + +/** @satisfies {BootstrapManifestPermit} */ +export const orchPermit = /** @type {const} */ ({ + localchain: true, + cosmosInterchainService: true, + chainStorage: true, + chainTimerService: true, + agoricNames: true, + + // for publishing Brands and other remote object references + board: true, + + // limited distribution durin MN2: contract installation + startUpgradable: true, + zoe: true, // only getTerms() is needed. XXX should be split? +}); +harden(orchPermit); + +/** + * to find deposit facets for admin invitations + * + * @satisfies {BootstrapManifestPermit} + */ +export const adminPermit = /** @type {const} */ ({ + namesByAddress: true, +}); +harden(adminPermit); + +/** + * @template {CopyRecord} CFG + * @template {PermitG} P permit + * + * @param {Function} startFn + * @param {P} permit + * @param {string} contractName + */ +export const makeGetManifest = (startFn, permit, contractName) => { + /** + * @param {{ + * restoreRef: (b: ERef) => Promise; + * }} utils + * @param {{ + * installKeys: { fastUsdc: ERef }; + * options: LegibleCapData; + * }} data + */ + const getManifestForFastOrch = ({ restoreRef }, { installKeys, options }) => { + return { + /** @satisfies {BootstrapManifest} */ + manifest: { [startFn.name]: permit }, + installations: { [contractName]: restoreRef(installKeys[contractName]) }, + options, + }; + }; + harden(getManifestForFastOrch); + + return getManifestForFastOrch; +}; From 402792dfcd053e37d32eae0ad97b01d22f78f30d Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Tue, 17 Dec 2024 02:24:58 -0600 Subject: [PATCH 19/21] WIP(orch.start): fix generic issuer handling --- .../fast-usdc/src/fast-usdc.contract.meta.js | 4 ++-- packages/fast-usdc/src/orch.start.js | 20 ++++++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/fast-usdc/src/fast-usdc.contract.meta.js b/packages/fast-usdc/src/fast-usdc.contract.meta.js index 47e59658f6d..7c3ca891586 100644 --- a/packages/fast-usdc/src/fast-usdc.contract.meta.js +++ b/packages/fast-usdc/src/fast-usdc.contract.meta.js @@ -68,7 +68,7 @@ export const permit = /** @type {const} */ ({ consume: { ...orchPermit, ...adminPermit }, instance: { produce: { [meta.name]: true } }, installation: { consume: { [meta.name]: true } }, - issuer: { produce: { FastLP: true }, consume: { USDC: true } }, - brand: { produce: { FastLP: true } }, + issuer: { produce: { FastLP: 'PoolShares' }, consume: { USDC: true } }, + brand: { produce: { FastLP: 'PoolShares' } }, }); harden(permit); diff --git a/packages/fast-usdc/src/orch.start.js b/packages/fast-usdc/src/orch.start.js index a6669d6899d..4e8c5517be6 100644 --- a/packages/fast-usdc/src/orch.start.js +++ b/packages/fast-usdc/src/orch.start.js @@ -12,7 +12,7 @@ import { fromExternalConfig } from './utils/config-marshal.js'; * @import {OrchestrationPowers} from '@agoric/orchestration'; * @import {ContractStartFunction, Instance, StartedInstanceKit} from '@agoric/zoe/src/zoeService/utils' * @import {DepositFacet} from '@agoric/ertp/src/types.js' - * @import {Board} from '@agoric/vats' + * @import {Board, NameHub} from '@agoric/vats' * @import {BootstrapManifest} from '@agoric/vats/src/core/lib-boot.js' * @import {BootstrapManifestPermit} from '@agoric/vats/src/core/lib-boot.js'; * @import {LegibleCapData} from './utils/config-marshal.js' @@ -207,10 +207,12 @@ export const startOrchContract = async ( const { agoricNames } = consume; const issuerKeywordRecord = await permittedIssuers(agoricNames, permitG); - const xVatContext = await E(E(agoricNames).lookup('brand')).entries(); + /** @type {Promise} */ + const brandHub = E(agoricNames).lookup('brand'); + const xVatEntries = await E(brandHub).entries(); const config = fromExternalConfig( configStruct.options, - xVatContext, + fromEntries(xVatEntries), metaG.deployConfigShape, ); const { terms } = config; @@ -274,14 +276,18 @@ export const startOrchContract = async ( n => permitG?.brand?.produce?.[n], ); if (newIssuerNames.length > 0) { + const nameToKeyword = permitG.issuer.produce; const { issuers, brands } = await E(zoe).getTerms(instance); for (const name of newIssuerNames) { - console.log('new well-known Issuer, Brand:', name); + const keyword = nameToKeyword[name]; + keyword in issuers || + Fail`${name} not in contract issuers: ${keys(issuers)}`; + console.log('new well-known Issuer, Brand:', name, 'from', keyword); produceIssuer[name].reset(); - produceIssuer[name].resolve(issuers[name]); + produceIssuer[name].resolve(issuers[keyword]); produceBrand[name].reset(); - produceBrand[name].resolve(brands[name]); - await publishDisplayInfo(brands[name], { board, chainStorage }); + produceBrand[name].resolve(brands[keyword]); + await publishDisplayInfo(brands[keyword], { board, chainStorage }); } } From 31d89096858104d945e7ba28e1d85321db12123b Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Tue, 17 Dec 2024 02:26:53 -0600 Subject: [PATCH 20/21] objectFilter is unused --- packages/fast-usdc/src/orch.start.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/packages/fast-usdc/src/orch.start.js b/packages/fast-usdc/src/orch.start.js index 4e8c5517be6..27d34403e3a 100644 --- a/packages/fast-usdc/src/orch.start.js +++ b/packages/fast-usdc/src/orch.start.js @@ -98,19 +98,6 @@ const makeAdminRole = (role, namesByAddress, nameToAddress) => { }); }; -/** - * @template {{}} T - * @param {T} obj - * @param {(entry: [k: K, v: T[K]], index: number, es: [PropertyKey, unknown][]) => Partial} pred - * @returns {Partial} - */ -const objectFilter = (obj, pred) => { - /** @type {Partial} */ - // @ts-expect-error pred type too narrow - const found = harden(fromEntries(entries(obj).filter(pred))); - return found; -}; - /** * @template {PermitG} P * @param {BootstrapPowers['consume']['agoricNames']} agoricNames From 5d5d1ebf47a12e45229c123a6f4512a4bde849d7 Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Tue, 17 Dec 2024 02:28:01 -0600 Subject: [PATCH 21/21] fixup! WIP: more generic start --- packages/fast-usdc/src/orch.start.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/fast-usdc/src/orch.start.js b/packages/fast-usdc/src/orch.start.js index 27d34403e3a..6711c772c38 100644 --- a/packages/fast-usdc/src/orch.start.js +++ b/packages/fast-usdc/src/orch.start.js @@ -60,7 +60,7 @@ const publishDisplayInfo = async (brand, { board, chainStorage }) => { /** * @param {string} role - * @param {ERef} namesByAddress + * @param {BootstrapPowers['consume']['namesByAddress']} namesByAddress * @param {Record} nameToAddress */ const makeAdminRole = (role, namesByAddress, nameToAddress) => {