1 | const { assert, format, decorate } = require('./util');
|
2 | const providerFactory = require('./provider');
|
3 | const accountFactory = require('./account');
|
4 | const Contract = require('./contract');
|
5 | const Drip = require('./Drip');
|
6 | const decodeError = require('./contract/decodeError');
|
7 | const { PendingTransaction } = require('./subscribe');
|
8 | const internalContract = require('./contract/internal');
|
9 |
|
10 | /**
|
11 | * A sdk of conflux.
|
12 | */
|
13 | class Conflux {
|
14 | /**
|
15 | * @param [options] {object} - Conflux and Provider constructor options.
|
16 | * @param [options.url] {string} - Url of Conflux node to connect.
|
17 | * @param [options.defaultGasPrice] {string|number} - The default gas price in drip to use for transactions.
|
18 | * @param [options.logger] {Object} - Logger object with 'info' and 'error' method.
|
19 | * @example
|
20 | * > const { Conflux } = require('js-conflux-sdk');
|
21 | * > const conflux = new Conflux({url:'http://testnet-jsonrpc.conflux-chain.org:12537'});
|
22 | *
|
23 | * @example
|
24 | * > const conflux = new Conflux({
|
25 | url: 'http://localhost:8000',
|
26 | defaultGasPrice: 100,
|
27 | logger: console,
|
28 | });
|
29 | */
|
30 | constructor({ defaultGasPrice, ...rest } = {}) {
|
31 | this.provider = providerFactory(rest);
|
32 |
|
33 | /**
|
34 | * Default gas price for following methods:
|
35 | * - `Conflux.sendTransaction`
|
36 | *
|
37 | * @deprecated
|
38 | * @type {number|string}
|
39 | */
|
40 | this.defaultGasPrice = defaultGasPrice;
|
41 |
|
42 | this.sendTransaction = decorate(this.sendTransaction, (func, ...args) => {
|
43 | return new PendingTransaction(func, args, this);
|
44 | });
|
45 |
|
46 | this.sendRawTransaction = decorate(this.sendRawTransaction, (func, ...args) => {
|
47 | return new PendingTransaction(func, args, this);
|
48 | });
|
49 | }
|
50 |
|
51 | /**
|
52 | * A shout cut for `accountFactory(options, conflux);`
|
53 | *
|
54 | * @param options {object} - See [accountFactory](#account/index.js/accountFactory)
|
55 | * @return {BaseAccount} A BaseAccount subclass instance
|
56 | *
|
57 | * @example
|
58 | * > account = conflux.Account({privateKey: '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'})
|
59 | */
|
60 | Account(options) {
|
61 | return accountFactory(options, this);
|
62 | }
|
63 |
|
64 | /**
|
65 | * A shout cut for `new Contract(options, conflux);`
|
66 | *
|
67 | * @param options {object} - See [Contract.constructor](#Contract.js/constructor)
|
68 | * @return {Contract} - A Contract instance
|
69 | */
|
70 | Contract(options) {
|
71 | return new Contract(options, this);
|
72 | }
|
73 |
|
74 | /**
|
75 | * Create internal contract by default abi and address
|
76 | *
|
77 | * - [AdminControl](https://github.com/Conflux-Chain/conflux-rust/blob/master/internal_contract/contracts/AdminControl.sol)
|
78 | * - [SponsorWhitelistControl](https://github.com/Conflux-Chain/conflux-rust/blob/master/internal_contract/contracts/SponsorWhitelistControl.sol)
|
79 | * - [Staking](https://github.com/Conflux-Chain/conflux-rust/blob/master/internal_contract/contracts/Staking.sol)
|
80 | *
|
81 | * @param name {string} Internal contract name
|
82 | * @return {Contract}
|
83 | *
|
84 | * @example
|
85 | * > conflux.InternalContract('AdminControl')
|
86 | {
|
87 | constructor: [Function: bound call],
|
88 | abi: ContractABICoder { * },
|
89 | address: '0x0888000000000000000000000000000000000000',
|
90 | destroy: [Function: bound call],
|
91 | set_admin: [Function: bound call],
|
92 | 'destroy(address)': [Function: bound call],
|
93 | '0x00f55d9d': [Function: bound call],
|
94 | 'set_admin(address,address)': [Function: bound call],
|
95 | '0x73e80cba': [Function: bound call]
|
96 | }
|
97 | */
|
98 | InternalContract(name) {
|
99 | const options = internalContract[name];
|
100 | assert(options, `can not find internal contract named "${name}"`);
|
101 | return this.Contract(options);
|
102 | }
|
103 |
|
104 | /**
|
105 | * close connection.
|
106 | *
|
107 | * @example
|
108 | * > conflux.close();
|
109 | */
|
110 | close() {
|
111 | this.provider.close();
|
112 | this.provider = providerFactory();
|
113 | }
|
114 |
|
115 | // --------------------------------------------------------------------------
|
116 | /**
|
117 | * Get node client version
|
118 | *
|
119 | * @private
|
120 | * @return {Promise<string>}
|
121 | */
|
122 | async getClientVersion() {
|
123 | return this.provider.call('cfx_clientVersion');
|
124 | }
|
125 |
|
126 | /**
|
127 | * Get status
|
128 | * @return {Promise<object>} Status information object
|
129 | * - `number` chainId: Chain id
|
130 | * - `number` epochNumber: Epoch number
|
131 | * - `number` blockNumber: Block number
|
132 | * - `number` pendingTxNumber: Pending transaction number
|
133 | * - `string` bestHash: The block hash of best pivot block
|
134 | *
|
135 | * @example
|
136 | * > await conflux.getStatus()
|
137 | {
|
138 | "chainId": 2,
|
139 | "epochNumber": 324105,
|
140 | "blockNumber": 426341,
|
141 | "pendingTxNumber": 40,
|
142 | "bestHash": "0xef08f2702335f149afc021607511ffae49df8bb56b2afb7f42de02d9cbbf7ef6"
|
143 | }
|
144 | */
|
145 | async getStatus() {
|
146 | const result = await this.provider.call('cfx_getStatus');
|
147 | return format.status(result);
|
148 | }
|
149 |
|
150 | /**
|
151 | * Returns the current price per gas in Drip.
|
152 | *
|
153 | * @return {Promise<Drip>} Gas price in drip.
|
154 | *
|
155 | * @example
|
156 | * > await conflux.getGasPrice();
|
157 | [String (Drip): '1']
|
158 | */
|
159 | async getGasPrice() {
|
160 | const result = await this.provider.call('cfx_gasPrice');
|
161 | return Drip.fromDrip(result);
|
162 | }
|
163 |
|
164 | /**
|
165 | * Returns the interest rate of given parameter.
|
166 | *
|
167 | * @param [epochNumber='latest_state'] {string|number} - See [format.sendTx](#util/format.js/epochNumber)
|
168 | * @return {Promise<JSBI>} The interest rate of given parameter.
|
169 | *
|
170 | * @example
|
171 | * > await conflux.getInterestRate();
|
172 | "2522880000000"
|
173 | */
|
174 | async getInterestRate(epochNumber) {
|
175 | const result = await this.provider.call('cfx_getInterestRate',
|
176 | format.epochNumber.$or(undefined)(epochNumber),
|
177 | );
|
178 | return format.bigUInt(result);
|
179 | }
|
180 |
|
181 | /**
|
182 | * Returns the accumulate interest rate of given parameter.
|
183 | *
|
184 | * @param [epochNumber='latest_state'] {string|number} - See [format.sendTx](#util/format.js/epochNumber)
|
185 | * @return {Promise<JSBI>} The accumulate interest rate of given parameter.
|
186 | *
|
187 | * @example
|
188 | * > await conflux.getAccumulateInterestRate()
|
189 | "76269979767787603657181926319926"
|
190 | */
|
191 | async getAccumulateInterestRate(epochNumber) {
|
192 | const result = await this.provider.call('cfx_getAccumulateInterestRate',
|
193 | format.epochNumber.$or(undefined)(epochNumber),
|
194 | );
|
195 | return format.bigUInt(result);
|
196 | }
|
197 |
|
198 | // ------------------------------- address ----------------------------------
|
199 | /**
|
200 | * Return account related states of the given account
|
201 | *
|
202 | * @param address {string} - address to get account.
|
203 | * @param [epochNumber='latest_state'] {string|number} - See [format.sendTx](#util/format.js/epochNumber)
|
204 | * @return {Promise<object>} Return the states of the given account:
|
205 | * balance `JSBI`: the balance of the account.
|
206 | * nonce `JSBI`: the nonce of the account's next transaction.
|
207 | * codeHash `string`: the code hash of the account.
|
208 | * stakingBalance `JSBI`: the staking balance of the account.
|
209 | * collateralForStorage `JSBI`: the collateral storage of the account.
|
210 | * accumulatedInterestReturn `JSBI`: accumulated unterest return of the account.
|
211 | * admin `string`: admin of the account.
|
212 | *
|
213 | * @example
|
214 | > await conflux.getAccount('0x1bd9e9be525ab967e633bcdaeac8bd5723ed4d6b');
|
215 | {
|
216 | "accumulatedInterestReturn": "0",
|
217 | "balance": "0",
|
218 | "collateralForStorage": "0",
|
219 | "nonce": "0",
|
220 | "stakingBalance": "0",
|
221 | "admin": "0x0000000000000000000000000000000000000000",
|
222 | "codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
|
223 | }
|
224 | */
|
225 | async getAccount(address, epochNumber) {
|
226 | const result = await this.provider.call('cfx_getAccount',
|
227 | format.address(address),
|
228 | format.epochNumber.$or(undefined)(epochNumber),
|
229 | );
|
230 | return format.account(result);
|
231 | }
|
232 |
|
233 | /**
|
234 | * Returns the balance of the account of given address.
|
235 | *
|
236 | * @param address {string} - The address to get the balance of.
|
237 | * @param [epochNumber='latest_state'] {string|number} - See [format.sendTx](#util/format.js/epochNumber)
|
238 | * @return {Promise<Drip>} The balance in Drip.
|
239 | *
|
240 | * @example
|
241 | * > await conflux.getBalance("0x1bd9e9be525ab967e633bcdaeac8bd5723ed4d6b");
|
242 | [String (Drip): '10098788868004995614504']
|
243 | */
|
244 | async getBalance(address, epochNumber) {
|
245 | const result = await this.provider.call('cfx_getBalance',
|
246 | format.address(address),
|
247 | format.epochNumber.$or(undefined)(epochNumber),
|
248 | );
|
249 | return Drip.fromDrip(result);
|
250 | }
|
251 |
|
252 | /**
|
253 | * Returns the balance of the staking account of given address.
|
254 | *
|
255 | * @param address {string} - Address to check for staking balance.
|
256 | * @param [epochNumber='latest_state'] {string|number} - See [format.sendTx](#util/format.js/epochNumber)
|
257 | * @return {Promise<Drip>} The staking balance in Drip.
|
258 | *
|
259 | * @example
|
260 | * > await conflux.getStakingBalance('0x194770007dda54cF92009BFF0dE90c06F603a09f', 'latest_state');
|
261 | [String (Drip): '6334100968004995614504']
|
262 | */
|
263 | async getStakingBalance(address, epochNumber) {
|
264 | const result = await this.provider.call('cfx_getStakingBalance',
|
265 | format.address(address),
|
266 | format.epochNumber.$or(undefined)(epochNumber),
|
267 | );
|
268 | return Drip.fromDrip(result);
|
269 | }
|
270 |
|
271 | /**
|
272 | * Returns the next nonce should be used by given address.
|
273 | *
|
274 | * @param address {string} - The address to get the numbers of transactions from.
|
275 | * @param [epochNumber] {string|number} - See [format.sendTx](#util/format.js/epochNumber)
|
276 | * @return {Promise<JSBI>} The next nonce should be used by given address.
|
277 | *
|
278 | * @example
|
279 | * > await conflux.getNextNonce("0x1be45681ac6c53d5a40475f7526bac1fe7590fb8");
|
280 | "3"
|
281 | */
|
282 | async getNextNonce(address, epochNumber) {
|
283 | const result = await this.provider.call('cfx_getNextNonce',
|
284 | format.address(address),
|
285 | format.epochNumber.$or(undefined)(epochNumber),
|
286 | );
|
287 | return format.bigUInt(result);
|
288 | }
|
289 |
|
290 | /**
|
291 | * Returns the admin of given contract.
|
292 | *
|
293 | * @param address {string} - Address to contract.
|
294 | * @param [epochNumber='latest_state'] {string|number} - See [format.sendTx](#util/format.js/epochNumber)
|
295 | * @return {Promise<string>} Address to admin, or `null` if the contract does not exist.
|
296 | *
|
297 | * @example
|
298 | * > conflux.getAdmin('0x8af71f222b6e05b47d8385fe437fe2f2a9ec1f1f')
|
299 | "0x144aa8f554d2ffbc81e0aa0f533f76f5220db09c"
|
300 | */
|
301 | async getAdmin(address, epochNumber) {
|
302 | return this.provider.call('cfx_getAdmin',
|
303 | format.address(address),
|
304 | format.epochNumber.$or(undefined)(epochNumber),
|
305 | );
|
306 | }
|
307 |
|
308 | // -------------------------------- epoch -----------------------------------
|
309 | /**
|
310 | * Returns the epoch number of given parameter.
|
311 | *
|
312 | * @param [epochNumber='latest_state'] {string|number} - See [format.sendTx](#util/format.js/epochNumber)
|
313 | * @return {Promise<number>} integer of the current epoch number of given parameter.
|
314 | *
|
315 | * @example
|
316 | * > await conflux.getEpochNumber();
|
317 | 443
|
318 | */
|
319 | async getEpochNumber(epochNumber) {
|
320 | const result = await this.provider.call('cfx_epochNumber',
|
321 | format.epochNumber.$or(undefined)(epochNumber),
|
322 | );
|
323 | return format.uInt(result);
|
324 | }
|
325 |
|
326 | /**
|
327 | * Returns information about a block by epoch number.
|
328 | *
|
329 | * @param epochNumber {string|number} - See [format.sendTx](#util/format.js/epochNumber)
|
330 | * @param [detail=false] {boolean} - If `true` it returns the full transaction objects, if `false` only the hashes of the transactions.
|
331 | * @return {Promise<object|null>} See `getBlockByHash`
|
332 | *
|
333 | * @example
|
334 | * > await conflux.getBlockByEpochNumber('latest_mined', true);
|
335 | {...}
|
336 | */
|
337 | async getBlockByEpochNumber(epochNumber, detail = false) {
|
338 | const result = await this.provider.call('cfx_getBlockByEpochNumber',
|
339 | format.epochNumber(epochNumber),
|
340 | format.boolean(detail),
|
341 | );
|
342 | return format.block.$or(null)(result);
|
343 | }
|
344 |
|
345 | /**
|
346 | * Returns hashes of blocks located in some epoch.
|
347 | *
|
348 | * @param epochNumber {string|number} - See [format.sendTx](#util/format.js/epochNumber)
|
349 | * @return {Promise<string[]>} Array of block hashes, sorted by execution(topological) order.
|
350 | *
|
351 | * @example
|
352 | * > await conflux.getBlocksByEpochNumber(0);
|
353 | ['0xe677ae5206a5d67d9efa183d867b4b986ed82a3e62174a1488cf8364d58534ec']
|
354 | */
|
355 | async getBlocksByEpochNumber(epochNumber) {
|
356 | return this.provider.call('cfx_getBlocksByEpoch',
|
357 | format.epochNumber(epochNumber),
|
358 | );
|
359 | }
|
360 |
|
361 | /**
|
362 | * Get epoch blocks reward info
|
363 | *
|
364 | * @private
|
365 | * @param epochNumber {string|number} - See [format.sendTx](#util/format.js/epochNumber)
|
366 | * @return {Promise<object[]>} List of block reward info
|
367 | * - blockHash `string`: Hash of the block.
|
368 | * - author `string`: The address of the beneficiary to whom the mining rewards were given.
|
369 | * - baseReward `JSBI`: Block base reward in `Drip`
|
370 | * - totalReward `JSBI`: Block total reward in `Drip`
|
371 | * - txFee `JSBI`: Total gas fee of block transaction
|
372 | *
|
373 | * @example
|
374 | * > await conflux.getBlockRewardInfo(4060000);
|
375 | [
|
376 | {
|
377 | "baseReward": "11295480000000000000",
|
378 | "totalReward": "11295509726193823715",
|
379 | "txFee": "0",
|
380 | "author": "0x13bbe31525cb9ed1461d3277c4413c854d9f8355",
|
381 | "blockHash": "0x305c0a205af135ffca55a6ffb9569cbf93451ea3b7211b8f0ae39c147f3320e8"
|
382 | },
|
383 | {
|
384 | "baseReward": "11300000000000000000",
|
385 | "totalReward": "11300029738091185588",
|
386 | "txFee": "2126250",
|
387 | "author": "0x1a84009b2f981155b98bb7e10aa0965fbc169be7",
|
388 | "blockHash": "0xfc75086a3a752d742673859d371061e8a59c85a54e90f13914b62c20364a2150"
|
389 | }
|
390 | ]
|
391 | */
|
392 | async getBlockRewardInfo(epochNumber) {
|
393 | const result = await this.provider.call('cfx_getBlockRewardInfo',
|
394 | format.epochNumber(epochNumber),
|
395 | );
|
396 | return format.rewardInfo(result);
|
397 | }
|
398 |
|
399 | // -------------------------------- block -----------------------------------
|
400 | /**
|
401 | * Returns the hash of best block.
|
402 | *
|
403 | * @return {Promise<string>} hash of the best block.
|
404 | *
|
405 | * @example
|
406 | * > await conflux.getBestBlockHash();
|
407 | "0xb8bb355bfeaf055a032d5b7df719917c090ee4fb6fee42383004dfe8911d7daf"
|
408 | */
|
409 | async getBestBlockHash() {
|
410 | return this.provider.call('cfx_getBestBlockHash');
|
411 | }
|
412 |
|
413 | /**
|
414 | * Returns information about a block by hash.
|
415 | *
|
416 | * @param blockHash {string} - hash of a block.
|
417 | * @param [detail=false] {boolean} - If `true` it returns the full transaction objects, if `false` only the hashes of the transactions.
|
418 | * @return {Promise<object|null>} A block object, or null when no block was found:
|
419 | * - adaptive `boolean`: If `true` the weight of the block is adaptive under GHAST rule, if `false` otherwise.
|
420 | * - blame `number`: If 0, then no blocks are blamed on its parent path, If greater than 0, then the nearest blamed block on the parent path is blame steps away.
|
421 | * - deferredLogsBloomHash `string`: The bloom hash of deferred logs.
|
422 | * - deferredReceiptsRoot `string`: The hash of the receipts of the block after deferred execution.
|
423 | * - deferredStateRoot `string`: The root of the final state trie of the block after deferred execution.
|
424 | * - difficulty `string`: Integer string of the difficulty for this block.
|
425 | * - epochNumber `number|null`: The current block epoch number in the client's view. null when it's not in best block's past set and the epoch number is not determined.
|
426 | * - gasLimit `JSBI`: The maximum gas allowed in this block.
|
427 | * - hash `string|null`: Hash of the block. `null` when its pending block.
|
428 | * - height `number`: The block heights. `null` when its pending block.
|
429 | * - miner `string`: The address of the beneficiary to whom the mining rewards were given.
|
430 | * - nonce `string`: Hash of the generated proof-of-work. `null` when its pending block.
|
431 | * - parentHash `string`: Hash of the parent block.
|
432 | * - powQuality `string`:Hash of the generated proof-of-work. `null` when its pending block.
|
433 | * - refereeHashes `string[]`: Array of referee hashes.
|
434 | * - size `number`: Integer the size of this block in bytes.
|
435 | * - timestamp `number`: The unix timestamp for when the block was collated.
|
436 | * - transactions `string[]|object[]`: Array of transaction objects, or 32 Bytes transaction hashes depending on the last given parameter.
|
437 | * - transactionsRoot `string`: The hash of the transactions of the block.
|
438 | *
|
439 | * @example
|
440 | * > await conflux.getBlockByHash('0x0909bdb39910d743e7e9b68f24afbbf187349447b161c4716bfd278fd7a0cbc7');
|
441 | {
|
442 | "epochNumber": 455,
|
443 | "blame": 0,
|
444 | "height": 455,
|
445 | "size": 122,
|
446 | "timestamp": 1594912954,
|
447 | "gasLimit": "30000000",
|
448 | "difficulty": "30000",
|
449 | "transactions": [
|
450 | "0xe6b56ef6a2be1987b0353a316cb02c78493673c31adb847b947d47c3936d89a8"
|
451 | ],
|
452 | "adaptive": false,
|
453 | "deferredLogsBloomHash": "0xd397b3b043d87fcd6fad1291ff0bfd16401c274896d8c63a923727f077b8e0b5",
|
454 | "deferredReceiptsRoot": "0x09f8709ea9f344a810811a373b30861568f5686e649d6177fd92ea2db7477508",
|
455 | "deferredStateRoot": "0x2124f4f35df1abeb01a43ed25c6b7ea5a56bbc2bdb3ab3feb096e3911e522181",
|
456 | "hash": "0x0909bdb39910d743e7e9b68f24afbbf187349447b161c4716bfd278fd7a0cbc7",
|
457 | "miner": "0x100000000000000000000000000000000000007c",
|
458 | "nonce": "0xcc2eadd8c5c369ff",
|
459 | "parentHash": "0x9ced22205ac0fe96ad27be9c0add073ce49582220b8fd1006edf16a402aef9b4",
|
460 | "powQuality": "0x167d3",
|
461 | "refereeHashes": [],
|
462 | "transactionsRoot": "0x5a31184b86d8b88a3860649c17a4b7b4d3c7ef35fea971afb1f44081feff5b60"
|
463 | }
|
464 | */
|
465 | async getBlockByHash(blockHash, detail = false) {
|
466 | const result = await this.provider.call('cfx_getBlockByHash',
|
467 | format.blockHash(blockHash),
|
468 | format.boolean(detail),
|
469 | );
|
470 | return format.block.$or(null)(result);
|
471 | }
|
472 |
|
473 | /**
|
474 | * Get block by `blockHash` if pivot block of `epochNumber` is `pivotBlockHash`.
|
475 | *
|
476 | * @private
|
477 | * @param blockHash {string} - Block hash which epochNumber expect to be `epochNumber`.
|
478 | * @param pivotBlockHash {string} - Block hash which expect to be the pivot block of `epochNumber`.
|
479 | * @param epochNumber {number} - Epoch number
|
480 | * @return {Promise<object>} See `getBlockByHash`
|
481 | */
|
482 | async getBlockByHashWithPivotAssumption(blockHash, pivotBlockHash, epochNumber) {
|
483 | const result = await this.provider.call('cfx_getBlockByHashWithPivotAssumption',
|
484 | format.blockHash(blockHash),
|
485 | format.blockHash(pivotBlockHash),
|
486 | format.epochNumber(epochNumber),
|
487 | );
|
488 | return format.block(result);
|
489 | }
|
490 |
|
491 | /**
|
492 | * Get the risk of the block could be reverted.
|
493 | * All block in one same epoch returned same risk number
|
494 | *
|
495 | * @param blockHash {string} - Hash of a block
|
496 | * @return {Promise<number|null>} Number >0 and <1
|
497 | *
|
498 | * @example
|
499 | * > await conflux.getConfirmationRiskByHash('0x24dcc768132dc7f651d7cb35c52e7bba632eda073d8743f81cfe905ff7e4157a')
|
500 | 1e-8
|
501 | */
|
502 | async getConfirmationRiskByHash(blockHash) {
|
503 | const result = await this.provider.call('cfx_getConfirmationRiskByHash',
|
504 | format.blockHash(blockHash),
|
505 | );
|
506 | return format.riskNumber.$or(null)(result);
|
507 | }
|
508 |
|
509 | // ----------------------------- transaction --------------------------------
|
510 | /**
|
511 | * Returns the information about a transaction requested by transaction hash.
|
512 | *
|
513 | * @param transactionHash {string} - hash of a transaction
|
514 | * @return {Promise<object|null>} transaction object, or `null` when no transaction was found:
|
515 | * - blockHash `string`: hash of the block where this transaction was in and got executed. `null` when its pending.
|
516 | * - contractCreated `string|null`: address of created contract. `null` when it's not a contract creating transaction
|
517 | * - data `string`: the data send along with the transaction.
|
518 | * - epochHeight `number`: TODO
|
519 | * - from `string`: address of the sender.
|
520 | * - gas `JSBI`: gas provided by the sender.
|
521 | * - gasPrice `number`: gas price provided by the sender in Drip.
|
522 | * - hash `string`: hash of the transaction.
|
523 | * - nonce `JSBI`: the number of transactions made by the sender prior to this one.
|
524 | * - r `string`: ECDSA signature r
|
525 | * - s `string`: ECDSA signature s
|
526 | * - status `number`: 0 for success, 1 for error occured, `null` when the transaction is skipped or not packed.
|
527 | * - storageLimit `JSBI`: TODO
|
528 | * - chainId `number`: TODO
|
529 | * - to `string`: address of the receiver. null when its a contract creation transaction.
|
530 | * - transactionIndex `number`: integer of the transactions's index position in the block. `null` when its pending.
|
531 | * - v `string`: ECDSA recovery id
|
532 | * - value `JSBI`: value transferred in Drip.
|
533 | *
|
534 | * @example
|
535 | * > await conflux.getTransactionByHash('0xe6b56ef6a2be1987b0353a316cb02c78493673c31adb847b947d47c3936d89a8');
|
536 | {
|
537 | "nonce": "0",
|
538 | "value": "1000000000000000000000000000000000",
|
539 | "gasPrice": "3",
|
540 | "gas": "16777216",
|
541 | "v": 1,
|
542 | "transactionIndex": 0,
|
543 | "status": 0,
|
544 | "storageLimit": "65536",
|
545 | "chainId": 2,
|
546 | "epochHeight": 454,
|
547 | "blockHash": "0x0909bdb39910d743e7e9b68f24afbbf187349447b161c4716bfd278fd7a0cbc7",
|
548 | "contractCreated": null,
|
549 | "data": "0x",
|
550 | "from": "0x1be45681ac6c53d5a40475f7526bac1fe7590fb8",
|
551 | "hash": "0xe6b56ef6a2be1987b0353a316cb02c78493673c31adb847b947d47c3936d89a8",
|
552 | "r": "0x85f6729aa1e709202318bd6746c4a232a379eaa4cd9c2ea24c7babdbd09085cd",
|
553 | "s": "0x7101e1e2ee4ddfcef8879358df0cb0792f34712116f100b76c8e9582625acd2f",
|
554 | "to": "0x144aa8f554d2ffbc81e0aa0f533f76f5220db09c"
|
555 | }
|
556 | */
|
557 | async getTransactionByHash(transactionHash) {
|
558 | const result = await this.provider.call('cfx_getTransactionByHash',
|
559 | format.transactionHash(transactionHash),
|
560 | );
|
561 | return format.transaction.$or(null)(result);
|
562 | }
|
563 |
|
564 | /**
|
565 | * Returns the information about a transaction receipt requested by transaction hash.
|
566 | *
|
567 | * @param transactionHash {string} - Hash of a transaction
|
568 | * @return {Promise<object|null>} A transaction receipt object, or null when no transaction was found or the transaction was not executed yet:
|
569 | * - transactionHash `string`: Hash of the given transaction.
|
570 | * - index `number`: Transaction index within the block.
|
571 | * - blockHash `string`: Hash of the block where this transaction was in and got executed.
|
572 | * - epochNumber `number`: Epoch number of the block where this transaction was in and got executed.
|
573 | * - from `string`: Address of the sender.
|
574 | * - to `string`: Address of the receiver. `null` when its a contract creation transaction.
|
575 | * - gasUsed `number`: Gas used the transaction.
|
576 | * - contractCreated `string|null`: Address of created contract. `null` when it's not a contract creating transaction.
|
577 | * - stateRoot `string`: Hash of the state root.
|
578 | * - outcomeStatus `number`: the outcome status code, 0 was successful, 1 for an error occurred in the execution.
|
579 | * - logsBloom `string`: Bloom filter for light clients to quickly retrieve related logs.
|
580 | * - logs `object[]`: Array of log objects, which this transaction generated.
|
581 | *
|
582 | * @example
|
583 | * > await conflux.getTransactionReceipt('0xe6b56ef6a2be1987b0353a316cb02c78493673c31adb847b947d47c3936d89a8');
|
584 | {
|
585 | "index": 0,
|
586 | "epochNumber": 455,
|
587 | "outcomeStatus": 0,
|
588 | "gasUsed": "21000",
|
589 | "gasFee": "37748736",
|
590 | "blockHash": "0x0909bdb39910d743e7e9b68f24afbbf187349447b161c4716bfd278fd7a0cbc7",
|
591 | "contractCreated": null,
|
592 | "from": "0x1be45681ac6c53d5a40475f7526bac1fe7590fb8",
|
593 | "logs": [],
|
594 | "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
595 | "stateRoot": "0x19d109e6fe9f5a75cc54543af4beab08c0f23fdf95eea33b1afe5a9ef8b770dc",
|
596 | "to": "0x144aa8f554d2ffbc81e0aa0f533f76f5220db09c",
|
597 | "transactionHash": "0xe6b56ef6a2be1987b0353a316cb02c78493673c31adb847b947d47c3936d89a8"
|
598 | }
|
599 | */
|
600 | async getTransactionReceipt(transactionHash) {
|
601 | const result = await this.provider.call('cfx_getTransactionReceipt',
|
602 | format.transactionHash(transactionHash),
|
603 | );
|
604 | return format.receipt.$or(null)(result);
|
605 | }
|
606 |
|
607 | /**
|
608 | * Creates new message call transaction or a contract creation for signed transactions.
|
609 | *
|
610 | * @param hex {string|Buffer} - The signed transaction data.
|
611 | * @return {Promise<PendingTransaction>} The transaction hash, or the zero hash if the transaction is not yet available.
|
612 | *
|
613 | * @example
|
614 | * > await conflux.sendRawTransaction('0xf85f800382520894bbd9e9b...');
|
615 | "0xbe007c3eca92d01f3917f33ae983f40681182cf618defe75f490a65aac016914"
|
616 | */
|
617 | async sendRawTransaction(hex) {
|
618 | return this.provider.call('cfx_sendRawTransaction',
|
619 | format.hex(hex),
|
620 | );
|
621 | }
|
622 |
|
623 | /**
|
624 | * Send transaction and sign by remote by password
|
625 | *
|
626 | * @private
|
627 | * @param options {object} - See [format.sendTx](#util/format.js/sendTx)
|
628 | * @param password {string} - Password for remote node.
|
629 | * @return {Promise<PendingTransaction>} The PendingTransaction object.
|
630 | */
|
631 | async sendTransaction(options, password) {
|
632 | return this.provider.call('cfx_sendTransaction',
|
633 | format.sendTx(options),
|
634 | password,
|
635 | );
|
636 | }
|
637 |
|
638 | // ------------------------------ contract ----------------------------------
|
639 | /**
|
640 | * Returns the code of given contract.
|
641 | *
|
642 | * @param address {string} - Address to contract.
|
643 | * @param [epochNumber='latest_state'] {string|number} - See [format.sendTx](#util/format.js/epochNumber)
|
644 | * @return {Promise<string>} Byte code of contract, or 0x if the contract does not exist.
|
645 | *
|
646 | * @example
|
647 | * > await conflux.getCode('0xb385b84f08161f92a195953b980c8939679e906a');
|
648 | "0x6080604052348015600f57600080fd5b506004361060325760003560e01c806306661abd1460375780638..."
|
649 | */
|
650 | async getCode(address, epochNumber) {
|
651 | return this.provider.call('cfx_getCode',
|
652 | format.address(address),
|
653 | format.epochNumber.$or(undefined)(epochNumber),
|
654 | );
|
655 | }
|
656 |
|
657 | /**
|
658 | * Returns storage entries from a given contract.
|
659 | *
|
660 | * @param address {string} - Address to contract.
|
661 | * @param position {string} - The given position.
|
662 | * @param [epochNumber='latest_state'] {string|number} - See [format.sendTx](#util/format.js/epochNumber)
|
663 | * @return {Promise<string|null>} Storage entry of given query, or null if the it does not exist.
|
664 | *
|
665 | * @example
|
666 | * > await conflux.getStorageAt('0x866aca87ff33a0ae05d2164b3d999a804f583222', '0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9')
|
667 | "0x000000000000000000000000000000000000000000000000000000000000162e"
|
668 | */
|
669 | async getStorageAt(address, position, epochNumber) {
|
670 | return this.provider.call('cfx_getStorageAt',
|
671 | format.address(address),
|
672 | format.hex64(position),
|
673 | format.epochNumber.$or(undefined)(epochNumber),
|
674 | );
|
675 | }
|
676 |
|
677 | /**
|
678 | * Returns the storage root of a given contract.
|
679 | *
|
680 | * @param address {string} - Address to contract.
|
681 | * @param [epochNumber='latest_state'] {string|number} - See [format.sendTx](#util/format.js/epochNumber)
|
682 | * @return {Promise<object>} A storage root object, or `null` if the contract does not exist
|
683 | * - delta `string`: storage root in the delta trie.
|
684 | * - intermediate `string`: storage root in the intermediate trie.
|
685 | * - snapshot `string`: storage root in the snapshot.
|
686 | *
|
687 | * @example
|
688 | * > await conflux.getStorageRoot('0x866aca87ff33a0ae05d2164b3d999a804f583222')
|
689 | {
|
690 | "delta": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
|
691 | "intermediate": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
|
692 | "snapshot": "0x7bb7d43152e56f529fbef709aab7371b0672f2332ae0fb4786da350f664df5b4"
|
693 | }
|
694 | */
|
695 | async getStorageRoot(address, epochNumber) {
|
696 | return this.provider.call('cfx_getStorageRoot',
|
697 | format.address(address),
|
698 | format.epochNumber.$or(undefined)(epochNumber),
|
699 | );
|
700 | }
|
701 |
|
702 | /**
|
703 | * Returns the sponsor info of given contract.
|
704 | *
|
705 | * @param address {string} - Address to contract.
|
706 | * @param [epochNumber='latest_state'] {string|number} - See [format.sendTx](#util/format.js/epochNumber)
|
707 | * @return {Promise<object>} A sponsor info object, if the contract doesn't have a sponsor, then the all fields in returned object will be 0:
|
708 | * - sponsorBalanceForCollateral `JSBI`: the sponsored balance for storage.
|
709 | * - sponsorBalanceForGas `JSBI`: the sponsored balance for gas.
|
710 | * - sponsorGasBound `JSBI`: the max gas could be sponsored for one transaction.
|
711 | * - sponsorForCollateral `string`: the address of the storage sponsor.
|
712 | * - sponsorForGas `string`: the address of the gas sponsor.
|
713 | *
|
714 | * @example
|
715 | * > await conflux.getSponsorInfo('0x866aca87ff33a0ae05d2164b3d999a804f583222')
|
716 | {
|
717 | "sponsorBalanceForCollateral": "0",
|
718 | "sponsorBalanceForGas": "0",
|
719 | "sponsorGasBound": "0",
|
720 | "sponsorForCollateral": "0x0000000000000000000000000000000000000000",
|
721 | "sponsorForGas": "0x0000000000000000000000000000000000000000"
|
722 | }
|
723 | */
|
724 | async getSponsorInfo(address, epochNumber) {
|
725 | const result = await this.provider.call('cfx_getSponsorInfo',
|
726 | format.address(address),
|
727 | format.epochNumber.$or(undefined)(epochNumber),
|
728 | );
|
729 | return format.sponsorInfo(result);
|
730 | }
|
731 |
|
732 | /**
|
733 | * Returns the size of the collateral storage of given address, in Byte.
|
734 | *
|
735 | * @param address {string} - Address to check for collateral storage.
|
736 | * @param [epochNumber='latest_state'] - See [format.sendTx](#util/format.js/epochNumber)
|
737 | * @return {Promise<JSBI>} - The collateral storage in Byte.
|
738 | *
|
739 | * @example
|
740 | * > await conflux.getCollateralForStorage('0xc94770007dda54cf92009bff0de90c06f603a09f')
|
741 | "158972490234375000"
|
742 | */
|
743 | async getCollateralForStorage(address, epochNumber) {
|
744 | const result = await this.provider.call('cfx_getCollateralForStorage',
|
745 | format.address(address),
|
746 | format.epochNumber.$or(undefined)(epochNumber),
|
747 | );
|
748 | return format.bigUInt(result);
|
749 | }
|
750 |
|
751 | /**
|
752 | * Virtually call a contract, return the output data.
|
753 | *
|
754 | * @param options {object} - See [format.sendTx](#util/format.js/sendTx)
|
755 | * @param [epochNumber='latest_state'] {string|number} - See [format.sendTx](#util/format.js/epochNumber)
|
756 | * @return {Promise<string>} The output data.
|
757 | */
|
758 | async call(options, epochNumber) {
|
759 | try {
|
760 | return await this.provider.call('cfx_call',
|
761 | format.callTx(options),
|
762 | format.epochNumber.$or(undefined)(epochNumber),
|
763 | );
|
764 | } catch (e) {
|
765 | throw decodeError(e);
|
766 | }
|
767 | }
|
768 |
|
769 | /**
|
770 | * Virtually call a contract, return the estimate gas used and storage collateralized.
|
771 | *
|
772 | * @param options {object} - See [format.estimateTx](#util/format.js/estimateTx)
|
773 | * @return {Promise<object>} A estimate result object:
|
774 | * - `BigInt` gasUsed: The gas used.
|
775 | * - `BigInt` storageCollateralized: The storage collateralized in Byte.
|
776 | */
|
777 | async estimateGasAndCollateral(options) {
|
778 | try {
|
779 | const result = await this.provider.call('cfx_estimateGasAndCollateral',
|
780 | format.estimateTx(options),
|
781 | );
|
782 | return format.estimate(result);
|
783 | } catch (e) {
|
784 | throw decodeError(e);
|
785 | }
|
786 | }
|
787 |
|
788 | /**
|
789 | * Returns logs matching the filter provided.
|
790 | *
|
791 | * @param [options] {object}
|
792 | * @param [options.fromEpoch='latest_checkpoint'] {string|number} - See [format.sendTx](#util/format.js/epochNumber). Search will be applied from this epoch number.
|
793 | * @param [options.toEpoch='latest_state'] {string|number} - See [format.sendTx](#util/format.js/epochNumber). Search will be applied up until (and including) this epoch number.
|
794 | * @param [options.blockHashes] {string[]} - Array of up to 128 block hashes that the search will be applied to. This will override from/to epoch fields if it's not null
|
795 | * @param [options.address] {string|string[]} - Search contract addresses. If null, match all. If specified, log must be produced by one of these addresses.
|
796 | * @param [options.topics] {array} - Search topics. Logs can have 4 topics: the function signature and up to 3 indexed event arguments. The elements of topics match the corresponding log topics. Example: ["0xA", null, ["0xB", "0xC"], null] matches logs with "0xA" as the 1st topic AND ("0xB" OR "0xC") as the 3rd topic. If null, match all.
|
797 | * @param [options.limit] {number} - Return the last limit logs
|
798 | * @return {Promise<object[]>} Array of log, that the logs matching the filter provided:
|
799 | * - address `string`: Address this event originated from.
|
800 | * - topics `string[]`: Array of topics.
|
801 | * - data `string`: The data containing non-indexed log parameter.
|
802 | * - blockHash `string`: Hash of the block where the log in.
|
803 | * - epochNumber `number`: Epoch number of the block where the log in.
|
804 | * - transactionHash `string`: Hash of the transaction where the log in.
|
805 | * - transactionIndex `string`: Transaction index in the block.
|
806 | * - logIndex `number`: Log index in block.
|
807 | * - transactionLogIndex `number`: Log index in transaction.
|
808 | *
|
809 | * @example
|
810 | * > await conflux.getLogs({
|
811 | address: '0x866aca87ff33a0ae05d2164b3d999a804f583222',
|
812 | fromEpoch: 0,
|
813 | toEpoch: 'latest_mined',
|
814 | limit: 1,
|
815 | topics: ['0x93baa6efbd2244243bfee6ce4cfdd1d04fc4c0e9a786abd3a41313bd352db153']
|
816 | });
|
817 | [
|
818 | {
|
819 | "address": "0x866aca87ff33a0ae05d2164b3d999a804f583222",
|
820 | "blockHash": "0x0ecbc75aca22cd1566a18c6a7a55f235ae12684c2749b40ac91262d6e8783b0b",
|
821 | "data": "0x",
|
822 | "epochNumber": 1504,
|
823 | "logIndex": 2,
|
824 | "topics": [
|
825 | "0x93baa6efbd2244243bfee6ce4cfdd1d04fc4c0e9a786abd3a41313bd352db153",
|
826 | "0x000000000000000000000000873c4bd4d847bcf7dc066bf4a7cd31dcf182258c",
|
827 | "0xb281fc8c12954d22544db45de3159a39272895b169a852b314f9cc762e44c53b",
|
828 | "0x000000000000000000000000873c4bd4d847bcf7dc066bf4a7cd31dcf182258c"
|
829 | ],
|
830 | "transactionHash": "0x2a696f7be50c364333bc145f082e79da3a6e730318b7f7822e3e1fe22e42560b",
|
831 | "transactionIndex": 0,
|
832 | "transactionLogIndex": 2
|
833 | }
|
834 | ]
|
835 | */
|
836 | async getLogs(options) {
|
837 | if (options.blockHashes !== undefined && (options.fromEpoch !== undefined || options.toEpoch !== undefined)) {
|
838 | throw new Error('OverrideError, do not use `blockHashes` with `fromEpoch` or `toEpoch`, cause only `blockHashes` will take effect');
|
839 | }
|
840 |
|
841 | const result = await this.provider.call('cfx_getLogs', format.getLogs(options));
|
842 |
|
843 | return format.logs(result);
|
844 | }
|
845 | }
|
846 |
|
847 | module.exports = Conflux;
|