From 904987109c5ad39be2cd267b7529c05befb2063e Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Tue, 4 Jun 2024 22:07:17 -0400 Subject: [PATCH] feat(orchestration): ChainAccountKit returns unwrapped vows - refs: #9449 --- .../orchestration/src/exos/chainAccountKit.js | 42 +++++++++++++------ packages/orchestration/src/service.js | 2 +- packages/orchestration/test/service.test.ts | 35 ++++++++++++---- 3 files changed, 57 insertions(+), 22 deletions(-) diff --git a/packages/orchestration/src/exos/chainAccountKit.js b/packages/orchestration/src/exos/chainAccountKit.js index 35d20c5583d3..d47ca4cc678d 100644 --- a/packages/orchestration/src/exos/chainAccountKit.js +++ b/packages/orchestration/src/exos/chainAccountKit.js @@ -2,7 +2,7 @@ import { NonNullish } from '@agoric/assert'; import { PurseShape } from '@agoric/ertp'; import { makeTracer } from '@agoric/internal'; -import { V as E } from '@agoric/vow/vat.js'; +import { E } from '@endo/far'; import { M } from '@endo/patterns'; import { ChainAddressShape, @@ -15,7 +15,7 @@ import { makeTxPacket, parseTxPacket } from '../utils/packet.js'; /** * @import {Zone} from '@agoric/base-zone'; * @import {Connection, Port} from '@agoric/network'; - * @import {Remote} from '@agoric/vow'; + * @import {Remote, VowTools} from '@agoric/vow'; * @import {AnyJson} from '@agoric/cosmic-proto'; * @import {TxBody} from '@agoric/cosmic-proto/cosmos/tx/v1beta1/tx.js'; * @import {LocalIbcAddress, RemoteIbcAddress} from '@agoric/vats/tools/ibc-utils.js'; @@ -55,11 +55,22 @@ export const ChainAccountI = M.interface('ChainAccount', { * }} State */ -/** @param {Zone} zone */ -export const prepareChainAccountKit = zone => +/** + * @param {Zone} zone + * @param {VowTools} vowTools + */ +export const prepareChainAccountKit = (zone, { watch, when }) => zone.exoClassKit( 'ChainAccountKit', - { account: ChainAccountI, connectionHandler: ConnectionHandlerI }, + { + account: ChainAccountI, + connectionHandler: ConnectionHandlerI, + handleExecuteEncodedTxWatcher: M.interface('HandleQueryWatcher', { + onFulfilled: M.call(M.string()) + .optional(M.arrayOf(M.undefined())) // does not need watcherContext + .returns(M.string()), + }), + }, /** * @param {string} chainId * @param {Port} port @@ -76,6 +87,12 @@ export const prepareChainAccountKit = zone => localAddress: undefined, }), { + handleExecuteEncodedTxWatcher: { + /** @param {string} ack */ + onFulfilled(ack) { + return parseTxPacket(ack); + }, + }, account: { /** @returns {ChainAddress} */ getAddress() { @@ -123,20 +140,21 @@ export const prepareChainAccountKit = zone => executeEncodedTx(msgs, opts) { const { connection } = this.state; if (!connection) throw Fail`connection not available`; - return E.when( - E(connection).send(makeTxPacket(msgs, opts)), - // if parseTxPacket cannot find a `result` key, it throws - ack => parseTxPacket(ack), + return when( + watch( + E(connection).send(makeTxPacket(msgs, opts)), + this.facets.handleExecuteEncodedTxWatcher, + ), ); }, /** Close the remote account */ - async close() { - /// XXX what should the behavior be here? and `onClose`? + close() { + /// TODO #9192 what should the behavior be here? and `onClose`? // - retrieve assets? // - revoke the port? const { connection } = this.state; if (!connection) throw Fail`connection not available`; - await E(connection).close(); + return when(watch(E(connection).close())); }, /** * get Purse for a brand to .withdraw() a Payment from the account diff --git a/packages/orchestration/src/service.js b/packages/orchestration/src/service.js index 03ea23723cfd..2f905dc42da4 100644 --- a/packages/orchestration/src/service.js +++ b/packages/orchestration/src/service.js @@ -244,7 +244,7 @@ const prepareOrchestrationKit = ( * @param {VowTools} vowTools */ export const prepareOrchestrationTools = (zone, vowTools) => { - const makeChainAccountKit = prepareChainAccountKit(zone); + const makeChainAccountKit = prepareChainAccountKit(zone, vowTools); const makeICQConnectionKit = prepareICQConnectionKit(zone, vowTools); const makeOrchestrationKit = prepareOrchestrationKit( zone, diff --git a/packages/orchestration/test/service.test.ts b/packages/orchestration/test/service.test.ts index 0a324843eeb7..5bbf024ef885 100644 --- a/packages/orchestration/test/service.test.ts +++ b/packages/orchestration/test/service.test.ts @@ -4,7 +4,9 @@ import { toRequestQueryJson } from '@agoric/cosmic-proto'; import { QueryBalanceRequest } from '@agoric/cosmic-proto/cosmos/bank/v1beta1/query.js'; import { MsgDelegate } from '@agoric/cosmic-proto/cosmos/staking/v1beta1/tx.js'; import { Any } from '@agoric/cosmic-proto/google/protobuf/any.js'; +import { matches } from '@endo/patterns'; import { commonSetup } from './supports.js'; +import { ChainAddressShape } from '../src/typeGuards.js'; test('makeICQConnection returns an ICQConnection', async t => { const { @@ -89,17 +91,32 @@ test('makeAccount returns a ChainAccount', async t => { 'remote address contains version and encoding in version string', ); + t.true(matches(chainAddr, ChainAddressShape)); + t.regex( + chainAddr.address, + /UNPARSABLE_CHAIN_ADDRESS/, + 'TODO use mocked ibc connection instead of echo connection', + ); + + const delegateMsg = Any.toJSON( + MsgDelegate.toProtoMsg({ + delegatorAddress: 'cosmos1test', + validatorAddress: 'cosmosvaloper1test', + amount: { denom: 'uatom', amount: '10' }, + }), + ); await t.throwsAsync( - E(account).executeEncodedTx([ - Any.toJSON( - MsgDelegate.toProtoMsg({ - delegatorAddress: 'cosmos1test', - validatorAddress: 'cosmosvaloper1test', - amount: { denom: 'uatom', amount: '10' }, - }), - ), - ]), + E(account).executeEncodedTx([delegateMsg]), { message: /"type":1(.*)"data":"(.*)"memo":""/ }, 'TODO do not use echo connection', ); + + await E(account).close(); + await t.throwsAsync( + E(account).executeEncodedTx([delegateMsg]), + { + message: 'Connection closed', + }, + 'cannot execute transaction if connection is closed', + ); });