From a6360a50bedd00cd9e0df0b0a37738edffd32620 Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Wed, 1 May 2024 19:13:09 -0400 Subject: [PATCH] refactor(orchestration): prefer ChainAddress object to string --- .../test/bootstrapTests/test-orchestration.ts | 2 +- .../bootstrapTests/test-vat-orchestration.ts | 19 +++++----- .../src/examples/stakeAtom.contract.js | 4 +-- .../src/exos/stakingAccountKit.js | 19 +++++----- packages/orchestration/src/service.js | 35 ++++++++++++++----- packages/orchestration/src/types.d.ts | 7 ++-- 6 files changed, 50 insertions(+), 36 deletions(-) diff --git a/packages/boot/test/bootstrapTests/test-orchestration.ts b/packages/boot/test/bootstrapTests/test-orchestration.ts index d105d481dc8..6a9ff4f6f5d 100644 --- a/packages/boot/test/bootstrapTests/test-orchestration.ts +++ b/packages/boot/test/bootstrapTests/test-orchestration.ts @@ -140,7 +140,7 @@ test.serial('stakeAtom - smart wallet', async t => { invitationSpec: { source: 'agoricContract', instancePath: ['stakeAtom'], - callPipe: [['makeNewAccountInvitation']], + callPipe: [['makeMakeAccountInvitation']], }, proposal: {}, }); diff --git a/packages/boot/test/bootstrapTests/test-vat-orchestration.ts b/packages/boot/test/bootstrapTests/test-vat-orchestration.ts index 21c18ffcaf2..d3a347260cb 100644 --- a/packages/boot/test/bootstrapTests/test-vat-orchestration.ts +++ b/packages/boot/test/bootstrapTests/test-vat-orchestration.ts @@ -76,22 +76,21 @@ test('makeAccount returns an ICA connection', async t => { matches(account, M.remotable('ChainAccount')), 'account is a remotable', ); - const [remoteAddress, localAddress, accountAddress, port] = await Promise.all( - [ - EV(account).getRemoteAddress(), - EV(account).getLocalAddress(), - EV(account).getAddress(), - EV(account).getPort(), - ], - ); + const [remoteAddress, localAddress, chainAddress, port] = await Promise.all([ + EV(account).getRemoteAddress(), + EV(account).getLocalAddress(), + EV(account).getAddress(), + EV(account).getPort(), + ]); t.regex(remoteAddress, /icahost/); t.regex(localAddress, /icacontroller/); - t.regex(accountAddress, /cosmos1/); + t.regex(chainAddress.address, /cosmos1/); + t.regex(chainAddress.chainId, /FIXME/); // TODO, use a real chainId #9063 t.truthy(matches(port, M.remotable('Port'))); t.log('ICA Account Addresses', { remoteAddress, localAddress, - accountAddress, + chainAddress, }); }); diff --git a/packages/orchestration/src/examples/stakeAtom.contract.js b/packages/orchestration/src/examples/stakeAtom.contract.js index 6635477224e..0b9baaafeae 100644 --- a/packages/orchestration/src/examples/stakeAtom.contract.js +++ b/packages/orchestration/src/examples/stakeAtom.contract.js @@ -70,14 +70,14 @@ export const start = async (zcf, privateArgs, baggage) => { 'StakeAtom', M.interface('StakeAtomI', { makeAccount: M.callWhen().returns(M.remotable('ChainAccount')), - makeNewAccountInvitation: M.call().returns(M.promise()), + makeMakeAccountInvitation: M.call().returns(M.promise()), }), { async makeAccount() { trace('makeAccount'); return makeAccount().then(({ account }) => account); }, - makeNewAccountInvitation() { + makeMakeAccountInvitation() { trace('makeCreateAccountInvitation'); return zcf.makeInvitation( async seat => { diff --git a/packages/orchestration/src/exos/stakingAccountKit.js b/packages/orchestration/src/exos/stakingAccountKit.js index c1fc2dd8024..71692682096 100644 --- a/packages/orchestration/src/exos/stakingAccountKit.js +++ b/packages/orchestration/src/exos/stakingAccountKit.js @@ -14,8 +14,7 @@ import { E } from '@endo/far'; import { Any } from '@agoric/cosmic-proto/google/protobuf/any'; /** - * @import { ChainAddress } from '../types.js'; - * @import { ChainAccountKit } from '../service.js'; + * @import { ChainAccount, ChainAddress } from '../types.js'; * @import { RecorderKit, MakeRecorderKit } from '@agoric/zoe/src/contractSupport/recorder.js'; * @import { Baggage } from '@agoric/swingset-liveslots'; * @import {AnyJson} from '@agoric/cosmic-proto'; @@ -26,14 +25,14 @@ const trace = makeTracer('StakingAccountHolder'); const { Fail } = assert; /** * @typedef {object} StakingAccountNotification - * @property {ChainAddress['address']} address + * @property {ChainAddress} chainAddress */ /** * @typedef {{ * topicKit: RecorderKit; - * account: ChainAccountKit['account']; - * address: ChainAddress['address']; + * account: ChainAccount; + * chainAddress: ChainAddress; * }} State */ @@ -70,16 +69,16 @@ export const prepareStakingAccountKit = (baggage, makeRecorderKit, zcf) => { }), }, /** - * @param {ChainAccountKit['account']} account + * @param {ChainAccount} account * @param {StorageNode} storageNode - * @param {ChainAddress['address']} address + * @param {ChainAddress} chainAddress * @returns {State} */ - (account, storageNode, address) => { + (account, storageNode, chainAddress) => { // must be the fully synchronous maker because the kit is held in durable state const topicKit = makeRecorderKit(storageNode, PUBLIC_TOPICS.account[1]); - return { account, address, topicKit }; + return { account, chainAddress, topicKit }; }, { helper: { @@ -110,7 +109,7 @@ export const prepareStakingAccountKit = (baggage, makeRecorderKit, zcf) => { }; const account = this.facets.helper.owned(); - const delegatorAddress = this.state.address; + const delegatorAddress = this.state.chainAddress.address; const result = await E(account).executeEncodedTx([ /** @type {AnyJson} */ ( diff --git a/packages/orchestration/src/service.js b/packages/orchestration/src/service.js index d3b951ff0d7..3e816703ffb 100644 --- a/packages/orchestration/src/service.js +++ b/packages/orchestration/src/service.js @@ -19,7 +19,7 @@ import { makeTxPacket, parsePacketAck } from './utils/tx.js'; * @import { IBCConnectionID } from '@agoric/vats'; * @import { Zone } from '@agoric/base-zone'; * @import { TxBody } from '@agoric/cosmic-proto/cosmos/tx/v1beta1/tx.js'; - * @import { AttenuatedNetwork, ChainAccount, ChainAddress } from './types.js'; + * @import { ChainAccount, ChainAddress } from './types.js'; */ const { Fail, bare } = assert; @@ -58,8 +58,17 @@ export const Proto3Shape = { value: M.string(), }; +export const ChainAddressShape = { + address: M.string(), + chainId: M.string(), + addressEncoding: M.string(), +}; + +/** @typedef {'UNPARSABLE_CHAIN_ADDRESS'} UnparsableChainAddress */ +const UNPARSABLE_CHAIN_ADDRESS = 'UNPARSABLE_CHAIN_ADDRESS'; + export const ChainAccountI = M.interface('ChainAccount', { - getAddress: M.call().returns(M.string()), + getAddress: M.call().returns(ChainAddressShape), getLocalAddress: M.call().returns(M.string()), getRemoteAddress: M.call().returns(M.string()), getPort: M.call().returns(M.remotable('Port')), @@ -96,7 +105,7 @@ const prepareChainAccount = zone => * localAddress: string | undefined; * requestedRemoteAddress: string; * remoteAddress: string | undefined; - * address: ChainAddress['address'] | undefined; + * chainAddress: ChainAddress | undefined; * }} */ ( harden({ @@ -104,19 +113,19 @@ const prepareChainAccount = zone => connection: undefined, requestedRemoteAddress, remoteAddress: undefined, - address: undefined, + chainAddress: undefined, localAddress: undefined, }) ), { account: { /** - * @returns {ChainAddress['address']} the address of the account on the chain + * @returns {ChainAddress} */ getAddress() { return NonNullish( - this.state.address, - 'Error parsing account address from remote address', + this.state.chainAddress, + 'ICA channel creation acknowledgement not yet received.', ); }, getLocalAddress() { @@ -194,7 +203,15 @@ const prepareChainAccount = zone => this.state.remoteAddress = remoteAddr; this.state.localAddress = localAddr; // XXX parseAddress currently throws, should it return '' instead? - this.state.address = parseAddress(remoteAddr); + this.state.chainAddress = harden({ + address: parseAddress(remoteAddr) || UNPARSABLE_CHAIN_ADDRESS, + // TODO get this from `Chain` object #9063 + // XXX how do we get a chainId for an unknown chain? seems it may need to be a user supplied arg + chainId: 'FIXME', + addressEncoding: 'bech32', + }); + trace('got chainAddress', this.state.chainAddress); + trace('parseAddress(remoteAddr)', parseAddress(remoteAddr)); }, async onClose(_connection, reason) { trace(`ICA Channel closed. Reason: ${reason}`); @@ -252,7 +269,7 @@ const prepareOrchestration = (zone, createChainAccount) => * the counterparty connection_id * @param {IBCConnectionID} controllerConnectionId * self connection_id - * @returns {Promise} + * @returns {Promise} */ async makeAccount(hostConnectionId, controllerConnectionId) { const port = await this.facets.self.bindPort(); diff --git a/packages/orchestration/src/types.d.ts b/packages/orchestration/src/types.d.ts index 59de8f0c029..9a71dd1e055 100644 --- a/packages/orchestration/src/types.d.ts +++ b/packages/orchestration/src/types.d.ts @@ -419,12 +419,11 @@ export type TransferMsg = { data?: object; }; -// Example -// await icaNoble.transferSteps(usdcAmt, -// osmosisSwap(tiaBrand, { pool: 1224, slippage: 0.05 }, icaCel.getChainAddress())); - /** * @param pool - Required. Pool number + * @example + * await icaNoble.transferSteps(usdcAmt, + * osmosisSwap(tiaBrand, { pool: 1224, slippage: 0.05 }, icaCel.getAddress())); */ export type OsmoSwapOptions = { pool: string;