ETH Price: $3,318.37 (+3.86%)
 
Transaction Hash
Method
Block
From
To

There are no matching entries

> 10 Token Transfers found.

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

Optimization Enabled:
Yes with 1000 runs

Other Settings:
default evmVersion, MIT license

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

Contract ABI

[{"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"}]

608060405234801561001057600080fd5b50610f96806100206000396000f3fe60806040526004361061005e5760003560e01c80637b103999116100435780637b103999146100b05780638cedca71146100f0578063c579d4901461011857600080fd5b806316d2a88c1461006a57806341c0e1b51461009957600080fd5b3661006557005b600080fd5b61007d610078366004610c4f565b610138565b6040805192151583526020830191909152015b60405180910390f35b3480156100a557600080fd5b506100ae6103fd565b005b3480156100bc57600080fd5b506100d873287778f121f134c66212fb16c9b53ec991d32f5b81565b6040516001600160a01b039091168152602001610090565b3480156100fc57600080fd5b506100d873ccf3d848e08b94478ed8f46ffead3008faf581fd81565b34801561012457600080fd5b506100ae610133366004610caa565b6104c0565b60008061017f61014c610120850185610ceb565b61015d906060810190604001610d0b565b604085013561016f6020870187610d0b565b6001600160a01b031691906105fa565b6040517f93b188540000000000000000000000000000000000000000000000000000000081527f559d99f500000000000000000000000000000000000000000000000000000000600482015260009073287778f121f134c66212fb16c9b53ec991d32f5b906393b1885490602401602060405180830381865afa15801561020a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061022e9190610d28565b905060006001600160a01b03821663e4da6f2e61024f610120880188610ceb565b61025d9060a0810190610d45565b88604001356040518463ffffffff1660e01b815260040161028093929190610d93565b600060405180830381865afa15801561029d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526102c59190810190610e0e565b905060006102ec306102dd6040890160208a01610d0b565b6001600160a01b0316906106fe565b90506102fc610120870187610ceb565b61030d906040810190602001610d0b565b6001600160a01b0316826040516103249190610ebb565b6000604051808303816000865af19150503d8060008114610361576040519150601f19603f3d011682016040523d82523d6000602084013e610366565b606091505b505080955050600085156103cc5781610389306102dd60408b0160208c01610d0b565b6103939190610ecd565b9050806103cc576040517f6a756fbe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6103f26103dc6020890189610d0b565b6103ec60408a0160208b01610d0b565b336107c2565b949694955050505050565b336001600160a01b031673ccf3d848e08b94478ed8f46ffead3008faf581fd6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610459573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061047d9190610d28565b6001600160a01b0316146104bd576040517fa6c827a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33ff5b336001600160a01b031673ccf3d848e08b94478ed8f46ffead3008faf581fd6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561051c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105409190610d28565b6001600160a01b031614610580576040517f19494c8a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b03841614156105e1576040516001600160a01b0383169082156108fc029083906000818181858888f193505050501580156105db573d6000803e3d6000fd5b50505050565b6105f56001600160a01b0384168383610811565b505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663095ea7b360e01b179052610660848261085a565b6105db576040516001600160a01b0384166024820152600060448201526106f490859063095ea7b360e01b906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152610902565b6105db8482610902565b60006001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee141561073657506001600160a01b038116316107bc565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301528416906370a0823190602401602060405180830381865afa158015610795573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b99190610ef2565b90505b92915050565b6107e373eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee826000196109ef565b506107fa6001600160a01b038416826000196109ef565b506105db6001600160a01b038316826000196109ef565b6040516001600160a01b0383166024820152604481018290526105f59084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401610690565b6000806000846001600160a01b0316846040516108779190610ebb565b6000604051808303816000865af19150503d80600081146108b4576040519150601f19603f3d011682016040523d82523d6000602084013e6108b9565b606091505b50915091508180156108e35750805115806108e35750808060200190518101906108e39190610f0b565b80156108f957506000856001600160a01b03163b115b95945050505050565b6000610957826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316610b229092919063ffffffff16565b90508051600014806109785750808060200190518101906109789190610f0b565b6105f55760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6000600019821415610a0857610a0584306106fe565b91505b6001600160a01b03831615801590610a2957506001600160a01b0383163014155b8015610a3457508115155b15610b1b576001600160a01b03841673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610a7657610a716001600160a01b0385168484610811565b610b1b565b6000836001600160a01b03168360405160006040518083038185875af1925050503d8060008114610ac3576040519150601f19603f3d011682016040523d82523d6000602084013e610ac8565b606091505b5050905080610b195760405162461bcd60e51b815260206004820152600d60248201527f4574682073656e64206661696c0000000000000000000000000000000000000060448201526064016109e6565b505b5092915050565b6060610b318484600085610b39565b949350505050565b6060610b4485610c16565b610b7a576040517f304619b500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080866001600160a01b03168587604051610b969190610ebb565b60006040518083038185875af1925050503d8060008114610bd3576040519150601f19603f3d011682016040523d82523d6000602084013e610bd8565b606091505b50915091508115610bec579150610b319050565b805115610bfc5780518082602001fd5b8360405162461bcd60e51b81526004016109e69190610f2d565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610b31575050151592915050565b600060208284031215610c6157600080fd5b813567ffffffffffffffff811115610c7857600080fd5b82016101408185031215610c8b57600080fd5b9392505050565b6001600160a01b0381168114610ca757600080fd5b50565b600080600060608486031215610cbf57600080fd5b8335610cca81610c92565b92506020840135610cda81610c92565b929592945050506040919091013590565b6000823560be19833603018112610d0157600080fd5b9190910192915050565b600060208284031215610d1d57600080fd5b8135610c8b81610c92565b600060208284031215610d3a57600080fd5b8151610c8b81610c92565b6000808335601e19843603018112610d5c57600080fd5b83018035915067ffffffffffffffff821115610d7757600080fd5b602001915036819003821315610d8c57600080fd5b9250929050565b604081528260408201528284606083013760006060848301015260006060601f19601f8601168301019050826020830152949350505050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015610dfd578181015183820152602001610de5565b838111156105db5750506000910152565b600060208284031215610e2057600080fd5b815167ffffffffffffffff80821115610e3857600080fd5b818401915084601f830112610e4c57600080fd5b815181811115610e5e57610e5e610dcc565b604051601f8201601f19908116603f01168101908382118183101715610e8657610e86610dcc565b81604052828152876020848701011115610e9f57600080fd5b610eb0836020830160208801610de2565b979650505050505050565b60008251610d01818460208701610de2565b600082821015610eed57634e487b7160e01b600052601160045260246000fd5b500390565b600060208284031215610f0457600080fd5b5051919050565b600060208284031215610f1d57600080fd5b81518015158114610c8b57600080fd5b6020815260008251806020840152610f4c816040850160208701610de2565b601f01601f1916919091016040019291505056fea2646970667358221220c80b62d0024a1baa833a40ae35eaddc3f6db6d9c23002ece241d1f6f4cc6a66664736f6c634300080a0033

Deployed Bytecode

0x60806040526004361061005e5760003560e01c80637b103999116100435780637b103999146100b05780638cedca71146100f0578063c579d4901461011857600080fd5b806316d2a88c1461006a57806341c0e1b51461009957600080fd5b3661006557005b600080fd5b61007d610078366004610c4f565b610138565b6040805192151583526020830191909152015b60405180910390f35b3480156100a557600080fd5b506100ae6103fd565b005b3480156100bc57600080fd5b506100d873287778f121f134c66212fb16c9b53ec991d32f5b81565b6040516001600160a01b039091168152602001610090565b3480156100fc57600080fd5b506100d873ccf3d848e08b94478ed8f46ffead3008faf581fd81565b34801561012457600080fd5b506100ae610133366004610caa565b6104c0565b60008061017f61014c610120850185610ceb565b61015d906060810190604001610d0b565b604085013561016f6020870187610d0b565b6001600160a01b031691906105fa565b6040517f93b188540000000000000000000000000000000000000000000000000000000081527f559d99f500000000000000000000000000000000000000000000000000000000600482015260009073287778f121f134c66212fb16c9b53ec991d32f5b906393b1885490602401602060405180830381865afa15801561020a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061022e9190610d28565b905060006001600160a01b03821663e4da6f2e61024f610120880188610ceb565b61025d9060a0810190610d45565b88604001356040518463ffffffff1660e01b815260040161028093929190610d93565b600060405180830381865afa15801561029d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526102c59190810190610e0e565b905060006102ec306102dd6040890160208a01610d0b565b6001600160a01b0316906106fe565b90506102fc610120870187610ceb565b61030d906040810190602001610d0b565b6001600160a01b0316826040516103249190610ebb565b6000604051808303816000865af19150503d8060008114610361576040519150601f19603f3d011682016040523d82523d6000602084013e610366565b606091505b505080955050600085156103cc5781610389306102dd60408b0160208c01610d0b565b6103939190610ecd565b9050806103cc576040517f6a756fbe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6103f26103dc6020890189610d0b565b6103ec60408a0160208b01610d0b565b336107c2565b949694955050505050565b336001600160a01b031673ccf3d848e08b94478ed8f46ffead3008faf581fd6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610459573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061047d9190610d28565b6001600160a01b0316146104bd576040517fa6c827a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33ff5b336001600160a01b031673ccf3d848e08b94478ed8f46ffead3008faf581fd6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561051c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105409190610d28565b6001600160a01b031614610580576040517f19494c8a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b03841614156105e1576040516001600160a01b0383169082156108fc029083906000818181858888f193505050501580156105db573d6000803e3d6000fd5b50505050565b6105f56001600160a01b0384168383610811565b505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663095ea7b360e01b179052610660848261085a565b6105db576040516001600160a01b0384166024820152600060448201526106f490859063095ea7b360e01b906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152610902565b6105db8482610902565b60006001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee141561073657506001600160a01b038116316107bc565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301528416906370a0823190602401602060405180830381865afa158015610795573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b99190610ef2565b90505b92915050565b6107e373eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee826000196109ef565b506107fa6001600160a01b038416826000196109ef565b506105db6001600160a01b038316826000196109ef565b6040516001600160a01b0383166024820152604481018290526105f59084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401610690565b6000806000846001600160a01b0316846040516108779190610ebb565b6000604051808303816000865af19150503d80600081146108b4576040519150601f19603f3d011682016040523d82523d6000602084013e6108b9565b606091505b50915091508180156108e35750805115806108e35750808060200190518101906108e39190610f0b565b80156108f957506000856001600160a01b03163b115b95945050505050565b6000610957826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316610b229092919063ffffffff16565b90508051600014806109785750808060200190518101906109789190610f0b565b6105f55760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6000600019821415610a0857610a0584306106fe565b91505b6001600160a01b03831615801590610a2957506001600160a01b0383163014155b8015610a3457508115155b15610b1b576001600160a01b03841673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610a7657610a716001600160a01b0385168484610811565b610b1b565b6000836001600160a01b03168360405160006040518083038185875af1925050503d8060008114610ac3576040519150601f19603f3d011682016040523d82523d6000602084013e610ac8565b606091505b5050905080610b195760405162461bcd60e51b815260206004820152600d60248201527f4574682073656e64206661696c0000000000000000000000000000000000000060448201526064016109e6565b505b5092915050565b6060610b318484600085610b39565b949350505050565b6060610b4485610c16565b610b7a576040517f304619b500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080866001600160a01b03168587604051610b969190610ebb565b60006040518083038185875af1925050503d8060008114610bd3576040519150601f19603f3d011682016040523d82523d6000602084013e610bd8565b606091505b50915091508115610bec579150610b319050565b805115610bfc5780518082602001fd5b8360405162461bcd60e51b81526004016109e69190610f2d565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610b31575050151592915050565b600060208284031215610c6157600080fd5b813567ffffffffffffffff811115610c7857600080fd5b82016101408185031215610c8b57600080fd5b9392505050565b6001600160a01b0381168114610ca757600080fd5b50565b600080600060608486031215610cbf57600080fd5b8335610cca81610c92565b92506020840135610cda81610c92565b929592945050506040919091013590565b6000823560be19833603018112610d0157600080fd5b9190910192915050565b600060208284031215610d1d57600080fd5b8135610c8b81610c92565b600060208284031215610d3a57600080fd5b8151610c8b81610c92565b6000808335601e19843603018112610d5c57600080fd5b83018035915067ffffffffffffffff821115610d7757600080fd5b602001915036819003821315610d8c57600080fd5b9250929050565b604081528260408201528284606083013760006060848301015260006060601f19601f8601168301019050826020830152949350505050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015610dfd578181015183820152602001610de5565b838111156105db5750506000910152565b600060208284031215610e2057600080fd5b815167ffffffffffffffff80821115610e3857600080fd5b818401915084601f830112610e4c57600080fd5b815181811115610e5e57610e5e610dcc565b604051601f8201601f19908116603f01168101908382118183101715610e8657610e86610dcc565b81604052828152876020848701011115610e9f57600080fd5b610eb0836020830160208801610de2565b979650505050505050565b60008251610d01818460208701610de2565b600082821015610eed57634e487b7160e01b600052601160045260246000fd5b500390565b600060208284031215610f0457600080fd5b5051919050565b600060208284031215610f1d57600080fd5b81518015158114610c8b57600080fd5b6020815260008251806020840152610f4c816040850160208701610de2565b601f01601f1916919091016040019291505056fea2646970667358221220c80b62d0024a1baa833a40ae35eaddc3f6db6d9c23002ece241d1f6f4cc6a66664736f6c634300080a0033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
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.