From b6df6c230a902288f11f6217dbd1ca9701a9a8b6 Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Wed, 12 Jun 2024 17:19:01 -0400 Subject: [PATCH] feat(orchestration): add init-stakeOsmo.js to support .query tests - a better approach seems to be refactoring start-stakeAtom.js to start-stakeIca.js with parameters. buildProposal doesn't seem to accept options so punted for now - TODO: register OSMO in bank --- .../test/bootstrapTests/orchestration.test.ts | 52 +++++++-- .../scripts/orchestration/init-stakeAtom.js | 15 +-- .../scripts/orchestration/init-stakeOsmo.js | 23 ++++ .../src/examples/stakeIca.contract.js | 2 +- .../orchestration/src/exos/chainAccountKit.js | 2 + .../src/exos/cosmosOrchestrationAccount.js | 9 +- .../src/proposals/start-stakeAtom.js | 7 +- .../src/proposals/start-stakeOsmo.js | 109 ++++++++++++++++++ .../test/examples/stake-atom.contract.test.ts | 35 ++---- .../orchestration/test/staking-ops.test.ts | 9 +- .../vm-config/decentral-devnet-config.json | 13 --- 11 files changed, 196 insertions(+), 80 deletions(-) create mode 100644 packages/builders/scripts/orchestration/init-stakeOsmo.js create mode 100644 packages/orchestration/src/proposals/start-stakeOsmo.js diff --git a/packages/boot/test/bootstrapTests/orchestration.test.ts b/packages/boot/test/bootstrapTests/orchestration.test.ts index 1d468e8abc9..4bdc1fc7f4b 100644 --- a/packages/boot/test/bootstrapTests/orchestration.test.ts +++ b/packages/boot/test/bootstrapTests/orchestration.test.ts @@ -72,6 +72,42 @@ test.serial('config', async t => { } }); +test.serial('stakeOsmo - queries', async t => { + const { + buildProposal, + evalProposal, + runUtils: { EV }, + } = t.context; + await evalProposal( + buildProposal('@agoric/builders/scripts/orchestration/init-stakeOsmo.js'), + ); + + const agoricNames = await EV.vat('bootstrap').consumeItem('agoricNames'); + const instance: Instance = await EV(agoricNames).lookup( + 'instance', + 'stakeOsmo', + ); + t.truthy(instance, 'stakeOsmo instance is available'); + + const zoe: ZoeService = await EV.vat('bootstrap').consumeItem('zoe'); + const publicFacet = await EV(zoe).getPublicFacet(instance); + t.truthy(publicFacet, 'stakeOsmo publicFacet is available'); + + const account = await EV(publicFacet).makeAccount(); + t.log('account', account); + t.truthy(account, 'makeAccount returns an account on OSMO connection'); + + const queryRes = await EV(account).getBalance('uatom'); + t.deepEqual(queryRes, { value: 0n, denom: 'uatom' }); + + const queryUnknownDenom = await EV(account).getBalance('some-invalid-denom'); + t.deepEqual( + queryUnknownDenom, + { value: 0n, denom: 'some-invalid-denom' }, + 'getBalance for unknown denom returns value: 0n', + ); +}); + test.serial('stakeAtom - repl-style', async t => { const { buildProposal, @@ -111,15 +147,9 @@ test.serial('stakeAtom - repl-style', async t => { }; await t.notThrowsAsync(EV(account).delegate(validatorAddress, atomAmount)); - const queryRes = await EV(account).getBalance('uatom'); - t.deepEqual(queryRes, { value: 0n, denom: 'uatom' }); - - const queryUnknownDenom = await EV(account).getBalance('some-invalid-denom'); - t.deepEqual( - queryUnknownDenom, - { value: 0n, denom: 'some-invalid-denom' }, - 'getBalance for unknown denom returns value: 0n', - ); + await t.throwsAsync(EV(account).getBalance('uatom'), { + message: 'Queries not available for chain "cosmoshub-4"', + }); }); test.serial('stakeAtom - smart wallet', async t => { @@ -151,9 +181,7 @@ test.serial('stakeAtom - smart wallet', async t => { t.like(wd.getLatestUpdateRecord(), { status: { id: 'request-account', numWantsSatisfied: 1 }, }); - t.like(readLatest('published.stakeAtom.accounts.cosmos1test'), { - sequence: 0n, - }); + t.is(readLatest('published.stakeAtom.accounts.cosmos1test'), ''); const { ATOM } = agoricNamesRemotes.brand; ATOM || Fail`ATOM missing from agoricNames`; diff --git a/packages/builders/scripts/orchestration/init-stakeAtom.js b/packages/builders/scripts/orchestration/init-stakeAtom.js index 94f5ab4aea2..da1ea661073 100644 --- a/packages/builders/scripts/orchestration/init-stakeAtom.js +++ b/packages/builders/scripts/orchestration/init-stakeAtom.js @@ -1,16 +1,7 @@ import { makeHelpers } from '@agoric/deploy-script-support'; /** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */ -export const defaultProposalBuilder = async ( - { publishRef, install }, - options = {}, -) => { - const { - hostConnectionId = 'connection-1', - controllerConnectionId = 'connection-0', - bondDenom = 'uatom', - icqEnabled = true, - } = options; +export const defaultProposalBuilder = async ({ publishRef, install }) => { return harden({ sourceSpec: '@agoric/orchestration/src/proposals/start-stakeAtom.js', getManifestCall: [ @@ -21,10 +12,6 @@ export const defaultProposalBuilder = async ( install('@agoric/orchestration/src/examples/stakeIca.contract.js'), ), }, - hostConnectionId, - controllerConnectionId, - bondDenom, - icqEnabled, }, ], }); diff --git a/packages/builders/scripts/orchestration/init-stakeOsmo.js b/packages/builders/scripts/orchestration/init-stakeOsmo.js new file mode 100644 index 00000000000..7374d3d59a6 --- /dev/null +++ b/packages/builders/scripts/orchestration/init-stakeOsmo.js @@ -0,0 +1,23 @@ +import { makeHelpers } from '@agoric/deploy-script-support'; + +/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */ +export const defaultProposalBuilder = async ({ publishRef, install }) => { + return harden({ + sourceSpec: '@agoric/orchestration/src/proposals/start-stakeOsmo.js', + getManifestCall: [ + 'getManifestForStakeOsmo', + { + installKeys: { + stakeIca: publishRef( + install('@agoric/orchestration/src/examples/stakeIca.contract.js'), + ), + }, + }, + ], + }); +}; + +export default async (homeP, endowments) => { + const { writeCoreEval } = await makeHelpers(homeP, endowments); + await writeCoreEval('start-stakeOsmo', defaultProposalBuilder); +}; diff --git a/packages/orchestration/src/examples/stakeIca.contract.js b/packages/orchestration/src/examples/stakeIca.contract.js index 5c5b14ffb1c..40fc24c08e1 100644 --- a/packages/orchestration/src/examples/stakeIca.contract.js +++ b/packages/orchestration/src/examples/stakeIca.contract.js @@ -137,4 +137,4 @@ export const start = async (zcf, privateArgs, baggage) => { return { publicFacet }; }; -/** @typedef {typeof start} StakeAtomSF */ +/** @typedef {typeof start} StakeIcaSF */ diff --git a/packages/orchestration/src/exos/chainAccountKit.js b/packages/orchestration/src/exos/chainAccountKit.js index 35d20c5583d..187b661ea8e 100644 --- a/packages/orchestration/src/exos/chainAccountKit.js +++ b/packages/orchestration/src/exos/chainAccountKit.js @@ -160,6 +160,8 @@ export const prepareChainAccountKit = zone => this.state.remoteAddress = remoteAddr; this.state.localAddress = localAddr; this.state.chainAddress = harden({ + // FIXME need a fallback value like icacontroller-1-connection-1 if this fails + // https://github.com/Agoric/agoric-sdk/issues/9066 address: findAddressField(remoteAddr) || UNPARSABLE_CHAIN_ADDRESS, chainId: this.state.chainId, addressEncoding: 'bech32', diff --git a/packages/orchestration/src/exos/cosmosOrchestrationAccount.js b/packages/orchestration/src/exos/cosmosOrchestrationAccount.js index 136489ac752..968b61335b7 100644 --- a/packages/orchestration/src/exos/cosmosOrchestrationAccount.js +++ b/packages/orchestration/src/exos/cosmosOrchestrationAccount.js @@ -158,9 +158,8 @@ export const prepareCosmosOrchestrationAccountKit = ( // 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 https://github.com/Agoric/agoric-sdk/issues/9066 - // update sequence after successful executeEncodedTx, _if we want sequence in `vstorage`_ - void E(topicKit.recorder).write(harden({ sequence: 0n })); + // TODO determine what goes in vstorage https://github.com/Agoric/agoric-sdk/issues/9066 + void E(topicKit.recorder).write(''); return { chainAddress, bondDenom, topicKit, ...rest }; }, @@ -366,7 +365,9 @@ export const prepareCosmosOrchestrationAccountKit = ( */ async getBalance(denom) { const { chainAddress, icqConnection } = this.state; - if (!icqConnection) throw Error('Queries not enabled.'); + if (!icqConnection) { + throw Fail`Queries not available for chain ${chainAddress.chainId}`; + } // TODO #9211 lookup denom from brand assert.typeof(denom, 'string'); diff --git a/packages/orchestration/src/proposals/start-stakeAtom.js b/packages/orchestration/src/proposals/start-stakeAtom.js index cde690f509a..f0150404470 100644 --- a/packages/orchestration/src/proposals/start-stakeAtom.js +++ b/packages/orchestration/src/proposals/start-stakeAtom.js @@ -5,7 +5,7 @@ import { makeChainHub } from '../utils/chainHub.js'; /** * @import {IBCConnectionID} from '@agoric/vats'; - * @import {StakeAtomSF, StakeIcaTerms} from '../examples/stakeIca.contract'; + * @import {StakeIcaSF, StakeIcaTerms} from '../examples/stakeIca.contract'; */ const trace = makeTracer('StartStakeAtom', true); @@ -43,8 +43,6 @@ export const startStakeAtom = async ({ const storageNode = await makeStorageNodeChild(chainStorage, VSTORAGE_PATH); const marshaller = await E(board).getPublishingMarshaller(); - const atomIssuer = await E(agoricNames).lookup('issuer', 'ATOM'); - trace('ATOM Issuer', atomIssuer); const chainHub = makeChainHub(await agoricNames); @@ -55,11 +53,10 @@ export const startStakeAtom = async ({ cosmoshub.chainId, ); - /** @type {StartUpgradableOpts} */ + /** @type {StartUpgradableOpts} */ const startOpts = { label: 'stakeAtom', installation: stakeIca, - issuerKeywordRecord: harden({ ATOM: atomIssuer }), terms: { chainId: cosmoshub.chainId, hostConnectionId: connectionInfo.id, diff --git a/packages/orchestration/src/proposals/start-stakeOsmo.js b/packages/orchestration/src/proposals/start-stakeOsmo.js new file mode 100644 index 00000000000..96c8ea69fbe --- /dev/null +++ b/packages/orchestration/src/proposals/start-stakeOsmo.js @@ -0,0 +1,109 @@ +import { makeTracer } from '@agoric/internal'; +import { makeStorageNodeChild } from '@agoric/internal/src/lib-chainStorage.js'; +import { E } from '@endo/far'; +import { makeChainHub } from '../utils/chainHub.js'; + +/** + * @import {IBCConnectionID} from '@agoric/vats'; + * @import {StakeIcaSF} from '../examples/stakeIca.contract'; + */ + +const trace = makeTracer('StartStakeOsmo', true); + +/** + * @param {BootstrapPowers & { + * installation: { + * consume: { + * stakeIca: Installation< + * import('../examples/stakeIca.contract.js').start + * >; + * }; + * }; + * }} powers + */ +export const startStakeOsmo = async ({ + consume: { + agoricNames, + board, + chainStorage, + chainTimerService, + orchestration, + startUpgradable, + }, + installation: { + consume: { stakeIca }, + }, + instance: { + // @ts-expect-error stakeOsmo not typed + produce: { stakeOsmo: produceInstance }, + }, +}) => { + const VSTORAGE_PATH = 'stakeOsmo'; + trace('startStakeOsmo'); + await null; + + const storageNode = await makeStorageNodeChild(chainStorage, VSTORAGE_PATH); + const marshaller = await E(board).getPublishingMarshaller(); + + const chainHub = makeChainHub(await agoricNames); + + const agoric = await chainHub.getChainInfo('agoric'); + const osmosis = await chainHub.getChainInfo('osmosis'); + const connectionInfo = await chainHub.getConnectionInfo( + agoric.chainId, + osmosis.chainId, + ); + + /** @type {StartUpgradableOpts} */ + const startOpts = { + label: 'stakeOsmo', + installation: stakeIca, + terms: { + chainId: osmosis.chainId, + hostConnectionId: connectionInfo.id, + controllerConnectionId: connectionInfo.counterparty.connection_id, + bondDenom: osmosis.stakingTokens[0].denom, + icqEnabled: osmosis.icqEnabled, + }, + privateArgs: { + orchestration: await orchestration, + storageNode, + marshaller, + timer: await chainTimerService, + }, + }; + + const { instance } = await E(startUpgradable)(startOpts); + produceInstance.resolve(instance); +}; +harden(startStakeOsmo); + +export const getManifestForStakeOsmo = ( + { restoreRef }, + { installKeys, ...options }, +) => { + return { + manifest: { + [startStakeOsmo.name]: { + consume: { + agoricNames: true, + board: true, + chainStorage: true, + chainTimerService: true, + orchestration: true, + startUpgradable: true, + }, + installation: { + consume: { stakeIca: true }, + }, + instance: { + produce: { stakeOsmo: true }, + }, + }, + }, + installations: { + stakeIca: restoreRef(installKeys.stakeIca), + }, + options, + }; +}; diff --git a/packages/orchestration/test/examples/stake-atom.contract.test.ts b/packages/orchestration/test/examples/stake-atom.contract.test.ts index 53570a3e9f9..5df7dc624de 100644 --- a/packages/orchestration/test/examples/stake-atom.contract.test.ts +++ b/packages/orchestration/test/examples/stake-atom.contract.test.ts @@ -19,7 +19,7 @@ const startContract = async ({ timer, marshaller, storage, - issuerKeywordRecord, + issuerKeywordRecord = undefined, terms = { chainId: 'cosmoshub-4', hostConnectionId: 'connection-1', @@ -52,15 +52,13 @@ test('makeAccount, getAddress, getBalances, getBalance', async t => { brands: { ist }, utils, } = await commonSetup(t); - const { publicFacet } = await startContract({ - ...bootstrap, - issuerKeywordRecord: { In: ist.issuer }, - }); + const { publicFacet } = await startContract(bootstrap); t.log('make an ICA account'); const account = await E(publicFacet).makeAccount(); t.truthy(account, 'account is returned'); const chainAddress = await E(account).getAddress(); + // FIXME mock remoteAddress in ibc bridge. Currently UNPARSABLE_CHAIN_ADDRESS // t.regex(address.address, /cosmos1/); t.like(chainAddress, { chainId: 'cosmoshub-4', addressEncoding: 'bech32' }); @@ -72,25 +70,17 @@ test('makeAccount, getAddress, getBalances, getBalance', async t => { }); await t.throwsAsync(E(account).getBalance('uatom'), { - message: 'Queries not enabled.', + message: 'Queries not available for chain "cosmoshub-4"', }); }); test('makeAccountInvitationMaker', async t => { - const { - bootstrap, - brands: { ist }, - } = await commonSetup(t); - const { publicFacet, zoe } = await startContract({ - ...bootstrap, - issuerKeywordRecord: { In: ist.issuer }, - }); + const { bootstrap } = await commonSetup(t); + const { publicFacet, zoe } = await startContract(bootstrap); const inv = await E(publicFacet).makeAccountInvitationMaker(); t.log('make an offer for ICA account'); - t.log('inv', inv); const seat = await E(zoe).offer(inv); - t.log('seat', seat); const offerResult = await E(seat).getOfferResult(); t.like(offerResult, { @@ -107,19 +97,14 @@ test('makeAccountInvitationMaker', async t => { const storageUpdate = await E(accountNotifier).getUpdateSince(); t.deepEqual(storageUpdate, { updateCount: 1n, - value: { - sequence: 0n, - }, + value: '', }); // FIXME mock remoteAddress in ibc bridge const storagePath = 'mockChainStorageRoot.stakeAtom.accounts.UNPARSABLE_CHAIN_ADDRESS'; const vstorageEntry = bootstrap.storage.data.get(storagePath); - if (typeof vstorageEntry !== 'string') { - t.fail('vstorageEntry not found'); - } else { - t.log(storagePath, vstorageEntry); - t.regex(vstorageEntry, /sequence/); - } + t.truthy(vstorageEntry, 'vstorage account entry created'); + t.log(storagePath, vstorageEntry); + t.is(bootstrap.marshaller.fromCapData(JSON.parse(vstorageEntry!)), ''); }); diff --git a/packages/orchestration/test/staking-ops.test.ts b/packages/orchestration/test/staking-ops.test.ts index b1c2058b115..fbc873e52d6 100644 --- a/packages/orchestration/test/staking-ops.test.ts +++ b/packages/orchestration/test/staking-ops.test.ts @@ -185,7 +185,7 @@ const makeScenario = () => { const { delegations, startTime } = configStaking; - const { rootNode } = makeFakeStorageKit('mockChainStorageRoot', { + const { rootNode } = makeFakeStorageKit('stakingOpsTest', { sequence: false, }); @@ -209,11 +209,10 @@ const makeScenario = () => { test('makeAccount() writes to storage', async t => { const s = makeScenario(); - const { account, calls, timer } = s; + const { account, timer } = s; const { makeRecorderKit, storageNode, zcf, icqConnection, zone } = s; const make = prepareCosmosOrchestrationAccountKit(zone, makeRecorderKit, zcf); - // Higher fidelity tests below use invitationMakers. const { holder } = make(account.getAddress(), 'uatom', { account, storageNode, @@ -227,9 +226,7 @@ test('makeAccount() writes to storage', async t => { const storageUpdate = await E(accountNotifier).getUpdateSince(); t.deepEqual(storageUpdate, { updateCount: 1n, - value: { - sequence: 0n, - }, + value: '', }); }); diff --git a/packages/vm-config/decentral-devnet-config.json b/packages/vm-config/decentral-devnet-config.json index e93ba27a609..232420684cc 100644 --- a/packages/vm-config/decentral-devnet-config.json +++ b/packages/vm-config/decentral-devnet-config.json @@ -165,19 +165,6 @@ } ] } - ], - [ - { - "module": "@agoric/builders/scripts/orchestration/init-stakeAtom.js", - "entrypoint": "defaultProposalBuilder", - "args": [ - { - "hostConnectionId": "connection-1", - "controllerConnectionId": "connection-0", - "bondDenom": "uatom" - } - ] - } ] ] },