js-conflux-sdk
Version:
JavaScript Conflux Software Development Kit
201 lines (187 loc) • 7.65 kB
JavaScript
const { assert } = require('../util');
const format = require('../util/format');
const sign = require('../util/sign');
const Account = require('./Account');
class PrivateKeyAccount extends Account {
/**
* Create a new PrivateKeyAccount with random privateKey.
*
* @param {string|Buffer} entropy - Entropy of random account, if pass undefined will random generate a buffer
* @param {number} networkId - network id of account
* @return {PrivateKeyAccount}
*
* @example
* > PrivateKeyAccount.random(undefined, 1)
PrivateKeyAccount {
privateKey: '0xd28edbdb7bbe75787b84c5f525f47666a3274bb06561581f00839645f3c26f66',
publicKey: '0xc42b53ae2ef95fee489948d33df391c4a9da31b7a3e29cf772c24eb42f74e94ab3bfe00bf29a239c17786a5b921853b7c5344d36694db43aa849e401f91566a5',
address: 'cfxtest:aass3rfcwjz1ab9cg5rtbv61531fmwnsuuy8c26f20'
}
* > PrivateKeyAccount.random(undefined, 1) // gen a different account from above
PrivateKeyAccount {
privateKey: '0x1b67150f56f49556ef7e3899024d83c125d84990d311ec08fa98aa1433bc0f53',
publicKey: '0xd442207828ffd4dad918fea0d75d42dbea1fe5e3789c00a82e18ce8229714eae3f70b12f2f1abd795ad3e5c52a5a597289eb5096548438c233431f498b47b9a6',
address: 'cfxtest:aanpezyvznsdg29zu20wpudwnbhx7t4gcpzcnkzjd2'
}
* > PrivateKeyAccount.random('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 1);
PrivateKeyAccount {
privateKey: '0x1d41e006afd28ea339922d8ab4be93154a14d4f1b6d0ad4e7aabf807e7536a5f',
publicKey: '0x4c07c75d3fdc5b1d6afef6ec374b0eaac86bcaa771a1d536bc4ce6f111b1c60e414b370e4cf31bf7770ae6818a3518c485398a43857d9053153f6eb4f5644a90',
address: 'cfxtest:aajx4wn2kwarr8h71uf880w40dp6x91feac1n6ur3s'
}
* > PrivateKeyAccount.random('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 1);
* // gen a different account from above, even use same entropy
PrivateKeyAccount {
privateKey: '0x5a34ff3318674c33209ce856218890e9a6ee3811e8a51e3094ed1e6a94bf58ef',
publicKey: '0xe530d77c3ed6115cb46ba79821085bf67d2a7a8c808c1d52dec03fd7a82e569c2136dba84b21d40f46d90484722b21a9d5a8038495adf93f2eed564ababa2422',
address: 'cfxtest:aat0h9htkmzjvub61rsk9p4n64s863suza6zu7d2rr'
}
*/
static random(entropy, networkId) {
const privateKeyBuffer = sign.randomPrivateKey(entropy === undefined ? undefined : format.hexBuffer(entropy));
return new this(privateKeyBuffer, networkId);
}
/**
* Decrypt account encrypt info.
*
* @param {object} keystore - Keystore version 3 object.
* @param {string|Buffer} password - Password for keystore to decrypt with.
* @param {number} networkId - Network id of account
* @return {PrivateKeyAccount}
*
* @example
* > PrivateKeyAccount.decrypt({
version: 3,
id: '0bb47ee0-aac3-a006-2717-03877afa15f0',
address: '1cad0b19bb29d4674531d6f115237e16afce377c',
crypto: {
ciphertext: 'a8ec41d2440311ce897bacb6f7942f3235113fa17c4ae6732e032336038a8f73',
cipherparams: { iv: '85b5e092c1c32129e3d27df8c581514d' },
cipher: 'aes-128-ctr',
kdf: 'scrypt',
kdfparams: {
dklen: 32,
salt: 'b662f09bdf6751ac599219732609dceac430bc0629a7906eaa1451555f051ebc',
n: 8192,
r: 8,
p: 1
},
mac: 'cc89df7ef6c27d284526a65cabf8e5042cdf1ec1aa4ee36dcf65b965fa34843d'
}
}, 'password');
PrivateKeyAccount {
address: '0x1cad0b19bb29d4674531d6f115237e16afce377c',
publicKey: '0x4646ae5047316b4230d0086c8acec687f00b1cd9d1dc634f6cb358ac0a9a8ffffe77b4dd0a4bfb95851f3b7355c781dd60f8418fc8a65d14907aff47c903a559',
privateKey: '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
}
*/
static decrypt(keystore, password, networkId) {
const privateKeyBuffer = sign.decrypt(keystore, password);
return new this(privateKeyBuffer, networkId);
}
/**
* Create a account by privateKey.
*
* @param {string|Buffer} privateKey - Private key of account
* @param {number} networkId - Network id of account
* @return {PrivateKeyAccount}
*
* @example
* > new PrivateKeyAccount('0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef')
PrivateKeyAccount {
address: 'cfxtest:aasm4c231py7j34fghntcfkdt2nm9xv1tu6jd3r1s7',
publicKey: '0x4646ae5047316b4230d0086c8acec687f00b1cd9d1dc634f6cb358ac0a9a8ffffe77b4dd0a4bfb95851f3b7355c781dd60f8418fc8a65d14907aff47c903a559',
privateKey: '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
}
*/
constructor(privateKey, networkId) {
const privateKeyBuffer = format.hexBuffer(privateKey);
const publicKeyBuffer = sign.privateKeyToPublicKey(privateKeyBuffer);
const addressBuffer = sign.publicKeyToAddress(publicKeyBuffer);
super(format.address(addressBuffer, networkId));
this.publicKey = format.publicKey(publicKeyBuffer);
this.privateKey = format.privateKey(privateKeyBuffer);
this.networkId = networkId;
}
/**
* Encrypt account privateKey to object.
*
* @param {string} password
* @return {object} - keystoreV3 object
*
* @example
* > account = new PrivateKeyAccount('0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef')
* > account.encrypt('password')
{version:3, id:..., address:..., crypto:...}
*/
encrypt(password) {
return sign.encrypt(format.hexBuffer(this.privateKey), password);
}
/**
* Sign a transaction.
*
* @param {object} options - See [Transaction](Transaction.md#Transaction.js/Transaction/**constructor**)
* @return {Promise<import('../Transaction').Transaction>}
*
* @example
* > account = new PrivateKeyAccount('0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef')
* > transaction = account.signTransaction({
nonce: 0,
gasPrice: 100,
gas: 10000,
storageLimit: 10000,
epochHeight: 100,
chainId: 0,
})
Transaction {
from: 'cfxtest:aasm4c231py7j34fghntcfkdt2nm9xv1tu6jd3r1s7',
nonce: 0,
gasPrice: 100,
gas: 10000,
to: undefined,
value: undefined,
storageLimit: 10000,
epochHeight: 100,
chainId: 0,
data: undefined,
v: 0,
r: '0x096f4e00ac15f6bd6e09937e99f0e54aaa2dd0f4c6bd8421e1e81b0e8bd30723',
s: '0x41e63a41ede0cbb8ccfaa827423c654dcdc09fb1aa1c3a7233566544aff4cd9a'
}
*/
async signTransaction(options) {
const transaction = await super.signTransaction(options);
transaction.sign(this.privateKey, this.networkId); // sign will cover r,s,v fields
assert(transaction.from === this.address, {
message: 'Invalid sign transaction.from',
expected: this.address,
got: transaction.from,
});
return transaction;
}
/**
* Sign a string.
*
* @param {string} options
* @return {Promise<import('../Message').Message>}
*
* @example
* > account = new PrivateKeyAccount('0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef')
* > message = account.signMessage('Hello World')
Message {
message: 'Hello World',
signature: '0x6e913e2b76459f19ebd269b82b51a70e912e909b2f5c002312efc27bcc280f3c29134d382aad0dbd3f0ccc9f0eb8f1dbe3f90141d81574ebb6504156b0d7b95f01'
}
*/
async signMessage(options) {
const message = await super.signMessage(options);
message.sign(this.privateKey, this.networkId); // sign will cover r,s,v fields
assert(message.from === this.address, {
message: 'Invalid sign message.from',
expected: this.address,
got: message.from,
});
return message;
}
}
module.exports = PrivateKeyAccount;