diff --git a/packages/orchestration/package.json b/packages/orchestration/package.json index cd307b5e38e..e8bfeb7c7f5 100644 --- a/packages/orchestration/package.json +++ b/packages/orchestration/package.json @@ -92,6 +92,6 @@ "access": "public" }, "typeCoverage": { - "atLeast": 98.04 + "atLeast": 98.09 } } diff --git a/packages/orchestration/src/examples/sendAnywhere.contract.js b/packages/orchestration/src/examples/sendAnywhere.contract.js index ca0b4fb5909..ea5269e7129 100644 --- a/packages/orchestration/src/examples/sendAnywhere.contract.js +++ b/packages/orchestration/src/examples/sendAnywhere.contract.js @@ -13,8 +13,9 @@ import { orchestrationFns } from './sendAnywhereFlows.js'; * @import {TimerService} from '@agoric/time'; * @import {LocalChain} from '@agoric/vats/src/localchain.js'; * @import {NameHub} from '@agoric/vats'; - * @import {Remote} from '@agoric/vow'; + * @import {Remote, Vow} from '@agoric/vow'; * @import {Zone} from '@agoric/zone'; + * @import {VBankAssetDetail} from '@agoric/vats/tools/board-utils.js'; * @import {CosmosChainInfo, IBCConnectionInfo} from '../cosmos-api'; * @import {CosmosInterchainService} from '../exos/cosmos-interchain-service.js'; * @import {OrchestrationTools} from '../utils/start-helper.js'; @@ -60,6 +61,7 @@ const contract = async ( ); // TODO should be a provided helper + /** @type {(brand: Brand) => Vow} */ const findBrandInVBank = vowTools.retriable( zone, 'findBrandInVBank', diff --git a/packages/orchestration/src/examples/sendAnywhereFlows.js b/packages/orchestration/src/examples/sendAnywhereFlows.js index c6d34c31912..db9405d5efc 100644 --- a/packages/orchestration/src/examples/sendAnywhereFlows.js +++ b/packages/orchestration/src/examples/sendAnywhereFlows.js @@ -1,7 +1,10 @@ import { M, mustMatch } from '@endo/patterns'; /** - * @import {Orchestrator, OrchestrationAccount} from '../types.js'; + * @import {GuestOf} from '@agoric/async-flow'; + * @import {VBankAssetDetail} from '@agoric/vats/tools/board-utils.js'; + * @import {ZoeTools} from '../utils/zoe-tools.js'; + * @import {Orchestrator, OrchestrationAccount, LocalAccountMethods, OrchestrationAccountI} from '../types.js'; */ const { entries } = Object; @@ -13,9 +16,9 @@ export const orchestrationFns = harden({ /** * @param {Orchestrator} orch * @param {object} ctx - * @param {{ account: OrchestrationAccount }} ctx.contractState - * @param {any} ctx.localTransfer - * @param {any} ctx.findBrandInVBank + * @param {{ account?: OrchestrationAccountI & LocalAccountMethods }} ctx.contractState + * @param {GuestOf} ctx.localTransfer + * @param {(brand: Brand) => Promise} ctx.findBrandInVBank * @param {ZCFSeat} seat * @param {{ chainName: string; destAddr: string }} offerArgs */ diff --git a/packages/orchestration/src/exos/cosmos-orchestration-account.js b/packages/orchestration/src/exos/cosmos-orchestration-account.js index bc86158ba54..50293b4253a 100644 --- a/packages/orchestration/src/exos/cosmos-orchestration-account.js +++ b/packages/orchestration/src/exos/cosmos-orchestration-account.js @@ -1,7 +1,4 @@ /** @file Use-object for the owner of a staking account */ -import { Fail } from '@endo/errors'; -import { decodeBase64 } from '@endo/base64'; -import { E } from '@endo/far'; import { toRequestQueryJson } from '@agoric/cosmic-proto'; import { QueryBalanceRequest, @@ -22,12 +19,14 @@ import { makeTracer } from '@agoric/internal'; import { Shape as NetworkShape } from '@agoric/network'; import { M } from '@agoric/vat-data'; import { VowShape } from '@agoric/vow'; +import { decodeBase64 } from '@endo/base64'; +import { Fail } from '@endo/errors'; +import { E } from '@endo/far'; import { AmountArgShape, ChainAddressShape, - ChainAmountShape, - CoinShape, DelegationShape, + DenomAmountShape, } from '../typeGuards.js'; import { maxClockSkew, tryDecodeResponse } from '../utils/cosmos.js'; import { orchestrationAccountMethods } from '../utils/orchestrationAccount.js'; @@ -78,9 +77,9 @@ export const IcaAccountHolderI = M.interface('IcaAccountHolder', { AmountArgShape, ).returns(VowShape), withdrawReward: M.call(ChainAddressShape).returns( - Vow$(M.arrayOf(ChainAmountShape)), + Vow$(M.arrayOf(DenomAmountShape)), ), - withdrawRewards: M.call().returns(Vow$(M.arrayOf(ChainAmountShape))), + withdrawRewards: M.call().returns(Vow$(M.arrayOf(DenomAmountShape))), undelegate: M.call(M.arrayOf(DelegationShape)).returns(VowShape), }); @@ -130,7 +129,7 @@ export const prepareCosmosOrchestrationAccountKit = ( withdrawRewardWatcher: M.interface('withdrawRewardWatcher', { onFulfilled: M.call(M.string()) .optional(M.arrayOf(M.undefined())) // empty context - .returns(M.arrayOf(CoinShape)), + .returns(M.arrayOf(DenomAmountShape)), }), holder: IcaAccountHolderI, invitationMakers: M.interface('invitationMakers', { diff --git a/packages/orchestration/src/exos/local-orchestration-account.js b/packages/orchestration/src/exos/local-orchestration-account.js index 4159912c91d..2a21a905368 100644 --- a/packages/orchestration/src/exos/local-orchestration-account.js +++ b/packages/orchestration/src/exos/local-orchestration-account.js @@ -8,7 +8,6 @@ import { VowShape } from '@agoric/vow'; import { E } from '@endo/far'; import { ChainAddressShape, - ChainAmountShape, DenomAmountShape, DenomShape, IBCTransferOptionsShape, @@ -105,7 +104,7 @@ export const prepareLocalOrchestrationAccountKit = ( .optional({ destination: ChainAddressShape, opts: M.or(M.undefined(), IBCTransferOptionsShape), - amount: ChainAmountShape, + amount: DenomAmountShape, }) .returns(Vow$(M.record())), }), diff --git a/packages/orchestration/src/facade.js b/packages/orchestration/src/facade.js index 709b8d26e65..f4cfa08aeef 100644 --- a/packages/orchestration/src/facade.js +++ b/packages/orchestration/src/facade.js @@ -3,7 +3,7 @@ import { assertAllDefined } from '@agoric/internal'; /** - * @import {AsyncFlowTools, GuestInterface, HostArgs} from '@agoric/async-flow'; + * @import {AsyncFlowTools, GuestInterface, HostArgs, HostOf} from '@agoric/async-flow'; * @import {Zone} from '@agoric/zone'; * @import {Vow, VowTools} from '@agoric/vow'; * @import {TimerService} from '@agoric/time'; @@ -14,6 +14,19 @@ import { assertAllDefined } from '@agoric/internal'; * @import {Chain, ChainInfo, CosmosChainInfo, IBCConnectionInfo, OrchestrationAccount, Orchestrator} from './types.js'; */ +/** + * For a given guest passed to orchestrate(), return the host-side form. + * + * @template {(orc: Orchestrator, ctx: any, ...args: any[]) => Promise} GF + * @typedef {GF extends ( + * orc: Orchestrator, + * ctx: any, + * ...args: infer GA + * ) => Promise + * ? (...args: HostArgs) => Vow + * : never} HostForGuest + */ + /** * @param {{ * zone: Zone; @@ -91,15 +104,27 @@ export const makeOrchestrationFacade = ({ * * NOTE multiple calls to this with the same guestFn name will fail * - * @param {{ [durableName: string]: (...args: any[]) => any }} guestFns - * @param {any} hostCtx + * @template HC - host context + * @template {{ + * [durableName: string]: ( + * orc: Orchestrator, + * ctx: GuestInterface, + * ...args: any[] + * ) => Promise; + * }} GFM + * guest fn map + * @param {GFM} guestFns + * @param {HC} hostCtx + * @returns {{ [N in keyof GFM]: HostForGuest }} */ const orchestrateAll = (guestFns, hostCtx) => - Object.fromEntries( - Object.entries(guestFns).map(([name, guestFn]) => [ - name, - orchestrate(name, hostCtx, guestFn), - ]), + /** @type {{ [N in keyof GFM]: HostForGuest }} */ ( + Object.fromEntries( + Object.entries(guestFns).map(([name, guestFn]) => [ + name, + orchestrate(name, hostCtx, guestFn), + ]), + ) ); return harden({ diff --git a/packages/orchestration/src/typeGuards.js b/packages/orchestration/src/typeGuards.js index 056a677c397..800b2ced1ca 100644 --- a/packages/orchestration/src/typeGuards.js +++ b/packages/orchestration/src/typeGuards.js @@ -35,13 +35,6 @@ export const Proto3Shape = { value: M.string(), }; -// XXX same as ChainAmountShape and DenomAmount type -export const CoinShape = { value: M.bigint(), denom: M.string() }; - -export const ChainAmountShape = harden({ denom: M.string(), value: M.nat() }); - -export const AmountArgShape = M.or(AmountShape, ChainAmountShape); - // FIXME missing `delegatorAddress` from the type /** @type {TypedPattern} */ export const DelegationShape = harden({ @@ -111,6 +104,8 @@ export const BrandInfoShape = M.any(); /** @type {TypedPattern} */ export const DenomAmountShape = { denom: DenomShape, value: M.bigint() }; +export const AmountArgShape = M.or(AmountShape, DenomAmountShape); + /** @see {Chain} */ export const ChainFacadeI = M.interface('ChainFacade', { getChainInfo: M.call().returns(VowShape), diff --git a/packages/orchestration/src/utils/orchestrationAccount.js b/packages/orchestration/src/utils/orchestrationAccount.js index 67045a59114..34fa69de696 100644 --- a/packages/orchestration/src/utils/orchestrationAccount.js +++ b/packages/orchestration/src/utils/orchestrationAccount.js @@ -2,7 +2,11 @@ import { M } from '@endo/patterns'; import { Shape as NetworkShape } from '@agoric/network'; import { VowShape } from '@agoric/vow'; import { TopicsRecordShape } from '@agoric/zoe/src/contractSupport/topics.js'; -import { AmountArgShape, ChainAddressShape, CoinShape } from '../typeGuards.js'; +import { + AmountArgShape, + ChainAddressShape, + DenomAmountShape, +} from '../typeGuards.js'; /** @import {OrchestrationAccountI} from '../orchestration-api.js'; */ @@ -11,8 +15,8 @@ const { Vow$ } = NetworkShape; // TODO #9611 /** @see {OrchestrationAccountI} */ export const orchestrationAccountMethods = { getAddress: M.call().returns(ChainAddressShape), - getBalance: M.call(M.any()).returns(Vow$(CoinShape)), - getBalances: M.call().returns(Vow$(M.arrayOf(CoinShape))), + getBalance: M.call(M.any()).returns(Vow$(DenomAmountShape)), + getBalances: M.call().returns(Vow$(M.arrayOf(DenomAmountShape))), send: M.call(ChainAddressShape, AmountArgShape).returns(VowShape), transfer: M.call(AmountArgShape, ChainAddressShape) .optional(M.record()) diff --git a/packages/orchestration/src/utils/zoe-tools.js b/packages/orchestration/src/utils/zoe-tools.js index 4fe36052894..32b7632bec0 100644 --- a/packages/orchestration/src/utils/zoe-tools.js +++ b/packages/orchestration/src/utils/zoe-tools.js @@ -77,3 +77,4 @@ export const makeZoeTools = (zone, { zcf, vowTools }) => { localTransfer, }); }; +/** @typedef {ReturnType} ZoeTools */