@@ -19,14 +19,24 @@ contract ListaAutoBuyback is Initializable, AccessControlUpgradeable {
1919 using SafeERC20 for IERC20 ;
2020
2121 event BoughtBack (address indexed tokenIn , uint256 amountIn , uint256 amountOut );
22+ event BoughtBack (
23+ address indexed pair ,
24+ address indexed tokenIn ,
25+ address indexed tokenOut ,
26+ uint256 amountIn ,
27+ uint256 amountOut
28+ );
2229
2330 event ReceiverChanged (address indexed receiver );
24-
2531 event RouterChanged (address indexed router , bool added );
32+ event TokenWhitelistChanged (address indexed token , bool added );
33+ event AdminTransfer (address token , uint256 amount );
34+
2635
2736 bytes32 public constant BOT = keccak256 ("BOT " );
2837
2938 bytes4 public constant SWAP_FUNCTION_SELECTOR = bytes4 (keccak256 ("swap(address,(address,address,address,address,uint256,uint256,uint256),bytes) " ));
39+ address public constant SWAP_NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE ;
3040
3141 // The offset of the dstReceiver in the call data
3242 // 4 bytes for the function selector + 32 bytes for executor + 32 bytes for srcToken +
@@ -38,15 +48,19 @@ contract ListaAutoBuyback is Initializable, AccessControlUpgradeable {
3848
3949 address public defaultReceiver;
4050
41- mapping (address => bool ) public oneInchRouterWhitelist ;
51+ mapping (address => bool ) public routerWhitelist ;
4252
4353 mapping (uint256 => uint256 ) public dailyBought;
4454
55+ mapping (address => bool ) public tokenWhitelist;
56+
4557 /// @custom:oz-upgrades-unsafe-allow constructor
4658 constructor () {
4759 _disableInitializers ();
4860 }
4961
62+ receive () external payable {}
63+
5064 function initialize (
5165 address _admin ,
5266 address _bot ,
@@ -62,7 +76,7 @@ contract ListaAutoBuyback is Initializable, AccessControlUpgradeable {
6276 _setupRole (BOT, _bot);
6377
6478 defaultReceiver = _initReceiver;
65- oneInchRouterWhitelist [_initRouter] = true ;
79+ routerWhitelist [_initRouter] = true ;
6680 }
6781
6882 /**
@@ -77,7 +91,7 @@ contract ListaAutoBuyback is Initializable, AccessControlUpgradeable {
7791 onlyRole (BOT)
7892 {
7993 require (_amountIn > 0 , "amountIn is zero " );
80- require (oneInchRouterWhitelist [_1inchRouter], "router not whitelisted " );
94+ require (routerWhitelist [_1inchRouter], "router not whitelisted " );
8195 require (_getFunctionSelector (_data) == SWAP_FUNCTION_SELECTOR, "invalid function selector of _data " );
8296 require (_extractDstReceiver (_data) == defaultReceiver, "invalid dst receiver of _data " );
8397 require (IERC20 (_tokenIn).balanceOf (address (this )) >= _amountIn, "insufficient balance " );
@@ -98,8 +112,52 @@ contract ListaAutoBuyback is Initializable, AccessControlUpgradeable {
98112 emit BoughtBack (_tokenIn, _amountIn, amountOut);
99113 }
100114
115+ /// @dev buy back tokens using router
116+ /// @param router The address of the router.
117+ /// @param tokenIn The address of the input token.
118+ /// @param tokenOut The address of the output token.
119+ /// @param amountIn The amount to sell.
120+ /// @param amountOutMin The minimum amount to receive.
121+ /// @param swapData The swap data.
122+ function buyback (
123+ address router ,
124+ address tokenIn ,
125+ address tokenOut ,
126+ uint256 amountIn ,
127+ uint256 amountOutMin ,
128+ bytes calldata swapData
129+ ) external onlyRole (BOT) {
130+ require (tokenWhitelist[tokenIn], "token not whitelisted " );
131+ require (tokenWhitelist[tokenOut], "token not whitelisted " );
132+ require (routerWhitelist[router], "router not whitelisted " );
133+
134+ uint256 beforeTokenIn = _getTokenBalance (tokenIn, address (this ));
135+ uint256 beforeTokenOut = _getTokenBalance (tokenOut, defaultReceiver);
136+
137+ bool isNativeTokenIn = (tokenIn == SWAP_NATIVE_TOKEN_ADDRESS);
138+ if (! isNativeTokenIn) {
139+ IERC20 (tokenIn).safeApprove (router, amountIn);
140+ }
141+ (bool success , ) = router.call {value: isNativeTokenIn ? amountIn : 0 }(swapData);
142+ require (success, "swap failed " );
143+
144+ uint256 actualAmountIn = beforeTokenIn - _getTokenBalance (tokenIn, address (this ));
145+ uint256 actualAmountOut = _getTokenBalance (tokenOut, defaultReceiver) - beforeTokenOut;
146+
147+ require (actualAmountIn <= amountIn, "exceed amount in " );
148+ require (actualAmountOut >= amountOutMin, "not enough profit " );
149+
150+ emit BoughtBack (router, tokenIn, tokenOut, actualAmountIn, actualAmountOut);
151+ }
152+
101153 function adminTransfer (address _token , uint256 _amount ) external onlyRole (DEFAULT_ADMIN_ROLE) {
102- IERC20 (_token).safeTransfer (msg .sender , _amount);
154+ if (_token == SWAP_NATIVE_TOKEN_ADDRESS) {
155+ (bool success , ) = payable (msg .sender ).call { value: _amount }("" );
156+ require (success, "Withdraw failed " );
157+ } else {
158+ IERC20 (_token).safeTransfer (msg .sender , _amount);
159+ }
160+ emit AdminTransfer (_token, _amount);
103161 }
104162
105163 function changeDefaultReceiver (address _receiver ) external onlyRole (DEFAULT_ADMIN_ROLE) {
@@ -110,20 +168,27 @@ contract ListaAutoBuyback is Initializable, AccessControlUpgradeable {
110168 emit ReceiverChanged (defaultReceiver);
111169 }
112170
113- function add1InchRouterWhitelist (address _router ) external onlyRole (DEFAULT_ADMIN_ROLE) {
114- require (! oneInchRouterWhitelist[_router], "router already whitelisted " );
115-
116- oneInchRouterWhitelist[_router] = true ;
171+ /// @dev sets the router whitelist.
172+ /// @param _router The address of the router.
173+ /// @param status The status of the router.
174+ function setRouterWhitelist (address _router , bool status ) external onlyRole (DEFAULT_ADMIN_ROLE) {
175+ require (_router != address (0 ), "Invalid router address " );
176+ require (routerWhitelist[_router] != status, "whitelist same status " );
177+ routerWhitelist[_router] = status;
117178 emit RouterChanged (_router, true );
118179 }
119180
120- function remove1InchRouterWhitelist (address _router ) external onlyRole (DEFAULT_ADMIN_ROLE) {
121- require (oneInchRouterWhitelist[_router], "router not whitelisted " );
122-
123- delete oneInchRouterWhitelist[_router];
124- emit RouterChanged (_router, false );
181+ /// @dev sets the token whitelist.
182+ /// @param token The address of the token.
183+ /// @param status The status of the token.
184+ function setTokenWhitelist (address token , bool status ) external onlyRole (DEFAULT_ADMIN_ROLE) {
185+ require (token != address (0 ), "Invalid token " );
186+ require (tokenWhitelist[token] != status, "whitelist same status " );
187+ tokenWhitelist[token] = status;
188+ emit TokenWhitelistChanged (token, status);
125189 }
126190
191+
127192 function _getFunctionSelector (bytes calldata _data ) private pure returns (bytes4 ) {
128193 return bytes4 (_data[0 :4 ]);
129194 }
@@ -135,4 +200,12 @@ contract ListaAutoBuyback is Initializable, AccessControlUpgradeable {
135200 dstReceiver := calldataload (add (_data.offset, SWAP_DST_RECEIVER_OFFSET))
136201 }
137202 }
203+
204+ function _getTokenBalance (address _token , address account ) internal view returns (uint256 ) {
205+ if (_token == SWAP_NATIVE_TOKEN_ADDRESS) {
206+ return account.balance;
207+ } else {
208+ return IERC20 (_token).balanceOf (account);
209+ }
210+ }
138211}
0 commit comments