Transaction Hash:
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 | ||
---|---|---|---|---|---|
0x057FCA19...72892ecCF | 3,349.734172490127270172 Eth | 3,350.034172490127270172 Eth | 0.3 | ||
0x1aD91ee0...dA6B45836
Miner
| (Hiveon Pool) | 10,981.988738390104104192 Eth | 10,981.991220341063495812 Eth | 0.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( )
deposit[THORChain_Router (ln:68)]
send[THORChain_Router (ln:72)]
transferTo[THORChain_Router (ln:76)]
burn[THORChain_Router (ln:77)]
safeTransferFrom[THORChain_Router (ln:79)]
balanceOf[THORChain_Router (ln:145)]
call[THORChain_Router (ln:146)]
encodeWithSignature[THORChain_Router (ln:146)]
decode[THORChain_Router (ln:147)]
balanceOf[THORChain_Router (ln:148)]
Deposit[THORChain_Router (ln:82)]
// 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 } }