89 lines
3.4 KiB
Solidity
89 lines
3.4 KiB
Solidity
// SPDX-License-Identifier: BUSL-1.1
|
|
pragma solidity ^0.8.26;
|
|
|
|
import "./Constants.sol";
|
|
import "@permit2/src/interfaces/IAllowanceTransfer.sol";
|
|
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
|
|
contract Permit2TestHelper is Constants {
|
|
/**
|
|
* @dev Handles the Permit2 approval process for Alice, allowing the TychoRouter contract
|
|
* to spend `amount_in` of `tokenIn` on her behalf.
|
|
*
|
|
* This function approves the Permit2 contract to transfer the specified token amount
|
|
* and constructs a `PermitSingle` struct for the approval. It also generates a valid
|
|
* EIP-712 signature for the approval using Alice's private key.
|
|
*
|
|
* @param tokenIn The address of the token being approved.
|
|
* @param amount_in The amount of tokens to approve for transfer.
|
|
* @return permitSingle The `PermitSingle` struct containing the approval details.
|
|
* @return signature The EIP-712 signature for the approval.
|
|
*/
|
|
function handlePermit2Approval(
|
|
address tokenIn,
|
|
address spender,
|
|
uint256 amount_in
|
|
) internal returns (IAllowanceTransfer.PermitSingle memory, bytes memory) {
|
|
IERC20(tokenIn).approve(PERMIT2_ADDRESS, amount_in);
|
|
IAllowanceTransfer.PermitSingle memory permitSingle =
|
|
IAllowanceTransfer.PermitSingle({
|
|
details: IAllowanceTransfer.PermitDetails({
|
|
token: tokenIn,
|
|
amount: uint160(amount_in),
|
|
expiration: uint48(block.timestamp + 1 days),
|
|
nonce: 0
|
|
}),
|
|
spender: spender,
|
|
sigDeadline: block.timestamp + 1 days
|
|
});
|
|
|
|
bytes memory signature = signPermit2(permitSingle, ALICE_PK);
|
|
return (permitSingle, signature);
|
|
}
|
|
|
|
/**
|
|
* @dev Signs a Permit2 `PermitSingle` struct with the given private key.
|
|
* @param permit The `PermitSingle` struct to sign.
|
|
* @param privateKey The private key of the signer.
|
|
* @return The signature as a `bytes` array.
|
|
*/
|
|
function signPermit2(
|
|
IAllowanceTransfer.PermitSingle memory permit,
|
|
uint256 privateKey
|
|
) internal view returns (bytes memory) {
|
|
bytes32 _PERMIT_DETAILS_TYPEHASH = keccak256(
|
|
"PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)"
|
|
);
|
|
bytes32 _PERMIT_SINGLE_TYPEHASH = keccak256(
|
|
"PermitSingle(PermitDetails details,address spender,uint256 sigDeadline)PermitDetails(address token,uint160 amount,uint48 expiration,uint48 nonce)"
|
|
);
|
|
bytes32 domainSeparator = keccak256(
|
|
abi.encode(
|
|
keccak256(
|
|
"EIP712Domain(string name,uint256 chainId,address verifyingContract)"
|
|
),
|
|
keccak256("Permit2"),
|
|
block.chainid,
|
|
PERMIT2_ADDRESS
|
|
)
|
|
);
|
|
bytes32 detailsHash =
|
|
keccak256(abi.encode(_PERMIT_DETAILS_TYPEHASH, permit.details));
|
|
bytes32 permitHash = keccak256(
|
|
abi.encode(
|
|
_PERMIT_SINGLE_TYPEHASH,
|
|
detailsHash,
|
|
permit.spender,
|
|
permit.sigDeadline
|
|
)
|
|
);
|
|
|
|
bytes32 digest = keccak256(
|
|
abi.encodePacked("\x19\x01", domainSeparator, permitHash)
|
|
);
|
|
(uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest);
|
|
|
|
return abi.encodePacked(r, s, v);
|
|
}
|
|
}
|