Accounts
0x30...3305
0x30...3305

0x30...3305

$500
This contract's source code is verified!
Contract Metadata
Compiler
0.8.20+commit.a1b79de6
Language
Solidity
Contract Source Code
File 1 of 1: CrosschainTokenCashierWithPayloadRouter.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

interface ICashier {
    function depositTo(address _token, address _to, uint256 _amount, bytes memory _payload) external payable;
}

interface IERC20 {
    function balanceOf(address _owner) external view returns(uint256);
}

interface ICrosschainToken {
    function balanceOf(address _account) external returns (uint256);
    function deposit(uint256 _amount) external;
    function coToken() external view returns (address);
}

interface WToken {
    function deposit() external payable;
}

contract CrosschainTokenCashierWithPayloadRouter {

    address public ciotx;
    address public wiotx;

    constructor(ICrosschainToken _ciotx, address _wiotx) {
        if (address(_ciotx) != address(0)) {
            wiotx = _ciotx.coToken();
            require(wiotx == _wiotx, "invalid parameter");
            ciotx = address(_ciotx);
            _approve(ciotx, _wiotx);
        } else {
            wiotx = _wiotx;
        }
    }

    function _approve(address _ctoken, address _coToken) private {
        require(safeApprove(_coToken, _ctoken, type(uint256).max), "failed to approve allowance to crosschain token");
    }

    function approveCrosschainToken(address _crosschainToken) public {
        _approve(_crosschainToken, ICrosschainToken(_crosschainToken).coToken());
    }

    function _depositToCashier(address _token, address _cashier, address _to, uint256 _amount, uint256 _value, bytes memory _payload) private {
        ICrosschainToken ctoken = ICrosschainToken(_token);
        uint256 originBalance = ctoken.balanceOf(address(this));
        ctoken.deposit(_amount);
        uint256 newBalance = ctoken.balanceOf(address(this));
        require(newBalance > originBalance, "invalid balance");
        require(safeApprove(_token, _cashier, newBalance - originBalance), "failed to approve allowance to cashier");
        ICashier(_cashier).depositTo{value: _value}(_token, _to, newBalance - originBalance, _payload);
    }

    function depositCoinTo(address _cashier, address _to, uint256 _amount, bytes memory _payload) public payable {
        require(_amount <= msg.value, "invalid amount");
        WToken(wiotx).deposit{value: _amount}();
        if (ciotx != address(0)) {
            _depositToCashier(ciotx, _cashier, _to, _amount, msg.value - _amount, _payload);
        } else {
            require(safeApprove(wiotx, _cashier, _amount), "failed to approve allowance to cashier");
            ICashier(_cashier).depositTo{value: msg.value - _amount}(wiotx, _to, _amount, _payload);
        }
    }

    function depositTo(address _cashier, address _crosschainToken, address _to, uint256 _amount, bytes memory _payload) public payable {
        require(_crosschainToken != address(0), "invalid token");
        address coToken = ICrosschainToken(_crosschainToken).coToken();
        uint256 originBalance = IERC20(coToken).balanceOf(address(this));
        require(safeTransferFrom(coToken, msg.sender, address(this), _amount), "failed to transfer token");
        uint256 newBalance = IERC20(coToken).balanceOf(address(this));
        require(newBalance > originBalance, "invalid balance");
        _depositToCashier(_crosschainToken, _cashier, _to, newBalance - originBalance, msg.value, _payload);
    }

    function safeTransferFrom(address _token, address _from, address _to, uint256 _amount) internal returns (bool) {
        // selector = bytes4(keccak256(bytes('transferFrom(address,address,uint256)')))
        (bool success, bytes memory data) = _token.call(abi.encodeWithSelector(0x23b872dd, _from, _to, _amount));
        return success && (data.length == 0 || abi.decode(data, (bool)));
    }

    function safeApprove(address _token, address _spender, uint256 _amount) internal returns (bool) {
        // selector = bytes4(keccak256(bytes('approve(address,uint256)')))
        (bool success, bytes memory data) = _token.call(abi.encodeWithSelector(0x095ea7b3, _spender, _amount));
        return success && (data.length == 0 || abi.decode(data, (bool)));
    }
}
Settings
{
  "compilationTarget": {
    "CrosschainTokenCashierWithPayloadRouter.sol": "CrosschainTokenCashierWithPayloadRouter"
  },
  "evmVersion": "shanghai",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "remappings": []
}
ABI
[{"inputs":[{"internalType":"contract ICrosschainToken","name":"_ciotx","type":"address"},{"internalType":"address","name":"_wiotx","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"_crosschainToken","type":"address"}],"name":"approveCrosschainToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ciotx","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_cashier","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_payload","type":"bytes"}],"name":"depositCoinTo","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_cashier","type":"address"},{"internalType":"address","name":"_crosschainToken","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_payload","type":"bytes"}],"name":"depositTo","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"wiotx","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]