Skip to content

Commit

Permalink
Safer transaction serialization, matching signature.v with chainId (#708
Browse files Browse the repository at this point in the history
).
  • Loading branch information
ricmoo committed Feb 4, 2020
1 parent 15bb840 commit edb7c5d
Showing 1 changed file with 28 additions and 8 deletions.
36 changes: 28 additions & 8 deletions packages/transactions/src.ts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { getAddress } from "@ethersproject/address";
import { BigNumber, BigNumberish } from "@ethersproject/bignumber";
import { arrayify, BytesLike, DataOptions, hexDataSlice, hexlify, hexZeroPad, SignatureLike, splitSignature, stripZeros, } from "@ethersproject/bytes";
import { arrayify, BytesLike, DataOptions, hexDataSlice, hexlify, hexZeroPad, isBytesLike, SignatureLike, splitSignature, stripZeros, } from "@ethersproject/bytes";
import { Zero } from "@ethersproject/constants";
import { keccak256 } from "@ethersproject/keccak256";
import { checkProperties } from "@ethersproject/properties";
Expand Down Expand Up @@ -109,17 +109,30 @@ export function serialize(transaction: UnsignedTransaction, signature?: Signatur
raw.push(hexlify(value));
});

if (transaction.chainId != null && transaction.chainId !== 0) {
raw.push(hexlify(transaction.chainId));
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 && !isBytesLike(signature) && 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(hexlify(chainId));
raw.push("0x");
raw.push("0x");
}

const unsignedTransaction = RLP.encode(raw);

// Requesting an unsigned transation
if (!signature) {
return unsignedTransaction;
return RLP.encode(raw);
}

// The splitSignature will ensure the transaction has a recoveryParam in the
Expand All @@ -128,11 +141,18 @@ export function serialize(transaction: UnsignedTransaction, signature?: Signatur

// We pushed a chainId and null r, s on for hashing only; remove those
let v = 27 + sig.recoveryParam
if (raw.length === 9) {
if (chainId !== 0) {
raw.pop();
raw.pop();
raw.pop();
v += transaction.chainId * 2 + 8;
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(hexlify(v));
Expand Down

0 comments on commit edb7c5d

Please sign in to comment.