1 | const lodash = require('lodash');
|
2 | const { FunctionCoder, errorCoder } = require('../abi');
|
3 | const callable = require('../lib/callable');
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | class Called {
|
9 | constructor(cfx, method, { to, data }) {
|
10 | this.cfx = cfx;
|
11 | this.method = method;
|
12 | this.to = to;
|
13 | this.data = data;
|
14 | }
|
15 |
|
16 | |
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 | sendTransaction(options) {
|
27 | return this.cfx.sendTransaction({
|
28 | to: this.to,
|
29 | data: this.data,
|
30 | ...options,
|
31 | });
|
32 | }
|
33 |
|
34 | |
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 | async estimateGasAndCollateral(options) {
|
43 | try {
|
44 | return await this.cfx.estimateGasAndCollateral({ to: this.to, data: this.data, ...options });
|
45 | } catch (e) {
|
46 | throw errorCoder.decodeError(e);
|
47 | }
|
48 | }
|
49 |
|
50 | |
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 | async call(options, epochNumber) {
|
62 | try {
|
63 | const hex = await this.cfx.call({ to: this.to, data: this.data, ...options }, epochNumber);
|
64 | return this.method.decodeOutputs(hex);
|
65 | } catch (e) {
|
66 | throw errorCoder.decodeError(e);
|
67 | }
|
68 | }
|
69 |
|
70 | async then(resolve, reject) {
|
71 | try {
|
72 | const result = await this.call();
|
73 | resolve(result);
|
74 | } catch (e) {
|
75 | reject(e);
|
76 | }
|
77 | }
|
78 | }
|
79 |
|
80 | class ContractMethod extends FunctionCoder {
|
81 | constructor(cfx, contract, fragment) {
|
82 | super(fragment);
|
83 | this.cfx = cfx;
|
84 | this.contract = contract;
|
85 |
|
86 | return callable(this, this.call.bind(this));
|
87 | }
|
88 |
|
89 | call(...args) {
|
90 | const to = this.contract.address;
|
91 | const data = this.encodeData(args);
|
92 | return new Called(this.cfx, this, { to, data });
|
93 | }
|
94 |
|
95 | decodeData(hex) {
|
96 | const namedTuple = super.decodeData(hex);
|
97 | return {
|
98 | name: this.name,
|
99 | fullName: this.fullName,
|
100 | type: this.type,
|
101 | signature: this.signature,
|
102 | array: [...namedTuple],
|
103 | object: namedTuple.toObject(),
|
104 | };
|
105 | }
|
106 | }
|
107 |
|
108 |
|
109 |
|
110 |
|
111 | class ContractMethodOverride {
|
112 | constructor(cfx, contract, methods) {
|
113 | this.cfx = cfx;
|
114 | this.contract = contract;
|
115 | this.signatureToMethod = lodash.keyBy(methods, 'signature');
|
116 |
|
117 | return callable(this, this.call.bind(this));
|
118 | }
|
119 |
|
120 | call(...args) {
|
121 | const acceptArray = [];
|
122 | const rejectArray = [];
|
123 |
|
124 | let called;
|
125 | for (const method of Object.values(this.signatureToMethod)) {
|
126 | try {
|
127 | called = method(...args);
|
128 | acceptArray.push(method.type);
|
129 | } catch (e) {
|
130 | rejectArray.push(method.type);
|
131 | }
|
132 | }
|
133 |
|
134 | if (!acceptArray.length) {
|
135 | throw new Error(`can not match override "${rejectArray.join('|')}" with args (${args.join(',')})`);
|
136 | }
|
137 | if (acceptArray.length > 1) {
|
138 | throw new Error(`can not determine override "${acceptArray.join('|')}" with args (${args.join(',')})`);
|
139 | }
|
140 |
|
141 | return called;
|
142 | }
|
143 |
|
144 | decodeData(hex) {
|
145 | const signature = hex.slice(0, 10);
|
146 | const method = this.signatureToMethod[signature];
|
147 | return method.decodeData(hex);
|
148 | }
|
149 | }
|
150 |
|
151 | module.exports = ContractMethod;
|
152 | module.exports.ContractMethodOverride = ContractMethodOverride;
|
153 | module.exports.Called = Called;
|