-
Notifications
You must be signed in to change notification settings - Fork 0
/
utils.ts
108 lines (93 loc) · 3.29 KB
/
utils.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import secp256k1 from 'secp256k1';
import keccak from 'keccak';
import randomBytes from 'randombytes';
/**
* Transform a private key into an address
*/
const privateToAddress = (privateKey:any) => {
const pub = secp256k1.publicKeyCreate(privateKey, false).slice(1);
return keccak('keccak256').update(Buffer.from(pub)).digest().slice(-20).toString('hex');
};
/**
* Create a wallet from a random private key
* @returns {{address: string, privKey: string}}
*/
const getRandomWallet = () => {
const randbytes = randomBytes(32);
return {
address: privateToAddress(randbytes),
privKey: randbytes.toString('hex'),
};
}
/**
* Generate a lot of wallets until one satisfies the input constraints
* @param prefix - Prefix chosen by the user
* @param suffix - Suffix chosen by the user
* @param isChecksum - Is the input case-sensitive
* @param cb - Callback called after x attempts, or when an address if found
* @returns
*/
const getVanityWallet = (step:any, prefix:any, suffix:any, isChecksum:any, cb:any) => {
let wallet = getRandomWallet();
let attempts = 1;
const pre = isChecksum ? prefix : prefix.toLowerCase();
const suf = isChecksum ? suffix : suffix.toLowerCase();
while (!isValidVanityAddress(wallet.address, pre, suf, isChecksum)) {
if (attempts >= step) {
cb({ attempts });
attempts = 0;
}
wallet = getRandomWallet();
attempts++;
}
cb({ address: '0x' + toChecksumAddress(wallet.address), privKey: wallet.privKey, attempts });
};
/**
* Check if a wallet respects the input constraints
* @param address - Wallet address
* @param prefix - Prefix chosen by the user
* @param suffix - Suffix chosen by the user
* @param isChecksum - Is the input case-sensitive
* @returns {boolean}
*/
const isValidVanityAddress = (address: any, prefix: any, suffix: any, isChecksum: any) => {
const addressPrefix = address.substring(0, prefix.length);
const addressSuffix = address.substring(40 - suffix.length);
if (!isChecksum) {
return prefix === addressPrefix && suffix === addressSuffix;
}
if (prefix.toLowerCase() !== addressPrefix || suffix.toLowerCase() !== addressSuffix) {
return false;
}
return isValidChecksum(address, prefix, suffix);
};
const isValidChecksum = (address: any | Buffer, prefix: string | any[], suffix: string | any[]) => {
const hash = keccak('keccak256').update(address).digest().toString('hex');
for (let i = 0; i < prefix.length; i++) {
if (prefix[i] !== (parseInt(hash[i], 16) >= 8 ? address[i].toUpperCase() : address[i])) {
return false;
}
}
for (let i = 0; i < suffix.length; i++) {
const j = i + 40 - suffix.length;
if (suffix[i] !== (parseInt(hash[j], 16) >= 8 ? address[j].toUpperCase() : address[j])) {
return false;
}
}
return true;
};
const toChecksumAddress = (address:any) => {
const hash = keccak('keccak256').update(address).digest().toString('hex');
let ret = '';
for (let i = 0; i < address.length; i++) {
ret += parseInt(hash[i], 16) >= 8 ? address[i].toUpperCase() : address[i];
}
return ret;
};
export {
privateToAddress,
getRandomWallet,
getVanityWallet,
isValidChecksum,
isValidVanityAddress
}