This repository has been archived by the owner on May 16, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
TpdaLiquidationRouter.sol
143 lines (120 loc) · 5.37 KB
/
TpdaLiquidationRouter.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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import { IERC20 } from "openzeppelin/token/ERC20/IERC20.sol";
import { SafeERC20 } from "openzeppelin/token/ERC20/utils/SafeERC20.sol";
import { IFlashSwapCallback } from "pt-v5-liquidator-interfaces/IFlashSwapCallback.sol";
import { TpdaLiquidationPair } from "./TpdaLiquidationPair.sol";
import { TpdaLiquidationPairFactory } from "./TpdaLiquidationPairFactory.sol";
/// @notice Thrown when the liquidation pair factory is the zero address
error UndefinedTpdaLiquidationPairFactory();
/// @notice Throw when the liquidation pair was not created by the liquidation pair factory
error UnknownTpdaLiquidationPair(address liquidationPair);
/// @notice Thrown when a swap deadline has passed
error SwapExpired(uint256 deadline);
/// @notice Thrown when the router is used as a receiver in a swap by another EOA or contract
error InvalidSender(address sender);
/// @title TpdaLiquidationRouter
/// @author G9 Software Inc.
/// @notice Serves as the user-facing swapping interface for Liquidation Pairs.
contract TpdaLiquidationRouter is IFlashSwapCallback {
using SafeERC20 for IERC20;
/* ============ Events ============ */
/// @notice Emitted when the router is created
event LiquidationRouterCreated(TpdaLiquidationPairFactory indexed liquidationPairFactory);
/// @notice Emitted after a swap occurs
/// @param liquidationPair The pair that was swapped against
/// @param sender The address that initiated the swap
/// @param receiver The address that received the output tokens
/// @param amountOut The amount of output tokens received
/// @param amountInMax The maximum amount of input tokens that could have been used
/// @param amountIn The amount of input tokens that were actually used
/// @param deadline The deadline for the swap
event SwappedExactAmountOut(
TpdaLiquidationPair indexed liquidationPair,
address indexed sender,
address indexed receiver,
uint256 amountOut,
uint256 amountInMax,
uint256 amountIn,
uint256 deadline
);
/* ============ Variables ============ */
/// @notice The TpdaLiquidationPairFactory that this router uses.
/// @dev TpdaLiquidationPairs will be checked to ensure they were created by the factory
TpdaLiquidationPairFactory internal immutable _liquidationPairFactory;
/// @notice Constructs a new LiquidationRouter
/// @param liquidationPairFactory_ The factory that pairs will be verified to have been created by
constructor(TpdaLiquidationPairFactory liquidationPairFactory_) {
if (address(liquidationPairFactory_) == address(0)) {
revert UndefinedTpdaLiquidationPairFactory();
}
_liquidationPairFactory = liquidationPairFactory_;
emit LiquidationRouterCreated(liquidationPairFactory_);
}
/* ============ External Methods ============ */
/// @notice Swaps the given amount of output tokens for at most input tokens
/// @param _liquidationPair The pair to swap against
/// @param _receiver The account to receive the output tokens
/// @param _amountOut The exact amount of output tokens expected
/// @param _amountInMax The maximum of input tokens to spend
/// @param _deadline The timestamp that the swap must be completed by
/// @return The actual number of input tokens used
function swapExactAmountOut(
TpdaLiquidationPair _liquidationPair,
address _receiver,
uint256 _amountOut,
uint256 _amountInMax,
uint256 _deadline
) external onlyTrustedTpdaLiquidationPair(address(_liquidationPair)) returns (uint256) {
if (block.timestamp > _deadline) {
revert SwapExpired(_deadline);
}
uint256 amountIn = _liquidationPair.swapExactAmountOut(
address(this),
_amountOut,
_amountInMax,
abi.encode(msg.sender)
);
IERC20(_liquidationPair.tokenOut()).safeTransfer(_receiver, _amountOut);
emit SwappedExactAmountOut(
_liquidationPair,
msg.sender,
_receiver,
_amountOut,
_amountInMax,
amountIn,
_deadline
);
return amountIn;
}
/// @inheritdoc IFlashSwapCallback
function flashSwapCallback(
address _sender,
uint256 _amountIn,
uint256,
bytes calldata _flashSwapData
) external override onlyTrustedTpdaLiquidationPair(msg.sender) onlySelf(_sender) {
address _originalSender = abi.decode(_flashSwapData, (address));
IERC20(TpdaLiquidationPair(msg.sender).tokenIn()).safeTransferFrom(
_originalSender,
TpdaLiquidationPair(msg.sender).target(),
_amountIn
);
}
/// @notice Checks that the given pair was created by the factory
/// @param _liquidationPair The pair address to check
modifier onlyTrustedTpdaLiquidationPair(address _liquidationPair) {
if (!_liquidationPairFactory.deployedPairs(_liquidationPair)) {
revert UnknownTpdaLiquidationPair(_liquidationPair);
}
_;
}
/// @notice Checks that the given address matches this contract
/// @param _sender The address that called the liquidation pair
modifier onlySelf(address _sender) {
if (_sender != address(this)) {
revert InvalidSender(_sender);
}
_;
}
}