Skip to content

Commit

Permalink
Merge pull request #438 from morpho-org/feat/permit-base
Browse files Browse the repository at this point in the history
Add PermitBundler to BaseBundler
  • Loading branch information
MathisGD authored May 15, 2024
2 parents 5bef994 + ddfc75b commit 3e6e637
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 1 deletion.
2 changes: 2 additions & 0 deletions src/base/BaseBundlerV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity 0.8.24;
import {CoreBundler} from "../CoreBundler.sol";
import {TransferBundler} from "../TransferBundler.sol";
import {Permit2Bundler} from "../Permit2Bundler.sol";
import {PermitBundler} from "../PermitBundler.sol";
import {ERC4626Bundler} from "../ERC4626Bundler.sol";
import {WNativeBundler} from "../WNativeBundler.sol";
import {UrdBundler} from "../UrdBundler.sol";
Expand All @@ -17,6 +18,7 @@ import {ERC20WrapperBundler} from "../ERC20WrapperBundler.sol";
contract BaseBundlerV2 is
TransferBundler,
Permit2Bundler,
PermitBundler,
ERC4626Bundler,
WNativeBundler,
UrdBundler,
Expand Down
84 changes: 83 additions & 1 deletion test/forge/fork/PermitBundlerForkTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,26 @@ pragma solidity ^0.8.0;

import {ErrorsLib} from "../../../src/libraries/ErrorsLib.sol";

import {DaiPermit} from "../helpers/SigUtils.sol";
import {DaiPermit, Permit} from "../helpers/SigUtils.sol";

import "../../../src/ethereum/EthereumPermitBundler.sol";
import {IERC20Permit} from "../../../lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol";
import {ERC20PermitMock} from "../../../src/mocks/ERC20PermitMock.sol";

import "./helpers/ForkTest.sol";

/// @dev The unique EIP-712 domain domain separator for the DAI token contract on Ethereum.
bytes32 constant DAI_DOMAIN_SEPARATOR = 0xdbb8cf42e1ecb028be3f3dbc922e1d878b963f411dc388ced501601c60f7c6f7;

contract PermitBundlerForkTest is ForkTest {
ERC20PermitMock internal permitToken;

function setUp() public override {
super.setUp();

permitToken = new ERC20PermitMock("Permit Token", "PT");
}

function testPermitDai(uint256 privateKey, uint256 expiry) public onlyEthereum {
expiry = bound(expiry, block.timestamp, type(uint48).max);
privateKey = bound(privateKey, 1, type(uint160).max);
Expand Down Expand Up @@ -62,4 +72,76 @@ contract PermitBundlerForkTest is ForkTest {

return abi.encodeCall(EthereumPermitBundler.permitDai, (nonce, expiry, allowed, v, r, s, skipRevert));
}

function testPermit(uint256 amount, uint256 privateKey, uint256 deadline) public {
amount = bound(amount, MIN_AMOUNT, MAX_AMOUNT);
deadline = bound(deadline, block.timestamp, type(uint48).max);
privateKey = bound(privateKey, 1, type(uint160).max);

address user = vm.addr(privateKey);

bundle.push(_permit(permitToken, privateKey, amount, deadline, false));
bundle.push(_permit(permitToken, privateKey, amount, deadline, true));

vm.prank(user);
bundler.multicall(bundle);

assertEq(permitToken.allowance(user, address(bundler)), amount, "allowance(user, bundler)");
}

function testPermitUninitiated(uint256 amount) public {
amount = bound(amount, MIN_AMOUNT, MAX_AMOUNT);

vm.expectRevert(bytes(ErrorsLib.UNINITIATED));
PermitBundler(address(bundler)).permit(address(USDC), amount, SIGNATURE_DEADLINE, 0, 0, 0, true);
}

function testPermitRevert(uint256 amount, uint256 privateKey, uint256 deadline) public {
amount = bound(amount, MIN_AMOUNT, MAX_AMOUNT);
deadline = bound(deadline, block.timestamp, type(uint48).max);
privateKey = bound(privateKey, 1, type(uint160).max);

address user = vm.addr(privateKey);

bundle.push(_permit(permitToken, privateKey, amount, deadline, false));
bundle.push(_permit(permitToken, privateKey, amount, deadline, false));

vm.prank(user);
vm.expectRevert("ERC20Permit: invalid signature");
bundler.multicall(bundle);
}

function testTransferFrom(uint256 amount, uint256 privateKey, uint256 deadline) public {
amount = bound(amount, MIN_AMOUNT, MAX_AMOUNT);
deadline = bound(deadline, block.timestamp, type(uint48).max);
privateKey = bound(privateKey, 1, type(uint160).max);

address user = vm.addr(privateKey);

bundle.push(_permit(permitToken, privateKey, amount, deadline, false));
bundle.push(_erc20TransferFrom(address(permitToken), amount));

permitToken.setBalance(user, amount);

vm.prank(user);
bundler.multicall(bundle);

assertEq(permitToken.balanceOf(address(bundler)), amount, "balanceOf(bundler)");
assertEq(permitToken.balanceOf(user), 0, "balanceOf(user)");
}

function _permit(IERC20Permit token, uint256 privateKey, uint256 amount, uint256 deadline, bool skipRevert)
internal
view
returns (bytes memory)
{
address user = vm.addr(privateKey);

Permit memory permit = Permit(user, address(bundler), amount, token.nonces(user), deadline);

bytes32 digest = SigUtils.toTypedDataHash(token.DOMAIN_SEPARATOR(), permit);
(uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest);

return abi.encodeCall(PermitBundler.permit, (address(token), amount, deadline, v, r, s, skipRevert));
}
}

0 comments on commit 3e6e637

Please sign in to comment.