diff --git a/.forge-snapshots/batchTransferFrom.snap b/.forge-snapshots/batchTransferFrom.snap index 85e3cbf0..12330bfb 100644 --- a/.forge-snapshots/batchTransferFrom.snap +++ b/.forge-snapshots/batchTransferFrom.snap @@ -1 +1 @@ -61806 \ No newline at end of file +61797 \ No newline at end of file diff --git a/.gas-snapshot b/.gas-snapshot index a5dc34af..8a9a0e8e 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,115 +1,115 @@ -AllowanceTransferInvariants:invariant_balanceEqualsSpent() (runs: 256, calls: 3840, reverts: 886) -AllowanceTransferInvariants:invariant_permit2NeverHoldsBalance() (runs: 256, calls: 3840, reverts: 886) -AllowanceTransferInvariants:invariant_spendNeverExceedsPermit() (runs: 256, calls: 3840, reverts: 886) -AllowanceTransferTest:testApprove() (gas: 47561) -AllowanceTransferTest:testBatchTransferFrom() (gas: 159268) -AllowanceTransferTest:testBatchTransferFromDifferentOwners() (gas: 235508) -AllowanceTransferTest:testBatchTransferFromMultiToken() (gas: 231828) -AllowanceTransferTest:testBatchTransferFromWithGasSnapshot() (gas: 159818) -AllowanceTransferTest:testExcessiveInvalidation() (gas: 64136) -AllowanceTransferTest:testInvalidateMultipleNonces() (gas: 83139) -AllowanceTransferTest:testInvalidateNonces() (gas: 62679) -AllowanceTransferTest:testInvalidateNoncesInvalid() (gas: 16261) -AllowanceTransferTest:testLockdown() (gas: 145952) -AllowanceTransferTest:testLockdownEvent() (gas: 117758) -AllowanceTransferTest:testMaxAllowance() (gas: 134993) -AllowanceTransferTest:testMaxAllowanceDirtyWrite() (gas: 117582) -AllowanceTransferTest:testPartialAllowance() (gas: 105067) -AllowanceTransferTest:testReuseOrderedNonceInvalid() (gas: 69095) -AllowanceTransferTest:testSetAllowance() (gas: 89583) -AllowanceTransferTest:testSetAllowanceBatch() (gas: 133608) -AllowanceTransferTest:testSetAllowanceBatchDifferentNonces() (gas: 118583) -AllowanceTransferTest:testSetAllowanceBatchDirtyWrite() (gas: 99144) -AllowanceTransferTest:testSetAllowanceBatchEvent() (gas: 115892) -AllowanceTransferTest:testSetAllowanceCompactSig() (gas: 89543) -AllowanceTransferTest:testSetAllowanceDeadlinePassed() (gas: 56500) +AllowanceTransferInvariants:invariant_balanceEqualsSpent() (runs: 256, calls: 3840, reverts: 879) +AllowanceTransferInvariants:invariant_permit2NeverHoldsBalance() (runs: 256, calls: 3840, reverts: 878) +AllowanceTransferInvariants:invariant_spendNeverExceedsPermit() (runs: 256, calls: 3840, reverts: 881) +AllowanceTransferTest:testApprove() (gas: 47570) +AllowanceTransferTest:testBatchTransferFrom() (gas: 159197) +AllowanceTransferTest:testBatchTransferFromDifferentOwners() (gas: 235094) +AllowanceTransferTest:testBatchTransferFromMultiToken() (gas: 231841) +AllowanceTransferTest:testBatchTransferFromWithGasSnapshot() (gas: 159857) +AllowanceTransferTest:testExcessiveInvalidation() (gas: 64205) +AllowanceTransferTest:testInvalidateMultipleNonces() (gas: 83150) +AllowanceTransferTest:testInvalidateNonces() (gas: 62847) +AllowanceTransferTest:testInvalidateNoncesInvalid() (gas: 16327) +AllowanceTransferTest:testLockdown() (gas: 145984) +AllowanceTransferTest:testLockdownEvent() (gas: 117749) +AllowanceTransferTest:testMaxAllowance() (gas: 134888) +AllowanceTransferTest:testMaxAllowanceDirtyWrite() (gas: 117455) +AllowanceTransferTest:testPartialAllowance() (gas: 105140) +AllowanceTransferTest:testReuseOrderedNonceInvalid() (gas: 69154) +AllowanceTransferTest:testSetAllowance() (gas: 89627) +AllowanceTransferTest:testSetAllowanceBatch() (gas: 133740) +AllowanceTransferTest:testSetAllowanceBatchDifferentNonces() (gas: 118603) +AllowanceTransferTest:testSetAllowanceBatchDirtyWrite() (gas: 99210) +AllowanceTransferTest:testSetAllowanceBatchEvent() (gas: 116049) +AllowanceTransferTest:testSetAllowanceCompactSig() (gas: 89587) +AllowanceTransferTest:testSetAllowanceDeadlinePassed() (gas: 56512) AllowanceTransferTest:testSetAllowanceDirtyWrite() (gas: 72175) -AllowanceTransferTest:testSetAllowanceIncorrectSigLength() (gas: 29157) -AllowanceTransferTest:testSetAllowanceInvalidSignature() (gas: 64071) -AllowanceTransferTest:testSetAllowanceTransfer() (gas: 103161) -AllowanceTransferTest:testSetAllowanceTransferDirtyNonceDirtyTransfer() (gas: 97432) -AllowanceTransferTest:testTransferFromWithGasSnapshot() (gas: 133004) -AllowanceUnitTest:testPackAndUnpack(uint160,uint48,uint48) (runs: 256, μ: 38998, ~: 39076) -AllowanceUnitTest:testUpdateAllRandomly(uint160,uint48,uint48) (runs: 256, μ: 40222, ~: 40223) -AllowanceUnitTest:testUpdateAmountExpirationRandomly(uint160,uint48) (runs: 256, μ: 39224, ~: 39225) -CompactSignature:testCompactSignature27() (gas: 253) -CompactSignature:testCompactSignature28() (gas: 141) -DeployPermit2Test:testAllowanceTransferSanityCheck() (gas: 101958) -DeployPermit2Test:testDeployPermit2() (gas: 4337486) -DeployPermit2Test:testSignatureTransferSanityCheck() (gas: 92819) -EIP712Test:testDomainSeparator() (gas: 5804) -EIP712Test:testDomainSeparatorAfterFork() (gas: 10787) -MockPermit2Lib:testPermit2Code(address):(bool) (runs: 256, μ: 3016, ~: 3016) -NonceBitmapTest:testHighNonces() (gas: 36186) -NonceBitmapTest:testInvalidateFullWord() (gas: 63125) -NonceBitmapTest:testInvalidateNoncesRandomly(uint248,uint256) (runs: 256, μ: 30308, ~: 31008) -NonceBitmapTest:testInvalidateNonzeroWord() (gas: 85665) -NonceBitmapTest:testInvalidateTwoNoncesRandomly(uint248,uint256,uint256) (runs: 256, μ: 39187, ~: 39187) -NonceBitmapTest:testLowNonces() (gas: 41004) -NonceBitmapTest:testNonceWordBoundary() (gas: 42203) -NonceBitmapTest:testUseTwoRandomNonces(uint256,uint256) (runs: 256, μ: 49205, ~: 51640) -NonceBitmapTest:testUsingNonceTwiceFails(uint256) (runs: 256, μ: 21866, ~: 21889) -Permit2LibTest:testOZSafePermit() (gas: 24553) -Permit2LibTest:testOZSafePermitPlusOZSafeTransferFrom() (gas: 129219) -Permit2LibTest:testOZSafeTransferFrom() (gas: 38941) -Permit2LibTest:testPermit2() (gas: 22834) -Permit2LibTest:testPermit2DSLessToken() (gas: 7033) -Permit2LibTest:testPermit2DSMore32Token() (gas: 7120) -Permit2LibTest:testPermit2DSMoreToken() (gas: 6979) -Permit2LibTest:testPermit2Full() (gas: 42293) -Permit2LibTest:testPermit2InvalidAmount() (gas: 20860) -Permit2LibTest:testPermit2LargerDS() (gas: 51338) -Permit2LibTest:testPermit2LargerDSRevert() (gas: 32778) -Permit2LibTest:testPermit2NonPermitFallback() (gas: 37138) -Permit2LibTest:testPermit2NonPermitToken() (gas: 32101) -Permit2LibTest:testPermit2PlusTransferFrom2() (gas: 126951) -Permit2LibTest:testPermit2PlusTransferFrom2WithNonPermit() (gas: 148111) -Permit2LibTest:testPermit2PlusTransferFrom2WithNonPermitFallback() (gas: 174727) -Permit2LibTest:testPermit2PlusTransferFrom2WithWETH9Mainnet() (gas: 147802) -Permit2LibTest:testPermit2SmallerDS() (gas: 77694) -Permit2LibTest:testPermit2SmallerDSNoRevert() (gas: 59305) -Permit2LibTest:testPermit2WETH9Mainnet() (gas: 28777) -Permit2LibTest:testSimplePermit2() (gas: 29010) -Permit2LibTest:testSimplePermit2InvalidAmount() (gas: 16925) -Permit2LibTest:testSimplePermit2PlusTransferFrom2WithNonPermit() (gas: 148309) -Permit2LibTest:testStandardPermit() (gas: 22384) +AllowanceTransferTest:testSetAllowanceIncorrectSigLength() (gas: 29198) +AllowanceTransferTest:testSetAllowanceInvalidSignature() (gas: 64065) +AllowanceTransferTest:testSetAllowanceTransfer() (gas: 103115) +AllowanceTransferTest:testSetAllowanceTransferDirtyNonceDirtyTransfer() (gas: 97194) +AllowanceTransferTest:testTransferFromWithGasSnapshot() (gas: 132867) +AllowanceUnitTest:testPackAndUnpack(uint160,uint48,uint48) (runs: 256, μ: 39025, ~: 39103) +AllowanceUnitTest:testUpdateAllRandomly(uint160,uint48,uint48) (runs: 256, μ: 40243, ~: 40244) +AllowanceUnitTest:testUpdateAmountExpirationRandomly(uint160,uint48) (runs: 256, μ: 39169, ~: 39170) +CompactSignature:testCompactSignature27() (gas: 300) +CompactSignature:testCompactSignature28() (gas: 144) +DeployPermit2Test:testAllowanceTransferSanityCheck() (gas: 101876) +DeployPermit2Test:testDeployPermit2() (gas: 4337527) +DeployPermit2Test:testSignatureTransferSanityCheck() (gas: 92792) +EIP712Test:testDomainSeparator() (gas: 5881) +EIP712Test:testDomainSeparatorAfterFork() (gas: 10830) +MockPermit2Lib:testPermit2Code(address):(bool) (runs: 256, μ: 3003, ~: 3016) +NonceBitmapTest:testHighNonces() (gas: 36305) +NonceBitmapTest:testInvalidateFullWord() (gas: 63061) +NonceBitmapTest:testInvalidateNoncesRandomly(uint248,uint256) (runs: 256, μ: 30439, ~: 31139) +NonceBitmapTest:testInvalidateNonzeroWord() (gas: 85642) +NonceBitmapTest:testInvalidateTwoNoncesRandomly(uint248,uint256,uint256) (runs: 256, μ: 39182, ~: 39182) +NonceBitmapTest:testLowNonces() (gas: 41041) +NonceBitmapTest:testNonceWordBoundary() (gas: 42284) +NonceBitmapTest:testUseTwoRandomNonces(uint256,uint256) (runs: 256, μ: 49190, ~: 51625) +NonceBitmapTest:testUsingNonceTwiceFails(uint256) (runs: 256, μ: 21935, ~: 21960) +Permit2LibTest:testOZSafePermit() (gas: 24682) +Permit2LibTest:testOZSafePermitPlusOZSafeTransferFrom() (gas: 129329) +Permit2LibTest:testOZSafeTransferFrom() (gas: 39007) +Permit2LibTest:testPermit2() (gas: 22941) +Permit2LibTest:testPermit2DSLessToken() (gas: 7143) +Permit2LibTest:testPermit2DSMore32Token() (gas: 7252) +Permit2LibTest:testPermit2DSMoreToken() (gas: 7023) +Permit2LibTest:testPermit2Full() (gas: 42356) +Permit2LibTest:testPermit2InvalidAmount() (gas: 21011) +Permit2LibTest:testPermit2LargerDS() (gas: 51464) +Permit2LibTest:testPermit2LargerDSRevert() (gas: 32841) +Permit2LibTest:testPermit2NonPermitFallback() (gas: 37245) +Permit2LibTest:testPermit2NonPermitToken() (gas: 32164) +Permit2LibTest:testPermit2PlusTransferFrom2() (gas: 126995) +Permit2LibTest:testPermit2PlusTransferFrom2WithNonPermit() (gas: 148221) +Permit2LibTest:testPermit2PlusTransferFrom2WithNonPermitFallback() (gas: 174749) +Permit2LibTest:testPermit2PlusTransferFrom2WithWETH9Mainnet() (gas: 147934) +Permit2LibTest:testPermit2SmallerDS() (gas: 77688) +Permit2LibTest:testPermit2SmallerDSNoRevert() (gas: 59324) +Permit2LibTest:testPermit2WETH9Mainnet() (gas: 28774) +Permit2LibTest:testSimplePermit2() (gas: 29117) +Permit2LibTest:testSimplePermit2InvalidAmount() (gas: 16944) +Permit2LibTest:testSimplePermit2PlusTransferFrom2WithNonPermit() (gas: 148463) +Permit2LibTest:testStandardPermit() (gas: 22535) Permit2LibTest:testStandardTransferFrom() (gas: 38143) -Permit2LibTest:testTransferFrom2() (gas: 38624) -Permit2LibTest:testTransferFrom2Full() (gas: 53280) -Permit2LibTest:testTransferFrom2InvalidAmount() (gas: 12710) -Permit2LibTest:testTransferFrom2NonPermitToken() (gas: 53126) -SignatureTransferTest:testCorrectWitnessTypehashes() (gas: 3075) -SignatureTransferTest:testGasMultiplePermitBatchTransferFrom() (gas: 270919) -SignatureTransferTest:testGasSinglePermitBatchTransferFrom() (gas: 186316) -SignatureTransferTest:testGasSinglePermitTransferFrom() (gas: 123850) -SignatureTransferTest:testInvalidateUnorderedNonces() (gas: 41268) -SignatureTransferTest:testPermitBatchMultiPermitSingleTransfer() (gas: 133644) -SignatureTransferTest:testPermitBatchTransferFrom() (gas: 162010) -SignatureTransferTest:testPermitBatchTransferFromSingleRecipient() (gas: 190319) -SignatureTransferTest:testPermitBatchTransferFromTypedWitness() (gas: 239854) -SignatureTransferTest:testPermitBatchTransferFromTypedWitnessInvalidType() (gas: 84467) -SignatureTransferTest:testPermitBatchTransferFromTypedWitnessInvalidTypeHash() (gas: 85864) -SignatureTransferTest:testPermitBatchTransferFromTypedWitnessInvalidWitness() (gas: 85688) -SignatureTransferTest:testPermitBatchTransferInvalidAmountsLengthMismatch() (gas: 43967) -SignatureTransferTest:testPermitBatchTransferMultiAddr() (gas: 160406) -SignatureTransferTest:testPermitBatchTransferSingleRecipientManyTokens() (gas: 211834) -SignatureTransferTest:testPermitTransferFrom() (gas: 93012) -SignatureTransferTest:testPermitTransferFromCompactSig() (gas: 123927) -SignatureTransferTest:testPermitTransferFromIncorrectSigLength() (gas: 51327) -SignatureTransferTest:testPermitTransferFromInvalidNonce() (gas: 72799) -SignatureTransferTest:testPermitTransferFromRandomNonceAndAmount(uint256,uint128) (runs: 256, μ: 95754, ~: 96730) -SignatureTransferTest:testPermitTransferFromToSpender() (gas: 93342) -SignatureTransferTest:testPermitTransferFromTypedWitness() (gas: 125271) -SignatureTransferTest:testPermitTransferFromTypedWitnessInvalidType() (gas: 55906) -SignatureTransferTest:testPermitTransferFromTypedWitnessInvalidTypehash() (gas: 56794) -SignatureTransferTest:testPermitTransferSpendLessThanFull(uint256,uint128) (runs: 256, μ: 97989, ~: 99707) -TypehashGeneration:testPermitBatch() (gas: 40493) -TypehashGeneration:testPermitBatchTransferFrom() (gas: 49854) -TypehashGeneration:testPermitBatchTransferFromWithWitness() (gas: 56587) +Permit2LibTest:testTransferFrom2() (gas: 38734) +Permit2LibTest:testTransferFrom2Full() (gas: 53368) +Permit2LibTest:testTransferFrom2InvalidAmount() (gas: 12732) +Permit2LibTest:testTransferFrom2NonPermitToken() (gas: 53170) +SignatureTransferTest:testCorrectWitnessTypehashes() (gas: 3091) +SignatureTransferTest:testGasMultiplePermitBatchTransferFrom() (gas: 270972) +SignatureTransferTest:testGasSinglePermitBatchTransferFrom() (gas: 183860) +SignatureTransferTest:testGasSinglePermitTransferFrom() (gas: 123854) +SignatureTransferTest:testInvalidateUnorderedNonces() (gas: 41396) +SignatureTransferTest:testPermitBatchMultiPermitSingleTransfer() (gas: 133675) +SignatureTransferTest:testPermitBatchTransferFrom() (gas: 162019) +SignatureTransferTest:testPermitBatchTransferFromSingleRecipient() (gas: 187957) +SignatureTransferTest:testPermitBatchTransferFromTypedWitness() (gas: 239926) +SignatureTransferTest:testPermitBatchTransferFromTypedWitnessInvalidType() (gas: 84489) +SignatureTransferTest:testPermitBatchTransferFromTypedWitnessInvalidTypeHash() (gas: 86007) +SignatureTransferTest:testPermitBatchTransferFromTypedWitnessInvalidWitness() (gas: 85751) +SignatureTransferTest:testPermitBatchTransferInvalidAmountsLengthMismatch() (gas: 41574) +SignatureTransferTest:testPermitBatchTransferMultiAddr() (gas: 160547) +SignatureTransferTest:testPermitBatchTransferSingleRecipientManyTokens() (gas: 209422) +SignatureTransferTest:testPermitTransferFrom() (gas: 92909) +SignatureTransferTest:testPermitTransferFromCompactSig() (gas: 124059) +SignatureTransferTest:testPermitTransferFromIncorrectSigLength() (gas: 51346) +SignatureTransferTest:testPermitTransferFromInvalidNonce() (gas: 72928) +SignatureTransferTest:testPermitTransferFromRandomNonceAndAmount(uint256,uint128) (runs: 256, μ: 95752, ~: 96728) +SignatureTransferTest:testPermitTransferFromToSpender() (gas: 93283) +SignatureTransferTest:testPermitTransferFromTypedWitness() (gas: 125159) +SignatureTransferTest:testPermitTransferFromTypedWitnessInvalidType() (gas: 55947) +SignatureTransferTest:testPermitTransferFromTypedWitnessInvalidTypehash() (gas: 56879) +SignatureTransferTest:testPermitTransferSpendLessThanFull(uint256,uint128) (runs: 256, μ: 97604, ~: 99733) +TypehashGeneration:testPermitBatch() (gas: 40473) +TypehashGeneration:testPermitBatchTransferFrom() (gas: 49837) +TypehashGeneration:testPermitBatchTransferFromWithWitness() (gas: 56621) TypehashGeneration:testPermitBatchTransferFromWithWitnessIncorrectPermitData() (gas: 56744) -TypehashGeneration:testPermitBatchTransferFromWithWitnessIncorrectTypehashStub() (gas: 57229) -TypehashGeneration:testPermitSingle() (gas: 28117) -TypehashGeneration:testPermitTransferFrom() (gas: 36520) -TypehashGeneration:testPermitTransferFromWithWitness() (gas: 43369) -TypehashGeneration:testPermitTransferFromWithWitnessIncorrectPermitData() (gas: 43430) -TypehashGeneration:testPermitTransferFromWithWitnessIncorrectTypehashStub() (gas: 43833) \ No newline at end of file +TypehashGeneration:testPermitBatchTransferFromWithWitnessIncorrectTypehashStub() (gas: 57353) +TypehashGeneration:testPermitSingle() (gas: 28138) +TypehashGeneration:testPermitTransferFrom() (gas: 36511) +TypehashGeneration:testPermitTransferFromWithWitness() (gas: 43469) +TypehashGeneration:testPermitTransferFromWithWitnessIncorrectPermitData() (gas: 43436) +TypehashGeneration:testPermitTransferFromWithWitnessIncorrectTypehashStub() (gas: 43956) \ No newline at end of file diff --git a/lib/forge-std b/lib/forge-std index 27e14b7f..66bf4e2c 160000 --- a/lib/forge-std +++ b/lib/forge-std @@ -1 +1 @@ -Subproject commit 27e14b7f2448e5f5ac32719f51fe652aa0b0733e +Subproject commit 66bf4e2c92cf507531599845e8d5a08cc2e3b5bb diff --git a/package.json b/package.json new file mode 100644 index 00000000..a38ebcff --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "@uniswap/permit2", + "description": "Low-overhead, next generation token approval/meta-tx system to make token approvals easier, more secure, and more consistent across applications", + "version": "1.0.0", + "bugs": "https://github.com/Uniswap/permit2/issues", + "keywords": [ + "ethereum", + "permit2", + "uniswap" + ], + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/Uniswap/permit2.git" + } +} \ No newline at end of file diff --git a/src/EIP712.sol b/src/EIP712.sol index bbd77f07..971a03db 100644 --- a/src/EIP712.sol +++ b/src/EIP712.sol @@ -1,10 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.17; +import {IEIP712} from "./interfaces/IEIP712.sol"; + /// @notice EIP712 helpers for permit2 /// @dev Maintains cross-chain replay protection in the event of a fork /// @dev Reference: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/EIP712.sol -contract EIP712 { +contract EIP712 is IEIP712 { // 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. bytes32 private immutable _CACHED_DOMAIN_SEPARATOR; @@ -21,7 +23,7 @@ contract EIP712 { /// @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) { + function DOMAIN_SEPARATOR() public view override returns (bytes32) { return block.chainid == _CACHED_CHAIN_ID ? _CACHED_DOMAIN_SEPARATOR : _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME); diff --git a/src/interfaces/IAllowanceTransfer.sol b/src/interfaces/IAllowanceTransfer.sol index 7135335e..cd81c6c0 100644 --- a/src/interfaces/IAllowanceTransfer.sol +++ b/src/interfaces/IAllowanceTransfer.sol @@ -1,10 +1,12 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.17; +pragma solidity ^0.8.0; + +import {IEIP712} from "./IEIP712.sol"; /// @title AllowanceTransfer /// @notice Handles ERC20 token permissions through signature based allowance setting and ERC20 token transfers by checking allowed amounts /// @dev Requires user's token approval on the Permit2 contract -interface IAllowanceTransfer { +interface IAllowanceTransfer is IEIP712 { /// @notice Thrown when an allowance on a token has expired. /// @param deadline The timestamp at which the allowed amount is no longer valid error AllowanceExpired(uint256 deadline); diff --git a/src/interfaces/IDAIPermit.sol b/src/interfaces/IDAIPermit.sol index 912b7817..7cf9d3af 100644 --- a/src/interfaces/IDAIPermit.sol +++ b/src/interfaces/IDAIPermit.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.17; +pragma solidity ^0.8.0; interface IDAIPermit { /// @param holder The address of the token owner. diff --git a/src/interfaces/IEIP712.sol b/src/interfaces/IEIP712.sol new file mode 100644 index 00000000..355c443f --- /dev/null +++ b/src/interfaces/IEIP712.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IEIP712 { + function DOMAIN_SEPARATOR() external view returns (bytes32); +} diff --git a/src/interfaces/IERC1271.sol b/src/interfaces/IERC1271.sol index b8e66762..a3c1cbac 100644 --- a/src/interfaces/IERC1271.sol +++ b/src/interfaces/IERC1271.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.17; +pragma solidity ^0.8.0; interface IERC1271 { /// @dev Should return whether the signature provided is valid for the provided data diff --git a/src/interfaces/IPermit2.sol b/src/interfaces/IPermit2.sol new file mode 100644 index 00000000..a800a18f --- /dev/null +++ b/src/interfaces/IPermit2.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {ISignatureTransfer} from "./ISignatureTransfer.sol"; +import {IAllowanceTransfer} from "./IAllowanceTransfer.sol"; + +/// @notice Permit2 handles signature-based transfers in SignatureTransfer and allowance-based transfers in AllowanceTransfer. +/// @dev Users must approve Permit2 before calling any of the transfer functions. +interface IPermit2 is ISignatureTransfer, IAllowanceTransfer { +// IPermit2 unifies the two interfaces so users have maximal flexibility with their approval. +} diff --git a/src/interfaces/ISignatureTransfer.sol b/src/interfaces/ISignatureTransfer.sol index 8b76a3eb..63297c3b 100644 --- a/src/interfaces/ISignatureTransfer.sol +++ b/src/interfaces/ISignatureTransfer.sol @@ -1,10 +1,12 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.17; +pragma solidity ^0.8.0; + +import {IEIP712} from "./IEIP712.sol"; /// @title SignatureTransfer /// @notice Handles ERC20 token transfers through signature based actions /// @dev Requires user's token approval on the Permit2 contract -interface ISignatureTransfer { +interface ISignatureTransfer is IEIP712 { /// @notice Thrown when the requested amount for a transfer is larger than the permissioned amount /// @param maxAmount The maximum amount a spender can request to transfer error InvalidAmount(uint256 maxAmount); diff --git a/test/AllowanceTransferInvariants.t.sol b/test/AllowanceTransferInvariants.t.sol index 9fdbd290..a980f7ce 100644 --- a/test/AllowanceTransferInvariants.t.sol +++ b/test/AllowanceTransferInvariants.t.sol @@ -1,12 +1,12 @@ pragma solidity 0.8.17; -import "forge-std/Test.sol"; +import {Test} from "forge-std/Test.sol"; +import {StdInvariant} from "forge-std/StdInvariant.sol"; import {TokenProvider} from "./utils/TokenProvider.sol"; import {Permit2} from "../src/Permit2.sol"; import {IAllowanceTransfer} from "../src/interfaces/IAllowanceTransfer.sol"; import {SignatureVerification} from "../src/libraries/SignatureVerification.sol"; import {PermitSignature} from "./utils/PermitSignature.sol"; -import {InvariantTest} from "./utils/InvariantTest.sol"; import {MockERC20} from "./mocks/MockERC20.sol"; import {Permitter} from "./actors/Permitter.sol"; import {Spender} from "./actors/Spender.sol"; @@ -77,7 +77,7 @@ contract Runner { } } -contract AllowanceTransferInvariants is Test, InvariantTest { +contract AllowanceTransferInvariants is StdInvariant, Test { Permit2 permit2; Runner runner; MockERC20 token; @@ -86,8 +86,8 @@ contract AllowanceTransferInvariants is Test, InvariantTest { permit2 = new Permit2(); runner = new Runner(permit2); - addTargetContract(address(runner)); - addTargetSender(address(vm.addr(0xb0b0))); + targetContract(address(runner)); + targetSender(address(vm.addr(0xb0b0))); } function invariant_spendNeverExceedsPermit() public { diff --git a/test/AllowanceTransferTest.t.sol b/test/AllowanceTransferTest.t.sol index 16595ac0..a661e62e 100644 --- a/test/AllowanceTransferTest.t.sol +++ b/test/AllowanceTransferTest.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import "forge-std/Test.sol"; +import {StdStorage, stdStorage, Test} from "forge-std/Test.sol"; import {TokenProvider} from "./utils/TokenProvider.sol"; import {Permit2} from "../src/Permit2.sol"; import {PermitSignature} from "./utils/PermitSignature.sol"; diff --git a/test/AllowanceUnitTest.sol b/test/AllowanceUnitTest.sol index 2aa0d170..4bac6432 100644 --- a/test/AllowanceUnitTest.sol +++ b/test/AllowanceUnitTest.sol @@ -1,9 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import "forge-std/Test.sol"; -import "./mocks/MockPermit2.sol"; +import {Test} from "forge-std/Test.sol"; +import {MockPermit2} from "./mocks/MockPermit2.sol"; import {TokenProvider} from "./utils/TokenProvider.sol"; +import {Allowance} from "../src/libraries/Allowance.sol"; contract AllowanceUnitTest is Test, TokenProvider { MockPermit2 permit2; diff --git a/test/CompactSignature.t.sol b/test/CompactSignature.t.sol index 0f6cbc91..0884a699 100644 --- a/test/CompactSignature.t.sol +++ b/test/CompactSignature.t.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import "forge-std/Test.sol"; +import {Test} from "forge-std/Test.sol"; import {PermitSignature} from "./utils/PermitSignature.sol"; -contract CompactSignature is PermitSignature { +contract CompactSignature is Test, PermitSignature { /// test cases pulled from EIP-2098 function testCompactSignature27() public { bytes32 r = 0x68a020a209d3d56c46f38cc50a33f704f4a9a10a59377f8dd762ac66910e9b90; diff --git a/test/EIP712.t.sol b/test/EIP712.t.sol index b56d6e24..ac28144b 100644 --- a/test/EIP712.t.sol +++ b/test/EIP712.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import "forge-std/Test.sol"; +import {Test} from "forge-std/Test.sol"; import {Permit2} from "../src/Permit2.sol"; // forge test --match-contract EIP712 diff --git a/test/NonceBitmap.t.sol b/test/NonceBitmap.t.sol index eed4f561..f29d6fbe 100644 --- a/test/NonceBitmap.t.sol +++ b/test/NonceBitmap.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import "forge-std/Test.sol"; +import {Test} from "forge-std/Test.sol"; import {SafeERC20, IERC20, IERC20Permit} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; import {MockPermit2} from "./mocks/MockPermit2.sol"; import {InvalidNonce} from "../src/PermitErrors.sol"; diff --git a/test/Permit2Lib.t.sol b/test/Permit2Lib.t.sol index 5048a633..cd14c8de 100644 --- a/test/Permit2Lib.t.sol +++ b/test/Permit2Lib.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import "forge-std/Test.sol"; +import {Test} from "forge-std/Test.sol"; import {SafeERC20, IERC20, IERC20Permit} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; import {DSTestPlus} from "solmate/src/test/utils/DSTestPlus.sol"; diff --git a/test/SignatureTransfer.t.sol b/test/SignatureTransfer.t.sol index 758b1498..0d6b710e 100644 --- a/test/SignatureTransfer.t.sol +++ b/test/SignatureTransfer.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import "forge-std/Test.sol"; +import {Test} from "forge-std/Test.sol"; import {SafeERC20, IERC20, IERC20Permit} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; import {SignatureVerification} from "../src/libraries/SignatureVerification.sol"; import {TokenProvider} from "./utils/TokenProvider.sol"; diff --git a/test/TypehashGeneration.t.sol b/test/TypehashGeneration.t.sol index 763b2ac5..68920dbc 100644 --- a/test/TypehashGeneration.t.sol +++ b/test/TypehashGeneration.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import "forge-std/Test.sol"; +import {Test} from "forge-std/Test.sol"; import {PermitSignature} from "./utils/PermitSignature.sol"; import {PermitHash} from "../src/libraries/PermitHash.sol"; import {IAllowanceTransfer} from "../src/interfaces/IAllowanceTransfer.sol"; diff --git a/test/actors/Permitter.sol b/test/actors/Permitter.sol index 76e00e8e..76dbbc17 100644 --- a/test/actors/Permitter.sol +++ b/test/actors/Permitter.sol @@ -1,6 +1,6 @@ pragma solidity 0.8.17; -import "forge-std/Test.sol"; +import {Vm} from "forge-std/Vm.sol"; import {Permit2} from "../../src/Permit2.sol"; import {IAllowanceTransfer} from "../../src/interfaces/IAllowanceTransfer.sol"; import {PermitSignature} from "../utils/PermitSignature.sol"; @@ -10,6 +10,8 @@ contract Permitter is PermitSignature { uint256 private immutable privateKey; Permit2 private immutable permit2; MockERC20 private immutable token; + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + address public immutable signer; mapping(address => uint48) private nonces; diff --git a/test/integration/Argent.t.sol b/test/integration/Argent.t.sol index 1eb8ceb9..51b29526 100644 --- a/test/integration/Argent.t.sol +++ b/test/integration/Argent.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import "forge-std/Test.sol"; +import {Test} from "forge-std/Test.sol"; import {IERC1271} from "../../src/interfaces/IERC1271.sol"; interface WalletFactory { diff --git a/test/integration/GnosisSafe.t.sol b/test/integration/GnosisSafe.t.sol index 68eb104d..5469be55 100644 --- a/test/integration/GnosisSafe.t.sol +++ b/test/integration/GnosisSafe.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import "forge-std/Test.sol"; +import {Test} from "forge-std/Test.sol"; import {IERC1271} from "../../src/interfaces/IERC1271.sol"; interface GnosisSafeProxy is IERC1271 { diff --git a/test/integration/MainnetToken.t.sol b/test/integration/MainnetToken.t.sol index c90ed983..fc03ea7c 100644 --- a/test/integration/MainnetToken.t.sol +++ b/test/integration/MainnetToken.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import "forge-std/Test.sol"; +import {Test} from "forge-std/Test.sol"; import {SafeTransferLib} from "solmate/src/utils/SafeTransferLib.sol"; import {ERC20} from "solmate/src/tokens/ERC20.sol"; import {AddressBuilder} from "../utils/AddressBuilder.sol"; diff --git a/test/mocks/MockHash.sol b/test/mocks/MockHash.sol index 1cf1f59a..de7ab4ca 100644 --- a/test/mocks/MockHash.sol +++ b/test/mocks/MockHash.sol @@ -1,9 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import "forge-std/Test.sol"; import {ISignatureTransfer} from "../../src/interfaces/ISignatureTransfer.sol"; -import {IAllowanceTransfer} from "../../src/interfaces/IAllowanceTransfer.sol"; import {PermitHash} from "../../src/libraries/PermitHash.sol"; contract MockHash { diff --git a/test/utils/DeployPermit2.t.sol b/test/utils/DeployPermit2.t.sol index 27408bc5..d314d022 100644 --- a/test/utils/DeployPermit2.t.sol +++ b/test/utils/DeployPermit2.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import "forge-std/Test.sol"; +import {Test} from "forge-std/Test.sol"; import {IAllowanceTransfer} from "../../src/interfaces/IAllowanceTransfer.sol"; import {ISignatureTransfer} from "../../src/interfaces/ISignatureTransfer.sol"; import {TokenProvider} from "./TokenProvider.sol"; diff --git a/test/utils/InvariantTest.sol b/test/utils/InvariantTest.sol deleted file mode 100644 index dae5df15..00000000 --- a/test/utils/InvariantTest.sol +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later -// from: https://github.com/maple-labs/contract-test-utils/blob/add-bounded-invariants/contracts/test.sol -pragma solidity 0.8.17; - -contract InvariantTest { - address[] private _excludedContracts; - address[] private _targetContracts; - address[] private _targetSenders; - - function addTargetContract(address newTargetContract_) internal { - _targetContracts.push(newTargetContract_); - } - - function targetContracts() public view returns (address[] memory targetContracts_) { - require(_targetContracts.length != uint256(0), "NO_TARGET_CONTRACTS"); - return _targetContracts; - } - - function addTargetSender(address newTargetSender_) internal { - _targetSenders.push(newTargetSender_); - } - - function targetSenders() public view returns (address[] memory targetSenders_) { - require(_targetSenders.length != uint256(0), "NO_TARGET_SENDERS"); - return _targetSenders; - } - - function excludeContract(address newExcludedContract_) internal { - _excludedContracts.push(newExcludedContract_); - } - - function excludeContracts() public view returns (address[] memory excludedContracts_) { - require(_excludedContracts.length != uint256(0), "NO_TARGET_CONTRACTS"); - return _excludedContracts; - } -} diff --git a/test/utils/PermitSignature.sol b/test/utils/PermitSignature.sol index fb65618e..0cb0c3d2 100644 --- a/test/utils/PermitSignature.sol +++ b/test/utils/PermitSignature.sol @@ -1,14 +1,15 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import {Test} from "forge-std/Test.sol"; +import {Vm} from "forge-std/Vm.sol"; import {EIP712} from "openzeppelin-contracts/contracts/utils/cryptography/draft-EIP712.sol"; import {ECDSA} from "openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol"; -import {Permit2} from "../../src/Permit2.sol"; import {IAllowanceTransfer} from "../../src/interfaces/IAllowanceTransfer.sol"; import {ISignatureTransfer} from "../../src/interfaces/ISignatureTransfer.sol"; -contract PermitSignature is Test { +contract PermitSignature { + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + bytes32 public constant _PERMIT_DETAILS_TYPEHASH = keccak256("PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)"); @@ -34,7 +35,7 @@ contract PermitSignature is Test { IAllowanceTransfer.PermitSingle memory permit, uint256 privateKey, bytes32 domainSeparator - ) internal returns (uint8 v, bytes32 r, bytes32 s) { + ) internal pure returns (uint8 v, bytes32 r, bytes32 s) { bytes32 permitHash = keccak256(abi.encode(_PERMIT_DETAILS_TYPEHASH, permit.details)); bytes32 msgHash = keccak256( @@ -52,7 +53,7 @@ contract PermitSignature is Test { IAllowanceTransfer.PermitSingle memory permit, uint256 privateKey, bytes32 domainSeparator - ) internal returns (bytes memory sig) { + ) internal pure returns (bytes memory sig) { (uint8 v, bytes32 r, bytes32 s) = getPermitSignatureRaw(permit, privateKey, domainSeparator); return bytes.concat(r, s, bytes1(v)); } @@ -61,7 +62,7 @@ contract PermitSignature is Test { IAllowanceTransfer.PermitSingle memory permit, uint256 privateKey, bytes32 domainSeparator - ) internal returns (bytes memory sig) { + ) internal pure returns (bytes memory sig) { (uint8 v, bytes32 r, bytes32 s) = getPermitSignatureRaw(permit, privateKey, domainSeparator); bytes32 vs; (r, vs) = _getCompactSignature(v, r, s); @@ -72,7 +73,7 @@ contract PermitSignature is Test { ISignatureTransfer.PermitTransferFrom memory permit, uint256 privateKey, bytes32 domainSeparator - ) internal returns (bytes memory sig) { + ) internal view returns (bytes memory sig) { bytes32 tokenPermissions = keccak256(abi.encode(_TOKEN_PERMISSIONS_TYPEHASH, permit.permitted)); bytes32 msgHash = keccak256( abi.encodePacked( @@ -106,7 +107,7 @@ contract PermitSignature is Test { IAllowanceTransfer.PermitBatch memory permit, uint256 privateKey, bytes32 domainSeparator - ) internal returns (bytes memory sig) { + ) internal pure returns (bytes memory sig) { bytes32[] memory permitHashes = new bytes32[](permit.details.length); for (uint256 i = 0; i < permit.details.length; ++i) { permitHashes[i] = keccak256(abi.encode(_PERMIT_DETAILS_TYPEHASH, permit.details[i])); @@ -134,7 +135,7 @@ contract PermitSignature is Test { ISignatureTransfer.PermitTransferFrom memory permit, uint256 privateKey, bytes32 domainSeparator - ) internal returns (bytes memory sig) { + ) internal view returns (bytes memory sig) { bytes32 tokenPermissions = keccak256(abi.encode(_TOKEN_PERMISSIONS_TYPEHASH, permit.permitted)); bytes32 msgHash = keccak256( abi.encodePacked( @@ -158,7 +159,7 @@ contract PermitSignature is Test { bytes32 typehash, bytes32 witness, bytes32 domainSeparator - ) internal returns (bytes memory sig) { + ) internal view returns (bytes memory sig) { bytes32 tokenPermissions = keccak256(abi.encode(_TOKEN_PERMISSIONS_TYPEHASH, permit.permitted)); bytes32 msgHash = keccak256( @@ -177,7 +178,7 @@ contract PermitSignature is Test { ISignatureTransfer.PermitBatchTransferFrom memory permit, uint256 privateKey, bytes32 domainSeparator - ) internal returns (bytes memory sig) { + ) internal view returns (bytes memory sig) { bytes32[] memory tokenPermissions = new bytes32[](permit.permitted.length); for (uint256 i = 0; i < permit.permitted.length; ++i) { tokenPermissions[i] = keccak256(abi.encode(_TOKEN_PERMISSIONS_TYPEHASH, permit.permitted[i])); @@ -208,7 +209,7 @@ contract PermitSignature is Test { bytes32 typeHash, bytes32 witness, bytes32 domainSeparator - ) internal returns (bytes memory sig) { + ) internal view returns (bytes memory sig) { bytes32[] memory tokenPermissions = new bytes32[](permit.permitted.length); for (uint256 i = 0; i < permit.permitted.length; ++i) { tokenPermissions[i] = keccak256(abi.encode(_TOKEN_PERMISSIONS_TYPEHASH, permit.permitted[i])); diff --git a/test/utils/TokenProvider.sol b/test/utils/TokenProvider.sol index a240fa40..8b28fa4c 100644 --- a/test/utils/TokenProvider.sol +++ b/test/utils/TokenProvider.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import "forge-std/Test.sol"; +import {Vm} from "forge-std/Test.sol"; import {MockERC20} from "../mocks/MockERC20.sol"; import {MockERC721} from "../mocks/MockERC721.sol"; import {MockERC1155} from "../mocks/MockERC1155.sol";