1
1
// SPDX-License-Identifier: UNLICENSED
2
2
pragma solidity ^ 0.8.24 ;
3
3
4
- import {Test, console2} from "forge-std/Test.sol " ;
5
4
import {Zenith} from "../src/Zenith.sol " ;
5
+ import {UsesPermit2} from "../src/permit2/UsesPermit2.sol " ;
6
+
7
+ import {Test, console2} from "forge-std/Test.sol " ;
6
8
import {ERC20 } from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol " ;
7
9
import {ERC20Burnable } from "openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol " ;
10
+ import {ISignatureTransfer} from "permit2/src/interfaces/ISignatureTransfer.sol " ;
8
11
9
12
contract TestERC20 is ERC20Burnable {
10
13
constructor (string memory name_ , string memory symbol_ ) ERC20 (name_, symbol_) {}
@@ -14,6 +17,127 @@ contract TestERC20 is ERC20Burnable {
14
17
}
15
18
}
16
19
20
+ contract Permit2Stub {
21
+ /// @notice stubbed `permitWitnessTransferFrom` - does not check signature, nonce, or deadline
22
+ function permitWitnessTransferFrom (
23
+ ISignatureTransfer.PermitTransferFrom memory permit ,
24
+ ISignatureTransfer.SignatureTransferDetails calldata transferDetails ,
25
+ address owner ,
26
+ bytes32 , /*witness*/
27
+ string calldata , /*witnessTypeString*/
28
+ bytes calldata /*signature*/
29
+ ) external {
30
+ ERC20 (permit.permitted.token).transferFrom (owner, transferDetails.to, transferDetails.requestedAmount);
31
+ }
32
+ }
33
+
34
+ contract BatchPermit2Stub {
35
+ function permitWitnessTransferFrom (
36
+ ISignatureTransfer.PermitBatchTransferFrom memory permit ,
37
+ ISignatureTransfer.SignatureTransferDetails[] calldata transferDetails ,
38
+ address owner ,
39
+ bytes32 , /*witness*/
40
+ string calldata , /*witnessTypeString*/
41
+ bytes calldata /*signature*/
42
+ ) external {
43
+ for (uint256 i = 0 ; i < transferDetails.length ; i++ ) {
44
+ ERC20 (permit.permitted[i].token).transferFrom (
45
+ owner, transferDetails[i].to, transferDetails[i].requestedAmount
46
+ );
47
+ }
48
+ }
49
+ }
50
+
51
+ contract Permit2Helpers is Test {
52
+ string public constant _PERMIT_TRANSFER_FROM_WITNESS_TYPEHASH_STUB =
53
+ "PermitWitnessTransferFrom(TokenPermissions permitted,address spender,uint256 nonce,uint256 deadline, " ;
54
+
55
+ bytes32 public constant _TOKEN_PERMISSIONS_TYPEHASH = keccak256 ("TokenPermissions(address token,uint256 amount) " );
56
+
57
+ string public constant _PERMIT_BATCH_WITNESS_TRANSFER_FROM_TYPEHASH_STUB =
58
+ "PermitBatchWitnessTransferFrom(TokenPermissions[] permitted,address spender,uint256 nonce,uint256 deadline, " ;
59
+
60
+ /// @notice given a Permit and a Witness, produce a signature from the `owner`
61
+ function signPermit (
62
+ uint256 signingKey ,
63
+ address spender ,
64
+ ISignatureTransfer.PermitTransferFrom memory permit ,
65
+ UsesPermit2.Witness memory _witness
66
+ ) internal pure returns (bytes memory signature ) {
67
+ bytes32 permit2Hash = hashWithWitness (spender, permit, _witness.witnessHash, _witness.witnessTypeString);
68
+ uint8 v;
69
+ bytes32 r;
70
+ bytes32 s;
71
+ (v, r, s) = vm.sign (signingKey, permit2Hash);
72
+ signature = abi.encodePacked (r, s, v);
73
+ }
74
+
75
+ // this function is private on permit2 contracts but need to port it here for test functionality
76
+ function hashWithWitness (
77
+ address spender ,
78
+ ISignatureTransfer.PermitTransferFrom memory _permit ,
79
+ bytes32 witness ,
80
+ string memory witnessTypeString
81
+ ) internal pure returns (bytes32 ) {
82
+ bytes32 typeHash = keccak256 (abi.encodePacked (_PERMIT_TRANSFER_FROM_WITNESS_TYPEHASH_STUB, witnessTypeString));
83
+
84
+ bytes32 tokenPermissionsHash = _hashTokenPermissions (_permit.permitted);
85
+ return keccak256 (abi.encode (typeHash, tokenPermissionsHash, spender, _permit.nonce, _permit.deadline, witness));
86
+ }
87
+
88
+ /// @notice given a Permit and a Witness, produce a signature from the `owner`
89
+ function signPermit (
90
+ uint256 signingKey ,
91
+ address spender ,
92
+ ISignatureTransfer.PermitBatchTransferFrom memory permit ,
93
+ UsesPermit2.Witness memory _witness
94
+ ) internal pure returns (bytes memory signature ) {
95
+ bytes32 permit2Hash = hashWithWitness (spender, permit, _witness.witnessHash, _witness.witnessTypeString);
96
+ uint8 v;
97
+ bytes32 r;
98
+ bytes32 s;
99
+ (v, r, s) = vm.sign (signingKey, permit2Hash);
100
+ signature = abi.encodePacked (r, s, v);
101
+ }
102
+
103
+ function hashWithWitness (
104
+ address spender ,
105
+ ISignatureTransfer.PermitBatchTransferFrom memory permit ,
106
+ bytes32 witness ,
107
+ string memory witnessTypeString
108
+ ) internal pure returns (bytes32 ) {
109
+ bytes32 typeHash =
110
+ keccak256 (abi.encodePacked (_PERMIT_BATCH_WITNESS_TRANSFER_FROM_TYPEHASH_STUB, witnessTypeString));
111
+
112
+ uint256 numPermitted = permit.permitted.length ;
113
+ bytes32 [] memory tokenPermissionHashes = new bytes32 [](numPermitted);
114
+
115
+ for (uint256 i = 0 ; i < numPermitted; ++ i) {
116
+ tokenPermissionHashes[i] = _hashTokenPermissions (permit.permitted[i]);
117
+ }
118
+
119
+ return keccak256 (
120
+ abi.encode (
121
+ typeHash,
122
+ keccak256 (abi.encodePacked (tokenPermissionHashes)),
123
+ spender,
124
+ permit.nonce,
125
+ permit.deadline,
126
+ witness
127
+ )
128
+ );
129
+ }
130
+
131
+ // this function is private on permit2 contracts but need to port it here for test functionality
132
+ function _hashTokenPermissions (ISignatureTransfer.TokenPermissions memory _permitted )
133
+ private
134
+ pure
135
+ returns (bytes32 )
136
+ {
137
+ return keccak256 (abi.encode (_TOKEN_PERMISSIONS_TYPEHASH, _permitted));
138
+ }
139
+ }
140
+
17
141
contract HelpersTest is Test {
18
142
Zenith public target;
19
143
0 commit comments