@@ -9,10 +9,6 @@ import { CallConfig } from "src/contracts/types/ConfigTypes.sol";
9
9
import "src/contracts/types/UserOperation.sol " ;
10
10
import "src/contracts/types/SolverOperation.sol " ;
11
11
12
- // NOTES:
13
- // Support for native in/out?
14
- // Support for bid token (TREB) in/out?
15
-
16
12
// ODOS v2 Router on Base: https://basescan.org/address/0x19ceead7105607cd444f5ad10dd51356436095a1
17
13
// Main function: swapCompact()
18
14
@@ -26,13 +22,16 @@ struct SwapTokenInfo {
26
22
contract TrebleSwapDAppControl is DAppControl {
27
23
address public constant ODOS_ROUTER = 0x19cEeAd7105607Cd444F5ad10dd51356436095a1 ;
28
24
29
- // TODO WETH on Base for now, change to TREB when token deployed
30
- address public constant TREB = address ( 0x4200000000000000000000000000000000000006 ) ;
25
+ // TODO TREB token not available yet - replace when it is. DEGEN address for now.
26
+ address public constant TREB = 0x4ed4E862860beD51a9570b96d89aF5E1B0Efefed ;
31
27
address internal constant _ETH = address (0 );
28
+ address internal constant _BURN = address (0xdead );
32
29
33
30
error InvalidUserOpData ();
34
31
error UserOpDappNotOdosRouter ();
35
32
error InsufficientUserOpValue ();
33
+ error InsufficientTrebBalance ();
34
+ error InsufficientOutputBalance ();
36
35
37
36
constructor (
38
37
address atlas
@@ -73,30 +72,56 @@ contract TrebleSwapDAppControl is DAppControl {
73
72
function _preOpsCall (UserOperation calldata userOp ) internal virtual override returns (bytes memory ) {
74
73
if (userOp.dapp != ODOS_ROUTER) revert UserOpDappNotOdosRouter ();
75
74
76
- (bool success , bytes memory data ) =
75
+ (bool success , bytes memory swapData ) =
77
76
CONTROL.staticcall (abi.encodePacked (this .decodeUserOpData.selector , userOp.data));
78
77
79
78
if (! success) revert InvalidUserOpData ();
80
79
81
- SwapTokenInfo memory swapTokenInfo = abi.decode (data , (SwapTokenInfo));
80
+ SwapTokenInfo memory _swapInfo = abi.decode (swapData , (SwapTokenInfo));
82
81
83
82
// If inputToken is ERC20, transfer tokens from user to EE, and approve Odos router for swap
84
- if (swapTokenInfo .inputToken != _ETH) {
85
- _transferUserERC20 (swapTokenInfo .inputToken, address (this ), swapTokenInfo .inputAmount);
86
- SafeTransferLib.safeApprove (swapTokenInfo .inputToken, ODOS_ROUTER, swapTokenInfo .inputAmount);
83
+ if (_swapInfo .inputToken != _ETH) {
84
+ _transferUserERC20 (_swapInfo .inputToken, address (this ), _swapInfo .inputAmount);
85
+ SafeTransferLib.safeApprove (_swapInfo .inputToken, ODOS_ROUTER, _swapInfo .inputAmount);
87
86
} else {
88
- if (userOp.value < swapTokenInfo .inputAmount) revert InsufficientUserOpValue ();
87
+ if (userOp.value < _swapInfo .inputAmount) revert InsufficientUserOpValue ();
89
88
}
90
89
91
- return data ; // return SwapTokenInfo in bytes format, to be used in allocateValue.
90
+ return swapData ; // return SwapTokenInfo in bytes format, to be used in allocateValue.
92
91
}
93
92
94
- // UserOperation happens here. EE calls router (userOp.dapp) with userOp.data as calldata.
93
+ function _allocateValueCall (address , uint256 bidAmount , bytes calldata data ) internal virtual override {
94
+ SwapTokenInfo memory _swapInfo = abi.decode (data, (SwapTokenInfo));
95
+ uint256 _outputTokenBalance = _balanceOf (_swapInfo.outputToken);
96
+
97
+ // Check enough output token was received after swap
98
+ if (_swapInfo.outputToken == TREB) {
99
+ // If outputToken is TREB, check there is enough to burn the solver bid and fulfill user swap
100
+ if (_outputTokenBalance < bidAmount + _swapInfo.outputMin) revert InsufficientTrebBalance ();
101
+ _outputTokenBalance -= bidAmount; // deduct solver bid to get final user output amount to send
102
+ } else {
103
+ if (_outputTokenBalance < _swapInfo.outputMin) revert InsufficientOutputBalance ();
104
+ }
105
+
106
+ // Transfer output token to user
107
+ if (_swapInfo.outputToken == _ETH) {
108
+ SafeTransferLib.safeTransferETH (_user (), _outputTokenBalance);
109
+ } else {
110
+ SafeTransferLib.safeTransfer (_swapInfo.outputToken, _user (), _outputTokenBalance);
111
+ }
112
+
113
+ // If solver won, burn TREB bid
114
+ if (bidAmount > 0 ) SafeTransferLib.safeTransfer (TREB, _BURN, bidAmount);
95
115
96
- function _allocateValueCall (address bidToken , uint256 bidAmount , bytes calldata data ) internal virtual override {
97
- // Solver bid (in TREB) gets burnt here
98
- // Send user back their tokenOut from the swap, and any leftover tokenIn
99
- // Revert here if swap fails
116
+ // If any leftover input token, transfer back to user
117
+ uint256 _inputTokenBalance = _balanceOf (_swapInfo.inputToken);
118
+ if (_inputTokenBalance > 0 ) {
119
+ if (_swapInfo.inputToken == _ETH) {
120
+ SafeTransferLib.safeTransferETH (_user (), _inputTokenBalance);
121
+ } else {
122
+ SafeTransferLib.safeTransfer (_swapInfo.inputToken, _user (), _inputTokenBalance);
123
+ }
124
+ }
100
125
}
101
126
102
127
// ---------------------------------------------------- //
@@ -184,4 +209,12 @@ contract TrebleSwapDAppControl is DAppControl {
184
209
}
185
210
}
186
211
}
212
+
213
+ function _balanceOf (address token ) internal view returns (uint256 ) {
214
+ if (token == _ETH) {
215
+ return address (this ).balance;
216
+ } else {
217
+ return SafeTransferLib.balanceOf (token, address (this ));
218
+ }
219
+ }
187
220
}
0 commit comments