More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
KyberAggregatorWrapper
Compiler Version
v0.8.10+commit.fc410830
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2024-03-14 */ // SPDX-License-Identifier: MIT pragma solidity =0.8.10; contract MainnetAuthAddresses { address internal constant ADMIN_VAULT_ADDR = 0xCCf3d848e08b94478Ed8f46fFead3008faF581fD; address internal constant DSGUARD_FACTORY_ADDRESS = 0x5a15566417e6C1c9546523066500bDDBc53F88C7; address internal constant ADMIN_ADDR = 0x25eFA336886C74eA8E282ac466BdCd0199f85BB9; // USED IN ADMIN VAULT CONSTRUCTOR address internal constant PROXY_AUTH_ADDRESS = 0x149667b6FAe2c63D1B4317C716b0D0e4d3E2bD70; address internal constant MODULE_AUTH_ADDRESS = 0x7407974DDBF539e552F1d051e44573090912CC3D; } contract AuthHelper is MainnetAuthAddresses { } contract AdminVault is AuthHelper { address public owner; address public admin; error SenderNotAdmin(); constructor() { owner = msg.sender; admin = ADMIN_ADDR; } /// @notice Admin is able to change owner /// @param _owner Address of new owner function changeOwner(address _owner) public { if (admin != msg.sender){ revert SenderNotAdmin(); } owner = _owner; } /// @notice Admin is able to set new admin /// @param _admin Address of multisig that becomes new admin function changeAdmin(address _admin) public { if (admin != msg.sender){ revert SenderNotAdmin(); } admin = _admin; } } interface IERC20 { function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint256 digits); function totalSupply() external view returns (uint256 supply); function balanceOf(address _owner) external view returns (uint256 balance); function transfer(address _to, uint256 _value) external returns (bool success); function transferFrom( address _from, address _to, uint256 _value ) external returns (bool success); function approve(address _spender, uint256 _value) external returns (bool success); function allowance(address _owner, address _spender) external view returns (uint256 remaining); event Approval(address indexed _owner, address indexed _spender, uint256 _value); } library Address { //insufficient balance error InsufficientBalance(uint256 available, uint256 required); //unable to send value, recipient may have reverted error SendingValueFail(); //insufficient balance for call error InsufficientBalanceForCall(uint256 available, uint256 required); //call to non-contract error NonContractCall(); function isContract(address account) internal view returns (bool) { // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != accountHash && codehash != 0x0); } function sendValue(address payable recipient, uint256 amount) internal { uint256 balance = address(this).balance; if (balance < amount){ revert InsufficientBalance(balance, amount); } // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{value: amount}(""); if (!(success)){ revert SendingValueFail(); } } function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return _functionCallWithValue(target, data, 0, errorMessage); } function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { uint256 balance = address(this).balance; if (balance < value){ revert InsufficientBalanceForCall(balance, value); } return _functionCallWithValue(target, data, value, errorMessage); } function _functionCallWithValue( address target, bytes memory data, uint256 weiValue, string memory errorMessage ) private returns (bytes memory) { if (!(isContract(target))){ revert NonContractCall(); } // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{value: weiValue}(data); if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } library SafeERC20 { using Address for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to * 0 before setting it to a non-zero value. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0; } } contract AdminAuth is AuthHelper { using SafeERC20 for IERC20; AdminVault public constant adminVault = AdminVault(ADMIN_VAULT_ADDR); error SenderNotOwner(); error SenderNotAdmin(); modifier onlyOwner() { if (adminVault.owner() != msg.sender){ revert SenderNotOwner(); } _; } modifier onlyAdmin() { if (adminVault.admin() != msg.sender){ revert SenderNotAdmin(); } _; } /// @notice withdraw stuck funds function withdrawStuckFunds(address _token, address _receiver, uint256 _amount) public onlyOwner { if (_token == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) { payable(_receiver).transfer(_amount); } else { IERC20(_token).safeTransfer(_receiver, _amount); } } /// @notice Destroy the contract /// @dev Deprecated method, selfdestruct will soon just send eth function kill() public onlyAdmin { selfdestruct(payable(msg.sender)); } } contract DFSRegistry is AdminAuth { error EntryAlreadyExistsError(bytes4); error EntryNonExistentError(bytes4); error EntryNotInChangeError(bytes4); error ChangeNotReadyError(uint256,uint256); error EmptyPrevAddrError(bytes4); error AlreadyInContractChangeError(bytes4); error AlreadyInWaitPeriodChangeError(bytes4); event AddNewContract(address,bytes4,address,uint256); event RevertToPreviousAddress(address,bytes4,address,address); event StartContractChange(address,bytes4,address,address); event ApproveContractChange(address,bytes4,address,address); event CancelContractChange(address,bytes4,address,address); event StartWaitPeriodChange(address,bytes4,uint256); event ApproveWaitPeriodChange(address,bytes4,uint256,uint256); event CancelWaitPeriodChange(address,bytes4,uint256,uint256); struct Entry { address contractAddr; uint256 waitPeriod; uint256 changeStartTime; bool inContractChange; bool inWaitPeriodChange; bool exists; } mapping(bytes4 => Entry) public entries; mapping(bytes4 => address) public previousAddresses; mapping(bytes4 => address) public pendingAddresses; mapping(bytes4 => uint256) public pendingWaitTimes; /// @notice Given an contract id returns the registered address /// @dev Id is keccak256 of the contract name /// @param _id Id of contract function getAddr(bytes4 _id) public view returns (address) { return entries[_id].contractAddr; } /// @notice Helper function to easily query if id is registered /// @param _id Id of contract function isRegistered(bytes4 _id) public view returns (bool) { return entries[_id].exists; } /////////////////////////// OWNER ONLY FUNCTIONS /////////////////////////// /// @notice Adds a new contract to the registry /// @param _id Id of contract /// @param _contractAddr Address of the contract /// @param _waitPeriod Amount of time to wait before a contract address can be changed function addNewContract( bytes4 _id, address _contractAddr, uint256 _waitPeriod ) public onlyOwner { if (entries[_id].exists){ revert EntryAlreadyExistsError(_id); } entries[_id] = Entry({ contractAddr: _contractAddr, waitPeriod: _waitPeriod, changeStartTime: 0, inContractChange: false, inWaitPeriodChange: false, exists: true }); emit AddNewContract(msg.sender, _id, _contractAddr, _waitPeriod); } /// @notice Reverts to the previous address immediately /// @dev In case the new version has a fault, a quick way to fallback to the old contract /// @param _id Id of contract function revertToPreviousAddress(bytes4 _id) public onlyOwner { if (!(entries[_id].exists)){ revert EntryNonExistentError(_id); } if (previousAddresses[_id] == address(0)){ revert EmptyPrevAddrError(_id); } address currentAddr = entries[_id].contractAddr; entries[_id].contractAddr = previousAddresses[_id]; emit RevertToPreviousAddress(msg.sender, _id, currentAddr, previousAddresses[_id]); } /// @notice Starts an address change for an existing entry /// @dev Can override a change that is currently in progress /// @param _id Id of contract /// @param _newContractAddr Address of the new contract function startContractChange(bytes4 _id, address _newContractAddr) public onlyOwner { if (!entries[_id].exists){ revert EntryNonExistentError(_id); } if (entries[_id].inWaitPeriodChange){ revert AlreadyInWaitPeriodChangeError(_id); } entries[_id].changeStartTime = block.timestamp; // solhint-disable-line entries[_id].inContractChange = true; pendingAddresses[_id] = _newContractAddr; emit StartContractChange(msg.sender, _id, entries[_id].contractAddr, _newContractAddr); } /// @notice Changes new contract address, correct time must have passed /// @param _id Id of contract function approveContractChange(bytes4 _id) public onlyOwner { if (!entries[_id].exists){ revert EntryNonExistentError(_id); } if (!entries[_id].inContractChange){ revert EntryNotInChangeError(_id); } if (block.timestamp < (entries[_id].changeStartTime + entries[_id].waitPeriod)){// solhint-disable-line revert ChangeNotReadyError(block.timestamp, (entries[_id].changeStartTime + entries[_id].waitPeriod)); } address oldContractAddr = entries[_id].contractAddr; entries[_id].contractAddr = pendingAddresses[_id]; entries[_id].inContractChange = false; entries[_id].changeStartTime = 0; pendingAddresses[_id] = address(0); previousAddresses[_id] = oldContractAddr; emit ApproveContractChange(msg.sender, _id, oldContractAddr, entries[_id].contractAddr); } /// @notice Cancel pending change /// @param _id Id of contract function cancelContractChange(bytes4 _id) public onlyOwner { if (!entries[_id].exists){ revert EntryNonExistentError(_id); } if (!entries[_id].inContractChange){ revert EntryNotInChangeError(_id); } address oldContractAddr = pendingAddresses[_id]; pendingAddresses[_id] = address(0); entries[_id].inContractChange = false; entries[_id].changeStartTime = 0; emit CancelContractChange(msg.sender, _id, oldContractAddr, entries[_id].contractAddr); } /// @notice Starts the change for waitPeriod /// @param _id Id of contract /// @param _newWaitPeriod New wait time function startWaitPeriodChange(bytes4 _id, uint256 _newWaitPeriod) public onlyOwner { if (!entries[_id].exists){ revert EntryNonExistentError(_id); } if (entries[_id].inContractChange){ revert AlreadyInContractChangeError(_id); } pendingWaitTimes[_id] = _newWaitPeriod; entries[_id].changeStartTime = block.timestamp; // solhint-disable-line entries[_id].inWaitPeriodChange = true; emit StartWaitPeriodChange(msg.sender, _id, _newWaitPeriod); } /// @notice Changes new wait period, correct time must have passed /// @param _id Id of contract function approveWaitPeriodChange(bytes4 _id) public onlyOwner { if (!entries[_id].exists){ revert EntryNonExistentError(_id); } if (!entries[_id].inWaitPeriodChange){ revert EntryNotInChangeError(_id); } if (block.timestamp < (entries[_id].changeStartTime + entries[_id].waitPeriod)){ // solhint-disable-line revert ChangeNotReadyError(block.timestamp, (entries[_id].changeStartTime + entries[_id].waitPeriod)); } uint256 oldWaitTime = entries[_id].waitPeriod; entries[_id].waitPeriod = pendingWaitTimes[_id]; entries[_id].inWaitPeriodChange = false; entries[_id].changeStartTime = 0; pendingWaitTimes[_id] = 0; emit ApproveWaitPeriodChange(msg.sender, _id, oldWaitTime, entries[_id].waitPeriod); } /// @notice Cancel wait period change /// @param _id Id of contract function cancelWaitPeriodChange(bytes4 _id) public onlyOwner { if (!entries[_id].exists){ revert EntryNonExistentError(_id); } if (!entries[_id].inWaitPeriodChange){ revert EntryNotInChangeError(_id); } uint256 oldWaitPeriod = pendingWaitTimes[_id]; pendingWaitTimes[_id] = 0; entries[_id].inWaitPeriodChange = false; entries[_id].changeStartTime = 0; emit CancelWaitPeriodChange(msg.sender, _id, oldWaitPeriod, entries[_id].waitPeriod); } } contract MainnetCoreAddresses { address internal constant REGISTRY_ADDR = 0x287778F121F134C66212FB16c9b53eC991D32f5b; address internal constant PROXY_AUTH_ADDR = 0x149667b6FAe2c63D1B4317C716b0D0e4d3E2bD70; address internal constant MODULE_AUTH_ADDR = 0x7407974DDBF539e552F1d051e44573090912CC3D; address internal constant DEFISAVER_LOGGER = 0xcE7a977Cac4a481bc84AC06b2Da0df614e621cf3; address internal constant SUB_STORAGE_ADDR = 0x1612fc28Ee0AB882eC99842Cde0Fc77ff0691e90; address internal constant BUNDLE_STORAGE_ADDR = 0x223c6aDE533851Df03219f6E3D8B763Bd47f84cf; address internal constant STRATEGY_STORAGE_ADDR = 0xF52551F95ec4A2B4299DcC42fbbc576718Dbf933; address internal constant RECIPE_EXECUTOR_ADDR = 0x5029336642814bC51a42bA80BF83a6322110035D; } contract CoreHelper is MainnetCoreAddresses { } contract Discount is AdminAuth{ mapping(address => bool) public serviceFeesDisabled; function reenableServiceFee(address _wallet) public onlyOwner{ serviceFeesDisabled[_wallet] = false; } function disableServiceFee(address _wallet) public onlyOwner{ serviceFeesDisabled[_wallet] = true; } } abstract contract IWETH { function allowance(address, address) public virtual view returns (uint256); function balanceOf(address) public virtual view returns (uint256); function approve(address, uint256) public virtual; function transfer(address, uint256) public virtual returns (bool); function transferFrom( address, address, uint256 ) public virtual returns (bool); function deposit() public payable virtual; function withdraw(uint256) public virtual; } library TokenUtils { using SafeERC20 for IERC20; address public constant WETH_ADDR = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; address public constant ETH_ADDR = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; /// @dev Only approves the amount if allowance is lower than amount, does not decrease allowance function approveToken( address _tokenAddr, address _to, uint256 _amount ) internal { if (_tokenAddr == ETH_ADDR) return; if (IERC20(_tokenAddr).allowance(address(this), _to) < _amount) { IERC20(_tokenAddr).safeApprove(_to, _amount); } } function pullTokensIfNeeded( address _token, address _from, uint256 _amount ) internal returns (uint256) { // handle max uint amount if (_amount == type(uint256).max) { _amount = getBalance(_token, _from); } if (_from != address(0) && _from != address(this) && _token != ETH_ADDR && _amount != 0) { IERC20(_token).safeTransferFrom(_from, address(this), _amount); } return _amount; } function withdrawTokens( address _token, address _to, uint256 _amount ) internal returns (uint256) { if (_amount == type(uint256).max) { _amount = getBalance(_token, address(this)); } if (_to != address(0) && _to != address(this) && _amount != 0) { if (_token != ETH_ADDR) { IERC20(_token).safeTransfer(_to, _amount); } else { (bool success, ) = _to.call{value: _amount}(""); require(success, "Eth send fail"); } } return _amount; } function depositWeth(uint256 _amount) internal { IWETH(WETH_ADDR).deposit{value: _amount}(); } function withdrawWeth(uint256 _amount) internal { IWETH(WETH_ADDR).withdraw(_amount); } function getBalance(address _tokenAddr, address _acc) internal view returns (uint256) { if (_tokenAddr == ETH_ADDR) { return _acc.balance; } else { return IERC20(_tokenAddr).balanceOf(_acc); } } function getTokenDecimals(address _token) internal view returns (uint256) { if (_token == ETH_ADDR) return 18; return IERC20(_token).decimals(); } } contract DFSExchangeHelper { using TokenUtils for address; error InvalidOffchainData(); error OutOfRangeSlicingError(); //Order success but amount 0 error ZeroTokensSwapped(); using SafeERC20 for IERC20; function sendLeftover( address _srcAddr, address _destAddr, address payable _to ) internal { // clean out any eth leftover TokenUtils.ETH_ADDR.withdrawTokens(_to, type(uint256).max); _srcAddr.withdrawTokens(_to, type(uint256).max); _destAddr.withdrawTokens(_to, type(uint256).max); } function sliceUint(bytes memory bs, uint256 start) internal pure returns (uint256) { if (bs.length < start + 32){ revert OutOfRangeSlicingError(); } uint256 x; assembly { x := mload(add(bs, add(0x20, start))) } return x; } function writeUint256( bytes memory _b, uint256 _index, uint256 _input ) internal pure { if (_b.length < _index + 32) { revert InvalidOffchainData(); } bytes32 input = bytes32(_input); _index += 32; // Read the bytes32 from array memory assembly { mstore(add(_b, _index), input) } } } contract DFSExchangeData { struct OffchainData { address wrapper; // dfs wrapper address for the aggregator (must be in WrapperExchangeRegistry) address exchangeAddr; // exchange address we are calling to execute the order (must be in ExchangeAggregatorRegistry) address allowanceTarget; // exchange aggregator contract we give allowance to uint256 price; // expected price that the aggregator sent us uint256 protocolFee; // deprecated (used as a separate fee amount for 0x v1) bytes callData; // 0ff-chain calldata the aggregator gives to perform the swap } struct ExchangeData { address srcAddr; // source token address (which we're selling) address destAddr; // destination token address (which we're buying) uint256 srcAmount; // amount of source token in token decimals uint256 destAmount; // amount of bought token in token decimals uint256 minPrice; // minPrice we are expecting (checked in DFSExchangeCore) uint256 dfsFeeDivider; // service fee divider address user; // currently deprecated (used to check custom fees for the user) address wrapper; // on-chain wrapper address (must be in WrapperExchangeRegistry) bytes wrapperData; // on-chain additional data for on-chain (uniswap route for example) OffchainData offchainData; // offchain aggregator order } } abstract contract IOffchainWrapper is DFSExchangeData { function takeOrder( ExchangeData memory _exData ) virtual public payable returns (bool success, uint256); } interface IExecutorHelper { struct Swap { bytes data; bytes32 selectorAndFlags; // [selector (32 bits) + flags (224 bits)]; selector is 4 most significant bytes; flags are stored in 4 least significant bytes. } struct SwapExecutorDescription { Swap[][] swapSequences; address tokenIn; address tokenOut; uint256 minTotalAmountOut; address to; uint256 deadline; bytes positiveSlippageData; } struct UniSwap { address pool; address tokenIn; address tokenOut; address recipient; uint256 collectAmount; // amount that should be transferred to the pool uint32 swapFee; uint32 feePrecision; uint32 tokenWeightInput; } struct StableSwap { address pool; address tokenFrom; address tokenTo; uint8 tokenIndexFrom; uint8 tokenIndexTo; uint256 dx; uint256 poolLength; address poolLp; bool isSaddle; // true: saddle, false: stable } struct CurveSwap { address pool; address tokenFrom; address tokenTo; int128 tokenIndexFrom; int128 tokenIndexTo; uint256 dx; bool usePoolUnderlying; bool useTriCrypto; } struct UniswapV3KSElastic { address recipient; address pool; address tokenIn; address tokenOut; uint256 swapAmount; uint160 sqrtPriceLimitX96; bool isUniV3; // true = UniV3, false = KSElastic } struct BalancerV2 { address vault; bytes32 poolId; address assetIn; address assetOut; uint256 amount; } struct DODO { address recipient; address pool; address tokenFrom; address tokenTo; uint256 amount; address sellHelper; bool isSellBase; bool isVersion2; } struct GMX { address vault; address tokenIn; address tokenOut; uint256 amount; address receiver; } struct Synthetix { address synthetixProxy; address tokenIn; address tokenOut; bytes32 sourceCurrencyKey; uint256 sourceAmount; bytes32 destinationCurrencyKey; bool useAtomicExchange; } struct Platypus { address pool; address tokenIn; address tokenOut; address recipient; uint256 collectAmount; // amount that should be transferred to the pool } struct PSM { address router; address tokenIn; address tokenOut; uint256 amountIn; address recipient; } struct WSTETH { address pool; uint256 amount; bool isWrapping; } struct Maverick { address pool; address tokenIn; address tokenOut; address recipient; uint256 swapAmount; uint256 sqrtPriceLimitD18; } struct SyncSwap { bytes _data; address vault; address tokenIn; address pool; uint256 collectAmount; } struct AlgebraV1 { address recipient; address pool; address tokenIn; address tokenOut; uint256 swapAmount; uint160 sqrtPriceLimitX96; uint256 senderFeeOnTransfer; // [ FoT_FLAG(1 bit) ... SENDER_ADDRESS(160 bits) ] } struct BalancerBatch { address vault; bytes32[] poolIds; address[] path; // swap path from assetIn to assetOut bytes[] userDatas; uint256 amountIn; // assetIn amount } struct Mantis { address pool; address tokenIn; address tokenOut; uint256 amount; address recipient; } struct IziSwap { address pool; address tokenIn; address tokenOut; address recipient; uint256 swapAmount; int24 limitPoint; } struct TraderJoeV2 { address recipient; address pool; address tokenIn; address tokenOut; uint256 collectAmount; // most significant 1 bit is to determine whether pool is v2.1, else v2.0 } struct LevelFiV2 { address pool; address fromToken; address toToken; uint256 amountIn; uint256 minAmountOut; address recipient; // receive token out } struct GMXGLP { address rewardRouter; address stakedGLP; address glpManager; address yearnVault; address tokenIn; address tokenOut; uint256 swapAmount; address recipient; } struct Vooi { address pool; address fromToken; address toToken; uint256 fromID; uint256 toID; uint256 fromAmount; address to; } struct VelocoreV2 { address vault; address tokenIn; address tokenOut; uint256 amount; } struct MaticMigrate { address pool; address tokenAddress; // should be POL uint256 amount; address recipient; // empty if migrate } function executeUniswap( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeStableSwap( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeCurve( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeKSClassic( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeUniV3KSElastic( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeRfq( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeBalV2( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeDODO( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeVelodrome( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeGMX( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executePlatypus( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeWrappedstETH( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeStEth( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeSynthetix( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeHashflow( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executePSM( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeFrax( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeCamelot( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeKyberLimitOrder( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeMaverick( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeSyncSwap( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeAlgebraV1( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeBalancerBatch( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeWombat( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeMantis( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeIziSwap( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeWooFiV2( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeTraderJoeV2( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executePancakeStableSwap( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeLevelFiV2( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeGMXGLP( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeVooi( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeVelocoreV2( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeMaticMigrate( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); function executeSmardex( bytes memory data, uint256 flagsAndPrevAmountOut ) external payable returns (uint256); } interface IAggregationExecutor { function callBytes(bytes calldata data) external payable; // 0xd9c45357 // callbytes per swap sequence function swapSingleSequence(bytes calldata data) external; function finalTransactionProcessing( address tokenIn, address tokenOut, address to, bytes calldata destTokenFeeData ) external; } interface IMetaAggregationRouterV2 { struct SwapDescriptionV2 { IERC20 srcToken; IERC20 dstToken; address[] srcReceivers; // transfer src token to these addresses, default uint256[] srcAmounts; address[] feeReceivers; uint256[] feeAmounts; address dstReceiver; uint256 amount; uint256 minReturnAmount; uint256 flags; bytes permit; } /// @dev use for swapGeneric and swap to avoid stack too deep struct SwapExecutionParams { address callTarget; // call this address address approveTarget; // approve this address if _APPROVE_FUND set bytes targetData; SwapDescriptionV2 desc; bytes clientData; } struct SimpleSwapData { address[] firstPools; uint256[] firstSwapAmounts; bytes[] swapDatas; uint256 deadline; bytes positiveSlippageData; } function swap( SwapExecutionParams calldata execution ) external payable returns (uint256, uint256); function swapSimpleMode( IAggregationExecutor caller, SwapDescriptionV2 memory desc, bytes calldata executorData, bytes calldata clientData ) external returns (uint256, uint256); } contract KyberInputScalingHelper { uint256 private constant _PARTIAL_FILL = 0x01; uint256 private constant _REQUIRES_EXTRA_ETH = 0x02; uint256 private constant _SHOULD_CLAIM = 0x04; uint256 private constant _BURN_FROM_MSG_SENDER = 0x08; uint256 private constant _BURN_FROM_TX_ORIGIN = 0x10; uint256 private constant _SIMPLE_SWAP = 0x20; // fee data in case taking in dest token struct PositiveSlippageFeeData { uint256 partnerPSInfor; // [partnerReceiver (160 bit) + partnerPercent(96bits)] uint256 expectedReturnAmount; } struct Swap { bytes data; bytes32 selectorAndFlags; // [selector (32 bits) + flags (224 bits)]; selector is 4 most significant bytes; flags are stored in 4 least significant bytes. } struct SimpleSwapData { address[] firstPools; uint256[] firstSwapAmounts; bytes[] swapDatas; uint256 deadline; bytes positiveSlippageData; } struct SwapExecutorDescription { Swap[][] swapSequences; address tokenIn; address tokenOut; address to; uint256 deadline; bytes positiveSlippageData; } function getScaledInputData( bytes calldata inputData, uint256 newAmount ) public pure returns (bytes memory) { bytes4 selector = bytes4(inputData[:4]); bytes calldata dataToDecode = inputData[4:]; if (selector == IMetaAggregationRouterV2.swap.selector) { IMetaAggregationRouterV2.SwapExecutionParams memory params = abi.decode( dataToDecode, (IMetaAggregationRouterV2.SwapExecutionParams) ); (params.desc, params.targetData) = _getScaledInputDataV2( params.desc, params.targetData, newAmount, _flagsChecked(params.desc.flags, _SIMPLE_SWAP) ); return abi.encodeWithSelector(selector, params); } else if (selector == IMetaAggregationRouterV2.swapSimpleMode.selector) { ( address callTarget, IMetaAggregationRouterV2.SwapDescriptionV2 memory desc, bytes memory targetData, bytes memory clientData ) = abi.decode( dataToDecode, (address, IMetaAggregationRouterV2.SwapDescriptionV2, bytes, bytes) ); (desc, targetData) = _getScaledInputDataV2(desc, targetData, newAmount, true); return abi.encodeWithSelector(selector, callTarget, desc, targetData, clientData); } else revert("InputScalingHelper: Invalid selector"); } function _getScaledInputDataV2( IMetaAggregationRouterV2.SwapDescriptionV2 memory desc, bytes memory executorData, uint256 newAmount, bool isSimpleMode ) internal pure returns (IMetaAggregationRouterV2.SwapDescriptionV2 memory, bytes memory) { uint256 oldAmount = desc.amount; if (oldAmount == newAmount) { return (desc, executorData); } // simple mode swap if (isSimpleMode) { return ( _scaledSwapDescriptionV2(desc, oldAmount, newAmount), _scaledSimpleSwapData(executorData, oldAmount, newAmount) ); } //normal mode swap return ( _scaledSwapDescriptionV2(desc, oldAmount, newAmount), _scaledExecutorCallBytesData(executorData, oldAmount, newAmount) ); } /// @dev Scale the swap description function _scaledSwapDescriptionV2( IMetaAggregationRouterV2.SwapDescriptionV2 memory desc, uint256 oldAmount, uint256 newAmount ) internal pure returns (IMetaAggregationRouterV2.SwapDescriptionV2 memory) { desc.minReturnAmount = (desc.minReturnAmount * newAmount) / oldAmount; if (desc.minReturnAmount == 0) desc.minReturnAmount = 1; desc.amount = newAmount; uint256 nReceivers = desc.srcReceivers.length; for (uint256 i = 0; i < nReceivers; ) { desc.srcAmounts[i] = (desc.srcAmounts[i] * newAmount) / oldAmount; unchecked { ++i; } } return desc; } /// @dev Scale the executorData in case swapSimpleMode function _scaledSimpleSwapData( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory) { SimpleSwapData memory swapData = abi.decode(data, (SimpleSwapData)); uint256 nPools = swapData.firstPools.length; for (uint256 i = 0; i < nPools; ) { swapData.firstSwapAmounts[i] = (swapData.firstSwapAmounts[i] * newAmount) / oldAmount; unchecked { ++i; } } swapData.positiveSlippageData = _scaledPositiveSlippageFeeData( swapData.positiveSlippageData, oldAmount, newAmount ); return abi.encode(swapData); } function _scaledExecutorCallBytesData( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory) { SwapExecutorDescription memory executorDesc = abi.decode(data, (SwapExecutorDescription)); executorDesc.positiveSlippageData = _scaledPositiveSlippageFeeData( executorDesc.positiveSlippageData, oldAmount, newAmount ); uint256 nSequences = executorDesc.swapSequences.length; for (uint256 i = 0; i < nSequences; ) { Swap memory swap = executorDesc.swapSequences[i][0]; bytes4 functionSelector = bytes4(swap.selectorAndFlags); if (functionSelector == IExecutorHelper.executeUniswap.selector) { swap.data = newUniSwap(swap.data, oldAmount, newAmount); } else if (functionSelector == IExecutorHelper.executeStableSwap.selector) { swap.data = newStableSwap(swap.data, oldAmount, newAmount); } else if (functionSelector == IExecutorHelper.executeCurve.selector) { swap.data = newCurveSwap(swap.data, oldAmount, newAmount); } else if (functionSelector == IExecutorHelper.executeKSClassic.selector) { swap.data = newKyberDMM(swap.data, oldAmount, newAmount); } else if (functionSelector == IExecutorHelper.executeUniV3KSElastic.selector) { swap.data = newUniV3ProMM(swap.data, oldAmount, newAmount); } else if (functionSelector == IExecutorHelper.executeRfq.selector) { revert("InputScalingHelper: Can not scale RFQ swap"); } else if (functionSelector == IExecutorHelper.executeBalV2.selector) { swap.data = newBalancerV2(swap.data, oldAmount, newAmount); } else if (functionSelector == IExecutorHelper.executeWrappedstETH.selector) { swap.data = newWrappedstETHSwap(swap.data, oldAmount, newAmount); } else if (functionSelector == IExecutorHelper.executeStEth.selector) { swap.data = newStETHSwap(swap.data, oldAmount, newAmount); } else if (functionSelector == IExecutorHelper.executeDODO.selector) { swap.data = newDODO(swap.data, oldAmount, newAmount); } else if (functionSelector == IExecutorHelper.executeVelodrome.selector) { swap.data = newVelodrome(swap.data, oldAmount, newAmount); } else if (functionSelector == IExecutorHelper.executeGMX.selector) { swap.data = newGMX(swap.data, oldAmount, newAmount); } else if (functionSelector == IExecutorHelper.executeSynthetix.selector) { swap.data = newSynthetix(swap.data, oldAmount, newAmount); } else if (functionSelector == IExecutorHelper.executeHashflow.selector) { revert("InputScalingHelper: Can not scale RFQ swap"); } else if (functionSelector == IExecutorHelper.executeCamelot.selector) { swap.data = newCamelot(swap.data, oldAmount, newAmount); } else if (functionSelector == IExecutorHelper.executeKyberLimitOrder.selector) { revert("InputScalingHelper: Can not scale RFQ swap"); } else if (functionSelector == IExecutorHelper.executePSM.selector) { swap.data = newPSM(swap.data, oldAmount, newAmount); } else if (functionSelector == IExecutorHelper.executeFrax.selector) { swap.data = newFrax(swap.data, oldAmount, newAmount); } else if (functionSelector == IExecutorHelper.executePlatypus.selector) { swap.data = newPlatypus(swap.data, oldAmount, newAmount); } else if (functionSelector == IExecutorHelper.executeMaverick.selector) { swap.data = newMaverick(swap.data, oldAmount, newAmount); } else if (functionSelector == IExecutorHelper.executeSyncSwap.selector) { swap.data = newSyncSwap(swap.data, oldAmount, newAmount); } else if (functionSelector == IExecutorHelper.executeAlgebraV1.selector) { swap.data = newAlgebraV1(swap.data, oldAmount, newAmount); } else if (functionSelector == IExecutorHelper.executeBalancerBatch.selector) { swap.data = newBalancerBatch(swap.data, oldAmount, newAmount); } else if (functionSelector == IExecutorHelper.executeWombat.selector) { swap.data = newMantis(swap.data, oldAmount, newAmount); // @dev struct Mantis is used for both Wombat and Mantis because of same fields } else if (functionSelector == IExecutorHelper.executeMantis.selector) { swap.data = newMantis(swap.data, oldAmount, newAmount); } else if (functionSelector == IExecutorHelper.executeIziSwap.selector) { swap.data = newIziSwap(swap.data, oldAmount, newAmount); } else if (functionSelector == IExecutorHelper.executeWooFiV2.selector) { swap.data = newMantis(swap.data, oldAmount, newAmount); // @dev using Mantis struct because WooFiV2 and Mantis have same fields } else if (functionSelector == IExecutorHelper.executeTraderJoeV2.selector) { swap.data = newTraderJoeV2(swap.data, oldAmount, newAmount); } else if (functionSelector == IExecutorHelper.executePancakeStableSwap.selector) { swap.data = newCurveSwap(swap.data, oldAmount, newAmount); } else revert("AggregationExecutor: Dex type not supported"); unchecked { ++i; } } return abi.encode(executorDesc); } function newUniSwap( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory) { IExecutorHelper.UniSwap memory uniSwap = abi.decode(data, (IExecutorHelper.UniSwap)); uniSwap.collectAmount = (uniSwap.collectAmount * newAmount) / oldAmount; return abi.encode(uniSwap); } function newStableSwap( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory) { IExecutorHelper.StableSwap memory stableSwap = abi.decode( data, (IExecutorHelper.StableSwap) ); stableSwap.dx = (stableSwap.dx * newAmount) / oldAmount; return abi.encode(stableSwap); } function newCurveSwap( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory) { IExecutorHelper.CurveSwap memory curveSwap = abi.decode(data, (IExecutorHelper.CurveSwap)); curveSwap.dx = (curveSwap.dx * newAmount) / oldAmount; return abi.encode(curveSwap); } function newKyberDMM( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory) { IExecutorHelper.UniSwap memory kyberDMMSwap = abi.decode(data, (IExecutorHelper.UniSwap)); kyberDMMSwap.collectAmount = (kyberDMMSwap.collectAmount * newAmount) / oldAmount; return abi.encode(kyberDMMSwap); } function newUniV3ProMM( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory) { IExecutorHelper.UniswapV3KSElastic memory uniSwapV3ProMM = abi.decode( data, (IExecutorHelper.UniswapV3KSElastic) ); uniSwapV3ProMM.swapAmount = (uniSwapV3ProMM.swapAmount * newAmount) / oldAmount; return abi.encode(uniSwapV3ProMM); } function newBalancerV2( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory) { IExecutorHelper.BalancerV2 memory balancerV2 = abi.decode( data, (IExecutorHelper.BalancerV2) ); balancerV2.amount = (balancerV2.amount * newAmount) / oldAmount; return abi.encode(balancerV2); } function newDODO( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory) { IExecutorHelper.DODO memory dodo = abi.decode(data, (IExecutorHelper.DODO)); dodo.amount = (dodo.amount * newAmount) / oldAmount; return abi.encode(dodo); } function newVelodrome( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory) { IExecutorHelper.UniSwap memory velodrome = abi.decode(data, (IExecutorHelper.UniSwap)); velodrome.collectAmount = (velodrome.collectAmount * newAmount) / oldAmount; return abi.encode(velodrome); } function newGMX( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory) { IExecutorHelper.GMX memory gmx = abi.decode(data, (IExecutorHelper.GMX)); gmx.amount = (gmx.amount * newAmount) / oldAmount; return abi.encode(gmx); } function newSynthetix( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory) { IExecutorHelper.Synthetix memory synthetix = abi.decode(data, (IExecutorHelper.Synthetix)); synthetix.sourceAmount = (synthetix.sourceAmount * newAmount) / oldAmount; return abi.encode(synthetix); } function newCamelot( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory) { IExecutorHelper.UniSwap memory camelot = abi.decode(data, (IExecutorHelper.UniSwap)); camelot.collectAmount = (camelot.collectAmount * newAmount) / oldAmount; return abi.encode(camelot); } function newPlatypus( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory) { IExecutorHelper.Platypus memory platypus = abi.decode(data, (IExecutorHelper.Platypus)); platypus.collectAmount = (platypus.collectAmount * newAmount) / oldAmount; return abi.encode(platypus); } function newWrappedstETHSwap( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory) { IExecutorHelper.WSTETH memory wstEthData = abi.decode(data, (IExecutorHelper.WSTETH)); wstEthData.amount = (wstEthData.amount * newAmount) / oldAmount; return abi.encode(wstEthData); } function newPSM( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory) { IExecutorHelper.PSM memory psm = abi.decode(data, (IExecutorHelper.PSM)); psm.amountIn = (psm.amountIn * newAmount) / oldAmount; return abi.encode(psm); } function newFrax( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory) { IExecutorHelper.UniSwap memory frax = abi.decode(data, (IExecutorHelper.UniSwap)); frax.collectAmount = (frax.collectAmount * newAmount) / oldAmount; return abi.encode(frax); } function newStETHSwap( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory) { uint256 amount = abi.decode(data, (uint256)); amount = (amount * newAmount) / oldAmount; return abi.encode(amount); } function newMaverick( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory) { IExecutorHelper.Maverick memory maverick = abi.decode(data, (IExecutorHelper.Maverick)); maverick.swapAmount = (maverick.swapAmount * newAmount) / oldAmount; return abi.encode(maverick); } function newSyncSwap( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory) { IExecutorHelper.SyncSwap memory syncSwap = abi.decode(data, (IExecutorHelper.SyncSwap)); syncSwap.collectAmount = (syncSwap.collectAmount * newAmount) / oldAmount; return abi.encode(syncSwap); } function newAlgebraV1( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory) { IExecutorHelper.AlgebraV1 memory algebraV1Swap = abi.decode( data, (IExecutorHelper.AlgebraV1) ); algebraV1Swap.swapAmount = (algebraV1Swap.swapAmount * newAmount) / oldAmount; return abi.encode(algebraV1Swap); } function newBalancerBatch( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory) { IExecutorHelper.BalancerBatch memory balancerBatch = abi.decode( data, (IExecutorHelper.BalancerBatch) ); balancerBatch.amountIn = (balancerBatch.amountIn * newAmount) / oldAmount; return abi.encode(balancerBatch); } function newMantis( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory) { IExecutorHelper.Mantis memory mantis = abi.decode(data, (IExecutorHelper.Mantis)); mantis.amount = (mantis.amount * newAmount) / oldAmount; return abi.encode(mantis); } function newIziSwap( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory) { IExecutorHelper.IziSwap memory iZi = abi.decode(data, (IExecutorHelper.IziSwap)); iZi.swapAmount = (iZi.swapAmount * newAmount) / oldAmount; return abi.encode(iZi); } function newTraderJoeV2( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory) { IExecutorHelper.TraderJoeV2 memory traderJoe = abi.decode( data, (IExecutorHelper.TraderJoeV2) ); // traderJoe.collectAmount; // most significant 1 bit is to determine whether pool is v2.1, else v2.0 traderJoe.collectAmount = (traderJoe.collectAmount & (1 << 255)) | ((uint256((traderJoe.collectAmount << 1) >> 1) * newAmount) / oldAmount); return abi.encode(traderJoe); } function _scaledPositiveSlippageFeeData( bytes memory data, uint256 oldAmount, uint256 newAmount ) internal pure returns (bytes memory newData) { if (data.length > 32) { PositiveSlippageFeeData memory psData = abi.decode(data, (PositiveSlippageFeeData)); uint256 left = uint256(psData.expectedReturnAmount >> 128); uint256 right = (uint256(uint128(psData.expectedReturnAmount)) * newAmount) / oldAmount; require(right <= type(uint128).max, "Exceeded type range"); psData.expectedReturnAmount = right | (left << 128); data = abi.encode(psData); } else if (data.length == 32) { uint256 expectedReturnAmount = abi.decode(data, (uint256)); uint256 left = uint256(expectedReturnAmount >> 128); uint256 right = (uint256(uint128(expectedReturnAmount)) * newAmount) / oldAmount; require(right <= type(uint128).max, "Exceeded type range"); expectedReturnAmount = right | (left << 128); data = abi.encode(expectedReturnAmount); } return data; } function _flagsChecked(uint256 number, uint256 flag) internal pure returns (bool) { return number & flag != 0; } } contract KyberAggregatorWrapper is IOffchainWrapper, DFSExchangeHelper, AdminAuth, CoreHelper{ using TokenUtils for address; using SafeERC20 for IERC20; bytes4 constant SCALING_HELPER_ID = bytes4(keccak256("KyberInputScalingHelper")); DFSRegistry public constant registry = DFSRegistry(REGISTRY_ADDR); /// @notice Takes order from Kyberswap and returns bool indicating if it is successful /// @param _exData Exchange data function takeOrder( ExchangeData calldata _exData ) override public payable returns (bool success, uint256) { /// @dev safeApprove is modified to always first set approval to 0, then to exact amount IERC20(_exData.srcAddr).safeApprove(_exData.offchainData.allowanceTarget, _exData.srcAmount); address scalingHelperAddr = registry.getAddr(SCALING_HELPER_ID); bytes memory scaledCalldata = KyberInputScalingHelper(scalingHelperAddr).getScaledInputData(_exData.offchainData.callData, _exData.srcAmount); uint256 tokensBefore = _exData.destAddr.getBalance(address(this)); /// @dev the amount of tokens received is checked in DFSExchangeCore /// @dev Exchange wrapper contracts should not be used on their own (success, ) = _exData.offchainData.exchangeAddr.call(scaledCalldata); uint256 tokensSwapped = 0; if (success) { // get the current balance of the swapped tokens tokensSwapped = _exData.destAddr.getBalance(address(this)) - tokensBefore; if (tokensSwapped == 0){ revert ZeroTokensSwapped(); } } // returns all funds from src addr, dest addr and eth funds (protocol fee leftovers) sendLeftover(_exData.srcAddr, _exData.destAddr, payable(msg.sender)); return (success, tokensSwapped); } // solhint-disable-next-line no-empty-blocks receive() external virtual payable {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"name":"InvalidOffchainData","type":"error"},{"inputs":[],"name":"NonContractCall","type":"error"},{"inputs":[],"name":"OutOfRangeSlicingError","type":"error"},{"inputs":[],"name":"SenderNotAdmin","type":"error"},{"inputs":[],"name":"SenderNotOwner","type":"error"},{"inputs":[],"name":"ZeroTokensSwapped","type":"error"},{"inputs":[],"name":"adminVault","outputs":[{"internalType":"contract AdminVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"kill","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"registry","outputs":[{"internalType":"contract DFSRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"srcAddr","type":"address"},{"internalType":"address","name":"destAddr","type":"address"},{"internalType":"uint256","name":"srcAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"minPrice","type":"uint256"},{"internalType":"uint256","name":"dfsFeeDivider","type":"uint256"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"wrapper","type":"address"},{"internalType":"bytes","name":"wrapperData","type":"bytes"},{"components":[{"internalType":"address","name":"wrapper","type":"address"},{"internalType":"address","name":"exchangeAddr","type":"address"},{"internalType":"address","name":"allowanceTarget","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"protocolFee","type":"uint256"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct DFSExchangeData.OffchainData","name":"offchainData","type":"tuple"}],"internalType":"struct DFSExchangeData.ExchangeData","name":"_exData","type":"tuple"}],"name":"takeOrder","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawStuckFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
608060405234801561001057600080fd5b50610f96806100206000396000f3fe60806040526004361061005e5760003560e01c80637b103999116100435780637b103999146100b05780638cedca71146100f0578063c579d4901461011857600080fd5b806316d2a88c1461006a57806341c0e1b51461009957600080fd5b3661006557005b600080fd5b61007d610078366004610c4f565b610138565b6040805192151583526020830191909152015b60405180910390f35b3480156100a557600080fd5b506100ae6103fd565b005b3480156100bc57600080fd5b506100d873287778f121f134c66212fb16c9b53ec991d32f5b81565b6040516001600160a01b039091168152602001610090565b3480156100fc57600080fd5b506100d873ccf3d848e08b94478ed8f46ffead3008faf581fd81565b34801561012457600080fd5b506100ae610133366004610caa565b6104c0565b60008061017f61014c610120850185610ceb565b61015d906060810190604001610d0b565b604085013561016f6020870187610d0b565b6001600160a01b031691906105fa565b6040517f93b188540000000000000000000000000000000000000000000000000000000081527f559d99f500000000000000000000000000000000000000000000000000000000600482015260009073287778f121f134c66212fb16c9b53ec991d32f5b906393b1885490602401602060405180830381865afa15801561020a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061022e9190610d28565b905060006001600160a01b03821663e4da6f2e61024f610120880188610ceb565b61025d9060a0810190610d45565b88604001356040518463ffffffff1660e01b815260040161028093929190610d93565b600060405180830381865afa15801561029d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526102c59190810190610e0e565b905060006102ec306102dd6040890160208a01610d0b565b6001600160a01b0316906106fe565b90506102fc610120870187610ceb565b61030d906040810190602001610d0b565b6001600160a01b0316826040516103249190610ebb565b6000604051808303816000865af19150503d8060008114610361576040519150601f19603f3d011682016040523d82523d6000602084013e610366565b606091505b505080955050600085156103cc5781610389306102dd60408b0160208c01610d0b565b6103939190610ecd565b9050806103cc576040517f6a756fbe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6103f26103dc6020890189610d0b565b6103ec60408a0160208b01610d0b565b336107c2565b949694955050505050565b336001600160a01b031673ccf3d848e08b94478ed8f46ffead3008faf581fd6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610459573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061047d9190610d28565b6001600160a01b0316146104bd576040517fa6c827a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33ff5b336001600160a01b031673ccf3d848e08b94478ed8f46ffead3008faf581fd6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561051c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105409190610d28565b6001600160a01b031614610580576040517f19494c8a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b03841614156105e1576040516001600160a01b0383169082156108fc029083906000818181858888f193505050501580156105db573d6000803e3d6000fd5b50505050565b6105f56001600160a01b0384168383610811565b505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663095ea7b360e01b179052610660848261085a565b6105db576040516001600160a01b0384166024820152600060448201526106f490859063095ea7b360e01b906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152610902565b6105db8482610902565b60006001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee141561073657506001600160a01b038116316107bc565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301528416906370a0823190602401602060405180830381865afa158015610795573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b99190610ef2565b90505b92915050565b6107e373eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee826000196109ef565b506107fa6001600160a01b038416826000196109ef565b506105db6001600160a01b038316826000196109ef565b6040516001600160a01b0383166024820152604481018290526105f59084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401610690565b6000806000846001600160a01b0316846040516108779190610ebb565b6000604051808303816000865af19150503d80600081146108b4576040519150601f19603f3d011682016040523d82523d6000602084013e6108b9565b606091505b50915091508180156108e35750805115806108e35750808060200190518101906108e39190610f0b565b80156108f957506000856001600160a01b03163b115b95945050505050565b6000610957826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316610b229092919063ffffffff16565b90508051600014806109785750808060200190518101906109789190610f0b565b6105f55760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6000600019821415610a0857610a0584306106fe565b91505b6001600160a01b03831615801590610a2957506001600160a01b0383163014155b8015610a3457508115155b15610b1b576001600160a01b03841673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610a7657610a716001600160a01b0385168484610811565b610b1b565b6000836001600160a01b03168360405160006040518083038185875af1925050503d8060008114610ac3576040519150601f19603f3d011682016040523d82523d6000602084013e610ac8565b606091505b5050905080610b195760405162461bcd60e51b815260206004820152600d60248201527f4574682073656e64206661696c0000000000000000000000000000000000000060448201526064016109e6565b505b5092915050565b6060610b318484600085610b39565b949350505050565b6060610b4485610c16565b610b7a576040517f304619b500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080866001600160a01b03168587604051610b969190610ebb565b60006040518083038185875af1925050503d8060008114610bd3576040519150601f19603f3d011682016040523d82523d6000602084013e610bd8565b606091505b50915091508115610bec579150610b319050565b805115610bfc5780518082602001fd5b8360405162461bcd60e51b81526004016109e69190610f2d565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610b31575050151592915050565b600060208284031215610c6157600080fd5b813567ffffffffffffffff811115610c7857600080fd5b82016101408185031215610c8b57600080fd5b9392505050565b6001600160a01b0381168114610ca757600080fd5b50565b600080600060608486031215610cbf57600080fd5b8335610cca81610c92565b92506020840135610cda81610c92565b929592945050506040919091013590565b6000823560be19833603018112610d0157600080fd5b9190910192915050565b600060208284031215610d1d57600080fd5b8135610c8b81610c92565b600060208284031215610d3a57600080fd5b8151610c8b81610c92565b6000808335601e19843603018112610d5c57600080fd5b83018035915067ffffffffffffffff821115610d7757600080fd5b602001915036819003821315610d8c57600080fd5b9250929050565b604081528260408201528284606083013760006060848301015260006060601f19601f8601168301019050826020830152949350505050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015610dfd578181015183820152602001610de5565b838111156105db5750506000910152565b600060208284031215610e2057600080fd5b815167ffffffffffffffff80821115610e3857600080fd5b818401915084601f830112610e4c57600080fd5b815181811115610e5e57610e5e610dcc565b604051601f8201601f19908116603f01168101908382118183101715610e8657610e86610dcc565b81604052828152876020848701011115610e9f57600080fd5b610eb0836020830160208801610de2565b979650505050505050565b60008251610d01818460208701610de2565b600082821015610eed57634e487b7160e01b600052601160045260246000fd5b500390565b600060208284031215610f0457600080fd5b5051919050565b600060208284031215610f1d57600080fd5b81518015158114610c8b57600080fd5b6020815260008251806020840152610f4c816040850160208701610de2565b601f01601f1916919091016040019291505056fea2646970667358221220c80b62d0024a1baa833a40ae35eaddc3f6db6d9c23002ece241d1f6f4cc6a66664736f6c634300080a0033
Deployed Bytecode
0x60806040526004361061005e5760003560e01c80637b103999116100435780637b103999146100b05780638cedca71146100f0578063c579d4901461011857600080fd5b806316d2a88c1461006a57806341c0e1b51461009957600080fd5b3661006557005b600080fd5b61007d610078366004610c4f565b610138565b6040805192151583526020830191909152015b60405180910390f35b3480156100a557600080fd5b506100ae6103fd565b005b3480156100bc57600080fd5b506100d873287778f121f134c66212fb16c9b53ec991d32f5b81565b6040516001600160a01b039091168152602001610090565b3480156100fc57600080fd5b506100d873ccf3d848e08b94478ed8f46ffead3008faf581fd81565b34801561012457600080fd5b506100ae610133366004610caa565b6104c0565b60008061017f61014c610120850185610ceb565b61015d906060810190604001610d0b565b604085013561016f6020870187610d0b565b6001600160a01b031691906105fa565b6040517f93b188540000000000000000000000000000000000000000000000000000000081527f559d99f500000000000000000000000000000000000000000000000000000000600482015260009073287778f121f134c66212fb16c9b53ec991d32f5b906393b1885490602401602060405180830381865afa15801561020a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061022e9190610d28565b905060006001600160a01b03821663e4da6f2e61024f610120880188610ceb565b61025d9060a0810190610d45565b88604001356040518463ffffffff1660e01b815260040161028093929190610d93565b600060405180830381865afa15801561029d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526102c59190810190610e0e565b905060006102ec306102dd6040890160208a01610d0b565b6001600160a01b0316906106fe565b90506102fc610120870187610ceb565b61030d906040810190602001610d0b565b6001600160a01b0316826040516103249190610ebb565b6000604051808303816000865af19150503d8060008114610361576040519150601f19603f3d011682016040523d82523d6000602084013e610366565b606091505b505080955050600085156103cc5781610389306102dd60408b0160208c01610d0b565b6103939190610ecd565b9050806103cc576040517f6a756fbe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6103f26103dc6020890189610d0b565b6103ec60408a0160208b01610d0b565b336107c2565b949694955050505050565b336001600160a01b031673ccf3d848e08b94478ed8f46ffead3008faf581fd6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610459573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061047d9190610d28565b6001600160a01b0316146104bd576040517fa6c827a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33ff5b336001600160a01b031673ccf3d848e08b94478ed8f46ffead3008faf581fd6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561051c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105409190610d28565b6001600160a01b031614610580576040517f19494c8a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b03841614156105e1576040516001600160a01b0383169082156108fc029083906000818181858888f193505050501580156105db573d6000803e3d6000fd5b50505050565b6105f56001600160a01b0384168383610811565b505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663095ea7b360e01b179052610660848261085a565b6105db576040516001600160a01b0384166024820152600060448201526106f490859063095ea7b360e01b906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152610902565b6105db8482610902565b60006001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee141561073657506001600160a01b038116316107bc565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301528416906370a0823190602401602060405180830381865afa158015610795573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b99190610ef2565b90505b92915050565b6107e373eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee826000196109ef565b506107fa6001600160a01b038416826000196109ef565b506105db6001600160a01b038316826000196109ef565b6040516001600160a01b0383166024820152604481018290526105f59084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401610690565b6000806000846001600160a01b0316846040516108779190610ebb565b6000604051808303816000865af19150503d80600081146108b4576040519150601f19603f3d011682016040523d82523d6000602084013e6108b9565b606091505b50915091508180156108e35750805115806108e35750808060200190518101906108e39190610f0b565b80156108f957506000856001600160a01b03163b115b95945050505050565b6000610957826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316610b229092919063ffffffff16565b90508051600014806109785750808060200190518101906109789190610f0b565b6105f55760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6000600019821415610a0857610a0584306106fe565b91505b6001600160a01b03831615801590610a2957506001600160a01b0383163014155b8015610a3457508115155b15610b1b576001600160a01b03841673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610a7657610a716001600160a01b0385168484610811565b610b1b565b6000836001600160a01b03168360405160006040518083038185875af1925050503d8060008114610ac3576040519150601f19603f3d011682016040523d82523d6000602084013e610ac8565b606091505b5050905080610b195760405162461bcd60e51b815260206004820152600d60248201527f4574682073656e64206661696c0000000000000000000000000000000000000060448201526064016109e6565b505b5092915050565b6060610b318484600085610b39565b949350505050565b6060610b4485610c16565b610b7a576040517f304619b500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080866001600160a01b03168587604051610b969190610ebb565b60006040518083038185875af1925050503d8060008114610bd3576040519150601f19603f3d011682016040523d82523d6000602084013e610bd8565b606091505b50915091508115610bec579150610b319050565b805115610bfc5780518082602001fd5b8360405162461bcd60e51b81526004016109e69190610f2d565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610b31575050151592915050565b600060208284031215610c6157600080fd5b813567ffffffffffffffff811115610c7857600080fd5b82016101408185031215610c8b57600080fd5b9392505050565b6001600160a01b0381168114610ca757600080fd5b50565b600080600060608486031215610cbf57600080fd5b8335610cca81610c92565b92506020840135610cda81610c92565b929592945050506040919091013590565b6000823560be19833603018112610d0157600080fd5b9190910192915050565b600060208284031215610d1d57600080fd5b8135610c8b81610c92565b600060208284031215610d3a57600080fd5b8151610c8b81610c92565b6000808335601e19843603018112610d5c57600080fd5b83018035915067ffffffffffffffff821115610d7757600080fd5b602001915036819003821315610d8c57600080fd5b9250929050565b604081528260408201528284606083013760006060848301015260006060601f19601f8601168301019050826020830152949350505050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015610dfd578181015183820152602001610de5565b838111156105db5750506000910152565b600060208284031215610e2057600080fd5b815167ffffffffffffffff80821115610e3857600080fd5b818401915084601f830112610e4c57600080fd5b815181811115610e5e57610e5e610dcc565b604051601f8201601f19908116603f01168101908382118183101715610e8657610e86610dcc565b81604052828152876020848701011115610e9f57600080fd5b610eb0836020830160208801610de2565b979650505050505050565b60008251610d01818460208701610de2565b600082821015610eed57634e487b7160e01b600052601160045260246000fd5b500390565b600060208284031215610f0457600080fd5b5051919050565b600060208284031215610f1d57600080fd5b81518015158114610c8b57600080fd5b6020815260008251806020840152610f4c816040850160208701610de2565b601f01601f1916919091016040019291505056fea2646970667358221220c80b62d0024a1baa833a40ae35eaddc3f6db6d9c23002ece241d1f6f4cc6a66664736f6c634300080a0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.