diff --git a/packages/orchestration/src/exos/cosmos-orchestration-account.js b/packages/orchestration/src/exos/cosmos-orchestration-account.js index fc24f954ec0b..f63b2ae27e51 100644 --- a/packages/orchestration/src/exos/cosmos-orchestration-account.js +++ b/packages/orchestration/src/exos/cosmos-orchestration-account.js @@ -17,7 +17,7 @@ import { } from '@agoric/cosmic-proto/cosmos/staking/v1beta1/tx.js'; import { Any } from '@agoric/cosmic-proto/google/protobuf/any.js'; import { MsgTransfer } from '@agoric/cosmic-proto/ibc/applications/transfer/v1/tx.js'; -import { makeTracer, NonNullish } from '@agoric/internal'; +import { makeTracer } from '@agoric/internal'; import { Shape as NetworkShape } from '@agoric/network'; import { M } from '@agoric/vat-data'; import { VowShape } from '@agoric/vow'; @@ -31,7 +31,7 @@ import { DenomAmountShape, IBCTransferOptionsShape, } from '../typeGuards.js'; -import { coerceDenom } from '../utils/amounts.js'; +import { coerceCoin, coerceDenom } from '../utils/amounts.js'; import { maxClockSkew, tryDecodeResponse } from '../utils/cosmos.js'; import { orchestrationAccountMethods } from '../utils/orchestrationAccount.js'; import { makeTimestampHelper } from '../utils/time.js'; @@ -215,17 +215,7 @@ export const prepareCosmosOrchestrationAccountKit = ( * @returns {Coin} */ amountToCoin(amount) { - const denom = - 'denom' in amount - ? amount.denom - : NonNullish( - chainHub.lookupDenom(amount.brand), - `No denomination for brand ${amount.brand}`, - ); - return harden({ - denom, - amount: String(amount.value), - }); + return coerceCoin(chainHub, amount); }, }, balanceQueryWatcher: { diff --git a/packages/orchestration/src/exos/local-orchestration-account.js b/packages/orchestration/src/exos/local-orchestration-account.js index c2f8a0d2c1a5..96d5621b5fd2 100644 --- a/packages/orchestration/src/exos/local-orchestration-account.js +++ b/packages/orchestration/src/exos/local-orchestration-account.js @@ -20,6 +20,7 @@ import { orchestrationAccountMethods } from '../utils/orchestrationAccount.js'; import { makeTimestampHelper } from '../utils/time.js'; import { preparePacketTools } from './packet-tools.js'; import { prepareIBCTools } from './ibc-packet.js'; +import { coerceCoin, coerceDenomAmount } from '../utils/amounts.js'; /** * @import {HostOf} from '@agoric/async-flow'; @@ -175,15 +176,7 @@ export const prepareLocalOrchestrationAccountKit = ( * @returns {Coin} */ amountToCoin(amount) { - if (!('denom' in amount)) { - // FIXME(#9211) look up values from brands - trace('TODO #9211: handle brand', amount); - throw Fail`Brands not currently supported.`; - } - return harden({ - denom: amount.denom, - amount: String(amount.value), - }); + return coerceCoin(chainHub, amount); }, }, invitationMakers: { @@ -437,13 +430,10 @@ export const prepareLocalOrchestrationAccountKit = ( * @param {Amount<'nat'>} ertpAmount */ delegate(validatorAddress, ertpAmount) { - // TODO #9211 lookup denom from brand - const amount = { - amount: String(ertpAmount.value), - denom: 'ubld', - }; const { account: lca } = this.state; + const amount = coerceCoin(chainHub, ertpAmount); + return watch( E(lca).executeTx([ typedJson('/cosmos.staking.v1beta1.MsgDelegate', { @@ -462,11 +452,7 @@ export const prepareLocalOrchestrationAccountKit = ( * @returns {Vow} */ undelegate(validatorAddress, ertpAmount) { - // TODO #9211 lookup denom from brand - const amount = { - amount: String(ertpAmount.value), - denom: 'ubld', - }; + const amount = coerceCoin(chainHub, ertpAmount); const { account: lca } = this.state; return watch( E(lca).executeTx([ @@ -557,8 +543,6 @@ export const prepareLocalOrchestrationAccountKit = ( transfer(amount, destination, opts) { return asVow(() => { trace('Transferring funds from LCA over IBC'); - // TODO #9211 lookup denom from brand - if ('brand' in amount) throw Fail`ERTP Amounts not yet supported`; const connectionInfoV = watch( chainHub.getConnectionInfo( @@ -580,7 +564,11 @@ export const prepareLocalOrchestrationAccountKit = ( const resultV = watch( allVows([connectionInfoV, timeoutTimestampVowOrValue]), this.facets.transferWatcher, - { opts, amount, destination }, + { + opts, + amount: coerceDenomAmount(chainHub, amount), + destination, + }, ); return resultV; }); diff --git a/packages/orchestration/test/exos/local-orchestration-account-kit.test.ts b/packages/orchestration/test/exos/local-orchestration-account-kit.test.ts index 5930fe84ebff..54bc1ae4274a 100644 --- a/packages/orchestration/test/exos/local-orchestration-account-kit.test.ts +++ b/packages/orchestration/test/exos/local-orchestration-account-kit.test.ts @@ -2,20 +2,20 @@ import { test } from '@agoric/zoe/tools/prepare-test-env-ava.js'; import { AmountMath } from '@agoric/ertp'; import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js'; -import { heapVowE as VE } from '@agoric/vow/vat.js'; import { TargetApp } from '@agoric/vats/src/bridge-target.js'; import { SIMULATED_ERRORS } from '@agoric/vats/tools/fake-bridge.js'; +import { heapVowE as VE } from '@agoric/vow/vat.js'; import { ChainAddress, type AmountArg } from '../../src/orchestration-api.js'; +import { maxClockSkew } from '../../src/utils/cosmos.js'; import { NANOSECONDS_PER_SECOND } from '../../src/utils/time.js'; -import { commonSetup } from '../supports.js'; +import { buildVTransferEvent } from '../../tools/ibc-mocks.js'; import { UNBOND_PERIOD_SECONDS } from '../ibc-mocks.js'; -import { maxClockSkew } from '../../src/utils/cosmos.js'; +import { commonSetup } from '../supports.js'; import { prepareMakeTestLOAKit } from './make-test-loa-kit.js'; -import { buildVTransferEvent } from '../../tools/ibc-mocks.js'; test('deposit, withdraw', async t => { const common = await commonSetup(t); - const makeTestLOAKit = prepareMakeTestLOAKit(t, common.bootstrap); + const makeTestLOAKit = prepareMakeTestLOAKit(t, common); const account = await makeTestLOAKit(); const { @@ -27,8 +27,10 @@ test('deposit, withdraw', async t => { t.log('deposit 100 bld to account'); await VE(account).deposit(oneHundredStakePmt); - // FIXME #9211 - // t.deepEqual(await E(account).getBalance('ubld'), stake.units(100)); + t.deepEqual(await VE(account).getBalance('ubld'), { + denom: 'ubld', + value: stake.units(100).value, + }); // XXX races in the bridge await eventLoopIteration(); @@ -58,7 +60,7 @@ test('deposit, withdraw', async t => { test('delegate, undelegate', async t => { const common = await commonSetup(t); - const makeTestLOAKit = prepareMakeTestLOAKit(t, common.bootstrap); + const makeTestLOAKit = prepareMakeTestLOAKit(t, common); const account = await makeTestLOAKit(); const { @@ -94,7 +96,7 @@ test('delegate, undelegate', async t => { test('transfer', async t => { const common = await commonSetup(t); - const makeTestLOAKit = prepareMakeTestLOAKit(t, common.bootstrap); + const makeTestLOAKit = prepareMakeTestLOAKit(t, common); const account = await makeTestLOAKit(); const { value: sender } = await VE(account).getAddress(); @@ -111,8 +113,10 @@ test('transfer', async t => { t.log('deposit 100 bld to account'); await VE(account).deposit(oneHundredStakePmt); - // FIXME #9211 - // t.deepEqual(await E(account).getBalance('ubld'), stake.units(100)); + t.deepEqual(await VE(account).getBalance('ubld'), { + denom: 'ubld', + value: stake.units(100).value, + }); const destination: ChainAddress = { chainId: 'cosmoshub-4', @@ -144,12 +148,6 @@ test('transfer', async t => { return { transferP }; }; - // TODO #9211, support ERTP amounts - t.log('ERTP Amounts not yet supported for AmountArg'); - await t.throwsAsync(() => VE(account).transfer(stake.units(1), destination), { - message: 'ERTP Amounts not yet supported', - }); - t.log('.transfer() 1 bld to cosmos using DenomAmount'); const { transferP } = await startTransfer( { denom: 'ubld', value: 1_000_000n }, @@ -247,7 +245,7 @@ test('transfer', async t => { test('monitor transfers', async t => { const common = await commonSetup(t); - const makeTestLOAKit = prepareMakeTestLOAKit(t, common.bootstrap); + const makeTestLOAKit = prepareMakeTestLOAKit(t, common); const account = await makeTestLOAKit(); const { mocks: { transferBridge }, @@ -290,15 +288,15 @@ test('monitor transfers', async t => { }); test('send', async t => { - const { - bootstrap, - brands: { bld: stake, ist: stable }, - utils: { pourPayment, inspectLocalBridge }, - } = await commonSetup(t); - const makeTestLOAKit = prepareMakeTestLOAKit(t, bootstrap); + const common = await commonSetup(t); + const makeTestLOAKit = prepareMakeTestLOAKit(t, common); const account = await makeTestLOAKit(); t.truthy(account, 'account is returned'); + const { + brands: { bld: stake, ist: stable }, + utils: { pourPayment, inspectLocalBridge }, + } = common; const oneHundredStakePmt = await pourPayment(stake.units(100)); const oneHundredStablePmt = await pourPayment(stable.units(100)); t.log('deposit 100 bld to account'); @@ -313,10 +311,7 @@ test('send', async t => { }; t.log(`send 10 bld to ${toAddress.value}`); - await t.throwsAsync(VE(account).send(toAddress, stake.units(10)), { - message: 'Brands not currently supported.', - }); - await VE(account).send(toAddress, { denom: 'ubld', value: 10_000_000n }); + await VE(account).send(toAddress, stake.units(10)); // this would normally fail since we do not have ibc/1234 in our wallet, // but the mocked localchain bridge doesn't currently know about balances diff --git a/packages/orchestration/test/exos/make-test-loa-kit.ts b/packages/orchestration/test/exos/make-test-loa-kit.ts index 018aa638fd5e..239c5a461bc7 100644 --- a/packages/orchestration/test/exos/make-test-loa-kit.ts +++ b/packages/orchestration/test/exos/make-test-loa-kit.ts @@ -1,9 +1,13 @@ +/* eslint-disable jsdoc/require-param -- ts types */ +import { makeIssuerKit } from '@agoric/ertp'; import { heapVowE as E } from '@agoric/vow/vat.js'; import { prepareRecorderKitMakers } from '@agoric/zoe/src/contractSupport/recorder.js'; +import { withAmountUtils } from '@agoric/zoe/tools/test-utils.js'; import { Far } from '@endo/far'; import { ExecutionContext } from 'ava'; -import { prepareLocalOrchestrationAccountKit } from '../../src/exos/local-orchestration-account.js'; import { makeChainHub } from '../../src/exos/chain-hub.js'; +import { prepareLocalOrchestrationAccountKit } from '../../src/exos/local-orchestration-account.js'; +import fetchedChainInfo from '../../src/fetched-chain-info.js'; import { commonSetup } from '../supports.js'; /** @@ -13,15 +17,13 @@ import { commonSetup } from '../supports.js'; * * Helps reduce boilerplate in test files, and retains testing context through * parameterized endowments. - * - * @param t - * @param bootstrap - * @param opts - * @param opts.zcf */ export const prepareMakeTestLOAKit = ( t: ExecutionContext, - bootstrap: Awaited>['bootstrap'], + { + bootstrap, + brands, + }: Pick>, 'bootstrap' | 'brands'>, { zcf = Far('MockZCF', {}) } = {}, ) => { const { timer, localchain, marshaller, rootZone, vowTools, agoricNames } = @@ -32,6 +34,7 @@ export const prepareMakeTestLOAKit = ( marshaller, ); + const chainHub = makeChainHub(agoricNames, vowTools); const makeLocalOrchestrationAccountKit = prepareLocalOrchestrationAccountKit( rootZone, makeRecorderKit, @@ -39,9 +42,18 @@ export const prepareMakeTestLOAKit = ( zcf, timer, vowTools, - makeChainHub(agoricNames, vowTools), + chainHub, ); + const bld = withAmountUtils(makeIssuerKit('BLD')); + chainHub.registerChain('agoric', fetchedChainInfo.agoric); + chainHub.registerAsset('ubld', { + chainName: 'agoric', + baseName: 'agoric', + baseDenom: 'ubld', + brand: brands.bld.brand, + }); + return async ({ storageNode = bootstrap.storage.rootNode.makeChildNode('accounts'), } = {}) => { diff --git a/packages/orchestration/test/exos/portfolio-holder-kit.test.ts b/packages/orchestration/test/exos/portfolio-holder-kit.test.ts index 5c215731212a..53255f27610d 100644 --- a/packages/orchestration/test/exos/portfolio-holder-kit.test.ts +++ b/packages/orchestration/test/exos/portfolio-holder-kit.test.ts @@ -7,8 +7,8 @@ import { prepareMakeTestLOAKit } from './make-test-loa-kit.js'; import { prepareMakeTestCOAKit } from './make-test-coa-kit.js'; test('portfolio holder kit behaviors', async t => { - const { bootstrap } = await commonSetup(t); - const { rootZone, storage, vowTools } = bootstrap; + const common = await commonSetup(t); + const { rootZone, storage, vowTools } = common.bootstrap; const storageNode = storage.rootNode.makeChildNode('accounts'); /** @@ -23,8 +23,10 @@ test('portfolio holder kit behaviors', async t => { }, }); - const makeTestCOAKit = prepareMakeTestCOAKit(t, bootstrap, { zcf: mockZcf }); - const makeTestLOAKit = prepareMakeTestLOAKit(t, bootstrap, { zcf: mockZcf }); + const makeTestCOAKit = prepareMakeTestCOAKit(t, common.bootstrap, { + zcf: mockZcf, + }); + const makeTestLOAKit = prepareMakeTestLOAKit(t, common, { zcf: mockZcf }); const makeCosmosAccount = async ({ chainId, hostConnectionId,