From 1c2c5faebca05bdb7f085e466d0a655a1ee0dfd3 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Fri, 31 May 2024 08:58:21 -0700 Subject: [PATCH 01/14] test(a3p): undelegate --- .../proposals/c:stake-bld/stakeBld.test.js | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/a3p-integration/proposals/c:stake-bld/stakeBld.test.js b/a3p-integration/proposals/c:stake-bld/stakeBld.test.js index 13e6cb52c1f..352db45415d 100644 --- a/a3p-integration/proposals/c:stake-bld/stakeBld.test.js +++ b/a3p-integration/proposals/c:stake-bld/stakeBld.test.js @@ -66,10 +66,33 @@ test('basic', async t => { }, }); - const postDelegation = await currentDelegation(); - t.is(postDelegation.length, 2, 'new delegation now'); - t.like(postDelegation[1], { + const afterDelegate = await currentDelegation(); + t.is(afterDelegate.length, 2, 'delegations after delegation'); + t.like(afterDelegate[1], { balance: { amount: '10', denom: 'ubld' }, // omit 'delegation' because it has 'delegatorAddress' which is different every test run }); + + await walletUtils.broadcastBridgeAction(GOV1ADDR, { + method: 'executeOffer', + offer: { + id: 'request-undelegate', + invitationSpec: { + source: 'continuing', + previousOffer: 'request-stake', + invitationMakerName: 'Undelegate', + invitationArgs: [VALIDATOR_ADDRESS, { brand: brand.BLD, value: 5n }], + }, + proposal: {}, + }, + }); + + // TODO wait until completionTime, so we can check the count has gone back down + // https://github.com/Agoric/agoric-sdk/pull/9439#discussion_r1626451871 + + // const afterUndelegate = await currentDelegation(); + // t.is(afterDelegate.length, 1, 'delegations after undelegation'); + // t.like(afterUndelegate[1], { + // balance: { amount: '5', denom: 'ubld' }, + // }); }); From 5659362b247593793bd30a6b726b261587701487 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Fri, 31 May 2024 15:13:04 -0700 Subject: [PATCH 02/14] test: use fake orchestrationService in facade --- packages/orchestration/src/cosmos-api.ts | 2 +- .../src/examples/stakeBld.contract.js | 2 +- .../src/examples/swapExample.contract.js | 5 +- .../src/examples/unbondExample.contract.js | 16 +-- .../orchestration/src/exos/chainAccountKit.js | 18 ++- .../src/exos/local-chain-account-kit.js | 8 +- packages/orchestration/src/facade.js | 99 +++++---------- .../orchestration/src/utils/mockChainInfo.js | 12 +- .../test/examples/swapExample.test.ts | 2 +- .../test/examples/unbondExample.test.ts | 2 +- .../test/exos/local-chain-account-kit.test.ts | 8 +- packages/orchestration/test/network-fakes.ts | 117 ++++++++++++++++++ packages/orchestration/test/supports.ts | 11 ++ 13 files changed, 193 insertions(+), 109 deletions(-) create mode 100644 packages/orchestration/test/network-fakes.ts diff --git a/packages/orchestration/src/cosmos-api.ts b/packages/orchestration/src/cosmos-api.ts index 2a81bc261e2..da0f7646df4 100644 --- a/packages/orchestration/src/cosmos-api.ts +++ b/packages/orchestration/src/cosmos-api.ts @@ -67,7 +67,7 @@ export type IBCConnectionInfo = { */ export type CosmosChainInfo = { chainId: string; - connections: MapStore; // chainId or wellKnownName + connections: Record; // chainId or wellKnownName icaEnabled: boolean; icqEnabled: boolean; pfmEnabled: boolean; diff --git a/packages/orchestration/src/examples/stakeBld.contract.js b/packages/orchestration/src/examples/stakeBld.contract.js index c51b2544ccf..b2ae4d1dfe2 100644 --- a/packages/orchestration/src/examples/stakeBld.contract.js +++ b/packages/orchestration/src/examples/stakeBld.contract.js @@ -44,7 +44,7 @@ export const start = async (zcf, privateArgs, baggage) => { // Mocked until #8879 // Would expect this to be instantiated elsewhere, and passed in as a reference - const agoricChainInfo = prepareMockChainInfo(zone); + const agoricChainInfo = prepareMockChainInfo(); const makeLocalChainAccountKit = prepareLocalChainAccountKit( zone, diff --git a/packages/orchestration/src/examples/swapExample.contract.js b/packages/orchestration/src/examples/swapExample.contract.js index 1557a5da778..4e5c504e9ac 100644 --- a/packages/orchestration/src/examples/swapExample.contract.js +++ b/packages/orchestration/src/examples/swapExample.contract.js @@ -1,6 +1,7 @@ import { StorageNodeShape } from '@agoric/internal'; import { TimerServiceShape } from '@agoric/time'; import { withdrawFromSeat } from '@agoric/zoe/src/contractSupport/zoeHelpers.js'; +import { makeDurableZone } from '@agoric/zone/durable.js'; import { Far } from '@endo/far'; import { deeplyFulfilled } from '@endo/marshal'; import { M, objectMap } from '@endo/patterns'; @@ -42,9 +43,9 @@ export const makeNatAmountShape = (brand, min) => * @param {ZCF} zcf * @param {{ * localchain: Remote; - * orchestrationService: Remote | null; + * orchestrationService: Remote; * storageNode: Remote; - * timerService: Remote | null; + * timerService: Remote; * zone: Zone; * }} privateArgs */ diff --git a/packages/orchestration/src/examples/unbondExample.contract.js b/packages/orchestration/src/examples/unbondExample.contract.js index fdddab58908..48a2a1979d5 100644 --- a/packages/orchestration/src/examples/unbondExample.contract.js +++ b/packages/orchestration/src/examples/unbondExample.contract.js @@ -1,6 +1,6 @@ +import { makeDurableZone } from '@agoric/zone/durable.js'; import { Far } from '@endo/far'; import { M } from '@endo/patterns'; -import { makeDurableZone } from '@agoric/zone/durable.js'; import { makeOrchestrationFacade } from '../facade.js'; /** @@ -49,19 +49,21 @@ export const start = async (zcf, privateArgs, baggage) => { const celestia = await orch.getChain('celestia'); const celestiaAccount = await celestia.makeAccount(); - const delegations = await celestiaAccount.getDelegations(); - // wait for the undelegations to be complete (may take weeks) - await celestiaAccount.undelegate(delegations); + // TODO implement these + // const delegations = await celestiaAccount.getDelegations(); + // // wait for the undelegations to be complete (may take weeks) + // await celestiaAccount.undelegate(delegations); // ??? should this be synchronous? depends on how names are resolved. const stride = await orch.getChain('stride'); const strideAccount = await stride.makeAccount(); // TODO the `TIA` string actually needs to be the Brand from AgoricNames - const tiaAmt = await celestiaAccount.getBalance('TIA'); - await celestiaAccount.transfer(tiaAmt, strideAccount.getAddress()); + // const tiaAmt = await celestiaAccount.getBalance('TIA'); + // await celestiaAccount.transfer(tiaAmt, strideAccount.getAddress()); - await strideAccount.liquidStake(tiaAmt); + // await strideAccount.liquidStake(tiaAmt); + console.log(celestiaAccount, strideAccount); }, ); diff --git a/packages/orchestration/src/exos/chainAccountKit.js b/packages/orchestration/src/exos/chainAccountKit.js index 34674106aef..73980dc0529 100644 --- a/packages/orchestration/src/exos/chainAccountKit.js +++ b/packages/orchestration/src/exos/chainAccountKit.js @@ -63,16 +63,14 @@ export const prepareChainAccountKit = zone => * @param {string} requestedRemoteAddress */ (port, requestedRemoteAddress) => - /** @type {State} */ ( - harden({ - port, - connection: undefined, - requestedRemoteAddress, - remoteAddress: undefined, - chainAddress: undefined, - localAddress: undefined, - }) - ), + /** @type {State} */ ({ + port, + connection: undefined, + requestedRemoteAddress, + remoteAddress: undefined, + chainAddress: undefined, + localAddress: undefined, + }), { account: { /** diff --git a/packages/orchestration/src/exos/local-chain-account-kit.js b/packages/orchestration/src/exos/local-chain-account-kit.js index 0571c1bbc79..655c843423c 100644 --- a/packages/orchestration/src/exos/local-chain-account-kit.js +++ b/packages/orchestration/src/exos/local-chain-account-kit.js @@ -243,10 +243,12 @@ export const prepareLocalChainAccountKit = ( // TODO #9211 lookup denom from brand if ('brand' in amount) throw Fail`ERTP Amounts not yet supported`; + destination.chainId in agoricChainInfo.connections || + Fail`Unknown chain ${destination.chainId}`; + // TODO #8879 chainInfo and #9063 well-known chains - const { transferChannel } = agoricChainInfo.connections.get( - destination.chainId, - ); + const { transferChannel } = + agoricChainInfo.connections[destination.chainId]; await null; // set a `timeoutTimestamp` if caller does not supply either `timeoutHeight` or `timeoutTimestamp` diff --git a/packages/orchestration/src/facade.js b/packages/orchestration/src/facade.js index 04cd6e68e50..aa25005e4bc 100644 --- a/packages/orchestration/src/facade.js +++ b/packages/orchestration/src/facade.js @@ -8,7 +8,7 @@ import { E } from '@endo/far'; * @import {LocalChain} from '@agoric/vats/src/localchain.js'; * @import {Remote} from '@agoric/internal'; * @import {OrchestrationService} from './service.js'; - * @import {Chain, ChainInfo, OrchestrationAccount, Orchestrator} from './types.js'; + * @import {Chain, ChainInfo, CosmosChainInfo, KnownChains, OrchestrationAccount, Orchestrator} from './types.js'; */ /** @type {any} */ @@ -54,78 +54,36 @@ const makeLocalChainFacade = localchain => { /** * @template {string} C * @param {C} name - * @returns {Chain} + * @param {object} io + * @param {Remote} io.orchestration + * @returns {Chain} */ -const makeRemoteChainFacade = name => { - const chainInfo = { +const makeRemoteChainFacade = (name, { orchestration }) => { + const chainInfo = /** @type {CosmosChainInfo} */ ({ allegedName: name, chainId: 'fixme', - }; + connections: {}, + icaEnabled: true, + icqEnabled: true, + pfmEnabled: true, + ibcHooksEnabled: true, + allowedMessages: [], + allowedQueries: [], + }); return { - /** @returns {Promise} */ - getChainInfo: async () => anyVal, + getChainInfo: async () => chainInfo, /** @returns {Promise>} */ makeAccount: async () => { console.log('makeAccount for', name); - // @ts-expect-error fake yet - return { - delegate(validator, amount) { - console.log('delegate got', validator, amount); - return Promise.resolve(); - }, - deposit(payment) { - console.log('deposit got', payment); - return Promise.resolve(); - }, - getAddress() { - return { - chainId: chainInfo.chainId, - address: 'an address!', - addressEncoding: 'bech32', - }; - }, - getBalance(_denom) { - console.error('getBalance not yet implemented'); - return Promise.resolve({ denom: 'fixme', value: 0n }); - }, - getBalances() { - throw new Error('not yet implemented'); - }, - getDelegations() { - console.error('getDelegations not yet implemented'); - return []; - }, - getRedelegations() { - throw new Error('not yet implemented'); - }, - getUnbondingDelegations() { - throw new Error('not yet implemented'); - }, - liquidStake() { - console.error('liquidStake not yet implemented'); - return 0n; - }, - send(toAccount, amount) { - console.log('send got', toAccount, amount); - return Promise.resolve(); - }, - transfer(amount, destination, memo) { - console.log('transfer got', amount, destination, memo); - return Promise.resolve(); - }, - transferSteps(amount, msg) { - console.log('transferSteps got', amount, msg); - return Promise.resolve(); - }, - undelegate(validator, amount) { - console.log('undelegate got', validator, amount); - return Promise.resolve(); - }, - withdraw(amount) { - console.log('withdraw got', amount); - return Promise.resolve(); - }, - }; + + // FIXME look up real values + const hostConnectionId = 'connection-1'; + const controllerConnectionId = 'connection-2'; + + return E(orchestration).makeAccount( + hostConnectionId, + controllerConnectionId, + ); }, }; }; @@ -133,10 +91,10 @@ const makeRemoteChainFacade = name => { /** * @param {{ * zone: Zone; - * timerService: Remote | null; + * timerService: Remote; * zcf: ZCF; * storageNode: Remote; - * orchestrationService: Remote | null; + * orchestrationService: Remote; * localchain: Remote; * }} powers */ @@ -172,7 +130,10 @@ export const makeOrchestrationFacade = ({ if (name === 'agoric') { return makeLocalChainFacade(localchain); } - return makeRemoteChainFacade(name); + + return makeRemoteChainFacade(name, { + orchestration: orchestrationService, + }); }, makeLocalAccount() { return E(localchain).makeAccount(); diff --git a/packages/orchestration/src/utils/mockChainInfo.js b/packages/orchestration/src/utils/mockChainInfo.js index 136306c4e54..d7fb12cea0e 100644 --- a/packages/orchestration/src/utils/mockChainInfo.js +++ b/packages/orchestration/src/utils/mockChainInfo.js @@ -68,19 +68,11 @@ const connectionEntries = harden({ }); /** - * @param {Zone} zone * @returns {Pick} */ -export const prepareMockChainInfo = zone => { - const agoricConnections = - /** @type {import('@agoric/store').MapStore} */ ( - zone.mapStore('ibcConnections') - ); - - agoricConnections.addAll(Object.entries(connectionEntries)); - +export const prepareMockChainInfo = () => { return harden({ chainId: 'agoriclocal', - connections: agoricConnections, + connections: connectionEntries, }); }; diff --git a/packages/orchestration/test/examples/swapExample.test.ts b/packages/orchestration/test/examples/swapExample.test.ts index f973a47f733..dbe4b84ceb4 100644 --- a/packages/orchestration/test/examples/swapExample.test.ts +++ b/packages/orchestration/test/examples/swapExample.test.ts @@ -29,7 +29,7 @@ test('start', async t => { {}, { localchain: bootstrap.localchain, - orchestrationService: null as any, + orchestrationService: bootstrap.orchestration, storageNode: bootstrap.storage.rootNode, timerService: bootstrap.timer, zone: bootstrap.rootZone, diff --git a/packages/orchestration/test/examples/unbondExample.test.ts b/packages/orchestration/test/examples/unbondExample.test.ts index 06cf5f9f0d8..b78e606fdf0 100644 --- a/packages/orchestration/test/examples/unbondExample.test.ts +++ b/packages/orchestration/test/examples/unbondExample.test.ts @@ -27,7 +27,7 @@ test('start', async t => { {}, { localchain: bootstrap.localchain, - orchestrationService: null as any, + orchestrationService: bootstrap.orchestration, storageNode: bootstrap.storage.rootNode, timerService: bootstrap.timer, }, diff --git a/packages/orchestration/test/exos/local-chain-account-kit.test.ts b/packages/orchestration/test/exos/local-chain-account-kit.test.ts index 0147054f5b1..368b1d5489a 100644 --- a/packages/orchestration/test/exos/local-chain-account-kit.test.ts +++ b/packages/orchestration/test/exos/local-chain-account-kit.test.ts @@ -17,7 +17,7 @@ test('deposit, withdraw', async t => { const { timer, localchain, marshaller, rootZone, storage } = bootstrap; t.log('chainInfo mocked via `prepareMockChainInfo` until #8879'); - const agoricChainInfo = prepareMockChainInfo(rootZone.subZone('chainInfo')); + const agoricChainInfo = prepareMockChainInfo(); t.log('exo setup - prepareLocalChainAccountKit'); const { makeRecorderKit } = prepareRecorderKitMakers( @@ -85,7 +85,7 @@ test('delegate, undelegate', async t => { const { timer, localchain, marshaller, rootZone, storage } = bootstrap; t.log('chainInfo mocked via `prepareMockChainInfo` until #8879'); - const agoricChainInfo = prepareMockChainInfo(rootZone.subZone('chainInfo')); + const agoricChainInfo = prepareMockChainInfo(); t.log('exo setup - prepareLocalChainAccountKit'); const { makeRecorderKit } = prepareRecorderKitMakers( @@ -136,7 +136,7 @@ test('transfer', async t => { const { timer, localchain, marshaller, rootZone, storage } = bootstrap; t.log('chainInfo mocked via `prepareMockChainInfo` until #8879'); - const agoricChainInfo = prepareMockChainInfo(rootZone.subZone('chainInfo')); + const agoricChainInfo = prepareMockChainInfo(); t.log('exo setup - prepareLocalChainAccountKit'); const { makeRecorderKit } = prepareRecorderKitMakers( @@ -207,7 +207,7 @@ test('transfer', async t => { await t.throwsAsync( () => E(account).transfer({ denom: 'ubld', value: 1n }, unknownDestination), { - message: /not found(.*)fakenet/, + message: /Unknown chain "fakenet"/, }, 'cannot create transfer msg with unknown chainId', ); diff --git a/packages/orchestration/test/network-fakes.ts b/packages/orchestration/test/network-fakes.ts new file mode 100644 index 00000000000..92a2f77ac68 --- /dev/null +++ b/packages/orchestration/test/network-fakes.ts @@ -0,0 +1,117 @@ +// @ts-check +import { prepareVowTools } from '@agoric/vow'; +import assert from 'node:assert/strict'; +import { + prepareEchoConnectionKit, + prepareNetworkProtocol, + preparePortAllocator, + type ListenHandler, + type MakeEchoConnectionKit, +} from '@agoric/network'; +import type { Zone } from '@agoric/zone'; + +// eslint-disable-next-line no-constant-condition +const log = false ? console.log : () => {}; + +export const prepareProtocolHandler = ( + zone: Zone, + makeEchoConnectionHandler: MakeEchoConnectionKit, + { when }, +) => { + const makeProtocolHandler = zone.exoClass( + 'ProtocolHandler', + undefined, + () => { + return { + l: undefined as ListenHandler | undefined, + lp: undefined, + nonce: 0, + }; + }, + { + async onInstantiate(_port, _localAddr, _remote, _protocol) { + return ''; + }, + async onCreate(_protocol, _impl) { + log('created', _protocol, _impl); + }, + async generatePortID() { + this.state.nonce += 1; + return `port-${this.state.nonce}`; + }, + async onBind(port, localAddr) { + assert(port, `port is supplied to onBind`); + assert(localAddr, `local address is supplied to onBind`); + }, + async onConnect(port, localAddr, remoteAddr) { + assert(port, `port is tracked in onConnect`); + assert(localAddr, `local address is supplied to onConnect`); + assert(remoteAddr, `remote address is supplied to onConnect`); + if (!this.state.lp) { + return { handler: makeEchoConnectionHandler().handler }; + } + assert(this.state.l); + const ch = await when( + this.state.l.onAccept( + this.state.lp, + localAddr, + remoteAddr, + this.state.l, + ), + ); + return { localAddr, handler: ch }; + }, + async onListen(port, localAddr, listenHandler) { + assert(port, `port is tracked in onListen`); + assert(localAddr, `local address is supplied to onListen`); + assert(listenHandler, `listen handler is tracked in onListen`); + this.state.lp = port; + this.state.l = listenHandler; + log('listening', port.getLocalAddress(), listenHandler); + }, + async onListenRemove(port, localAddr, listenHandler) { + assert(port, `port is tracked in onListen`); + assert(localAddr, `local address is supplied to onListen`); + assert.equal( + listenHandler, + this.state.lp && this.state.l, + `listenHandler is tracked in onListenRemove`, + ); + this.state.lp = undefined; + log('port done listening', port.getLocalAddress()); + }, + async onRevoke(port, localAddr) { + assert(port, `port is tracked in onRevoke`); + assert(localAddr, `local address is supplied to onRevoke`); + log('port done revoking', port.getLocalAddress()); + }, + }, + ); + + return makeProtocolHandler; +}; + +export const fakeNetworkEchoStuff = (zone: Zone) => { + const powers = prepareVowTools(zone); + const { makeVowKit, when } = powers; + + const makeNetworkProtocol = prepareNetworkProtocol(zone, powers); + const makeEchoConnectionHandler = prepareEchoConnectionKit(zone); + const makeProtocolHandler = prepareProtocolHandler( + zone, + makeEchoConnectionHandler, + powers, + ); + const protocol = makeNetworkProtocol(makeProtocolHandler()); + + const makePortAllocator = preparePortAllocator(zone, powers); + const portAllocator = makePortAllocator({ protocol }); + + return { + makeEchoConnectionHandler, + makeVowKit, + portAllocator, + protocol, + when, + }; +}; diff --git a/packages/orchestration/test/supports.ts b/packages/orchestration/test/supports.ts index 906cbe22f10..d13338b260b 100644 --- a/packages/orchestration/test/supports.ts +++ b/packages/orchestration/test/supports.ts @@ -9,6 +9,8 @@ import { buildZoeManualTimer } from '@agoric/zoe/tools/manualTimer.js'; import { withAmountUtils } from '@agoric/zoe/tools/test-utils.js'; import { makeHeapZone } from '@agoric/zone'; import { E } from '@endo/far'; +import { fakeNetworkEchoStuff } from './network-fakes.js'; +import { prepareOrchestrationTools } from '../src/service.js'; export { makeFakeLocalchainBridge } from '@agoric/vats/tools/fake-bridge.js'; @@ -43,12 +45,21 @@ export const commonSetup = async t => { const storage = makeFakeStorageKit('mockChainStorageRoot', { sequence: false, }); + + const { makeOrchestrationKit } = prepareOrchestrationTools( + rootZone.subZone('orchestration'), + ); + + const { portAllocator } = fakeNetworkEchoStuff(rootZone.subZone('network')); + const { public: orchestration } = makeOrchestrationKit({ portAllocator }); + return { bootstrap: { bankManager, timer, localchain, marshaller, + orchestration, rootZone, storage, }, From 44e74b3db731358c15f1ae5ab8c3bd9b6bb5616c Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 3 Jun 2024 14:15:30 -0700 Subject: [PATCH 03/14] chore(types): KnownChains --- packages/orchestration/src/chain-info.ts | 6 +++--- packages/orchestration/src/orchestration-api.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/orchestration/src/chain-info.ts b/packages/orchestration/src/chain-info.ts index bb729352588..c916d8f8019 100644 --- a/packages/orchestration/src/chain-info.ts +++ b/packages/orchestration/src/chain-info.ts @@ -13,10 +13,12 @@ import type { StakingAccountQueries, } from './types.js'; +export type ChainInfo = CosmosChainInfo | EthChainInfo; + // TODO generate this automatically with a build script drawing on data sources such as https://github.com/cosmos/chain-registry // XXX methods ad-hoc and not fully accurate -export type KnownChains = { +export type KnownChains = Record & { stride: { info: CosmosChainInfo; methods: IcaAccount & @@ -60,5 +62,3 @@ export type KnownChains = { StakingAccountQueries; }; }; - -export type ChainInfo = CosmosChainInfo | EthChainInfo; diff --git a/packages/orchestration/src/orchestration-api.ts b/packages/orchestration/src/orchestration-api.ts index 3ee02806bb0..0f022b3c336 100644 --- a/packages/orchestration/src/orchestration-api.ts +++ b/packages/orchestration/src/orchestration-api.ts @@ -170,7 +170,7 @@ export interface OrchestrationAccountI { * deposit payment from zoe to the account. For remote accounts, * an IBC Transfer will be executed to transfer funds there. */ - deposit: (payment: Payment) => Promise; + deposit: (payment: Payment<'nat'>) => Promise; } /** From 8383ca50d200f3fdac14d392449e30c320eb7879 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 3 Jun 2024 16:21:33 -0700 Subject: [PATCH 04/14] improve examples and stubs --- .../src/examples/stakeAtom.contract.js | 9 ++- .../src/examples/swapExample.contract.js | 10 ++-- .../orchestration/src/exos/chainAccountKit.js | 22 +++++--- .../src/exos/icqConnectionKit.js | 14 ++--- .../src/exos/stakingAccountKit.js | 29 ++++++---- packages/orchestration/src/facade.js | 56 ++++++++++++++++++- .../test/examples/swapExample.test.ts | 1 - 7 files changed, 107 insertions(+), 34 deletions(-) diff --git a/packages/orchestration/src/examples/stakeAtom.contract.js b/packages/orchestration/src/examples/stakeAtom.contract.js index 9d09d025912..a1cf95a5b5f 100644 --- a/packages/orchestration/src/examples/stakeAtom.contract.js +++ b/packages/orchestration/src/examples/stakeAtom.contract.js @@ -1,6 +1,7 @@ /** * @file Example contract that uses orchestration */ +// TODO rename to "stakeIca" or something else that conveys is parameterized nature import { makeTracer, StorageNodeShape } from '@agoric/internal'; import { TimerServiceShape } from '@agoric/time'; @@ -20,6 +21,11 @@ const trace = makeTracer('StakeAtom'); */ export const meta = harden({ + customTermsShape: { + hostConnectionId: M.string(), + controllerConnectionId: M.string(), + bondDenom: M.string(), + }, privateArgsShape: { orchestration: M.remotable('orchestration'), storageNode: StorageNodeShape, @@ -68,7 +74,8 @@ export const start = async (zcf, privateArgs, baggage) => { hostConnectionId, controllerConnectionId, ); - // #9212 TODO do not fail if host does not have `async-icq` module; + // TODO https://github.com/Agoric/agoric-sdk/issues/9326 + // Should not fail if host does not have `async-icq` module; // communicate to OrchestrationAccount that it can't send queries const icqConnection = await E(orchestration).provideICQConnection( controllerConnectionId, diff --git a/packages/orchestration/src/examples/swapExample.contract.js b/packages/orchestration/src/examples/swapExample.contract.js index 4e5c504e9ac..8fdb4ac49de 100644 --- a/packages/orchestration/src/examples/swapExample.contract.js +++ b/packages/orchestration/src/examples/swapExample.contract.js @@ -14,6 +14,7 @@ import { orcUtils } from '../utils/orc.js'; * @import {LocalChain} from '@agoric/vats/src/localchain.js'; * @import {Remote} from '@agoric/internal'; * @import {OrchestrationService} from '../service.js'; + * @import {Baggage} from '@agoric/vat-data' * @import {Zone} from '@agoric/zone'; */ @@ -24,7 +25,6 @@ export const meta = { orchestrationService: M.or(M.remotable('orchestration'), null), storageNode: StorageNodeShape, timerService: M.or(TimerServiceShape, null), - zone: M.any(), }, upgradability: 'canUpgrade', }; @@ -46,13 +46,15 @@ export const makeNatAmountShape = (brand, min) => * orchestrationService: Remote; * storageNode: Remote; * timerService: Remote; - * zone: Zone; * }} privateArgs + * @param {Baggage} baggage */ -export const start = async (zcf, privateArgs) => { +export const start = async (zcf, privateArgs, baggage) => { const { brands } = zcf.getTerms(); - const { localchain, orchestrationService, storageNode, timerService, zone } = + const zone = makeDurableZone(baggage); + + const { localchain, orchestrationService, storageNode, timerService } = privateArgs; const { orchestrate } = makeOrchestrationFacade({ diff --git a/packages/orchestration/src/exos/chainAccountKit.js b/packages/orchestration/src/exos/chainAccountKit.js index 73980dc0529..562702359e5 100644 --- a/packages/orchestration/src/exos/chainAccountKit.js +++ b/packages/orchestration/src/exos/chainAccountKit.js @@ -30,6 +30,8 @@ const UNPARSABLE_CHAIN_ADDRESS = 'UNPARSABLE_CHAIN_ADDRESS'; export const ChainAccountI = M.interface('ChainAccount', { getAddress: M.call().returns(ChainAddressShape), + getBalance: M.callWhen(M.string()).returns(M.any()), + getBalances: M.callWhen().returns(M.any()), getLocalAddress: M.call().returns(M.string()), getRemoteAddress: M.call().returns(M.string()), getPort: M.call().returns(M.remotable('Port')), @@ -73,15 +75,21 @@ export const prepareChainAccountKit = zone => }), { account: { - /** - * @returns {ChainAddress} - */ + /** @returns {ChainAddress} */ getAddress() { return NonNullish( this.state.chainAddress, 'ICA channel creation acknowledgement not yet received.', ); }, + getBalance(_denom) { + // UNTIL https://github.com/Agoric/agoric-sdk/issues/9326 + throw new Error('not yet implemented'); + }, + getBalances() { + // UNTIL https://github.com/Agoric/agoric-sdk/issues/9326 + throw new Error('not yet implemented'); + }, getLocalAddress() { return NonNullish( this.state.localAddress, @@ -119,9 +127,7 @@ export const prepareChainAccountKit = zone => ack => parseTxPacket(ack), ); }, - /** - * Close the remote account - */ + /** Close the remote account */ async close() { /// XXX what should the behavior be here? and `onClose`? // - retrieve assets? @@ -132,7 +138,9 @@ export const prepareChainAccountKit = zone => }, async deposit(payment) { console.log('deposit got', payment); - throw new Error('not yet implemented'); + console.error( + 'FIXME deposit noop until https://github.com/Agoric/agoric-sdk/issues/9193', + ); }, /** * get Purse for a brand to .withdraw() a Payment from the account diff --git a/packages/orchestration/src/exos/icqConnectionKit.js b/packages/orchestration/src/exos/icqConnectionKit.js index 8c9c8323f2d..6c29d491ce3 100644 --- a/packages/orchestration/src/exos/icqConnectionKit.js +++ b/packages/orchestration/src/exos/icqConnectionKit.js @@ -61,14 +61,12 @@ export const prepareICQConnectionKit = zone => * @param {Port} port */ port => - /** @type {ICQConnectionKitState} */ ( - harden({ - port, - connection: undefined, - remoteAddress: undefined, - localAddress: undefined, - }) - ), + /** @type {ICQConnectionKitState} */ ({ + port, + connection: undefined, + remoteAddress: undefined, + localAddress: undefined, + }), { connection: { getLocalAddress() { diff --git a/packages/orchestration/src/exos/stakingAccountKit.js b/packages/orchestration/src/exos/stakingAccountKit.js index 1461df5f850..bb05d2c45b3 100644 --- a/packages/orchestration/src/exos/stakingAccountKit.js +++ b/packages/orchestration/src/exos/stakingAccountKit.js @@ -16,7 +16,7 @@ import { MsgUndelegateResponse, } from '@agoric/cosmic-proto/cosmos/staking/v1beta1/tx.js'; import { Any } from '@agoric/cosmic-proto/google/protobuf/any.js'; -import { AmountShape } from '@agoric/ertp'; +import { AmountShape, PaymentShape } from '@agoric/ertp'; import { makeTracer } from '@agoric/internal'; import { M } from '@agoric/vat-data'; import { TopicsRecordShape } from '@agoric/zoe/src/contractSupport/index.js'; @@ -38,10 +38,11 @@ import { import { dateInSeconds } from '../utils/time.js'; /** - * @import {AmountArg, IcaAccount, ChainAddress, CosmosValidatorAddress, ICQConnection, StakingAccountActions, DenomAmount} from '../types.js'; + * @import {AmountArg, IcaAccount, ChainAddress, CosmosValidatorAddress, ICQConnection, StakingAccountActions, DenomAmount, OrchestrationAccountI} from '../types.js'; * @import {RecorderKit, MakeRecorderKit} from '@agoric/zoe/src/contractSupport/recorder.js'; * @import {Coin} from '@agoric/cosmic-proto/cosmos/base/v1beta1/coin.js'; * @import {Delegation} from '@agoric/cosmic-proto/cosmos/staking/v1beta1/staking.js'; + * @import {Remote} from '@agoric/internal'; * @import {TimerService} from '@agoric/time'; * @import {Zone} from '@agoric/zone'; */ @@ -61,15 +62,18 @@ const { Fail } = assert; * chainAddress: ChainAddress; * icqConnection: ICQConnection; * bondDenom: string; - * timer: TimerService; + * timer: Remote; * }} State */ +/** @see {OrchestrationAccountI} */ export const IcaAccountHolderI = M.interface('IcaAccountHolder', { getPublicTopics: M.call().returns(TopicsRecordShape), getAddress: M.call().returns(ChainAddressShape), getBalance: M.callWhen().optional(M.string()).returns(CoinShape), + getBalances: M.callWhen().optional(M.string()).returns(M.arrayOf(CoinShape)), delegate: M.callWhen(ChainAddressShape, AmountShape).returns(M.undefined()), + deposit: M.callWhen(PaymentShape).returns(M.undefined()), redelegate: M.callWhen( ChainAddressShape, ChainAddressShape, @@ -138,9 +142,9 @@ export const prepareStakingAccountKit = (zone, makeRecorderKit, zcf) => { * @param {string} bondDenom e.g. 'uatom' * @param {object} io * @param {IcaAccount} io.account - * @param {StorageNode} io.storageNode + * @param {Remote} io.storageNode * @param {ICQConnection} io.icqConnection - * @param {TimerService} io.timer + * @param {Remote} io.timer * @returns {State} */ (chainAddress, bondDenom, io) => { @@ -221,9 +225,7 @@ export const prepareStakingAccountKit = (zone, makeRecorderKit, zcf) => { return this.facets.holder.withdrawReward(validator); }, 'WithdrawReward'); }, - /** - * @param {Delegation[]} delegations - */ + /** @param {Delegation[]} delegations */ Undelegate(delegations) { trace('Undelegate', delegations); @@ -285,6 +287,13 @@ export const prepareStakingAccountKit = (zone, makeRecorderKit, zcf) => { expect(result, trivialDelegateResponse, 'MsgDelegateResponse'); }, + async deposit(payment) { + const { helper } = this.facets; + return E(helper.owned()).deposit(payment); + }, + async getBalances() { + throw Error('not yet implemented'); + }, /** * _Assumes users has already sent funds to their ICA, until #9193 * @@ -361,9 +370,7 @@ export const prepareStakingAccountKit = (zone, makeRecorderKit, zcf) => { throw assert.error('Not implemented'); }, - /** - * @param {Delegation[]} delegations - */ + /** @param {Delegation[]} delegations */ async undelegate(delegations) { trace('undelegate', delegations); const { helper } = this.facets; diff --git a/packages/orchestration/src/facade.js b/packages/orchestration/src/facade.js index aa25005e4bc..62b4b5167a1 100644 --- a/packages/orchestration/src/facade.js +++ b/packages/orchestration/src/facade.js @@ -1,6 +1,7 @@ /** @file Orchestration service */ import { E } from '@endo/far'; +import { prepareStakingAccountKit } from './exos/stakingAccountKit.js'; /** * @import {Zone} from '@agoric/zone'; @@ -34,6 +35,8 @@ const makeLocalChainFacade = localchain => { pfmEnabled: true, }; }, + + // @ts-expect-error FIXME promise resolution through membrane async makeAccount() { const account = await E(localchain).makeAccount(); @@ -42,6 +45,30 @@ const makeLocalChainFacade = localchain => { console.log('deposit got', payment); return E(account).deposit(payment); }, + async getAddress() { + const addressStr = await E(account).getAddress(); + return { + address: addressStr, + chainId: 'agoric-3', + addressEncoding: 'bech32', + }; + }, + getBalance(_denom) { + // FIXME map denom to Brand + const brand = /** @type {any} */ (null); + return E(account).getBalance(brand); + }, + getBalances() { + throw new Error('not yet implemented'); + }, + send(toAccount, amount) { + // FIXME implement + console.log('send got', toAccount, amount); + }, + transfer(amount, destination, opts) { + // FIXME implement + console.log('transfer got', amount, destination, opts); + }, transferSteps(amount, msg) { console.log('transferSteps got', amount, msg); return Promise.resolve(); @@ -56,9 +83,12 @@ const makeLocalChainFacade = localchain => { * @param {C} name * @param {object} io * @param {Remote} io.orchestration + * @param {Remote} io.timer + * @param {ZCF} io.zcf + * @param {Zone} io.zone * @returns {Chain} */ -const makeRemoteChainFacade = (name, { orchestration }) => { +const makeRemoteChainFacade = (name, { orchestration, timer, zcf, zone }) => { const chainInfo = /** @type {CosmosChainInfo} */ ({ allegedName: name, chainId: 'fixme', @@ -70,6 +100,13 @@ const makeRemoteChainFacade = (name, { orchestration }) => { allowedMessages: [], allowedQueries: [], }); + const makeRecorderKit = () => anyVal; + const makeStakingAccountKit = prepareStakingAccountKit( + zone.subZone(name), + makeRecorderKit, + zcf, + ); + return { getChainInfo: async () => chainInfo, /** @returns {Promise>} */ @@ -80,10 +117,22 @@ const makeRemoteChainFacade = (name, { orchestration }) => { const hostConnectionId = 'connection-1'; const controllerConnectionId = 'connection-2'; - return E(orchestration).makeAccount( + const icaAccount = await E(orchestration).makeAccount( hostConnectionId, controllerConnectionId, ); + + const address = await E(icaAccount).getAddress(); + + // FIXME look up real values + const bondDenom = name; + // @ts-expect-error FIXME promise resolution through membrane + return makeStakingAccountKit(address, bondDenom, { + account: icaAccount, + storageNode: anyVal, + icqConnection: anyVal, + timer, + }).holder; }, }; }; @@ -133,6 +182,9 @@ export const makeOrchestrationFacade = ({ return makeRemoteChainFacade(name, { orchestration: orchestrationService, + timer: timerService, + zcf, + zone, }); }, makeLocalAccount() { diff --git a/packages/orchestration/test/examples/swapExample.test.ts b/packages/orchestration/test/examples/swapExample.test.ts index dbe4b84ceb4..ca1a8852fe5 100644 --- a/packages/orchestration/test/examples/swapExample.test.ts +++ b/packages/orchestration/test/examples/swapExample.test.ts @@ -32,7 +32,6 @@ test('start', async t => { orchestrationService: bootstrap.orchestration, storageNode: bootstrap.storage.rootNode, timerService: bootstrap.timer, - zone: bootstrap.rootZone, }, ); From f14394dfac83ef0d12735c2ac314b460dfceb002 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 3 Jun 2024 16:22:06 -0700 Subject: [PATCH 05/14] test: stakeAtom --- .../test/examples/stake-atom.contract.test.ts | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 packages/orchestration/test/examples/stake-atom.contract.test.ts diff --git a/packages/orchestration/test/examples/stake-atom.contract.test.ts b/packages/orchestration/test/examples/stake-atom.contract.test.ts new file mode 100644 index 00000000000..96097031fbe --- /dev/null +++ b/packages/orchestration/test/examples/stake-atom.contract.test.ts @@ -0,0 +1,65 @@ +import { test } from '@agoric/zoe/tools/prepare-test-env-ava.js'; + +import { AmountMath } from '@agoric/ertp'; +import { setUpZoeForTest } from '@agoric/zoe/tools/setup-zoe.js'; +import { E } from '@endo/far'; +import path from 'path'; +import type { Installation } from '@agoric/zoe/src/zoeService/utils.js'; +import { commonSetup } from '../supports.js'; + +const dirname = path.dirname(new URL(import.meta.url).pathname); + +const contractFile = `${dirname}/../../src/examples/stakeAtom.contract.js`; +type StartFn = + typeof import('@agoric/orchestration/src/examples/stakeAtom.contract.js').start; + +const coreEval = async ( + t, + { orchestration, timer, marshaller, storage, bld }, +) => { + t.log('install stakeAtom contract'); + const { zoe, bundleAndInstall } = await setUpZoeForTest(); + const installation: Installation = + await bundleAndInstall(contractFile); + + const { publicFacet } = await E(zoe).startInstance( + installation, + { In: bld.issuer }, + { + hostConnectionId: 'connection-1', + controllerConnectionId: 'connection-2', + bondDenom: 'uatom', + }, + { + marshaller, + orchestration, + storageNode: storage.rootNode, + timer, + }, + ); + return { publicFacet, zoe }; +}; + +test('makeAccount, deposit, withdraw', async t => { + const { + bootstrap, + brands: { ist }, + utils, + } = await commonSetup(t); + const { publicFacet } = await coreEval(t, { ...bootstrap, bld: ist }); + + t.log('make an ICA account'); + const account = await E(publicFacet).makeAccount(); + t.truthy(account, 'account is returned'); + const address = await E(account).getAddress(); + // XXX address.address is weird + // t.regex(address.address, /agoric1/); + t.like(address, { chainId: 'FIXME', addressEncoding: 'bech32' }); + + t.log('deposit 100 bld to account'); + await E(account).deposit(await utils.pourPayment(ist.units(100))); + + await t.throwsAsync(E(account).getBalances(), { + message: 'not yet implemented', + }); +}); From 76c5bdc95025d0749898710d1952f7190b4b367a Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 4 Jun 2024 09:59:28 -0700 Subject: [PATCH 06/14] test: clarify startContract() --- .../test/examples/stake-atom.contract.test.ts | 14 ++++++++------ .../test/examples/stake-bld.contract.test.ts | 15 ++++++++++----- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/packages/orchestration/test/examples/stake-atom.contract.test.ts b/packages/orchestration/test/examples/stake-atom.contract.test.ts index 96097031fbe..652997171c4 100644 --- a/packages/orchestration/test/examples/stake-atom.contract.test.ts +++ b/packages/orchestration/test/examples/stake-atom.contract.test.ts @@ -13,11 +13,13 @@ const contractFile = `${dirname}/../../src/examples/stakeAtom.contract.js`; type StartFn = typeof import('@agoric/orchestration/src/examples/stakeAtom.contract.js').start; -const coreEval = async ( - t, - { orchestration, timer, marshaller, storage, bld }, -) => { - t.log('install stakeAtom contract'); +const startContract = async ({ + orchestration, + timer, + marshaller, + storage, + bld, +}) => { const { zoe, bundleAndInstall } = await setUpZoeForTest(); const installation: Installation = await bundleAndInstall(contractFile); @@ -46,7 +48,7 @@ test('makeAccount, deposit, withdraw', async t => { brands: { ist }, utils, } = await commonSetup(t); - const { publicFacet } = await coreEval(t, { ...bootstrap, bld: ist }); + const { publicFacet } = await startContract({ ...bootstrap, bld: ist }); t.log('make an ICA account'); const account = await E(publicFacet).makeAccount(); diff --git a/packages/orchestration/test/examples/stake-bld.contract.test.ts b/packages/orchestration/test/examples/stake-bld.contract.test.ts index 412c60ab876..7dc11530e48 100644 --- a/packages/orchestration/test/examples/stake-bld.contract.test.ts +++ b/packages/orchestration/test/examples/stake-bld.contract.test.ts @@ -12,8 +12,13 @@ const contractFile = `${dirname}/../../src/examples/stakeBld.contract.js`; type StartFn = typeof import('@agoric/orchestration/src/examples/stakeBld.contract.js').start; -const coreEval = async (t, { timer, localchain, marshaller, storage, bld }) => { - t.log('install stakeBld contract'); +const startContract = async ({ + timer, + localchain, + marshaller, + storage, + bld, +}) => { const { zoe, bundleAndInstall } = await setUpZoeForTest(); const installation: Installation = await bundleAndInstall(contractFile); @@ -39,7 +44,7 @@ test('makeAccount, deposit, withdraw', async t => { brands: { bld }, utils, } = await commonSetup(t); - const { publicFacet } = await coreEval(t, { ...bootstrap, bld }); + const { publicFacet } = await startContract({ ...bootstrap, bld }); t.log('make a LocalChainAccount'); const account = await E(publicFacet).makeAccount(); @@ -72,7 +77,7 @@ test('makeStakeBldInvitation', async t => { brands: { bld }, utils, } = await commonSetup(t); - const { publicFacet, zoe } = await coreEval(t, { ...bootstrap, bld }); + const { publicFacet, zoe } = await startContract({ ...bootstrap, bld }); t.log('call makeStakeBldInvitation'); const inv = await E(publicFacet).makeStakeBldInvitation(); @@ -113,7 +118,7 @@ test('makeAccountInvitationMaker', async t => { bootstrap, brands: { bld }, } = await commonSetup(t); - const { publicFacet, zoe } = await coreEval(t, { ...bootstrap, bld }); + const { publicFacet, zoe } = await startContract({ ...bootstrap, bld }); const inv = await E(publicFacet).makeAccountInvitationMaker(); From 20d693b5137549b699cfc25a0e744368cb774259 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 4 Jun 2024 11:55:59 -0700 Subject: [PATCH 07/14] refactor: DRY local chainId --- packages/orchestration/src/facade.js | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/orchestration/src/facade.js b/packages/orchestration/src/facade.js index 62b4b5167a1..3de98abc435 100644 --- a/packages/orchestration/src/facade.js +++ b/packages/orchestration/src/facade.js @@ -15,6 +15,19 @@ import { prepareStakingAccountKit } from './exos/stakingAccountKit.js'; /** @type {any} */ const anyVal = null; +// FIXME should be configurable +const mockLocalChainInfo = { + allegedName: 'agoric', + allowedMessages: [], + allowedQueries: [], + chainId: 'agoriclocal', + connections: anyVal, + ibcHooksEnabled: true, + icaEnabled: true, + icqEnabled: true, + pfmEnabled: true, +}; + /** * @param {Remote} localchain * @returns {Chain} @@ -23,17 +36,7 @@ const makeLocalChainFacade = localchain => { return { /** @returns {Promise} */ async getChainInfo() { - return { - allegedName: 'agoric', - allowedMessages: [], - allowedQueries: [], - chainId: 'agoric-3', - connections: anyVal, - ibcHooksEnabled: true, - icaEnabled: true, - icqEnabled: true, - pfmEnabled: true, - }; + return mockLocalChainInfo; }, // @ts-expect-error FIXME promise resolution through membrane @@ -49,7 +52,7 @@ const makeLocalChainFacade = localchain => { const addressStr = await E(account).getAddress(); return { address: addressStr, - chainId: 'agoric-3', + chainId: mockLocalChainInfo.chainId, addressEncoding: 'bech32', }; }, From e43674374a6eece4d0b73b04ee7387c8e3354d05 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 4 Jun 2024 10:50:05 -0700 Subject: [PATCH 08/14] =?UTF-8?q?refactor:=20StakingAccount=20=E2=86=92=20?= =?UTF-8?q?CosmosOrchestrationAccount?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/examples/stakeAtom.contract.js | 15 ++++-------- ...ntKit.js => cosmosOrchestrationAccount.js} | 20 +++++++++++----- packages/orchestration/src/facade.js | 15 ++++++------ .../orchestration/test/staking-ops.test.ts | 24 ++++++++++++++----- 4 files changed, 45 insertions(+), 29 deletions(-) rename packages/orchestration/src/exos/{stakingAccountKit.js => cosmosOrchestrationAccount.js} (96%) diff --git a/packages/orchestration/src/examples/stakeAtom.contract.js b/packages/orchestration/src/examples/stakeAtom.contract.js index a1cf95a5b5f..504cb200645 100644 --- a/packages/orchestration/src/examples/stakeAtom.contract.js +++ b/packages/orchestration/src/examples/stakeAtom.contract.js @@ -1,6 +1,4 @@ -/** - * @file Example contract that uses orchestration - */ +/** @file Example contract that uses orchestration */ // TODO rename to "stakeIca" or something else that conveys is parameterized nature import { makeTracer, StorageNodeShape } from '@agoric/internal'; @@ -10,7 +8,7 @@ import { prepareRecorderKitMakers } from '@agoric/zoe/src/contractSupport'; import { InvitationShape } from '@agoric/zoe/src/typeGuards.js'; import { makeDurableZone } from '@agoric/zone/durable.js'; import { M } from '@endo/patterns'; -import { prepareStakingAccountKit } from '../exos/stakingAccountKit.js'; +import { prepareCosmosOrchestrationAccountKit } from '../exos/cosmosOrchestrationAccount.js'; const trace = makeTracer('StakeAtom'); /** @@ -63,11 +61,8 @@ export const start = async (zcf, privateArgs, baggage) => { const { makeRecorderKit } = prepareRecorderKitMakers(baggage, marshaller); - const makeStakingAccountKit = prepareStakingAccountKit( - zone, - makeRecorderKit, - zcf, - ); + const makeCosmosOrchestrationAccountKit = + prepareCosmosOrchestrationAccountKit(zone, makeRecorderKit, zcf); async function makeAccountKit() { const account = await E(orchestration).makeAccount( @@ -82,7 +77,7 @@ export const start = async (zcf, privateArgs, baggage) => { ); const accountAddress = await E(account).getAddress(); trace('account address', accountAddress); - const { holder, invitationMakers } = makeStakingAccountKit( + const { holder, invitationMakers } = makeCosmosOrchestrationAccountKit( accountAddress, bondDenom, { diff --git a/packages/orchestration/src/exos/stakingAccountKit.js b/packages/orchestration/src/exos/cosmosOrchestrationAccount.js similarity index 96% rename from packages/orchestration/src/exos/stakingAccountKit.js rename to packages/orchestration/src/exos/cosmosOrchestrationAccount.js index bb05d2c45b3..f13ce644372 100644 --- a/packages/orchestration/src/exos/stakingAccountKit.js +++ b/packages/orchestration/src/exos/cosmosOrchestrationAccount.js @@ -110,8 +110,12 @@ const toDenomAmount = c => ({ denom: c.denom, value: BigInt(c.amount) }); * @param {MakeRecorderKit} makeRecorderKit * @param {ZCF} zcf */ -export const prepareStakingAccountKit = (zone, makeRecorderKit, zcf) => { - const makeStakingAccountKit = zone.exoClassKit( +export const prepareCosmosOrchestrationAccountKit = ( + zone, + makeRecorderKit, + zcf, +) => { + const makeCosmosOrchestrationAccountKit = zone.exoClassKit( 'Staking Account Holder', { helper: M.interface('helper', { @@ -408,11 +412,15 @@ export const prepareStakingAccountKit = (zone, makeRecorderKit, zcf) => { const arg = null; /** @satisfies {StakingAccountActions} */ // eslint-disable-next-line no-unused-vars - const kit = makeStakingAccountKit(arg, arg, arg).holder; + const kit = makeCosmosOrchestrationAccountKit(arg, arg, arg).holder; }; - return makeStakingAccountKit; + return makeCosmosOrchestrationAccountKit; }; -/** @typedef {ReturnType>} StakingAccountKit */ -/** @typedef {StakingAccountKit['holder']} StakingAccounHolder */ +/** + * @typedef {ReturnType< + * ReturnType + * >} CosmosOrchestrationAccountKit + */ +/** @typedef {CosmosOrchestrationAccountKit['holder']} StakingAccounHolder */ diff --git a/packages/orchestration/src/facade.js b/packages/orchestration/src/facade.js index 3de98abc435..0551b89c2df 100644 --- a/packages/orchestration/src/facade.js +++ b/packages/orchestration/src/facade.js @@ -1,7 +1,7 @@ /** @file Orchestration service */ import { E } from '@endo/far'; -import { prepareStakingAccountKit } from './exos/stakingAccountKit.js'; +import { prepareCosmosOrchestrationAccountKit } from './exos/cosmosOrchestrationAccount.js'; /** * @import {Zone} from '@agoric/zone'; @@ -104,11 +104,12 @@ const makeRemoteChainFacade = (name, { orchestration, timer, zcf, zone }) => { allowedQueries: [], }); const makeRecorderKit = () => anyVal; - const makeStakingAccountKit = prepareStakingAccountKit( - zone.subZone(name), - makeRecorderKit, - zcf, - ); + const makeCosmosOrchestrationAccountKit = + prepareCosmosOrchestrationAccountKit( + zone.subZone(name), + makeRecorderKit, + zcf, + ); return { getChainInfo: async () => chainInfo, @@ -130,7 +131,7 @@ const makeRemoteChainFacade = (name, { orchestration, timer, zcf, zone }) => { // FIXME look up real values const bondDenom = name; // @ts-expect-error FIXME promise resolution through membrane - return makeStakingAccountKit(address, bondDenom, { + return makeCosmosOrchestrationAccountKit(address, bondDenom, { account: icaAccount, storageNode: anyVal, icqConnection: anyVal, diff --git a/packages/orchestration/test/staking-ops.test.ts b/packages/orchestration/test/staking-ops.test.ts index c0bba8c3001..6daf8722874 100644 --- a/packages/orchestration/test/staking-ops.test.ts +++ b/packages/orchestration/test/staking-ops.test.ts @@ -17,9 +17,9 @@ import type { TimestampRecord, TimestampValue } from '@agoric/time'; import type { AnyJson } from '@agoric/cosmic-proto'; import { makeDurableZone } from '@agoric/zone/durable.js'; import { - prepareStakingAccountKit, + prepareCosmosOrchestrationAccountKit, trivialDelegateResponse, -} from '../src/exos/stakingAccountKit.js'; +} from '../src/exos/cosmosOrchestrationAccount.js'; import { encodeTxResponse } from '../src/utils/cosmos.js'; import type { IcaAccount, ChainAddress, ICQConnection } from '../src/types.js'; @@ -208,7 +208,7 @@ test('withdrawRewards() on StakingAccountHolder formats message correctly', asyn const s = makeScenario(); const { account, calls, timer } = s; const { makeRecorderKit, storageNode, zcf, icqConnection, zone } = s; - const make = prepareStakingAccountKit(zone, makeRecorderKit, zcf); + const make = prepareCosmosOrchestrationAccountKit(zone, makeRecorderKit, zcf); // Higher fidelity tests below use invitationMakers. const { holder } = make(account.getAddress(), 'uatom', { @@ -232,7 +232,11 @@ test(`delegate; redelegate using invitationMakers`, async t => { const { account, calls, timer } = s; const { makeRecorderKit, storageNode, zcf, zoe, icqConnection, zone } = s; const aBrand = Far('Token') as Brand<'nat'>; - const makeAccountKit = prepareStakingAccountKit(zone, makeRecorderKit, zcf); + const makeAccountKit = prepareCosmosOrchestrationAccountKit( + zone, + makeRecorderKit, + zcf, + ); const { invitationMakers } = makeAccountKit(account.getAddress(), 'uatom', { account, @@ -297,7 +301,11 @@ test(`withdraw rewards using invitationMakers`, async t => { const s = makeScenario(); const { account, calls, timer } = s; const { makeRecorderKit, storageNode, zcf, zoe, icqConnection, zone } = s; - const makeAccountKit = prepareStakingAccountKit(zone, makeRecorderKit, zcf); + const makeAccountKit = prepareCosmosOrchestrationAccountKit( + zone, + makeRecorderKit, + zcf, + ); const { invitationMakers } = makeAccountKit(account.getAddress(), 'uatom', { account, @@ -323,7 +331,11 @@ test(`undelegate waits for unbonding period`, async t => { const s = makeScenario(); const { account, calls, timer } = s; const { makeRecorderKit, storageNode, zcf, zoe, icqConnection, zone } = s; - const makeAccountKit = prepareStakingAccountKit(zone, makeRecorderKit, zcf); + const makeAccountKit = prepareCosmosOrchestrationAccountKit( + zone, + makeRecorderKit, + zcf, + ); const { invitationMakers } = makeAccountKit(account.getAddress(), 'uatom', { account, From b8b349bffd9d5dc861a6efe67892c3957397daec Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 4 Jun 2024 10:57:51 -0700 Subject: [PATCH 09/14] refactor: makeCosmosOrchestrationAccount --- .../src/exos/cosmosOrchestrationAccount.js | 31 ++++++++++++++++--- packages/orchestration/src/facade.js | 19 ++++++------ 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/packages/orchestration/src/exos/cosmosOrchestrationAccount.js b/packages/orchestration/src/exos/cosmosOrchestrationAccount.js index f13ce644372..6ed48a2e70c 100644 --- a/packages/orchestration/src/exos/cosmosOrchestrationAccount.js +++ b/packages/orchestration/src/exos/cosmosOrchestrationAccount.js @@ -47,17 +47,17 @@ import { dateInSeconds } from '../utils/time.js'; * @import {Zone} from '@agoric/zone'; */ -const trace = makeTracer('StakingAccountHolder'); +const trace = makeTracer('ComosOrchestrationAccountHolder'); const { Fail } = assert; /** - * @typedef {object} StakingAccountNotification + * @typedef {object} ComosOrchestrationAccountNotification * @property {ChainAddress} chainAddress */ /** * @typedef {{ - * topicKit: RecorderKit; + * topicKit: RecorderKit; * account: IcaAccount; * chainAddress: ChainAddress; * icqConnection: ICQConnection; @@ -423,4 +423,27 @@ export const prepareCosmosOrchestrationAccountKit = ( * ReturnType * >} CosmosOrchestrationAccountKit */ -/** @typedef {CosmosOrchestrationAccountKit['holder']} StakingAccounHolder */ + +/** + * @param {Zone} zone + * @param {MakeRecorderKit} makeRecorderKit + * @param {ZCF} zcf + * @returns {( + * ...args: Parameters< + * ReturnType + * > + * ) => CosmosOrchestrationAccountKit['holder']} + */ +export const prepareCosmosOrchestrationAccount = ( + zone, + makeRecorderKit, + zcf, +) => { + const makeKit = prepareCosmosOrchestrationAccountKit( + zone, + makeRecorderKit, + zcf, + ); + return (...args) => makeKit(...args).holder; +}; +/** @typedef {CosmosOrchestrationAccountKit['holder']} CosmosOrchestrationAccount */ diff --git a/packages/orchestration/src/facade.js b/packages/orchestration/src/facade.js index 0551b89c2df..46e06fd6bf2 100644 --- a/packages/orchestration/src/facade.js +++ b/packages/orchestration/src/facade.js @@ -1,7 +1,7 @@ /** @file Orchestration service */ import { E } from '@endo/far'; -import { prepareCosmosOrchestrationAccountKit } from './exos/cosmosOrchestrationAccount.js'; +import { prepareCosmosOrchestrationAccount } from './exos/cosmosOrchestrationAccount.js'; /** * @import {Zone} from '@agoric/zone'; @@ -104,12 +104,11 @@ const makeRemoteChainFacade = (name, { orchestration, timer, zcf, zone }) => { allowedQueries: [], }); const makeRecorderKit = () => anyVal; - const makeCosmosOrchestrationAccountKit = - prepareCosmosOrchestrationAccountKit( - zone.subZone(name), - makeRecorderKit, - zcf, - ); + const makeCosmosOrchestrationAccount = prepareCosmosOrchestrationAccount( + zone.subZone(name), + makeRecorderKit, + zcf, + ); return { getChainInfo: async () => chainInfo, @@ -130,13 +129,13 @@ const makeRemoteChainFacade = (name, { orchestration, timer, zcf, zone }) => { // FIXME look up real values const bondDenom = name; - // @ts-expect-error FIXME promise resolution through membrane - return makeCosmosOrchestrationAccountKit(address, bondDenom, { + // @ts-expect-error FIXME missing methods + return makeCosmosOrchestrationAccount(address, bondDenom, { account: icaAccount, storageNode: anyVal, icqConnection: anyVal, timer, - }).holder; + }); }, }; }; From bb21c0425a056be902739e1529a67c39d3df34eb Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 4 Jun 2024 11:02:03 -0700 Subject: [PATCH 10/14] test: types test for interfaces --- .../src/exos/cosmosOrchestrationAccount.js | 10 -------- packages/orchestration/test/types.test-d.ts | 23 ++++++++++++++++++- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/packages/orchestration/src/exos/cosmosOrchestrationAccount.js b/packages/orchestration/src/exos/cosmosOrchestrationAccount.js index 6ed48a2e70c..16cb1b9e659 100644 --- a/packages/orchestration/src/exos/cosmosOrchestrationAccount.js +++ b/packages/orchestration/src/exos/cosmosOrchestrationAccount.js @@ -405,16 +405,6 @@ export const prepareCosmosOrchestrationAccountKit = ( }, ); - /** check holder facet against StakingAccountActions interface. */ - // eslint-disable-next-line no-unused-vars - const typeCheck = () => { - /** @type {any} */ - const arg = null; - /** @satisfies {StakingAccountActions} */ - // eslint-disable-next-line no-unused-vars - const kit = makeCosmosOrchestrationAccountKit(arg, arg, arg).holder; - }; - return makeCosmosOrchestrationAccountKit; }; diff --git a/packages/orchestration/test/types.test-d.ts b/packages/orchestration/test/types.test-d.ts index 4a4e61c7747..37095f7538d 100644 --- a/packages/orchestration/test/types.test-d.ts +++ b/packages/orchestration/test/types.test-d.ts @@ -5,8 +5,15 @@ import { expectNotType, expectType } from 'tsd'; import { typedJson } from '@agoric/cosmic-proto'; import type { MsgDelegateResponse } from '@agoric/cosmic-proto/cosmos/staking/v1beta1/tx.js'; import type { QueryAllBalancesResponse } from '@agoric/cosmic-proto/cosmos/bank/v1beta1/query.js'; -import type { ChainAddress, CosmosValidatorAddress } from '../src/types.js'; +import type { + ChainAddress, + CosmosValidatorAddress, + StakingAccountActions, +} from '../src/types.js'; import type { LocalChainAccountKit } from '../src/exos/local-chain-account-kit.js'; +import { prepareCosmosOrchestrationAccount } from '../src/exos/cosmosOrchestrationAccount.js'; + +const anyVal = null as any; const validatorAddr = { chainId: 'agoric3', @@ -46,3 +53,17 @@ expectNotType(chainAddr); expectType(results[0]); expectType(results[1]); } + +// CosmosOrchestrationAccount interfaces +{ + const makeCosmosOrchestrationAccount = prepareCosmosOrchestrationAccount( + anyVal, + anyVal, + anyVal, + ); + makeCosmosOrchestrationAccount( + anyVal, + anyVal, + anyVal, + ) satisfies StakingAccountActions; +} From 3af2b5c8660d1fb7af217183bffc2f8de0e1cbc5 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 4 Jun 2024 11:20:22 -0700 Subject: [PATCH 11/14] feat(types): ContinuingOfferResult --- packages/smart-wallet/src/offerWatcher.js | 13 ++++++++----- packages/smart-wallet/src/types.d.ts | 5 +++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/smart-wallet/src/offerWatcher.js b/packages/smart-wallet/src/offerWatcher.js index 283adb41547..3b2bc004f62 100644 --- a/packages/smart-wallet/src/offerWatcher.js +++ b/packages/smart-wallet/src/offerWatcher.js @@ -12,8 +12,12 @@ import { deeplyFulfilledObject, objectMap } from '@agoric/internal'; import { UNPUBLISHED_RESULT } from './offers.js'; -/** @import {OfferSpec} from "./offers.js" */ -/** @import {PromiseWatcher} from '@agoric/swingset-liveslots' */ +/** + * @import {OfferSpec} from "./offers.js"; + * @import {ContinuingOfferResult} from "./types.js"; + * @import {Passable} from '@endo/pass-style'; + * @import {PromiseWatcher} from '@agoric/swingset-liveslots'; + */ /** * @template {any} T @@ -22,7 +26,7 @@ import { UNPUBLISHED_RESULT } from './offers.js'; /** * @typedef {{ - * resultWatcher: OfferPromiseWatcher; + * resultWatcher: OfferPromiseWatcher; * numWantsWatcher: OfferPromiseWatcher; * paymentWatcher: OfferPromiseWatcher; * }} OutcomeWatchers @@ -156,7 +160,7 @@ export const prepareOfferWatcher = baggage => { ); }, - /** @param {unknown} result */ + /** @param {Passable | ContinuingOfferResult} result */ publishResult(result) { const { state, facets } = this; @@ -182,7 +186,6 @@ export const prepareOfferWatcher = baggage => { state.invitationAmount, // @ts-expect-error narrowed by passStyle result.invitationMakers, - // @ts-expect-error narrowed by passStyle result.publicSubscribers, ); } diff --git a/packages/smart-wallet/src/types.d.ts b/packages/smart-wallet/src/types.d.ts index 54ad2a8cb0d..4e780451590 100644 --- a/packages/smart-wallet/src/types.d.ts +++ b/packages/smart-wallet/src/types.d.ts @@ -29,6 +29,11 @@ export type InvitationMakers = Record< export type PublicSubscribers = Record>; +export interface ContinuingOfferResult { + invitationMakers: InvitationMakers; + publicSubscribers: PublicSubscribers; +} + export type Cell = { get: () => T; set(val: T): void; From 1549b46d0721dd9cabcf322c5a0110c56411436a Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 4 Jun 2024 11:31:08 -0700 Subject: [PATCH 12/14] feat: asContinuingOffer --- .../src/examples/stakeAtom.contract.js | 37 ++++++++----------- .../src/exos/cosmosOrchestrationAccount.js | 13 +++++++ 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/packages/orchestration/src/examples/stakeAtom.contract.js b/packages/orchestration/src/examples/stakeAtom.contract.js index 504cb200645..eb5812c805d 100644 --- a/packages/orchestration/src/examples/stakeAtom.contract.js +++ b/packages/orchestration/src/examples/stakeAtom.contract.js @@ -8,7 +8,7 @@ import { prepareRecorderKitMakers } from '@agoric/zoe/src/contractSupport'; import { InvitationShape } from '@agoric/zoe/src/typeGuards.js'; import { makeDurableZone } from '@agoric/zone/durable.js'; import { M } from '@endo/patterns'; -import { prepareCosmosOrchestrationAccountKit } from '../exos/cosmosOrchestrationAccount.js'; +import { prepareCosmosOrchestrationAccount } from '../exos/cosmosOrchestrationAccount.js'; const trace = makeTracer('StakeAtom'); /** @@ -61,8 +61,11 @@ export const start = async (zcf, privateArgs, baggage) => { const { makeRecorderKit } = prepareRecorderKitMakers(baggage, marshaller); - const makeCosmosOrchestrationAccountKit = - prepareCosmosOrchestrationAccountKit(zone, makeRecorderKit, zcf); + const makeCosmosOrchestrationAccount = prepareCosmosOrchestrationAccount( + zone, + makeRecorderKit, + zcf, + ); async function makeAccountKit() { const account = await E(orchestration).makeAccount( @@ -77,21 +80,13 @@ export const start = async (zcf, privateArgs, baggage) => { ); const accountAddress = await E(account).getAddress(); trace('account address', accountAddress); - const { holder, invitationMakers } = makeCosmosOrchestrationAccountKit( - accountAddress, - bondDenom, - { - account, - storageNode, - icqConnection, - timer, - }, - ); - return { - publicSubscribers: holder.getPublicTopics(), - invitationMakers, - account: holder, - }; + const holder = makeCosmosOrchestrationAccount(accountAddress, bondDenom, { + account, + storageNode, + icqConnection, + timer, + }); + return holder; } const publicFacet = zone.exo( @@ -103,15 +98,15 @@ export const start = async (zcf, privateArgs, baggage) => { { async makeAccount() { trace('makeAccount'); - const { account } = await makeAccountKit(); - return account; + return makeAccountKit(); }, makeAccountInvitationMaker() { trace('makeCreateAccountInvitation'); return zcf.makeInvitation( async seat => { seat.exit(); - return makeAccountKit(); + const holder = await makeAccountKit(); + return holder.asContinuingOffer(); }, 'wantStakingAccount', undefined, diff --git a/packages/orchestration/src/exos/cosmosOrchestrationAccount.js b/packages/orchestration/src/exos/cosmosOrchestrationAccount.js index 16cb1b9e659..6e699ac0a6f 100644 --- a/packages/orchestration/src/exos/cosmosOrchestrationAccount.js +++ b/packages/orchestration/src/exos/cosmosOrchestrationAccount.js @@ -68,6 +68,11 @@ const { Fail } = assert; /** @see {OrchestrationAccountI} */ export const IcaAccountHolderI = M.interface('IcaAccountHolder', { + asContinuingOffer: M.call().returns({ + publicSubscribers: M.any(), + invitationMakers: M.any(), + holder: M.any(), + }), getPublicTopics: M.call().returns(TopicsRecordShape), getAddress: M.call().returns(ChainAddressShape), getBalance: M.callWhen().optional(M.string()).returns(CoinShape), @@ -251,6 +256,14 @@ export const prepareCosmosOrchestrationAccountKit = ( }, }, holder: { + asContinuingOffer() { + const { holder, invitationMakers } = this.facets; + return harden({ + publicSubscribers: holder.getPublicTopics(), + invitationMakers, + holder, + }); + }, getPublicTopics() { const { topicKit } = this.state; return harden({ From ab9e4490ca85168ab37a642a45c7c0a6c98b7fb3 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 4 Jun 2024 11:47:30 -0700 Subject: [PATCH 13/14] chore: orchestrationAccountMethods --- .../test/bootstrapTests/orchestration.test.ts | 2 +- .../src/exos/cosmosOrchestrationAccount.js | 32 +++++++++++++------ packages/orchestration/src/facade.js | 1 - .../src/utils/orchestrationAccount.js | 19 +++++++++++ 4 files changed, 42 insertions(+), 12 deletions(-) create mode 100644 packages/orchestration/src/utils/orchestrationAccount.js diff --git a/packages/boot/test/bootstrapTests/orchestration.test.ts b/packages/boot/test/bootstrapTests/orchestration.test.ts index 17a2ddc18a8..ddc95ce7c2f 100644 --- a/packages/boot/test/bootstrapTests/orchestration.test.ts +++ b/packages/boot/test/bootstrapTests/orchestration.test.ts @@ -62,7 +62,7 @@ test.serial('stakeAtom - repl-style', async t => { }; await t.notThrowsAsync(EV(account).delegate(validatorAddress, atomAmount)); - const queryRes = await EV(account).getBalance(); + const queryRes = await EV(account).getBalance('uatom'); t.deepEqual(queryRes, { value: 0n, denom: 'uatom' }); const queryUnknownDenom = await EV(account).getBalance('some-invalid-denom'); diff --git a/packages/orchestration/src/exos/cosmosOrchestrationAccount.js b/packages/orchestration/src/exos/cosmosOrchestrationAccount.js index 6e699ac0a6f..cd5bc18e941 100644 --- a/packages/orchestration/src/exos/cosmosOrchestrationAccount.js +++ b/packages/orchestration/src/exos/cosmosOrchestrationAccount.js @@ -16,7 +16,7 @@ import { MsgUndelegateResponse, } from '@agoric/cosmic-proto/cosmos/staking/v1beta1/tx.js'; import { Any } from '@agoric/cosmic-proto/google/protobuf/any.js'; -import { AmountShape, PaymentShape } from '@agoric/ertp'; +import { AmountShape } from '@agoric/ertp'; import { makeTracer } from '@agoric/internal'; import { M } from '@agoric/vat-data'; import { TopicsRecordShape } from '@agoric/zoe/src/contractSupport/index.js'; @@ -27,7 +27,6 @@ import { AmountArgShape, ChainAddressShape, ChainAmountShape, - CoinShape, DelegationShape, } from '../typeGuards.js'; import { @@ -35,10 +34,11 @@ import { maxClockSkew, tryDecodeResponse, } from '../utils/cosmos.js'; +import { orchestrationAccountMethods } from '../utils/orchestrationAccount.js'; import { dateInSeconds } from '../utils/time.js'; /** - * @import {AmountArg, IcaAccount, ChainAddress, CosmosValidatorAddress, ICQConnection, StakingAccountActions, DenomAmount, OrchestrationAccountI} from '../types.js'; + * @import {AmountArg, IcaAccount, ChainAddress, CosmosValidatorAddress, ICQConnection, StakingAccountActions, DenomAmount, OrchestrationAccountI, DenomArg} from '../types.js'; * @import {RecorderKit, MakeRecorderKit} from '@agoric/zoe/src/contractSupport/recorder.js'; * @import {Coin} from '@agoric/cosmic-proto/cosmos/base/v1beta1/coin.js'; * @import {Delegation} from '@agoric/cosmic-proto/cosmos/staking/v1beta1/staking.js'; @@ -68,17 +68,14 @@ const { Fail } = assert; /** @see {OrchestrationAccountI} */ export const IcaAccountHolderI = M.interface('IcaAccountHolder', { + ...orchestrationAccountMethods, asContinuingOffer: M.call().returns({ publicSubscribers: M.any(), invitationMakers: M.any(), holder: M.any(), }), getPublicTopics: M.call().returns(TopicsRecordShape), - getAddress: M.call().returns(ChainAddressShape), - getBalance: M.callWhen().optional(M.string()).returns(CoinShape), - getBalances: M.callWhen().optional(M.string()).returns(M.arrayOf(CoinShape)), delegate: M.callWhen(ChainAddressShape, AmountShape).returns(M.undefined()), - deposit: M.callWhen(PaymentShape).returns(M.undefined()), redelegate: M.callWhen( ChainAddressShape, ChainAddressShape, @@ -359,12 +356,12 @@ export const prepareCosmosOrchestrationAccountKit = ( return harden(coins.map(toDenomAmount)); }, /** - * @param {DenomAmount['denom']} [denom] - defaults to bondDenom + * @param {DenomArg} denom * @returns {Promise} */ async getBalance(denom) { - const { chainAddress, icqConnection, bondDenom } = this.state; - denom ||= bondDenom; + const { chainAddress, icqConnection } = this.state; + // TODO #9211 lookup denom from brand assert.typeof(denom, 'string'); const [result] = await E(icqConnection).query([ @@ -383,6 +380,21 @@ export const prepareCosmosOrchestrationAccountKit = ( return harden(toDenomAmount(balance)); }, + send(toAccount, amount) { + console.log('send got', toAccount, amount); + throw Error('not yet implemented'); + }, + + transfer(amount, msg) { + console.log('transferSteps got', amount, msg); + throw Error('not yet implemented'); + }, + + transferSteps(amount, msg) { + console.log('transferSteps got', amount, msg); + throw Error('not yet implemented'); + }, + withdrawRewards() { throw assert.error('Not implemented'); }, diff --git a/packages/orchestration/src/facade.js b/packages/orchestration/src/facade.js index 46e06fd6bf2..33fb0107e33 100644 --- a/packages/orchestration/src/facade.js +++ b/packages/orchestration/src/facade.js @@ -129,7 +129,6 @@ const makeRemoteChainFacade = (name, { orchestration, timer, zcf, zone }) => { // FIXME look up real values const bondDenom = name; - // @ts-expect-error FIXME missing methods return makeCosmosOrchestrationAccount(address, bondDenom, { account: icaAccount, storageNode: anyVal, diff --git a/packages/orchestration/src/utils/orchestrationAccount.js b/packages/orchestration/src/utils/orchestrationAccount.js new file mode 100644 index 00000000000..b5b325980c1 --- /dev/null +++ b/packages/orchestration/src/utils/orchestrationAccount.js @@ -0,0 +1,19 @@ +import { M } from '@endo/patterns'; +import { PaymentShape } from '@agoric/ertp'; +import { AmountArgShape, ChainAddressShape, CoinShape } from '../typeGuards.js'; + +/** @import {OrchestrationAccountI} from '../orchestration-api.js'; */ + +// TODO complete this interface +/** @see {OrchestrationAccountI} */ +export const orchestrationAccountMethods = { + getAddress: M.call().returns(ChainAddressShape), + getBalance: M.callWhen(M.any()).returns(CoinShape), + getBalances: M.callWhen().returns(M.arrayOf(CoinShape)), + send: M.callWhen(ChainAddressShape, AmountArgShape).returns(M.undefined()), + transfer: M.callWhen(AmountArgShape, ChainAddressShape).returns( + M.undefined(), + ), + transferSteps: M.callWhen(AmountArgShape, M.any()).returns(M.undefined()), + deposit: M.callWhen(PaymentShape).returns(M.undefined()), +}; From 19bc874e26b3257ccf48e93bd454153e5ca8be88 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 4 Jun 2024 13:14:10 -0700 Subject: [PATCH 14/14] chore: remove deposit() from Cosmos acct interface --- packages/orchestration/src/cosmos-api.ts | 2 -- packages/orchestration/src/exos/chainAccountKit.js | 13 +++---------- .../src/exos/cosmosOrchestrationAccount.js | 6 ++++-- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/packages/orchestration/src/cosmos-api.ts b/packages/orchestration/src/cosmos-api.ts index da0f7646df4..134628e4462 100644 --- a/packages/orchestration/src/cosmos-api.ts +++ b/packages/orchestration/src/cosmos-api.ts @@ -196,8 +196,6 @@ export interface IcaAccount { msgs: AnyJson[], opts?: Partial>, ) => Promise; - /** deposit payment from zoe to the account*/ - deposit: (payment: Payment) => Promise; /** get Purse for a brand to .withdraw() a Payment from the account */ getPurse: (brand: Brand) => Promise; /** diff --git a/packages/orchestration/src/exos/chainAccountKit.js b/packages/orchestration/src/exos/chainAccountKit.js index 562702359e5..01f3d92afe5 100644 --- a/packages/orchestration/src/exos/chainAccountKit.js +++ b/packages/orchestration/src/exos/chainAccountKit.js @@ -1,15 +1,15 @@ /** @file ChainAccount exo */ 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 { M } from '@endo/patterns'; -import { PaymentShape, PurseShape } from '@agoric/ertp'; -import { findAddressField } from '../utils/address.js'; import { - ConnectionHandlerI, ChainAddressShape, + ConnectionHandlerI, Proto3Shape, } from '../typeGuards.js'; +import { findAddressField } from '../utils/address.js'; import { makeTxPacket, parseTxPacket } from '../utils/packet.js'; /** @@ -40,7 +40,6 @@ export const ChainAccountI = M.interface('ChainAccount', { .optional(M.record()) .returns(M.promise()), close: M.callWhen().returns(M.undefined()), - deposit: M.callWhen(PaymentShape).returns(M.undefined()), getPurse: M.callWhen().returns(PurseShape), }); @@ -136,12 +135,6 @@ export const prepareChainAccountKit = zone => if (!connection) throw Fail`connection not available`; await E(connection).close(); }, - async deposit(payment) { - console.log('deposit got', payment); - console.error( - 'FIXME deposit noop until https://github.com/Agoric/agoric-sdk/issues/9193', - ); - }, /** * get Purse for a brand to .withdraw() a Payment from the account * diff --git a/packages/orchestration/src/exos/cosmosOrchestrationAccount.js b/packages/orchestration/src/exos/cosmosOrchestrationAccount.js index cd5bc18e941..f1c10cb24ac 100644 --- a/packages/orchestration/src/exos/cosmosOrchestrationAccount.js +++ b/packages/orchestration/src/exos/cosmosOrchestrationAccount.js @@ -302,8 +302,10 @@ export const prepareCosmosOrchestrationAccountKit = ( expect(result, trivialDelegateResponse, 'MsgDelegateResponse'); }, async deposit(payment) { - const { helper } = this.facets; - return E(helper.owned()).deposit(payment); + trace('deposit', payment); + console.error( + 'FIXME deposit noop until https://github.com/Agoric/agoric-sdk/issues/9193', + ); }, async getBalances() { throw Error('not yet implemented');