diff --git a/packages/orchestration/src/exos/cosmos-orchestration-account.js b/packages/orchestration/src/exos/cosmos-orchestration-account.js index 431b8cb1d710..7ee95f003cb9 100644 --- a/packages/orchestration/src/exos/cosmos-orchestration-account.js +++ b/packages/orchestration/src/exos/cosmos-orchestration-account.js @@ -163,6 +163,7 @@ export const prepareCosmosOrchestrationAccountKit = ( // @ts-expect-error XXX Patterns const topicKit = makeRecorderKit(storageNode, PUBLIC_TOPICS.account[1]); // TODO determine what goes in vstorage https://github.com/Agoric/agoric-sdk/issues/9066 + // TODO consider making this opt-out void E(topicKit.recorder).write(''); return { chainAddress, bondDenom, topicKit, ...rest }; diff --git a/packages/orchestration/src/exos/local-chain-facade.js b/packages/orchestration/src/exos/local-chain-facade.js index ddada8f15f4a..cb3d0e850a06 100644 --- a/packages/orchestration/src/exos/local-chain-facade.js +++ b/packages/orchestration/src/exos/local-chain-facade.js @@ -2,6 +2,7 @@ import { E } from '@endo/far'; import { M } from '@endo/patterns'; import { pickFacet } from '@agoric/vat-data'; +import { VowShape } from '@agoric/vow'; import { ChainFacadeI } from '../typeGuards.js'; @@ -36,7 +37,7 @@ const prepareLocalChainFacadeKit = ( { makeLocalOrchestrationAccountKit, localchain, - storageNode, + storageNode, // consider making an accounts childNode TODO #9066 vowTools: { allVows, watch }, }, ) => @@ -44,9 +45,14 @@ const prepareLocalChainFacadeKit = ( 'LocalChainFacade', { public: ChainFacadeI, - makeAccountWatcher: M.interface('undelegateWatcher', { + makeAccountWatcher: M.interface('makeAccountWatcher', { onFulfilled: M.call([M.remotable('LCA Account'), M.string()]) .optional(M.arrayOf(M.undefined())) // empty context + .returns(VowShape), + }), + makeChildNodeWatcher: M.interface('makeChildNodeWatcher', { + onFulfilled: M.call(M.remotable()) + .optional({ account: M.remotable(), address: M.string() }) // empty context .returns(M.remotable()), }), }, @@ -82,6 +88,22 @@ const prepareLocalChainFacadeKit = ( * @param {[LocalChainAccount, ChainAddress['value']]} results */ onFulfilled([account, address]) { + return watch( + E(storageNode).makeChildNode(address), + this.facets.makeChildNodeWatcher, + { account, address }, + ); + }, + }, + makeChildNodeWatcher: { + /** + * @param {Remote} childNode + * @param {{ + * account: LocalChainAccount; + * address: ChainAddress['value']; + * }} ctx + */ + onFulfilled(childNode, { account, address }) { const { localChainInfo } = this.state; const { holder } = makeLocalOrchestrationAccountKit({ account, @@ -91,7 +113,7 @@ const prepareLocalChainFacadeKit = ( chainId: localChainInfo.chainId, }), // FIXME storage path https://github.com/Agoric/agoric-sdk/issues/9066 - storageNode, + storageNode: childNode, }); return holder; }, diff --git a/packages/orchestration/src/exos/local-orchestration-account.js b/packages/orchestration/src/exos/local-orchestration-account.js index 94e8d3a1368f..744db9cb2e29 100644 --- a/packages/orchestration/src/exos/local-orchestration-account.js +++ b/packages/orchestration/src/exos/local-orchestration-account.js @@ -140,6 +140,9 @@ export const prepareLocalOrchestrationAccountKit = ( // must be the fully synchronous maker because the kit is held in durable state // @ts-expect-error XXX Patterns const topicKit = makeRecorderKit(storageNode, PUBLIC_TOPICS.account[1]); + // TODO determine what goes in vstorage https://github.com/Agoric/agoric-sdk/issues/9066 + // TODO consider making this opt-out + void E(topicKit.recorder).write(''); return { account, address, topicKit }; }, diff --git a/packages/orchestration/src/exos/remote-chain-facade.js b/packages/orchestration/src/exos/remote-chain-facade.js index 3b87240c39d0..7019da68c664 100644 --- a/packages/orchestration/src/exos/remote-chain-facade.js +++ b/packages/orchestration/src/exos/remote-chain-facade.js @@ -4,7 +4,7 @@ import { E } from '@endo/far'; import { M } from '@endo/patterns'; import { pickFacet } from '@agoric/vat-data'; import { VowShape } from '@agoric/vow'; -import { ChainFacadeI } from '../typeGuards.js'; +import { ChainAddressShape, ChainFacadeI } from '../typeGuards.js'; /** * @import {Zone} from '@agoric/base-zone'; @@ -43,7 +43,7 @@ const prepareRemoteChainFacadeKit = ( { makeCosmosOrchestrationAccount, orchestration, - storageNode, + storageNode, // consider making an accounts childNode TODO #9066 timer, vowTools: { asVow, watch }, }, @@ -54,12 +54,20 @@ const prepareRemoteChainFacadeKit = ( public: ChainFacadeI, makeAccountWatcher: M.interface('makeAccountWatcher', { onFulfilled: M.call(M.remotable()) - .optional(M.string()) + .optional(M.arrayOf(M.undefined())) // empty context .returns(VowShape), }), - getAddressWatcher: M.interface('makeAccountWatcher', { + getAddressWatcher: M.interface('getAddressWatcher', { onFulfilled: M.call(M.record()) - .optional({ stakingDenom: M.string(), account: M.remotable() }) + .optional(M.remotable()) + .returns(VowShape), + }), + makeChildNodeWatcher: M.interface('makeChildNodeWatcher', { + onFulfilled: M.call(M.remotable()) + .optional({ + account: M.remotable(), + chainAddress: ChainAddressShape, + }) .returns(M.remotable()), }), }, @@ -95,32 +103,55 @@ const prepareRemoteChainFacadeKit = ( connectionInfo.counterparty.connection_id, ), this.facets.makeAccountWatcher, - stakingDenom, ); }); }, }, makeAccountWatcher: { /** + * XXX Pipeline vows allVows and E + * * @param {IcaAccount} account - * @param {Denom} stakingDenom */ - onFulfilled(account, stakingDenom) { - return watch(E(account).getAddress(), this.facets.getAddressWatcher, { - stakingDenom, + onFulfilled(account) { + return watch( + E(account).getAddress(), + this.facets.getAddressWatcher, account, - }); + ); }, }, getAddressWatcher: { /** * @param {ChainAddress} chainAddress - * @param {{ stakingDenom: Denom; account: IcaAccount }} ctx + * @param {IcaAccount} account + */ + onFulfilled(chainAddress, account) { + return watch( + E(storageNode).makeChildNode(chainAddress.value), + this.facets.makeChildNodeWatcher, + { account, chainAddress }, + ); + }, + }, + makeChildNodeWatcher: { + /** + * @param {Remote} childNode + * @param {{ + * account: IcaAccount; + * chainAddress: ChainAddress; + * }} ctx */ - onFulfilled(chainAddress, { account, stakingDenom }) { + onFulfilled(childNode, { account, chainAddress }) { + const { remoteChainInfo } = this.state; + const stakingDenom = remoteChainInfo.stakingTokens?.[0]?.denom; + if (!stakingDenom) { + throw Fail`chain info lacks staking denom`; + } return makeCosmosOrchestrationAccount(chainAddress, stakingDenom, { account, - storageNode, + // FIXME storage path https://github.com/Agoric/agoric-sdk/issues/9066 + storageNode: childNode, // FIXME provide real ICQ connection // FIXME make Query Connection available via chain, not orchestrationAccount icqConnection: anyVal,