From d6c487c1aca11b2287253b8885778dff9fd27a55 Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Sat, 26 Oct 2024 12:10:36 -0400 Subject: [PATCH] feat(chainHub): `getChainInfoByAddress` helper - takes a ChainAddress.value, parses the bech32Prefix, and looks up the corresponding ChainInfo --- packages/orchestration/src/exos/chain-hub.js | 25 ++++++++++++++ packages/orchestration/src/utils/address.js | 19 ++++++++++- .../snapshots/send-anywhere.test.ts.md | 3 ++ .../snapshots/send-anywhere.test.ts.snap | Bin 1674 -> 1702 bytes .../snapshots/staking-combinations.test.ts.md | 4 +++ .../staking-combinations.test.ts.snap | Bin 2707 -> 2743 bytes .../snapshots/unbond.contract.test.ts.md | 5 +++ .../snapshots/unbond.contract.test.ts.snap | Bin 2284 -> 2328 bytes .../orchestration/test/exos/chain-hub.test.ts | 32 ++++++++++++++++++ .../orchestration/test/utils/address.test.ts | 31 +++++++++++++++++ 10 files changed, 118 insertions(+), 1 deletion(-) diff --git a/packages/orchestration/src/exos/chain-hub.js b/packages/orchestration/src/exos/chain-hub.js index 120d51fae9a..6b86cfe881a 100644 --- a/packages/orchestration/src/exos/chain-hub.js +++ b/packages/orchestration/src/exos/chain-hub.js @@ -5,6 +5,7 @@ import { BrandShape } from '@agoric/ertp/src/typeGuards.js'; import { VowShape } from '@agoric/vow'; import { CosmosChainInfoShape, IBCConnectionInfoShape } from '../typeGuards.js'; +import { getBech32Prefix } from '../utils/address.js'; /** * @import {NameHub} from '@agoric/vats'; @@ -180,6 +181,7 @@ const ChainHubI = M.interface('ChainHub', { registerAsset: M.call(M.string(), DenomDetailShape).returns(), getAsset: M.call(M.string()).returns(M.or(DenomDetailShape, M.undefined())), getDenom: M.call(BrandShape).returns(M.or(M.string(), M.undefined())), + getChainInfoByAddress: M.call(M.string()).returns(CosmosChainInfoShape), }); /** @@ -216,6 +218,11 @@ export const makeChainHub = (zone, agoricNames, vowTools) => { keyShape: BrandShape, valueShape: M.string(), }); + /** @type {MapStore} */ + const bech32PrefixToChainName = zone.mapStore('bech32PrefixToChainName', { + keyShape: M.string(), + valueShape: M.string(), + }); const lookupChainInfo = vowTools.retryable( zone, @@ -230,6 +237,9 @@ export const makeChainHub = (zone, agoricNames, vowTools) => { // TODO consider makeAtomicProvider for vows if (!chainInfos.has(chainName)) { chainInfos.init(chainName, chainInfo); + if (chainInfo.bech32Prefix) { + bech32PrefixToChainName.init(chainInfo.bech32Prefix, chainName); + } } return chainInfo; } catch (e) { @@ -316,6 +326,9 @@ export const makeChainHub = (zone, agoricNames, vowTools) => { */ registerChain(name, chainInfo) { chainInfos.init(name, chainInfo); + if (chainInfo.bech32Prefix) { + bech32PrefixToChainName.init(chainInfo.bech32Prefix, name); + } }, /** * @template {string} K @@ -425,6 +438,18 @@ export const makeChainHub = (zone, agoricNames, vowTools) => { } return undefined; }, + /** + * @param {string} address bech32 address + * @returns {CosmosChainInfo} + */ + getChainInfoByAddress(address) { + const prefix = getBech32Prefix(address); + if (!bech32PrefixToChainName.has(prefix)) { + throw makeError(`Chain info not found for bech32Prefix ${q(prefix)}`); + } + const chainName = bech32PrefixToChainName.get(prefix); + return chainInfos.get(chainName); + }, }); return chainHub; diff --git a/packages/orchestration/src/utils/address.js b/packages/orchestration/src/utils/address.js index 1735040c401..8d39ed5afa6 100644 --- a/packages/orchestration/src/utils/address.js +++ b/packages/orchestration/src/utils/address.js @@ -1,4 +1,4 @@ -import { Fail } from '@endo/errors'; +import { Fail, q } from '@endo/errors'; /** * @import {IBCConnectionID} from '@agoric/vats'; @@ -84,3 +84,20 @@ export const findAddressField = remoteAddressString => { } }; harden(findAddressField); + +/** + * Extracts the human readable part (HRP), aka `bech32Prefix`, from an address. + * + * see + * [bech32.js](https://github.com/bitcoinjs/bech32/blob/5ceb0e3d4625561a459c85643ca6947739b2d83c/src/index.ts#L146) + * for reference implementation + * + * @param {string} address + */ +export const getBech32Prefix = address => { + assert(address, 'address is required'); + const split = address.lastIndexOf('1'); + if (split === -1) return Fail`No separator character for ${q(address)}`; + if (split === 0) return Fail`Missing prefix for ${q(address)}`; + return address.slice(0, split); +}; diff --git a/packages/orchestration/test/examples/snapshots/send-anywhere.test.ts.md b/packages/orchestration/test/examples/snapshots/send-anywhere.test.ts.md index 14c7fa11ebb..cb7e77f4a24 100644 --- a/packages/orchestration/test/examples/snapshots/send-anywhere.test.ts.md +++ b/packages/orchestration/test/examples/snapshots/send-anywhere.test.ts.md @@ -34,6 +34,9 @@ Generated by [AVA](https://avajs.dev). chainHub: { ChainHub_kindHandle: 'Alleged: kind', ChainHub_singleton: 'Alleged: ChainHub', + bech32PrefixToChainName: { + agoric: 'agoric', + }, brandDenom: {}, chainInfos: { agoric: { diff --git a/packages/orchestration/test/examples/snapshots/send-anywhere.test.ts.snap b/packages/orchestration/test/examples/snapshots/send-anywhere.test.ts.snap index 92840da3e5e14bb69f79fb2722b5327186c9a1c0..019aa9a9d1af05779e75d69327a22ac5f66f262f 100644 GIT binary patch literal 1702 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 UD;6`#rbP|wKj|Q*e1a7K0D)pMb^rhX diff --git a/packages/orchestration/test/examples/snapshots/staking-combinations.test.ts.md b/packages/orchestration/test/examples/snapshots/staking-combinations.test.ts.md index 8c787b28444..bbf2ad9192b 100644 --- a/packages/orchestration/test/examples/snapshots/staking-combinations.test.ts.md +++ b/packages/orchestration/test/examples/snapshots/staking-combinations.test.ts.md @@ -30,6 +30,10 @@ Generated by [AVA](https://avajs.dev). chainHub: { ChainHub_kindHandle: 'Alleged: kind', ChainHub_singleton: 'Alleged: ChainHub', + bech32PrefixToChainName: { + agoric: 'agoric', + cosmos: 'cosmoshub', + }, brandDenom: { 'Alleged: BLD brand': 'ubld', }, diff --git a/packages/orchestration/test/examples/snapshots/staking-combinations.test.ts.snap b/packages/orchestration/test/examples/snapshots/staking-combinations.test.ts.snap index 694625ae9256de203d6ffae379762c326dddfb27..01a323d924f17902e88e58d2a0c44d1e0f98fc89 100644 GIT binary patch literal 2743 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 literal 2707 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 literal 2284 zcmV$V4HS_9CYN?h+sc8|zQcXr0 z=BjR)S8pl`vB<^oxBUpC^-qdOk$C_M06qiYrvP39@Gk%b2{}1m*RgF$8HmjOyu1?&qTFYxHQ%(`4XtWDU%xW5~ zQRM>@Et}vYyF_K(P^i%daafYhNI=&dCFTZ`=QVxZHa*3eBJwIx*{NpLw*1j$(V1ls z*|IHrd_7A-H{?}nS_ZLHo!RD#oH=k=UpHH;n7Hl(zUTvP`GCEC;2}Togdcd_4 zd;oYf06Y@_UJL+l1ca6KxmPwK#cmG*2ZBH?2s|AGeh>tH9R%JE0@)C7E(AOg65NDE zH-X=UfIo$Ra2S{i3-B=!9(^TJ*mD)UWd6ECoJgESg_<+RH~+3UeGjgsTQ1GaPahp}GHrWW+tIZHR_8ETQ1 z9*BppYacYw;yH_0bdY(rjv*IWu6=f!Oum=YsPQ0KqlRgt{6jrd+Cj||Rcjiw4cW^> zRy2KmUN_D*Em^PA2R!>3ZQ4vzz(PI7#6mML>i5QBOe?|5>}q7Nqtv<&YE_N}3<_1rbmo<^%=$@4^}1DC8k z&-H9?&Y^NJJH&|K=fIq9)^&5@EFb5@tSswIW=)*Zwf?H2%jX>nx=ge!T<)Sgmu-Lc z*3J`|C<80SNG}w9;Mr7`XkEAHV8ahf65?E!V4s%{k~+0b`#4iXt;*+hU2C6{OPpn> zLF6@Rb&Lr}AtAC+yM`=L%h+gjK)Weel}%iDvZ?GYS}wGx$%}?wS55jLvE2;NypY@1~+APt)XqL5l`3klQ{76IPh8=_@@|T)C12afN}yjo&c%|0iNA<>`~E~ z?^6ljn&@O)g!#Xj0KSs|UKF9XdBXcc0{BY;m>vd4qxX&yR4=!?v=j?SrlI1k*B9g>vp5=d78wyZr~3 zJN*6AHs%*ez9;Eo+O9f~Sc-GwusKY7n!}Pb%OTTER@Ip@%arp5VdhG!hf6^6*+4C| z#e_bW+Hykfa(ep2T-Wb8$`oqsrUIx{d5M}$&DyQ7cpP|CuITVZ?562aTKTEO z5-Fi;8Q`-S;71wY)eI2H0=H!aTFyh8&jJfs;A2_f@htFM7I;;pjd*Cj91zI?_vC;} zIpC8y;6_fMl{^CSYz}xn2l(;=bixB2%L9{n;DiW$j|X}&4=m?_kBZRSJrWTRav)x% z^6J5vMT4%WS3Gjyf`;22v*MKf?gnTl(tf{PaUSFfk z>_4zT>-g>vR+Q76?c++?aeeo{5SODK+b>v8#rj#WSGErvhU3b5q~p24#xMYJ5_!a{SnBa-js5#YBY zaCNOi?ygnx{dolVn*bUXL2r$;?r`0pv;gwQ3P7p=oGb`hn-^s{vQYp&UI4yc0DfNp z_7s7`Mc_k4V52C|_jpwOsUq;zB5+HD7Ca**N&mtfU6bY$%;U)c-q__SAZ8p*xqg1-1nxX zy-pr_USvDB1Dg@w*Eca{_eMjK^h(9P;&*-rN8P{gZ2#UQVf)a5sbd0%6Q|{^4*j8H zn|?BAy^XidG*|XIPdo~p?`X|pOKavt+EABvaAr!pd*g|Vx?ypZ%yQan7bRkUg6N*x z*6W7L9BTCCMbtI7GF+yHsrGu_uqvA~Q=K=1op&WI)Wn(oHf5OKl=;$aSw~5 z^tmb1hs2uof4M2%Mx~D};k%NVJ~xER_9FxBh;zCQ|L^Zd`}O(UXs?<|Q?@ui@{YQF zVpI_4xJScpjsjm3VM!0{g;C%o5ti}5{yqx4CBojdeu3x% zXj+ECEmv-gyYGBNUg=zEMx^lBG2p@&@P#qp^)X=IIM5sizCA8X>fN46iMOF+#5Ad4 zU0~|NO?p4wSl10@&})Lx&3t%n3M!6^P2l3i1F`hFDlbuD7=+aZ|HvisJ<$|;(YT?a zr#e}qr`cuIBD?u4QV{6deA;v)sYa?)yHe?X^PZ@ZT8-4`1X;1DF=79ofqw%_&0|GM GAOHZyTVgx_ diff --git a/packages/orchestration/test/exos/chain-hub.test.ts b/packages/orchestration/test/exos/chain-hub.test.ts index 81b22718c46..95119b96fa8 100644 --- a/packages/orchestration/test/exos/chain-hub.test.ts +++ b/packages/orchestration/test/exos/chain-hub.test.ts @@ -159,3 +159,35 @@ test.serial('toward asset info in agoricNames (#9572)', async t => { }); } }); + +test.serial('getChainInfoByAddress', async t => { + const { chainHub, nameAdmin, vt } = setup(); + // use fetched chain info + await registerKnownChains(nameAdmin); + + // call getChainInfo so ChainHub performs agoricNames lookup that populates its local cache + await vt.asPromise(chainHub.getChainInfo('osmosis')); + + const MOCK_ICA_ADDRESS = + 'osmo1ht7u569vpuryp6utadsydcne9ckeh2v8dkd38v5hptjl3u2ewppqc6kzgd'; + t.like(chainHub.getChainInfoByAddress(MOCK_ICA_ADDRESS), { + chainId: 'osmosis-1', + bech32Prefix: 'osmo', + }); + + t.throws( + () => + chainHub.getChainInfoByAddress(MOCK_ICA_ADDRESS.replace('osmo1', 'foo1')), + { + message: 'Chain info not found for bech32Prefix "foo"', + }, + ); + + t.throws(() => chainHub.getChainInfoByAddress('notbech32'), { + message: 'No separator character for "notbech32"', + }); + + t.throws(() => chainHub.getChainInfoByAddress('1notbech32'), { + message: 'Missing prefix for "1notbech32"', + }); +}); diff --git a/packages/orchestration/test/utils/address.test.ts b/packages/orchestration/test/utils/address.test.ts index 9012edc9da3..ecdf12b688b 100644 --- a/packages/orchestration/test/utils/address.test.ts +++ b/packages/orchestration/test/utils/address.test.ts @@ -4,6 +4,7 @@ import { makeICAChannelAddress, makeICQChannelAddress, findAddressField, + getBech32Prefix, } from '../../src/utils/address.js'; test('makeICAChannelAddress', t => { @@ -107,3 +108,33 @@ test('makeICQChannelAddress', t => { 'makeICQChannelAddress not hardened against malformed version. use `validateRemoteIbcAddress` to detect this, or expect IBC ProtocolImpl to throw', ); }); + +const bech32 = test.macro({ + title: (_, input: string, expected: string | null) => + expected !== null + ? `can extract ${expected} prefix from ${input}` + : `throws error for invalid address ${input}`, + exec: (t, input: string, expected: string | null, error?: string) => { + if (expected !== null) { + t.is(getBech32Prefix(input), expected); + } else { + t.throws(() => getBech32Prefix(input), { message: error }); + } + }, +}); + +test(bech32, 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4', 'bc'); +test(bech32, 'cosmos1n4f2eqt2gm5mh6gevf8aw2wrf75q25yru09yvn', 'cosmos'); +test(bech32, '111qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4', '11'); +test( + bech32, + 'qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4', + null, + 'No separator character for "qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"', +); +test( + bech32, + '1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4', + null, + 'Missing prefix for "1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"', +);