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