Skip to content

Commit

Permalink
chore: support for asset info in agoricNames
Browse files Browse the repository at this point in the history
  • Loading branch information
dckc committed Jul 26, 2024
1 parent 7ac60a2 commit 829331a
Show file tree
Hide file tree
Showing 6 changed files with 278 additions and 13 deletions.
34 changes: 27 additions & 7 deletions packages/orchestration/src/chain-info.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import { E } from '@endo/far';
import { mustMatch } from '@endo/patterns';
import { normalizeConnectionInfo } from './exos/chain-hub.js';
import { M, mustMatch } from '@endo/patterns';
import {
ASSETS_KEY,
CHAIN_KEY,
CONNECTIONS_KEY,
normalizeConnectionInfo,
} from './exos/chain-hub.js';
import fetchedChainInfo from './fetched-chain-info.js'; // Refresh with scripts/refresh-chain-info.ts
import { CosmosChainInfoShape } from './typeGuards.js';
import { CosmosAssetInfoShape, CosmosChainInfoShape } from './typeGuards.js';

/** @import {CosmosChainInfo, EthChainInfo, IBCConnectionInfo} from './types.js'; */
/** @import {CosmosAssetInfo, CosmosChainInfo, EthChainInfo, IBCConnectionInfo} from './types.js'; */
/** @import {NameAdmin} from '@agoric/vats'; */

/** @typedef {CosmosChainInfo | EthChainInfo} ChainInfo */

Expand Down Expand Up @@ -66,7 +72,21 @@ const knownChains = /** @satisfies {Record<string, ChainInfo>} */ (
/** @typedef {typeof knownChains} KnownChains */

/**
* @param {ERef<import('@agoric/vats').NameHubKit['nameAdmin']>} agoricNamesAdmin
* TODO(#9572): include this in registerChain
*
* @param {ERef<NameAdmin>} agoricNamesAdmin
* @param {string} name
* @param {CosmosAssetInfo[]} assets
*/
export const registerChainAssets = async (agoricNamesAdmin, name, assets) => {
mustMatch(assets, M.arrayOf(CosmosAssetInfoShape));
const { nameAdmin: assetAdmin } =
await E(agoricNamesAdmin).provideChild(ASSETS_KEY);
return E(assetAdmin).update(name, assets);
};

/**
* @param {ERef<NameAdmin>} agoricNamesAdmin
* @param {string} name
* @param {CosmosChainInfo} chainInfo
* @param {(...messages: string[]) => void} [log]
Expand All @@ -80,9 +100,9 @@ export const registerChain = async (
log = () => {},
handledConnections = new Set(),
) => {
const { nameAdmin } = await E(agoricNamesAdmin).provideChild('chain');
const { nameAdmin } = await E(agoricNamesAdmin).provideChild(CHAIN_KEY);
const { nameAdmin: connAdmin } =
await E(agoricNamesAdmin).provideChild('chainConnection');
await E(agoricNamesAdmin).provideChild(CONNECTIONS_KEY);

mustMatch(chainInfo, CosmosChainInfoShape);
const { connections = {}, ...vertex } = chainInfo;
Expand Down
25 changes: 24 additions & 1 deletion packages/orchestration/src/cosmos-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import type {
LocalIbcAddress,
RemoteIbcAddress,
} from '@agoric/vats/tools/ibc-utils.js';
import type { AmountArg, ChainAddress, DenomAmount } from './types.js';
import type { AmountArg, ChainAddress, Denom, DenomAmount } from './types.js';

/** An address for a validator on some blockchain, e.g., cosmos, eth, etc. */
export type CosmosValidatorAddress = ChainAddress & {
Expand Down Expand Up @@ -54,6 +54,29 @@ export type IBCConnectionInfo = {
};
};

/**
* https://github.com/cosmos/chain-registry/blob/master/assetlist.schema.json
*/
export type CosmosAssetInfo = {
base: Denom;
name: string;
display: string;
symbol: string;
denom_units: Array<{ denom: Denom; exponent: number }>;
traces?: Array<{
type: 'ibc';
counterparty: {
chain_name: string;
base_denom: Denom;
channel_id: IBCChannelID;
};
chain: {
channel_id: IBCChannelID;
path: string;
};
}>;
} & Record<string, unknown>;

/**
* Info for a Cosmos-based chain.
*/
Expand Down
24 changes: 23 additions & 1 deletion packages/orchestration/src/exos/chain-hub.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { CosmosChainInfoShape, IBCConnectionInfoShape } from '../typeGuards.js';
/**
* @import {NameHub} from '@agoric/vats';
* @import {Vow, VowTools} from '@agoric/vow';
* @import {CosmosChainInfo, IBCConnectionInfo} from '../cosmos-api.js';
* @import {CosmosAssetInfo, CosmosChainInfo, IBCConnectionInfo} from '../cosmos-api.js';
* @import {ChainInfo, KnownChains} from '../chain-info.js';
* @import {Denom} from '../orchestration-api.js';
* @import {Remote} from '@agoric/internal';
Expand Down Expand Up @@ -42,6 +42,8 @@ export const DenomDetailShape = M.splitRecord(
export const CHAIN_KEY = 'chain';
/** namehub for connection info */
export const CONNECTIONS_KEY = 'chainConnection';
/** namehub for assets info */
export const ASSETS_KEY = 'chainAssets';

/**
* Character used in a connection tuple key to separate the two chain ids. Valid
Expand Down Expand Up @@ -390,3 +392,23 @@ export const makeChainHub = (agoricNames, vowTools) => {
return chainHub;
};
/** @typedef {ReturnType<typeof makeChainHub>} ChainHub */

/**
* @param {ChainHub} chainHub
* @param {string} name
* @param {CosmosAssetInfo[]} assets
*/
export const registerAssets = (chainHub, name, assets) => {
for (const { base, traces } of assets) {
const native = !traces;
native || traces.length === 1 || Fail`unexpected ${traces.length} traces`;
const [chainName, baseName, baseDenom] = native
? [name, name, base]
: [
name,
traces[0].counterparty.chain_name,
traces[0].counterparty.base_denom,
];
chainHub.registerAsset(base, { chainName, baseName, baseDenom });
}
};
13 changes: 12 additions & 1 deletion packages/orchestration/src/typeGuards.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { M } from '@endo/patterns';

/**
* @import {TypedPattern} from '@agoric/internal';
* @import {ChainAddress, ChainInfo, CosmosChainInfo, DenomAmount, DenomDetail} from './types.js';
* @import {ChainAddress, CosmosAssetInfo, ChainInfo, CosmosChainInfo, DenomAmount, DenomDetail} from './types.js';
* @import {Delegation} from '@agoric/cosmic-proto/cosmos/staking/v1beta1/staking.js';
*/

Expand Down Expand Up @@ -79,6 +79,17 @@ export const IBCConnectionInfoShape = M.splitRecord({
transferChannel: IBCChannelInfoShape,
});

/** @type {TypedPattern<CosmosAssetInfo>} */
export const CosmosAssetInfoShape = M.splitRecord({
base: M.string(),
name: M.string(),
display: M.string(),
symbol: M.string(),
denom_units: M.arrayOf(
M.splitRecord({ denom: M.string(), exponent: M.number() }),
),
});

/** @type {TypedPattern<CosmosChainInfo>} */
export const CosmosChainInfoShape = M.splitRecord(
{
Expand Down
145 changes: 145 additions & 0 deletions packages/orchestration/test/assets.fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import type { CosmosAssetInfo } from '../src/cosmos-api.js';

// https://github.com/cosmos/chain-registry/blob/master/cosmoshub/assetlist.json
export const assets = {
cosmoshub: [
{
description:
'ATOM is the native cryptocurrency of the Cosmos network, designed to facilitate interoperability between multiple blockchains through its innovative hub-and-spoke model.',
extended_description:
"ATOM, the native cryptocurrency of the Cosmos network, is essential for achieving the project's goal of creating an 'Internet of Blockchains.' Launched in 2019, Cosmos aims to solve the scalability, usability, and interoperability issues prevalent in existing blockchain ecosystems. The Cosmos Hub, the central blockchain of the network, uses ATOM for transaction fees, staking, and governance. By staking ATOM, users can earn rewards and participate in governance, influencing decisions on network upgrades and changes.\n\nCosmos leverages the Tendermint consensus algorithm to achieve high transaction throughput and fast finality. Its Inter-Blockchain Communication (IBC) protocol enables seamless data and value transfer between different blockchains, fostering a highly interconnected and collaborative ecosystem. The flexibility and scalability offered by Cosmos have attracted numerous projects, enhancing its utility and adoption. ATOM's role in securing the network and facilitating governance underscores its importance in the broader blockchain landscape.",
denom_units: [
{
denom: 'uatom',
exponent: 0,
},
{
denom: 'atom',
exponent: 6,
},
],
base: 'uatom',
name: 'Cosmos Hub Atom',
display: 'atom',
symbol: 'ATOM',
logo_URIs: {
png: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/cosmoshub/images/atom.png',
svg: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/cosmoshub/images/atom.svg',
},
coingecko_id: 'cosmos',
images: [
{
png: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/cosmoshub/images/atom.png',
svg: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/cosmoshub/images/atom.svg',
theme: {
primary_color_hex: '#272d45',
},
},
],
socials: {
website: 'https://cosmos.network',
twitter: 'https://twitter.com/cosmoshub',
},
},
{
description: 'Tether USDt on the Cosmos Hub',
denom_units: [
{
denom:
'ibc/F04D72CF9B5D9C849BB278B691CDFA2241813327430EC9CDC83F8F4CA4CDC2B0',
exponent: 0,
},
{
denom: 'usdt',
exponent: 6,
},
],
type_asset: 'ics20',
base: 'ibc/F04D72CF9B5D9C849BB278B691CDFA2241813327430EC9CDC83F8F4CA4CDC2B0',
name: 'Tether USDt',
display: 'usdt',
symbol: 'USDt',
traces: [
{
type: 'ibc',
counterparty: {
chain_name: 'kava',
base_denom: 'erc20/tether/usdt',
channel_id: 'channel-0',
},
chain: {
channel_id: 'channel-277',
path: 'transfer/channel-277/erc20/tether/usdt',
},
},
],
images: [
{
image_sync: {
chain_name: 'kava',
base_denom: 'erc20/tether/usdt',
},
svg: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/usdt.svg',
png: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/usdt.png',
theme: {
circle: true,
primary_color_hex: '#009393',
background_color_hex: '#009393',
},
},
],
logo_URIs: {
png: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/usdt.png',
svg: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/_non-cosmos/ethereum/images/usdt.svg',
},
},
{
description: 'FX on Cosmos Hub',
denom_units: [
{
denom:
'ibc/4925E6ABA571A44D2BE0286D2D29AF42A294D0FF2BB16490149A1B26EAD33729',
exponent: 0,
aliases: ['FX'],
},
],
type_asset: 'ics20',
base: 'ibc/4925E6ABA571A44D2BE0286D2D29AF42A294D0FF2BB16490149A1B26EAD33729',
name: 'Function X',
display: 'FX',
symbol: 'FX',
traces: [
{
type: 'ibc',
counterparty: {
chain_name: 'fxcore',
base_denom: 'FX',
channel_id: 'channel-10',
},
chain: {
channel_id: 'channel-585',
path: 'transfer/channel-585/FX',
},
},
],
images: [
{
image_sync: {
chain_name: 'fxcore',
base_denom: 'FX',
},
png: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/fxcore/images/fx.png',
svg: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/fxcore/images/fx.svg',
theme: {
primary_color_hex: '#1c1c1c',
},
},
],
logo_URIs: {
png: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/fxcore/images/fx.png',
svg: 'https://raw.githubusercontent.com/cosmos/chain-registry/master/fxcore/images/fx.svg',
},
},
] as CosmosAssetInfo[],
};
harden(assets);
50 changes: 47 additions & 3 deletions packages/orchestration/test/exos/chain-hub.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,19 @@ import test from '@endo/ses-ava/prepare-endo.js';

import { makeNameHubKit } from '@agoric/vats';
import { prepareSwingsetVowTools } from '@agoric/vow/vat.js';
import { makeChainHub } from '../../src/exos/chain-hub.js';
import { E } from '@endo/far';
import { makeChainHub, registerAssets } from '../../src/exos/chain-hub.js';
import { provideDurableZone } from '../supports.js';
import { registerKnownChains } from '../../src/chain-info.js';
import {
registerChainAssets,
registerKnownChains,
} from '../../src/chain-info.js';
import knownChains from '../../src/fetched-chain-info.js';
import type {
CosmosChainInfo,
IBCConnectionInfo,
} from '../../src/cosmos-api.js';
import { assets as assetFixture } from '../assets.fixture.js';

const connection = {
id: 'connection-1',
Expand Down Expand Up @@ -91,7 +96,7 @@ test.serial('getConnectionInfo', async t => {
});

test('getBrandInfo support', async t => {
const { chainHub, vt } = setup();
const { chainHub } = setup();

const denom = 'utok1';
const info1: CosmosChainInfo = {
Expand All @@ -110,3 +115,42 @@ test('getBrandInfo support', async t => {
const actual = chainHub.lookupAsset('utok1');
t.deepEqual(actual, info);
});

test('toward asset info in agoricNames (#9572)', async t => {
const { chainHub, nameAdmin, vt } = setup();
// use fetched chain info
await registerKnownChains(nameAdmin);

await vt.when(chainHub.getChainInfo('cosmoshub'));

for (const name of ['kava', 'fxcore']) {
chainHub.registerChain(name, { chainId: name });
}

await registerChainAssets(nameAdmin, 'cosmoshub', assetFixture.cosmoshub);
const details = await E(E(nameAdmin).readonly()).lookup(
'chainAssets',
'cosmoshub',
);
registerAssets(chainHub, 'cosmoshub', details);

{
const actual = chainHub.lookupAsset('uatom');
t.deepEqual(actual, {
chainName: 'cosmoshub',
baseName: 'cosmoshub',
baseDenom: 'uatom',
});
}

{
const actual = chainHub.lookupAsset(
'ibc/F04D72CF9B5D9C849BB278B691CDFA2241813327430EC9CDC83F8F4CA4CDC2B0',
);
t.deepEqual(actual, {
chainName: 'cosmoshub',
baseName: 'kava',
baseDenom: 'erc20/tether/usdt',
});
}
});

0 comments on commit 829331a

Please sign in to comment.