Skip to content

Commit

Permalink
feat: local-orch-account .transfer() supports pfm routes (#10571)
Browse files Browse the repository at this point in the history
refs: #10445 

## Description

- leverages `ChainHub.makeTransferRoute` to support PFM routing in `LocalOrchAccount.transfer()`
- updates test harness to supply chain and asset info for `chainHub` in exo and contract tests
- refactors send-anywhere `contract-upgrade.test.ts` to no longer rely on a buggy `agoricNames`
- updates several orchestration examples contracts to seed their own `chainHub` to facilitate boot and multichain testing

### Security Considerations
No new considerations from these changes.

### Scaling Considerations
No new considerations from these changes.

### Documentation Considerations
None

### Testing Considerations
Includes unit tests. See #10584 for more robust testing of the pfm route logic.  Existing `multichain-testing` will cover potential regressions (single-hop) transfers. Multi-hop tests are forthcoming.

### Upgrade Considerations
N/A, library code. Part of NPM Orch or FUSDC release.
  • Loading branch information
mergify[bot] authored Dec 4, 2024
2 parents 13796d6 + a2d491f commit 9b8cad2
Show file tree
Hide file tree
Showing 49 changed files with 1,986 additions and 479 deletions.
2 changes: 0 additions & 2 deletions a3p-integration/proposals/f:fast-usdc/package.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
{
"agoricProposal": {
"source": "subdir",
"$UNTIL": "write-chain-info to agoricNames until #10445 and chainHub setup",
"sdk-generate": [
"orchestration/write-chain-info.js",
"fast-usdc/init-fast-usdc.js submission --net A3P_INTEGRATION"
],
"type": "/agoric.swingset.CoreEvalProposal"
Expand Down
21 changes: 11 additions & 10 deletions multichain-testing/test/auto-stake-it.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { CosmosChainInfo } from '@agoric/orchestration';
import anyTest from '@endo/ses-ava/prepare-endo.js';
import type { ExecutionContext, TestFn } from 'ava';
import chainInfo from '../starship-chain-info.js';
import starshipChainInfo from '../starship-chain-info.js';
import { makeDoOffer } from '../tools/e2e-tools.js';
import {
createFundedWalletAndClient,
Expand All @@ -18,15 +17,19 @@ const accounts = ['agoricAdmin', 'cosmoshub', 'osmosis'];

const contractName = 'autoAutoStakeIt';
const contractBuilder =
'../packages/builders/scripts/testing/start-auto-stake-it.js';
'../packages/builders/scripts/testing/init-auto-stake-it.js';

test.before(async t => {
const { deleteTestKeys, setupTestKeys, ...rest } = await commonSetup(t);
const { setupTestKeys, ...common } = await commonSetup(t);
const { assetInfo, chainInfo, deleteTestKeys, startContract } = common;
deleteTestKeys(accounts).catch();
const wallets = await setupTestKeys(accounts);
t.context = { ...rest, wallets, deleteTestKeys };
const { startContract } = rest;
await startContract(contractName, contractBuilder);
t.context = { ...common, wallets };

await startContract(contractName, contractBuilder, {
chainInfo,
assetInfo,
});
});

test.after(async t => {
Expand Down Expand Up @@ -96,9 +99,7 @@ const autoStakeItScenario = test.macro({
const fundAndTransfer = makeFundAndTransfer(t);

// 2. Find 'stakingDenom' denom on agoric
const remoteChainInfo = (chainInfo as Record<string, CosmosChainInfo>)[
chainName
];
const remoteChainInfo = starshipChainInfo[chainName];
const stakingDenom = remoteChainInfo?.stakingTokens?.[0].denom;
if (!stakingDenom) throw Error(`staking denom found for ${chainName}`);

Expand Down
11 changes: 7 additions & 4 deletions multichain-testing/test/basic-flows.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@ const contractBuilder =
'../packages/builders/scripts/orchestration/init-basic-flows.js';

test.before(async t => {
const { deleteTestKeys, setupTestKeys, ...rest } = await commonSetup(t);
const { setupTestKeys, ...common } = await commonSetup(t);
const { assetInfo, chainInfo, deleteTestKeys, startContract } = common;
deleteTestKeys(accounts).catch();
const wallets = await setupTestKeys(accounts);
t.context = { ...rest, wallets, deleteTestKeys };
const { startContract } = rest;
await startContract(contractName, contractBuilder);
t.context = { ...common, wallets };
await startContract(contractName, contractBuilder, {
chainInfo,
assetInfo,
});
});

test.after(async t => {
Expand Down
11 changes: 7 additions & 4 deletions multichain-testing/test/deposit-withdraw-lca.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@ const contractBuilder =
'../packages/builders/scripts/orchestration/init-basic-flows.js';

test.before(async t => {
const { deleteTestKeys, setupTestKeys, ...rest } = await commonSetup(t);
const { setupTestKeys, ...common } = await commonSetup(t);
const { assetInfo, chainInfo, deleteTestKeys, startContract } = common;
deleteTestKeys(accounts).catch();
const wallets = await setupTestKeys(accounts);
t.context = { ...rest, wallets, deleteTestKeys };
const { startContract } = rest;
await startContract(contractName, contractBuilder);
t.context = { ...common, wallets };
await startContract(contractName, contractBuilder, {
chainInfo,
assetInfo,
});
});

test.after(async t => {
Expand Down
11 changes: 7 additions & 4 deletions multichain-testing/test/deposit-withdraw-portfolio.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@ const contractBuilder =
'../packages/builders/scripts/orchestration/init-basic-flows.js';

test.before(async t => {
const { deleteTestKeys, setupTestKeys, ...rest } = await commonSetup(t);
const { setupTestKeys, ...common } = await commonSetup(t);
const { assetInfo, chainInfo, deleteTestKeys, startContract } = common;
deleteTestKeys(accounts).catch();
const wallets = await setupTestKeys(accounts);
t.context = { ...rest, wallets, deleteTestKeys };
const { startContract } = rest;
await startContract(contractName, contractBuilder);
t.context = { ...common, wallets };
await startContract(contractName, contractBuilder, {
chainInfo,
assetInfo,
});
});

test.after(async t => {
Expand Down
11 changes: 7 additions & 4 deletions multichain-testing/test/ica-channel-close.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,15 @@ const contractBuilder =
'../packages/builders/scripts/orchestration/init-basic-flows.js';

test.before(async t => {
const { deleteTestKeys, setupTestKeys, ...rest } = await commonSetup(t);
const { setupTestKeys, ...common } = await commonSetup(t);
const { assetInfo, chainInfo, deleteTestKeys, startContract } = common;
deleteTestKeys(accounts).catch();
const wallets = await setupTestKeys(accounts);
t.context = { ...rest, wallets, deleteTestKeys };
const { startContract } = rest;
await startContract(contractName, contractBuilder);
t.context = { ...common, wallets };
await startContract(contractName, contractBuilder, {
chainInfo,
assetInfo,
});
});

test.after(async t => {
Expand Down
4 changes: 2 additions & 2 deletions multichain-testing/test/send-anywhere.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ test.before(async t => {
t.context = { ...common, wallets };

await startContract(contractName, contractBuilder, {
chainInfo: JSON.stringify(chainInfo),
assetInfo: JSON.stringify(assetInfo),
chainInfo,
assetInfo,
});
});

Expand Down
16 changes: 14 additions & 2 deletions multichain-testing/test/support.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { execa } from 'execa';
import fse from 'fs-extra';
import childProcess from 'node:child_process';
import { withChainCapabilities } from '@agoric/orchestration';
import { objectMap } from '@endo/patterns';
import { makeAgdTools } from '../tools/agd-tools.js';
import { type E2ETools } from '../tools/e2e-tools.js';
import {
Expand Down Expand Up @@ -94,7 +95,7 @@ export const commonSetup = async (t: ExecutionContext) => {
const startContract = async (
contractName: string,
contractBuilder: string,
builderOpts?: Record<string, string>,
builderOpts?: Record<string, unknown>,
) => {
const { vstorageClient } = tools;
const instances = Object.fromEntries(
Expand All @@ -104,7 +105,18 @@ export const commonSetup = async (t: ExecutionContext) => {
return t.log('Contract found. Skipping installation...');
}
t.log('bundle and install contract', contractName);
await deployBuilder(contractBuilder, builderOpts);

const formattedOpts = builderOpts
? objectMap(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
builderOpts as Record<string, any>,
value => {
if (typeof value === 'string') return value;
return JSON.stringify(value);
},
)
: undefined;
await deployBuilder(contractBuilder, formattedOpts);
await retryUntilCondition(
() => vstorageClient.queryData(`published.agoricNames.instance`),
res => contractName in Object.fromEntries(res),
Expand Down
2 changes: 2 additions & 0 deletions multichain-testing/test/tools/asset-info.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ test('makeAssetInfo', async t => {
{
baseDenom: 'uist',
baseName: 'agoric',
brandKey: 'IST',
chainName: 'agoric',
},
],
Expand All @@ -88,6 +89,7 @@ test('makeAssetInfo', async t => {
{
baseDenom: 'ubld',
baseName: 'agoric',
brandKey: 'BLD',
chainName: 'agoric',
},
],
Expand Down
14 changes: 13 additions & 1 deletion multichain-testing/tools/asset-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ export const makeAssetInfo = (
return `ibc/${denomHash({ denom, channelId })}`;
};

// `brandKey` instead of `brand` until #10580
// only BLD, IST until #9966
const BRAND_KEY_MAP: Record<string, string> = {
ubld: 'BLD',
uist: 'IST',
};

// only include chains present in `chainInfo`
const tokens = Object.entries(tokenMap)
.filter(([chain]) => chain in chainInfo)
Expand All @@ -55,18 +62,23 @@ export const makeAssetInfo = (
{
...baseDetails,
chainName: chain,
...(BRAND_KEY_MAP[denom] && { brandKey: BRAND_KEY_MAP[denom] }),
},
]);

// Add IBC entries for non-issuing chains
const issuingChainId = chainInfo[chain].chainId;
for (const holdingChain of Object.keys(chainInfo)) {
if (holdingChain === chain) continue;
const denomHash = toDenomHash(denom, issuingChainId, holdingChain);
assetInfo.push([
toDenomHash(denom, issuingChainId, holdingChain),
denomHash,
{
...baseDetails,
chainName: holdingChain,
...(BRAND_KEY_MAP[denomHash] && {
brandKey: BRAND_KEY_MAP[denomHash],
}),
},
]);
}
Expand Down
Loading

0 comments on commit 9b8cad2

Please sign in to comment.