diff --git a/multichain-testing/test/send-anywhere.test.ts b/multichain-testing/test/send-anywhere.test.ts index 717e1b5282e..376853600f0 100644 --- a/multichain-testing/test/send-anywhere.test.ts +++ b/multichain-testing/test/send-anywhere.test.ts @@ -10,6 +10,8 @@ import { createWallet } from '../tools/wallet.js'; import { AmountMath } from '@agoric/ertp'; import { makeQueryClient } from '../tools/query.js'; import type { Amount } from '@agoric/ertp/src/types.js'; +import chainInfo from '../starship-chain-info.js'; +import { denomHash, withChainCapabilities } from '@agoric/orchestration'; const test = anyTest as TestFn; @@ -17,7 +19,7 @@ const accounts = ['osmosis1', 'osmosis2', 'cosmoshub1', 'cosmoshub2']; const contractName = 'sendAnywhere'; const contractBuilder = - '../packages/builders/scripts/testing/start-send-anywhere.js'; + '../packages/builders/scripts/testing/init-send-anywhere.js'; test.before(async t => { const { deleteTestKeys, setupTestKeys, ...rest } = await commonSetup(t); @@ -25,7 +27,36 @@ test.before(async t => { const wallets = await setupTestKeys(accounts); t.context = { ...rest, wallets, deleteTestKeys }; const { startContract } = rest; - await startContract(contractName, contractBuilder); + + const assetInfo = { + uosmo: { + baseName: 'osmosis', + chainName: 'osmosis', + baseDenom: 'uosmo', + }, + [`ibc/${denomHash({ denom: 'uosmo', channelId: chainInfo.agoric.connections['osmosislocal'].transferChannel.channelId })}`]: + { + baseName: 'osmosis', + chainName: 'agoric', + baseDenom: 'uosmo', + }, + uatom: { + baseName: 'cosmoshub', + chainName: 'cosmoshub', + baseDenom: 'uatom', + }, + [`ibc/${denomHash({ denom: 'uatom', channelId: chainInfo.agoric.connections['gaialocal'].transferChannel.channelId })}`]: + { + baseName: 'cosmoshub', + chainName: 'agoric', + baseDenom: 'uatom', + }, + }; + + await startContract(contractName, contractBuilder, { + chainInfo: JSON.stringify(withChainCapabilities(chainInfo)), + assetInfo: JSON.stringify(assetInfo), + }); }); test.after(async t => { diff --git a/packages/boot/test/orchestration/restart-contracts.test.ts b/packages/boot/test/orchestration/restart-contracts.test.ts index a8f5f56511a..790f58e5d44 100644 --- a/packages/boot/test/orchestration/restart-contracts.test.ts +++ b/packages/boot/test/orchestration/restart-contracts.test.ts @@ -32,7 +32,7 @@ test.serial('send-anywhere', async t => { t.log('start send-anywhere'); await evalProposal( - buildProposal('@agoric/builders/scripts/testing/start-send-anywhere.js'), + buildProposal('@agoric/builders/scripts/testing/init-send-anywhere.js'), ); t.log('making offer'); diff --git a/packages/builders/scripts/testing/init-send-anywhere.js b/packages/builders/scripts/testing/init-send-anywhere.js new file mode 100644 index 00000000000..51604ee287d --- /dev/null +++ b/packages/builders/scripts/testing/init-send-anywhere.js @@ -0,0 +1,73 @@ +import { makeHelpers } from '@agoric/deploy-script-support'; +import { + getManifest, + startSendAnywhere, +} from '@agoric/orchestration/src/proposals/start-send-anywhere.js'; +import { parseArgs } from 'node:util'; + +/** + * @import {ParseArgsConfig} from 'node:util' + */ + +const chainInfoUsage = 'use --chainInfo chainName:CosmosChainInfo ...'; +const assetInfoUsage = + 'use --assetInfo denom:DenomInfo & {brandKey?: string} ...'; + +/** @type {ParseArgsConfig['options']} */ +const parserOpts = { + chainInfo: { type: 'string' }, + assetInfo: { type: 'string' }, +}; + +/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */ +export const defaultProposalBuilder = async ( + { publishRef, install }, + options, +) => + harden({ + sourceSpec: '@agoric/orchestration/src/proposals/start-send-anywhere.js', + getManifestCall: [ + getManifest.name, + { + installationRef: publishRef( + install( + '@agoric/orchestration/src/examples/send-anywhere.contract.js', + ), + ), + options, + }, + ], + }); + +/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').DeployScriptFunction} */ +export default async (homeP, endowments) => { + const { scriptArgs } = endowments; + + const { + values: { chainInfo, assetInfo }, + } = parseArgs({ + args: scriptArgs, + options: parserOpts, + }); + + const parseChainInfo = () => { + if (!chainInfo) throw Error(chainInfoUsage); + if (typeof chainInfo !== 'string') throw Error('chainInfo must be string'); + return JSON.parse(chainInfo); + }; + const parseAssetInfo = () => { + if (!assetInfo) throw Error(assetInfoUsage); + if (typeof assetInfo !== 'string') throw Error('assetInfo must be string'); + return JSON.parse(assetInfo); + }; + const opts = harden({ + chainInfo: parseChainInfo(), + assetInfo: parseAssetInfo(), + }); + + const { writeCoreEval } = await makeHelpers(homeP, endowments); + + await writeCoreEval(startSendAnywhere.name, utils => + defaultProposalBuilder(utils, opts), + ); +}; diff --git a/packages/orchestration/src/examples/send-anywhere.contract.js b/packages/orchestration/src/examples/send-anywhere.contract.js index 3cfab6ec922..f44e24824c1 100644 --- a/packages/orchestration/src/examples/send-anywhere.contract.js +++ b/packages/orchestration/src/examples/send-anywhere.contract.js @@ -4,6 +4,7 @@ import { M } from '@endo/patterns'; import { prepareChainHubAdmin } from '../exos/chain-hub-admin.js'; import { AnyNatAmountShape } from '../typeGuards.js'; import { withOrchestration } from '../utils/start-helper.js'; +import { registerChainsAndAssets } from '../utils/chain-hub-helper.js'; import * as flows from './send-anywhere.flows.js'; import * as sharedFlows from './shared.flows.js'; @@ -11,6 +12,7 @@ import * as sharedFlows from './shared.flows.js'; * @import {Vow} from '@agoric/vow'; * @import {Zone} from '@agoric/zone'; * @import {OrchestrationPowers, OrchestrationTools} from '../utils/start-helper.js'; + * @import {CosmosChainInfo, Denom, DenomDetail} from '@agoric/orchestration'; */ export const SingleNatAmountRecord = M.and( @@ -27,6 +29,8 @@ harden(SingleNatAmountRecord); * @param {ZCF} zcf * @param {OrchestrationPowers & { * marshaller: Marshaller; + * chainInfo: Record; + * assetInfo: Record; * }} privateArgs * @param {Zone} zone * @param {OrchestrationTools} tools @@ -82,6 +86,13 @@ export const contract = async ( }, ); + registerChainsAndAssets( + chainHub, + zcf.getTerms().brands, + privateArgs.chainInfo, + privateArgs.assetInfo, + ); + return { publicFacet, creatorFacet }; }; harden(contract); diff --git a/packages/builders/scripts/testing/start-send-anywhere.js b/packages/orchestration/src/proposals/start-send-anywhere.js similarity index 53% rename from packages/builders/scripts/testing/start-send-anywhere.js rename to packages/orchestration/src/proposals/start-send-anywhere.js index e29d043ccb8..a50d87f3f7f 100644 --- a/packages/builders/scripts/testing/start-send-anywhere.js +++ b/packages/orchestration/src/proposals/start-send-anywhere.js @@ -1,7 +1,3 @@ -/** - * @file This is for use in tests in a3p-integration - * Unlike most builder scripts, this one includes the proposal exports as well. - */ import { deeplyFulfilledObject, makeTracer, @@ -12,6 +8,7 @@ import { E } from '@endo/far'; /// /** * @import {Installation} from '@agoric/zoe/src/zoeService/utils.js'; + * @import {CosmosChainInfo, Denom, DenomDetail} from '@agoric/orchestration'; */ const trace = makeTracer('StartSA', true); @@ -28,28 +25,37 @@ const trace = makeTracer('StartSA', true); * }; * }; * }} powers + * @param {{ + * options: { + * chainInfo: Record; + * assetInfo: Record; + * }; + * }} config */ -export const startSendAnywhere = async ({ - consume: { - agoricNames, - board, - chainStorage, - chainTimerService, - cosmosInterchainService, - localchain, - startUpgradable, - }, - installation: { - consume: { sendAnywhere }, - }, - instance: { - // @ts-expect-error unknown instance - produce: { sendAnywhere: produceInstance }, - }, - issuer: { - consume: { IST }, +export const startSendAnywhere = async ( + { + consume: { + agoricNames, + board, + chainStorage, + chainTimerService, + cosmosInterchainService, + localchain, + startUpgradable, + }, + installation: { + consume: { sendAnywhere }, + }, + instance: { + // @ts-expect-error unknown instance + produce: { sendAnywhere: produceInstance }, + }, + issuer: { + consume: { IST }, + }, }, -}) => { + { options: { chainInfo, assetInfo } }, +) => { trace(startSendAnywhere.name); const marshaller = await E(board).getReadonlyMarshaller(); @@ -64,6 +70,8 @@ export const startSendAnywhere = async ({ 'send-anywhere', ), timerService: chainTimerService, + chainInfo, + assetInfo, }), ); @@ -78,7 +86,7 @@ export const startSendAnywhere = async ({ }; harden(startSendAnywhere); -export const getManifest = ({ restoreRef }, { installationRef }) => { +export const getManifest = ({ restoreRef }, { installationRef, options }) => { return { manifest: { [startSendAnywhere.name]: { @@ -106,31 +114,6 @@ export const getManifest = ({ restoreRef }, { installationRef }) => { installations: { sendAnywhere: restoreRef(installationRef), }, + options, }; }; - -/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */ -export const defaultProposalBuilder = async ({ publishRef, install }) => - harden({ - // Somewhat unorthodox, source the exports from this builder module - sourceSpec: '@agoric/builders/scripts/testing/start-send-anywhere.js', - getManifestCall: [ - getManifest.name, - { - installationRef: publishRef( - install( - '@agoric/orchestration/src/examples/send-anywhere.contract.js', - ), - ), - }, - ], - }); - -/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').DeployScriptFunction} */ -export default async (homeP, endowments) => { - // import dynamically so the module can work in CoreEval environment - const dspModule = await import('@agoric/deploy-script-support'); - const { makeHelpers } = dspModule; - const { writeCoreEval } = await makeHelpers(homeP, endowments); - await writeCoreEval(startSendAnywhere.name, defaultProposalBuilder); -};