Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP]Feat: add EIP-1559 transaction type #12

4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ contract Example {
});

// Encode to RLP
bytes memory rlp = Transactions.encodeRLP(legacyTxn0);
bytes memory rlp = Transactions.encodeLegacyRLP(legacyTxn0);

// Decode from RLP
Transactions.Legacy memory legacyTxn1 = Transactions.decodeRLP(rlp);
Transactions.Legacy memory legacyTxn1 = Transactions.decodeLegacyRLP(rlp);
}
}
```
69 changes: 67 additions & 2 deletions src/Transactions.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,22 @@ library Transactions {
bytes v;
}

function encodeRLP(Legacy memory txStruct) internal pure returns (bytes memory) {
struct EIP1559 {
address to;
uint64 gas;
uint64 maxFeePerGas;
uint64 maxPriorityFeePerGas;
uint64 value;
uint64 nonce;
bytes data;
uint64 chainId;
bytes[] accessList;
bytes r;
bytes s;
bytes v;
}

function encodeLegacyRLP(Legacy memory txStruct) internal pure returns (bytes memory) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you keep the same name here? I imagine having the same encodeRLP name overloaded for both transactions.

bytes[] memory items = new bytes[](9);

items[0] = RLPWriter.writeUint(txStruct.nonce);
Expand All @@ -38,7 +53,26 @@ library Transactions {
return RLPWriter.writeList(items);
}

function decodeRLP(bytes memory rlp) internal pure returns (Legacy memory) {
function encodeRLP(EIP1559 memory txStruct) internal pure returns (bytes memory) {
bytes[] memory items = new bytes[](12);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this encoding correct? EIP-1559 transactions are encoded with EIP-2718 format, so it needs to have the transaction type prefixed. You can find a code reference here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just fixed this, lmk if it is still not correct.


items[0] = RLPWriter.writeUint(txStruct.chainId);
items[1] = RLPWriter.writeUint(txStruct.nonce);
items[2] = RLPWriter.writeUint(txStruct.maxPriorityFeePerGas);
items[3] = RLPWriter.writeUint(txStruct.maxFeePerGas);
items[4] = RLPWriter.writeUint(txStruct.gas);
items[5] = RLPWriter.writeAddress(txStruct.to);
items[6] = RLPWriter.writeUint(txStruct.value);
items[7] = RLPWriter.writeBytes(txStruct.data);
items[8] = RLPWriter.writeList(txStruct.accessList);
items[9] = RLPWriter.writeBytes(txStruct.v);
items[10] = RLPWriter.writeBytes(txStruct.r);
items[11] = RLPWriter.writeBytes(txStruct.s);

return RLPWriter.writeList(items);
}

function decodeLegacyRLP(bytes memory rlp) internal pure returns (Legacy memory) {
Legacy memory txStruct;

RLPReader.RLPItem[] memory ls = rlp.toRlpItem().toList();
Expand All @@ -56,4 +90,35 @@ library Transactions {

return txStruct;
}

function decodeRLP(bytes memory rlp) internal pure returns (EIP1559 memory) {
EIP1559 memory txStruct;

RLPReader.RLPItem[] memory ls = rlp.toRlpItem().toList();
require(ls.length == 12, "invalid transaction");

txStruct.chainId = uint64(ls[0].toUint());
txStruct.nonce = uint64(ls[1].toUint());
txStruct.maxPriorityFeePerGas = uint64(ls[2].toUint());
txStruct.maxFeePerGas = uint64(ls[3].toUint());
txStruct.gas = uint64(ls[4].toUint());
txStruct.to = ls[5].toAddress();
txStruct.value = uint64(ls[6].toUint());
txStruct.data = ls[7].toBytes();

// Decode accessList
RLPReader.RLPItem[] memory accessListItems = ls[8].toBytes().toRlpItem().toList();
uint256 numAccessListItems = accessListItems.length;
txStruct.accessList = new bytes[](numAccessListItems);

for (uint256 i; i < numAccessListItems; i++) {
txStruct.accessList[i] = accessListItems[i].toBytes();
}

txStruct.v = ls[9].toBytes();
txStruct.r = ls[10].toBytes();
txStruct.s = ls[11].toBytes();

return txStruct;
}
}
6 changes: 3 additions & 3 deletions test/Transactions.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,17 @@ contract TestTransactions is Test {
s: abi.encodePacked(hex"8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1")
});

bytes memory rlp = Transactions.encodeRLP(legacyTxn0);
bytes memory rlp = Transactions.encodeLegacyRLP(legacyTxn0);

bytes memory expected = abi.encodePacked(
hex"f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba09bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094fa08a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1"
);
assertEq0(rlp, expected);

Transactions.Legacy memory legacyTxn1 = Transactions.decodeRLP(rlp);
Transactions.Legacy memory legacyTxn1 = Transactions.decodeLegacyRLP(rlp);

// re-encode to validate that the decoding was correct
bytes memory rlp1 = Transactions.encodeRLP(legacyTxn1);
bytes memory rlp1 = Transactions.encodeLegacyRLP(legacyTxn1);
assertEq0(rlp1, expected);
}
}