ETH Price: $2,525.86 (-0.32%)

Transaction Decoder

Block:
19387835 at Mar-08-2024 03:41:59 AM +UTC
Transaction Fee:
0.003014606694328584 ETH $7.61
Gas Used:
61,592 Gas / 48.944776827 Gwei

Emitted Events:

108 MinterProxy.LogVaultIn( token=0xEeeeeEee...eeeeeEEeE, orderID=33146, receiver=0xb991175200a225f124c7bb820751411144d03552, amount=101484716473840203 )

Account State Difference:

  Address   Before After State Difference Code
0x026151a3...F17846986
1.380767157978350622 Eth
Nonce: 4482
1.377752551284022038 Eth
Nonce: 4483
0.003014606694328584
0x77F0De65...dfD3f5DA9 44.678312224635735509 Eth44.576827508161895306 Eth0.101484716473840203
(Fee Recipient: 0x9f4...a2A)
757.928567785803283623 Eth757.928567842016639039 Eth0.000000056213355416
0xb9911752...144D03552 0.022411765193374647 Eth0.12389648166721485 Eth0.101484716473840203

Execution Trace

MinterProxy.vaultIn( orderID=33146, tokenAddr=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, toAddr=0xb991175200A225f124C7BB820751411144D03552, amount=101484716473840203 )
  • ETH 0.101484716473840203 0xb991175200a225f124c7bb820751411144d03552.CALL( )
    // SPDX-License-Identifier: UNLICENSED
    pragma solidity ^0.8.9;
    
    abstract contract Context {
        function _msgSender() internal view virtual returns (address) {
            return msg.sender;
        }
    
        function _msgData() internal view virtual returns (bytes calldata) {
            return msg.data;
        }
    }
    
    interface IERC20 {
        event Transfer(address indexed from, address indexed to, uint256 value);
    
        event Approval(
            address indexed owner,
            address indexed spender,
            uint256 value
        );
    
        function totalSupply() external view returns (uint256);
    
        function balanceOf(address account) external view returns (uint256);
    
        function transfer(address to, uint256 amount) external returns (bool);
    
        function allowance(
            address owner,
            address spender
        ) external view returns (uint256);
    
        function approve(address spender, uint256 amount) external returns (bool);
    
        function transferFrom(
            address from,
            address to,
            uint256 amount
        ) external returns (bool);
    }
    
    interface IERC20Permit {
        function permit(
            address owner,
            address spender,
            uint256 value,
            uint256 deadline,
            uint8 v,
            bytes32 r,
            bytes32 s
        ) external;
    
        function nonces(address owner) external view returns (uint256);
    
        function DOMAIN_SEPARATOR() external view returns (bytes32);
    }
    
    library Address {
        function isContract(address account) internal view returns (bool) {
            return account.code.length > 0;
        }
    
        function sendValue(address payable recipient, uint256 amount) internal {
            require(
                address(this).balance >= amount,
                "Address: insufficient balance"
            );
    
            (bool success, ) = recipient.call{value: amount}("");
            require(
                success,
                "Address: unable to send value, recipient may have reverted"
            );
        }
    
        function functionCall(
            address target,
            bytes memory data
        ) internal returns (bytes memory) {
            return
                functionCallWithValue(
                    target,
                    data,
                    0,
                    "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) {
            require(
                address(this).balance >= value,
                "Address: insufficient balance for call"
            );
            (bool success, bytes memory returndata) = target.call{value: value}(
                data
            );
            return
                verifyCallResultFromTarget(
                    target,
                    success,
                    returndata,
                    errorMessage
                );
        }
    
        function functionStaticCall(
            address target,
            bytes memory data
        ) internal view returns (bytes memory) {
            return
                functionStaticCall(
                    target,
                    data,
                    "Address: low-level static call failed"
                );
        }
    
        function functionStaticCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal view returns (bytes memory) {
            (bool success, bytes memory returndata) = target.staticcall(data);
            return
                verifyCallResultFromTarget(
                    target,
                    success,
                    returndata,
                    errorMessage
                );
        }
    
        function functionDelegateCall(
            address target,
            bytes memory data
        ) internal returns (bytes memory) {
            return
                functionDelegateCall(
                    target,
                    data,
                    "Address: low-level delegate call failed"
                );
        }
    
        function functionDelegateCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal returns (bytes memory) {
            (bool success, bytes memory returndata) = target.delegatecall(data);
            return
                verifyCallResultFromTarget(
                    target,
                    success,
                    returndata,
                    errorMessage
                );
        }
    
        function verifyCallResultFromTarget(
            address target,
            bool success,
            bytes memory returndata,
            string memory errorMessage
        ) internal view returns (bytes memory) {
            if (success) {
                if (returndata.length == 0) {
                    // only check isContract if the call was successful and the return data is empty
                    // otherwise we already know that it was a contract
                    require(isContract(target), "Address: call to non-contract");
                }
                return returndata;
            } else {
                _revert(returndata, errorMessage);
            }
        }
    
        function verifyCallResult(
            bool success,
            bytes memory returndata,
            string memory errorMessage
        ) internal pure returns (bytes memory) {
            if (success) {
                return returndata;
            } else {
                _revert(returndata, errorMessage);
            }
        }
    
        function _revert(
            bytes memory returndata,
            string memory errorMessage
        ) private pure {
            // 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
                /// @solidity memory-safe-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
    
    library SafeERC20 {
        using Address for address;
    
        function safeTransfer(IERC20 token, address to, uint256 value) internal {
            _callOptionalReturn(
                token,
                abi.encodeWithSelector(token.transfer.selector, to, value)
            );
        }
    
        function safeTransferFrom(
            IERC20 token,
            address from,
            address to,
            uint256 value
        ) internal {
            _callOptionalReturn(
                token,
                abi.encodeWithSelector(token.transferFrom.selector, from, to, value)
            );
        }
    
        function safeApprove(
            IERC20 token,
            address spender,
            uint256 value
        ) internal {
            require(
                (value == 0) || (token.allowance(address(this), spender) == 0),
                "SafeERC20: approve from non-zero to non-zero allowance"
            );
            _callOptionalReturn(
                token,
                abi.encodeWithSelector(token.approve.selector, spender, value)
            );
        }
    
        function safeIncreaseAllowance(
            IERC20 token,
            address spender,
            uint256 value
        ) internal {
            uint256 oldAllowance = token.allowance(address(this), spender);
            _callOptionalReturn(
                token,
                abi.encodeWithSelector(
                    token.approve.selector,
                    spender,
                    oldAllowance + value
                )
            );
        }
    
        function safeDecreaseAllowance(
            IERC20 token,
            address spender,
            uint256 value
        ) internal {
            unchecked {
                uint256 oldAllowance = token.allowance(address(this), spender);
                require(
                    oldAllowance >= value,
                    "SafeERC20: decreased allowance below zero"
                );
                _callOptionalReturn(
                    token,
                    abi.encodeWithSelector(
                        token.approve.selector,
                        spender,
                        oldAllowance - value
                    )
                );
            }
        }
    
        function forceApprove(
            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);
            }
        }
    
        function safePermit(
            IERC20Permit token,
            address owner,
            address spender,
            uint256 value,
            uint256 deadline,
            uint8 v,
            bytes32 r,
            bytes32 s
        ) internal {
            uint256 nonceBefore = token.nonces(owner);
            token.permit(owner, spender, value, deadline, v, r, s);
            uint256 nonceAfter = token.nonces(owner);
            require(
                nonceAfter == nonceBefore + 1,
                "SafeERC20: permit did not succeed"
            );
        }
    
        function _callOptionalReturn(IERC20 token, bytes memory data) private {
            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"
            );
        }
    
        function _callOptionalReturnBool(
            IERC20 token,
            bytes memory data
        ) private returns (bool) {
            (bool success, bytes memory returndata) = address(token).call(data);
            return
                success &&
                (returndata.length == 0 || abi.decode(returndata, (bool))) &&
                Address.isContract(address(token));
        }
    }
    
    abstract contract Ownable is Context {
        address private _owner;
    
        event OwnershipTransferred(
            address indexed previousOwner,
            address indexed newOwner
        );
    
        constructor() {
            _transferOwnership(_msgSender());
        }
    
        function owner() public view virtual returns (address) {
            return _owner;
        }
    
        modifier onlyOwner() {
            require(owner() == _msgSender(), "Ownable: caller is not the owner");
            _;
        }
    
        function transferOwnership(address newOwner) public virtual onlyOwner {
            require(
                newOwner != address(0),
                "Ownable: new owner is the zero address"
            );
            _transferOwnership(newOwner);
        }
    
        function _transferOwnership(address newOwner) internal virtual {
            address oldOwner = _owner;
            _owner = newOwner;
            emit OwnershipTransferred(oldOwner, newOwner);
        }
    }
    
    abstract contract Controller is Ownable {
        event ControllerAdded(address controller);
        event ControllerRemoved(address controller);
        mapping(address => bool) controllers;
        uint8 public controllerCnt = 0;
    
        modifier onlyController() {
            require(isController(_msgSender()), "no controller rights");
            _;
        }
    
        function isController(address _controller) public view returns (bool) {
            return _controller == owner() || controllers[_controller];
        }
    
        function addController(address _controller) public onlyOwner {
            if (controllers[_controller] == false) {
                controllers[_controller] = true;
                controllerCnt++;
            }
            emit ControllerAdded(_controller);
        }
    
        function removeController(address _controller) public onlyOwner {
            if (controllers[_controller] == true) {
                controllers[_controller] = false;
                controllerCnt--;
            }
            emit ControllerRemoved(_controller);
        }
    }
    
    library TransferHelper {
        function safeTransferNative(address to, uint256 value) internal {
            (bool success, ) = to.call{value: value}(new bytes(0));
            require(success, "TransferHelper: NATIVE_TRANSFER_FAILED");
        }
    }
    
    contract MinterProxy is Controller {
        using SafeERC20 for IERC20;
        using Address for address;
        using Address for address payable;
    
        address public immutable NATIVE;
    
        uint256 MAX_UINT256 =
            0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
    
        mapping(uint256 => bool) public completedOrder;
    
        address public liquidpool;
    
        event LogVaultIn(
            address indexed token,
            uint256 indexed orderID,
            address indexed receiver,
            uint256 amount
        );
        event LogVaultOut(
            address indexed token,
            address indexed from,
            uint256 fromChainID,
            uint256 amount,
            string toChain,
            string toAddr
        );
    
        event LogVaultCall(
            address indexed target,
            uint256 amount,
            bool success,
            bytes reason
        );
    
        constructor(address _NATIVE, address _liquidpool) {
            require(_NATIVE != address(0), "MP: NATIVE is empty");
            require(_liquidpool != address(0), "MP: Liquidpool is empty");
            NATIVE = _NATIVE;
            liquidpool = _liquidpool;
        }
    
        receive() external payable {}
    
        fallback() external payable {}
    
        function chainID() public view returns (uint) {
            return block.chainid;
        }
    
        function setLiquidpool(address _liquidpool) external onlyOwner {
            require(_liquidpool != address(0), "MP: Liquidpool is empty");
            liquidpool = _liquidpool;
        }
    
        function isUUIDCompleted(uint256 uuid) external view returns (bool) {
            return completedOrder[uuid];
        }
    
        function _registerOrder(uint256 uuid) internal {
            require(!completedOrder[uuid], "MP: already completed");
            completedOrder[uuid] = true;
        }
    
        function _balanceOf(address receiveToken) internal view returns (uint256) {
            uint256 _balance;
            if (receiveToken == NATIVE) {
                _balance = address(this).balance;
            } else {
                _balance = IERC20(receiveToken).balanceOf(address(liquidpool));
            }
            return _balance;
        }
    
        function _balanceOfSelf(
            address receiveToken
        ) internal view returns (uint256) {
            uint256 _balance;
            if (receiveToken == NATIVE) {
                _balance = address(this).balance;
            } else {
                _balance = IERC20(receiveToken).balanceOf(address(this));
            }
            return _balance;
        }
    
        function vaultIn(
            uint256 orderID,
            address tokenAddr,
            address toAddr,
            uint256 amount
        ) external onlyController {
            _registerOrder(orderID);
            require(_balanceOf(tokenAddr) >= amount, "MP: insufficient balance");
            if (tokenAddr == NATIVE) {
                TransferHelper.safeTransferNative(toAddr, amount);
            } else {
                IERC20(tokenAddr).safeTransferFrom(liquidpool, toAddr, amount);
            }
            emit LogVaultIn(tokenAddr, orderID, toAddr, amount);
        }
    
        function vaultInAndCall(
            uint256 orderID,
            address tokenAddr,
            address toAddr,
            uint256 amount,
            bool isNative,
            address receiver,
            address receiveToken,
            bytes calldata data
        ) external onlyController {
            require(_balanceOf(tokenAddr) >= amount, "MP: insufficient balance");
            require(
                (receiveToken == NATIVE) == isNative,
                "MP: Native dismatch"
            );
            require(data.length > 0, "MP: data empty");
            _registerOrder(orderID);
            bool fromTokenNative = tokenAddr == NATIVE;
            if (!fromTokenNative) {
                IERC20(tokenAddr).safeTransferFrom(
                    liquidpool,
                    address(this),
                    amount
                );
                if (IERC20(tokenAddr).allowance(address(this), toAddr) < amount) {
                    IERC20(tokenAddr).safeApprove(toAddr, MAX_UINT256);
                }
            }
    
            uint256 amountOut = _callAndTransfer(
                toAddr,
                fromTokenNative ? amount : 0,
                isNative,
                receiver,
                receiveToken,
                data
            );
    
            emit LogVaultIn(receiveToken, orderID, receiver, amountOut);
        }
    
        function call(
            address _target,
            bytes calldata _data
        ) external payable onlyController {
            (bool success, bytes memory result) = _target.call{value: msg.value}(
                _data
            );
            emit LogVaultCall(_target, msg.value, success, result);
        }
    
        function _callAndTransfer(
            address contractAddr,
            uint256 fromNativeAmount,
            bool isNative,
            address receiver,
            address receiveToken,
            bytes calldata data
        ) internal returns (uint256) {
            uint256 old_balance = _balanceOfSelf(receiveToken);
    
            if (fromNativeAmount > 0) {
                // address payable to = payable(contractAddr);
                contractAddr.functionCallWithValue(
                    data,
                    fromNativeAmount,
                    "MP: callAndTransfer failed"
                );
            } else {
                contractAddr.functionCall(data, "MP: callAndTransfer failed");
            }
    
            uint256 new_balance = _balanceOfSelf(receiveToken);
            require(new_balance > old_balance, "MP: receiver should get assets");
            uint256 amountOut = new_balance - old_balance;
    
            if (receiver != address(this)) {
                if (isNative) {
                    TransferHelper.safeTransferNative(receiver, amountOut);
                } else {
                    IERC20(receiveToken).safeTransfer(receiver, amountOut);
                }
            }
            return amountOut;
        }
    
        function withdrawFee(
            address token,
            uint256 amount
        ) external onlyController {
            if (token == NATIVE) {
                uint256 balance = address(this).balance;
                uint256 tmp = balance > amount ? amount : balance;
                TransferHelper.safeTransferNative(owner(), tmp);
            } else {
                uint256 balance = IERC20(token).balanceOf(address(this));
                uint256 tmp = balance > amount ? amount : balance;
                IERC20(token).safeTransfer(owner(), tmp);
            }
        }
    }