From 71ae5fe1d269bb6a7468c48c1c9b3d30dd8b602e Mon Sep 17 00:00:00 2001 From: Nicolas Brugneaux Date: Mon, 2 Oct 2023 18:16:12 +0200 Subject: [PATCH] fix: legacy-celo v/r/s black magic --- src/lib/transactions.ts | 92 ++++++++++++++--------------------------- test/useContract.ts | 57 +++++++++++-------------- 2 files changed, 56 insertions(+), 93 deletions(-) diff --git a/src/lib/transactions.ts b/src/lib/transactions.ts index 44f6e58..0d02c91 100644 --- a/src/lib/transactions.ts +++ b/src/lib/transactions.ts @@ -18,6 +18,7 @@ import { accessListify, AccessListish } from "ethers/lib/utils"; // NOTE: Black magic const Y_PARITY_EIP_2098 = 27; +const BULLSHIT_NUMBER = 8; // From https://github.com/ethers-io/ethers.js/blob/master/packages/bytes/src.ts/index.ts#L33 // Copied because it doesn't seem to be exported from 'ethers' anywhere @@ -352,42 +353,34 @@ export function serializeCeloTransaction( // case that the signTransaction function only adds a v. const sig = utils.splitSignature(signature); - let v = sig.v - Y_PARITY_EIP_2098; + let v: number; if (txArgs.type) { // cip64,cip42, eip-1559 - // noop + v = sig.v - Y_PARITY_EIP_2098; } else { // celo-legacy - v = sig.v + chainId * 2 + 35; + v = Y_PARITY_EIP_2098 + sig.recoveryParam; + + if (chainId !== 0) { + v += chainId * 2 + BULLSHIT_NUMBER; + + // 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) { + logger.throwArgumentError( + "transaction.chainId/signature.v mismatch", + "signature", + signature + ); + } + } else if (sig.v !== v) { + logger.throwArgumentError( + "transaction.chainId/signature.v mismatch", + "signature", + signature + ); + } } - // TODO: rossy cleanup nico - // let v = 27 + sig.recoveryParam; - // if (chainId !== 0) { - // // NOTE: this makes the recoveryParam recovery custom in `parseCeloTransaction` - // // see line: - // if (txArgs.type) { - // // cip64,cip42, eip-1559 - // } else { - // // celo-legacy - // 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 - // ); - // } // @ts-expect-error const raw = prepareEncodeTx(txArgs, { ...sig, v }); const encoded = utils.RLP.encode(raw); @@ -484,34 +477,20 @@ export function parseCeloTransaction( // EIP-155 unsigned transaction if (handleNumber(tx.r).isZero() && handleNumber(tx.s).isZero()) { - tx.chainId = tx.v; - tx.v = 0; + if (!type) { + tx.chainId = tx.v; + tx.v = 0; + } } // Signed Transaction else { - let chainId: number; let recoveryParam = tx.v; - if (tx.type) { - // cip64, cip42, eip-1559 - // noop, chainId is in tx - chainId = tx.chainId; - } else { + if (!type) { // celo-legacy - chainId = Math.max(0, Math.floor((tx.v - 35) / 2)); - tx.chainId = chainId; - recoveryParam = tx.v + Y_PARITY_EIP_2098; - recoveryParam -= tx.chainId * 2 + 35; + tx.chainId = Math.max(0, Math.floor((tx.v - 35) / 2)); + recoveryParam = tx.v - Y_PARITY_EIP_2098; + recoveryParam -= tx.chainId * 2 + BULLSHIT_NUMBER; } - // // NOTE: is this condition even correct now? - // if (!tx.chainId) { - // const chainId = Math.max(0, Math.floor((tx.v - 35) / 2)); - // tx.chainId = chainId; - // } - // let recoveryParam = tx.v - 27; - // if (tx.chainId !== 0) { - // // NOTE: inverse operation that was done in `serializeCeloTransaction` - // recoveryParam -= tx.chainId * 2 + 8; - // } // NOTE: Serialization needs to happen here because chainId may not populated before const serialized = serializeCeloTransaction( @@ -533,15 +512,6 @@ export function parseCeloTransaction( tx.hash = utils.keccak256(rawTransaction); } - console.log("---------"); - console.log("Raw signed Tx", rawTransaction); - console.log("---------"); - console.log("RLP decoded Tx", transaction); - console.log("---------"); - console.log("Inferred type", type!); - console.log("---------"); - console.log("Parsed TX from raw signed:", tx); - console.log("---------"); return tx; } diff --git a/test/useContract.ts b/test/useContract.ts index 965ebf6..c01b3ef 100644 --- a/test/useContract.ts +++ b/test/useContract.ts @@ -1,22 +1,19 @@ -import { BigNumber } from "ethers"; -// import { CUSD_ADDRESS } from "./consts"; -// import { STABLE_TOKEN_ABI } from "./stableToken"; -import { getSigner } from "./utils"; +import { BigNumber, Contract } from "ethers"; import { CUSD_ADDRESS } from "./consts"; -// import { parseCeloTransaction } from "../src/lib/transactions"; -// import { parseCeloTransaction } from "../src/lib/transactions"; +import { STABLE_TOKEN_ABI } from "./stableToken"; +import { getSigner } from "./utils"; async function main() { const signer = getSigner(); - // console.info("Getting account balance for:", signer.address); - // const balance = await signer.getBalance(); - // console.info("Balance:", balance.toString()); + console.info("Getting account balance for:", signer.address); + const balance = await signer.getBalance(); + console.info("Balance:", balance.toString()); - // console.info("Sending 1 CELO wei", signer.address); - // const txResponse1 = await signer.sendTransaction({ - // to: signer.address, - // value: BigNumber.from("1"), - // }); + console.info("Sending 1 CELO wei", signer.address); + const txResponse1 = await signer.sendTransaction({ + to: signer.address, + value: BigNumber.from("1"), + }); // Or, alternatively, break apart signing and sending: // const signedTx = await signer.signTransaction({ @@ -25,13 +22,9 @@ async function main() { // }); // const provider = signer.provider; // const txResponse1 = await provider.sendTransaction(signedTx); - // const txReceipt1 = await txResponse1.wait(); - // console.info("Funds sent. Hash:", txReceipt1.transactionHash); - // console.log( - // parseCeloTransaction( - // "0x7bf88b82f37082050484313da74884362a38028301688c94325f890e573880311cfbadfe8ec3d51ffdd97a7687038d7ea4c6800080c09462492a644a588fd904270bed06ad52b9abfea1ae01a0920e75c798a225d5bd1b1e5c66babdc51943f39b32694d1819f99e5d33353b76a014473654adc9d03fe8de4fe275c1054b5b73d23095fecf7630e2b3a78322e0a2" - // ) - // ); + const txReceipt1 = await txResponse1.wait(); + console.info("Funds sent. Hash:", txReceipt1.transactionHash); + console.info("Sending 1 CELO wei with cUSD feeCurrency"); const txResponse1feeCurrency = await signer.sendTransaction({ to: signer.address, @@ -45,19 +38,19 @@ async function main() { `CELO w/ feeCurrency payment hash: ${txReceipt1FeeCurency.transactionHash}` ); - // const stableToken = new Contract(CUSD_ADDRESS, STABLE_TOKEN_ABI, signer); + const stableToken = new Contract(CUSD_ADDRESS, STABLE_TOKEN_ABI, signer); - // console.info("Getting cUSD balance"); - // const stableBalance = await stableToken.balanceOf(signer.address); - // console.info(`cUSD balance: ${stableBalance.toString()}`); + console.info("Getting cUSD balance"); + const stableBalance = await stableToken.balanceOf(signer.address); + console.info(`cUSD balance: ${stableBalance.toString()}`); - // console.info("Sending 1 cUSD wei"); - // const txResponse2 = await stableToken.transfer( - // signer.address, - // BigNumber.from("1") - // ); - // const txReceipt2 = await txResponse2.wait(); - // console.info(`cUSD payment hash: ${txReceipt2.transactionHash}`); + console.info("Sending 1 cUSD wei"); + const txResponse2 = await stableToken.transfer( + signer.address, + BigNumber.from("1") + ); + const txReceipt2 = await txResponse2.wait(); + console.info(`cUSD payment hash: ${txReceipt2.transactionHash}`); } main()