forked from autofarmnetwork/autofarm-v2-contracts
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAutoSwap.sol
More file actions
212 lines (179 loc) · 5.73 KB
/
AutoSwap.sol
File metadata and controls
212 lines (179 loc) · 5.73 KB
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
import "./libraries/SafeERC20.sol";
import "./helpers/Ownable.sol";
import "./helpers/Pausable.sol";
import "./libraries/UniversalERC20.sol";
import "./helpers/ReentrancyGuard.sol";
import "./helpers/Whitelist.sol";
contract AutoSwap is Ownable, ReentrancyGuard, Pausable, Whitelist {
using SafeMath for uint256;
using SafeERC20 for IERC20;
using UniversalERC20 for IERC20;
uint256 public feeRate;
uint256 public referrerFeeRate;
event FeeRateChanged(
uint256 indexed oldFeeRate,
uint256 indexed newFeeRate
);
event ReferrerFeeRateChanged(
uint256 indexed oldReferrerFeeRate,
uint256 indexed newReferrerFeeRate
);
event Order(
address indexed sender,
IERC20 indexed inToken,
IERC20 indexed outToken,
uint256 inAmount,
uint256 outAmount
);
event Swapped(
IERC20 indexed inToken,
IERC20 indexed outToken,
address indexed referrer,
uint256 inAmount,
uint256 outAmount,
uint256 fee,
uint256 referrerFee
);
struct CallStruct {
address spenderIfIsApproval;
address target;
uint256 value;
bytes data;
}
constructor(
address _owner,
uint256 _feeRate,
uint256 _referrerFeeRate
) public {
transferOwnership(_owner);
feeRate = _feeRate;
referrerFeeRate = _referrerFeeRate;
}
function swap(
IERC20 inToken,
IERC20 outToken,
uint256 inAmount,
uint256 minOutAmount,
uint256 guaranteedAmount,
address payable referrer,
CallStruct[] calldata calls
) public payable nonReentrant whenNotPaused returns (uint256 outAmount) {
// Initial checks
require(minOutAmount > 0, "!(minOutAmount > 0)");
require(calls.length > 0, "!(calls.length > 0)");
require(
(msg.value != 0) == inToken.isETH(),
"msg.value should be used only for ETH swap"
);
// Transfer inToken to address(this)
if (!inToken.isETH()) {
inToken.safeTransferFrom(msg.sender, address(this), inAmount);
}
// Execute swaps
for (uint256 i = 0; i < calls.length; i++) {
if (calls[i].spenderIfIsApproval != address(0)) {
// If call is to approve spending of a token
_resetAllowances(calls[i].target, calls[i].spenderIfIsApproval);
} else {
// If call is a swap
require(isMember(calls[i].target), "!whitelisted");
calls[i].target.call{value: calls[i].value}(calls[i].data);
}
}
// Transfer inToken dust (if any) to user
inToken.universalTransfer(
msg.sender,
inToken.universalBalanceOf(address(this))
);
// Handle fees
outAmount = outToken.universalBalanceOf(address(this));
uint256 fee;
uint256 referrerFee;
(outAmount, fee, referrerFee) = _handleFees(
outToken,
outAmount,
guaranteedAmount,
referrer
);
// Closing checks
require(
outAmount >= minOutAmount,
"Return amount less than the minimum required amount"
);
// Transfer outToken to user
outToken.universalTransfer(msg.sender, outAmount);
emit Order(msg.sender, inToken, outToken, inAmount, outAmount);
emit Swapped(
inToken,
outToken,
referrer,
inAmount,
outAmount,
fee,
referrerFee
);
}
function _handleFees(
IERC20 toToken,
uint256 outAmount,
uint256 guaranteedAmount,
address referrer
)
internal
returns (
uint256 realOutAmount,
uint256 fee,
uint256 referrerFee
)
{
if (outAmount <= guaranteedAmount || feeRate == 0) {
return (outAmount, 0, 0);
}
fee = outAmount.sub(guaranteedAmount).mul(feeRate).div(10000);
if (
referrer != address(0) &&
referrer != msg.sender &&
referrer != tx.origin
) {
referrerFee = fee.mul(referrerFeeRate).div(10000);
if (toToken.universalTransfer(referrer, referrerFee)) {
outAmount = outAmount.sub(referrerFee);
fee = fee.sub(referrerFee);
} else {
referrerFee = 0;
}
}
if (toToken.universalTransfer(owner(), fee)) {
outAmount = outAmount.sub(fee);
}
return (outAmount, fee, referrerFee);
}
function _resetAllowances(address tokenAddress, address spenderAddress)
internal
{
IERC20(tokenAddress).safeApprove(spenderAddress, uint256(0));
IERC20(tokenAddress).safeIncreaseAllowance(spenderAddress, uint256(-1));
}
function changeFeeRate(uint256 _feeRate) public onlyOwner {
require(_feeRate <= 10000, "!safe - too high");
uint256 oldFeeRate = feeRate;
feeRate = _feeRate;
emit FeeRateChanged(oldFeeRate, _feeRate);
}
function changeReferrerFeeRate(uint256 _referrerFeeRate) public onlyOwner {
require(_referrerFeeRate <= 10000, "!safe - too high");
uint256 oldReferrerFeeRate = referrerFeeRate;
referrerFeeRate = _referrerFeeRate;
emit ReferrerFeeRateChanged(oldReferrerFeeRate, _referrerFeeRate);
}
function pause() public onlyOwner {
_pause();
}
function unpause() public onlyOwner {
_unpause();
}
receive() external payable {}
}