Skip to content

Commit

Permalink
feat!: chainHub.getAsset requires srcChainName parameter (#10588)
Browse files Browse the repository at this point in the history
refs: #10445 

## Description
IBC Denoms are unique to a chain but not all not all chains. e.g., if `channel-0` points to `osmosis` for two chains, the `uosmo` denom  will be `ibc/ED07A3391A112B175915CD8FAF43A2DA8E4790EDE12566649D0C2F97716B8518` for both.

This change requires callers to specify the `holdingChainName` for the denom they wish to retrieve information about.

### Security Considerations
None

### Scaling Considerations
None

### Documentation Considerations
None

### Testing Considerations
Updates existing tests. Motivated from work in #10571 which surfaced this issue.

### Upgrade Considerations
Breaking change, but for library code that will be part on NPM or FUSDC release.
  • Loading branch information
mergify[bot] authored Dec 3, 2024
2 parents dcf2772 + 5912769 commit 3154854
Show file tree
Hide file tree
Showing 24 changed files with 393 additions and 123 deletions.
3 changes: 2 additions & 1 deletion a3p-integration/proposals/z:acceptance/vaults.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,8 @@ test.serial('user cannot open a vault above debt limit', async t => {
);
});

test.serial('user can open a vault under debt limit', async t => {
// TODO #10599. marked as `skip` since several flakes were observed
test.skip('user can open a vault under debt limit', async t => {
const istBalanceBefore = await getISTBalance(GOV1ADDR);
const activeVaultsBefore = await listVaults(GOV1ADDR, walletUtils);

Expand Down
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',
},
],
]);
});
76 changes: 76 additions & 0 deletions multichain-testing/tools/asset-info.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
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 =>
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 })}`;
};

// only include chains present in `chainInfo`
const tokens = Object.entries(tokenMap)
.filter(([chain]) => chain in chainInfo)
.flatMap(([chain, denoms]) => denoms.map(denom => ({ denom, chain })));

const assetInfo: [Denom, DenomDetail][] = [];
for (const { denom, chain } of tokens) {
const baseDetails = {
baseName: chain,
baseDenom: denom,
};

// Add native token entry
assetInfo.push([
denom,
{
...baseDetails,
chainName: chain,
},
]);

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

return harden(assetInfo);
};
28 changes: 18 additions & 10 deletions packages/builders/scripts/fast-usdc/init-fast-usdc.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,39 @@ import { parseArgs } from 'node:util';
* @import {ParseArgsConfig} from 'node:util'
* @import {FastUSDCConfig} from '@agoric/fast-usdc/src/fast-usdc.start.js'
* @import {Passable} from '@endo/marshal';
* @import {CosmosChainInfo} from '@agoric/orchestration';
* @import {CosmosChainInfo, Denom, DenomDetail} from '@agoric/orchestration';
*/

const { keys } = Object;

const defaultAssetInfo = {
uusdc: {
baseName: 'noble',
chainName: 'noble',
baseDenom: 'uusdc',
},
[`ibc/${denomHash({ denom: 'uusdc', channelId: fetchedChainInfo.agoric.connections['noble-1'].transferChannel.channelId })}`]:
/** @type {[Denom, DenomDetail & { brandKey?: string}][]} */
const defaultAssetInfo = [
[
'uusdc',
{
baseName: 'noble',
chainName: 'noble',
baseDenom: 'uusdc',
},
],
[
`ibc/${denomHash({ denom: 'uusdc', channelId: fetchedChainInfo.agoric.connections['noble-1'].transferChannel.channelId })}`,
{
baseName: 'noble',
chainName: 'agoric',
baseDenom: 'uusdc',
brandKey: 'USDC',
},
[`ibc/${denomHash({ denom: 'uusdc', channelId: fetchedChainInfo.osmosis.connections['noble-1'].transferChannel.channelId })}`]:
],
[
`ibc/${denomHash({ denom: 'uusdc', channelId: fetchedChainInfo.osmosis.connections['noble-1'].transferChannel.channelId })}`,
{
baseName: 'noble',
chainName: 'osmosis',
baseDenom: 'uusdc',
},
};
],
];

/**
* @type {Record<string, Pick<FastUSDCConfig, 'oracles' | 'feedPolicy' | 'chainInfo' | 'assetInfo' >>}
Expand Down
Loading

0 comments on commit 3154854

Please sign in to comment.