UNPKG

@celo-tools/celo-ethers-wrapper

Version:

A minimal wrapper to make Ethers.JS compatible with the Celo network.

428 lines 35.3 kB
import { accessListify, assertArgument, decodeRlp, encodeRlp, getAddress, getBigInt, getBytes, getNumber, hexlify, isBytesLike, keccak256, recoverAddress, Signature, stripZerosLeft, toBeArray, toBeHex, zeroPadValue, } from "ethers"; import { concatHex, isCIP64, isCIP66 } from "./transaction/utils"; import { EIGHT, EIP155_NUMBER, Y_PARITY_EIP_2098 } from "../consts"; export var TxTypeToPrefix; (function (TxTypeToPrefix) { TxTypeToPrefix[TxTypeToPrefix["cip64"] = 123] = "cip64"; TxTypeToPrefix[TxTypeToPrefix["cip66"] = 122] = "cip66"; TxTypeToPrefix[TxTypeToPrefix["eip1559"] = 2] = "eip1559"; })(TxTypeToPrefix || (TxTypeToPrefix = {})); export const celoAllowedTransactionKeys = { type: true, chainId: true, data: true, gasLimit: true, gasPrice: true, nonce: true, to: true, value: true, feeCurrency: true, maxFeePerGas: true, maxPriorityFeePerGas: true, accessList: true, maxFeeInFeeCurrency: true, }; export const celoTransactionFields = { nonce: { maxLength: 32, numeric: true }, gasPrice: { maxLength: 32, numeric: true }, gasLimit: { maxLength: 32, numeric: true }, feeCurrency: { length: 20 }, to: { length: 20 }, value: { maxLength: 32, numeric: true }, data: {}, maxFeePerGas: { maxLength: 32, numeric: true }, maxPriorityFeePerGas: { maxLength: 32, numeric: true }, maxFeeInFeeCurrency: { maxLength: 32, numeric: true }, }; function formatCeloField(name, value) { const fieldInfo = celoTransactionFields[name]; const options = {}; if (!value || value === "0x") return value; if (fieldInfo.numeric) { options.hexPad = "left"; value = value ? toBeHex(value, fieldInfo.maxLength) : "0x"; } else { value = hexlify(value); } let _value = toBeArray(value); // Fixed-width field if (fieldInfo.length && _value.length !== fieldInfo.length && _value.length > 0) { assertArgument(false, "invalid length for " + name, "transaction:" + name, _value); } // Variable-width (with a maximum) if (fieldInfo.maxLength) { _value = toBeArray(stripZerosLeft(_value)); if (_value.length > fieldInfo.maxLength) { assertArgument(false, "invalid length for " + name, "transaction:" + name, _value); } } return hexlify(_value); } export function getTxType(tx) { if (tx.gasPrice) { return ""; } if (isCIP66(tx)) { return TxTypeToPrefix.cip66; } if (isCIP64(tx)) { return TxTypeToPrefix.cip64; } return TxTypeToPrefix.eip1559; } function prepareEncodeTx(tx, signature) { let raw = []; switch (tx.type) { case TxTypeToPrefix.cip66: // https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0066.md // 0x7a || rlp([chainId, nonce, maxPriorityFeePerGas, maxFeePerGas, gasLimit, to, value, data, accessList, feeCurrency, maxFeeInFeeCurrency, signatureYParity, signatureR, signatureS]). raw = [ toBeHex(tx.chainId), toBeHex(tx.nonce), tx.maxPriorityFeePerGas ? toBeHex(tx.maxPriorityFeePerGas) : "0x", tx.maxFeePerGas ? toBeHex(tx.maxFeePerGas) : "0x", tx.gasLimit ? toBeHex(tx.gasLimit) : "0x", tx.to || "0x", tx.value ? toBeHex(tx.value) : "0x", tx.data || "0x", formatAccessList(tx.accessList || []), tx.feeCurrency || "0x", tx.maxFeeInFeeCurrency ? toBeHex(tx.maxFeeInFeeCurrency) : "0x", ]; break; case TxTypeToPrefix.cip64: // https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0064.md // 0x7b || rlp([chainId, nonce, maxPriorityFeePerGas, maxFeePerGas, gasLimit, to, value, data, accessList, feeCurrency, signatureYParity, signatureR, signatureS]). raw = [ toBeHex(tx.chainId), toBeHex(tx.nonce), tx.maxPriorityFeePerGas ? toBeHex(tx.maxPriorityFeePerGas) : "0x", tx.maxFeePerGas ? toBeHex(tx.maxFeePerGas) : "0x", tx.gasLimit ? toBeHex(tx.gasLimit) : "0x", tx.to || "0x", tx.value ? toBeHex(tx.value) : "0x", tx.data || "0x", formatAccessList(tx.accessList || []), tx.feeCurrency || "0x", ]; break; case TxTypeToPrefix.eip1559: // https://eips.ethereum.org/EIPS/eip-1559 // 0x02 || rlp([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, destination, amount, data, access_list, signature_y_parity, signature_r, signature_s]). raw = [ toBeHex(tx.chainId), toBeHex(tx.nonce), tx.maxPriorityFeePerGas ? toBeHex(tx.maxPriorityFeePerGas) : "0x", tx.maxFeePerGas ? toBeHex(tx.maxFeePerGas) : "0x", tx.gasLimit ? toBeHex(tx.gasLimit) : "0x", tx.to || "0x", tx.value ? toBeHex(tx.value) : "0x", tx.data || "0x", formatAccessList(tx.accessList || []), ]; break; default: // Type 0 Ethereum legacy transaction: // rlp([nonce, gasprice, gaslimit, recipient, amount, data, v, r, s]) raw = [ toBeHex(tx.nonce), tx.gasPrice ? toBeHex(tx.gasPrice) : "0x", tx.gasLimit ? toBeHex(tx.gasLimit) : "0x", tx.to || "0x", tx.value ? toBeHex(tx.value) : "0x", tx.data || "0x", ]; if (!signature) { raw.push(...[toBeHex(tx.chainId), "0x", "0x"]); } break; } if (signature) { raw.push(...[ // NOTE: Somehow geth cannot parse `0x00` because it's dumb signature.v ? toBeHex(signature.v) : "0x", stripZerosLeft(getBytes(signature.r)), stripZerosLeft(getBytes(signature.s)), ]); } return raw; } // 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 export function serializeCeloTransaction(transaction, signature) { Object.keys(transaction).forEach((property) => { if (!(property in celoAllowedTransactionKeys)) { assertArgument(false, "unknown property", "serializeCeloTransaction", property); } }); const txArgs = {}; Object.entries(transaction).forEach(([fieldName, fieldValue]) => { if (fieldName in celoTransactionFields) { // @ts-expect-error txArgs[fieldName] = formatCeloField(fieldName, fieldValue); } else if (fieldName === 'accessList') { txArgs[fieldName] = fieldValue; } }); let chainId = 0; if (transaction.chainId != null) { // A chainId was provided; if non-zero we'll use EIP-155 chainId = parseInt(transaction.chainId.toString(16), 16); if (typeof chainId !== "number") { assertArgument(false, "invalid transaction.chainId", "transaction", transaction); } } else if (signature && !isBytesLike(signature) && signature.v && getNumber(signature.v) > 28) { // No chainId provided, but the signature is signing with EIP-155; derive chainId chainId = Math.floor((getNumber(signature.v) - EIP155_NUMBER) / 2); } // We have an EIP-155 transaction (chainId was specified and non-zero) if (chainId !== 0) { txArgs["chainId"] = toBeHex(chainId); // @TODO: hexValue? } // Requesting an unsigned transation // @ts-ignore const type = getTxType(txArgs); // @ts-expect-error txArgs.type = type; if (!signature) { // @ts-expect-error const raw = prepareEncodeTx(txArgs); const encoded = encodeRlp(raw); return type ? concatHex([toBeHex(type), encoded]) : encoded; } // The splitSignature will ensure the transaction has a recoveryParam in the // case that the signTransaction function only adds a v. const sig = Signature.from(signature); let v; if (txArgs.type) { // cip64, eip-1559 v = sig.v - Y_PARITY_EIP_2098; } else { // celo-legacy v = Y_PARITY_EIP_2098 + sig.yParity; if (chainId !== 0) { v += chainId * 2 + EIGHT; // If an EIP-155 v (directly or indirectly; maybe _vs) was provided, check it! if (sig.v > Y_PARITY_EIP_2098 + 1 && sig.v !== v) { assertArgument(false, "transaction.chainId/signature.v mismatch", "signature", signature); } } else if (sig.v !== v) { assertArgument(false, "transaction.chainId/signature.v mismatch", "signature", signature); } } // @ts-expect-error const raw = prepareEncodeTx(txArgs, { ...sig.toJSON(), v }); const encoded = encodeRlp(raw); return type ? concatHex([toBeHex(type), encoded]) : encoded; } // Based on https://github.com/ethers-io/ethers.js/blob/0234cfbbef76b7f7a53efe4c434cc6d8892bf404/packages/transactions/src.ts/index.ts#L165 // Need to override to use the celo tx prop whitelists above export function parseCeloTransaction(rawTransaction) { const [type, transaction] = splitTypeAndRawTx(rawTransaction); let tx; switch (type) { case TxTypeToPrefix.cip66: tx = { type: TxTypeToPrefix.cip66, chainId: handleNumber(transaction[0]), nonce: handleNumber(transaction[1]), maxPriorityFeePerGas: handleBigInt(transaction[2]), maxFeePerGas: handleBigInt(transaction[3]), gasLimit: handleBigInt(transaction[4]), to: handleAddress(transaction[5]), value: handleBigInt(transaction[6]), data: transaction[7], accessList: handleAccessList(transaction[8]), feeCurrency: handleAddress(transaction[9]), maxFeeInFeeCurrency: handleBigInt(transaction[10]), }; break; case TxTypeToPrefix.cip64: tx = { type: TxTypeToPrefix.cip64, chainId: handleNumber(transaction[0]), nonce: handleNumber(transaction[1]), maxPriorityFeePerGas: handleBigInt(transaction[2]), maxFeePerGas: handleBigInt(transaction[3]), gasLimit: handleBigInt(transaction[4]), to: handleAddress(transaction[5]), value: handleBigInt(transaction[6]), data: transaction[7], accessList: handleAccessList(transaction[8]), feeCurrency: handleAddress(transaction[9]), }; break; case TxTypeToPrefix.eip1559: // untested tx = { type: TxTypeToPrefix.eip1559, chainId: handleNumber(transaction[0]), nonce: handleNumber(transaction[1]), maxPriorityFeePerGas: handleBigInt(transaction[2]), maxFeePerGas: handleBigInt(transaction[3]), gasLimit: handleBigInt(transaction[4]), to: handleAddress(transaction[5]), value: handleBigInt(transaction[6]), data: transaction[7], accessList: handleAccessList(transaction[8]), }; break; default: /** * Type 0 Ethereum legacy transaction: * RLP([nonce, gasprice, gaslimit, recipient, amount, data, chaindId, 0, 0]) */ tx = { nonce: handleNumber(transaction[0]), gasPrice: handleBigInt(transaction[1]), gasLimit: handleBigInt(transaction[2]), to: handleAddress(transaction[3]), value: handleBigInt(transaction[4]), data: transaction[5], chainId: handleBigInt(transaction[6]), }; break; } // Legacy unsigned transaction if (!isSigned(type, transaction)) { return tx; } let v; try { v = handleNumber(transaction.at(-3)); } catch (error) { console.log(error); return tx; } const r = zeroPadValue(transaction.at(-2), 32); const s = zeroPadValue(transaction.at(-1), 32); // EIP-155 unsigned transaction if (handleBigInt(r) === 0n && handleBigInt(s) === 0n) { if (!type) { tx.chainId = v; v = 0; } } // Signed Transaction else { let recoveryParam = v; if (!type) { // celo-legacy tx.chainId = Math.max(0, Math.floor((v - EIP155_NUMBER) / 2)); recoveryParam = v - Y_PARITY_EIP_2098; recoveryParam -= tx.chainId * 2 + EIGHT; } // NOTE: Serialization needs to happen here because chainId may not populated before const serialized = serializeCeloTransaction(tx); const digest = keccak256(serialized); try { tx.from = recoverAddress(digest, { r, s, yParity: recoveryParam, }); } catch (error) { console.log(error); } tx.hash = keccak256(rawTransaction); } return tx; } function handleAddress(value) { if (value === "0x") { return undefined; } try { return getAddress(value); } catch (error) { return value; } } function handleNumber(value) { if (value === "0x") { return 0; } return getNumber(value); } function handleBigInt(value) { if (value === "0x") { return 0n; } return getBigInt(value); } function formatAccessList(value) { return accessListify(value).map((set) => [set.address, set.storageKeys]); } /* @param value [ [ '0x0000000000000000000000000000000000000000', [ '0x0000000000000000000000000000000000000000000000000000000000000001', '0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe' ] ] ] */ function handleAccessList(value) { if (value === "0x") { return accessListify([]); } return accessListify(value); } const baseTxLengths = { [TxTypeToPrefix.cip64]: { unsigned: 10, signed: 13 }, [TxTypeToPrefix.cip66]: { unsigned: 11, signed: 14 }, [TxTypeToPrefix.eip1559]: { unsigned: 9, signed: 12 }, /** * Unsigned: RLP([nonce, gasprice, gaslimit, recipient, amount, data, chaindId, 0, 0]) * Signed: RLP([nonce, gasprice, gaslimit, recipient, amount, data, v, r, s]) * Source: https://github.com/celo-org/txtypes?tab=readme-ov-file#legacy-transactions */ "ethereum-legacy": { unsigned: 9, signed: 9 }, }; function isSigned(type, transaction) { if (type) { const { signed } = baseTxLengths[type]; return transaction.length === signed; } const r = transaction.at(-2) || "0x"; const s = transaction.at(-1) || "0x"; return r !== "0x" && s !== "0x"; } function isCorrectLength(type, transaction) { const { unsigned } = baseTxLengths[type || "ethereum-legacy"]; return transaction.length === unsigned || isSigned(type, transaction); } function splitTypeAndRawTx(rawTransaction) { let rawStr = rawTransaction.toString(); let type; for (const _type of [TxTypeToPrefix.cip64, TxTypeToPrefix.cip66, TxTypeToPrefix.eip1559]) { const prefix = toBeHex(_type); if (rawStr.startsWith(prefix)) { rawStr = `0x${rawStr.slice(prefix.length)}`; type = _type; break; } } const transaction = decodeRlp(rawStr); if (!isCorrectLength(type, transaction)) { assertArgument(false, "invalid raw transaction", "{type, rawTransaction}", { type: type, rawTransaction, }); } return [type, transaction]; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNhY3Rpb25zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2xpYi90cmFuc2FjdGlvbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUVMLGFBQWEsRUFFYixjQUFjLEVBRWQsU0FBUyxFQUNULFNBQVMsRUFDVCxVQUFVLEVBQ1YsU0FBUyxFQUNULFFBQVEsRUFDUixTQUFTLEVBQ1QsT0FBTyxFQUNQLFdBQVcsRUFDWCxTQUFTLEVBQ1QsY0FBYyxFQUVkLFNBQVMsRUFFVCxjQUFjLEVBQ2QsU0FBUyxFQUNULE9BQU8sRUFHUCxZQUFZLEdBQ2IsTUFBTSxRQUFRLENBQUM7QUFDaEIsT0FBTyxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDbEUsT0FBTyxFQUFFLEtBQUssRUFBRSxhQUFhLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxXQUFXLENBQUM7QUE0QnBFLE1BQU0sQ0FBTixJQUFZLGNBSVg7QUFKRCxXQUFZLGNBQWM7SUFDeEIsdURBQVksQ0FBQTtJQUNaLHVEQUFZLENBQUE7SUFDWix5REFBYyxDQUFBO0FBQ2hCLENBQUMsRUFKVyxjQUFjLEtBQWQsY0FBYyxRQUl6QjtBQVFELE1BQU0sQ0FBQyxNQUFNLDBCQUEwQixHQUFHO0lBQ3hDLElBQUksRUFBRSxJQUFJO0lBQ1YsT0FBTyxFQUFFLElBQUk7SUFDYixJQUFJLEVBQUUsSUFBSTtJQUNWLFFBQVEsRUFBRSxJQUFJO0lBQ2QsUUFBUSxFQUFFLElBQUk7SUFDZCxLQUFLLEVBQUUsSUFBSTtJQUNYLEVBQUUsRUFBRSxJQUFJO0lBQ1IsS0FBSyxFQUFFLElBQUk7SUFDWCxXQUFXLEVBQUUsSUFBSTtJQUNqQixZQUFZLEVBQUUsSUFBSTtJQUNsQixvQkFBb0IsRUFBRSxJQUFJO0lBQzFCLFVBQVUsRUFBRSxJQUFJO0lBQ2hCLG1CQUFtQixFQUFFLElBQUk7Q0FDakIsQ0FBQztBQXFCWCxNQUFN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