Skip to content

Commit

Permalink
feat: multichain-testing makeAssetInfo helper
Browse files Browse the repository at this point in the history
  • Loading branch information
0xpatrickdev committed Nov 29, 2024
1 parent fec9ebc commit 1eed391
Show file tree
Hide file tree
Showing 4 changed files with 253 additions and 31 deletions.
35 changes: 4 additions & 31 deletions multichain-testing/test/send-anywhere.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ 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<SetupContextWithWallets>;

Expand All @@ -22,39 +20,14 @@ const contractBuilder =
'../packages/builders/scripts/testing/init-send-anywhere.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;

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',
},
};
t.context = { ...common, wallets };

await startContract(contractName, contractBuilder, {
chainInfo: JSON.stringify(withChainCapabilities(chainInfo)),
chainInfo: JSON.stringify(chainInfo),
assetInfo: JSON.stringify(assetInfo),
});
});
Expand Down
7 changes: 7 additions & 0 deletions multichain-testing/test/support.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { dirname, join } from 'path';
import { execa } from 'execa';
import fse from 'fs-extra';
import childProcess from 'node:child_process';
import { withChainCapabilities } from '@agoric/orchestration';
import { makeAgdTools } from '../tools/agd-tools.js';
import { type E2ETools } from '../tools/e2e-tools.js';
import {
Expand All @@ -15,6 +16,8 @@ import { makeRetryUntilCondition } from '../tools/sleep.js';
import { makeDeployBuilder } from '../tools/deploy.js';
import { makeHermes } from '../tools/hermes-tools.js';
import { makeNobleTools } from '../tools/noble-tools.js';
import { makeAssetInfo } from '../tools/asset-info.js';
import starshipChainInfo from '../starship-chain-info.js';

export const FAUCET_POUR = 10_000n * 1_000_000n;

Expand Down Expand Up @@ -78,6 +81,8 @@ export const commonSetup = async (t: ExecutionContext) => {
});
const hermes = makeHermes(childProcess);
const nobleTools = makeNobleTools(childProcess);
const assetInfo = makeAssetInfo(starshipChainInfo);
const chainInfo = withChainCapabilities(starshipChainInfo);

/**
* Starts a contract if instance not found. Takes care of installing
Expand Down Expand Up @@ -116,6 +121,8 @@ export const commonSetup = async (t: ExecutionContext) => {
hermes,
nobleTools,
startContract,
assetInfo,
chainInfo,
};
};

Expand Down
167 changes: 167 additions & 0 deletions multichain-testing/test/tools/asset-info.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import test from '@endo/ses-ava/prepare-endo.js';
import type { Denom, DenomDetail } from '@agoric/orchestration';
import { makeAssetInfo } from '../../tools/asset-info.js';

const minChainInfo = {
agoric: {
chainId: 'agoriclocal',
connections: {
gaialocal: {
transferChannel: {
channelId: 'channel-1',
},
},
osmosislocal: {
transferChannel: {
channelId: 'channel-0',
},
},
},
},
cosmoshub: {
chainId: 'gaialocal',
connections: {
agoriclocal: {
transferChannel: {
channelId: 'channel-1',
},
},
osmosislocal: {
transferChannel: {
channelId: 'channel-0',
},
},
},
},
osmosis: {
chainId: 'osmosislocal',
connections: {
agoriclocal: {
transferChannel: {
channelId: 'channel-1',
},
},
gaialocal: {
transferChannel: {
channelId: 'channel-0',
},
},
},
},
};

const minTokenMap = {
agoric: ['ubld', 'uist'],
cosmoshub: ['uatom'],
osmosis: ['uosmo'],
};

test('makeAssetInfo', async t => {
const byDenom = (assetInfo: [Denom, DenomDetail][]) =>
assetInfo.sort(([a], [b]) => a.localeCompare(b) * -1);

const assetInfo = makeAssetInfo(
/** @ts-expect-error minified mock */
minChainInfo,
minTokenMap,
);

t.deepEqual(byDenom([...assetInfo]), [
[
'uosmo',
{
baseDenom: 'uosmo',
baseName: 'osmosis',
chainName: 'osmosis',
},
],
[
'uist',
{
baseDenom: 'uist',
baseName: 'agoric',
chainName: 'agoric',
},
],
[
'ubld',
{
baseDenom: 'ubld',
baseName: 'agoric',
chainName: 'agoric',
},
],
[
'uatom',
{
baseDenom: 'uatom',
baseName: 'cosmoshub',
chainName: 'cosmoshub',
},
],
[
'ibc/ED07A3391A112B175915CD8FAF43A2DA8E4790EDE12566649D0C2F97716B8518',
{
baseDenom: 'uosmo',
baseName: 'osmosis',
chainName: 'agoric',
},
],
[
'ibc/ED07A3391A112B175915CD8FAF43A2DA8E4790EDE12566649D0C2F97716B8518',
{
baseDenom: 'uosmo',
baseName: 'osmosis',
chainName: 'cosmoshub',
},
],
[
'ibc/E7827844CB818EE9C4DB2C159F1543FF62B26213B44CE8029D5CEFE52F0EE596',
{
baseDenom: 'ubld',
baseName: 'agoric',
chainName: 'cosmoshub',
},
],
[
'ibc/E7827844CB818EE9C4DB2C159F1543FF62B26213B44CE8029D5CEFE52F0EE596',
{
baseDenom: 'ubld',
baseName: 'agoric',
chainName: 'osmosis',
},
],
[
'ibc/C4CFF46FD6DE35CA4CF4CE031E643C8FDC9BA4B99AE598E9B0ED98FE3A2319F9',
{
baseDenom: 'uatom',
baseName: 'cosmoshub',
chainName: 'agoric',
},
],
[
'ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2',
{
baseDenom: 'uatom',
baseName: 'cosmoshub',
chainName: 'osmosis',
},
],
[
'ibc/16CD81E12F05F5397CA2D580B4BA786A12A8F48B6FB3823D82EBE95D80B5287B',
{
baseDenom: 'uist',
baseName: 'agoric',
chainName: 'cosmoshub',
},
],
[
'ibc/16CD81E12F05F5397CA2D580B4BA786A12A8F48B6FB3823D82EBE95D80B5287B',
{
baseDenom: 'uist',
baseName: 'agoric',
chainName: 'osmosis',
},
],
]);
});
75 changes: 75 additions & 0 deletions multichain-testing/tools/asset-info.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import {
denomHash,
type CosmosChainInfo,
type Denom,
type DenomDetail,
} from '@agoric/orchestration';
import type { IBCChannelID } from '@agoric/vats';

/** make asset info for current env */
export const makeAssetInfo = (
chainInfo: Record<string, CosmosChainInfo>,
tokenMap: Record<string, Denom[]> = {
agoric: ['ubld', 'uist'],
cosmoshub: ['uatom'],
noble: ['uusdc'],
osmosis: ['uosmo', 'uion'],
},
): [Denom, DenomDetail][] => {
const getChannelId = (
issuingChainId: string,
holdingChainName: string,
): IBCChannelID | undefined => {
return chainInfo[holdingChainName]?.connections?.[issuingChainId]
.transferChannel.channelId;
};

const toDenomHash = (
denom: Denom,
issuingChainId: string,
holdingChainName: string,
): Denom => {
const channelId = getChannelId(issuingChainId, holdingChainName);
if (!channelId) {
throw new Error(
`No channel found for ${issuingChainId} -> ${holdingChainName}`,
);
}
return `ibc/${denomHash({ denom, channelId })}`;
};

// Filter tokenMap to only include chains present in the current environment
const currentTokenMap = Object.entries(tokenMap).reduce<
Record<string, Denom[]>
>(
(acc, [chainName, denoms]) =>
chainName in chainInfo ? { ...acc, [chainName]: denoms } : acc,
{},
);

const seen = new Set();
const assetInfo: [Denom, DenomDetail][] = [];
for (const holdingChain of Object.keys(chainInfo)) {
for (const [issuingChain, denoms] of Object.entries(currentTokenMap)) {
for (const denom of denoms) {
const seenKey = [denom, issuingChain, holdingChain].sort().join(':');
if (seen.has(seenKey)) continue;
seen.add(seenKey);
const denomOrHash =
holdingChain === issuingChain
? denom
: toDenomHash(denom, chainInfo[issuingChain].chainId, holdingChain);
assetInfo.push([
denomOrHash,
{
baseName: issuingChain,
chainName: holdingChain,
baseDenom: denom,
},
]);
}
}
}

return harden(assetInfo);
};

0 comments on commit 1eed391

Please sign in to comment.