@ethersproject/transactions
Advanced tools
Comparing version 5.0.11 to 5.1.0
@@ -1,2 +0,2 @@ | ||
export declare const version = "transactions/5.0.11"; | ||
export declare const version = "transactions/5.1.0"; | ||
//# sourceMappingURL=_version.d.ts.map |
@@ -1,2 +0,2 @@ | ||
export const version = "transactions/5.0.11"; | ||
export const version = "transactions/5.1.0"; | ||
//# sourceMappingURL=_version.js.map |
import { BigNumber, BigNumberish } from "@ethersproject/bignumber"; | ||
import { BytesLike, SignatureLike } from "@ethersproject/bytes"; | ||
export declare type AccessList = Array<{ | ||
address: string; | ||
storageKeys: Array<string>; | ||
}>; | ||
export declare type AccessListish = AccessList | Array<[string, Array<string>]> | Record<string, Array<string>>; | ||
export declare type UnsignedTransaction = { | ||
@@ -11,2 +16,4 @@ to?: string; | ||
chainId?: number; | ||
type?: number | null; | ||
accessList?: AccessListish; | ||
}; | ||
@@ -26,7 +33,10 @@ export interface Transaction { | ||
v?: number; | ||
type?: number | null; | ||
accessList?: AccessList; | ||
} | ||
export declare function computeAddress(key: BytesLike | string): string; | ||
export declare function recoverAddress(digest: BytesLike, signature: SignatureLike): string; | ||
export declare function accessListify(value: AccessListish): AccessList; | ||
export declare function serialize(transaction: UnsignedTransaction, signature?: SignatureLike): string; | ||
export declare function parse(rawTransaction: BytesLike): Transaction; | ||
//# sourceMappingURL=index.d.ts.map |
"use strict"; | ||
import { getAddress } from "@ethersproject/address"; | ||
import { BigNumber } from "@ethersproject/bignumber"; | ||
import { arrayify, hexDataSlice, hexlify, hexZeroPad, isBytesLike, splitSignature, stripZeros, } from "@ethersproject/bytes"; | ||
import { arrayify, hexConcat, hexDataLength, hexDataSlice, hexlify, hexZeroPad, isBytesLike, splitSignature, stripZeros, } from "@ethersproject/bytes"; | ||
import { Zero } from "@ethersproject/constants"; | ||
@@ -26,2 +26,3 @@ import { keccak256 } from "@ethersproject/keccak256"; | ||
} | ||
// Legacy Transaction Fields | ||
const transactionFields = [ | ||
@@ -45,3 +46,66 @@ { name: "nonce", maxLength: 32, numeric: true }, | ||
} | ||
export function serialize(transaction, signature) { | ||
function formatNumber(value, name) { | ||
const result = stripZeros(BigNumber.from(value).toHexString()); | ||
if (result.length > 32) { | ||
logger.throwArgumentError("invalid length for " + name, ("transaction:" + name), value); | ||
} | ||
return result; | ||
} | ||
function accessSetify(addr, storageKeys) { | ||
return { | ||
address: getAddress(addr), | ||
storageKeys: (storageKeys || []).map((storageKey, index) => { | ||
if (hexDataLength(storageKey) !== 32) { | ||
logger.throwArgumentError("invalid access list storageKey", `accessList[${addr}:${index}]`, storageKey); | ||
} | ||
return storageKey.toLowerCase(); | ||
}) | ||
}; | ||
} | ||
export function accessListify(value) { | ||
if (Array.isArray(value)) { | ||
return value.map((set, index) => { | ||
if (Array.isArray(set)) { | ||
if (set.length > 2) { | ||
logger.throwArgumentError("access list expected to be [ address, storageKeys[] ]", `value[${index}]`, set); | ||
} | ||
return accessSetify(set[0], set[1]); | ||
} | ||
return accessSetify(set.address, set.storageKeys); | ||
}); | ||
} | ||
const result = Object.keys(value).map((addr) => { | ||
const storageKeys = value[addr].reduce((accum, storageKey) => { | ||
accum[storageKey] = true; | ||
return accum; | ||
}, {}); | ||
return accessSetify(addr, Object.keys(storageKeys).sort()); | ||
}); | ||
result.sort((a, b) => (a.address.localeCompare(b.address))); | ||
return result; | ||
} | ||
function formatAccessList(value) { | ||
return accessListify(value).map((set) => [set.address, set.storageKeys]); | ||
} | ||
function _serializeEip2930(transaction, signature) { | ||
const fields = [ | ||
formatNumber(transaction.chainId || 0, "chainId"), | ||
formatNumber(transaction.nonce || 0, "nonce"), | ||
formatNumber(transaction.gasPrice || 0, "gasPrice"), | ||
formatNumber(transaction.gasLimit || 0, "gasLimit"), | ||
((transaction.to != null) ? getAddress(transaction.to) : "0x"), | ||
formatNumber(transaction.value || 0, "value"), | ||
(transaction.data || "0x"), | ||
(formatAccessList(transaction.accessList || [])) | ||
]; | ||
if (signature) { | ||
const sig = splitSignature(signature); | ||
fields.push(formatNumber(sig.recoveryParam, "recoveryParam")); | ||
fields.push(stripZeros(sig.r)); | ||
fields.push(stripZeros(sig.s)); | ||
} | ||
return hexConcat(["0x01", RLP.encode(fields)]); | ||
} | ||
// Legacy Transactions and EIP-155 | ||
function _serialize(transaction, signature) { | ||
checkProperties(transaction, allowedTransactionKeys); | ||
@@ -114,3 +178,63 @@ const raw = []; | ||
} | ||
export function parse(rawTransaction) { | ||
export function serialize(transaction, signature) { | ||
// Legacy and EIP-155 Transactions | ||
if (transaction.type == null) { | ||
return _serialize(transaction, signature); | ||
} | ||
// Typed Transactions (EIP-2718) | ||
switch (transaction.type) { | ||
case 1: | ||
return _serializeEip2930(transaction, signature); | ||
default: | ||
break; | ||
} | ||
return logger.throwError(`unsupported transaction type: ${transaction.type}`, Logger.errors.UNSUPPORTED_OPERATION, { | ||
operation: "serializeTransaction", | ||
transactionType: transaction.type | ||
}); | ||
} | ||
function _parseEip2930(payload) { | ||
const transaction = RLP.decode(payload.slice(1)); | ||
if (transaction.length !== 8 && transaction.length !== 11) { | ||
logger.throwArgumentError("invalid component count for transaction type: 1", "payload", hexlify(payload)); | ||
} | ||
const tx = { | ||
type: 1, | ||
chainId: handleNumber(transaction[0]).toNumber(), | ||
nonce: handleNumber(transaction[1]).toNumber(), | ||
gasPrice: handleNumber(transaction[2]), | ||
gasLimit: handleNumber(transaction[3]), | ||
to: handleAddress(transaction[4]), | ||
value: handleNumber(transaction[5]), | ||
data: transaction[6], | ||
accessList: accessListify(transaction[7]), | ||
}; | ||
// Unsigned EIP-2930 Transaction | ||
if (transaction.length === 8) { | ||
return tx; | ||
} | ||
try { | ||
const recid = handleNumber(transaction[8]).toNumber(); | ||
if (recid !== 0 && recid !== 1) { | ||
throw new Error("bad recid"); | ||
} | ||
tx.v = recid; | ||
} | ||
catch (error) { | ||
logger.throwArgumentError("invalid v for transaction type: 1", "v", transaction[8]); | ||
} | ||
tx.r = hexZeroPad(transaction[9], 32); | ||
tx.s = hexZeroPad(transaction[10], 32); | ||
try { | ||
const digest = keccak256(_serializeEip2930(tx)); | ||
tx.from = recoverAddress(digest, { r: tx.r, s: tx.s, recoveryParam: tx.v }); | ||
} | ||
catch (error) { | ||
console.log(error); | ||
} | ||
tx.hash = keccak256(payload); | ||
return tx; | ||
} | ||
// Legacy Transactions and EIP-155 | ||
function _parse(rawTransaction) { | ||
const transaction = RLP.decode(rawTransaction); | ||
@@ -170,4 +294,23 @@ if (transaction.length !== 9 && transaction.length !== 6) { | ||
} | ||
tx.type = null; | ||
return tx; | ||
} | ||
export function parse(rawTransaction) { | ||
const payload = arrayify(rawTransaction); | ||
// Legacy and EIP-155 Transactions | ||
if (payload[0] > 0x7f) { | ||
return _parse(payload); | ||
} | ||
// Typed Transaction (EIP-2718) | ||
switch (payload[0]) { | ||
case 1: | ||
return _parseEip2930(payload); | ||
default: | ||
break; | ||
} | ||
return logger.throwError(`unsupported transaction type: ${payload[0]}`, Logger.errors.UNSUPPORTED_OPERATION, { | ||
operation: "parseTransaction", | ||
transactionType: payload[0] | ||
}); | ||
} | ||
//# sourceMappingURL=index.js.map |
@@ -1,2 +0,2 @@ | ||
export declare const version = "transactions/5.0.11"; | ||
export declare const version = "transactions/5.1.0"; | ||
//# sourceMappingURL=_version.d.ts.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.version = void 0; | ||
exports.version = "transactions/5.0.11"; | ||
exports.version = "transactions/5.1.0"; | ||
//# sourceMappingURL=_version.js.map |
import { BigNumber, BigNumberish } from "@ethersproject/bignumber"; | ||
import { BytesLike, SignatureLike } from "@ethersproject/bytes"; | ||
export declare type AccessList = Array<{ | ||
address: string; | ||
storageKeys: Array<string>; | ||
}>; | ||
export declare type AccessListish = AccessList | Array<[string, Array<string>]> | Record<string, Array<string>>; | ||
export declare type UnsignedTransaction = { | ||
@@ -11,2 +16,4 @@ to?: string; | ||
chainId?: number; | ||
type?: number | null; | ||
accessList?: AccessListish; | ||
}; | ||
@@ -26,7 +33,10 @@ export interface Transaction { | ||
v?: number; | ||
type?: number | null; | ||
accessList?: AccessList; | ||
} | ||
export declare function computeAddress(key: BytesLike | string): string; | ||
export declare function recoverAddress(digest: BytesLike, signature: SignatureLike): string; | ||
export declare function accessListify(value: AccessListish): AccessList; | ||
export declare function serialize(transaction: UnsignedTransaction, signature?: SignatureLike): string; | ||
export declare function parse(rawTransaction: BytesLike): Transaction; | ||
//# sourceMappingURL=index.d.ts.map |
150
lib/index.js
@@ -22,3 +22,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.parse = exports.serialize = exports.recoverAddress = exports.computeAddress = void 0; | ||
exports.parse = exports.serialize = exports.accessListify = exports.recoverAddress = exports.computeAddress = void 0; | ||
var address_1 = require("@ethersproject/address"); | ||
@@ -48,2 +48,3 @@ var bignumber_1 = require("@ethersproject/bignumber"); | ||
} | ||
// Legacy Transaction Fields | ||
var transactionFields = [ | ||
@@ -69,3 +70,67 @@ { name: "nonce", maxLength: 32, numeric: true }, | ||
exports.recoverAddress = recoverAddress; | ||
function serialize(transaction, signature) { | ||
function formatNumber(value, name) { | ||
var result = bytes_1.stripZeros(bignumber_1.BigNumber.from(value).toHexString()); | ||
if (result.length > 32) { | ||
logger.throwArgumentError("invalid length for " + name, ("transaction:" + name), value); | ||
} | ||
return result; | ||
} | ||
function accessSetify(addr, storageKeys) { | ||
return { | ||
address: address_1.getAddress(addr), | ||
storageKeys: (storageKeys || []).map(function (storageKey, index) { | ||
if (bytes_1.hexDataLength(storageKey) !== 32) { | ||
logger.throwArgumentError("invalid access list storageKey", "accessList[" + addr + ":" + index + "]", storageKey); | ||
} | ||
return storageKey.toLowerCase(); | ||
}) | ||
}; | ||
} | ||
function accessListify(value) { | ||
if (Array.isArray(value)) { | ||
return value.map(function (set, index) { | ||
if (Array.isArray(set)) { | ||
if (set.length > 2) { | ||
logger.throwArgumentError("access list expected to be [ address, storageKeys[] ]", "value[" + index + "]", set); | ||
} | ||
return accessSetify(set[0], set[1]); | ||
} | ||
return accessSetify(set.address, set.storageKeys); | ||
}); | ||
} | ||
var result = Object.keys(value).map(function (addr) { | ||
var storageKeys = value[addr].reduce(function (accum, storageKey) { | ||
accum[storageKey] = true; | ||
return accum; | ||
}, {}); | ||
return accessSetify(addr, Object.keys(storageKeys).sort()); | ||
}); | ||
result.sort(function (a, b) { return (a.address.localeCompare(b.address)); }); | ||
return result; | ||
} | ||
exports.accessListify = accessListify; | ||
function formatAccessList(value) { | ||
return accessListify(value).map(function (set) { return [set.address, set.storageKeys]; }); | ||
} | ||
function _serializeEip2930(transaction, signature) { | ||
var fields = [ | ||
formatNumber(transaction.chainId || 0, "chainId"), | ||
formatNumber(transaction.nonce || 0, "nonce"), | ||
formatNumber(transaction.gasPrice || 0, "gasPrice"), | ||
formatNumber(transaction.gasLimit || 0, "gasLimit"), | ||
((transaction.to != null) ? address_1.getAddress(transaction.to) : "0x"), | ||
formatNumber(transaction.value || 0, "value"), | ||
(transaction.data || "0x"), | ||
(formatAccessList(transaction.accessList || [])) | ||
]; | ||
if (signature) { | ||
var sig = bytes_1.splitSignature(signature); | ||
fields.push(formatNumber(sig.recoveryParam, "recoveryParam")); | ||
fields.push(bytes_1.stripZeros(sig.r)); | ||
fields.push(bytes_1.stripZeros(sig.s)); | ||
} | ||
return bytes_1.hexConcat(["0x01", RLP.encode(fields)]); | ||
} | ||
// Legacy Transactions and EIP-155 | ||
function _serialize(transaction, signature) { | ||
properties_1.checkProperties(transaction, allowedTransactionKeys); | ||
@@ -138,4 +203,64 @@ var raw = []; | ||
} | ||
function serialize(transaction, signature) { | ||
// Legacy and EIP-155 Transactions | ||
if (transaction.type == null) { | ||
return _serialize(transaction, signature); | ||
} | ||
// Typed Transactions (EIP-2718) | ||
switch (transaction.type) { | ||
case 1: | ||
return _serializeEip2930(transaction, signature); | ||
default: | ||
break; | ||
} | ||
return logger.throwError("unsupported transaction type: " + transaction.type, logger_1.Logger.errors.UNSUPPORTED_OPERATION, { | ||
operation: "serializeTransaction", | ||
transactionType: transaction.type | ||
}); | ||
} | ||
exports.serialize = serialize; | ||
function parse(rawTransaction) { | ||
function _parseEip2930(payload) { | ||
var transaction = RLP.decode(payload.slice(1)); | ||
if (transaction.length !== 8 && transaction.length !== 11) { | ||
logger.throwArgumentError("invalid component count for transaction type: 1", "payload", bytes_1.hexlify(payload)); | ||
} | ||
var tx = { | ||
type: 1, | ||
chainId: handleNumber(transaction[0]).toNumber(), | ||
nonce: handleNumber(transaction[1]).toNumber(), | ||
gasPrice: handleNumber(transaction[2]), | ||
gasLimit: handleNumber(transaction[3]), | ||
to: handleAddress(transaction[4]), | ||
value: handleNumber(transaction[5]), | ||
data: transaction[6], | ||
accessList: accessListify(transaction[7]), | ||
}; | ||
// Unsigned EIP-2930 Transaction | ||
if (transaction.length === 8) { | ||
return tx; | ||
} | ||
try { | ||
var recid = handleNumber(transaction[8]).toNumber(); | ||
if (recid !== 0 && recid !== 1) { | ||
throw new Error("bad recid"); | ||
} | ||
tx.v = recid; | ||
} | ||
catch (error) { | ||
logger.throwArgumentError("invalid v for transaction type: 1", "v", transaction[8]); | ||
} | ||
tx.r = bytes_1.hexZeroPad(transaction[9], 32); | ||
tx.s = bytes_1.hexZeroPad(transaction[10], 32); | ||
try { | ||
var digest = keccak256_1.keccak256(_serializeEip2930(tx)); | ||
tx.from = recoverAddress(digest, { r: tx.r, s: tx.s, recoveryParam: tx.v }); | ||
} | ||
catch (error) { | ||
console.log(error); | ||
} | ||
tx.hash = keccak256_1.keccak256(payload); | ||
return tx; | ||
} | ||
// Legacy Transactions and EIP-155 | ||
function _parse(rawTransaction) { | ||
var transaction = RLP.decode(rawTransaction); | ||
@@ -195,5 +320,24 @@ if (transaction.length !== 9 && transaction.length !== 6) { | ||
} | ||
tx.type = null; | ||
return tx; | ||
} | ||
function parse(rawTransaction) { | ||
var payload = bytes_1.arrayify(rawTransaction); | ||
// Legacy and EIP-155 Transactions | ||
if (payload[0] > 0x7f) { | ||
return _parse(payload); | ||
} | ||
// Typed Transaction (EIP-2718) | ||
switch (payload[0]) { | ||
case 1: | ||
return _parseEip2930(payload); | ||
default: | ||
break; | ||
} | ||
return logger.throwError("unsupported transaction type: " + payload[0], logger_1.Logger.errors.UNSUPPORTED_OPERATION, { | ||
operation: "parseTransaction", | ||
transactionType: payload[0] | ||
}); | ||
} | ||
exports.parse = parse; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"author": "Richard Moore <me@ricmoo.com>", | ||
"dependencies": { | ||
"@ethersproject/address": "^5.0.9", | ||
"@ethersproject/bignumber": "^5.0.13", | ||
"@ethersproject/bytes": "^5.0.9", | ||
"@ethersproject/constants": "^5.0.8", | ||
"@ethersproject/keccak256": "^5.0.7", | ||
"@ethersproject/logger": "^5.0.8", | ||
"@ethersproject/properties": "^5.0.7", | ||
"@ethersproject/rlp": "^5.0.7", | ||
"@ethersproject/signing-key": "^5.0.8" | ||
"@ethersproject/address": "^5.1.0", | ||
"@ethersproject/bignumber": "^5.1.0", | ||
"@ethersproject/bytes": "^5.1.0", | ||
"@ethersproject/constants": "^5.1.0", | ||
"@ethersproject/keccak256": "^5.1.0", | ||
"@ethersproject/logger": "^5.1.0", | ||
"@ethersproject/properties": "^5.1.0", | ||
"@ethersproject/rlp": "^5.1.0", | ||
"@ethersproject/signing-key": "^5.1.0" | ||
}, | ||
@@ -26,3 +26,3 @@ "description": "Utilities for decoding and encoding Ethereum transaction for ethers.", | ||
], | ||
"gitHead": "6c43e20e7a68f3f5a141c74527ec63d9fe8458be", | ||
"gitHead": "3b1d3fcee6bfb5178861e26ff1a1e9daa0663ec9", | ||
"keywords": [ | ||
@@ -48,5 +48,5 @@ "Ethereum", | ||
"sideEffects": false, | ||
"tarballHash": "0x826a4b29d124329797ed54f00e1b48c246c2c148ed88ef449e16d30df72574fd", | ||
"tarballHash": "0xfcc7bf02b3381db31f124dd3b0cfcfa12e70b371e86b45238bc125e8d8e41d87", | ||
"types": "./lib/index.d.ts", | ||
"version": "5.0.11" | ||
"version": "5.1.0" | ||
} |
@@ -1,1 +0,1 @@ | ||
export const version = "transactions/5.0.11"; | ||
export const version = "transactions/5.1.0"; |
@@ -5,3 +5,3 @@ "use strict"; | ||
import { BigNumber, BigNumberish } from "@ethersproject/bignumber"; | ||
import { arrayify, BytesLike, DataOptions, hexDataSlice, hexlify, hexZeroPad, isBytesLike, SignatureLike, splitSignature, stripZeros, } from "@ethersproject/bytes"; | ||
import { arrayify, BytesLike, DataOptions, hexConcat, hexDataLength, hexDataSlice, hexlify, hexZeroPad, isBytesLike, SignatureLike, splitSignature, stripZeros, } from "@ethersproject/bytes"; | ||
import { Zero } from "@ethersproject/constants"; | ||
@@ -20,2 +20,9 @@ import { keccak256 } from "@ethersproject/keccak256"; | ||
export type AccessList = Array<{ address: string, storageKeys: Array<string> }>; | ||
// Input allows flexibility in describing an access list | ||
export type AccessListish = AccessList | | ||
Array<[ string, Array<string> ]> | | ||
Record<string, Array<string>>; | ||
export type UnsignedTransaction = { | ||
@@ -31,2 +38,6 @@ to?: string; | ||
chainId?: number; | ||
// Typed-Transaction features | ||
type?: number | null; | ||
accessList?: AccessListish; | ||
} | ||
@@ -51,2 +62,8 @@ | ||
v?: number; | ||
// Typed-Transaction features | ||
type?: number | null; | ||
// EIP-2930; Type 1 | ||
accessList?: AccessList; | ||
} | ||
@@ -66,2 +83,3 @@ | ||
// Legacy Transaction Fields | ||
const transactionFields = [ | ||
@@ -89,4 +107,74 @@ { name: "nonce", maxLength: 32, numeric: true }, | ||
function formatNumber(value: BigNumberish, name: string): Uint8Array { | ||
const result = stripZeros(BigNumber.from(value).toHexString()); | ||
if (result.length > 32) { | ||
logger.throwArgumentError("invalid length for " + name, ("transaction:" + name), value); | ||
} | ||
return result; | ||
} | ||
export function serialize(transaction: UnsignedTransaction, signature?: SignatureLike): string { | ||
function accessSetify(addr: string, storageKeys: Array<string>): { address: string,storageKeys: Array<string> } { | ||
return { | ||
address: getAddress(addr), | ||
storageKeys: (storageKeys || []).map((storageKey, index) => { | ||
if (hexDataLength(storageKey) !== 32) { | ||
logger.throwArgumentError("invalid access list storageKey", `accessList[${ addr }:${ index }]`, storageKey) | ||
} | ||
return storageKey.toLowerCase(); | ||
}) | ||
}; | ||
} | ||
export function accessListify(value: AccessListish): AccessList { | ||
if (Array.isArray(value)) { | ||
return (<Array<[ string, Array<string>] | { address: string, storageKeys: Array<string>}>>value).map((set, index) => { | ||
if (Array.isArray(set)) { | ||
if (set.length > 2) { | ||
logger.throwArgumentError("access list expected to be [ address, storageKeys[] ]", `value[${ index }]`, set); | ||
} | ||
return accessSetify(set[0], set[1]) | ||
} | ||
return accessSetify(set.address, set.storageKeys); | ||
}); | ||
} | ||
const result: Array<{ address: string, storageKeys: Array<string> }> = Object.keys(value).map((addr) => { | ||
const storageKeys: Record<string, true> = value[addr].reduce((accum, storageKey) => { | ||
accum[storageKey] = true; | ||
return accum; | ||
}, <Record<string, true>>{ }); | ||
return accessSetify(addr, Object.keys(storageKeys).sort()) | ||
}); | ||
result.sort((a, b) => (a.address.localeCompare(b.address))); | ||
return result; | ||
} | ||
function formatAccessList(value: AccessListish): Array<[ string, Array<string> ]> { | ||
return accessListify(value).map((set) => [ set.address, set.storageKeys ]); | ||
} | ||
function _serializeEip2930(transaction: UnsignedTransaction, signature?: SignatureLike): string { | ||
const fields: any = [ | ||
formatNumber(transaction.chainId || 0, "chainId"), | ||
formatNumber(transaction.nonce || 0, "nonce"), | ||
formatNumber(transaction.gasPrice || 0, "gasPrice"), | ||
formatNumber(transaction.gasLimit || 0, "gasLimit"), | ||
((transaction.to != null) ? getAddress(transaction.to): "0x"), | ||
formatNumber(transaction.value || 0, "value"), | ||
(transaction.data || "0x"), | ||
(formatAccessList(transaction.accessList || [])) | ||
]; | ||
if (signature) { | ||
const sig = splitSignature(signature); | ||
fields.push(formatNumber(sig.recoveryParam, "recoveryParam")); | ||
fields.push(stripZeros(sig.r)); | ||
fields.push(stripZeros(sig.s)); | ||
} | ||
return hexConcat([ "0x01", RLP.encode(fields)]); | ||
} | ||
// Legacy Transactions and EIP-155 | ||
function _serialize(transaction: UnsignedTransaction, signature?: SignatureLike): string { | ||
checkProperties(transaction, allowedTransactionKeys); | ||
@@ -171,3 +259,66 @@ | ||
export function parse(rawTransaction: BytesLike): Transaction { | ||
export function serialize(transaction: UnsignedTransaction, signature?: SignatureLike): string { | ||
// Legacy and EIP-155 Transactions | ||
if (transaction.type == null) { return _serialize(transaction, signature); } | ||
// Typed Transactions (EIP-2718) | ||
switch (transaction.type) { | ||
case 1: | ||
return _serializeEip2930(transaction, signature); | ||
default: | ||
break; | ||
} | ||
return logger.throwError(`unsupported transaction type: ${ transaction.type }`, Logger.errors.UNSUPPORTED_OPERATION, { | ||
operation: "serializeTransaction", | ||
transactionType: transaction.type | ||
}); | ||
} | ||
function _parseEip2930(payload: Uint8Array): Transaction { | ||
const transaction = RLP.decode(payload.slice(1)); | ||
if (transaction.length !== 8 && transaction.length !== 11) { | ||
logger.throwArgumentError("invalid component count for transaction type: 1", "payload", hexlify(payload)); | ||
} | ||
const tx: Transaction = { | ||
type: 1, | ||
chainId: handleNumber(transaction[0]).toNumber(), | ||
nonce: handleNumber(transaction[1]).toNumber(), | ||
gasPrice: handleNumber(transaction[2]), | ||
gasLimit: handleNumber(transaction[3]), | ||
to: handleAddress(transaction[4]), | ||
value: handleNumber(transaction[5]), | ||
data: transaction[6], | ||
accessList: accessListify(transaction[7]), | ||
}; | ||
// Unsigned EIP-2930 Transaction | ||
if (transaction.length === 8) { return tx; } | ||
try { | ||
const recid = handleNumber(transaction[8]).toNumber(); | ||
if (recid !== 0 && recid !== 1) { throw new Error("bad recid"); } | ||
tx.v = recid; | ||
} catch (error) { | ||
logger.throwArgumentError("invalid v for transaction type: 1", "v", transaction[8]); | ||
} | ||
tx.r = hexZeroPad(transaction[9], 32); | ||
tx.s = hexZeroPad(transaction[10], 32); | ||
try { | ||
const digest = keccak256(_serializeEip2930(tx)); | ||
tx.from = recoverAddress(digest, { r: tx.r, s: tx.s, recoveryParam: tx.v }); | ||
} catch (error) { | ||
console.log(error); | ||
} | ||
tx.hash = keccak256(payload); | ||
return tx; | ||
} | ||
// Legacy Transactions and EIP-155 | ||
function _parse(rawTransaction: Uint8Array): Transaction { | ||
const transaction = RLP.decode(rawTransaction); | ||
@@ -235,4 +386,27 @@ | ||
tx.type = null; | ||
return tx; | ||
} | ||
export function parse(rawTransaction: BytesLike): Transaction { | ||
const payload = arrayify(rawTransaction); | ||
// Legacy and EIP-155 Transactions | ||
if (payload[0] > 0x7f) { return _parse(payload); } | ||
// Typed Transaction (EIP-2718) | ||
switch (payload[0]) { | ||
case 1: | ||
return _parseEip2930(payload); | ||
default: | ||
break; | ||
} | ||
return logger.throwError(`unsupported transaction type: ${ payload[0] }`, Logger.errors.UNSUPPORTED_OPERATION, { | ||
operation: "parseTransaction", | ||
transactionType: payload[0] | ||
}); | ||
} | ||
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
71976
1057
Updated@ethersproject/bytes@^5.1.0
Updated@ethersproject/logger@^5.1.0
Updated@ethersproject/rlp@^5.1.0