UNPKG

@bcpros/crypto-wallet-core

Version:

A multi-currency support library for address derivation, private key creation, and transaction creation

147 lines 5.62 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ETHTxProvider = void 0; const ethers_1 = require("ethers"); const web3_1 = __importDefault(require("web3")); const constants_1 = require("../../constants"); const chains_1 = require("../../constants/chains"); const abi_1 = require("../erc20/abi"); const utils = require('web3-utils'); const { toBN } = web3_1.default.utils; class ETHTxProvider { chain; constructor(chain = 'ETH') { this.chain = chain; } create(params) { const { recipients, nonce, gasPrice, gasLimit, network, contractAddress, maxGasFee, priorityGasFee, txType } = params; let { data } = params; let to; let amount; if (recipients.length > 1) { if (!contractAddress) { throw new Error('Multiple recipients requires use of multi-send contract, please specify contractAddress'); } const addresses = []; const amounts = []; amount = toBN(0); for (let recipient of recipients) { addresses.push(recipient.address); amounts.push(toBN(this._valueToString(recipient.amount))); amount = amount.add(toBN(this._valueToString(recipient.amount))); } const multisendContract = this.getMultiSendContract(contractAddress); data = data || multisendContract.methods.sendEth(addresses, amounts).encodeABI(); to = contractAddress; } else { to = recipients[0].address; amount = toBN(this._valueToString(recipients[0].amount)); } let { chainId } = params; chainId = chainId || this.getChainId(network); let txData = { nonce: utils.toHex(nonce), gasLimit: utils.toHex(gasLimit), to, data, value: utils.toHex(amount), chainId }; if (maxGasFee && (txType == null || txType >= 2)) { txData.maxFeePerGas = utils.toHex(maxGasFee); txData.maxPriorityFeePerGas = utils.toHex(priorityGasFee || this.getPriorityFeeMinimum(chainId)); txData.type = 2; } else { txData.gasPrice = utils.toHex(gasPrice); txData.type = txType || 0; } return ethers_1.ethers.Transaction.from(txData).unsignedSerialized; } _valueToString(value) { const type = typeof value; if (type === 'number') { return (value).toLocaleString('fullwide', { useGrouping: false }); } else if (type === 'bigint') { return value.toString(); } else if (type === 'string') { return value; } else { throw new Error(`Unexpected type of: ${type}`); } } getMultiSendContract(tokenContractAddress) { const web3 = new web3_1.default(); return new web3.eth.Contract(abi_1.MULTISENDAbi, tokenContractAddress); } getPriorityFeeMinimum(chainId) { const chain = constants_1.Constants.EVM_CHAIN_ID_TO_CHAIN[chainId]; return constants_1.Constants.FEE_MINIMUMS[chain]?.priority || 0; } getChainId(network) { if (network === 'testnet') { network = chains_1.EVM_CHAIN_DEFAULT_TESTNET[this.chain]; } return chains_1.EVM_CHAIN_NETWORK_TO_CHAIN_ID[`${this.chain}_${network}`] || chains_1.EVM_CHAIN_NETWORK_TO_CHAIN_ID[`${this.chain}_mainnet`]; } getSignatureObject(params) { const { tx, key } = params; let k = key.privKey; if (k.substring(0, 2) != '0x') { k = '0x' + k; } const signingKey = new ethers_1.ethers.SigningKey(k); return signingKey.sign(ethers_1.ethers.keccak256(tx)); } getSignature(params) { const signatureHex = this.getSignatureObject(params).serialized; return signatureHex; } getHash(params) { const { tx } = params; return ethers_1.ethers.Transaction.from(tx).hash; } applySignature(params) { let { tx, signature } = params; const parsedTx = ethers_1.ethers.Transaction.from(tx); const { gasPrice, maxFeePerGas, maxPriorityFeePerGas } = parsedTx; if (maxFeePerGas) { parsedTx.maxFeePerGas = maxFeePerGas; parsedTx.maxPriorityFeePerGas = maxPriorityFeePerGas; parsedTx.type = 2; } else if (!gasPrice) { throw new Error('either gasPrice or maxFeePerGas is required'); } let valid = false; let signedTx; try { parsedTx.signature = ethers_1.ethers.Signature.from(signature); signedTx = ethers_1.ethers.Transaction.from(parsedTx); if (signedTx.hash) { const recoveredAddress = ethers_1.ethers.recoverAddress(ethers_1.ethers.keccak256(tx), signature); const expectedAddress = parsedTx.from; valid = recoveredAddress === expectedAddress; } } catch { } if (!valid) { throw new Error('invalid signature'); } return signedTx.serialized; } sign(params) { const { tx, key } = params; const signature = this.getSignatureObject({ tx, key }); return this.applySignature({ tx, signature }); } } exports.ETHTxProvider = ETHTxProvider; //# sourceMappingURL=index.js.map