1 | const { keccak256, ecdsaSign, ecdsaRecover, privateKeyToAddress } = require('./util/sign');
|
2 | const rlp = require('./util/rlp');
|
3 | const format = require('./util/format');
|
4 |
|
5 | class 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 |
|
115 | module.exports = Transaction;
|