Vectorized / solady

Optimized Solidity snippets.
MIT License
2.51k stars 339 forks source link

✨ RLP encoding #975

Closed Vectorized closed 2 months ago

Vectorized commented 3 months ago

Update: scroll down for the final API.

RogerPodacter commented 3 months ago

I love it! Though speaking as a representative of the sheeple (and a sherson myself) I wonder if they would find it more intuitive if we wrapped your API in something like this, so that users could call .encodeRLP() on anything without worrying about types and could also build lists using the famous p() approach.

Thoughts?

contract MyContract {
    using LibRLP for LibRLP.RLPList;
    using LibRLP for *;

    struct AccessListEntry {
        address addr;
        bytes32[] storageKeys;
    }

    struct EIP1559Transaction {
        uint256 nonce;
        uint256 maxPriorityFeePerGas;
        uint256 maxFeePerGas;
        uint256 gasLimit;
        address to;
        uint256 value;
        bytes data;
        AccessListEntry[] accessList;
        uint256 chainId;
        bytes r;
        bytes s;
        uint256 v;
    }

    function encodeEIP1559Transaction(EIP1559Transaction memory tx) public pure returns (bytes memory) {
        LibRLP.RLPList memory list;

        // Can also encode single item with
        // tx.nonce.encodeRLP();

        list.p(tx.nonce);
        list.p(tx.maxPriorityFeePerGas);
        list.p(tx.maxFeePerGas);
        list.p(tx.gasLimit);
        list.p(tx.to);
        list.p(tx.value);
        list.p(tx.data);

        // Encode access list
        LibRLP.RLPList memory accessList;
        for (uint i = 0; i < tx.accessList.length; i++) {
            LibRLP.RLPList memory accessListEntry;

            accessListEntry.p(tx.accessList[i].addr);

            LibRLP.RLPList memory storageKeys;
            for (uint j = 0; j < tx.accessList[i].storageKeys.length; j++) {
                storageKeys.p(tx.accessList[i].storageKeys[j]);
            }

            accessListEntry.p(storageKeys);
            accessList.p(accessListEntry);
        }
        list.p(accessList);

        list.p(tx.chainId);
        list.p(tx.r);
        list.p(tx.s);
        list.p(tx.v);

        return list.toRLP();
    }
}
Vectorized commented 3 months ago

Final API has already been merged.

I like the p. It's the most elegant API.

Let's go with it.

Vectorized commented 3 months ago
    function encodeEIP1559Transaction(EIP1559Transaction memory txn)
        public
        pure
        returns (bytes memory)
    {
        LibRLP.List memory list;
        list.p(txn.nonce);
        list.p(txn.maxPriorityFeePerGas).p(txn.maxFeePerGas).p(txn.gasLimit);
        list.p(txn.to).p(txn.value).p(txn.data);
        LibRLP.List memory accessList;
        for (uint256 i = 0; i < txn.accessList.length; i++) {
            LibRLP.List memory storageKeys;
            for (uint256 j = 0; j < txn.accessList[i].storageKeys.length; j++) {
                storageKeys.p(uint256(txn.accessList[i].storageKeys[j]));
            }
            accessList.p(LibRLP.l(txn.accessList[i].addr).p(storageKeys));
        }
        list.p(accessList);
        list.p(txn.chainId);
        list.p(txn.r).p(txn.s).p(txn.v);
        return list.encode();
    }

Added some extra shorthands like l to make things even more concise.

@RogerPodacter