Untitled diff

Created Diff never expires
2 removals
Words removed2
Total words418
Words removed (%)0.48
201 lines
39 additions
Words added85
Total words501
Words added (%)16.97
238 lines
pragma solidity 0.8.17;
pragma solidity 0.8.17;


import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "../core/libraries/SmardexLibrary.sol";
import "../core/libraries/SmardexLibrary.sol";
import "../periphery/libraries/Path.sol";
import "../periphery/libraries/Path.sol";


import "../periphery/interfaces/ISmardexRouter.sol";
import "../core/interfaces/ISmardexPair.sol";
import "../core/interfaces/ISmardexPair.sol";
import "./interfaces/IAutoSwapper.sol";
import "./interfaces/IAutoSwapper.sol";


contract AutoSwapper is IAutoSwapper {
contract AutoSwapper is IAutoSwapper, Ownable {
using SafeERC20 for IERC20;
using SafeERC20 for IERC20;
using SafeCast for uint256;
using SafeCast for uint256;
using SafeCast for int256;
using SafeCast for int256;
using Path for bytes;
using Path for bytes;
using Path for address[];


bytes4 private constant SWAP_SELECTOR =
bytes4 private constant SWAP_SELECTOR =
bytes4(keccak256(bytes("swap(address,bool,int256,bytes)")));
bytes4(keccak256(bytes("swap(address,bool,int256,bytes)")));
uint256 private constant AUTOSWAP_SLIPPAGE = 2;
uint256 private constant AUTOSWAP_SLIPPAGE = 2;
uint256 private constant AUTOSWAP_SLIPPAGE_BASE = 100;
uint256 private constant AUTOSWAP_SLIPPAGE_BASE = 100;


ISmardexFactory public immutable factory;
ISmardexFactory public immutable factory;
address public immutable stakingAddress;
address public immutable stakingAddress;
IERC20 public immutable smardexToken;
IERC20 public immutable smardexToken;


ISmardexPair private constant DEFAULT_CACHED_PAIR =
ISmardexPair private constant DEFAULT_CACHED_PAIR =
ISmardexPair(address(0));
ISmardexPair(address(0));
ISmardexPair private cachedPair = DEFAULT_CACHED_PAIR;
ISmardexPair private cachedPair = DEFAULT_CACHED_PAIR;


ISmardexRouter public immutable router;

constructor(
constructor(
ISmardexFactory _factory,
ISmardexFactory _factory,
IERC20 _smardexToken,
IERC20 _smardexToken,
address _stakingAddress
address _stakingAddress,
ISmardexRouter _router
) {
) {
require(
require(
address(_factory) != address(0),
address(_factory) != address(0),
"AutoSwapper: INVALID_FACTORY_ADDRESS"
"AutoSwapper: INVALID_FACTORY_ADDRESS"
);
);
require(
require(
address(_smardexToken) != address(0),
address(_smardexToken) != address(0),
"AutoSwapper: INVALID_SDEX_ADDRESS"
"AutoSwapper: INVALID_SDEX_ADDRESS"
);
);
require(
require(
_stakingAddress != address(0),
_stakingAddress != address(0),
"AutoSwapper: INVALID_STAKING_ADDRESS"
"AutoSwapper: INVALID_STAKING_ADDRESS"
);
);


factory = _factory;
factory = _factory;
smardexToken = _smardexToken;
smardexToken = _smardexToken;
stakingAddress = _stakingAddress;
stakingAddress = _stakingAddress;
router = _router;
}
}


function executeWork(IERC20 _token0, IERC20 _token1) external {
function executeWork(IERC20 _token0, IERC20 _token1) external {
uint256 _amount0 = _swapAndSend(_token0);
uint256 _amount0 = _swapAndSend(_token0);
uint256 _amount1 = _swapAndSend(_token1);
uint256 _amount1 = _swapAndSend(_token1);
uint256 _transferredAmount = transferTokens();
uint256 _transferredAmount = transferTokens();


emit workExecuted(
emit workExecuted(
_token0,
_token0,
_amount0,
_amount0,
_token1,
_token1,
_amount1,
_amount1,
_transferredAmount
_transferredAmount
);
);
}
}


function swapTokenWithPath(
uint256 _amountToSwap,
uint256 _amountOutMin,
address[] calldata _path,
uint256 _deadline
) external onlyOwner {
require(_path.length > 1, "AutoSwapper: INVALID_PATH");
require(
_path[_path.length - 1] == address(smardexToken),
"AutoSwapper: INVALID_LAST_TOKEN"
);
IERC20 _token = IERC20(_path[0]);

uint256 _balance = _token.balanceOf(address(this));
require(_amountToSwap <= _balance, "AutoSwapper: INVALID_AMOUNT");

uint256 _amountIn;
if (_amountToSwap != 0) _amountIn = _amountToSwap;
else _amountIn = _balance;
_token.safeApprove(address(router), _amountIn);

router.swapExactTokensForTokens(
_amountIn,
_amountOutMin,
_path,
stakingAddress,
_deadline
);
}

function transferTokens() public returns (uint256 _amount) {
function transferTokens() public returns (uint256 _amount) {
_amount = smardexToken.balanceOf(address(this));
_amount = smardexToken.balanceOf(address(this));
if (_amount != 0) {
if (_amount != 0) {
smardexToken.safeTransfer(stakingAddress, _amount);
smardexToken.safeTransfer(stakingAddress, _amount);
}
}
}
}


function _swapAndSend(IERC20 _token) private returns (uint256) {
function _swapAndSend(IERC20 _token) private returns (uint256) {
if (_token == smardexToken) {
if (_token == smardexToken) {
return 0;
return 0;
}
}
SwapCallParams memory _params = SwapCallParams({
SwapCallParams memory _params = SwapCallParams({
zeroForOne: _token < smardexToken,
zeroForOne: _token < smardexToken,
balanceIn: _token.balanceOf(address(this)),
balanceIn: _token.balanceOf(address(this)),
pair: ISmardexPair(
pair: ISmardexPair(
factory.getPair(address(_token), address(smardexToken))
factory.getPair(address(_token), address(smardexToken))
),
),
fictiveReserve0: 0,
fictiveReserve0: 0,
fictiveReserve1: 0,
fictiveReserve1: 0,
oldPriceAv0: 0,
oldPriceAv0: 0,
oldPriceAv1: 0,
oldPriceAv1: 0,
oldPriceAvTimestamp: 0,
oldPriceAvTimestamp: 0,
newPriceAvIn: 0,
newPriceAvIn: 0,
newPriceAvOut: 0
newPriceAvOut: 0
});
});


if (_params.balanceIn == 0 || address(_params.pair) == address(0)) {
if (_params.balanceIn == 0 || address(_params.pair) == address(0)) {
return 0;
return 0;
}
}


(_params.fictiveReserve0, _params.fictiveReserve1) = _params
(_params.fictiveReserve0, _params.fictiveReserve1) = _params
.pair
.pair
.getFictiveReserves();
.getFictiveReserves();
(
(
_params.oldPriceAv0,
_params.oldPriceAv0,
_params.oldPriceAv1,
_params.oldPriceAv1,
_params.oldPriceAvTimestamp
_params.oldPriceAvTimestamp
) = _params.pair.getPriceAverage();
) = _params.pair.getPriceAverage();


if (_params.oldPriceAv0 == 0 || _params.oldPriceAv1 == 0) {
if (_params.oldPriceAv0 == 0 || _params.oldPriceAv1 == 0) {
(_params.oldPriceAv0, _params.oldPriceAv1) = (
(_params.oldPriceAv0, _params.oldPriceAv1) = (
_params.fictiveReserve0,
_params.fictiveReserve0,
_params.fictiveReserve1
_params.fictiveReserve1
);
);
}
}


if (_params.zeroForOne) {
if (_params.zeroForOne) {
(_params.newPriceAvIn, _params.newPriceAvOut) = SmardexLibrary
(_params.newPriceAvIn, _params.newPriceAvOut) = SmardexLibrary
.getUpdatedPriceAverage(
.getUpdatedPriceAverage(
_params.fictiveReserve0,
_params.fictiveReserve0,
_params.fictiveReserve1,
_params.fictiveReserve1,
_params.oldPriceAvTimestamp,
_params.oldPriceAvTimestamp,
_params.oldPriceAv0,
_params.oldPriceAv0,
_params.oldPriceAv1,
_params.oldPriceAv1,
block.timestamp
block.timestamp
);
);
} else {
} else {
(_params.newPriceAvIn, _params.newPriceAvOut) = SmardexLibrary
(_params.newPriceAvIn, _params.newPriceAvOut) = SmardexLibrary
.getUpdatedPriceAverage(
.getUpdatedPriceAverage(
_params.fictiveReserve1,
_params.fictiveReserve1,
_params.fictiveReserve0,
_params.fictiveReserve0,
_params.oldPriceAvTimestamp,
_params.oldPriceAvTimestamp,
_params.oldPriceAv1,
_params.oldPriceAv1,
_params.oldPriceAv0,
_params.oldPriceAv0,
block.timestamp
block.timestamp
);
);
}
}


uint256 _amountOutWithSlippage = (_params.balanceIn *
uint256 _amountOutWithSlippage = (_params.balanceIn *
_params.newPriceAvOut *
_params.newPriceAvOut *
(AUTOSWAP_SLIPPAGE_BASE - AUTOSWAP_SLIPPAGE)) /
(AUTOSWAP_SLIPPAGE_BASE - AUTOSWAP_SLIPPAGE)) /
(_params.newPriceAvIn * AUTOSWAP_SLIPPAGE_BASE);
(_params.newPriceAvIn * AUTOSWAP_SLIPPAGE_BASE);
require(
require(
_amountOutWithSlippage != 0,
_amountOutWithSlippage != 0,
"AutoSwapper: slippage calculation failed"
"AutoSwapper: slippage calculation failed"
);
);


cachedPair = _params.pair;
cachedPair = _params.pair;


(bool success, ) = address(_params.pair).call(
(bool success, ) = address(_params.pair).call(
abi.encodeWithSelector(
abi.encodeWithSelector(
SWAP_SELECTOR,
SWAP_SELECTOR,
stakingAddress,
stakingAddress,
_token < smardexToken,
_token < smardexToken,
_params.balanceIn.toInt256(),
_params.balanceIn.toInt256(),
abi.encode(
abi.encode(
SwapCallbackData({
SwapCallbackData({
path: abi.encodePacked(_token, smardexToken),
path: abi.encodePacked(_token, smardexToken),
payer: address(this)
payer: address(this)
}),
}),
_amountOutWithSlippage
_amountOutWithSlippage
)
)
)
)
);
);


cachedPair = DEFAULT_CACHED_PAIR;
cachedPair = DEFAULT_CACHED_PAIR;


return success ? _params.balanceIn : 0;
return success ? _params.balanceIn : 0;
}
}


function smardexSwapCallback(
function smardexSwapCallback(
int256 _amount0Delta,
int256 _amount0Delta,
int256 _amount1Delta,
int256 _amount1Delta,
bytes calldata _dataFromPair
bytes calldata _dataFromPair
) external {
) external {
require(
require(
_amount0Delta > 0 || _amount1Delta > 0,
_amount0Delta > 0 || _amount1Delta > 0,
"SmardexRouter: Callback Invalid amount"
"SmardexRouter: Callback Invalid amount"
);
);
(SwapCallbackData memory _data, uint256 _amountOutWithSlippage) = abi
(SwapCallbackData memory _data, uint256 _amountOutWithSlippage) = abi
.decode(_dataFromPair, (SwapCallbackData, uint256));
.decode(_dataFromPair, (SwapCallbackData, uint256));
(address _tokenIn, ) = _data.path.decodeFirstPool();
(address _tokenIn, ) = _data.path.decodeFirstPool();
require(
require(
msg.sender == address(cachedPair),
msg.sender == address(cachedPair),
"SmarDexRouter: INVALID_PAIR"
"SmarDexRouter: INVALID_PAIR"
);
);


require(
require(
(
(
_amount0Delta < 0
_amount0Delta < 0
? uint256(-_amount0Delta)
? uint256(-_amount0Delta)
: (-_amount1Delta).toUint256()
: (-_amount1Delta).toUint256()
) >= _amountOutWithSlippage,
) >= _amountOutWithSlippage,
"SmardexAutoSwapper: Invalid price"
"SmardexAutoSwapper: Invalid price"
);
);


IERC20(_tokenIn).safeTransfer(
IERC20(_tokenIn).safeTransfer(
msg.sender,
msg.sender,
_amount0Delta > 0
_amount0Delta > 0
? uint256(_amount0Delta)
? uint256(_amount0Delta)
: _amount1Delta.toUint256()
: _amount1Delta.toUint256()
);
);
}
}
}
}