crypto-wallet-xpub 1.0.0
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/bep20-wallet.js +136 -0
- package/index.js +14 -0
- package/package.json +42 -0
- package/trc20-wallet.js +199 -0
package/bep20-wallet.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BEP20 Wallet Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates BEP20 (Binance Smart Chain) wallet addresses from Account Extended Public Key (XPUB).
|
|
5
|
+
*
|
|
6
|
+
* @module bep20-wallet
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { HDNodeWallet } = require('ethers');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* BEP20 Wallet Class
|
|
13
|
+
*
|
|
14
|
+
* @class BEP20Wallet
|
|
15
|
+
* @example
|
|
16
|
+
* const { BEP20Wallet } = require('crypto-wallet-xpub');
|
|
17
|
+
*
|
|
18
|
+
* const xpub = "xpub6Ce5wAYj54UjjC6T83tSoriMdebVzDJfNjB7ocoY9DJshVZsbciCgvLaKLJp38Zh7x8v2222Fob3Shqcum7g3Kg6Ja7igUo3LdrzNb9E93t";
|
|
19
|
+
* const wallet = new BEP20Wallet(xpub);
|
|
20
|
+
*
|
|
21
|
+
* // Get single address
|
|
22
|
+
* const address = wallet.getAddress(0);
|
|
23
|
+
* console.log(address); // 0x9894A0B1863382F74DCe886C6Bf6817C604BEE52
|
|
24
|
+
*
|
|
25
|
+
* // Get multiple addresses
|
|
26
|
+
* const addresses = wallet.getAddresses(0, 4);
|
|
27
|
+
* console.log(addresses);
|
|
28
|
+
*/
|
|
29
|
+
class BEP20Wallet {
|
|
30
|
+
/**
|
|
31
|
+
* Creates a new BEP20 wallet instance
|
|
32
|
+
*
|
|
33
|
+
* @param {string} xpub - Account Extended Public Key (XPUB) derived from path m/44'/60'/0'
|
|
34
|
+
* @throws {Error} If XPUB is not provided or invalid
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* const wallet = new BEP20Wallet("xpub6Ce5wAYj54Ujj...");
|
|
38
|
+
*/
|
|
39
|
+
constructor(xpub) {
|
|
40
|
+
if (!xpub) {
|
|
41
|
+
throw new Error('XPUB is required');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (typeof xpub !== 'string') {
|
|
45
|
+
throw new Error('XPUB must be a string');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!xpub.startsWith('xpub')) {
|
|
49
|
+
throw new Error('Invalid XPUB format. Must start with "xpub"');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
this.xpub = xpub;
|
|
54
|
+
this.root = HDNodeWallet.fromExtendedKey(xpub);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
throw new Error(`Invalid XPUB: ${error.message}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Get a single BEP20 address at specified index
|
|
62
|
+
*
|
|
63
|
+
* @param {number} index - Derivation index (0, 1, 2, ...)
|
|
64
|
+
* @returns {string} BEP20 wallet address (0x...)
|
|
65
|
+
* @throws {Error} If index is invalid
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* const address = wallet.getAddress(0);
|
|
69
|
+
* console.log(address); // "0x9894A0B1863382F74DCe886C6Bf6817C604BEE52"
|
|
70
|
+
*/
|
|
71
|
+
getAddress(index) {
|
|
72
|
+
if (typeof index !== 'number' || index < 0 || !Number.isInteger(index)) {
|
|
73
|
+
throw new Error('Index must be a non-negative integer');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const child = this.root.derivePath(`0/${index}`);
|
|
78
|
+
return child.address;
|
|
79
|
+
} catch (error) {
|
|
80
|
+
throw new Error(`Failed to derive address at index ${index}: ${error.message}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Get multiple BEP20 addresses in a range
|
|
86
|
+
*
|
|
87
|
+
* @param {number} start - Start index (inclusive)
|
|
88
|
+
* @param {number} end - End index (inclusive)
|
|
89
|
+
* @returns {Array<{index: number, address: string}>} Array of address objects
|
|
90
|
+
* @throws {Error} If range is invalid
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* const addresses = wallet.getAddresses(0, 4);
|
|
94
|
+
* // [
|
|
95
|
+
* // { index: 0, address: "0x9894A0B1863382F74DCe886C6Bf6817C604BEE52" },
|
|
96
|
+
* // { index: 1, address: "0x50EC5410B937438C49fdFf2981166064E4dF95cB" },
|
|
97
|
+
* // ...
|
|
98
|
+
* // ]
|
|
99
|
+
*/
|
|
100
|
+
getAddresses(start, end) {
|
|
101
|
+
if (typeof start !== 'number' || typeof end !== 'number') {
|
|
102
|
+
throw new Error('Start and end must be numbers');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (start < 0 || end < 0 || !Number.isInteger(start) || !Number.isInteger(end)) {
|
|
106
|
+
throw new Error('Start and end must be non-negative integers');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (start > end) {
|
|
110
|
+
throw new Error('Start index must be less than or equal to end index');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const addresses = [];
|
|
114
|
+
for (let i = start; i <= end; i++) {
|
|
115
|
+
addresses.push({
|
|
116
|
+
index: i,
|
|
117
|
+
address: this.getAddress(i)
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
return addresses;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Get the XPUB used by this wallet
|
|
125
|
+
*
|
|
126
|
+
* @returns {string} The Account Extended Public Key
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* const xpub = wallet.getXPUB();
|
|
130
|
+
*/
|
|
131
|
+
getXPUB() {
|
|
132
|
+
return this.xpub;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
module.exports = { BEP20Wallet };
|
package/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* crypto-wallet-xpub
|
|
3
|
+
* Generate BEP20 and TRC20 addresses from Account Extended Public Keys
|
|
4
|
+
*
|
|
5
|
+
* @module crypto-wallet-xpub
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { BEP20Wallet } = require('./bep20-wallet');
|
|
9
|
+
const { TRC20Wallet } = require('./trc20-wallet');
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
BEP20Wallet,
|
|
13
|
+
TRC20Wallet
|
|
14
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "crypto-wallet-xpub",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Generate BEP20 (BSC) and TRC20 (TRON) wallet addresses from Account Extended Public Keys (XPUB)",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "node examples/bep20-example.js && node examples/trc20-example.js"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"crypto",
|
|
11
|
+
"wallet",
|
|
12
|
+
"bep20",
|
|
13
|
+
"trc20",
|
|
14
|
+
"bsc",
|
|
15
|
+
"binance-smart-chain",
|
|
16
|
+
"tron",
|
|
17
|
+
"xpub",
|
|
18
|
+
"bip32",
|
|
19
|
+
"bip44",
|
|
20
|
+
"hdwallet",
|
|
21
|
+
"hierarchical-deterministic"
|
|
22
|
+
],
|
|
23
|
+
"author": "offici5l>",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "https://github.com/offici5l/crypto-wallet-xpub.git"
|
|
28
|
+
},
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/offici5l/crypto-wallet-xpub/issues"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/offici5l/crypto-wallet-xpub#readme",
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"ethers": "^6.9.0",
|
|
35
|
+
"hdkey": "^2.1.0",
|
|
36
|
+
"secp256k1": "^5.0.0",
|
|
37
|
+
"keccak": "^3.0.4"
|
|
38
|
+
},
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=14.0.0"
|
|
41
|
+
}
|
|
42
|
+
}
|
package/trc20-wallet.js
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TRC20 Wallet Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates TRC20 (TRON) wallet addresses from Account Extended Public Key (XPUB).
|
|
5
|
+
*
|
|
6
|
+
* @module trc20-wallet
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const HDKey = require('hdkey');
|
|
10
|
+
const secp256k1 = require('secp256k1');
|
|
11
|
+
const createKeccakHash = require('keccak');
|
|
12
|
+
const crypto = require('crypto');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* TRC20 Wallet Class
|
|
16
|
+
*
|
|
17
|
+
* @class TRC20Wallet
|
|
18
|
+
* @example
|
|
19
|
+
* const { TRC20Wallet } = require('crypto-wallet-xpub');
|
|
20
|
+
*
|
|
21
|
+
* const xpub = "xpub6C5KYvkMHmGWqx3yDSqiwcrgQbhxzQFUFPURg7Tvw3dELngbRd1sAuajPT1NsCfohgJHojoBS7XaQgBCMj2eJmX9xYAD9TzCHPXhkrw2PMy";
|
|
22
|
+
* const wallet = new TRC20Wallet(xpub);
|
|
23
|
+
*
|
|
24
|
+
* // Get single address
|
|
25
|
+
* const address = wallet.getAddress(0);
|
|
26
|
+
* console.log(address); // TFs5Wcs68CrmDG113bTJfKEUHvKUf9Vz6a
|
|
27
|
+
*
|
|
28
|
+
* // Get multiple addresses
|
|
29
|
+
* const addresses = wallet.getAddresses(0, 4);
|
|
30
|
+
* console.log(addresses);
|
|
31
|
+
*/
|
|
32
|
+
class TRC20Wallet {
|
|
33
|
+
/**
|
|
34
|
+
* Creates a new TRC20 wallet instance
|
|
35
|
+
*
|
|
36
|
+
* @param {string} xpub - Account Extended Public Key (XPUB) derived from path m/44'/195'/0'
|
|
37
|
+
* @throws {Error} If XPUB is not provided or invalid
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* const wallet = new TRC20Wallet("xpub6C5KYvkMHmGW...");
|
|
41
|
+
*/
|
|
42
|
+
constructor(xpub) {
|
|
43
|
+
if (!xpub) {
|
|
44
|
+
throw new Error('XPUB is required');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (typeof xpub !== 'string') {
|
|
48
|
+
throw new Error('XPUB must be a string');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!xpub.startsWith('xpub')) {
|
|
52
|
+
throw new Error('Invalid XPUB format. Must start with "xpub"');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
this.xpub = xpub;
|
|
57
|
+
this.master = HDKey.fromExtendedKey(xpub);
|
|
58
|
+
this.changeNode = this.master.deriveChild(0);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
throw new Error(`Invalid XPUB: ${error.message}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Encode address bytes to Base58Check format (TRON address format)
|
|
66
|
+
*
|
|
67
|
+
* @private
|
|
68
|
+
* @param {Buffer} payload - Address bytes to encode
|
|
69
|
+
* @returns {string} Base58Check encoded address
|
|
70
|
+
*/
|
|
71
|
+
base58CheckEncode(payload) {
|
|
72
|
+
const buffer = Buffer.isBuffer(payload) ? payload : Buffer.from(payload);
|
|
73
|
+
const hash1 = crypto.createHash("sha256").update(buffer).digest();
|
|
74
|
+
const hash2 = crypto.createHash("sha256").update(hash1).digest();
|
|
75
|
+
const checksum = hash2.slice(0, 4);
|
|
76
|
+
const data = Buffer.concat([buffer, checksum]);
|
|
77
|
+
|
|
78
|
+
const alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
79
|
+
let num = BigInt("0x" + data.toString("hex"));
|
|
80
|
+
let encoded = "";
|
|
81
|
+
|
|
82
|
+
while (num > 0n) {
|
|
83
|
+
const mod = Number(num % 58n);
|
|
84
|
+
encoded = alphabet[mod] + encoded;
|
|
85
|
+
num = num / 58n;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
for (const byte of data) {
|
|
89
|
+
if (byte !== 0) break;
|
|
90
|
+
encoded = "1" + encoded;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return encoded;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Generate TRON address from compressed public key
|
|
98
|
+
*
|
|
99
|
+
* @private
|
|
100
|
+
* @param {Buffer} compressedPubKey - Compressed public key (33 bytes)
|
|
101
|
+
* @returns {string} TRON address (T...)
|
|
102
|
+
*/
|
|
103
|
+
generateTronAddress(compressedPubKey) {
|
|
104
|
+
// Convert compressed public key to uncompressed format
|
|
105
|
+
const uncompressedPubKey = secp256k1.publicKeyConvert(
|
|
106
|
+
Buffer.isBuffer(compressedPubKey) ? compressedPubKey : Buffer.from(compressedPubKey),
|
|
107
|
+
false
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
const uncompressedBuffer = Buffer.from(uncompressedPubKey);
|
|
111
|
+
|
|
112
|
+
// Apply Keccak256 hash
|
|
113
|
+
const hash = createKeccakHash('keccak256').update(uncompressedBuffer.slice(1)).digest();
|
|
114
|
+
|
|
115
|
+
// Take last 20 bytes and add TRON prefix (0x41)
|
|
116
|
+
const addressBytes = hash.slice(-20);
|
|
117
|
+
const addressHex = "41" + addressBytes.toString('hex');
|
|
118
|
+
|
|
119
|
+
// Encode to Base58Check
|
|
120
|
+
return this.base58CheckEncode(Buffer.from(addressHex, "hex"));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Get a single TRC20 address at specified index
|
|
125
|
+
*
|
|
126
|
+
* @param {number} index - Derivation index (0, 1, 2, ...)
|
|
127
|
+
* @returns {string} TRC20 wallet address (T...)
|
|
128
|
+
* @throws {Error} If index is invalid
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* const address = wallet.getAddress(0);
|
|
132
|
+
* console.log(address); // "TFs5Wcs68CrmDG113bTJfKEUHvKUf9Vz6a"
|
|
133
|
+
*/
|
|
134
|
+
getAddress(index) {
|
|
135
|
+
if (typeof index !== 'number' || index < 0 || !Number.isInteger(index)) {
|
|
136
|
+
throw new Error('Index must be a non-negative integer');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
const node = this.changeNode.deriveChild(index);
|
|
141
|
+
return this.generateTronAddress(node.publicKey);
|
|
142
|
+
} catch (error) {
|
|
143
|
+
throw new Error(`Failed to derive address at index ${index}: ${error.message}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Get multiple TRC20 addresses in a range
|
|
149
|
+
*
|
|
150
|
+
* @param {number} start - Start index (inclusive)
|
|
151
|
+
* @param {number} end - End index (inclusive)
|
|
152
|
+
* @returns {Array<{index: number, address: string}>} Array of address objects
|
|
153
|
+
* @throws {Error} If range is invalid
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* const addresses = wallet.getAddresses(0, 4);
|
|
157
|
+
* // [
|
|
158
|
+
* // { index: 0, address: "TFs5Wcs68CrmDG113bTJfKEUHvKUf9Vz6a" },
|
|
159
|
+
* // { index: 1, address: "TEFosF8dnrgLYx4gAwYVq1sDpRTNUQ9br5" },
|
|
160
|
+
* // ...
|
|
161
|
+
* // ]
|
|
162
|
+
*/
|
|
163
|
+
getAddresses(start, end) {
|
|
164
|
+
if (typeof start !== 'number' || typeof end !== 'number') {
|
|
165
|
+
throw new Error('Start and end must be numbers');
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (start < 0 || end < 0 || !Number.isInteger(start) || !Number.isInteger(end)) {
|
|
169
|
+
throw new Error('Start and end must be non-negative integers');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (start > end) {
|
|
173
|
+
throw new Error('Start index must be less than or equal to end index');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const addresses = [];
|
|
177
|
+
for (let i = start; i <= end; i++) {
|
|
178
|
+
addresses.push({
|
|
179
|
+
index: i,
|
|
180
|
+
address: this.getAddress(i)
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
return addresses;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Get the XPUB used by this wallet
|
|
188
|
+
*
|
|
189
|
+
* @returns {string} The Account Extended Public Key
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* const xpub = wallet.getXPUB();
|
|
193
|
+
*/
|
|
194
|
+
getXPUB() {
|
|
195
|
+
return this.xpub;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
module.exports = { TRC20Wallet };
|