UNPKG

35.3 kBJavaScriptView Raw
1const { assert, format, decorate } = require('./util');
2const providerFactory = require('./provider');
3const accountFactory = require('./account');
4const Contract = require('./contract');
5const Drip = require('./Drip');
6const decodeError = require('./contract/decodeError');
7const { PendingTransaction } = require('./subscribe');
8const internalContract = require('./contract/internal');
9
10/**
11 * A sdk of conflux.
12 */
13class 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
847module.exports = Conflux;