Skip to content

Commit

Permalink
fixup! feat(chainHub): getChainInfoFromAddress helper
Browse files Browse the repository at this point in the history
  • Loading branch information
0xpatrickdev committed Oct 30, 2024
1 parent a00a0be commit f0c81c1
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 7 deletions.
7 changes: 3 additions & 4 deletions packages/orchestration/src/exos/chain-hub.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -442,14 +443,12 @@ export const makeChainHub = (zone, agoricNames, vowTools) => {
* @returns {CosmosChainInfo}
*/
getChainInfoFromAddress(address) {
const [prefix, rest] = address.split('1');
(prefix && rest) ||
Fail`Address contains invalid bech32 separator: ${q(address)}`;
const prefix = getBech32Prefix(address);
if (bech32PrefixToChainName.has(prefix)) {
const chainName = bech32PrefixToChainName.get(prefix);
return chainInfos.get(chainName);
}
throw makeError(`Chain info not found for bech32Prefix: ${q(prefix)}`);
throw makeError(`Chain info not found for bech32Prefix ${q(prefix)}`);
},
});

Expand Down
19 changes: 18 additions & 1 deletion packages/orchestration/src/utils/address.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Fail } from '@endo/errors';
import { Fail, q } from '@endo/errors';

/**
* @import {IBCConnectionID} from '@agoric/vats';
Expand Down Expand Up @@ -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);
};
8 changes: 6 additions & 2 deletions packages/orchestration/test/exos/chain-hub.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,11 +181,15 @@ test.serial('getChainInfoFromAddress', async t => {
MOCK_ICA_ADDRESS.replace('osmo1', 'foo1'),
),
{
message: 'Chain info not found for bech32Prefix: "foo"',
message: 'Chain info not found for bech32Prefix "foo"',
},
);

t.throws(() => chainHub.getChainInfoFromAddress('notbech32'), {
message: 'Address contains invalid bech32 separator: "notbech32"',
message: 'No separator character for "notbech32"',
});

t.throws(() => chainHub.getChainInfoFromAddress('1notbech32'), {
message: 'Missing prefix for "1notbech32"',
});
});
40 changes: 40 additions & 0 deletions packages/orchestration/test/utils/address.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
makeICAChannelAddress,
makeICQChannelAddress,
findAddressField,
getBech32Prefix,
} from '../../src/utils/address.js';

test('makeICAChannelAddress', t => {
Expand Down Expand Up @@ -107,3 +108,42 @@ test('makeICQChannelAddress', t => {
'makeICQChannelAddress not hardened against malformed version. use `validateRemoteIbcAddress` to detect this, or expect IBC ProtocolImpl to throw',
);
});

test('getBech32Prefix', t => {
const testCases = [
{
specimen: 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4',
expected: 'bc',
error: undefined,
},
{
specimen: 'cosmos1n4f2eqt2gm5mh6gevf8aw2wrf75q25yru09yvn',
expected: 'cosmos',
error: undefined,
},
{
specimen: '111qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4',
expected: '11',
error: undefined,
},
{
specimen: 'qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4',
expected: undefined,
error:
'No separator character for "qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"',
},
{
specimen: '1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4',
expected: undefined,
error: 'Missing prefix for "1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"',
},
];

for (const { specimen, expected, error } of testCases) {
if (expected) {
t.is(getBech32Prefix(specimen), expected);
} else {
t.throws(() => getBech32Prefix(specimen), { message: error });
}
}
});

0 comments on commit f0c81c1

Please sign in to comment.