UNPKG

@infibridge/celo-sdk-base

Version:

EthersJS wrapper for Celo Blockchain. Based on https://github.com/celo-tools/celo-ethers-wrapper with small modifications.

184 lines 15.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.parseCeloTransaction = exports.serializeCeloTransaction = exports.celoAllowedTransactionKeys = exports.celoTransactionFields = void 0; const ethers_1 = require("ethers"); const logger = new ethers_1.utils.Logger('CeloTransactionsWrapper'); exports.celoTransactionFields = [ { name: 'nonce', maxLength: 32, numeric: true }, { name: 'gasPrice', maxLength: 32, numeric: true }, { name: 'gasLimit', maxLength: 32, numeric: true }, { name: 'feeCurrency', length: 20 }, { name: 'gatewayFeeRecipient', length: 20 }, { name: 'gatewayFee', maxLength: 32, numeric: true }, { name: 'to', length: 20 }, { name: 'value', maxLength: 32, numeric: true }, { name: 'data' }, ]; exports.celoAllowedTransactionKeys = { chainId: true, data: true, gasLimit: true, gasPrice: true, nonce: true, to: true, value: true, feeCurrency: true, gatewayFeeRecipient: true, gatewayFee: true, }; // Almost identical to https://github.com/ethers-io/ethers.js/blob/master/packages/transactions/src.ts/index.ts#L85 // Need to override to use the celo tx prop whitelists above function serializeCeloTransaction(transaction, signature) { ethers_1.utils.checkProperties(transaction, exports.celoAllowedTransactionKeys); const raw = []; exports.celoTransactionFields.forEach(function (fieldInfo) { let value = transaction[fieldInfo.name] || []; const options = {}; if (fieldInfo.numeric) { options.hexPad = 'left'; } value = ethers_1.utils.arrayify(ethers_1.utils.hexlify(value, options)); // Fixed-width field if (fieldInfo.length && value.length !== fieldInfo.length && value.length > 0) { logger.throwArgumentError('invalid length for ' + fieldInfo.name, 'transaction:' + fieldInfo.name, value); } // Variable-width (with a maximum) if (fieldInfo.maxLength) { value = ethers_1.utils.stripZeros(value); if (value.length > fieldInfo.maxLength) { logger.throwArgumentError('invalid length for ' + fieldInfo.name, 'transaction:' + fieldInfo.name, value); } } raw.push(ethers_1.utils.hexlify(value)); }); let chainId = 0; if (transaction.chainId != null) { // A chainId was provided; if non-zero we'll use EIP-155 chainId = transaction.chainId; if (typeof chainId !== 'number') { logger.throwArgumentError('invalid transaction.chainId', 'transaction', transaction); } } else if (signature && !ethers_1.utils.isBytesLike(signature) && signature.v && signature.v > 28) { // No chainId provided, but the signature is signing with EIP-155; derive chainId chainId = Math.floor((signature.v - 35) / 2); } // We have an EIP-155 transaction (chainId was specified and non-zero) if (chainId !== 0) { raw.push(ethers_1.utils.hexlify(chainId)); // @TODO: hexValue? raw.push('0x'); raw.push('0x'); } // Requesting an unsigned transation if (!signature) { return ethers_1.utils.RLP.encode(raw); } // The splitSignature will ensure the transaction has a recoveryParam in the // case that the signTransaction function only adds a v. const sig = ethers_1.utils.splitSignature(signature); // We pushed a chainId and null r, s on for hashing only; remove those let v = 27 + sig.recoveryParam; if (chainId !== 0) { raw.pop(); raw.pop(); raw.pop(); v += chainId * 2 + 8; // If an EIP-155 v (directly or indirectly; maybe _vs) was provided, check it! if (sig.v > 28 && sig.v !== v) { logger.throwArgumentError('transaction.chainId/signature.v mismatch', 'signature', signature); } } else if (sig.v !== v) { logger.throwArgumentError('transaction.chainId/signature.v mismatch', 'signature', signature); } raw.push(ethers_1.utils.hexlify(v)); raw.push(ethers_1.utils.stripZeros(ethers_1.utils.arrayify(sig.r))); raw.push(ethers_1.utils.stripZeros(ethers_1.utils.arrayify(sig.s))); return ethers_1.utils.RLP.encode(raw); } exports.serializeCeloTransaction = serializeCeloTransaction; // Almost identical to https://github.com/ethers-io/ethers.js/blob/master/packages/transactions/src.ts/index.ts#L165 // Need to override to use the celo tx prop whitelists above function parseCeloTransaction(rawTransaction) { const transaction = ethers_1.utils.RLP.decode(rawTransaction); if (transaction.length !== 12 && transaction.length !== 9) { logger.throwArgumentError('invalid raw transaction', 'rawTransaction', rawTransaction); } const tx = { nonce: handleNumber(transaction[0]).toNumber(), gasPrice: handleNumber(transaction[1]), gasLimit: handleNumber(transaction[2]), feeCurrency: handleAddress(transaction[3]), gatewayFeeRecipient: handleAddress(transaction[4]), gatewayFee: handleNumber(transaction[5]), to: handleAddress(transaction[6]), value: handleNumber(transaction[7]), data: transaction[8], chainId: 0, }; // Legacy unsigned transaction if (transaction.length === 9) { return tx; } try { tx.v = ethers_1.BigNumber.from(transaction[9]).toNumber(); } catch (error) { console.log(error); return tx; } tx.r = ethers_1.utils.hexZeroPad(transaction[10], 32); tx.s = ethers_1.utils.hexZeroPad(transaction[11], 32); if (ethers_1.BigNumber.from(tx.r).isZero() && ethers_1.BigNumber.from(tx.s).isZero()) { // EIP-155 unsigned transaction tx.chainId = tx.v; tx.v = 0; } else { // Signed Tranasaction tx.chainId = Math.floor((tx.v - 35) / 2); if (tx.chainId < 0) { tx.chainId = 0; } let recoveryParam = tx.v - 27; const raw = transaction.slice(0, 6); if (tx.chainId !== 0) { raw.push(ethers_1.utils.hexlify(tx.chainId)); raw.push('0x'); raw.push('0x'); recoveryParam -= tx.chainId * 2 + 8; } const digest = ethers_1.utils.keccak256(ethers_1.utils.RLP.encode(raw)); try { tx.from = ethers_1.utils.recoverAddress(digest, { r: ethers_1.utils.hexlify(tx.r), s: ethers_1.utils.hexlify(tx.s), recoveryParam: recoveryParam, }); } catch (error) { console.log(error); } tx.hash = ethers_1.utils.keccak256(rawTransaction); } return tx; } exports.parseCeloTransaction = parseCeloTransaction; function handleAddress(value) { if (value === '0x') { return undefined; } return ethers_1.utils.getAddress(value); } function handleNumber(value) { if (value === '0x') { return ethers_1.constants.Zero; } return ethers_1.BigNumber.from(value); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ2Vsb1RyYW5zYWN0aW9uc1dyYXBwZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvQ2Vsb1RyYW5zYWN0aW9uc1dyYXBwZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsbUNBUWU7QUFjZixNQUFNLE1BQU0sR0FBRyxJQUFJLGNBQUssQ0FBQyxNQUFNLENBQUMseUJBQXlCLENBQUMsQ0FBQTtBQWM3QyxRQUFBLHFCQUFxQixHQUFHO0lBQ2pDLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxTQUFTLEVBQUUsRUFBRSxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUU7SUFDL0MsRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxFQUFFLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRTtJQUNsRCxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLEVBQUUsRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFO0lBQ2xELEVBQUUsSUFBSSxFQUFFLGFBQWEsRUFBRSxNQUFNLEVBQUUsRUFBRSxFQUFFO0lBQ25DLEVBQUUsSUFBSSxFQUFFLHFCQUFxQixFQUFFLE1BQU0sRUFBRSxFQUFFLEVBQUU7SUFDM0MsRUFBRSxJQUFJLEVBQUUsWUFBWSxFQUFFLFNBQVMsRUFBRSxFQUFFLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRTtJQUNwRCxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLEVBQUUsRUFBRTtJQUMxQixFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLEVBQUUsRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFO0lBQy9DLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRTtDQUNuQixDQUFBO0FBRVksUUFBQSwwQkFBMEIsR0FBK0I7SUFDbEUsT0FBTyxFQUFFLElBQUk7SUFDYixJQUFJLEVBQUUsSUFBSTtJQUNWLFFBQVEsRUFBRSxJQUFJO0lBQ2QsUUFBUSxFQUFFLElBQUk7SUFDZCxL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