Transaction Hash:
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 | ||
---|---|---|---|---|---|
0x026151a3...F17846986 |
1.380767157978350622 Eth
Nonce: 4482
|
1.377752551284022038 Eth
Nonce: 4483
| 0.003014606694328584 | ||
0x77F0De65...dfD3f5DA9 | 44.678312224635735509 Eth | 44.576827508161895306 Eth | 0.101484716473840203 | ||
0x9f4Cf329...9dd102a2A
Miner
| (Fee Recipient: 0x9f4...a2A) | 757.928567785803283623 Eth | 757.928567842016639039 Eth | 0.000000056213355416 | |
0xb9911752...144D03552 | 0.022411765193374647 Eth | 0.12389648166721485 Eth | 0.101484716473840203 |
Execution Trace
MinterProxy.vaultIn( orderID=33146, tokenAddr=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, toAddr=0xb991175200A225f124C7BB820751411144D03552, amount=101484716473840203 )
- ETH 0.101484716473840203
0xb991175200a225f124c7bb820751411144d03552.CALL( )
vaultIn[MinterProxy (ln:535)]
_registerOrder[MinterProxy (ln:541)]
_balanceOf[MinterProxy (ln:542)]
balanceOf[MinterProxy (ln:518)]
safeTransferNative[MinterProxy (ln:544)]
safeTransferFrom[MinterProxy (ln:546)]
LogVaultIn[MinterProxy (ln:548)]
// 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); } } }