@bcpros/crypto-wallet-core
Version:
A multi-currency support library for address derivation, private key creation, and transaction creation
147 lines • 5.62 kB
JavaScript
;
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