multichain-address-validator 0.7.5 → 0.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/chain-validators.js +7 -3
- package/dist/cjs/crypto/blake256.d.ts +6 -5
- package/dist/cjs/crypto/blake256.js +8 -7
- package/dist/cjs/crypto/utils.d.ts +1 -1
- package/dist/cjs/helpers.d.ts +1 -0
- package/dist/cjs/helpers.js +6 -0
- package/dist/cjs/validators/ripple_validator.d.ts +2 -2
- package/dist/cjs/validators/ripple_validator.js +8 -8
- package/dist/cjs/validators/xlm_validator.d.ts +1 -1
- package/dist/cjs/validators/xlm_validator.js +2 -2
- package/dist/esm/chain-validators.js +7 -3
- package/dist/esm/crypto/blake256.d.ts +6 -5
- package/dist/esm/crypto/blake256.js +1 -0
- package/dist/esm/crypto/utils.d.ts +1 -1
- package/dist/esm/helpers.d.ts +1 -0
- package/dist/esm/helpers.js +5 -0
- package/dist/esm/validators/ripple_validator.d.ts +2 -2
- package/dist/esm/validators/ripple_validator.js +9 -9
- package/dist/esm/validators/xlm_validator.d.ts +1 -1
- package/dist/esm/validators/xlm_validator.js +3 -3
- package/package.json +1 -1
- package/src/chain-validators.ts +7 -3
- package/src/crypto/blake256.js +2 -0
- package/src/helpers.ts +6 -0
- package/src/validators/ripple_validator.ts +9 -9
- package/src/validators/xlm_validator.ts +4 -4
- package/test/addresses/addresses.ts +7 -2
- package/test/addresses/doge.json +2 -1
- package/test/addresses/ripple.json +7 -2
- package/test/addresses/xlm.json +6 -1
- package/test/multichain-address-validator.test.ts +66 -47
|
@@ -62,6 +62,7 @@ const chainValidators = {
|
|
|
62
62
|
'EthereumPow',
|
|
63
63
|
'erc20',
|
|
64
64
|
'flare',
|
|
65
|
+
'optimism',
|
|
65
66
|
'sonic',
|
|
66
67
|
'story',
|
|
67
68
|
],
|
|
@@ -97,9 +98,12 @@ const chainValidators = {
|
|
|
97
98
|
alternatives: ['xrp'],
|
|
98
99
|
validator: index_js_1.RippleValidator,
|
|
99
100
|
},
|
|
100
|
-
sia: {
|
|
101
|
+
sia: {
|
|
102
|
+
alternatives: ['SiaCoin'],
|
|
103
|
+
validator: index_js_1.SiaValidator
|
|
104
|
+
},
|
|
101
105
|
solana: {
|
|
102
|
-
alternatives: ['spl'],
|
|
106
|
+
alternatives: ['sol', 'spl'],
|
|
103
107
|
validator: index_js_1.SolanaValidator,
|
|
104
108
|
},
|
|
105
109
|
sui: { validator: index_js_1.MoveValidator },
|
|
@@ -109,7 +113,7 @@ const chainValidators = {
|
|
|
109
113
|
},
|
|
110
114
|
tezos: { validator: index_js_1.TezosValidator },
|
|
111
115
|
xlm: {
|
|
112
|
-
alternatives: ['stellar'],
|
|
116
|
+
alternatives: ['stellar', 'stellarlumens'],
|
|
113
117
|
validator: index_js_1.XLMValidator,
|
|
114
118
|
},
|
|
115
119
|
};
|
|
@@ -3,20 +3,21 @@ declare function Blake256(): void;
|
|
|
3
3
|
declare class Blake256 {
|
|
4
4
|
_h: number[];
|
|
5
5
|
_s: number[];
|
|
6
|
-
_block:
|
|
6
|
+
_block: Buffer;
|
|
7
7
|
_blockOffset: number;
|
|
8
8
|
_length: number[];
|
|
9
9
|
_nullt: boolean;
|
|
10
|
-
_zo:
|
|
11
|
-
_oo:
|
|
10
|
+
_zo: Buffer;
|
|
11
|
+
_oo: Buffer;
|
|
12
12
|
_length_carry(arr: any): void;
|
|
13
13
|
update(data: any, encoding: any): this;
|
|
14
14
|
_compress(): void;
|
|
15
15
|
_padding(): void;
|
|
16
|
-
digest(encoding: any):
|
|
16
|
+
digest(encoding: any): string;
|
|
17
17
|
}
|
|
18
18
|
declare namespace Blake256 {
|
|
19
19
|
let sigma: number[][];
|
|
20
20
|
let u256: number[];
|
|
21
|
-
let padding:
|
|
21
|
+
let padding: Buffer;
|
|
22
22
|
}
|
|
23
|
+
import { Buffer } from 'buffer';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const buffer_1 = require("buffer");
|
|
3
4
|
/**
|
|
4
5
|
* Credits to https://github.com/cryptocoinjs/blake-hash
|
|
5
6
|
*/
|
|
@@ -27,7 +28,7 @@ Blake256.u256 = [
|
|
|
27
28
|
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
|
|
28
29
|
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917
|
|
29
30
|
];
|
|
30
|
-
Blake256.padding = Buffer.from([
|
|
31
|
+
Blake256.padding = buffer_1.Buffer.from([
|
|
31
32
|
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
32
33
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
33
34
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
@@ -46,7 +47,7 @@ Blake256.prototype._length_carry = function (arr) {
|
|
|
46
47
|
}
|
|
47
48
|
};
|
|
48
49
|
Blake256.prototype.update = function (data, encoding) {
|
|
49
|
-
data = Buffer.from(data, encoding);
|
|
50
|
+
data = buffer_1.Buffer.from(data, encoding);
|
|
50
51
|
var block = this._block;
|
|
51
52
|
var offset = 0;
|
|
52
53
|
while (this._blockOffset + data.length - offset >= block.length) {
|
|
@@ -61,8 +62,8 @@ Blake256.prototype.update = function (data, encoding) {
|
|
|
61
62
|
block[this._blockOffset++] = data[offset++];
|
|
62
63
|
return this;
|
|
63
64
|
};
|
|
64
|
-
var zo = Buffer.from([0x01]);
|
|
65
|
-
var oo = Buffer.from([0x81]);
|
|
65
|
+
var zo = buffer_1.Buffer.from([0x01]);
|
|
66
|
+
var oo = buffer_1.Buffer.from([0x81]);
|
|
66
67
|
function rot(x, n) {
|
|
67
68
|
return ((x << (32 - n)) | (x >>> n)) >>> 0;
|
|
68
69
|
}
|
|
@@ -84,7 +85,7 @@ function Blake256() {
|
|
|
84
85
|
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
|
85
86
|
];
|
|
86
87
|
this._s = [0, 0, 0, 0];
|
|
87
|
-
this._block = Buffer.allocUnsafe(64);
|
|
88
|
+
this._block = buffer_1.Buffer.allocUnsafe(64);
|
|
88
89
|
this._blockOffset = 0;
|
|
89
90
|
this._length = [0, 0];
|
|
90
91
|
this._nullt = false;
|
|
@@ -134,7 +135,7 @@ Blake256.prototype._padding = function () {
|
|
|
134
135
|
lo -= 0x0100000000;
|
|
135
136
|
hi += 1;
|
|
136
137
|
}
|
|
137
|
-
var msglen = Buffer.allocUnsafe(8);
|
|
138
|
+
var msglen = buffer_1.Buffer.allocUnsafe(8);
|
|
138
139
|
msglen.writeUInt32BE(hi, 0);
|
|
139
140
|
msglen.writeUInt32BE(lo, 4);
|
|
140
141
|
if (this._blockOffset === 55) {
|
|
@@ -163,7 +164,7 @@ Blake256.prototype._padding = function () {
|
|
|
163
164
|
};
|
|
164
165
|
Blake256.prototype.digest = function (encoding) {
|
|
165
166
|
this._padding();
|
|
166
|
-
var buffer = Buffer.allocUnsafe(32);
|
|
167
|
+
var buffer = buffer_1.Buffer.allocUnsafe(32);
|
|
167
168
|
for (var i = 0; i < 8; ++i)
|
|
168
169
|
buffer.writeUInt32BE(this._h[i], i * 4);
|
|
169
170
|
return buffer.toString(encoding);
|
|
@@ -9,7 +9,7 @@ declare const _default: {
|
|
|
9
9
|
sha256Checksum: (payload: any) => any;
|
|
10
10
|
sha512: (payload: any, format?: string) => string;
|
|
11
11
|
sha512_256: (payload: any, format?: string) => string;
|
|
12
|
-
blake256: (hexString: string) =>
|
|
12
|
+
blake256: (hexString: string) => string;
|
|
13
13
|
blake256Checksum: (payload: any) => any;
|
|
14
14
|
blake2b: (hexString: string, outlen: number) => any;
|
|
15
15
|
keccak256: (hexString: string) => string;
|
package/dist/cjs/helpers.d.ts
CHANGED
package/dist/cjs/helpers.js
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getAddress = getAddress;
|
|
4
|
+
exports.getMemo = getMemo;
|
|
4
5
|
function getAddress(address) {
|
|
5
6
|
return typeof address === 'string'
|
|
6
7
|
? address
|
|
7
8
|
: address.address;
|
|
8
9
|
}
|
|
10
|
+
function getMemo(address) {
|
|
11
|
+
return typeof address === 'string'
|
|
12
|
+
? undefined
|
|
13
|
+
: address.memo;
|
|
14
|
+
}
|
|
@@ -4,7 +4,7 @@ declare const _default: {
|
|
|
4
4
|
* ripple address validation
|
|
5
5
|
*/
|
|
6
6
|
isValidAddress: (address: Address) => any;
|
|
7
|
-
verifyMemo(
|
|
8
|
-
verifyChecksum
|
|
7
|
+
verifyMemo(memo?: string): boolean;
|
|
8
|
+
verifyChecksum(address: string): boolean;
|
|
9
9
|
};
|
|
10
10
|
export default _default;
|
|
@@ -15,18 +15,18 @@ exports.default = {
|
|
|
15
15
|
*/
|
|
16
16
|
isValidAddress: function (address) {
|
|
17
17
|
const addr = (0, helpers_js_1.getAddress)(address);
|
|
18
|
-
const
|
|
18
|
+
const memo = (0, helpers_js_1.getMemo)(address);
|
|
19
19
|
const validAddress = regexp.test(addr) && this.verifyChecksum(addr);
|
|
20
|
-
return validAddress && this.verifyMemo(
|
|
20
|
+
return validAddress && this.verifyMemo(memo);
|
|
21
21
|
},
|
|
22
|
-
verifyMemo(
|
|
23
|
-
if (!
|
|
22
|
+
verifyMemo(memo) {
|
|
23
|
+
if (!memo)
|
|
24
24
|
return true; // Optional
|
|
25
|
-
const
|
|
26
|
-
// A
|
|
27
|
-
return /^[0-9]+$/.test(
|
|
25
|
+
const memoNumber = Number(memo);
|
|
26
|
+
// A memo is a 32-bit unsigned integer.
|
|
27
|
+
return /^[0-9]+$/.test(memo) && memoNumber >= 0 && memoNumber <= 4294967295;
|
|
28
28
|
},
|
|
29
|
-
verifyChecksum
|
|
29
|
+
verifyChecksum(address) {
|
|
30
30
|
const bytes = codec.decode(address);
|
|
31
31
|
const computedChecksum = utils_js_1.default.sha256Checksum(utils_js_1.default.toHex(bytes.slice(0, -4)));
|
|
32
32
|
const checksum = utils_js_1.default.toHex(bytes.slice(-4));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Address } from '../types.js';
|
|
2
2
|
declare const _default: {
|
|
3
3
|
isValidAddress: (address: Address) => any;
|
|
4
|
-
verifyMemo(memo
|
|
4
|
+
verifyMemo(memo?: string): boolean;
|
|
5
5
|
verifyChecksum: (address: string) => boolean;
|
|
6
6
|
};
|
|
7
7
|
export default _default;
|
|
@@ -19,9 +19,9 @@ function swap16(number) {
|
|
|
19
19
|
exports.default = {
|
|
20
20
|
isValidAddress: function (address) {
|
|
21
21
|
const addr = (0, helpers_js_1.getAddress)(address);
|
|
22
|
-
const
|
|
22
|
+
const memo = (0, helpers_js_1.getMemo)(address);
|
|
23
23
|
const validAddress = regexp.test(addr) && this.verifyChecksum(addr);
|
|
24
|
-
return validAddress && this.verifyMemo(
|
|
24
|
+
return validAddress && this.verifyMemo(memo);
|
|
25
25
|
},
|
|
26
26
|
verifyMemo(memo) {
|
|
27
27
|
if (!memo)
|
|
@@ -59,6 +59,7 @@ const chainValidators = {
|
|
|
59
59
|
'EthereumPow',
|
|
60
60
|
'erc20',
|
|
61
61
|
'flare',
|
|
62
|
+
'optimism',
|
|
62
63
|
'sonic',
|
|
63
64
|
'story',
|
|
64
65
|
],
|
|
@@ -94,9 +95,12 @@ const chainValidators = {
|
|
|
94
95
|
alternatives: ['xrp'],
|
|
95
96
|
validator: RippleValidator,
|
|
96
97
|
},
|
|
97
|
-
sia: {
|
|
98
|
+
sia: {
|
|
99
|
+
alternatives: ['SiaCoin'],
|
|
100
|
+
validator: SiaValidator
|
|
101
|
+
},
|
|
98
102
|
solana: {
|
|
99
|
-
alternatives: ['spl'],
|
|
103
|
+
alternatives: ['sol', 'spl'],
|
|
100
104
|
validator: SolanaValidator,
|
|
101
105
|
},
|
|
102
106
|
sui: { validator: MoveValidator },
|
|
@@ -106,7 +110,7 @@ const chainValidators = {
|
|
|
106
110
|
},
|
|
107
111
|
tezos: { validator: TezosValidator },
|
|
108
112
|
xlm: {
|
|
109
|
-
alternatives: ['stellar'],
|
|
113
|
+
alternatives: ['stellar', 'stellarlumens'],
|
|
110
114
|
validator: XLMValidator,
|
|
111
115
|
},
|
|
112
116
|
};
|
|
@@ -3,20 +3,21 @@ declare function Blake256(): void;
|
|
|
3
3
|
declare class Blake256 {
|
|
4
4
|
_h: number[];
|
|
5
5
|
_s: number[];
|
|
6
|
-
_block:
|
|
6
|
+
_block: Buffer;
|
|
7
7
|
_blockOffset: number;
|
|
8
8
|
_length: number[];
|
|
9
9
|
_nullt: boolean;
|
|
10
|
-
_zo:
|
|
11
|
-
_oo:
|
|
10
|
+
_zo: Buffer;
|
|
11
|
+
_oo: Buffer;
|
|
12
12
|
_length_carry(arr: any): void;
|
|
13
13
|
update(data: any, encoding: any): this;
|
|
14
14
|
_compress(): void;
|
|
15
15
|
_padding(): void;
|
|
16
|
-
digest(encoding: any):
|
|
16
|
+
digest(encoding: any): string;
|
|
17
17
|
}
|
|
18
18
|
declare namespace Blake256 {
|
|
19
19
|
let sigma: number[][];
|
|
20
20
|
let u256: number[];
|
|
21
|
-
let padding:
|
|
21
|
+
let padding: Buffer;
|
|
22
22
|
}
|
|
23
|
+
import { Buffer } from 'buffer';
|
|
@@ -9,7 +9,7 @@ declare const _default: {
|
|
|
9
9
|
sha256Checksum: (payload: any) => any;
|
|
10
10
|
sha512: (payload: any, format?: string) => string;
|
|
11
11
|
sha512_256: (payload: any, format?: string) => string;
|
|
12
|
-
blake256: (hexString: string) =>
|
|
12
|
+
blake256: (hexString: string) => string;
|
|
13
13
|
blake256Checksum: (payload: any) => any;
|
|
14
14
|
blake2b: (hexString: string, outlen: number) => any;
|
|
15
15
|
keccak256: (hexString: string) => string;
|
package/dist/esm/helpers.d.ts
CHANGED
package/dist/esm/helpers.js
CHANGED
|
@@ -4,7 +4,7 @@ declare const _default: {
|
|
|
4
4
|
* ripple address validation
|
|
5
5
|
*/
|
|
6
6
|
isValidAddress: (address: Address) => any;
|
|
7
|
-
verifyMemo(
|
|
8
|
-
verifyChecksum
|
|
7
|
+
verifyMemo(memo?: string): boolean;
|
|
8
|
+
verifyChecksum(address: string): boolean;
|
|
9
9
|
};
|
|
10
10
|
export default _default;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import baseX from 'base-x';
|
|
2
2
|
import cryptoUtils from '../crypto/utils.js';
|
|
3
|
-
import { getAddress } from '../helpers.js';
|
|
3
|
+
import { getAddress, getMemo } from '../helpers.js';
|
|
4
4
|
const ALLOWED_CHARS = 'rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz';
|
|
5
5
|
const codec = baseX(ALLOWED_CHARS);
|
|
6
6
|
const regexp = new RegExp('^r[' + ALLOWED_CHARS + ']{27,35}$');
|
|
@@ -10,18 +10,18 @@ export default {
|
|
|
10
10
|
*/
|
|
11
11
|
isValidAddress: function (address) {
|
|
12
12
|
const addr = getAddress(address);
|
|
13
|
-
const
|
|
13
|
+
const memo = getMemo(address);
|
|
14
14
|
const validAddress = regexp.test(addr) && this.verifyChecksum(addr);
|
|
15
|
-
return validAddress && this.verifyMemo(
|
|
15
|
+
return validAddress && this.verifyMemo(memo);
|
|
16
16
|
},
|
|
17
|
-
verifyMemo(
|
|
18
|
-
if (!
|
|
17
|
+
verifyMemo(memo) {
|
|
18
|
+
if (!memo)
|
|
19
19
|
return true; // Optional
|
|
20
|
-
const
|
|
21
|
-
// A
|
|
22
|
-
return /^[0-9]+$/.test(
|
|
20
|
+
const memoNumber = Number(memo);
|
|
21
|
+
// A memo is a 32-bit unsigned integer.
|
|
22
|
+
return /^[0-9]+$/.test(memo) && memoNumber >= 0 && memoNumber <= 4294967295;
|
|
23
23
|
},
|
|
24
|
-
verifyChecksum
|
|
24
|
+
verifyChecksum(address) {
|
|
25
25
|
const bytes = codec.decode(address);
|
|
26
26
|
const computedChecksum = cryptoUtils.sha256Checksum(cryptoUtils.toHex(bytes.slice(0, -4)));
|
|
27
27
|
const checksum = cryptoUtils.toHex(bytes.slice(-4));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Address } from '../types.js';
|
|
2
2
|
declare const _default: {
|
|
3
3
|
isValidAddress: (address: Address) => any;
|
|
4
|
-
verifyMemo(memo
|
|
4
|
+
verifyMemo(memo?: string): boolean;
|
|
5
5
|
verifyChecksum: (address: string) => boolean;
|
|
6
6
|
};
|
|
7
7
|
export default _default;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import baseX from 'base-x';
|
|
2
2
|
import crc from 'crc';
|
|
3
3
|
import cryptoUtils from '../crypto/utils.js';
|
|
4
|
-
import { getAddress } from '../helpers.js';
|
|
4
|
+
import { getAddress, getMemo } from '../helpers.js';
|
|
5
5
|
const ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
|
|
6
6
|
const base32 = baseX(ALPHABET);
|
|
7
7
|
const regexp = new RegExp('^[' + ALPHABET + ']{56}$');
|
|
@@ -14,9 +14,9 @@ function swap16(number) {
|
|
|
14
14
|
export default {
|
|
15
15
|
isValidAddress: function (address) {
|
|
16
16
|
const addr = getAddress(address);
|
|
17
|
-
const
|
|
17
|
+
const memo = getMemo(address);
|
|
18
18
|
const validAddress = regexp.test(addr) && this.verifyChecksum(addr);
|
|
19
|
-
return validAddress && this.verifyMemo(
|
|
19
|
+
return validAddress && this.verifyMemo(memo);
|
|
20
20
|
},
|
|
21
21
|
verifyMemo(memo) {
|
|
22
22
|
if (!memo)
|
package/package.json
CHANGED
package/src/chain-validators.ts
CHANGED
|
@@ -90,6 +90,7 @@ const chainValidators: ChainValidators = {
|
|
|
90
90
|
'EthereumPow',
|
|
91
91
|
'erc20',
|
|
92
92
|
'flare',
|
|
93
|
+
'optimism',
|
|
93
94
|
'sonic',
|
|
94
95
|
'story',
|
|
95
96
|
],
|
|
@@ -125,9 +126,12 @@ const chainValidators: ChainValidators = {
|
|
|
125
126
|
alternatives: ['xrp'],
|
|
126
127
|
validator: RippleValidator,
|
|
127
128
|
},
|
|
128
|
-
sia: {
|
|
129
|
+
sia: {
|
|
130
|
+
alternatives: ['SiaCoin'],
|
|
131
|
+
validator: SiaValidator
|
|
132
|
+
},
|
|
129
133
|
solana: {
|
|
130
|
-
alternatives: ['spl'],
|
|
134
|
+
alternatives: ['sol','spl'],
|
|
131
135
|
validator: SolanaValidator,
|
|
132
136
|
},
|
|
133
137
|
sui: {validator: MoveValidator},
|
|
@@ -137,7 +141,7 @@ const chainValidators: ChainValidators = {
|
|
|
137
141
|
},
|
|
138
142
|
tezos: {validator: TezosValidator},
|
|
139
143
|
xlm: {
|
|
140
|
-
alternatives: ['stellar'],
|
|
144
|
+
alternatives: ['stellar', 'stellarlumens'],
|
|
141
145
|
validator: XLMValidator,
|
|
142
146
|
},
|
|
143
147
|
}
|
package/src/crypto/blake256.js
CHANGED
package/src/helpers.ts
CHANGED
|
@@ -2,7 +2,7 @@ import baseX from 'base-x'
|
|
|
2
2
|
|
|
3
3
|
import cryptoUtils from '../crypto/utils.js'
|
|
4
4
|
import {Address} from '../types.js'
|
|
5
|
-
import {getAddress} from '../helpers.js'
|
|
5
|
+
import {getAddress, getMemo} from '../helpers.js'
|
|
6
6
|
|
|
7
7
|
const ALLOWED_CHARS = 'rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz';
|
|
8
8
|
|
|
@@ -15,22 +15,22 @@ export default {
|
|
|
15
15
|
*/
|
|
16
16
|
isValidAddress: function (address: Address) {
|
|
17
17
|
const addr = getAddress(address)
|
|
18
|
-
const
|
|
18
|
+
const memo = getMemo(address)
|
|
19
19
|
|
|
20
20
|
const validAddress = regexp.test(addr) && this.verifyChecksum(addr);
|
|
21
21
|
|
|
22
|
-
return validAddress && this.verifyMemo(
|
|
22
|
+
return validAddress && this.verifyMemo(memo)
|
|
23
23
|
},
|
|
24
24
|
|
|
25
|
-
verifyMemo(
|
|
26
|
-
if (!
|
|
25
|
+
verifyMemo(memo?: string): boolean {
|
|
26
|
+
if (!memo) return true; // Optional
|
|
27
27
|
|
|
28
|
-
const
|
|
29
|
-
// A
|
|
30
|
-
return /^[0-9]+$/.test(
|
|
28
|
+
const memoNumber = Number(memo);
|
|
29
|
+
// A memo is a 32-bit unsigned integer.
|
|
30
|
+
return /^[0-9]+$/.test(memo) && memoNumber >= 0 && memoNumber <= 4294967295;
|
|
31
31
|
},
|
|
32
32
|
|
|
33
|
-
verifyChecksum
|
|
33
|
+
verifyChecksum(address: string): boolean {
|
|
34
34
|
const bytes = codec.decode(address);
|
|
35
35
|
const computedChecksum = cryptoUtils.sha256Checksum(cryptoUtils.toHex(bytes.slice(0, -4)));
|
|
36
36
|
const checksum = cryptoUtils.toHex(bytes.slice(-4));
|
|
@@ -3,7 +3,7 @@ import crc from 'crc'
|
|
|
3
3
|
|
|
4
4
|
import cryptoUtils from '../crypto/utils.js'
|
|
5
5
|
import {Address} from '../types.js'
|
|
6
|
-
import {getAddress} from '../helpers.js'
|
|
6
|
+
import {getAddress, getMemo} from '../helpers.js'
|
|
7
7
|
|
|
8
8
|
const ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
|
|
9
9
|
|
|
@@ -20,14 +20,14 @@ function swap16(number: number) {
|
|
|
20
20
|
export default {
|
|
21
21
|
isValidAddress: function (address: Address) {
|
|
22
22
|
const addr = getAddress(address)
|
|
23
|
-
const
|
|
23
|
+
const memo = getMemo(address)
|
|
24
24
|
|
|
25
25
|
const validAddress = regexp.test(addr) && this.verifyChecksum(addr);
|
|
26
26
|
|
|
27
|
-
return validAddress && this.verifyMemo(
|
|
27
|
+
return validAddress && this.verifyMemo(memo)
|
|
28
28
|
},
|
|
29
29
|
|
|
30
|
-
verifyMemo(memo
|
|
30
|
+
verifyMemo(memo?: string): boolean {
|
|
31
31
|
if (!memo) return true; // Optional
|
|
32
32
|
|
|
33
33
|
// Ensure it's a valid UTF-8 string and does not exceed 28 bytes
|
|
@@ -24,8 +24,11 @@ import sui from './sui.json'
|
|
|
24
24
|
import tezos from './tezos.json'
|
|
25
25
|
import tron from './tron.json'
|
|
26
26
|
import xlm from './xlm.json'
|
|
27
|
+
import {Address} from '../../src'
|
|
27
28
|
|
|
28
|
-
export
|
|
29
|
+
export type TestAddress = Address & { invalid?: boolean }
|
|
30
|
+
|
|
31
|
+
const testAddresses: Record<string, TestAddress[]> = {
|
|
29
32
|
aptos,
|
|
30
33
|
algorand,
|
|
31
34
|
bch,
|
|
@@ -52,4 +55,6 @@ export default {
|
|
|
52
55
|
tezos,
|
|
53
56
|
tron,
|
|
54
57
|
xlm,
|
|
55
|
-
}
|
|
58
|
+
} as const;
|
|
59
|
+
|
|
60
|
+
export default testAddresses
|
package/test/addresses/doge.json
CHANGED
|
@@ -5,11 +5,16 @@
|
|
|
5
5
|
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
|
6
6
|
{
|
|
7
7
|
"address": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
|
8
|
-
"
|
|
8
|
+
"memo": "4294967295"
|
|
9
9
|
},
|
|
10
10
|
"rDTXLQ7ZKZVKz33zJbHjgVShjsBnqMBhmN",
|
|
11
11
|
{
|
|
12
12
|
"address": "rDTXLQ7ZKZVKz33zJbHjgVShjsBnqMBhmN",
|
|
13
|
-
"
|
|
13
|
+
"memo": "50000"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"address": "rDTXLQ7ZKZVKz33zJbHjgVShjsBnqMBhmN",
|
|
17
|
+
"memo": "non-numeric-memo",
|
|
18
|
+
"invalid": true
|
|
14
19
|
}
|
|
15
20
|
]
|
package/test/addresses/xlm.json
CHANGED
|
@@ -11,6 +11,11 @@
|
|
|
11
11
|
"GDTYVCTAUQVPKEDZIBWEJGKBQHB4UGGXI2SXXUEW7LXMD4B7MK37CWLJ",
|
|
12
12
|
{
|
|
13
13
|
"address": "GDTYVCTAUQVPKEDZIBWEJGKBQHB4UGGXI2SXXUEW7LXMD4B7MK37CWLJ",
|
|
14
|
-
"
|
|
14
|
+
"memo": "3fdsfsdfasdfdsfgasdgfdsfgas"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"address": "GDTYVCTAUQVPKEDZIBWEJGKBQHB4UGGXI2SXXUEW7LXMD4B7MK37CWLJ",
|
|
18
|
+
"memo": "really long memo that exceeds 28 bytes",
|
|
19
|
+
"invalid": true
|
|
15
20
|
}
|
|
16
21
|
]
|
|
@@ -1,168 +1,187 @@
|
|
|
1
1
|
import {describe, it} from 'mocha'
|
|
2
2
|
import {expect} from 'chai'
|
|
3
3
|
|
|
4
|
-
import {validate,
|
|
4
|
+
import {validate, Chain, NetworkType} from '../src'
|
|
5
5
|
// @ts-ignore
|
|
6
|
-
import addresses from './addresses/addresses'
|
|
6
|
+
import addresses, {TestAddress} from './addresses/addresses'
|
|
7
7
|
|
|
8
|
+
function check(address: TestAddress, chain: Chain) {
|
|
9
|
+
address.invalid
|
|
10
|
+
? invalid(address, chain)
|
|
11
|
+
: valid(address, chain)
|
|
12
|
+
}
|
|
8
13
|
|
|
9
|
-
function valid(address:
|
|
14
|
+
function valid(address: TestAddress, chain: Chain) {
|
|
10
15
|
const valid = validate(address, chain);
|
|
11
16
|
expect({address, chain, valid}).to.deep.equal({address, chain, valid: true});
|
|
12
17
|
}
|
|
13
18
|
|
|
14
|
-
function invalid(address:
|
|
19
|
+
function invalid(address: TestAddress, chain: Chain) {
|
|
15
20
|
const valid = validate(address, chain);
|
|
16
21
|
expect({address, chain, valid}).to.deep.equal({address, chain, valid: false});
|
|
17
22
|
}
|
|
18
23
|
|
|
19
24
|
interface TestCase {
|
|
20
25
|
alternatives: string[],
|
|
21
|
-
|
|
26
|
+
testAddresses: keyof typeof addresses,
|
|
22
27
|
exclude?: (keyof typeof addresses)[]
|
|
23
28
|
testnet?: {
|
|
24
|
-
|
|
29
|
+
testAddresses: keyof typeof addresses
|
|
25
30
|
}
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
const TestCases: Record<string, TestCase> = {
|
|
29
34
|
'algorand': {
|
|
30
35
|
alternatives: [],
|
|
31
|
-
|
|
36
|
+
testAddresses: 'algorand',
|
|
32
37
|
},
|
|
33
38
|
'aptos': {
|
|
34
39
|
alternatives: [],
|
|
35
|
-
|
|
40
|
+
testAddresses: 'aptos',
|
|
36
41
|
exclude: ['sui']
|
|
37
42
|
},
|
|
38
43
|
'bitcoin': {
|
|
39
44
|
alternatives: ['btc', 'omni'],
|
|
40
|
-
|
|
45
|
+
testAddresses: 'btc', // corresponds to addresses.js
|
|
41
46
|
exclude: ['bch', 'ltc'],
|
|
42
47
|
testnet: {
|
|
43
|
-
|
|
48
|
+
testAddresses: 'btc-testnet'
|
|
44
49
|
}
|
|
45
50
|
},
|
|
46
51
|
'bitcoin-cash': {
|
|
47
52
|
alternatives: ['bch', 'bitcoincash', 'bitcoin cash'],
|
|
48
|
-
|
|
53
|
+
testAddresses: 'bch',
|
|
49
54
|
exclude: ['btc', 'ltc'],
|
|
50
55
|
testnet: {
|
|
51
|
-
|
|
56
|
+
testAddresses: 'bch-testnet',
|
|
52
57
|
}
|
|
53
58
|
},
|
|
54
59
|
'cardano': {
|
|
55
60
|
alternatives: ['ada'],
|
|
56
|
-
|
|
61
|
+
testAddresses: 'cardano',
|
|
57
62
|
},
|
|
58
63
|
'doge': {
|
|
59
64
|
alternatives: ['dogecoin'],
|
|
60
65
|
exclude: ['btc'],
|
|
61
|
-
|
|
66
|
+
testAddresses: 'doge',
|
|
62
67
|
testnet: {
|
|
63
|
-
|
|
68
|
+
testAddresses: 'doge-testnet',
|
|
64
69
|
}
|
|
65
70
|
},
|
|
66
71
|
'eos': {
|
|
67
72
|
alternatives: [],
|
|
68
|
-
|
|
73
|
+
testAddresses: 'eos',
|
|
69
74
|
},
|
|
70
75
|
'ethereum': {
|
|
71
|
-
alternatives: [
|
|
72
|
-
|
|
76
|
+
alternatives: [
|
|
77
|
+
'arbitrum',
|
|
78
|
+
'avalanche',
|
|
79
|
+
'avalanche-c',
|
|
80
|
+
'base',
|
|
81
|
+
'berachain',
|
|
82
|
+
'binance',
|
|
83
|
+
'bnb',
|
|
84
|
+
'bsc',
|
|
85
|
+
'eth',
|
|
86
|
+
'flare',
|
|
87
|
+
'optimism',
|
|
88
|
+
'sonic',
|
|
89
|
+
'story',
|
|
90
|
+
],
|
|
91
|
+
testAddresses: 'evm',
|
|
73
92
|
},
|
|
74
93
|
'hedera': {
|
|
75
94
|
alternatives: [],
|
|
76
|
-
|
|
95
|
+
testAddresses: 'hbar'
|
|
77
96
|
},
|
|
78
97
|
'litecoin': {
|
|
79
98
|
alternatives: ['ltc'],
|
|
80
99
|
exclude: ['btc', 'bch'],
|
|
81
|
-
|
|
100
|
+
testAddresses: 'ltc',
|
|
82
101
|
testnet: {
|
|
83
|
-
|
|
102
|
+
testAddresses: 'ltc-testnet'
|
|
84
103
|
}
|
|
85
104
|
},
|
|
86
105
|
'monero': {
|
|
87
106
|
alternatives: [],
|
|
88
|
-
|
|
107
|
+
testAddresses: 'monero',
|
|
89
108
|
testnet: {
|
|
90
|
-
|
|
109
|
+
testAddresses: 'monero-testnet',
|
|
91
110
|
}
|
|
92
111
|
},
|
|
93
112
|
'nano': {
|
|
94
113
|
alternatives: [],
|
|
95
|
-
|
|
114
|
+
testAddresses: 'nano',
|
|
96
115
|
},
|
|
97
116
|
'nem': {
|
|
98
117
|
alternatives: [],
|
|
99
|
-
|
|
118
|
+
testAddresses: 'nem',
|
|
100
119
|
},
|
|
101
120
|
'polkadot': {
|
|
102
121
|
alternatives: [],
|
|
103
|
-
|
|
122
|
+
testAddresses: 'polkadot',
|
|
104
123
|
},
|
|
105
124
|
'ripple': {
|
|
106
125
|
alternatives: ['xrp'],
|
|
107
|
-
|
|
126
|
+
testAddresses: 'ripple'
|
|
108
127
|
},
|
|
109
128
|
'sia': {
|
|
110
|
-
alternatives: [],
|
|
111
|
-
|
|
129
|
+
alternatives: ['SiaCoin'],
|
|
130
|
+
testAddresses: 'sia',
|
|
112
131
|
},
|
|
113
132
|
'solana': {
|
|
114
|
-
alternatives: ['spl'],
|
|
115
|
-
|
|
133
|
+
alternatives: ['sol', 'spl'],
|
|
134
|
+
testAddresses: 'solana'
|
|
116
135
|
},
|
|
117
136
|
'sui': {
|
|
118
137
|
alternatives: [],
|
|
119
|
-
|
|
138
|
+
testAddresses: 'sui',
|
|
120
139
|
exclude: ['aptos']
|
|
121
140
|
},
|
|
122
141
|
'tezos': {
|
|
123
142
|
alternatives: [],
|
|
124
|
-
|
|
143
|
+
testAddresses: 'tezos',
|
|
125
144
|
exclude: ['btc', 'bch', 'btc-testnet', 'ltc-testnet', 'bch-testnet', 'doge', 'doge-testnet', 'ltc', 'tron'],
|
|
126
145
|
},
|
|
127
146
|
'tron': {
|
|
128
147
|
alternatives: ['trc20'],
|
|
129
|
-
|
|
148
|
+
testAddresses: 'tron',
|
|
130
149
|
},
|
|
131
150
|
'xlm': {
|
|
132
|
-
alternatives: ['stellar'],
|
|
133
|
-
|
|
151
|
+
alternatives: ['stellar', 'stellarlumens'],
|
|
152
|
+
testAddresses: 'xlm',
|
|
134
153
|
}
|
|
135
154
|
}
|
|
136
155
|
|
|
137
156
|
describe('multichain address validator', function () {
|
|
138
157
|
|
|
139
|
-
it('should
|
|
158
|
+
it('should check valid addresses for chains', function () {
|
|
140
159
|
for (const chain in TestCases) {
|
|
141
160
|
for (const c of [chain, ...TestCases[chain].alternatives]) {
|
|
142
|
-
if (!addresses[TestCases[chain].
|
|
143
|
-
throw new Error(`No
|
|
161
|
+
if (!addresses[TestCases[chain].testAddresses]) {
|
|
162
|
+
throw new Error(`No test addresses for chain '${chain}'`)
|
|
144
163
|
}
|
|
145
|
-
for (const address of addresses[TestCases[chain].
|
|
146
|
-
|
|
164
|
+
for (const address of addresses[TestCases[chain].testAddresses]) {
|
|
165
|
+
check(address, c)
|
|
147
166
|
}
|
|
148
167
|
|
|
149
168
|
if (TestCases[chain].testnet) {
|
|
150
|
-
if (!addresses[TestCases[chain].testnet.
|
|
151
|
-
throw new Error(`No
|
|
169
|
+
if (!addresses[TestCases[chain].testnet.testAddresses]) {
|
|
170
|
+
throw new Error(`No test testnet addresses for chain '${chain}'`)
|
|
152
171
|
}
|
|
153
|
-
for (const address of addresses[TestCases[chain].testnet.
|
|
154
|
-
|
|
172
|
+
for (const address of addresses[TestCases[chain].testnet.testAddresses]) {
|
|
173
|
+
check(address, { chain: c, networkType: NetworkType.TestNet })
|
|
155
174
|
}
|
|
156
175
|
}
|
|
157
176
|
}
|
|
158
177
|
}
|
|
159
178
|
})
|
|
160
179
|
|
|
161
|
-
it('should
|
|
180
|
+
it('should check invalid addresses for chains', function () {
|
|
162
181
|
for (const chain in TestCases) {
|
|
163
182
|
for (const c of [chain, ...TestCases[chain].alternatives]) {
|
|
164
183
|
const invalidChains = Object.keys(addresses)
|
|
165
|
-
.filter(key => key !== TestCases[chain].
|
|
184
|
+
.filter(key => key !== TestCases[chain].testAddresses)
|
|
166
185
|
.filter(key => !TestCases[chain].exclude?.includes(key as any))
|
|
167
186
|
|
|
168
187
|
for (const invalidChain of invalidChains) {
|