From e88a16a61f3d94751d63bcdb1d3452d28e9fc1f8 Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Tue, 23 Sep 2025 15:18:04 -0500 Subject: [PATCH 1/2] KLUDGE: allow planner to resolve GMP makeAccount calls --- .../portfolio-contract/src/planner.exo.ts | 32 ++++++++++++++++++- .../test/planner.exo.test.ts | 11 +++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/packages/portfolio-contract/src/planner.exo.ts b/packages/portfolio-contract/src/planner.exo.ts index 4555a8f672b..d874ca7c0b8 100644 --- a/packages/portfolio-contract/src/planner.exo.ts +++ b/packages/portfolio-contract/src/planner.exo.ts @@ -3,6 +3,7 @@ * @see {@link preparePlanner} */ import { makeTracer } from '@agoric/internal'; +import type { AxelarChain } from '@agoric/portfolio-api/src/constants.js'; import { type Vow, VowShape, type VowTools } from '@agoric/vow'; import type { ZCF, ZCFSeat } from '@agoric/zoe'; import type { Zone } from '@agoric/zone'; @@ -10,6 +11,7 @@ import { M } from '@endo/patterns'; import type { PortfolioKit } from './portfolio.exo.ts'; import type { MovementDesc, OfferArgsFor } from './type-guards-steps.ts'; import { makeOfferArgsShapes } from './type-guards-steps.ts'; +import type { ChainHub } from '@agoric/orchestration'; const trace = makeTracer('PPLN'); @@ -28,6 +30,7 @@ export const preparePlanner = ( getPortfolio, shapes, vowTools, + chainHubTools, }: { rebalance: ( seat: ZCFSeat, @@ -37,7 +40,8 @@ export const preparePlanner = ( zcf: ZCF; getPortfolio: (id: number) => PortfolioKit; shapes: ReturnType; - vowTools: Pick; + vowTools: Pick; + chainHubTools: Pick; }, ) => { const { movementDescShape } = shapes; @@ -48,6 +52,11 @@ export const preparePlanner = ( M.number(), M.number(), ).returns(VowShape), + UNSAFEresolveEVMAddress: M.callWhen( + M.number(), + M.string(), + M.string(), + ).returns(), }); return zone.exoClass('Planner', PlannerI, () => ({}), { @@ -78,6 +87,27 @@ export const preparePlanner = ( return rebalance(emptySeat, { flow: plan }, pKit); }); }, + + /** KLUDGE - contract MUST NOT rely on planner for authentic remoteAddress */ + async UNSAFEresolveEVMAddress( + portfolioId: number, + chainName: AxelarChain, + remoteAddress: `0x${string}`, + ) { + assert(remoteAddress.startsWith('0x')); + const pKit = getPortfolio(portfolioId); + + const { namespace, reference } = await vowTools.when( + chainHubTools.getChainInfo(chainName), + ); + + pKit.manager.resolveAccount({ + namespace: 'eip155', + chainName, + chainId: `${namespace}:${reference}`, + remoteAddress, + }); + }, }); }; diff --git a/packages/portfolio-contract/test/planner.exo.test.ts b/packages/portfolio-contract/test/planner.exo.test.ts index ee7b027630c..9124c57f19e 100644 --- a/packages/portfolio-contract/test/planner.exo.test.ts +++ b/packages/portfolio-contract/test/planner.exo.test.ts @@ -3,6 +3,7 @@ import { test } from '@agoric/zoe/tools/prepare-test-env-ava.js'; import { makeIssuerKit } from '@agoric/ertp'; import { makeFakeStorageKit } from '@agoric/internal/src/storage-test-utils.js'; import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js'; +import type { ActualChainInfo } from '@agoric/orchestration'; import { makeFakeBoard } from '@agoric/vats/tools/board-utils.js'; import { prepareVowTools } from '@agoric/vow'; import type { ZCF } from '@agoric/zoe'; @@ -58,6 +59,16 @@ test('planner exo submit method', async t => { getPortfolio: mockGetPortfolio, shapes: makeOfferArgsShapes(USDC), vowTools: vt, + chainHubTools: { + getChainInfo: (_c: K) => + vt.asVow( + async () => + ({ + namespace: 'eip155', + reference: '1234', + }) as unknown as ActualChainInfo, + ), + }, }); const planner = makePlanner(); From 91430ccbf4f4e0291bccb63a054f392b378db81a Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Tue, 23 Sep 2025 15:26:14 -0500 Subject: [PATCH 2/2] feat(ymax-tool): UNSAFEresolveEVMAddress example: $ MNEMONIC='abc...' ./scripts/ymax-tool.ts --resolve-account-for 3 --chainName Arbitrum --unsafeRemoteAddress 0x23424 --- multichain-testing/scripts/ymax-tool.ts | 28 ++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/multichain-testing/scripts/ymax-tool.ts b/multichain-testing/scripts/ymax-tool.ts index b6c534705ff..d74b752473d 100755 --- a/multichain-testing/scripts/ymax-tool.ts +++ b/multichain-testing/scripts/ymax-tool.ts @@ -43,7 +43,10 @@ import { objectMap, type TypedPattern, } from '@agoric/internal'; -import { YieldProtocol } from '@agoric/portfolio-api/src/constants.js'; +import { + AxelarChain, + YieldProtocol, +} from '@agoric/portfolio-api/src/constants.js'; import type { OfferStatus } from '@agoric/smart-wallet/src/offers.js'; import type { NameHub } from '@agoric/vats'; import type { StartedInstanceKit as ZStarted } from '@agoric/zoe/src/zoeService/utils'; @@ -88,6 +91,9 @@ const parseToolArgs = (argv: string[]) => invitePlanner: { type: 'string' }, pruneStorage: { type: 'boolean', default: false }, 'submit-for': { type: 'string' }, + 'resolve-account-for': { type: 'string' }, + unsafeRemoteAddress: { type: 'string' }, + chainName: { type: 'string' }, help: { type: 'boolean', short: 'h', default: false }, }, allowPositionals: false, @@ -433,6 +439,26 @@ const main = async ( return; } + if (values['resolve-account-for']) { + const portfolioId = Number(values['resolve-account-for']); + const { chainName, unsafeRemoteAddress: remoteAddress } = values; + const planner = walletStore.get('planner'); + trace( + 'KLUDGE!!! resolve', + chainName, + 'account for', + portfolioId, + 'to', + remoteAddress, + ); + await planner.UNSAFEresolveEVMAddress( + portfolioId, + chainName as AxelarChain, + remoteAddress as `0x${string}`, + ); + return; + } + const positionData = parseTypedJSON(values.positions, GoalDataShape); const targetAllocation = values['target-allocation'] ? parseTypedJSON(