Skip to content

Commit

Permalink
feat: redo permit tests as mainnet fork
Browse files Browse the repository at this point in the history
  • Loading branch information
anna-carroll committed Jul 19, 2024
1 parent 5c723e3 commit beca65a
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 102 deletions.
14 changes: 7 additions & 7 deletions .gas-snapshot
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
OrderOriginPermit2Test:test_fillPermit2() (gas: 194206)
OrderOriginPermit2Test:test_fillPermit2_multi() (gas: 984133)
OrderOriginPermit2Test:test_initiatePermit2() (gas: 206669)
OrderOriginPermit2Test:test_initiatePermit2_multi() (gas: 961900)
OrderOriginPermit2Test:test_fillPermit2() (gas: 225289)
OrderOriginPermit2Test:test_fillPermit2_multi() (gas: 1019134)
OrderOriginPermit2Test:test_initiatePermit2() (gas: 235752)
OrderOriginPermit2Test:test_initiatePermit2_multi() (gas: 989274)
OrdersTest:test_fill_ERC20() (gas: 70537)
OrdersTest:test_fill_ETH() (gas: 68498)
OrdersTest:test_fill_both() (gas: 166773)
Expand All @@ -16,8 +16,8 @@ OrdersTest:test_orderExpired() (gas: 28106)
OrdersTest:test_sweepERC20() (gas: 60491)
OrdersTest:test_sweepETH() (gas: 82186)
OrdersTest:test_underflowETH() (gas: 63690)
PassagePermit2Test:test_disallowedEnterPermit2() (gas: 666583)
PassagePermit2Test:test_enterTokenPermit2() (gas: 115862)
PassagePermit2Test:test_disallowedEnterPermit2() (gas: 699630)
PassagePermit2Test:test_enterTokenPermit2() (gas: 145449)
PassageTest:test_configureEnter() (gas: 125771)
PassageTest:test_disallowedEnter() (gas: 56619)
PassageTest:test_enter() (gas: 25519)
Expand All @@ -29,7 +29,7 @@ PassageTest:test_onlyTokenAdmin() (gas: 16881)
PassageTest:test_receive() (gas: 21383)
PassageTest:test_setUp() (gas: 17011)
PassageTest:test_withdraw() (gas: 59188)
RollupPassagePermit2Test:test_exitTokenPermit2() (gas: 99802)
RollupPassagePermit2Test:test_exitTokenPermit2() (gas: 129402)
RollupPassageTest:test_exit() (gas: 22403)
RollupPassageTest:test_exitToken() (gas: 50232)
RollupPassageTest:test_fallback() (gas: 19949)
Expand Down
125 changes: 87 additions & 38 deletions test/Helpers.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,38 +17,23 @@ contract TestERC20 is ERC20Burnable {
}
}

contract Permit2Stub {
/// @notice stubbed `permitWitnessTransferFrom` - does not check signature, nonce, or deadline
function permitWitnessTransferFrom(
ISignatureTransfer.PermitTransferFrom memory permit,
ISignatureTransfer.SignatureTransferDetails calldata transferDetails,
address owner,
bytes32, /*witness*/
string calldata, /*witnessTypeString*/
bytes calldata /*signature*/
) external {
ERC20(permit.permitted.token).transferFrom(owner, transferDetails.to, transferDetails.requestedAmount);
}
}
contract Permit2Helpers is Test {
address permit2Contract;

contract BatchPermit2Stub {
function permitWitnessTransferFrom(
ISignatureTransfer.PermitBatchTransferFrom memory permit,
ISignatureTransfer.SignatureTransferDetails[] calldata transferDetails,
address owner,
bytes32, /*witness*/
string calldata, /*witnessTypeString*/
bytes calldata /*signature*/
) external {
for (uint256 i = 0; i < transferDetails.length; i++) {
ERC20(permit.permitted[i].token).transferFrom(
owner, transferDetails[i].to, transferDetails[i].requestedAmount
);
}
}
}
/// @notice the address signing the Permit messages and its pk
uint256 ownerKey = 123;
address owner = vm.addr(ownerKey);

// permit consts
UsesPermit2.Witness witness;

bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
uint256 private immutable _CACHED_CHAIN_ID;

bytes32 private constant _HASHED_NAME = keccak256("Permit2");
bytes32 private constant _TYPE_HASH =
keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");

contract Permit2Helpers is Test {
string public constant _PERMIT_TRANSFER_FROM_WITNESS_TYPEHASH_STUB =
"PermitWitnessTransferFrom(TokenPermissions permitted,address spender,uint256 nonce,uint256 deadline,";

Expand All @@ -57,32 +42,52 @@ contract Permit2Helpers is Test {
string public constant _PERMIT_BATCH_WITNESS_TRANSFER_FROM_TYPEHASH_STUB =
"PermitBatchWitnessTransferFrom(TokenPermissions[] permitted,address spender,uint256 nonce,uint256 deadline,";

// Cache the domain separator as an immutable value, but also store the chain id that it
// corresponds to, in order to invalidate the cached domain separator if the chain id changes.
constructor() {
_CACHED_CHAIN_ID = block.chainid;
_CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME);
}

function _setUpPermit2(address token, uint256 amount) internal {
vm.label(owner, "owner");

// setup permit2 contract
permit2Contract = 0x000000000022D473030F116dDEE9F6B43aC78BA3;
vm.label(address(permit2Contract), "permit2");

// approve permit2
vm.prank(owner);
TestERC20(token).approve(address(permit2Contract), amount * 10000);
}

/// @notice given a Permit and a Witness, produce a signature from the `owner`
function signPermit(
uint256 signingKey,
address spender,
ISignatureTransfer.PermitTransferFrom memory permit,
UsesPermit2.Witness memory _witness
) internal pure returns (bytes memory signature) {
) internal view returns (bytes memory signature) {
bytes32 permit2Hash = hashWithWitness(spender, permit, _witness.witnessHash, _witness.witnessTypeString);
bytes32 signHash = _hashTypedData(permit2Hash);
uint8 v;
bytes32 r;
bytes32 s;
(v, r, s) = vm.sign(signingKey, permit2Hash);
(v, r, s) = vm.sign(signingKey, signHash);
signature = abi.encodePacked(r, s, v);
}

// this function is private on permit2 contracts but need to port it here for test functionality
function hashWithWitness(
address spender,
ISignatureTransfer.PermitTransferFrom memory _permit,
bytes32 witness,
bytes32 _witness,
string memory witnessTypeString
) internal pure returns (bytes32) {
bytes32 typeHash = keccak256(abi.encodePacked(_PERMIT_TRANSFER_FROM_WITNESS_TYPEHASH_STUB, witnessTypeString));

bytes32 tokenPermissionsHash = _hashTokenPermissions(_permit.permitted);
return keccak256(abi.encode(typeHash, tokenPermissionsHash, spender, _permit.nonce, _permit.deadline, witness));
return keccak256(abi.encode(typeHash, tokenPermissionsHash, spender, _permit.nonce, _permit.deadline, _witness));
}

/// @notice given a Permit and a Witness, produce a signature from the `owner`
Expand All @@ -91,19 +96,20 @@ contract Permit2Helpers is Test {
address spender,
ISignatureTransfer.PermitBatchTransferFrom memory permit,
UsesPermit2.Witness memory _witness
) internal pure returns (bytes memory signature) {
) internal view returns (bytes memory signature) {
bytes32 permit2Hash = hashWithWitness(spender, permit, _witness.witnessHash, _witness.witnessTypeString);
bytes32 signHash = _hashTypedData(permit2Hash);
uint8 v;
bytes32 r;
bytes32 s;
(v, r, s) = vm.sign(signingKey, permit2Hash);
(v, r, s) = vm.sign(signingKey, signHash);
signature = abi.encodePacked(r, s, v);
}

function hashWithWitness(
address spender,
ISignatureTransfer.PermitBatchTransferFrom memory permit,
bytes32 witness,
bytes32 _witness,
string memory witnessTypeString
) internal pure returns (bytes32) {
bytes32 typeHash =
Expand All @@ -123,7 +129,7 @@ contract Permit2Helpers is Test {
spender,
permit.nonce,
permit.deadline,
witness
_witness
)
);
}
Expand All @@ -136,6 +142,49 @@ contract Permit2Helpers is Test {
{
return keccak256(abi.encode(_TOKEN_PERMISSIONS_TYPEHASH, _permitted));
}

/// @notice Returns the domain separator for the current chain.
/// @dev Uses cached version if chainid and address are unchanged from construction.
function DOMAIN_SEPARATOR() public view returns (bytes32) {
return block.chainid == _CACHED_CHAIN_ID
? _CACHED_DOMAIN_SEPARATOR
: _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME);
}

/// @notice Builds a domain separator using the current chainId and contract address.
function _buildDomainSeparator(bytes32 typeHash, bytes32 nameHash) private view returns (bytes32) {
return keccak256(abi.encode(typeHash, nameHash, block.chainid, permit2Contract));
}

/// @notice Creates an EIP-712 typed data hash
function _hashTypedData(bytes32 dataHash) internal view returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR(), dataHash));
}
}

/// HACK to use abi.encodeWithSelector
interface ISinglePermit {
/// @notice stubbed `permitWitnessTransferFrom` - does not check signature, nonce, or deadline
function permitWitnessTransferFrom(
ISignatureTransfer.PermitTransferFrom memory permit,
ISignatureTransfer.SignatureTransferDetails calldata transferDetails,
address owner,
bytes32, /*witness*/
string calldata, /*witnessTypeString*/
bytes calldata /*signature*/
) external;
}

/// HACK to use abi.encodeWithSelector
interface IBatchPermit {
function permitWitnessTransferFrom(
ISignatureTransfer.PermitBatchTransferFrom memory permit,
ISignatureTransfer.SignatureTransferDetails[] calldata transferDetails,
address owner,
bytes32, /*witness*/
string calldata, /*witnessTypeString*/
bytes calldata /*signature*/
) external;
}

contract HelpersTest is Test {
Expand Down
40 changes: 9 additions & 31 deletions test/Permit2Orders.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,17 @@ import {UsesPermit2} from "../src/permit2/UsesPermit2.sol";

// Permit2 deps
import {ISignatureTransfer} from "permit2/src/interfaces/ISignatureTransfer.sol";
import {PermitHash} from "permit2/src/libraries/PermitHash.sol";

// other test utils
import {Permit2Helpers, BatchPermit2Stub, TestERC20} from "./Helpers.t.sol";
import {Permit2Helpers, IBatchPermit, TestERC20} from "./Helpers.t.sol";
import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
import {ERC20Burnable} from "openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import {Test, console2} from "forge-std/Test.sol";

contract Permit2BatchTest is Permit2Helpers {
BatchPermit2Stub permit2Contract;

/// @notice the address signing the Permit messages and its pk
uint256 ownerKey = 123;
address owner = vm.addr(ownerKey);

// permit consts
UsesPermit2.Witness witness;
// batch permit
UsesPermit2.Permit2Batch permit2;
ISignatureTransfer.SignatureTransferDetails[] transferDetails;

function _setUpPermit2(address token, uint256 amount) internal {
vm.label(owner, "owner");

// deploy batch permit2
permit2Contract = new BatchPermit2Stub();
vm.label(address(permit2Contract), "permit2");

// approve batch permit2
vm.prank(owner);
TestERC20(token).approve(address(permit2Contract), amount * 10000);

_setupBatchPermit(token, amount);
}

function _setupBatchPermit(address token, uint256 amount) internal {
// create a batch permit with generic details
permit2.permit.permitted.push(ISignatureTransfer.TokenPermissions({token: token, amount: amount}));
Expand Down Expand Up @@ -73,13 +49,15 @@ contract OrderOriginPermit2Test is Permit2BatchTest {
event Filled(IOrders.Output[] outputs);

function setUp() public {
vm.createSelectFork("https://ethereum-rpc.publicnode.com");
// deploy token
token = address(new TestERC20("hi", "HI"));
TestERC20(token).mint(owner, amount * 10000);
isToken[token] = true;

// setup permit2 contract & permit details
_setUpPermit2(token, amount);
_setupBatchPermit(token, amount);

// deploy Orders contract
target = new RollupOrders(address(permit2Contract));
Expand All @@ -105,11 +83,11 @@ contract OrderOriginPermit2Test is Permit2BatchTest {

// expect Order event is initiated, ERC20 is transferred
vm.expectEmit();
emit Order(deadline, inputs, outputs);
emit Order(permit2.permit.deadline, inputs, outputs);
vm.expectCall(
address(permit2Contract),
abi.encodeWithSelector(
BatchPermit2Stub.permitWitnessTransferFrom.selector,
IBatchPermit.permitWitnessTransferFrom.selector,
permit2.permit,
transferDetails,
owner,
Expand Down Expand Up @@ -149,11 +127,11 @@ contract OrderOriginPermit2Test is Permit2BatchTest {

// expect Order event is emitted, ERC20 is transferred
vm.expectEmit();
emit Order(deadline, inputs, outputs);
emit Order(permit2.permit.deadline, inputs, outputs);
vm.expectCall(
address(permit2Contract),
abi.encodeWithSelector(
BatchPermit2Stub.permitWitnessTransferFrom.selector,
IBatchPermit.permitWitnessTransferFrom.selector,
permit2.permit,
transferDetails,
owner,
Expand All @@ -176,7 +154,7 @@ contract OrderOriginPermit2Test is Permit2BatchTest {
vm.expectCall(
address(permit2Contract),
abi.encodeWithSelector(
BatchPermit2Stub.permitWitnessTransferFrom.selector,
IBatchPermit.permitWitnessTransferFrom.selector,
permit2.permit,
transferDetails,
owner,
Expand Down Expand Up @@ -218,7 +196,7 @@ contract OrderOriginPermit2Test is Permit2BatchTest {
vm.expectCall(
address(permit2Contract),
abi.encodeWithSelector(
BatchPermit2Stub.permitWitnessTransferFrom.selector,
IBatchPermit.permitWitnessTransferFrom.selector,
permit2.permit,
transferDetails,
owner,
Expand Down
Loading

0 comments on commit beca65a

Please sign in to comment.