Skip to content

Commit bc0d063

Browse files
committed
test: permit2 flows
1 parent c8913cc commit bc0d063

File tree

2 files changed

+467
-1
lines changed

2 files changed

+467
-1
lines changed

test/Helpers.t.sol

Lines changed: 125 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
// SPDX-License-Identifier: UNLICENSED
22
pragma solidity ^0.8.24;
33

4-
import {Test, console2} from "forge-std/Test.sol";
54
import {Zenith} from "../src/Zenith.sol";
5+
import {UsesPermit2} from "../src/permit2/UsesPermit2.sol";
6+
7+
import {Test, console2} from "forge-std/Test.sol";
68
import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
79
import {ERC20Burnable} from "openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol";
10+
import {ISignatureTransfer} from "permit2/src/interfaces/ISignatureTransfer.sol";
811

912
contract TestERC20 is ERC20Burnable {
1013
constructor(string memory name_, string memory symbol_) ERC20(name_, symbol_) {}
@@ -14,6 +17,127 @@ contract TestERC20 is ERC20Burnable {
1417
}
1518
}
1619

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+
17141
contract HelpersTest is Test {
18142
Zenith public target;
19143

0 commit comments

Comments
 (0)