diff --git a/packages/orchestration/test/mocks/chain-info.js b/packages/orchestration/test/mocks/chain-info.js new file mode 100644 index 00000000000..1ff83d9ab78 --- /dev/null +++ b/packages/orchestration/test/mocks/chain-info.js @@ -0,0 +1,305 @@ +/** + * Generated using gRPC queries to local simulated chains + * See {@link https://github.com/Agoric/agoric-sdk/blob/43e0249502171e82460be7cf4bad8baf5db5aafd/packages/cosmic-proto/test/snapshots/test-chain-info.js.md | snapshots} and + * their {@link https://github.com/Agoric/agoric-sdk/blob/43e0249502171e82460be7cf4bad8baf5db5aafd/packages/cosmic-proto/test/test-chain-info.js | source test}. + + * // TODO check in some portion of above code + */ +export const mockChainInfo = { + agoric: { + icaParams: { + allowMessages: [ + '/agoric.*', + '/ibc.*', + '/cosmos.[a-rt-z]*', + '/cosmos.s[a-su-z]*', + ], + hostEnabled: true, + }, + icqParams: { + hostEnabled: false, + }, + chainId: 'agoriclocal', + bondDenom: 'ubld', + denoms: [ + { + denom: 'ubld', + native: true, + }, + { + denom: 'uist', + native: true, + }, + { + baseDenom: 'uion', + denom: + 'ibc/F7E92EE59B5428793F3EF5C1A4CB2494F61A9D0C9A69469D02390714A1372E16', + path: 'transfer/channel-0', + }, + { + baseDenom: 'uosmo', + denom: + 'ibc/ED07A3391A112B175915CD8FAF43A2DA8E4790EDE12566649D0C2F97716B8518', + path: 'transfer/channel-0', + }, + { + baseDenom: 'uatom', + denom: + 'ibc/C4CFF46FD6DE35CA4CF4CE031E643C8FDC9BA4B99AE598E9B0ED98FE3A2319F9', + path: 'transfer/channel-1', + }, + ], + connections: [ + { + chainId: 'osmosis-test', + connectionInfo: { + clientId: '07-tendermint-2', + counterparty: { + clientId: '07-tendermint-2', + connectionId: 'connection-1', + }, + id: 'connection-0', + state: 'STATE_OPEN', + }, + lastUpdated: { + revisionHeight: 831n, + revisionNumber: 0n, + }, + transferChannels: [ + { + counterpartyChannelId: 'channel-1', + counterpartyPortId: 'transfer', + ordering: 'ORDER_UNORDERED', + sourceChannelId: 'channel-0', + sourcePortId: 'transfer', + state: 'STATE_OPEN', + version: 'ics20-1', + }, + ], + }, + { + chainId: 'gaia-test', + connectionInfo: { + clientId: '07-tendermint-3', + counterparty: { + clientId: '07-tendermint-2', + connectionId: 'connection-1', + }, + id: 'connection-1', + state: 'STATE_OPEN', + }, + lastUpdated: { + revisionHeight: 854n, + revisionNumber: 0n, + }, + transferChannels: [ + { + counterpartyChannelId: 'channel-1', + counterpartyPortId: 'transfer', + ordering: 'ORDER_UNORDERED', + sourceChannelId: 'channel-1', + sourcePortId: 'transfer', + state: 'STATE_OPEN', + version: 'ics20-1', + }, + ], + }, + ], + }, + cosmos: { + icaParams: { + allowMessages: [], + hostEnabled: true, + }, + icqParams: { + hostEnabled: false, + }, + chainId: 'gaia-test', + bondDenom: 'uatom', + denoms: [ + { + denom: 'uatom', + native: true, + }, + { + baseDenom: 'uion', + denom: + 'ibc/F7E92EE59B5428793F3EF5C1A4CB2494F61A9D0C9A69469D02390714A1372E16', + path: 'transfer/channel-0', + }, + { + baseDenom: 'uosmo', + denom: + 'ibc/ED07A3391A112B175915CD8FAF43A2DA8E4790EDE12566649D0C2F97716B8518', + path: 'transfer/channel-0', + }, + { + baseDenom: 'ubld', + denom: + 'ibc/E7827844CB818EE9C4DB2C159F1543FF62B26213B44CE8029D5CEFE52F0EE596', + path: 'transfer/channel-1', + }, + { + baseDenom: 'uist', + denom: + 'ibc/16CD81E12F05F5397CA2D580B4BA786A12A8F48B6FB3823D82EBE95D80B5287B', + path: 'transfer/channel-1', + }, + ], + connections: [ + { + chainId: 'osmosis-test', + connectionInfo: { + clientId: '07-tendermint-0', + counterparty: { + clientId: '07-tendermint-0', + connectionId: 'connection-0', + }, + id: 'connection-0', + state: 'STATE_OPEN', + }, + lastUpdated: { + revisionHeight: 12056n, + revisionNumber: 0n, + }, + transferChannels: [ + { + counterpartyChannelId: 'channel-0', + counterpartyPortId: 'transfer', + ordering: 'ORDER_UNORDERED', + sourceChannelId: 'channel-0', + sourcePortId: 'transfer', + state: 'STATE_OPEN', + version: 'ics20-1', + }, + ], + }, + { + chainId: 'agoriclocal', + connectionInfo: { + clientId: '07-tendermint-2', + counterparty: { + clientId: '07-tendermint-3', + connectionId: 'connection-1', + }, + id: 'connection-1', + state: 'STATE_OPEN', + }, + lastUpdated: { + revisionHeight: 113n, + revisionNumber: 0n, + }, + transferChannels: [ + { + counterpartyChannelId: 'channel-1', + counterpartyPortId: 'transfer', + ordering: 'ORDER_UNORDERED', + sourceChannelId: 'channel-1', + sourcePortId: 'transfer', + state: 'STATE_OPEN', + version: 'ics20-1', + }, + ], + }, + ], + }, + osmosis: { + icaParams: { + allowMessages: ['*'], + hostEnabled: true, + }, + icqParams: { + allowQueries: [ + '/cosmos.bank.v1beta1.Query/Balance', + '/cosmos.staking.v1beta1.Query/Delegation', + ], + hostEnabled: true, + }, + chainId: 'osmosis-test', + bondDenom: 'uosmo', + denoms: [ + { + denom: 'uion', + native: true, + }, + { + denom: 'uosmo', + native: true, + }, + { + baseDenom: 'uatom', + denom: + 'ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2', + path: 'transfer/channel-0', + }, + { + baseDenom: 'ubld', + denom: + 'ibc/E7827844CB818EE9C4DB2C159F1543FF62B26213B44CE8029D5CEFE52F0EE596', + path: 'transfer/channel-1', + }, + { + baseDenom: 'uist', + denom: + 'ibc/16CD81E12F05F5397CA2D580B4BA786A12A8F48B6FB3823D82EBE95D80B5287B', + path: 'transfer/channel-1', + }, + ], + connections: [ + { + chainId: 'gaia-test', + connectionInfo: { + clientId: '07-tendermint-0', + counterparty: { + clientId: '07-tendermint-0', + connectionId: 'connection-0', + }, + id: 'connection-0', + state: 'STATE_OPEN', + }, + lastUpdated: { + revisionHeight: 7836n, + revisionNumber: 0n, + }, + transferChannels: [ + { + counterpartyChannelId: 'channel-0', + counterpartyPortId: 'transfer', + ordering: 'ORDER_UNORDERED', + sourceChannelId: 'channel-0', + sourcePortId: 'transfer', + state: 'STATE_OPEN', + version: 'ics20-1', + }, + ], + }, + { + chainId: 'agoriclocal', + connectionInfo: { + clientId: '07-tendermint-2', + counterparty: { + clientId: '07-tendermint-2', + connectionId: 'connection-0', + }, + id: 'connection-1', + state: 'STATE_OPEN', + }, + lastUpdated: { + revisionHeight: 110n, + revisionNumber: 0n, + }, + transferChannels: [ + { + counterpartyChannelId: 'channel-0', + counterpartyPortId: 'transfer', + ordering: 'ORDER_UNORDERED', + sourceChannelId: 'channel-1', + sourcePortId: 'transfer', + state: 'STATE_OPEN', + version: 'ics20-1', + }, + ], + }, + ], + }, +}; diff --git a/packages/orchestration/test/test-chain-name-hub.js b/packages/orchestration/test/test-chain-name-hub.js new file mode 100644 index 00000000000..b7f987cd855 --- /dev/null +++ b/packages/orchestration/test/test-chain-name-hub.js @@ -0,0 +1,213 @@ +// @ts-check +import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js'; +import { makeNameHubKit } from '@agoric/vats'; +import { mockChainInfo } from './mocks/chain-info.js'; + +/** + * @import {Brand} from '@agoric/ertp/exported.js'; + * @import {IBCConnectionID} from '@agoric/vats'; + */ + +const test = anyTest; + +/** @typedef {`channel-${number}`} IBCChannelID */ +/** @typedef {`ibc/${string}`} IBCDenom */ + +/** + * // TODO import from cosmic-proto? + * @typedef {'STATE_OPEN' | 'STATE_TRYOPEN' | 'STATE_INIT' | 'STATE_CLOSED'} IBCConnectionState + */ + +/** + * @typedef {{ + * counterpartyChannelId: IBCChannelID; + * counterpartyPortId: string; + * sourceChannelId: IBCChannelID; + * sourcePortId: string; + * version: string; + * state: IBCConnectionState; + * ordering: 'ORDER_UNORDERED' | 'ORDER_ORDERED'; + * }} IBChannelInfo + */ + +/** + * @typedef {{ + * clientId: string; + * counterparty: { + * clientId: string; + * connectionId: string; + * }; + * id: IBCConnectionID; + * state: IBCConnectionState + * revisionHeight: bigint; + * revisionNumber: bigint; + * }} IBCConnectionInfo; + */ + +/** + * @type {{ + * chainId: string; + * bondAsset: { + * brand: Brand; + * denom: IBCDenom; + * }; + * brand: { + * [denom: IBCDenom]: Brand; + * }; + * denom: { + * [allegedBrandName: string]: IBCDenom; + * } + * trace: { + * [denomOrBrand: IBCDenom|string]: { + * baseDenom: string; + * path: string; + * }; + * }; + * connection: { + * [allegedChainName: string]: { + * chainId: string; + * connectionInfo: IBCConnectionInfo; + * transferChannel: IBChannelInfo; + * }; + * }; + * }} ChainInfoEntry + */ + +/** @type {Record} */ +const denomsToBrandName = { + uion: 'ION', + ubld: 'BLD', + uatom: 'ATOM', + uosmo: 'OSMO', + uist: 'IST', +}; + +/** @type {Record} */ +const chainIdToChainName = { + 'osmosis-test': 'osmosis', + 'gaia-test': 'cosmos', + agoriclocal: 'agoric', +}; + +const makeChainNames = async () => { + // XXX get a mock agoricNames.brands, + const { nameHub: chainNames, nameAdmin: chainNamesAdmin } = makeNameHubKit(); + for (const [allegedChainName, value] of Object.entries(mockChainInfo)) { + const { bondDenom, chainId, denoms, connections } = value; + const child = await chainNamesAdmin.provideChild(allegedChainName, [ + 'chainId', + 'bondAsset', + 'brand', + 'denom', + 'trace', + 'connection', + ]); + child.nameAdmin.update('chainId', chainId); + child.nameAdmin.update( + 'bondAsset', + harden({ + brand: 'XXX_agoricNames_brand', // FIXME, use ERTP brand + denom: bondDenom, + }), + ); + const { nameHub: brandNames, nameAdmin: brandNamesAdmin } = + makeNameHubKit(); + const { nameHub: denomNames, nameAdmin: denomNamesAdmin } = + makeNameHubKit(); + const { nameHub: traceNames, nameAdmin: traceNamesAdmin } = + makeNameHubKit(); + + for (const { denom, path, baseDenom } of denoms) { + const brandName = denomsToBrandName[baseDenom || denom]; + await brandNamesAdmin.provideChild(denom); + brandNamesAdmin.update(denom, brandName); // FIXME, use ERTP Brand + + await denomNamesAdmin.provideChild(brandName); + denomNamesAdmin.update(brandName, denom); + + await traceNamesAdmin.provideChild(denom); + traceNamesAdmin.update(denom, harden({ baseDenom, path })); + await traceNamesAdmin.provideChild(brandName); + traceNamesAdmin.update(brandName, harden({ baseDenom, path })); + } + child.nameAdmin.update('brand', brandNames); + child.nameAdmin.update('denom', denomNames); + child.nameAdmin.update('trace', traceNames); + + const { nameHub: connectionNames, nameAdmin: connectionNamesAdmin } = + makeNameHubKit(); + for (const { + connectionInfo, + transferChannels, + chainId: lChainId, + lastUpdated, + } of connections) { + const chainName = chainIdToChainName[lChainId]; + await connectionNamesAdmin.provideChild(chainName); + connectionNamesAdmin.update( + chainName, + harden({ + chainId: lChainId, + connectionInfo: { + ...connectionInfo, + ...lastUpdated, + }, + // FIXME, there can be more than one, but typically only one canonical + transferChannel: transferChannels[0], + }), + ); + } + child.nameAdmin.update('connection', connectionNames); + } + return { chainNames, chainNamesAdmin }; +}; + +test('chain-name-hub', async t => { + const { chainNames } = await makeChainNames(); + + const chainId = await chainNames.lookup('osmosis', 'chainId'); + t.is(chainId, 'osmosis-test'); + const bondAsset = await chainNames.lookup('osmosis', 'bondAsset'); + t.deepEqual(bondAsset, { brand: 'XXX_agoricNames_brand', denom: 'uosmo' }); + + // lookup up Brand from denom + const brand = await chainNames.lookup('osmosis', 'brand', 'uosmo'); + t.is(brand, 'OSMO', 'FIXME, use real ERTP Brand'); + + // lookup denom from alleged brand name + const denom = await chainNames.lookup('osmosis', 'denom', 'ATOM'); + t.regex(denom, /ibc\/27394/); + + // lookup denom trace from denom + const traceFromDenom = await chainNames.lookup( + 'osmosis', + 'trace', + 'ibc/E7827844CB818EE9C4DB2C159F1543FF62B26213B44CE8029D5CEFE52F0EE596', + ); + const expectedTrace = { + baseDenom: 'ubld', + path: 'transfer/channel-1', + }; + t.deepEqual(traceFromDenom, expectedTrace); + // lookup denom trace from brand name + const traceFromBrandName = await chainNames.lookup('osmosis', 'trace', 'BLD'); + t.deepEqual(traceFromBrandName, expectedTrace); + + // lookup conneciton info for a chain + const connection = await chainNames.lookup('osmosis', 'connection', 'agoric'); + t.like(connection, { + chainId: 'agoriclocal', + connectionInfo: { + id: 'connection-1', + counterparty: { + connectionId: 'connection-0', + }, + }, + transferChannel: { + counterpartyChannelId: 'channel-0', + counterpartyPortId: 'transfer', + sourceChannelId: 'channel-1', + version: 'ics20-1', + }, + }); +});