UNPKG

js-conflux-sdk

Version:
1,192 lines (1,123 loc) 60 kB
const CONST = require('./CONST'); const { assert } = require('./util'); const format = require('./util/format'); const cfxFormat = require('./rpc/types/formatter'); const providerFactory = require('./provider'); const Wallet = require('./wallet'); const Contract = require('./contract'); const INTERNAL_CONTRACTS = require('./contract/internal'); const { CRC20_ABI } = require('./contract/standard'); const PendingTransaction = require('./subscribe/PendingTransaction'); const Subscription = require('./subscribe/Subscription'); const pkg = require('../package.json'); const PoS = require('./rpc/pos'); const CFX = require('./rpc/cfx'); const Trace = require('./rpc/trace'); const TxPool = require('./rpc/txpool'); const BatchRequester = require('./rpc/BatchRequester'); const AdvancedRPCUtilities = require('./rpc/Advanced'); /** * @typedef {Object} ConfluxOption * @property {string|number} [options.defaultGasPrice] - The default gas price in drip to use for transactions. * @property {string} [options.url] - Url of Conflux node to connect. * @property {number} [options.retry] - Retry times if request error occurs. * @property {number} [options.timeout] - Request time out in ms * @property {Object} [options.logger] - Logger object with 'info' and 'error' method. * @property {number} [options.networkId] - Connected RPC's networkId * @property {boolean} [options.useWechatProvider] - Use wechat provider * @property {boolean} [options.useHexAddressInParameter] - Use hex address in parameter * @property {boolean} [options.useVerboseAddress] - Use verbose address */ /** * The Client class that provides an interface to the Conflux network. */ class Conflux { /** * Create a Conflux instance with networdId set up * @param {ConfluxOption} options * @return {Conflux} */ static async create(options) { const cfx = new Conflux(options); if (options.networkId) return cfx; await cfx.updateNetworkId(); return cfx; } /** * @param {ConfluxOption} [options] - Conflux and Provider constructor options. * @return {Conflux} * @example * > const { Conflux } = require('js-conflux-sdk'); * > const conflux = new Conflux({url:'https://test.confluxrpc.com', networkId: 1}); * * @example * > const conflux = new Conflux({ url: 'http://localhost:8000', defaultGasPrice: 100, logger: console, }); */ constructor({ defaultGasPrice, networkId, useHexAddressInParameter = false, useVerboseAddress = false, ...rest } = {}) { /** @type {string} */ this.version = pkg.version; /** * Provider for rpc call * * @type {import('./provider/BaseProvider').BaseProvider|import('./provider/WechatProvider').WechatProvider|import('./provider/HttpProvider').HttpProvider|import('./provider/WebsocketProvider').WebsocketProvider} */ this.provider = providerFactory(rest); /** * Wallet for `sendTransaction` to get `Account` by `from` field * * @type {import("./wallet/Wallet").Wallet} */ this.wallet = new Wallet(); /** * Default gas price for following methods: * - `Conflux.sendTransaction` * * @deprecated * @type {number|string} */ this.defaultGasPrice = defaultGasPrice; this.sendRawTransaction = this._decoratePendingTransaction(this.sendRawTransaction); this.sendTransaction = this._decoratePendingTransaction(this.sendTransaction); if (networkId) { this.networkId = networkId; this.wallet.setNetworkId(networkId); } this.useHexAddressInParameter = useHexAddressInParameter; this.useVerboseAddress = useVerboseAddress; /** * pos RPC methods * @type {import('./rpc/pos').PoS} */ this.pos = new PoS(this); /** * trace RPC methods * @type {import('./rpc/trace').Trace} */ this.trace = new Trace(this); /** * txpool RPC methods * @type {import('./rpc/txpool').TxPool} */ this.txpool = new TxPool(this); /** * cfx RPC methods * @type {import('./rpc/cfx').CFX} */ this.cfx = new CFX(this); /** * Advanced RPC compose methods * @type {import('./rpc/Advanced').AdvancedRPCUtilities} */ this.advanced = new AdvancedRPCUtilities(this); } /** * Different kind provider API wrapper */ request(req) { if (this.provider.request) { return this.provider.request(req); } if (this.provider.call) { return this.provider.call(req.method, ...req.params); } if (this.provider.send) { return this.provider.send(req.method, req.params); } throw new Error('Provider does not support request'); } /** * @private */ _decoratePendingTransaction(func) { const conflux = this; return function (...args) { return new PendingTransaction(conflux, func.bind(this), args); }; } /** * @private */ _formatAddress(address) { if (!this.networkId) { console.warn('Conflux address: networkId is not set properly, please set it'); } return this.useHexAddressInParameter ? format.hexAddress(address) : format.address(address, this.networkId, this.useVerboseAddress); } /** * @private */ _formatCallTx(options) { return cfxFormat.callTxAdvance(this.networkId, this.useHexAddressInParameter, this.useVerboseAddress)(options); } /** * @private */ _formatGetLogs(options) { return cfxFormat.getLogsAdvance(this.networkId, this.useHexAddressInParameter, this.useVerboseAddress)(options); } /** * A shout cut for `new Contract(options, conflux);` * * @param {object} options - See [Contract.constructor](Contract.md#Contract.js/constructor) * @return {import('./contract/index').Contract} */ Contract(options) { return new Contract(options, this); } /** * Create internal contract by default abi and address * * - [AdminControl](https://github.com/Conflux-Chain/conflux-rust/blob/master/internal_contract/contracts/AdminControl.sol) * - [SponsorWhitelistControl](https://github.com/Conflux-Chain/conflux-rust/blob/master/internal_contract/contracts/SponsorWhitelistControl.sol) * - [Staking](https://github.com/Conflux-Chain/conflux-rust/blob/master/internal_contract/contracts/Staking.sol) * * @param {"AdminControl"|"SponsorWhitelistControl"|"Staking"|"PoSRegister"|"CrossSpaceCall"} name - Internal contract name * @return {import('./contract/index').Contract} * * @example * > conflux.InternalContract('AdminControl') { constructor: [Function: bound call], abi: ContractABI { * }, address: '0x0888000000000000000000000000000000000000', destroy: [Function: bound call], getAdmin: [Function: bound call], setAdmin: [Function: bound call], 'destroy(address)': [Function: bound call], '0x00f55d9d': [Function: bound call], 'getAdmin(address)': [Function: bound call], '0x64efb22b': [Function: bound call], 'setAdmin(address,address)': [Function: bound call], '0xc55b6bb7': [Function: bound call] } */ InternalContract(name) { const options = INTERNAL_CONTRACTS[name]; assert(options, `can not find internal contract named "${name}"`); return this.Contract(options); } /** * Create an token CRC20 contract with standard CRC20 abi * * @param {string} address * @returns {import('./contract/index').Contract} A token contract instance */ CRC20(address) { return this.Contract({ address, abi: CRC20_ABI }); } /** * Return a BatchRequester instance which can used to build batch request and decode response data * @returns {import('./rpc/BatchRequester').BatchRequester} - A BatchRequester instance */ BatchRequest() { return new BatchRequester(this); } /** * close connection. * * @example * > conflux.close(); */ close() { this.provider.close(); } // -------------------------------------------------------------------------- /** * Update conflux networkId from RPC */ async updateNetworkId() { const { networkId } = await this.getStatus(); this.networkId = networkId; this.wallet.setNetworkId(this.networkId); } /** * Get node client version * @return {Promise<string>} */ async getClientVersion() { return this.cfx.clientVersion(); } /** * Get supply info * * @param {string|number} [epochNumber='latest_state'] - See [format.epochNumber](utils.md#util/format.js/format/(static)epochNumber) * @return {Promise<import('./rpc/types/formatter').SupplyInfo>} Return supply info * - totalIssued `BigInt`: Total issued balance in `Drip` * - totalStaking `BigInt`: Total staking balance in `Drip` * - totalCollateral `BigInt`: Total collateral balance in `Drip` * * @example * > await conflux.getSupplyInfo() { totalCirculating: 28953062500000000000000n, totalCollateral: 28953062500000000000000n, totalIssued: 5033319899279074765657343554n, totalStaking: 25026010834970490328077641n } */ async getSupplyInfo(epochNumber) { return this.cfx.getSupplyInfo(epochNumber); } /** * Get status * @return {Promise<import('./rpc/types/formatter').ChainStatus>} Status information object * - chainId `number`: Chain id * - epochNumber `number`: Epoch number * - blockNumber `number`: Block number * - pendingTxNumber `number`: Pending transaction number * - bestHash `string`: The block hash of best pivot block * * @example * > await conflux.getStatus() { chainId: 1029, networkId: 1029, epochNumber: 1117476, blockNumber: 2230973, pendingTxNumber: 4531, bestHash: '0x8d581f13fa0548f2751450a7dabd871777875c9ccdf0d8bd629e07a7a5a7917a' } */ async getStatus() { return this.cfx.getStatus(); } /** * Returns the current price per gas in Drip. * * @return {Promise<BigInt>} Gas price in drip. * * @example * > await conflux.getGasPrice(); 1n */ async getGasPrice() { return this.cfx.gasPrice(); } /** * Returns the interest rate of given parameter. * * @param {string|number} [epochNumber='latest_state'] - See [format.epochNumber](utils.md#util/format.js/format/(static)epochNumber) * @return {Promise<BigInt>} The interest rate of given parameter. * * @example * > await conflux.getInterestRate(); 2522880000000n */ async getInterestRate(epochNumber) { return this.cfx.getInterestRate(epochNumber); } /** * Returns the accumulate interest rate of given parameter. * * @param {string|number} [epochNumber='latest_state'] - See [format.epochNumber](utils.md#util/format.js/format/(static)epochNumber) * @return {Promise<BigInt>} The accumulate interest rate of given parameter. * * @example * > await conflux.getAccumulateInterestRate() 76357297457647044505744908994993n */ async getAccumulateInterestRate(epochNumber) { return this.cfx.getAccumulateInterestRate(epochNumber); } // ------------------------------- address ---------------------------------- /** * Return account related states of the given account * * @param {string} address - address to get account. * @param {string|number} [epochNumber='latest_state'] - See [format.epochNumber](utils.md#util/format.js/format/(static)epochNumber) * @return {Promise<import('./rpc/types/Account').Account>} Return the states of the given account: * - balance `BigInt`: the balance of the account. * - nonce `BigInt`: the nonce of the account's next transaction. * - codeHash `string`: the code hash of the account. * - stakingBalance `BigInt`: the staking balance of the account. * - collateralForStorage `BigInt`: the collateral storage of the account. * - accumulatedInterestReturn `BigInt`: accumulated unterest return of the account. * - admin `string`: admin of the account. * * @example > await conflux.getAccount('cfxtest:aasb661u2r60uzn5h0c4h63hj76wtgf552r9ghu7a4'); { accumulatedInterestReturn: 0n, balance: 824812401057514588670n, collateralForStorage: 174187500000000000000n, nonce: 1449n, stakingBalance: 0n, admin: 'CFXTEST:TYPE.NULL:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6F0VRCSW', codeHash: '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470' } */ async getAccount(address, epochNumber) { return this.cfx.getAccount(address, epochNumber); } /** * Returns the balance of the account of given address. * * @param {string} address - The address to get the balance of. * @param {string|number} [epochNumber='latest_state'] - See [format.epochNumber](utils.md#util/format.js/format/(static)epochNumber) * @return {Promise<BigInt>} The balance in Drip. * * @example * > await conflux.getBalance("cfxtest:aasb661u2r60uzn5h0c4h63hj76wtgf552r9ghu7a4"); 824812401057514588670n */ async getBalance(address, epochNumber) { return this.cfx.getBalance(address, epochNumber); } /** * Returns the balance of the staking account of given address. * * @param {string} address - Address to check for staking balance. * @param {string|number} [epochNumber='latest_state'] - See [format.epochNumber](utils.md#util/format.js/format/(static)epochNumber) * @return {Promise<BigInt>} The staking balance in Drip. * * @example * > await conflux.getStakingBalance('cfxtest:aasb661u2r60uzn5h0c4h63hj76wtgf552r9ghu7a4', 'latest_state'); 0n */ async getStakingBalance(address, epochNumber) { return this.cfx.getStakingBalance(address, epochNumber); } /** * Returns the next nonce should be used by given address. * * @param {string} address - The address to get the numbers of transactions from. * @param {string|number} [epochNumber] - See [format.epochNumber](utils.md#util/format.js/format/(static)epochNumber) * @return {Promise<BigInt>} The next nonce should be used by given address. * * @example * > await conflux.getNextNonce("cfxtest:aasb661u2r60uzn5h0c4h63hj76wtgf552r9ghu7a4"); 1449n */ async getNextNonce(address, epochNumber) { return this.cfx.getNextNonce(address, epochNumber); } /** * Returns the admin of given contract. * * @param {string} address - Address to contract. * @param {string|number} [epochNumber='latest_state'] - See [format.epochNumber](utils.md#util/format.js/format/(static)epochNumber) * @return {Promise<string>} Address to admin, or `null` if the contract does not exist. * * @example * > conflux.getAdmin('cfxtest:achc8nxj7r451c223m18w2dwjnmhkd6rxa2gc31euw') "CFXTEST:TYPE.USER:AASB661U2R60UZN5H0C4H63HJ76WTGF552R9GHU7A4" */ async getAdmin(address, epochNumber) { return this.cfx.getAdmin(address, epochNumber); } /** * Returns vote list of the given account. * * @param {string} address - Address to contract. * @param {string|number} [epochNumber='latest_state'] - See [format.epochNumber](utils.md#util/format.js/format/(static)epochNumber) * @return {Promise<import('./rpc/types/formatter').Vote[]>} Vote list * - `array`: * - amount `BigInt`: This is the number of tokens should be locked before * - unlockBlockNumber `number`: This is the timestamp when the vote right will be invalid, measured in, the number of past blocks. */ async getVoteList(address, epochNumber) { return this.cfx.getVoteList(address, epochNumber); } /** * Returns deposit list of the given account. * @param {string} address - Address to contract. * @param {string|number} [epochNumber='latest_state'] - See [format.epochNumber](utils.md#util/format.js/format/(static)epochNumber) * @return {Promise<import('./rpc/types/formatter').Deposit[]>} Deposit list * - `array`: * - amount `BigInt`: the number of tokens deposited * - accumulatedInterestRate: `BigInt`: the accumulated interest rate at the time of the deposit * - depositTime `number`: the time of the deposit */ async getDepositList(address, epochNumber) { return this.cfx.getDepositList(address, epochNumber); } // -------------------------------- epoch ----------------------------------- /** * Returns the epoch number of given parameter. * * @param {string|number} [epochNumber='latest_state'] - See [format.epochNumber](utils.md#util/format.js/format/(static)epochNumber) * @return {Promise<number>} integer of the current epoch number of given parameter. * * @example * > await conflux.getEpochNumber(); 443 */ async getEpochNumber(epochNumber) { return this.cfx.epochNumber(epochNumber); } /** * Returns information about a block by epoch number. * * @param {string|number} epochNumber - See [format.epochNumber](utils.md#util/format.js/format/(static)epochNumber) * @param {boolean} [detail=false] - If `true` it returns the full transaction objects, if `false` only the hashes of the transactions. * @return {Promise<import('./rpc/types/formatter').Block|null>} See `getBlockByHash` * * @example * > await conflux.getBlockByEpochNumber('latest_mined', true); {...} */ async getBlockByEpochNumber(epochNumber, detail = false) { return this.cfx.getBlockByEpochNumber(epochNumber, detail); } /** * Returns information about a block by block number. * * @param {string|number} blockNumber * @param {boolean} [detail=false] - If `true` it returns the full transaction objects, if `false` only the hashes of the transactions. * @return {Promise<import('./rpc/types/formatter').Block|null>} See `getBlockByHash` * * @example * > await conflux.getBlockByBlockNumber('0x123', true); {...} */ async getBlockByBlockNumber(blockNumber, detail = false) { return this.cfx.getBlockByBlockNumber(blockNumber, detail); } /** * Returns hashes of blocks located in some epoch. * * @param {string|number} epochNumber - See [format.epochNumber](utils.md#util/format.js/format/(static)epochNumber) * @return {Promise<string[]>} Array of block hashes, sorted by execution(topological) order. * * @example * > await conflux.getBlocksByEpochNumber(0); ['0xe677ae5206a5d67d9efa183d867b4b986ed82a3e62174a1488cf8364d58534ec'] */ async getBlocksByEpochNumber(epochNumber) { return this.cfx.getBlocksByEpoch(epochNumber); } /** * Get epoch blocks reward info * * @param {string|number} epochNumber - See [format.epochNumber](utils.md#util/format.js/format/(static)epochNumber) * @return {Promise<import('./rpc/types/formatter').RewardInfo[]>} List of block reward info * - blockHash `string`: Hash of the block. * - author `string`: The address of the beneficiary to whom the mining rewards were given. * - baseReward `BigInt`: Block base reward in `Drip` * - totalReward `BigInt`: Block total reward in `Drip` * - txFee `BigInt`: Total gas fee of block transaction * * @example * > await conflux.getBlockRewardInfo(6); [ { baseReward: 6993700000000000000n, totalReward: 6993700031741486703n, txFee: 0n, author: 'CFXTEST:TYPE.USER:AATXETSP0KDARPDB5STDYEX11DR3X6SB0J2XZETSG6', blockHash: '0x73cd891aea310e2c0b8644de91746c7353cebfffb780126bc06101b20689c893' }, { baseReward: 6997200000000000000n, totalReward: 6997200031760371742n, txFee: 3000000n, author: 'CFXTEST:TYPE.USER:AATXETSP0KDARPDB5STDYEX11DR3X6SB0J2XZETSG6', blockHash: '0xaf4136d04e9e2cc470703251ec46f5913ab7955d526feed43771705e89c77390' } ] */ async getBlockRewardInfo(epochNumber) { return this.cfx.getBlockRewardInfo(epochNumber); } // -------------------------------- block ----------------------------------- /** * Returns the hash of best block. * * @return {Promise<string>} hash of the best block. * * @example * > await conflux.getBestBlockHash(); "0xb8bb355bfeaf055a032d5b7df719917c090ee4fb6fee42383004dfe8911d7daf" */ async getBestBlockHash() { return this.cfx.getBestBlockHash(); } /** * Returns information about a block by hash. * * @param {string} blockHash - hash of a block. * @param {boolean} [detail=false] - If `true` it returns the full transaction objects, if `false` only the hashes of the transactions. * @return {Promise<import('./rpc/types/formatter').Block|null>} A block object, or null when no block was found: * - adaptive `boolean`: If `true` the weight of the block is adaptive under GHAST rule, if `false` otherwise. * - 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. * - deferredLogsBloomHash `string`: The bloom hash of deferred logs. * - deferredReceiptsRoot `string`: The hash of the receipts of the block after deferred execution. * - deferredStateRoot `string`: The root of the final state trie of the block after deferred execution. * - difficulty `string`: Integer string of the difficulty for this block. * - 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. * - gasLimit `BigInt`: The maximum gas allowed in this block. * - hash `string|null`: Hash of the block. `null` when its pending block. * - height `number`: The block heights. `null` when its pending block. * - miner `string`: The address of the beneficiary to whom the mining rewards were given. * - nonce `string`: Hash of the generated proof-of-work. `null` when its pending block. * - parentHash `string`: Hash of the parent block. * - powQuality `string`:Hash of the generated proof-of-work. `null` when its pending block. * - refereeHashes `string[]`: Array of referee hashes. * - size `number`: Integer the size of this block in bytes. * - timestamp `number`: The unix timestamp for when the block was collated. * - transactions `string[]|object[]`: Array of transaction objects, or 32 Bytes transaction hashes depending on the last given parameter. * - transactionsRoot `string`: The hash of the transactions of the block. * * @example * > await conflux.getBlockByHash('0xaf4136d04e9e2cc470703251ec46f5913ab7955d526feed43771705e89c77390'); { epochNumber: 6, blame: 0, height: 6, size: 352, timestamp: 1603901780, gasLimit: 30000000n, gasUsed: 61118n, difficulty: 20000000000n, transactions: [ '0xaad69c8c814aec3e418b68f60917c607920a531e7082dd2c642323b43ecadb94', '0xbf7110474779ba2404433ef39a24cb5b277186ef1e6cb199b0b60907b029a1ce' ], adaptive: false, deferredLogsBloomHash: '0xd397b3b043d87fcd6fad1291ff0bfd16401c274896d8c63a923727f077b8e0b5', deferredReceiptsRoot: '0x09f8709ea9f344a810811a373b30861568f5686e649d6177fd92ea2db7477508', deferredStateRoot: '0x50c0fcbc5bafa7d1dba7b19c87629830106a6be8d0adf505cdc656bb43535d69', hash: '0xaf4136d04e9e2cc470703251ec46f5913ab7955d526feed43771705e89c77390', miner: 'CFXTEST:TYPE.USER:AATXETSP0KDARPDB5STDYEX11DR3X6SB0J2XZETSG6', nonce: '0x17d86f2f6', parentHash: '0xc8a412b4b77b48d61f694975f032d109f26bb0f9fc02e4b221d67a382fab386b', powQuality: '0x5a0f86a6f4', refereeHashes: [ '0x73cd891aea310e2c0b8644de91746c7353cebfffb780126bc06101b20689c893' ], transactionsRoot: '0xd2f08676484ba2a3738194f44542eb29fb290b8ed74bf007f132fe51d89b2e7c' } */ async getBlockByHash(blockHash, detail = false) { return this.cfx.getBlockByHash(blockHash, detail); } /** * Get block by `blockHash` if pivot block of `epochNumber` is `pivotBlockHash`. * * @param {string} blockHash - Block hash which epochNumber expect to be `epochNumber`. * @param {string} pivotBlockHash - Block hash which expect to be the pivot block of `epochNumber`. * @param {number} epochNumber - Epoch number * @return {Promise<import('./rpc/types/formatter').Block|null>} See `getBlockByHash` */ async getBlockByHashWithPivotAssumption(blockHash, pivotBlockHash, epochNumber) { return this.cfx.getBlockByHashWithPivotAssumption(blockHash, pivotBlockHash, epochNumber); } /** * Get the risk of the block could be reverted. * All block in one same epoch returned same risk number * * @param {string} blockHash - Hash of a block * @return {Promise<number|null>} Number >0 and <1 * * @example * > await conflux.getConfirmationRiskByHash('0xaf4136d04e9e2cc470703251ec46f5913ab7955d526feed43771705e89c77390') 1e-8 */ async getConfirmationRiskByHash(blockHash) { return this.cfx.getConfirmationRiskByHash(blockHash); } // ----------------------------- transaction -------------------------------- /** * Returns the information about a transaction requested by transaction hash. * * @param {string} transactionHash - hash of a transaction * @return {Promise<import('./rpc/types/formatter').Transaction|null>} transaction object, or `null` when no transaction was found: * - blockHash `string`: hash of the block where this transaction was in and got executed. `null` when its pending. * - contractCreated `string|null`: address of created contract. `null` when it's not a contract creating transaction * - data `string`: the data send along with the transaction. * - epochHeight `number`: epoch height * - from `string`: address of the sender. * - gas `BigInt`: gas provided by the sender. * - gasPrice `number`: gas price provided by the sender in Drip. * - hash `string`: hash of the transaction. * - nonce `BigInt`: the number of transactions made by the sender prior to this one. * - r `string`: ECDSA signature r * - s `string`: ECDSA signature s * - status `number`: 0 for success, 1 for error occured, `null` when the transaction is skipped or not packed. * - storageLimit `BigInt`: storage limit in bytes * - chainId `number`: chain id * - to `string`: address of the receiver. null when its a contract creation transaction. * - transactionIndex `number`: integer of the transactions's index position in the block. `null` when its pending. * - v `string`: ECDSA recovery id * - value `BigInt`: value transferred in Drip. * * @example * > await conflux.getTransactionByHash('0xbf7110474779ba2404433ef39a24cb5b277186ef1e6cb199b0b60907b029a1ce'); { nonce: 0n, gasPrice: 10n, gas: 200000n, value: 0n, storageLimit: 1024n, epochHeight: 0, chainId: 1029, v: 1, status: 0, transactionIndex: 1, blockHash: '0xaf4136d04e9e2cc470703251ec46f5913ab7955d526feed43771705e89c77390', contractCreated: null, data: '0xfebe49090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000162788589c8e386863f217faef78840919fb2854', from: 'CFXTEST:TYPE.USER:AATXETSP0KDARPDB5STDYEX11DR3X6SB0J2XZETSG6', hash: '0xbf7110474779ba2404433ef39a24cb5b277186ef1e6cb199b0b60907b029a1ce', r: '0x495da01ae9f445847022a8bc7df0198577ba75f88b26699f61afb435bb9c50bc', s: '0x2291051b1c53db1d6bfe2fb29be1bf512d063e726dc6b98aaf0f2259b7456be0', to: 'CFXTEST:TYPE.USER:AATXETSP0KDARPDB5STDYEX11DR3X6SB0J2XZETSG6' } */ async getTransactionByHash(transactionHash) { return this.cfx.getTransactionByHash(transactionHash); } /** * Returns the information about a transaction receipt requested by transaction hash. * * @param {string} transactionHash - Hash of a transaction * @return {Promise<import('./rpc/types/formatter').TransactionReceipt|null>} A transaction receipt object, or null when no transaction was found or the transaction was not executed yet: * - transactionHash `string`: Hash of the given transaction. * - index `number`: Transaction index within the block. * - blockHash `string`: Hash of the block where this transaction was in and got executed. * - epochNumber `number`: Epoch number of the block where this transaction was in and got executed. * - from `string`: Address of the sender. * - to `string`: Address of the receiver. `null` when its a contract creation transaction. * - gasUsed `number`: Gas used the transaction. * - contractCreated `string|null`: Address of created contract. `null` when it's not a contract creating transaction. * - stateRoot `string`: Hash of the state root. * - outcomeStatus `number`: the outcome status code, 0 was successful, 1 for an error occurred in the execution. * - logsBloom `string`: Bloom filter for light clients to quickly retrieve related logs. * - logs `object[]`: Array of log objects, which this transaction generated. * - gasCoveredBySponsor `boolean`: `true` if this transaction's gas fee was covered by the sponsor. * - storageCoveredBySponsor `boolean`: `true` if this transaction's storage collateral was covered by the sponsor. * - storageCollateralized `BigInt`: the amount of storage collateral this transaction required. * - storageReleased `array`: array of storage change objects, each specifying an address and the corresponding amount of storage collateral released * - address `string`: address released * - collaterals `BigInt`: corresponding amount of storage collateral released * * @example * > await conflux.getTransactionReceipt('0xbf7110474779ba2404433ef39a24cb5b277186ef1e6cb199b0b60907b029a1ce'); { index: 1, epochNumber: 6, outcomeStatus: 0, gasUsed: 30559n, gasFee: 1500000n, blockHash: '0xaf4136d04e9e2cc470703251ec46f5913ab7955d526feed43771705e89c77390', contractCreated: null, from: 'CFXTEST:TYPE.USER:AAJJ1C2XGRKDY8RPG2828UPAN4A5BBSZNYB28K0PHS', logs: [], logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', stateRoot: '0xd6a7c2c14cb0d1233010acca98e114db5a10e0b94803d23b01a6777b7fd3b2fd', to: 'CFXTEST:TYPE.CONTRACT:ACB59FK6VRYH8DJ5VYVEHJ9APZHPD72RDP2FVP77R9', transactionHash: '0xbf7110474779ba2404433ef39a24cb5b277186ef1e6cb199b0b60907b029a1ce', txExecErrorMsg: null, gasCoveredBySponsor: false, storageCoveredBySponsor: false, storageCollateralized: 0n, storageReleased: [ address: '0x0000000000000000000000000000000000000001', collaterals: 640n, ], } */ async getTransactionReceipt(transactionHash) { return this.cfx.getTransactionReceipt(transactionHash); } /** * Creates new message call transaction or a contract creation for signed transactions. * * @param {string|Buffer} hex - The signed transaction data. * @return {Promise<import('./subscribe/PendingTransaction').PendingTransaction>} The transaction hash, or the zero hash if the transaction is not yet available. * * @example * > await conflux.sendRawTransaction('0xf85f800382520894bbd9e9b...'); "0xbe007c3eca92d01f3917f33ae983f40681182cf618defe75f490a65aac016914" */ async sendRawTransaction(hex) { return this.request({ method: 'cfx_sendRawTransaction', params: [format.hex(hex)], }); } /** * @typedef { import('../Transaction').TransactionMeta } TransactionMeta */ /** * Sign and send transaction * if `from` field in `conflux.wallet`, sign by local account and send raw transaction, * else call `cfx_sendTransaction` and sign by remote wallet * * @param {TransactionMeta} options - See [Transaction](Transaction.md#Transaction.js/Transaction/**constructor**) * @param {string} [password] - Password for remote node. * @return {Promise<import('./subscribe/PendingTransaction').PendingTransaction>} The PendingTransaction object. * * @example * > txHash = await conflux.sendTransaction({from:account, to:address, value:0}); // send and get transaction hash "0xb2ba6cca35f0af99a9601d09ee19c1949d8130312550e3f5413c520c6d828f88" * @example * > packedTx = await conflux.sendTransaction({from:account, to:address, value:0}).get(); // await till transaction packed { "nonce": 8n, "value": 0n, "gasPrice": 1000000000n, "gas": 21000n, "v": 0, "transactionIndex": null, "status": null, "storageLimit": 0n, "chainId": 1, "epochHeight": 791394, "blockHash": null, "contractCreated": null, "data": "0x", "from": "CFXTEST:TYPE.USER:AAR7X4R8MKRNW39GGS8RZ40J1ZNWH5MRRPUFPR2U76", "hash": "0xb2ba6cca35f0af99a9601d09ee19c1949d8130312550e3f5413c520c6d828f88", "r": "0x245a1a86ae405eb72c1eaf98f5e22baa326fcf8262abad2c4a3e5bdcf2e912b5", "s": "0x4df8058887a4dd8aaf60208accb3e57292a50ff06a117df6e54f7f56176248c0", "to": "CFXTEST:TYPE.USER:AAR7X4R8MKRNW39GGS8RZ40J1ZNWH5MRRPUFPR2U76" } * @example * > minedTx = await conflux.sendTransaction({from:account, to:address, value:0}).mined(); // await till transaction mined { "nonce": 8n, "value": 0n, "gasPrice": 1000000000n, "gas": 21000n, "v": 0, "transactionIndex": 0, "status": 0, "storageLimit": 0n, "chainId": 1, "epochHeight": 791394, "blockHash": "0xdb2d2d438dcdee8d61c6f495bd363b1afb68cb0fdff16582c08450a9ca487852", "contractCreated": null, "data": "0x", "from": "CFXTEST:TYPE.USER:AAR7X4R8MKRNW39GGS8RZ40J1ZNWH5MRRPUFPR2U76", "hash": "0xb2ba6cca35f0af99a9601d09ee19c1949d8130312550e3f5413c520c6d828f88", "r": "0x245a1a86ae405eb72c1eaf98f5e22baa326fcf8262abad2c4a3e5bdcf2e912b5", "s": "0x4df8058887a4dd8aaf60208accb3e57292a50ff06a117df6e54f7f56176248c0", "to": "CFXTEST:TYPE.USER:AAR7X4R8MKRNW39GGS8RZ40J1ZNWH5MRRPUFPR2U76" } * @example * > executedReceipt = await conflux.sendTransaction({from:account, to:address, value:0}).executed(); // await till transaction executed { "index": 0, "epochNumber": 791402, "outcomeStatus": 0, "gasUsed": 21000n, "gasFee": 21000000000000n, "blockHash": "0xdb2d2d438dcdee8d61c6f495bd363b1afb68cb0fdff16582c08450a9ca487852", "contractCreated": null, "from": "CFXTEST:TYPE.USER:AAR7X4R8MKRNW39GGS8RZ40J1ZNWH5MRRPUFPR2U76", "logs": [], "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "stateRoot": "0x510d680cdbf60d34bcd987b3bf9925449c0839a7381dc8fd8222d2c7ee96122d", "to": "CFXTEST:TYPE.USER:AAR7X4R8MKRNW39GGS8RZ40J1ZNWH5MRRPUFPR2U76", "transactionHash": "0xb2ba6cca35f0af99a9601d09ee19c1949d8130312550e3f5413c520c6d828f88" } * @example * > confirmedReceipt = await conflux.sendTransaction({from:account, to:address, value:0}).confirmed(); // await till risk coefficient < threshold (default 1e-8) { "index": 0, "epochNumber": 791402, "outcomeStatus": 0, "gasUsed": 21000n, "gasFee": 21000000000000n, "blockHash": "0xdb2d2d438dcdee8d61c6f495bd363b1afb68cb0fdff16582c08450a9ca487852", "contractCreated": null, "from": "CFXTEST:TYPE.USER:AAR7X4R8MKRNW39GGS8RZ40J1ZNWH5MRRPUFPR2U76", "logs": [], "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "stateRoot": "0x510d680cdbf60d34bcd987b3bf9925449c0839a7381dc8fd8222d2c7ee96122d", "to": "CFXTEST:TYPE.USER:AAR7X4R8MKRNW39GGS8RZ40J1ZNWH5MRRPUFPR2U76", "transactionHash": "0xb2ba6cca35f0af99a9601d09ee19c1949d8130312550e3f5413c520c6d828f88" } */ async sendTransaction(options, password) { if (this.wallet.has(`${options.from}`)) { const rawTx = await this.cfx.populateAndSignTransaction(options); return this.sendRawTransaction(rawTx); } const params = [this._formatCallTx(options)]; if (password) params.push(password); return this.request({ method: 'cfx_sendTransaction', params, }); } // ------------------------------ contract ---------------------------------- /** * Returns the code of given contract. * * @param {string} address - Address to contract. * @param {string|number} [epochNumber='latest_state'] - See [format.epochNumber](utils.md#util/format.js/format/(static)epochNumber) * @return {Promise<string>} Byte code of contract, or 0x if the contract does not exist. * * @example * > await conflux.getCode('cfxtest:acb2nsctbanb9ezbw0mx1gapve60thyurjmxkage0f'); "0x6080604052348015600f57600080fd5b506004361060325760003560e01c806306661abd1460375780638..." */ async getCode(address, epochNumber) { return this.cfx.getCode(address, epochNumber); } /** * Returns storage entries from a given contract. * * @param {string} address - Address to contract. * @param {string} position - The given position. * @param {string|number} [epochNumber='latest_state'] - See [format.epochNumber](utils.md#util/format.js/format/(static)epochNumber) * @return {Promise<string|null>} Storage entry of given query, or null if the it does not exist. * * @example * > await conflux.getStorageAt('cfxtest:acdgzwyh9634bnuf4jne0tp3xmae80bwej1w4hr66c', '0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9') "0x000000000000000000000000000000000000000000000000000000000000162e" */ async getStorageAt(address, position, epochNumber) { return this.cfx.getStorageAt(address, position, epochNumber); } /** * Returns the storage root of a given contract. * * @param {string} address - Address to contract. * @param {string|number} [epochNumber='latest_state'] - See [format.epochNumber](utils.md#util/format.js/format/(static)epochNumber) * @return {Promise<object>} A storage root object, or `null` if the contract does not exist * - delta `string`: storage root in the delta trie. * - intermediate `string`: storage root in the intermediate trie. * - snapshot `string`: storage root in the snapshot. * * @example * > await conflux.getStorageRoot('cfxtest:acdgzwyh9634bnuf4jne0tp3xmae80bwej1w4hr66c') { "delta": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "intermediate": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "snapshot": "0x7bb7d43152e56f529fbef709aab7371b0672f2332ae0fb4786da350f664df5b4" } */ async getStorageRoot(address, epochNumber) { return this.cfx.getStorageRoot(address, epochNumber); } /** * Returns the sponsor info of given contract. * * @param {string} address - Address to contract. * @param {string|number} [epochNumber='latest_state'] - See [format.epochNumber](utils.md#util/format.js/format/(static)epochNumber) * @return {Promise<import('./rpc/types/formatter').SponsorInfo>} A sponsor info object, if the contract doesn't have a sponsor, then the all fields in returned object will be 0: * - sponsorBalanceForCollateral `BigInt`: the sponsored balance for storage. * - sponsorBalanceForGas `BigInt`: the sponsored balance for gas. * - sponsorGasBound `BigInt`: the max gas could be sponsored for one transaction. * - sponsorForCollateral `string`: the address of the storage sponsor. * - sponsorForGas `string`: the address of the gas sponsor. * * @example * > await conflux.getSponsorInfo('cfxtest:achc8nxj7r451c223m18w2dwjnmhkd6rxa2gc31euw') { sponsorBalanceForCollateral: 410625000000000000000n, sponsorBalanceForGas: 9999999993626232440n, sponsorGasBound: 10000000000n, sponsorForCollateral: 'CFXTEST:TYPE.CONTRACT:ACGZZ08M8Z2YWKEDA0JZU52FGAZ9U95Y1YV785YANX', sponsorForGas: 'CFXTEST:TYPE.CONTRACT:ACGZZ08M8Z2YWKEDA0JZU52FGAZ9U95Y1YV785YANX' } */ async getSponsorInfo(address, epochNumber) { return this.cfx.getSponsorInfo(address, epochNumber); } /** * Return pending info of an account * * @param {string} address - Address to account * @returns {Promise<import('./rpc/types/formatter').AccountPendingInfo>} An account pending info object. * - localNonce `BigInt`: then next nonce can use in the transaction pool * - nextPendingTx `string`: the hash of next pending transaction * - pendingCount `BigInt`: the count of pending transactions * - pendingNonce `BigInt`: the nonce of pending transaction * */ async getAccountPendingInfo(address) { return this.cfx.getAccountPendingInfo(address); } /** * Return pending transactions of one account * * @param {string} address - base32 address * @returns {Promise<import('./rpc/types/formatter').AccountPendingTransactions>} An account's pending transactions and info. * - pendingTransactions `Array`: pending transactions * - firstTxStatus `Object`: the status of first pending tx * - pendingCount `BigInt`: the count of pending transactions */ async getAccountPendingTransactions(address, startNonce, limit) { return this.cfx.getAccountPendingTransactions(address, startNonce, limit); } /** * Returns the size of the collateral storage of given address, in Byte. * * @param {string} address - Address to check for collateral storage. * @param [epochNumber='latest_state'] - See [format.epochNumber](utils.md#util/format.js/format/(static)epochNumber) * @return {Promise<BigInt>} - The collateral storage in Byte. * * @example * > await conflux.getCollateralForStorage('cfxtest:achc8nxj7r451c223m18w2dwjnmhkd6rxa2gc31euw') 89375000000000000000n */ async getCollateralForStorage(address, epochNumber) { return this.cfx.getCollateralForStorage(address, epochNumber); } /** * Virtually call a contract, return the output data. * * @param {TransactionMeta} options - See [Transaction](Transaction.md#Transaction.js/Transaction/**constructor**) * @param {string|number} [epochNumber='latest_state'] - See [format.epochNumber](utils.md#util/format.js/format/(static)epochNumber) * @return {Promise<string>} The output data. */ async call(options, epochNumber) { try { return await this.request({ method: 'cfx_call', params: [ this._formatCallTx(options), format.epochNumber.$or(undefined)(epochNumber), ], }); } catch (e) { throw Contract.decodeError(e); } } /** * Virtually call a contract, return the estimate gas used and storage collateralized. * * @param {TransactionMeta} options - See [Transaction](Transaction.md#Transaction.js/Transaction/**constructor**) * @param {string|number} [epochNumber='latest_state'] - See [format.epochNumber](utils.md#util/format.js/format/(static)epochNumber) * @return {Promise<import('./rpc/types/formatter').EstimateResult>} A estimate result object: * - `BigInt` gasUsed: The gas used. * - `BigInt` gasLimit: The gas limit. * - `BigInt` storageCollateralized: The storage collateralized in Byte. */ async estimateGasAndCollateral(options, epochNumber) { try { const result = await this.request({ method: 'cfx_estimateGasAndCollateral', params: [ this._formatCallTx(options), format.epochNumber.$or(undefined)(epochNumber), ], }); return cfxFormat.estimate(result); } catch (e) { throw Contract.decodeError(e); } } /** * Estimate a transaction's gas and storageCollateralize, check whether user's balance is enough for fee and value * @param {TransactionMeta} options - See [estimateGasAndCollateral](#Conflux.js/Conflux/estimateGasAndCollateral) * @param {string|number} [epochNumber='latest_state'] - See [estimateGasAndCollateral](#Conflux.js/Conflux/estimateGasAndCollateral) * @return {Promise<object>} A estimate result with advance info object: * - `BigInt` gasUsed: The gas used. * - `BigInt` gasLimit: The gas limit. * - `BigInt` storageCollateralized: The storage collateralized in Byte. * - `BigInt` balance: The balance of the options.from. * - `Boolean` isBalanceEnough: indicate balance is enough for gas and storage fee * - `Boolean` isBalanceEnoughForValueAndFee: indicate balance is enough for gas and storage fee plus value * - `Boolean` willPayCollateral: false if the transaction is eligible for storage collateral sponsorship, true otherwise * - `Boolean` willPayTxFee: false if the transaction is eligible for gas sponsorship, true otherwise */ async estimateGasAndCollateralAdvance(options, epochNumber) { return this.cfx.estimateGasAndCollateralAdvance(options, epochNumber); } /** * Check whether transaction sender's balance is enough for gas and storage fee * @param {string} from - sender address * @param {string} to - target address * @param {string|number} gas - gas limit (in drip) * @param {string|number} gasPrice - gas price (in drip) * @param {string|number} storageLimit - storage limit (in byte) * @param {string|number} [epochNumber] - optional epoch number * @return {Promise<object>} A check result object: * - `Boolean` isBalanceEnough: indicate balance is enough for gas and storage fee * - `Boolean` willPayCollateral: false if the transaction is eligible for storage collateral sponsorship, true otherwise * - `Boolean` willPayTxFee: false if the transaction is eligible for gas sponsorship, true otherwise */ async checkBalanceAgainstTransaction(from, to, gas, gasPrice, storageLimit, epochNumber) { return this.cfx.checkBalanceAgainstTransaction(from, to, gas, gasPrice, storageLimit, epochNumber); } /** * Returns logs matching the filter provided. * * @param {import('./rpc/types/formatter').LogFilter} [options] * @return {Promise<import('./rpc/types/formatter').Log[]>} Array of log, that the logs matching the filter provided: * - address `string`: Address this event originated from. * - topics `string[]`: Array of topics. * - data `string`: The data containing non-indexed log parameter. * - blockHash `string`: Hash of the block where the log in. * - epochNumber `number`: Epoch number of the block where the log in. * - transactionHash `string`: Hash of the transaction where the log in. * - transactionIndex `string`: Transaction index in the block. * - logIndex `number`: Log index in block. * - transactionLogIndex `number`: Log index in transaction. * * @example * > await conflux.getLogs({ address: 'cfxtest:achc8nxj7r451c223m18w2dwjnmhkd6rxa2gc31euw', fromEpoch: 39802, toEpoch: 39802, limit: 1, topics: ['0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d'], }); [ { epochNumber: 39802, logIndex: 2, transactionIndex: 0, transactionLogIndex: 2, address: 'CFXTEST:TYPE.CONTRACT:ACHC8NXJ7R451C223M18W2DWJNMHKD6RXA2GC31EUW', blockHash: '0xca00158a2a508170278d5bdc5ca258b6698306dd8c30fdba32266222c79e57e6', data: '0x', topics: [ '0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d', '0x0000000000000000000000000000000000000000000000000000000000000000', '0x0000000000000000000000001c1e72f0c37968557b3d85a3f32747792798bbde', '0x0000000000000000000000001c1e72f0c37968557b3d85a3f32747792798bbde' ], transactionHash: '0xeb75f47002720311f1709e36d7f7e9a91ee4aaa469a1de892839cb1ef66a9939' } ] */ async getLogs(options) { if (options.blockHashes !== undefined && (options.fromEpoch !== undefined || options.toEpoch !== undefined)) { throw new Error('OverrideError, do not use `blockHashes` with `fromEpoch` or `toEpoch`, cause only `blockHashes` will take effect'); } const result = await this.request({ method: 'cfx_getLogs', params: [this._formatGetLogs(options)] }); return cfxFormat.logs(result); } /** * Return block's execution trace. * * > Note: need RPC server open trace_block method * * @param {string} blockHash - block hash * @return {Promise<object[]>} Array of transaction traces. * * @example * > await conflux.traceBlock('0xaf0e1d773dee28c95bcfa5480ed663fcc695b32c8c1dd81f57ff61ff09f55f88') { "transactionTraces": [ { "traces": [ { "action": { "callType": "call", "from": "CFXTEST:TYPE.USER:AAP6SU0S2UZ36X19HSCP55SR6N42YR1YK6HX8D8SD1", "gas": "311592", "input": "0x", "to": "CFXTEST:TYPE.CONTRACT:ACCKUCYY5FHZKNBXMEEXWTAJ3BXMEG25B2NUF6KM25", "value": "0" }, "type": "call" } ] },