Skip to content

Commit

Permalink
feat: register interchain bank assets proposal
Browse files Browse the repository at this point in the history
- create `register-interchain-bank-assets.js` for multichain-testing environment
  - allow users to submit offers using new brands like OSMO, ION
  - override existing brands like ATOM (ibc/toyatom) with starship denom
- create `make-bank-asset-info.ts` to gather `InterchainAssetOptions` from starship env
- update `make start` and ci `multichain-e2e-template.yaml` to call these scripts
- deploy-cli.ts `deployBuilder` accepts `builderOpts`
  • Loading branch information
0xpatrickdev committed Dec 4, 2024
1 parent ce195ab commit 0e20707
Show file tree
Hide file tree
Showing 14 changed files with 359 additions and 22 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/multichain-e2e-template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ jobs:
run: make override-chain-registry
working-directory: ./agoric-sdk/multichain-testing

- name: Register Interchain Bank Assets
run: make register-bank-assets
working-directory: ./agoric-sdk/multichain-testing

- name: Run @agoric/multichain-testing E2E Tests
run: yarn ${{ inputs.test_command }}
working-directory: ./agoric-sdk/multichain-testing
Expand Down
5 changes: 3 additions & 2 deletions multichain-testing/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
!.yarn/patches/*
# fetched chain info from running starship
starship-chain-info.js
# output of build script to get update running chain info
revise-chain-info*
# builder prefix for contract starters
start*
# builder prefix for core evals
eval-*
7 changes: 6 additions & 1 deletion multichain-testing/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ override-chain-registry:
scripts/fetch-starship-chain-info.ts && \
scripts/deploy-cli.ts src/revise-chain-info.builder.js

register-bank-assets:
scripts/fetch-starship-chain-info.ts && \
scripts/deploy-cli.ts src/register-interchain-bank-assets.builder.js \
assets="$$(scripts/make-bank-asset-info.ts)"

ADDR=agoric1ldmtatp24qlllgxmrsjzcpe20fvlkp448zcuce
COIN=1000000000uist

Expand All @@ -101,5 +106,5 @@ wait-for-pods:
scripts/pod-readiness.ts

.PHONY: start
start: install wait-for-pods port-forward fund-provision-pool override-chain-registry
start: install wait-for-pods port-forward fund-provision-pool override-chain-registry register-bank-assets

2 changes: 1 addition & 1 deletion multichain-testing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ make wait-for-pods
make port-forward

# set up Agoric testing environment
make fund-provision-pool override-chain-registry
make fund-provision-pool override-chain-registry register-bank-assets
```

If you get an error like "connection refused", you need to wait longer, until all the pods are Running.
Expand Down
17 changes: 14 additions & 3 deletions multichain-testing/scripts/deploy-cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,28 @@ import { makeAgdTools } from '../tools/agd-tools.js';
import { makeDeployBuilder } from '../tools/deploy.js';

async function main() {
const builder = process.argv[2];
const [builder, ...rawArgs] = process.argv.slice(2);

// Parse builder options from command line arguments
const builderOpts: Record<string, string> = {};
for (const arg of rawArgs) {
const [key, value] = arg.split('=');
if (key && value) {
builderOpts[key] = value;
}
}

if (!builder) {
console.error('USAGE: deploy-cli.ts <builder script>');
console.error(
'USAGE: deploy-cli.ts <builder script> [key1=value1] [key2=value2]',
);
process.exit(1);
}

try {
const agdTools = await makeAgdTools(console.log, childProcess);
const deployBuilder = makeDeployBuilder(agdTools, fse.readJSON, execa);
await deployBuilder(builder);
await deployBuilder(builder, builderOpts);
} catch (err) {
console.error(err);
process.exit(1);
Expand Down
30 changes: 30 additions & 0 deletions multichain-testing/scripts/make-bank-asset-info.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env -S node --import ts-blank-space/register
/* eslint-env node */

import '@endo/init';
import starshipChainInfo from '../starship-chain-info.js';
import { makeAssetInfo } from '../tools/asset-info.ts';

const main = () => {
if (!starshipChainInfo) {
throw new Error(
'starshipChainInfo not found. run `./scripts/fetch-starship-chain-info.ts` first.',
);
}

const assetInfo = makeAssetInfo(starshipChainInfo)
.filter(
([_, { chainName, baseName }]) =>
chainName === 'agoric' && baseName !== 'agoric',
)
.map(([denom, { baseDenom }]) => ({
denom,
issuerName: baseDenom.replace(/^u/, '').toUpperCase(),
decimalPlaces: 6, // TODO do not assume 6
}));

// Directly output JSON string for proposal builder options
process.stdout.write(JSON.stringify(assetInfo));
};

main();
51 changes: 51 additions & 0 deletions multichain-testing/src/register-interchain-bank-assets.builder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/* global harden */
/// <reference types="ses" />
import { makeHelpers } from '@agoric/deploy-script-support';
import { parseArgs } from 'node:util';

/**
* @import {ParseArgsConfig} from 'node:util';
* @import {CoreEvalBuilder, DeployScriptFunction} from '@agoric/deploy-script-support/src/externalTypes.js';
*/

/** @type {ParseArgsConfig['options']} */
const parserOpts = {
assets: { type: 'string' },
};

/** @type {CoreEvalBuilder} */
export const defaultProposalBuilder = async (_, options) => {
return harden({
sourceSpec:
'@agoric/builders/scripts/testing/register-interchain-bank-assets.js',
getManifestCall: ['getManifestCall', options],
});
};

/** @type {DeployScriptFunction} */
export default async (homeP, endowments) => {
const { scriptArgs } = endowments;

const {
values: { assets },
} = parseArgs({
args: scriptArgs,
options: parserOpts,
});

const parseAssets = () => {
if (typeof assets !== 'string') {
throw Error(
'must provide --assets=JSON.stringify({ denom: Denom; issuerName: string; decimalPlaces: number; }[])',
);
}
return JSON.parse(assets);
};

const opts = harden({ assets: parseAssets() });

const { writeCoreEval } = await makeHelpers(homeP, endowments);
await writeCoreEval('eval-register-interchain-bank-assets', utils =>
defaultProposalBuilder(utils, opts),
);
};
2 changes: 1 addition & 1 deletion multichain-testing/src/revise-chain-info.builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@ export const defaultProposalBuilder = async () =>
/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').DeployScriptFunction} */
export default async (homeP, endowments) => {
const { writeCoreEval } = await makeHelpers(homeP, endowments);
await writeCoreEval('revise-chain-info', defaultProposalBuilder);
await writeCoreEval('eval-revise-chain-info', defaultProposalBuilder);
};
30 changes: 30 additions & 0 deletions multichain-testing/test/scripts/make-bank-asset-info.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import test from 'ava';
import { execFileSync } from 'node:child_process';

test('make-bank-asset-info', async t => {
const stdout = execFileSync('./scripts/make-bank-asset-info.ts', {
encoding: 'utf8',
});

const assetInfo = JSON.parse(stdout);

t.like(assetInfo, [
{
issuerName: 'ATOM',
decimalPlaces: 6,
},
{
issuerName: 'OSMO',
decimalPlaces: 6,
},
{
issuerName: 'ION',
decimalPlaces: 6,
},
]);

for (const { denom } of assetInfo) {
t.regex(denom, /^ibc\//);
t.is(denom.length, 68);
}
});
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 @@ -106,6 +106,7 @@ test('makeAssetInfo', async t => {
{
baseDenom: 'uosmo',
baseName: 'osmosis',
brandKey: 'OSMO',
chainName: 'agoric',
},
],
Expand Down Expand Up @@ -138,6 +139,7 @@ test('makeAssetInfo', async t => {
{
baseDenom: 'uatom',
baseName: 'cosmoshub',
brandKey: 'ATOM',
chainName: 'agoric',
},
],
Expand Down
29 changes: 16 additions & 13 deletions multichain-testing/tools/asset-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import {
} from '@agoric/orchestration';
import type { IBCChannelID } from '@agoric/vats';

/** make asset info for current env */
/**
* Make asset info for the current environment.
*
* until #10580, the contract's `issuerKeywordRecord` must include 'ATOM',
* 'OSMO', 'IST', etc. for the local `chainHub` to know about brands.
*/
export const makeAssetInfo = (
chainInfo: Record<string, CosmosChainInfo>,
tokenMap: Record<string, Denom[]> = {
Expand Down Expand Up @@ -37,13 +42,6 @@ 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 @@ -62,22 +60,27 @@ export const makeAssetInfo = (
{
...baseDetails,
chainName: chain,
...(BRAND_KEY_MAP[denom] && { brandKey: BRAND_KEY_MAP[denom] }),
...(chain === 'agoric' && {
// `brandKey` instead of `brand` until #10580
// assumes issuerKeywordRecord includes brand keywords like `IST`, `OSMO`
brandKey: denom.replace(/^u/, '').toUpperCase(),
}),
},
]);

// 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([
denomHash,
toDenomHash(denom, issuingChainId, holdingChain),
{
...baseDetails,
chainName: holdingChain,
...(BRAND_KEY_MAP[denomHash] && {
brandKey: BRAND_KEY_MAP[denomHash],
...(holdingChain === 'agoric' && {
// `brandKey` instead of `brand` until #10580
// assumes issuerKeywordRecord includes brand keywords like `IST`, `OSMO`
brandKey: denom.replace(/^u/, '').toUpperCase(),
}),
},
]);
Expand Down
2 changes: 1 addition & 1 deletion multichain-testing/tools/e2e-tools.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ export const provisionSmartWallet = async (
for await (const [name, qty] of Object.entries(balances)) {
const info = byName[name];
if (!info) {
throw Error(name);
throw Error(`${name} not found in vbank assets`);
}
const { denom, displayInfo } = info;
const { decimalPlaces } = displayInfo;
Expand Down
1 change: 1 addition & 0 deletions multichain-testing/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"extends": "../tsconfig.json",
"include": [
"src",
"tools",
"test"
],
Expand Down
Loading

0 comments on commit 0e20707

Please sign in to comment.