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