UNPKG

jcc-ethereum-utils

Version:

Toolkit of crossing chain from Ethereum to SWTC chain

512 lines 16.6 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const jcc_wallet_1 = require("jcc_wallet"); const web3_eth_contract_1 = require("web3-eth-contract"); const bignumber_js_1 = require("bignumber.js"); const { Web3 } = require("web3"); /** * Toolkit of Ethereum * * @export * @class Ethereum */ class Ethereum { /** * Creates an instance of Ethereum * @param {string} node http node * @memberof Ethereum */ constructor(node) { this._web3 = null; this._node = node; this._gasLimit = 200000; this._minGasPrice = 5 * Math.pow(10, 9); this._defaultGasPrice = Math.pow(10, 10); this._minFeePerGas = 5 * Math.pow(10, 9); this._minPriorityFeePerGas = Math.pow(10, 9); } /** * set & get _gasLimit * * @type {number} * @memberof Ethereum */ get gasLimit() { return this._gasLimit; } set gasLimit(gas) { this._gasLimit = gas; } /** * set & get _minGasPrice * * @type {number} * @memberof Ethereum */ get minGasPrice() { return this._minGasPrice; } set minGasPrice(value) { this._minGasPrice = value; } /** * set & get _defaultGasPrice * * @memberof Ethereum */ set defaultGasPrice(v) { this._defaultGasPrice = v; } get defaultGasPrice() { return this._defaultGasPrice; } /** * set & get _minFeePerGas * * @type {number} * @memberof Ethereum */ set minFeePerGas(v) { this._minFeePerGas = v; } get minFeePerGas() { return this._minFeePerGas; } /** * set & get _minPriorityFeePerGas * * @type {number} * @memberof Ethereum */ set minPriorityFeePerGas(v) { this._minPriorityFeePerGas = v; } get minPriorityFeePerGas() { return this._minPriorityFeePerGas; } /** * validate ethereum address * * @static * @param {string} address ethereum address * @returns {boolean} return true if the address is valid * @memberof Ethereum */ static isValidAddress(address) { return jcc_wallet_1.ethWallet.isValidAddress(address); } /** * validate ethereum secret * * @static * @param {string} secret ethereum secret * @returns {boolean} return true if the secret is valid * @memberof Ethereum */ static isValidSecret(secret) { return jcc_wallet_1.ethWallet.isValidSecret(secret); } /** * retrieve ethereum address via secret * * @static * @param {string} secret ethereum secret * @returns {string} return address if the secret is valid, otherwise return null * @memberof Ethereum */ static getAddress(secret) { return jcc_wallet_1.ethWallet.getAddress(secret); } /** * create ethereum wallet * * @static * @returns {IWalletModel} * @memberof Ethereum */ static createWallet() { return jcc_wallet_1.ethWallet.createWallet(); } /** * prefix `0x` if the given string not start with `0x` * * @static * @param {string} str * @returns {string} * @memberof Ethereum */ static prefix0x(str) { if (str && !str.startsWith("0x")) { str = "0x" + str; } return str; } /** * filter `0x` if the given string starts with `0x` * * @static * @param {string} str * @returns {string} * @memberof Ethereum */ static filter0x(str) { if (typeof str !== "string") { return str; } return str.startsWith("0x") ? str.substring(2) : str; } /** * init instance of web3 * * @memberof Ethereum */ initWeb3() { if (!this._web3 || !this._web3.currentProvider) { // Only allow safe transport schemes to prevent protocol-injection attacks. const allowedSchemes = ["http:", "https:", "ws:", "wss:"]; let parsedUrl; try { parsedUrl = new URL(this._node); } catch (_a) { throw new Error(`Invalid node URL: ${this._node}`); } if (!allowedSchemes.includes(parsedUrl.protocol)) { throw new Error(`Unsupported URL scheme "${parsedUrl.protocol}". Allowed: http, https, ws, wss.`); } this._web3 = new Web3(new Web3.providers.HttpProvider(this._node)); } } /** * destroy instance of web3 * * @memberof Ethereum */ destroyWeb3() { try { this._web3.setProvider(null); } catch (error) { /* istanbul ignore next */ } finally { this._web3 = null; } } /** * get instance of web3 * * @memberof Ethereum */ getWeb3() { return this._web3; } /** * request info of block * * @param {number|string} block number or string latest * @returns {Promise<any>} resolve null if request failed, return block info * @memberof Ethereum */ getBlock(block) { return __awaiter(this, void 0, void 0, function* () { let blockInfo; try { blockInfo = yield this._web3.eth.getBlock(block); } catch (error) { blockInfo = null; } return blockInfo; }); } /** * request balance of ether * * @param {string} address ethereum address * @returns {Promise<string>} resolve "0" if request failed * @memberof Ethereum */ getBalance(address) { return __awaiter(this, void 0, void 0, function* () { const wei = yield this._web3.eth.getBalance(address); const balance = this._web3.utils.fromWei(wei, "ether"); return balance; }); } /** * request current gas price * * @returns {Promise<number>} resolve gas price if success * @memberof Ethereum */ getGasPrice() { return __awaiter(this, void 0, void 0, function* () { try { const gasPrice = yield this._web3.eth.getGasPrice(); const bn = new bignumber_js_1.BigNumber(gasPrice); return bn.lte(this._minGasPrice) ? this._minGasPrice : bn.toNumber(); } catch (error) { return this._defaultGasPrice; } }); } /** * request current fee data * * @returns {Promise<IFeeData>} resolve gas price if success * @memberof Ethereum */ getFeeData() { return __awaiter(this, void 0, void 0, function* () { try { const feeData = yield this._web3.eth.calculateFeeData(); const gasPrice = new bignumber_js_1.BigNumber(feeData.gasPrice); feeData.gasPrice = gasPrice.lte(this._minGasPrice) ? this._minGasPrice : gasPrice.toNumber(); if (feeData.baseFeePerGas) { const maxFeePerGas = new bignumber_js_1.BigNumber(feeData.maxFeePerGas); const maxPriorityFeePerGas = new bignumber_js_1.BigNumber(feeData.maxPriorityFeePerGas); feeData.baseFeePerGas = new bignumber_js_1.BigNumber(feeData.baseFeePerGas).toNumber(); feeData.maxFeePerGas = maxFeePerGas.lte(this._minGasPrice) ? this._minGasPrice : maxFeePerGas.toNumber(); feeData.maxPriorityFeePerGas = maxPriorityFeePerGas.lte(this._minPriorityFeePerGas) ? this._minPriorityFeePerGas : maxPriorityFeePerGas.toNumber(); } return feeData; } catch (error) { return { gasPrice: this._defaultGasPrice }; } }); } /** * request nonce * * @param {string} address ethereum address * @returns {Promise<number>} resolve nonce if success * @memberof Ethereum */ getNonce(address) { return __awaiter(this, void 0, void 0, function* () { address = Ethereum.prefix0x(address); try { const ethCount = yield this._web3.eth.getTransactionCount(address); return new bignumber_js_1.BigNumber(ethCount).toNumber(); } catch (error) { throw error; } }); } /** * check if has pending transaction * * @param {string} address * @returns {Promise<boolean>} resolve true if has pending transaction * @memberof Ethereum */ hasPendingTransactions(address) { return __awaiter(this, void 0, void 0, function* () { try { const pendingList = yield this._web3.eth.getPendingTransactions(); address = Ethereum.prefix0x(address).toLowerCase(); let hasPending = false; for (const pending of pendingList) { if (address.includes(pending.from.toLowerCase())) { hasPending = true; break; } } return hasPending; } catch (error) { throw error; } }); } /** * check if has pending block transaction * * @param {string} address * @returns {Promise<boolean>} resolve true if has pending block transaction * @memberof Ethereum */ hasPendingBlockTransactions(address) { return __awaiter(this, void 0, void 0, function* () { try { const pendingBlock = yield this._web3.eth.getBlock("pending", true); address = Ethereum.prefix0x(address).toLowerCase(); let hasPending = false; for (const pending of pendingBlock.transactions) { if (address.includes(pending.from.toLowerCase())) { hasPending = true; break; } } return hasPending; } catch (error) { throw error; } }); } /** * format transaction info * * @param {string} from sender address * @param {string} to destination address * @param {number} nonce nonce * @param {number} gasLimit gas limit * @param {number} gasPrice gas price * @param {string} value value * @param {string} calldata call data * @returns {EthereumTransaction} * @memberof Ethereum */ getTx(from, to, nonce, gasLimit, gasPrice, value, calldata) { const tx = { data: !calldata ? "0x0" : calldata, from, gas: this._web3.utils.numberToHex(gasLimit), gasPrice: this._web3.utils.numberToHex(gasPrice), nonce, to, value: (value === null || value === void 0 ? void 0 : value.startsWith("0x")) ? value : this._web3.utils.numberToHex(this._web3.utils.toWei(value + "", "ether")) }; // 在判断uint类型时,toHex条件判断似乎有问题,所以这里使用numberToHex return tx; } /** * format EIP1559 transaction info * * @param {string} from sender address * @param {string} to destination address * @param {number} nonce nonce * @param {number} gasLimit gas limit * @param {number} maxFeePerGas max fee per gas * @param {number} maxPriorityFeePerGas max priority fee per gas * @param {string} value value * @param {string} calldata call data * @returns {EthereumTransaction} * @memberof Ethereum */ get1559Tx(from, to, nonce, gasLimit, maxFeePerGas, maxPriorityFeePerGas, value, calldata) { const tx = { from, to, nonce, value: (value === null || value === void 0 ? void 0 : value.startsWith("0x")) ? value : this._web3.utils.numberToHex(this._web3.utils.toWei(value + "", "ether")), gasLimit: this._web3.utils.numberToHex(gasLimit), maxFeePerGas: this._web3.utils.numberToHex(maxFeePerGas), maxPriorityFeePerGas: this._web3.utils.numberToHex(maxPriorityFeePerGas), data: !calldata ? "0x0" : calldata }; return tx; } /** * sign transaction with ethereum secret * * @param {EthereumTransaction} tx transaction * @param {string} secret ethereum secret * @returns {Promise<string>} return signed info * @memberof Ethereum */ signTransaction(tx, secret) { return __awaiter(this, void 0, void 0, function* () { const signed = yield this._web3.eth.accounts.signTransaction(tx, secret); return signed.rawTransaction; }); } /** * send signed transaction * * @param {string} sign * @returns {Promise<string>} resolve hash if success * @memberof Ethereum */ sendSignedTransaction(sign) { return __awaiter(this, void 0, void 0, function* () { // sendSignedTransaction会自动绑定receipt等事件,在销毁实例时会抛出错误 try { const txInfo = yield this._web3.eth.sendSignedTransaction(sign); // Explicitly check on-chain execution status. A falsy status means the // transaction was mined but reverted, which must be surfaced to callers. if (txInfo.status === false || txInfo.status === BigInt(0)) { throw new Error(`Transaction reverted on-chain: ${txInfo.transactionHash}`); } return txInfo.transactionHash; } catch (error) { throw error; } }); } /** * get transaction * * @param {string} hash transaction hash * @returns {any} null or transaction object * @memberof Ethereum */ getTransaction(hash) { return __awaiter(this, void 0, void 0, function* () { try { const data = yield this._web3.eth.getTransaction(hash); return data; } catch (error) { throw error; } }); } /** * get transaction receipt * * @param {string} hash transaction hash * @returns {any} null or transaction receipt object * @memberof Ethereum */ getTransactionReceipt(hash) { return __awaiter(this, void 0, void 0, function* () { try { const data = yield this._web3.eth.getTransactionReceipt(hash); return data; } catch (error) { throw error; } }); } /** * init instance of ethereum or erc20 contract * * @param {abitItem} abi definition of ethereum abi or erc20 abi * @param {string} address * @returns {Contract} return instance of ethereum or erc20 contract * @memberof Ethereum */ contract(abi, address) { return new this._web3.eth.Contract(abi, address); } /** * check instance of contract if initialied * * @param {Contract} contract current contract instance * @param {string} address current contract address * @returns {boolean} return true if initialied * @memberof Ethereum */ contractInitialied(contract, address) { return contract instanceof web3_eth_contract_1.Contract && !!contract.options.address && contract.options.address.toLowerCase() === address.toLowerCase(); } } exports.default = Ethereum; //# sourceMappingURL=ethereum.js.map