1 | const { assert } = require('../util');
|
2 | const format = require('../util/format');
|
3 | const sign = require('../util/sign');
|
4 | const Account = require('./Account');
|
5 |
|
6 | class PrivateKeyAccount extends Account {
|
7 | /**
|
8 | * Create a new PrivateKeyAccount with random privateKey.
|
9 | *
|
10 | * @param [entropy] {string|Buffer} - Entropy of random account
|
11 | * @return {PrivateKeyAccount}
|
12 | *
|
13 | * @example
|
14 | * > PrivateKeyAccount.random()
|
15 | PrivateKeyAccount {
|
16 | privateKey: '0xd28edbdb7bbe75787b84c5f525f47666a3274bb06561581f00839645f3c26f66',
|
17 | publicKey: '0xc42b53ae2ef95fee489948d33df391c4a9da31b7a3e29cf772c24eb42f74e94ab3bfe00bf29a239c17786a5b921853b7c5344d36694db43aa849e401f91566a5',
|
18 | address: '0x1cecb4a2922b7007e236daf0c797de6e55496e84'
|
19 | }
|
20 | * > PrivateKeyAccount.random() // gen a different account from above
|
21 | PrivateKeyAccount {
|
22 | privateKey: '0x1b67150f56f49556ef7e3899024d83c125d84990d311ec08fa98aa1433bc0f53',
|
23 | publicKey: '0xd442207828ffd4dad918fea0d75d42dbea1fe5e3789c00a82e18ce8229714eae3f70b12f2f1abd795ad3e5c52a5a597289eb5096548438c233431f498b47b9a6',
|
24 | address: '0x16c25691aadc3363f5862d264072584f3ebf4613'
|
25 | }
|
26 | * > PrivateKeyAccount.random('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');
|
27 | PrivateKeyAccount {
|
28 | privateKey: '0x1d41e006afd28ea339922d8ab4be93154a14d4f1b6d0ad4e7aabf807e7536a5f',
|
29 | publicKey: '0x4c07c75d3fdc5b1d6afef6ec374b0eaac86bcaa771a1d536bc4ce6f111b1c60e414b370e4cf31bf7770ae6818a3518c485398a43857d9053153f6eb4f5644a90',
|
30 | address: '0x113d49784c80d6f8fdbc0bef5a5ab0d9c9fee520'
|
31 | }
|
32 | * > PrivateKeyAccount.random('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');
|
33 | * // gen a different account from above, even use same entropy
|
34 | PrivateKeyAccount {
|
35 | privateKey: '0x5a34ff3318674c33209ce856218890e9a6ee3811e8a51e3094ed1e6a94bf58ef',
|
36 | publicKey: '0xe530d77c3ed6115cb46ba79821085bf67d2a7a8c808c1d52dec03fd7a82e569c2136dba84b21d40f46d90484722b21a9d5a8038495adf93f2eed564ababa2422',
|
37 | address: '0x1f63fcef4aaa88c03cbb5c9fb34be69dee65d0a8'
|
38 | }
|
39 | */
|
40 | static random(entropy) {
|
41 | const privateKeyBuffer = sign.randomPrivateKey(entropy === undefined ? undefined : format.hexBuffer(entropy));
|
42 | return new this(privateKeyBuffer);
|
43 | }
|
44 |
|
45 | /**
|
46 | * Decrypt account encrypt info.
|
47 | *
|
48 | * @param keystore {object} - Keystore version 3 object.
|
49 | * @param password {string|Buffer} - Password for keystore to decrypt with.
|
50 | * @return {PrivateKeyAccount}
|
51 | *
|
52 | * @example
|
53 | * > PrivateKeyAccount.decrypt({
|
54 | version: 3,
|
55 | id: '0bb47ee0-aac3-a006-2717-03877afa15f0',
|
56 | address: '1cad0b19bb29d4674531d6f115237e16afce377c',
|
57 | crypto: {
|
58 | ciphertext: 'a8ec41d2440311ce897bacb6f7942f3235113fa17c4ae6732e032336038a8f73',
|
59 | cipherparams: { iv: '85b5e092c1c32129e3d27df8c581514d' },
|
60 | cipher: 'aes-128-ctr',
|
61 | kdf: 'scrypt',
|
62 | kdfparams: {
|
63 | dklen: 32,
|
64 | salt: 'b662f09bdf6751ac599219732609dceac430bc0629a7906eaa1451555f051ebc',
|
65 | n: 8192,
|
66 | r: 8,
|
67 | p: 1
|
68 | },
|
69 | mac: 'cc89df7ef6c27d284526a65cabf8e5042cdf1ec1aa4ee36dcf65b965fa34843d'
|
70 | }
|
71 | }, 'password');
|
72 | PrivateKeyAccount {
|
73 | address: '0x1cad0b19bb29d4674531d6f115237e16afce377c',
|
74 | publicKey: '0x4646ae5047316b4230d0086c8acec687f00b1cd9d1dc634f6cb358ac0a9a8ffffe77b4dd0a4bfb95851f3b7355c781dd60f8418fc8a65d14907aff47c903a559',
|
75 | privateKey: '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
|
76 | }
|
77 | */
|
78 | static decrypt(keystore, password) {
|
79 | const privateKeyBuffer = sign.decrypt(keystore, password);
|
80 | return new this(privateKeyBuffer);
|
81 | }
|
82 |
|
83 | /**
|
84 | * Create a account by privateKey.
|
85 | *
|
86 | * @param privateKey {string|Buffer} - Private key of account
|
87 | * @return {PrivateKeyAccount}
|
88 | *
|
89 | * @example
|
90 | * > new PrivateKeyAccount('0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef')
|
91 | PrivateKeyAccount {
|
92 | address: '0x1cad0b19bb29d4674531d6f115237e16afce377c',
|
93 | publicKey: '0x4646ae5047316b4230d0086c8acec687f00b1cd9d1dc634f6cb358ac0a9a8ffffe77b4dd0a4bfb95851f3b7355c781dd60f8418fc8a65d14907aff47c903a559',
|
94 | privateKey: '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
|
95 | }
|
96 | */
|
97 | constructor(privateKey) {
|
98 | const privateKeyBuffer = format.hexBuffer(privateKey);
|
99 | const publicKeyBuffer = sign.privateKeyToPublicKey(privateKeyBuffer);
|
100 | const addressBuffer = sign.publicKeyToAddress(publicKeyBuffer);
|
101 |
|
102 | super(format.address(addressBuffer));
|
103 | this.publicKey = format.publicKey(publicKeyBuffer);
|
104 | this.privateKey = format.privateKey(privateKeyBuffer);
|
105 | }
|
106 |
|
107 | /**
|
108 | * Encrypt account privateKey to object.
|
109 | *
|
110 | * @param password {string}
|
111 | * @return {object} - keystoreV3 object
|
112 | *
|
113 | * @example
|
114 | * > account = new PrivateKeyAccount('0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef')
|
115 | * > account.encrypt('password')
|
116 | {version:3, id:..., address:..., crypto:...}
|
117 | */
|
118 | encrypt(password) {
|
119 | return sign.encrypt(format.hexBuffer(this.privateKey), password);
|
120 | }
|
121 |
|
122 | /**
|
123 | * Sign a transaction.
|
124 | *
|
125 | * @param options {object} - See [Transaction](Transaction.js/constructor)
|
126 | * @return {Promise<Transaction>}
|
127 | *
|
128 | * @example
|
129 | * > account = new PrivateKeyAccount('0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef')
|
130 | * > transaction = account.signTransaction({
|
131 | nonce: 0,
|
132 | gasPrice: 100,
|
133 | gas: 10000,
|
134 | storageLimit: 10000,
|
135 | epochHeight: 100,
|
136 | chainId: 0,
|
137 | })
|
138 |
|
139 | Transaction {
|
140 | from: '0x1cad0b19bb29d4674531d6f115237e16afce377c',
|
141 | nonce: 0,
|
142 | gasPrice: 100,
|
143 | gas: 10000,
|
144 | to: undefined,
|
145 | value: undefined,
|
146 | storageLimit: 10000,
|
147 | epochHeight: 100,
|
148 | chainId: 0,
|
149 | data: undefined,
|
150 | v: 0,
|
151 | r: '0x096f4e00ac15f6bd6e09937e99f0e54aaa2dd0f4c6bd8421e1e81b0e8bd30723',
|
152 | s: '0x41e63a41ede0cbb8ccfaa827423c654dcdc09fb1aa1c3a7233566544aff4cd9a'
|
153 | }
|
154 | */
|
155 | async signTransaction(options) {
|
156 | const transaction = await super.signTransaction(options);
|
157 | transaction.sign(this.privateKey); // sign will cover r,s,v fields
|
158 |
|
159 | assert(transaction.from === this.address, {
|
160 | message: 'Invalid sign transaction.from',
|
161 | expected: this.address,
|
162 | got: transaction.from,
|
163 | });
|
164 |
|
165 | return transaction;
|
166 | }
|
167 |
|
168 | /**
|
169 | * Sign a string.
|
170 | *
|
171 | * @param options {string}
|
172 | * @return {Promise<Message>}
|
173 | *
|
174 | * @example
|
175 | * > account = new PrivateKeyAccount('0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef')
|
176 | * > message = account.signMessage('Hello World')
|
177 | Message {
|
178 | message: 'Hello World',
|
179 | signature: '0x6e913e2b76459f19ebd269b82b51a70e912e909b2f5c002312efc27bcc280f3c29134d382aad0dbd3f0ccc9f0eb8f1dbe3f90141d81574ebb6504156b0d7b95f01'
|
180 | }
|
181 | */
|
182 | async signMessage(options) {
|
183 | const message = await super.signMessage(options);
|
184 | message.sign(this.privateKey); // sign will cover r,s,v fields
|
185 |
|
186 | assert(message.from === this.address, {
|
187 | message: 'Invalid sign message.from',
|
188 | expected: this.address,
|
189 | got: message.from,
|
190 | });
|
191 |
|
192 | return message;
|
193 | }
|
194 | }
|
195 |
|
196 | module.exports = PrivateKeyAccount;
|