ETH Price: $2,523.03 (-5.25%)

Transaction Decoder

Block:
14543099 at Apr-08-2022 04:43:26 AM +UTC
Transaction Fee:
0.0039541 ETH $9.98
Gas Used:
39,541 Gas / 100 Gwei

Emitted Events:

10 THORChain_Router.Deposit( to=0x057fca19be3750fdfeebe5d72a3944872892eccf, asset=0x00000000...000000000, amount=300000000000000000, memo==:TERRA.UST:terra1h56kjv7su2w84n3glwk4v5twmjftnv32445yvw:96288897111 )

Account State Difference:

  Address   Before After State Difference Code
0x057FCA19...72892ecCF 3,349.734172490127270172 Eth3,350.034172490127270172 Eth0.3
(Hiveon Pool)
10,981.988738390104104192 Eth10,981.991220341063495812 Eth0.00248195095939162
0xC2F6690E...41D819627
0.395711425157424983 Eth
Nonce: 12
0.091757325157424983 Eth
Nonce: 13
0.3039541

Execution Trace

ETH 0.3 THORChain_Router.deposit( vault=0x057FCA19Be3750fDfeEBE5D72A3944872892ecCF, asset=0x0000000000000000000000000000000000000000, amount=300000000000000000, memo==:TERRA.UST:terra1h56kjv7su2w84n3glwk4v5twmjftnv32445yvw:96288897111 )
  • ETH 0.3 0x057fca19be3750fdfeebe5d72a3944872892eccf.CALL( )
    // SPDX-License-Identifier: MIT
    // -------------------
    // Router Version: 3.0
    // -------------------
    pragma solidity 0.8.10;
    
    // ERC20 Interface
    interface iERC20 {
        function balanceOf(address) external view returns (uint256);
        function burn(uint) external;
    }
    // RUNE Interface
    interface iRUNE {
        function transferTo(address, uint) external returns (bool);
    }
    // ROUTER Interface
    interface iROUTER {
        function depositWithExpiry(address, address, uint, string calldata, uint) external;
    }
    
    // THORChain_Router is managed by THORChain Vaults
    contract THORChain_Router {
        address public RUNE;
    
        struct Coin {
            address asset;
            uint amount;
        }
    
        // Vault allowance for each asset
        mapping(address => mapping(address => uint)) private _vaultAllowance;
    
        uint256 private constant _NOT_ENTERED = 1;
        uint256 private constant _ENTERED = 2;
        uint256 private _status;
    
        // Emitted for all deposits, the memo distinguishes for swap, add, remove, donate etc
        event Deposit(address indexed to, address indexed asset, uint amount, string memo);
    
        // Emitted for all outgoing transfers, the vault dictates who sent it, memo used to track.
        event TransferOut(address indexed vault, address indexed to, address asset, uint amount, string memo);
    
        // Changes the spend allowance between vaults
        event TransferAllowance(address indexed oldVault, address indexed newVault, address asset, uint amount, string memo);
    
        // Specifically used to batch send the entire vault assets
        event VaultTransfer(address indexed oldVault, address indexed newVault, Coin[] coins, string memo);
    
        modifier nonReentrant() {
            require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
            _status = _ENTERED;
            _;
            _status = _NOT_ENTERED;
        }
    
        constructor(address rune) {
            RUNE = rune;
            _status = _NOT_ENTERED;
        }
    
        // Deposit with Expiry (preferred)
        function depositWithExpiry(address payable vault, address asset, uint amount, string memory memo, uint expiration) external payable {
            require(block.timestamp < expiration, "THORChain_Router: expired");
            deposit(vault, asset, amount, memo);
        }
    
        // Deposit an asset with a memo. ETH is forwarded, ERC-20 stays in ROUTER
        function deposit(address payable vault, address asset, uint amount, string memory memo) public payable nonReentrant{
            uint safeAmount;
            if(asset == address(0)){
                safeAmount = msg.value;
                bool success = vault.send(safeAmount);
                require(success);
            } else if(asset == RUNE) {
                safeAmount = amount;
                iRUNE(RUNE).transferTo(address(this), amount);
                iERC20(RUNE).burn(amount);
            } else {
                safeAmount = safeTransferFrom(asset, amount); // Transfer asset
                _vaultAllowance[vault][asset] += safeAmount; // Credit to chosen vault
            }
            emit Deposit(vault, asset, safeAmount, memo);
        }
    
        //############################## ALLOWANCE TRANSFERS ##############################
    
        // Use for "moving" assets between vaults (asgard<>ygg), as well "churning" to a new Asgard
        function transferAllowance(address router, address newVault, address asset, uint amount, string memory memo) external nonReentrant {
            if (router == address(this)){
                _adjustAllowances(newVault, asset, amount);
                emit TransferAllowance(msg.sender, newVault, asset, amount, memo);
            } else {
                _routerDeposit(router, newVault, asset, amount, memo);
            }
        }
    
        //############################## ASSET TRANSFERS ##############################
    
        // Any vault calls to transfer any asset to any recipient.
        // Note: Contract recipients of ETH are only given 2300 Gas to complete execution.
        function transferOut(address payable to, address asset, uint amount, string memory memo) public payable nonReentrant {
        uint safeAmount;
        if(asset == address(0)){
            safeAmount = msg.value;
            bool success = to.send(safeAmount); // Send ETH. 
            if (!success) {
                payable(address(msg.sender)).transfer(safeAmount); //For failure, bounce back to Yggdrasil & continue.
            }
        } else {
            _vaultAllowance[msg.sender][asset] -= amount; // Reduce allowance
            (bool success, bytes memory data) = asset.call(abi.encodeWithSignature("transfer(address,uint256)" , to, amount));
            require(success && (data.length == 0 || abi.decode(data, (bool))));
            safeAmount = amount;
        }
        emit TransferOut(msg.sender, to, asset, safeAmount, memo);
    }
    
    
        //############################## VAULT MANAGEMENT ##############################
    
        // A vault can call to "return" all assets to an asgard, including ETH. 
        function returnVaultAssets(address router, address payable asgard, Coin[] memory coins, string memory memo) external payable nonReentrant {
            if (router == address(this)){
                for(uint i = 0; i < coins.length; i++){
                    _adjustAllowances(asgard, coins[i].asset, coins[i].amount);
                }
                emit VaultTransfer(msg.sender, asgard, coins, memo); // Does not include ETH.           
            } else {
                for(uint i = 0; i < coins.length; i++){
                    _routerDeposit(router, asgard, coins[i].asset, coins[i].amount, memo);
                }
            }
            bool success = asgard.send(msg.value);
            require(success);
        }
    
        //############################## HELPERS ##############################
    
        function vaultAllowance(address vault, address token) public view returns(uint amount){
            return _vaultAllowance[vault][token];
        }
    
        // Safe transferFrom in case asset charges transfer fees
        function safeTransferFrom(address _asset, uint _amount) internal returns(uint amount) {
            uint _startBal = iERC20(_asset).balanceOf(address(this));
            (bool success, bytes memory data) = _asset.call(abi.encodeWithSignature("transferFrom(address,address,uint256)", msg.sender, address(this), _amount));
            require(success && (data.length == 0 || abi.decode(data, (bool))));
            return (iERC20(_asset).balanceOf(address(this)) - _startBal);
        }
    
        // Decrements and Increments Allowances between two vaults
        function _adjustAllowances(address _newVault, address _asset, uint _amount) internal {
            _vaultAllowance[msg.sender][_asset] -= _amount;
            _vaultAllowance[_newVault][_asset] += _amount;
        }
    
        // Adjust allowance and forwards funds to new router, credits allowance to desired vault
        function _routerDeposit(address _router, address _vault, address _asset, uint _amount, string memory _memo) internal {
            _vaultAllowance[msg.sender][_asset] -= _amount;
            (bool success,) = _asset.call(abi.encodeWithSignature("approve(address,uint256)", _router, _amount)); // Approve to transfer
            require(success);
            iROUTER(_router).depositWithExpiry(_vault, _asset, _amount, _memo, type(uint).max); // Transfer by depositing
        }
    }