From 88b767fd94d3993d307d66bffe5318596380ba12 Mon Sep 17 00:00:00 2001 From: MerlinEgalite Date: Tue, 19 Sep 2023 18:49:23 +0200 Subject: [PATCH 1/6] feat: add permit --- src/MetaMorpho.sol | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/MetaMorpho.sol b/src/MetaMorpho.sol index 97cdf6e9..abfafc8e 100644 --- a/src/MetaMorpho.sol +++ b/src/MetaMorpho.sol @@ -25,8 +25,9 @@ import { Math, SafeERC20 } from "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol"; +import {IERC20Metadata, ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; -contract MetaMorpho is ERC4626, Ownable2Step, IMetaMorpho { +contract MetaMorpho is ERC4626, ERC20Permit, Ownable2Step, IMetaMorpho { using Math for uint256; using UtilsLib for uint256; using SafeCast for uint256; @@ -71,6 +72,7 @@ contract MetaMorpho is ERC4626, Ownable2Step, IMetaMorpho { constructor(address morpho, uint256 initialTimelock, address _asset, string memory _name, string memory _symbol) ERC4626(IERC20(_asset)) + ERC20Permit("MetaMorpho Vault V1") ERC20(_name, _symbol) { require(initialTimelock <= MAX_TIMELOCK, ErrorsLib.MAX_TIMELOCK_EXCEEDED); @@ -255,6 +257,12 @@ contract MetaMorpho is ERC4626, Ownable2Step, IMetaMorpho { return _hasRole(target, ALLOCATOR_ROLE); } + /* ERC20 (PUBLIC) */ + + function decimals() public view override(IERC20Metadata, ERC20, ERC4626) returns (uint8) { + return ERC4626.decimals(); + } + /* ERC4626 (PUBLIC) */ function maxWithdraw(address owner) public view override(IERC4626, ERC4626) returns (uint256 assets) { From dd81638f5da1c946e92175f21b9d50bcaa8435bf Mon Sep 17 00:00:00 2001 From: MerlinEgalite Date: Tue, 19 Sep 2023 19:04:33 +0200 Subject: [PATCH 2/6] test: add permit test --- test/forge/PermitTest.sol | 174 ++++++++++++++++++++++++++++++++ test/forge/helpers/SigUtils.sol | 33 ++++++ 2 files changed, 207 insertions(+) create mode 100644 test/forge/PermitTest.sol create mode 100644 test/forge/helpers/SigUtils.sol diff --git a/test/forge/PermitTest.sol b/test/forge/PermitTest.sol new file mode 100644 index 00000000..950fcc6e --- /dev/null +++ b/test/forge/PermitTest.sol @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +import "./helpers/SigUtils.sol"; +import "./helpers/BaseTest.sol"; + +contract PermitTest is BaseTest { + SigUtils internal sigUtils; + + uint256 internal ownerPrivateKey; + uint256 internal spenderPrivateKey; + + address internal owner; + address internal spender; + + function setUp() public override { + super.setUp(); + + sigUtils = new SigUtils(vault.DOMAIN_SEPARATOR()); + + ownerPrivateKey = 0xA11CE; + spenderPrivateKey = 0xB0B; + + owner = vm.addr(ownerPrivateKey); + spender = vm.addr(spenderPrivateKey); + + deal(address(vault), owner, 1e18); + } + + function testPermit() public { + SigUtils.Permit memory permit = + SigUtils.Permit({owner: owner, spender: spender, value: 1e18, nonce: 0, deadline: 1 days}); + + bytes32 digest = sigUtils.getTypedDataHash(permit); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + + vault.permit(permit.owner, permit.spender, permit.value, permit.deadline, v, r, s); + + assertEq(vault.allowance(owner, spender), 1e18); + assertEq(vault.nonces(owner), 1); + } + + function testRevertExpiredPermit() public { + SigUtils.Permit memory permit = + SigUtils.Permit({owner: owner, spender: spender, value: 1e18, nonce: vault.nonces(owner), deadline: 1 days}); + + bytes32 digest = sigUtils.getTypedDataHash(permit); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + + vm.warp(1 days + 1 seconds); // fast forward one second past the deadline + + vm.expectRevert("ERC20Permit: expired deadline"); + vault.permit(permit.owner, permit.spender, permit.value, permit.deadline, v, r, s); + } + + function testRevertInvalidSigner() public { + SigUtils.Permit memory permit = + SigUtils.Permit({owner: owner, spender: spender, value: 1e18, nonce: vault.nonces(owner), deadline: 1 days}); + + bytes32 digest = sigUtils.getTypedDataHash(permit); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(spenderPrivateKey, digest); // spender signs owner's approval + + vm.expectRevert("ERC20Permit: invalid signature"); + vault.permit(permit.owner, permit.spender, permit.value, permit.deadline, v, r, s); + } + + function testRevertInvalidNonce() public { + SigUtils.Permit memory permit = SigUtils.Permit({ + owner: owner, + spender: spender, + value: 1e18, + nonce: 1, // owner nonce stored on-chain is 0 + deadline: 1 days + }); + + bytes32 digest = sigUtils.getTypedDataHash(permit); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + + vm.expectRevert("ERC20Permit: invalid signature"); + vault.permit(permit.owner, permit.spender, permit.value, permit.deadline, v, r, s); + } + + function testRevertSignatureReplay() public { + SigUtils.Permit memory permit = + SigUtils.Permit({owner: owner, spender: spender, value: 1e18, nonce: 0, deadline: 1 days}); + + bytes32 digest = sigUtils.getTypedDataHash(permit); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + + vault.permit(permit.owner, permit.spender, permit.value, permit.deadline, v, r, s); + + vm.expectRevert("ERC20Permit: invalid signature"); + vault.permit(permit.owner, permit.spender, permit.value, permit.deadline, v, r, s); + } + + function testTransferFromLimitedPermit() public { + SigUtils.Permit memory permit = + SigUtils.Permit({owner: owner, spender: spender, value: 1e18, nonce: 0, deadline: 1 days}); + + bytes32 digest = sigUtils.getTypedDataHash(permit); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + + vault.permit(permit.owner, permit.spender, permit.value, permit.deadline, v, r, s); + + vm.prank(spender); + vault.transferFrom(owner, spender, 1e18); + + assertEq(vault.balanceOf(owner), 0); + assertEq(vault.balanceOf(spender), 1e18); + assertEq(vault.allowance(owner, spender), 0); + } + + function testTransferFromMaxPermit() public { + SigUtils.Permit memory permit = + SigUtils.Permit({owner: owner, spender: spender, value: type(uint256).max, nonce: 0, deadline: 1 days}); + + bytes32 digest = sigUtils.getTypedDataHash(permit); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + + vault.permit(permit.owner, permit.spender, permit.value, permit.deadline, v, r, s); + + vm.prank(spender); + vault.transferFrom(owner, spender, 1e18); + + assertEq(vault.balanceOf(owner), 0); + assertEq(vault.balanceOf(spender), 1e18); + assertEq(vault.allowance(owner, spender), type(uint256).max); + } + + function testFailInvalidAllowance() public { + SigUtils.Permit memory permit = SigUtils.Permit({ + owner: owner, + spender: spender, + value: 5e17, // approve only 0.5 tokens + nonce: 0, + deadline: 1 days + }); + + bytes32 digest = sigUtils.getTypedDataHash(permit); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + + vault.permit(permit.owner, permit.spender, permit.value, permit.deadline, v, r, s); + + vm.prank(spender); + vault.transferFrom(owner, spender, 1e18); // attempt to transfer 1 vault + } + + function testFailInvalidBalance() public { + SigUtils.Permit memory permit = SigUtils.Permit({ + owner: owner, + spender: spender, + value: 2e18, // approve 2 tokens + nonce: 0, + deadline: 1 days + }); + + bytes32 digest = sigUtils.getTypedDataHash(permit); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + + vault.permit(permit.owner, permit.spender, permit.value, permit.deadline, v, r, s); + + vm.prank(spender); + vault.transferFrom(owner, spender, 2e18); // attempt to transfer 2 tokens (owner only owns 1) + } +} diff --git a/test/forge/helpers/SigUtils.sol b/test/forge/helpers/SigUtils.sol new file mode 100644 index 00000000..ac9f7715 --- /dev/null +++ b/test/forge/helpers/SigUtils.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +pragma solidity ^0.8.0; + +contract SigUtils { + bytes32 internal DOMAIN_SEPARATOR; + + constructor(bytes32 _DOMAIN_SEPARATOR) { + DOMAIN_SEPARATOR = _DOMAIN_SEPARATOR; + } + + // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); + bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; + + struct Permit { + address owner; + address spender; + uint256 value; + uint256 nonce; + uint256 deadline; + } + + // computes the hash of a permit + function getStructHash(Permit memory _permit) internal pure returns (bytes32) { + return keccak256( + abi.encode(PERMIT_TYPEHASH, _permit.owner, _permit.spender, _permit.value, _permit.nonce, _permit.deadline) + ); + } + + // computes the hash of the fully encoded EIP-712 message for the domain, which can be used to recover the signer + function getTypedDataHash(Permit memory _permit) public view returns (bytes32) { + return keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, getStructHash(_permit))); + } +} From 6f77e7130ec97f875c50cee11f66f2ab59d209c2 Mon Sep 17 00:00:00 2001 From: MerlinEgalite Date: Wed, 20 Sep 2023 09:20:47 +0200 Subject: [PATCH 3/6] fix: use name in constructor --- src/MetaMorpho.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MetaMorpho.sol b/src/MetaMorpho.sol index abfafc8e..b3cb8d7b 100644 --- a/src/MetaMorpho.sol +++ b/src/MetaMorpho.sol @@ -72,7 +72,7 @@ contract MetaMorpho is ERC4626, ERC20Permit, Ownable2Step, IMetaMorpho { constructor(address morpho, uint256 initialTimelock, address _asset, string memory _name, string memory _symbol) ERC4626(IERC20(_asset)) - ERC20Permit("MetaMorpho Vault V1") + ERC20Permit(_name) ERC20(_name, _symbol) { require(initialTimelock <= MAX_TIMELOCK, ErrorsLib.MAX_TIMELOCK_EXCEEDED); From 25018bb3aa01d620dce13f5f06c76df9ac4edac3 Mon Sep 17 00:00:00 2001 From: MerlinEgalite Date: Wed, 20 Sep 2023 09:59:22 +0200 Subject: [PATCH 4/6] test: implement suggestions --- test/forge/PermitTest.sol | 29 +++++++++++++---------------- test/forge/helpers/BaseTest.sol | 1 - test/forge/helpers/SigUtils.sol | 18 +++++++++--------- 3 files changed, 22 insertions(+), 26 deletions(-) diff --git a/test/forge/PermitTest.sol b/test/forge/PermitTest.sol index 950fcc6e..4bde2cdf 100644 --- a/test/forge/PermitTest.sol +++ b/test/forge/PermitTest.sol @@ -7,8 +7,8 @@ import "./helpers/BaseTest.sol"; contract PermitTest is BaseTest { SigUtils internal sigUtils; - uint256 internal ownerPrivateKey; - uint256 internal spenderPrivateKey; + uint256 internal constant OWNER_PK = 0xA11CE; + uint256 internal constant SPENDER_PK = 0xB0B; address internal owner; address internal spender; @@ -18,11 +18,8 @@ contract PermitTest is BaseTest { sigUtils = new SigUtils(vault.DOMAIN_SEPARATOR()); - ownerPrivateKey = 0xA11CE; - spenderPrivateKey = 0xB0B; - - owner = vm.addr(ownerPrivateKey); - spender = vm.addr(spenderPrivateKey); + owner = vm.addr(OWNER_PK); + spender = vm.addr(SPENDER_PK); deal(address(vault), owner, 1e18); } @@ -33,7 +30,7 @@ contract PermitTest is BaseTest { bytes32 digest = sigUtils.getTypedDataHash(permit); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(OWNER_PK, digest); vault.permit(permit.owner, permit.spender, permit.value, permit.deadline, v, r, s); @@ -47,7 +44,7 @@ contract PermitTest is BaseTest { bytes32 digest = sigUtils.getTypedDataHash(permit); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(OWNER_PK, digest); vm.warp(1 days + 1 seconds); // fast forward one second past the deadline @@ -61,7 +58,7 @@ contract PermitTest is BaseTest { bytes32 digest = sigUtils.getTypedDataHash(permit); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(spenderPrivateKey, digest); // spender signs owner's approval + (uint8 v, bytes32 r, bytes32 s) = vm.sign(SPENDER_PK, digest); // spender signs owner's approval vm.expectRevert("ERC20Permit: invalid signature"); vault.permit(permit.owner, permit.spender, permit.value, permit.deadline, v, r, s); @@ -78,7 +75,7 @@ contract PermitTest is BaseTest { bytes32 digest = sigUtils.getTypedDataHash(permit); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(OWNER_PK, digest); vm.expectRevert("ERC20Permit: invalid signature"); vault.permit(permit.owner, permit.spender, permit.value, permit.deadline, v, r, s); @@ -90,7 +87,7 @@ contract PermitTest is BaseTest { bytes32 digest = sigUtils.getTypedDataHash(permit); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(OWNER_PK, digest); vault.permit(permit.owner, permit.spender, permit.value, permit.deadline, v, r, s); @@ -104,7 +101,7 @@ contract PermitTest is BaseTest { bytes32 digest = sigUtils.getTypedDataHash(permit); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(OWNER_PK, digest); vault.permit(permit.owner, permit.spender, permit.value, permit.deadline, v, r, s); @@ -122,7 +119,7 @@ contract PermitTest is BaseTest { bytes32 digest = sigUtils.getTypedDataHash(permit); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(OWNER_PK, digest); vault.permit(permit.owner, permit.spender, permit.value, permit.deadline, v, r, s); @@ -145,7 +142,7 @@ contract PermitTest is BaseTest { bytes32 digest = sigUtils.getTypedDataHash(permit); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(OWNER_PK, digest); vault.permit(permit.owner, permit.spender, permit.value, permit.deadline, v, r, s); @@ -164,7 +161,7 @@ contract PermitTest is BaseTest { bytes32 digest = sigUtils.getTypedDataHash(permit); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPrivateKey, digest); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(OWNER_PK, digest); vault.permit(permit.owner, permit.spender, permit.value, permit.deadline, v, r, s); diff --git a/test/forge/helpers/BaseTest.sol b/test/forge/helpers/BaseTest.sol index 3b805dc9..80ba6e89 100644 --- a/test/forge/helpers/BaseTest.sol +++ b/test/forge/helpers/BaseTest.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.0; import "@morpho-blue/interfaces/IMorpho.sol"; -import {IOracle} from "@morpho-blue/interfaces/IOracle.sol"; import {MarketParamsLib} from "@morpho-blue/libraries/MarketParamsLib.sol"; import {MorphoLib} from "@morpho-blue/libraries/periphery/MorphoLib.sol"; diff --git a/test/forge/helpers/SigUtils.sol b/test/forge/helpers/SigUtils.sol index ac9f7715..310f07e2 100644 --- a/test/forge/helpers/SigUtils.sol +++ b/test/forge/helpers/SigUtils.sol @@ -2,15 +2,6 @@ pragma solidity ^0.8.0; contract SigUtils { - bytes32 internal DOMAIN_SEPARATOR; - - constructor(bytes32 _DOMAIN_SEPARATOR) { - DOMAIN_SEPARATOR = _DOMAIN_SEPARATOR; - } - - // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); - bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; - struct Permit { address owner; address spender; @@ -19,6 +10,15 @@ contract SigUtils { uint256 deadline; } + // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); + bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; + + bytes32 internal DOMAIN_SEPARATOR; + + constructor(bytes32 _DOMAIN_SEPARATOR) { + DOMAIN_SEPARATOR = _DOMAIN_SEPARATOR; + } + // computes the hash of a permit function getStructHash(Permit memory _permit) internal pure returns (bytes32) { return keccak256( From e9af3a38ff062f0613b7fac6a7a90f374b6243f9 Mon Sep 17 00:00:00 2001 From: MerlinEgalite Date: Wed, 20 Sep 2023 10:14:35 +0200 Subject: [PATCH 5/6] docs: erc4626 public --- src/MetaMorpho.sol | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/MetaMorpho.sol b/src/MetaMorpho.sol index b3cb8d7b..a3677cbf 100644 --- a/src/MetaMorpho.sol +++ b/src/MetaMorpho.sol @@ -257,14 +257,12 @@ contract MetaMorpho is ERC4626, ERC20Permit, Ownable2Step, IMetaMorpho { return _hasRole(target, ALLOCATOR_ROLE); } - /* ERC20 (PUBLIC) */ + /* ERC4626 (PUBLIC) */ function decimals() public view override(IERC20Metadata, ERC20, ERC4626) returns (uint8) { return ERC4626.decimals(); } - /* ERC4626 (PUBLIC) */ - function maxWithdraw(address owner) public view override(IERC4626, ERC4626) returns (uint256 assets) { (assets,) = _maxWithdraw(owner); } From 9c26dc3e499546b937d83807b829ff8c3310fcd7 Mon Sep 17 00:00:00 2001 From: MerlinEgalite Date: Wed, 20 Sep 2023 11:46:53 +0200 Subject: [PATCH 6/6] refactor: struct and constant to top level --- test/forge/PermitTest.sol | 27 ++++++++++++--------------- test/forge/helpers/SigUtils.sol | 20 ++++++++++---------- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/test/forge/PermitTest.sol b/test/forge/PermitTest.sol index 4bde2cdf..ce7028a0 100644 --- a/test/forge/PermitTest.sol +++ b/test/forge/PermitTest.sol @@ -25,8 +25,7 @@ contract PermitTest is BaseTest { } function testPermit() public { - SigUtils.Permit memory permit = - SigUtils.Permit({owner: owner, spender: spender, value: 1e18, nonce: 0, deadline: 1 days}); + Permit memory permit = Permit({owner: owner, spender: spender, value: 1e18, nonce: 0, deadline: 1 days}); bytes32 digest = sigUtils.getTypedDataHash(permit); @@ -39,8 +38,8 @@ contract PermitTest is BaseTest { } function testRevertExpiredPermit() public { - SigUtils.Permit memory permit = - SigUtils.Permit({owner: owner, spender: spender, value: 1e18, nonce: vault.nonces(owner), deadline: 1 days}); + Permit memory permit = + Permit({owner: owner, spender: spender, value: 1e18, nonce: vault.nonces(owner), deadline: 1 days}); bytes32 digest = sigUtils.getTypedDataHash(permit); @@ -53,8 +52,8 @@ contract PermitTest is BaseTest { } function testRevertInvalidSigner() public { - SigUtils.Permit memory permit = - SigUtils.Permit({owner: owner, spender: spender, value: 1e18, nonce: vault.nonces(owner), deadline: 1 days}); + Permit memory permit = + Permit({owner: owner, spender: spender, value: 1e18, nonce: vault.nonces(owner), deadline: 1 days}); bytes32 digest = sigUtils.getTypedDataHash(permit); @@ -65,7 +64,7 @@ contract PermitTest is BaseTest { } function testRevertInvalidNonce() public { - SigUtils.Permit memory permit = SigUtils.Permit({ + Permit memory permit = Permit({ owner: owner, spender: spender, value: 1e18, @@ -82,8 +81,7 @@ contract PermitTest is BaseTest { } function testRevertSignatureReplay() public { - SigUtils.Permit memory permit = - SigUtils.Permit({owner: owner, spender: spender, value: 1e18, nonce: 0, deadline: 1 days}); + Permit memory permit = Permit({owner: owner, spender: spender, value: 1e18, nonce: 0, deadline: 1 days}); bytes32 digest = sigUtils.getTypedDataHash(permit); @@ -96,8 +94,7 @@ contract PermitTest is BaseTest { } function testTransferFromLimitedPermit() public { - SigUtils.Permit memory permit = - SigUtils.Permit({owner: owner, spender: spender, value: 1e18, nonce: 0, deadline: 1 days}); + Permit memory permit = Permit({owner: owner, spender: spender, value: 1e18, nonce: 0, deadline: 1 days}); bytes32 digest = sigUtils.getTypedDataHash(permit); @@ -114,8 +111,8 @@ contract PermitTest is BaseTest { } function testTransferFromMaxPermit() public { - SigUtils.Permit memory permit = - SigUtils.Permit({owner: owner, spender: spender, value: type(uint256).max, nonce: 0, deadline: 1 days}); + Permit memory permit = + Permit({owner: owner, spender: spender, value: type(uint256).max, nonce: 0, deadline: 1 days}); bytes32 digest = sigUtils.getTypedDataHash(permit); @@ -132,7 +129,7 @@ contract PermitTest is BaseTest { } function testFailInvalidAllowance() public { - SigUtils.Permit memory permit = SigUtils.Permit({ + Permit memory permit = Permit({ owner: owner, spender: spender, value: 5e17, // approve only 0.5 tokens @@ -151,7 +148,7 @@ contract PermitTest is BaseTest { } function testFailInvalidBalance() public { - SigUtils.Permit memory permit = SigUtils.Permit({ + Permit memory permit = Permit({ owner: owner, spender: spender, value: 2e18, // approve 2 tokens diff --git a/test/forge/helpers/SigUtils.sol b/test/forge/helpers/SigUtils.sol index 310f07e2..11d90252 100644 --- a/test/forge/helpers/SigUtils.sol +++ b/test/forge/helpers/SigUtils.sol @@ -1,18 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; -contract SigUtils { - struct Permit { - address owner; - address spender; - uint256 value; - uint256 nonce; - uint256 deadline; - } +struct Permit { + address owner; + address spender; + uint256 value; + uint256 nonce; + uint256 deadline; +} - // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); - bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; +// keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); +bytes32 constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; +contract SigUtils { bytes32 internal DOMAIN_SEPARATOR; constructor(bytes32 _DOMAIN_SEPARATOR) {