Skip to content

Commit 1c1cd6f

Browse files
committed
feat: override isValidAddress for hbarevm
ticket: WIN-8724
1 parent 32059a0 commit 1c1cd6f

File tree

4 files changed

+130
-5
lines changed

4 files changed

+130
-5
lines changed

modules/sdk-coin-evm/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
"@ethereumjs/common": "^2.6.5",
2323
"superagent": "^9.0.1"
2424
},
25+
"devDependencies": {
26+
"@bitgo/sdk-api": "^1.73.4",
27+
"@bitgo/sdk-test": "^9.1.25"
28+
},
2529
"author": "BitGo SDK Team <sdkteam@bitgo.com>",
2630
"license": "MIT",
2731
"repository": {

modules/sdk-coin-evm/src/evmCoin.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
VerifyEthTransactionOptions,
1414
} from '@bitgo/abstract-eth';
1515
import { TransactionBuilder } from './lib';
16-
import { recovery_HBAREVM_BlockchainExplorerQuery } from './lib/utils';
16+
import { recovery_HBAREVM_BlockchainExplorerQuery, validateHederaAccountId } from './lib/utils';
1717
import assert from 'assert';
1818

1919
export class EvmCoin extends AbstractEthLikeNewCoins {
@@ -135,4 +135,13 @@ export class EvmCoin extends AbstractEthLikeNewCoins {
135135
// If validation passes, consider it verified
136136
return true;
137137
}
138+
139+
/** @inheritDoc */
140+
isValidAddress(address: string, isAlternateAddress?: boolean): boolean {
141+
if (isAlternateAddress && this.getFamily() === CoinFamily.HBAREVM) {
142+
const { valid } = validateHederaAccountId(address);
143+
return valid;
144+
}
145+
return super.isValidAddress(address);
146+
}
138147
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import 'should';
2+
import { BitGoAPI } from '@bitgo/sdk-api';
3+
import { TestBitGo, TestBitGoAPI } from '@bitgo/sdk-test';
4+
import { EvmCoin } from '../../src/evmCoin';
5+
import { coins } from '@bitgo/statics';
6+
7+
describe('EvmCoin', function () {
8+
let bitgo: TestBitGoAPI;
9+
let evmCoin: EvmCoin;
10+
11+
before(function () {
12+
bitgo = TestBitGo.decorate(BitGoAPI, { env: 'test' });
13+
});
14+
15+
describe('isValidAddress', function () {
16+
beforeEach(function () {
17+
// Create EvmCoin instance for testing
18+
const staticsCoin = coins.get('hbarevm');
19+
evmCoin = new (EvmCoin as any)(bitgo, staticsCoin);
20+
});
21+
22+
it('should validate standard Ethereum addresses (backward compatible)', function () {
23+
const validAddresses = [
24+
'0x5aAeb6053f3E94C9b9A09f33669435E7Ef1BeAed',
25+
'0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359',
26+
'0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB',
27+
'0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb',
28+
'0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb1',
29+
];
30+
31+
validAddresses.forEach((address) => {
32+
evmCoin.isValidAddress(address).should.be.true(`${address} should be valid`);
33+
});
34+
});
35+
36+
it('should validate addresses without 0x prefix (backward compatible)', function () {
37+
const validAddresses = ['5aAeb6053f3E94C9b9A09f33669435E7Ef1BeAed', 'fB6916095ca1df60bB79Ce92cE3Ea74c37c5d359'];
38+
39+
validAddresses.forEach((address) => {
40+
evmCoin.isValidAddress(address).should.be.true(`${address} should be valid`);
41+
});
42+
});
43+
44+
it('should reject invalid Ethereum addresses (backward compatible)', function () {
45+
const invalidAddresses = [
46+
'0xInvalidAddress',
47+
'0x123',
48+
'not-an-address',
49+
'',
50+
'0x',
51+
'0xzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz',
52+
];
53+
54+
invalidAddresses.forEach((address) => {
55+
evmCoin.isValidAddress(address).should.be.false(`${address} should be invalid`);
56+
});
57+
});
58+
59+
it('should work with first parameter only (backward compatible)', function () {
60+
const address = '0x5aAeb6053f3E94C9b9A09f33669435E7Ef1BeAed';
61+
evmCoin.isValidAddress(address).should.be.true();
62+
});
63+
64+
describe('with optional isAlternateAddress parameter for HBAREVM', function () {
65+
it('should validate Hedera account IDs when isAlternateAddress is true', function () {
66+
const validHederaAccountIds = ['0.0.123456', '0.0.1234567890', '0.0.1'];
67+
68+
validHederaAccountIds.forEach((accountId) => {
69+
evmCoin.isValidAddress(accountId, true).should.be.true(`${accountId} should be valid`);
70+
});
71+
});
72+
73+
it('should reject invalid Hedera account IDs when isAlternateAddress is true', function () {
74+
const invalidHederaAccountIds = ['0.0', '0.0.abc', '0.0.-123', 'not-an-account-id'];
75+
76+
invalidHederaAccountIds.forEach((accountId) => {
77+
evmCoin.isValidAddress(accountId, true).should.be.false(`${accountId} should be invalid`);
78+
});
79+
});
80+
81+
it('should still validate Ethereum addresses when isAlternateAddress is false', function () {
82+
const ethAddress = '0x5aAeb6053f3E94C9b9A09f33669435E7Ef1BeAed';
83+
evmCoin.isValidAddress(ethAddress, false).should.be.true();
84+
});
85+
86+
it('should validate Ethereum addresses when isAlternateAddress is undefined (default)', function () {
87+
const ethAddress = '0x5aAeb6053f3E94C9b9A09f33669435E7Ef1BeAed';
88+
evmCoin.isValidAddress(ethAddress, undefined).should.be.true();
89+
});
90+
});
91+
92+
describe('for non-HBAREVM coins', function () {
93+
beforeEach(function () {
94+
// Create a non-HBAREVM coin instance
95+
const staticsCoin = coins.get('polygon');
96+
evmCoin = new (EvmCoin as any)(bitgo, staticsCoin);
97+
});
98+
99+
it('should validate standard Ethereum addresses regardless of isAlternateAddress flag', function () {
100+
const ethAddress = '0x5aAeb6053f3E94C9b9A09f33669435E7Ef1BeAed';
101+
evmCoin.isValidAddress(ethAddress).should.be.true();
102+
evmCoin.isValidAddress(ethAddress, false).should.be.true();
103+
evmCoin.isValidAddress(ethAddress, true).should.be.true();
104+
});
105+
106+
it('should not validate Hedera account IDs even with isAlternateAddress=true', function () {
107+
const hederaAccountId = '0.0.123456';
108+
evmCoin.isValidAddress(hederaAccountId, true).should.be.false();
109+
});
110+
});
111+
});
112+
});

yarn.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3080,10 +3080,10 @@
30803080
resolved "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz"
30813081
integrity sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==
30823082

3083-
"@isaacs/brace-expansion@^5.0.0":
3084-
version "5.0.0"
3085-
resolved "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz"
3086-
integrity sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==
3083+
"@isaacs/brace-expansion@5.0.1", "@isaacs/brace-expansion@^5.0.0":
3084+
version "5.0.1"
3085+
resolved "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.1.tgz#0ef5a92d91f2fff2a37646ce54da9e5f599f6eff"
3086+
integrity sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==
30873087
dependencies:
30883088
"@isaacs/balanced-match" "^4.0.1"
30893089

0 commit comments

Comments
 (0)