UNPKG

3.96 kBJavaScriptView Raw
1const { keccak256, ecdsaSign, ecdsaRecover, privateKeyToAddress } = require('./util/sign');
2const rlp = require('./util/rlp');
3const format = require('./util/format');
4
5class Transaction {
6 /**
7 * Create a transaction.
8 *
9 * @param options {object}
10 * @param options.from {string} - The sender address.
11 * @param options.nonce {string|number} - This allows to overwrite your own pending transactions that use the same nonce.
12 * @param options.gasPrice {string|number} - The price of gas for this transaction in drip.
13 * @param options.gas {string|number} - The amount of gas to use for the transaction (unused gas is refunded).
14 * @param [options.to=null] {string} - The destination address of the message, left undefined for a contract-creation transaction.
15 * @param [options.value=0] {string|number} - The value transferred for the transaction in drip, also the endowment if it’s a contract-creation transaction.
16 * @param options.storageLimit {string|number} - TODO
17 * @param options.epochHeight {string|number} - TODO
18 * @param [options.chainId=0] {string|number} - TODO
19 * @param [options.data='0x'] {string|Buffer} - Either a ABI byte string containing the data of the function call on a contract, or in the case of a contract-creation transaction the initialisation code.
20 * @param [options.r] {string|Buffer} - ECDSA signature r
21 * @param [options.s] {string|Buffer} - ECDSA signature s
22 * @param [options.v] {number} - ECDSA recovery id
23 * @return {Transaction}
24 */
25 constructor({ from, nonce, gasPrice, gas, to, value, storageLimit, epochHeight, chainId, data, v, r, s }) {
26 this.from = from;
27 this.nonce = nonce;
28 this.gasPrice = gasPrice;
29 this.gas = gas;
30 this.to = to;
31 this.value = value;
32 this.storageLimit = storageLimit;
33 this.epochHeight = epochHeight;
34 this.chainId = chainId;
35 this.data = data;
36 this.v = v;
37 this.r = r;
38 this.s = s;
39 }
40
41 /**
42 * Getter of transaction hash include signature.
43 *
44 * > Note: calculate every time.
45 *
46 * @return {string|undefined} If transaction has r,s,v return hex string, else return undefined.
47 */
48 get hash() {
49 try {
50 return format.hex(keccak256(this.encode(true)));
51 } catch (e) {
52 return undefined;
53 }
54 }
55
56 /**
57 * Sign transaction and set 'r','s','v'.
58 *
59 * @param privateKey {string} - Private key hex string.
60 * @return {Transaction}
61 */
62 sign(privateKey) {
63 const privateKeyBuffer = format.hexBuffer(privateKey);
64 const addressBuffer = privateKeyToAddress(privateKeyBuffer);
65 const { r, s, v } = ecdsaSign(keccak256(this.encode(false)), privateKeyBuffer);
66
67 this.from = format.address(addressBuffer);
68 this.r = format.hex(r);
69 this.s = format.hex(s);
70 this.v = v;
71
72 return this;
73 }
74
75 /**
76 * Recover public key from signed Transaction.
77 *
78 * @return {string}
79 */
80 recover() {
81 const publicKey = ecdsaRecover(keccak256(this.encode(false)), {
82 r: format.hexBuffer(this.r),
83 s: format.hexBuffer(this.s),
84 v: format.uInt(this.v),
85 });
86 return format.publicKey(publicKey);
87 }
88
89 /**
90 * Encode rlp.
91 *
92 * @param [includeSignature=false] {boolean} - Whether or not to include the signature.
93 * @return {Buffer}
94 */
95 encode(includeSignature) {
96 const { nonce, gasPrice, gas, to, value, storageLimit, epochHeight, chainId, data, v, r, s } = format.signTx(this);
97
98 const raw = includeSignature
99 ? [[nonce, gasPrice, gas, to, value, storageLimit, epochHeight, chainId, data], v, r, s]
100 : [nonce, gasPrice, gas, to, value, storageLimit, epochHeight, chainId, data];
101
102 return rlp.encode(raw);
103 }
104
105 /**
106 * Get the raw transaction hex string.
107 *
108 * @return {string} Hex string
109 */
110 serialize() {
111 return format.hex(this.encode(true));
112 }
113}
114
115module.exports = Transaction;