-
Notifications
You must be signed in to change notification settings - Fork 49
/
Copy pathSwapsExternal.sol
167 lines (155 loc) · 5.87 KB
/
SwapsExternal.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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/**
* Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.
* Licensed under the Apache License, Version 2.0.
*/
pragma solidity 0.5.17;
pragma experimental ABIEncoderV2;
import "../core/State.sol";
import "../mixins/VaultController.sol";
import "../swaps/SwapsUser.sol";
import "../mixins/ModuleCommonFunctionalities.sol";
/**
* @title Swaps External contract.
*
* @notice This contract code comes from bZx. bZx is a protocol for tokenized
* margin trading and lending https://bzx.network similar to the dYdX protocol.
*
* This contract contains functions to calculate and execute swaps.
* */
contract SwapsExternal is VaultController, SwapsUser, ModuleCommonFunctionalities {
/**
* @notice Empty public constructor.
* */
constructor() public {}
/**
* @notice Fallback function is to react to receiving value (rBTC).
* */
function() external {
revert("fallback not allowed");
}
/**
* @notice Set function selectors on target contract.
*
* @param target The address of the target contract.
* */
function initialize(address target) external onlyOwner {
address prevModuleContractAddress = logicTargets[this.swapExternal.selector];
_setTarget(this.swapExternal.selector, target);
_setTarget(this.getSwapExpectedReturn.selector, target);
_setTarget(this.checkPriceDivergence.selector, target);
emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, "SwapsExternal");
}
/**
* @notice Perform a swap w/ tokens or rBTC as source currency.
*
* @dev External wrapper that calls SwapsUser::_swapsCall
* after turning potential incoming rBTC into wrBTC tokens.
*
* @param sourceToken The address of the source token instance.
* @param destToken The address of the destiny token instance.
* @param receiver The address of the recipient account.
* @param returnToSender The address of the sender account.
* @param sourceTokenAmount The amount of source tokens.
* @param requiredDestTokenAmount The amount of required destiny tokens.
* @param minReturn Minimum amount (position size) in the collateral tokens.
* @param swapData Additional swap data (not in use yet).
*
* @return destTokenAmountReceived The amount of destiny tokens sent.
* @return sourceTokenAmountUsed The amount of source tokens spent.
* */
function swapExternal(
address sourceToken,
address destToken,
address receiver,
address returnToSender,
uint256 sourceTokenAmount,
uint256 requiredDestTokenAmount,
uint256 minReturn,
bytes memory swapData
)
public
payable
nonReentrant
whenNotPaused
returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)
{
require(sourceTokenAmount != 0, "sourceTokenAmount == 0");
checkPriceDivergence(sourceToken, destToken, sourceTokenAmount, minReturn);
/// @dev Get payed value, be it rBTC or tokenized.
if (msg.value != 0) {
if (sourceToken == address(0)) {
sourceToken = address(wrbtcToken);
}
require(sourceToken == address(wrbtcToken), "sourceToken mismatch");
require(msg.value == sourceTokenAmount, "sourceTokenAmount mismatch");
/// @dev Update wrBTC balance for this contract.
wrbtcToken.deposit.value(sourceTokenAmount)();
} else {
if (address(this) != msg.sender) {
IERC20(sourceToken).safeTransferFrom(msg.sender, address(this), sourceTokenAmount);
}
}
/// @dev Perform the swap w/ tokens.
(destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall(
[
sourceToken,
destToken,
receiver,
returnToSender,
msg.sender /// user
],
[
sourceTokenAmount, /// minSourceTokenAmount
sourceTokenAmount, /// maxSourceTokenAmount
requiredDestTokenAmount
],
0, /// loanId (not tied to a specific loan)
false, /// bypassFee
swapData,
true // the flag for swapExternal (so that it will use the swapExternalFeePercent)
);
emit ExternalSwap(
msg.sender, /// user
sourceToken,
destToken,
sourceTokenAmountUsed,
destTokenAmountReceived
);
}
/**
* @notice Get the swap expected return value.
*
* @dev External wrapper that calls SwapsUser::_swapsExpectedReturn
*
* @param sourceToken The address of the source token instance.
* @param destToken The address of the destiny token instance.
* @param sourceTokenAmount The amount of source tokens.
*
* @return The expected return value.
* */
function getSwapExpectedReturn(
address sourceToken,
address destToken,
uint256 sourceTokenAmount
) external view returns (uint256) {
return _swapsExpectedReturn(sourceToken, destToken, sourceTokenAmount);
}
/**
* @notice Check the slippage based on the swapExpectedReturn.
*
* @param sourceToken The address of the source token instance.
* @param destToken The address of the destiny token instance.
* @param sourceTokenAmount The amount of source tokens.
* @param minReturn The amount (max slippage) that will be compared to the swapsExpectedReturn.
*
*/
function checkPriceDivergence(
address sourceToken,
address destToken,
uint256 sourceTokenAmount,
uint256 minReturn
) public view {
uint256 destTokenAmount = _swapsExpectedReturn(sourceToken, destToken, sourceTokenAmount);
require(destTokenAmount >= minReturn, "destTokenAmountReceived too low");
}
}