generated from PaulRBerg/foundry-template
-
Notifications
You must be signed in to change notification settings - Fork 1
/
SwapPermit2Adapter.sol
102 lines (85 loc) · 3.81 KB
/
SwapPermit2Adapter.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
// solhint-disable-next-line no-unused-import
import { Permit2Transfers, IPermit2 } from "../libraries/Permit2Transfers.sol";
import { Token } from "../libraries/Token.sol";
import { ISwapPermit2Adapter } from "../interfaces/ISwapPermit2Adapter.sol";
import { BasePermit2Adapter } from "./BasePermit2Adapter.sol";
/**
* @title Swap Permit2 Adapter
* @author Sam Bugs
* @notice This contracts adds Permit2 capabilities to existing token swap contracts by acting as a proxy. It performs
* some extra checks to guarantee that the minimum amounts are respected
* @dev It's important to note that this contract should never hold any funds outside of the scope of a transaction,
* nor should it be granted "regular" ERC20 token approvals. This contract is meant to be used as a proxy, so
* the only tokens approved/transferred through Permit2 should be entirely spent in the same transaction.
* Any unspent allowance or remaining tokens on the contract can be transferred by anyone, so please be careful!
*/
abstract contract SwapPermit2Adapter is BasePermit2Adapter, ISwapPermit2Adapter {
using Permit2Transfers for IPermit2;
using Token for address;
using Address for address;
/// @inheritdoc ISwapPermit2Adapter
function sellOrderSwap(SellOrderSwapParams calldata _params)
public
payable
checkDeadline(_params.deadline)
returns (uint256 _amountIn, uint256 _amountOut)
{
// Take from caller
PERMIT2.takeFromCaller(_params.tokenIn, _params.amountIn, _params.nonce, _params.deadline, _params.signature);
// Max approve token in
_params.tokenIn.maxApproveIfNecessary(_params.allowanceTarget);
// Execute swap
_params.swapper.functionCallWithValue(_params.swapData, msg.value);
// Distribute token out
_amountOut = _params.tokenOut.distributeTo(_params.transferOut);
// Check min amount
if (_amountOut < _params.minAmountOut) revert ReceivedTooLittleTokenOut(_amountOut, _params.minAmountOut);
// Set amount in
_amountIn = _params.amountIn;
}
/// @inheritdoc ISwapPermit2Adapter
function sellOrderSwapWithGasMeasurement(SellOrderSwapParams calldata _params)
external
payable
returns (uint256 _amountIn, uint256 _amountOut, uint256 _gasSpent)
{
uint256 _gasAtStart = gasleft();
(_amountIn, _amountOut) = sellOrderSwap(_params);
_gasSpent = _gasAtStart - gasleft();
}
/// @inheritdoc ISwapPermit2Adapter
function buyOrderSwap(BuyOrderSwapParams calldata _params)
public
payable
checkDeadline(_params.deadline)
returns (uint256 _amountIn, uint256 _amountOut)
{
// Take from caller
PERMIT2.takeFromCaller(_params.tokenIn, _params.maxAmountIn, _params.nonce, _params.deadline, _params.signature);
// Max approve token in
_params.tokenIn.maxApproveIfNecessary(_params.allowanceTarget);
// Execute swap
_params.swapper.functionCallWithValue(_params.swapData, msg.value);
// Distribute token out
_amountOut = _params.tokenOut.distributeTo(_params.transferOut);
// Check min amount
if (_amountOut < _params.amountOut) revert ReceivedTooLittleTokenOut(_amountOut, _params.amountOut);
// Send unspent to the set recipient
uint256 _unspentTokenIn = _params.tokenIn.sendBalanceOnContractTo(_params.unspentTokenInRecipient);
// Set amount in
_amountIn = _params.maxAmountIn - _unspentTokenIn;
}
/// @inheritdoc ISwapPermit2Adapter
function buyOrderSwapWithGasMeasurement(BuyOrderSwapParams calldata _params)
external
payable
returns (uint256 _amountIn, uint256 _amountOut, uint256 _gasSpent)
{
uint256 _gasAtStart = gasleft();
(_amountIn, _amountOut) = buyOrderSwap(_params);
_gasSpent = _gasAtStart - gasleft();
}
}