Skip to content

Commit

Permalink
✨ LibERC7579 reencodeBatch (#1187)
Browse files Browse the repository at this point in the history
  • Loading branch information
Vectorized authored Nov 28, 2024
1 parent a97a17a commit 82e14c6
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 1 deletion.
31 changes: 30 additions & 1 deletion src/accounts/LibERC7579.sol
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ library LibERC7579 {
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EXECUTION DATA DECODING OPERATIONS */
/* EXECUTION DATA OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

/// @dev Decodes a single call execution.
Expand Down Expand Up @@ -270,6 +270,35 @@ library LibERC7579 {
}
}

/// @dev Reencodes `executionData` such that it has `opData` added to it.
/// Like `abi.encode(abi.decode(executionData, (Call[])), opData)`.
/// Useful for forwarding `executionData` with extra `opData`.
/// This function does not perform any check on the validity of `executionData`.
function reencodeBatch(bytes calldata executionData, bytes memory opData)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let s := calldataload(executionData.offset) // Offset of `calls`.
let n := sub(executionData.length, s) // Byte length of `calls`.
mstore(add(result, 0x20), 0x40) // Store the new offset of `calls`.
calldatacopy(add(result, 0x60), add(executionData.offset, s), n)
mstore(add(result, 0x40), add(0x40, n)) // Store the new offset of `opData`.
let o := add(add(result, 0x60), n) // Start offset of `opData` in memory.
let d := sub(opData, o) // Offset difference between `opData` and `o`.
for { let end := add(mload(opData), add(0x20, o)) } 1 {} {
mstore(o, mload(add(o, d)))
o := add(o, 0x20)
if iszero(lt(o, end)) { break }
}
mstore(result, sub(o, add(result, 0x20))) // Store the length of `result`.
mstore(0x40, o) // Allocate memory.
}
}

/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
Expand Down
35 changes: 35 additions & 0 deletions test/LibERC7579.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,41 @@ contract LibERC7579Test is SoladyTest {
assertEq(t.value, calls[i].value);
assertEq(t.data, calls[i].data);
}

if (_randomChance(2)) {
bytes memory executionData;
if (_randomChance(2)) {
executionData = abi.encode(calls);
} else {
executionData = abi.encode(calls, opData);
}
opData = _truncateBytes(_randomBytes(), 0x1ff);
(t.calls, t.opData) = this.reencodeBatchAndDecodeBatch(executionData, opData);
for (uint256 i; i != calls.length; ++i) {
assertEq(t.calls[i].target, calls[i].target);
assertEq(t.calls[i].value, calls[i].value);
assertEq(t.calls[i].data, calls[i].data);
}
assertEq(t.opData, opData);
}
}

function reencodeBatchAndDecodeBatch(bytes calldata executionData, bytes memory opData)
public
returns (Call[] memory, bytes memory)
{
bytes memory reencoded;
if (_randomChance(2)) {
reencoded = LibERC7579.reencodeBatch(executionData, opData);
} else {
reencoded = abi.encode(abi.decode(executionData, (Call[])), opData);
}
_checkMemory(reencoded);
if (_randomChance(2)) {
return this.decodeBatchAndOpData(reencoded);
} else {
return abi.decode(reencoded, (Call[], bytes));
}
}

function decodeBatch(bytes calldata executionData) public pure returns (Call[] memory) {
Expand Down

0 comments on commit 82e14c6

Please sign in to comment.