Skip to content

Commit

Permalink
Tidy and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Vectorized committed Jan 20, 2025
1 parent 22a348b commit df4df75
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 44 deletions.
2 changes: 1 addition & 1 deletion lib/solady
Submodule solady updated 80 files
+4 −2 .github/workflows/ci.yml
+6 −0 README.md
+9 −4 docs/accounts/erc4337factory.md
+20 −2 docs/accounts/erc7821.md
+8 −0 docs/accounts/liberc7579.md
+17 −0 docs/accounts/timelock.md
+22 −2 docs/index.html
+1 −1 docs/sidebar.md
+4 −4 docs/tokens/erc20votes.md
+33 −0 docs/utils/dynamicarraylib.md
+3 −0 docs/utils/enumerablesetlib.md
+1 −1 docs/utils/initializable.md
+33 −0 docs/utils/libbit.md
+1 −1 docs/utils/libclone.md
+42 −2 docs/utils/libsort.md
+1 −1 docs/utils/libtransient.md
+7 −1 docs/utils/minheaplib.md
+1 −1 docs/utils/p256.md
+38 −1 docs/utils/safetransferlib.md
+8 −8 docs/utils/signaturecheckerlib.md
+11 −11 ext/wake/test_erc1155.py
+7 −2 foundry.toml
+1 −1 package.json
+63 −0 prep/zksync-compat-analysis.js
+4 −2 src/accounts/ERC4337.sol
+9 −10 src/accounts/ERC4337Factory.sol
+37 −20 src/accounts/ERC7821.sol
+3 −0 src/accounts/LibERC7579.sol
+1 −0 src/accounts/Receiver.sol
+42 −0 src/accounts/Timelock.sol
+5 −5 src/tokens/ERC20Votes.sol
+1,143 −0 src/tokens/ext/zksync/ERC1155.sol
+915 −0 src/tokens/ext/zksync/ERC721.sol
+34 −2 src/utils/DynamicArrayLib.sol
+3 −2 src/utils/EnumerableSetLib.sol
+11 −1 src/utils/Initializable.sol
+24 −0 src/utils/LibBit.sol
+6 −6 src/utils/LibClone.sol
+58 −1 src/utils/LibSort.sol
+1 −1 src/utils/LibTransient.sol
+3 −3 src/utils/LibZip.sol
+32 −23 src/utils/MinHeapLib.sol
+1 −1 src/utils/Multicallable.sol
+1 −1 src/utils/P256.sol
+6 −5 src/utils/RedBlackTreeLib.sol
+48 −2 src/utils/SafeTransferLib.sol
+84 −76 src/utils/SignatureCheckerLib.sol
+1 −0 src/utils/UUPSUpgradeable.sol
+1 −1 src/utils/ext/delegatexyz/DelegateCheckerLib.sol
+6 −60 src/utils/ext/ithaca/BLS.sol
+78 −0 src/utils/ext/zksync/ERC1967BeaconProxy.sol
+457 −0 src/utils/ext/zksync/ERC1967Factory.sol
+9 −0 src/utils/ext/zksync/ERC1967FactoryConstants.sol
+82 −0 src/utils/ext/zksync/ERC1967Proxy.sol
+387 −0 src/utils/ext/zksync/SafeTransferLib.sol
+367 −0 src/utils/ext/zksync/SignatureCheckerLib.sol
+50 −0 src/utils/ext/zksync/SingleUseETHVault.sol
+62 −0 src/utils/ext/zksync/UpgradeableBeacon.sol
+301 −0 src/utils/ext/zksync/delegatexyz/DelegateCheckerLib.sol
+34 −2 src/utils/g/DynamicArrayLib.sol
+3 −2 src/utils/g/EnumerableSetLib.sol
+1 −1 src/utils/g/LibTransient.sol
+32 −23 src/utils/g/MinHeapLib.sol
+6 −5 src/utils/g/RedBlackTreeLib.sol
+17 −1 test/DynamicArrayLib.t.sol
+14 −24 test/ERC4337Factory.t.sol
+52 −0 test/LibBit.t.sol
+60 −0 test/LibSort.t.sol
+1 −1 test/P256.t.sol
+47 −1 test/SafeTransferLib.t.sol
+7 −3 test/SignatureCheckerLib.t.sol
+2 −0 test/Timelock.t.sol
+34 −6 test/ext/ithaca/BLS.t.sol
+1,221 −0 test/ext/zksync/ERC1155.t.sol
+104 −0 test/ext/zksync/ERC1967Factory.t.sol
+1,005 −0 test/ext/zksync/ERC721.t.sol
+789 −0 test/ext/zksync/SafeTransferLib.t.sol
+387 −0 test/ext/zksync/SignatureCheckerLib.t.sol
+124 −0 test/utils/mocks/ext/zksync/MockERC1155.sol
+139 −0 test/utils/mocks/ext/zksync/MockERC721.sol
2 changes: 1 addition & 1 deletion src/MessageHubLibV1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ library MessageHubLibV1 {
/*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

/// @dev Returns the sender or signer.
/// Note: this function will never return a zero address.
/// Note: this function will never return a zero address.
function senderOrSigner() internal view returns (address result) {
result = LibMulticaller.senderOrSigner();
if (result == MESSAGE_HUB) {
Expand Down
23 changes: 17 additions & 6 deletions src/MessageHubV1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity ^0.8.23;
import {UUPSUpgradeable} from "solady/utils/UUPSUpgradeable.sol";
import {SafeTransferLib} from "solady/utils/SafeTransferLib.sol";
import {LibClone} from "solady/utils/LibClone.sol";
import {LibBytes} from "solady/utils/LibBytes.sol";
import {ERC7821} from "solady/accounts/ERC7821.sol";
import {Origin, OAppReceiverUpgradeable} from "layerzero-oapp/contracts/oapp-upgradeable/OAppReceiverUpgradeable.sol";

Expand Down Expand Up @@ -108,13 +109,21 @@ contract MessageHubV1 is UUPSUpgradeable, OAppReceiverUpgradeable {
return LibClone.predictDeterministicAddress(_podImplementation, args, keccak256(args), address(this));
}

/// @dev For efficiency, we will use the receive function
/// to return the original sender and the sender.
/// @dev Returns `abi.encode(sender, originalSender, originalSenderType)`.
/// This is queried by the MessageHubPodV1 or contracts that use MessageHubLibV1.
receive() external payable {
assembly ("memory-safe") {
mstore(0x40, tload(_ORIGINAL_SENDER_TYPE_TRANSIENT_SLOT))
mstore(0x20, tload(_ORIGINAL_SENDER_TRANSIENT_SLOT))
// The `sender` can be either:
// - A MessageHubPodV1 that is deployed on-the-fly if the
// message was initiated from a non-Ethereum address.
// - An Ethereum address that initiated the message.
//
// The `originalSender` can be either:
// - A non-Ethereum address.
// - An Ethereum address that matches `sender`.
mstore(0x00, tload(_SENDER_TRANSIENT_SLOT))
mstore(0x20, tload(_ORIGINAL_SENDER_TRANSIENT_SLOT))
mstore(0x40, tload(_ORIGINAL_SENDER_TYPE_TRANSIENT_SLOT))
return(0x00, 0x60)
}
}
Expand Down Expand Up @@ -143,6 +152,7 @@ contract MessageHubV1 is UUPSUpgradeable, OAppReceiverUpgradeable {
}

/// @dev Returns the immutable arguments for the sub account.
/// `abi.encodePacked(keccak256(abi.encode(originalSender, originalSenderType)), address(this))`.
function _subAccountArgs(bytes32 originalSender, uint256 originalSenderType)
internal
view
Expand All @@ -151,8 +161,8 @@ contract MessageHubV1 is UUPSUpgradeable, OAppReceiverUpgradeable {
if (originalSender == bytes32(0)) revert OriginalSenderIsZero();
assembly ("memory-safe") {
result := mload(0x40)
mstore(0x20, originalSenderType)
mstore(0x00, originalSender)
mstore(0x20, originalSenderType)
// Address of the mothership.
mstore(add(result, 0x34), address())
// Hash of the original sender and sender type.
Expand All @@ -163,7 +173,7 @@ contract MessageHubV1 is UUPSUpgradeable, OAppReceiverUpgradeable {
}

/// @dev Decodes and forwards the message to the target.
/// This modifier is to be attached onto the `_lzReceive` function.
/// This modifier is to be attached onto the `_lzReceive` function.
modifier forwardMessage(bytes calldata message) {
bytes32 originalSender;
uint256 originalSenderType;
Expand Down Expand Up @@ -222,6 +232,7 @@ contract MessageHubV1 is UUPSUpgradeable, OAppReceiverUpgradeable {

toRefund := mul(sub(selfbalance(), balanceBefore), gt(selfbalance(), balanceBefore))
}
// If the balance has somehow increased, refunds to the sender.
if (toRefund != 0) {
SafeTransferLib.forceSafeTransferETH(sender, toRefund);
}
Expand Down
127 changes: 91 additions & 36 deletions test/MessageHubV1.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,47 @@ import "devtools/mocks/EndpointV2Mock.sol";
import {LibClone} from "solady/utils/LibClone.sol";
import {SafeCastLib} from "solady/utils/SafeCastLib.sol";

contract Target {
address public hub;
uint256 public x;
uint256 public msgValueDuringSetX;
address public msgSenderDuringSetX;
address public senderDuringSetX;
bytes32 public originalSenderDuringSetX;
uint256 public originalSenderTypeDuringSetX;
uint256 public refundAmount;

function depositRefund() public payable {
refundAmount += msg.value;
}

function setHub(address newHub) public {
hub = newHub;
}

function setX(uint256 newX) public payable {
msgValueDuringSetX = msg.value;
msgSenderDuringSetX = msg.sender;
x = newX;
(bool success, bytes memory results) = hub.staticcall("");
(senderDuringSetX, originalSenderDuringSetX, originalSenderTypeDuringSetX) =
abi.decode(results, (address, bytes32, uint256));
require(success);

(success,) = msg.sender.call{value: refundAmount}("");
require(success);
refundAmount = 0;
}
}

contract MessagehubV1Test is SoladyTest {
MockMessageHubV1 hub;
MessageInitiatorV1 initiator;

EndpointV2Mock eid1;
EndpointV2Mock eid2;

uint256 x;
uint256 valueDuringSetX;
Target target;

address constant ALICE = address(111);

Expand Down Expand Up @@ -45,65 +77,88 @@ contract MessagehubV1Test is SoladyTest {

eid1.setDestLzEndpoint(address(initiator), address(eid2));
eid2.setDestLzEndpoint(address(hub), address(eid1));

target = new Target();
target.setHub(address(hub));
}

function testSubAccountArgsDifferential(bytes32 originalSender, uint256 originalSenderType) public view {
bytes memory expected =
abi.encodePacked(keccak256(abi.encode(originalSender, originalSenderType)), address(hub));
assertEq(hub.subAccountArgs(originalSender, originalSenderType), expected);
}

function testCrosschain() public {
uint256 gas = 100000;
uint256 gas = 1000000;
uint256 value = 1 ether;
uint256 newX = _random();

bytes memory data = abi.encodeWithSignature("setX(uint256)", newX);

uint256 nativeFee = initiator.quoteWithDefaultOptions(address(this), data, gas, value);
uint256 nativeFee = initiator.quoteWithDefaultOptions(address(target), data, gas, value);

vm.deal(ALICE, 10 ether);

vm.prank(ALICE);
initiator.sendWithDefaultOptions{value: nativeFee}(address(this), data, gas, value);
initiator.sendWithDefaultOptions{value: nativeFee}(address(target), data, gas, value);

assertEq(x, newX);
assertEq(valueDuringSetX, 1 ether);
assertEq(target.x(), newX);
assertEq(target.msgValueDuringSetX(), 1 ether);
assertEq(target.msgSenderDuringSetX(), address(hub));

assertEq(target.originalSenderDuringSetX(), bytes32(uint256(uint160(ALICE))));
assertEq(target.originalSenderTypeDuringSetX(), 0);
assertEq(target.senderDuringSetX(), ALICE);
}

function testMothership() public {
bytes32 originalSender = bytes32(_random());
while (originalSender == bytes32(0)) originalSender = bytes32(_random());
struct _TestMothershipTemps {
bool originalSenderIsEthereumAddress;
bytes32 originalSender;
uint256 originalSenderType;
address sender;
bytes message;
uint256 newX;
uint256 refundAmount;
}

uint256 senderType = _random();
while (senderType == 0) senderType = _random();
function testMothership(bytes32) public {
_TestMothershipTemps memory t;

address expected = hub.predictSubAccount(originalSender, senderType);
assertEq(hub.createSubAccount(originalSender, senderType), expected);
t.originalSenderIsEthereumAddress = _randomChance(2);

uint256 newX = _random();
if (t.originalSenderIsEthereumAddress) {
t.sender = _randomNonZeroAddress();
t.originalSenderType = 0;
t.originalSender = bytes32(uint256(uint160(t.sender)));
} else {
t.originalSender = bytes32(_random());
t.originalSenderType = 1 | _random();
while (t.originalSender == bytes32(0)) t.originalSender = bytes32(_random());
t.sender = hub.predictSubAccount(t.originalSender, t.originalSenderType);
assertEq(hub.createSubAccount(t.originalSender, t.originalSenderType), t.sender);
}
t.newX = _random();

vm.deal(address(this), 10 ether);
vm.deal(address(hub), _random() % 0.1 ether);

bytes memory message = abi.encode(
originalSender,
senderType,
expected,
_encodeExecuteCalldata(address(this), 1 ether, abi.encodeWithSignature("setX(uint256)", newX))
t.message = abi.encode(
t.originalSender, t.originalSenderType, address(target), abi.encodeWithSignature("setX(uint256)", t.newX)
);

hub.forward{value: 1 ether}(message);
vm.deal(address(this), 10 ether);
t.refundAmount = _random() % 1 ether;
target.depositRefund{value: t.refundAmount}();

assertEq(x, newX);
assertEq(valueDuringSetX, 1 ether);
}
hub.forward{value: 1 ether}(t.message);

function _encodeExecuteCalldata(address target, uint256 value, bytes memory data) internal returns (bytes memory) {
Call[] memory calls = new Call[](1);
calls[0].target = target;
calls[0].value = value;
calls[0].data = data;
bytes memory executionData = abi.encode(calls);
bytes32 mode = bytes32(bytes1(0x01));
return abi.encodeWithSignature("execute(bytes32,bytes)", mode, executionData);
}
assertEq(target.msgValueDuringSetX(), 1 ether);
assertEq(target.msgSenderDuringSetX(), address(hub));
assertEq(target.originalSenderDuringSetX(), t.originalSender);
assertEq(target.originalSenderTypeDuringSetX(), t.originalSenderType);
assertEq(target.senderDuringSetX(), t.sender);

function setX(uint256 value) public payable {
valueDuringSetX = msg.value;
x = value;
assertEq(target.x(), t.newX);
assertEq(t.sender.balance, t.refundAmount);
}
}
4 changes: 4 additions & 0 deletions test/mocks/MockMessageHubV1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,8 @@ contract MockMessageHubV1 is MessageHubV1 {
}

function forward(bytes calldata message) public payable forwardMessage(message) {}

function subAccountArgs(bytes32 originalSender, uint256 originalSenderType) public view returns (bytes memory) {
return _subAccountArgs(originalSender, originalSenderType);
}
}

0 comments on commit df4df75

Please sign in to comment.