Transaction Hash:
Block:
11053807 at Oct-14-2020 12:39:37 PM +UTC
Transaction Fee:
0.00162588 ETH
$4.08
Gas Used:
27,098 Gas / 60 Gwei
Emitted Events:
274 |
0x7a8223ac369a1d9ba637acbc12e5089de4700552.0x4103257eaac983ca79a70d28f90dfc4fa16b619bb0c17ee7cab0d4034c279624( 0x4103257eaac983ca79a70d28f90dfc4fa16b619bb0c17ee7cab0d4034c279624, 000000000000000000000000564286362092d8e7936f0549571a803b203aaced, 000000000000000000000000000000000000000000000000048a846224fcf000 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x56428636...B203aAceD | (Binance 3) |
16,357.459337134428075361 Eth
Nonce: 2954742
|
16,357.130491774428075361 Eth
Nonce: 2954743
| 0.32884536 | |
0x5A0b54D5...D3E029c4c
Miner
| (Spark Pool) | 38.986969338181064364 Eth | 38.988595218181064364 Eth | 0.00162588 | |
0x7a8223ac...De4700552 | 0.2460417 Eth | 0.57326118 Eth | 0.32721948 |
Execution Trace
ETH 0.32721948
0x7a8223ac369a1d9ba637acbc12e5089de4700552.CALL( )
-
ControllerProxy.CALL( )
- ETH 0.32721948
Wallet.DELEGATECALL( )
File 1 of 2: ControllerProxy
File 2 of 2: Wallet
pragma solidity ^0.4.23; contract Ownable { address public owner; modifier onlyOwner() { require(msg.sender == owner); _; } constructor() public { owner = msg.sender; } /** @dev Transfers the ownership of the contract. @param _owner Address of the new owner */ function setOwner(address _owner) public onlyOwner returns (bool) { require(_owner != address(0)); owner = _owner; return true; } } contract HasWorkers is Ownable { mapping(address => uint256) private workerToIndex; address[] private workers; event AddedWorker(address _worker); event RemovedWorker(address _worker); constructor() public { workers.length++; } modifier onlyWorker() { require(isWorker(msg.sender)); _; } modifier workerOrOwner() { require(isWorker(msg.sender) || msg.sender == owner); _; } function isWorker(address _worker) public view returns (bool) { return workerToIndex[_worker] != 0; } function allWorkers() public view returns (address[] memory result) { result = new address[](workers.length - 1); for (uint256 i = 1; i < workers.length; i++) { result[i - 1] = workers[i]; } } function addWorker(address _worker) public onlyOwner returns (bool) { require(!isWorker(_worker)); uint256 index = workers.push(_worker) - 1; workerToIndex[_worker] = index; emit AddedWorker(_worker); return true; } function removeWorker(address _worker) public onlyOwner returns (bool) { require(isWorker(_worker)); uint256 index = workerToIndex[_worker]; address lastWorker = workers[workers.length - 1]; workerToIndex[lastWorker] = index; workers[index] = lastWorker; workers.length--; delete workerToIndex[_worker]; emit RemovedWorker(_worker); return true; } } contract ControllerStorage { address public walletsDelegate; address public controllerDelegate; address public forward; uint256 public createdWallets; mapping(bytes32 => bytes32) public gStorage; } contract DelegateProxy { /** * @dev Performs a delegatecall and returns whatever the delegatecall returned (entire context execution will return!) * @param _dst Destination address to perform the delegatecall * @param _calldata Calldata for the delegatecall */ function delegatedFwd(address _dst, bytes _calldata) internal { assembly { let result := delegatecall(sub(gas, 10000), _dst, add(_calldata, 0x20), mload(_calldata), 0, 0) let size := returndatasize let ptr := mload(0x40) returndatacopy(ptr, 0, size) // revert instead of invalid() bc if the underlying call failed with invalid() it already wasted gas. // if the call returned error data, forward it switch result case 0 { revert(ptr, size) } default { return(ptr, size) } } } } contract DelegateProvider { function getDelegate() public view returns (address delegate); } contract ControllerProxy is ControllerStorage, Ownable, HasWorkers, DelegateProvider, DelegateProxy { function getDelegate() public view returns (address delegate) { delegate = walletsDelegate; } function setWalletsDelegate(address _delegate) public onlyOwner returns (bool) { walletsDelegate = _delegate; return true; } function setControllerDelegate(address _delegate) public onlyOwner returns (bool) { controllerDelegate = _delegate; return true; } function() public payable { if (gasleft() > 2400) { delegatedFwd(controllerDelegate, msg.data); } } }
File 2 of 2: Wallet
pragma solidity ^0.4.23; contract DelegateProvider { function getDelegate() public view returns (address delegate); } contract DelegateProxy { /** * @dev Performs a delegatecall and returns whatever the delegatecall returned (entire context execution will return!) * @param _dst Destination address to perform the delegatecall * @param _calldata Calldata for the delegatecall */ function delegatedFwd(address _dst, bytes _calldata) internal { assembly { let result := delegatecall(sub(gas, 10000), _dst, add(_calldata, 0x20), mload(_calldata), 0, 0) let size := returndatasize let ptr := mload(0x40) returndatacopy(ptr, 0, size) // revert instead of invalid() bc if the underlying call failed with invalid() it already wasted gas. // if the call returned error data, forward it switch result case 0 { revert(ptr, size) } default { return(ptr, size) } } } } contract Token { function transfer(address _to, uint _value) returns (bool success); function transferFrom(address _from, address _to, uint256 _value) returns (bool success); function allowance(address _owner, address _spender) constant returns (uint256 remaining); function approve(address _spender, uint256 _value) returns (bool success); function increaseApproval (address _spender, uint _addedValue) public returns (bool success); function balanceOf(address tokenOwner) public constant returns (uint balance); } contract WalletStorage { address public owner; } contract WalletProxy is WalletStorage, DelegateProxy { event ReceivedETH(address from, uint256 amount); constructor() public { owner = msg.sender; } function() public payable { if (msg.value > 0) { emit ReceivedETH(msg.sender, msg.value); } if (gasleft() > 2400) { delegatedFwd(DelegateProvider(owner).getDelegate(), msg.data); } } } contract Wallet is WalletStorage { function transferERC20Token(Token token, address to, uint256 amount) public returns (bool) { require(msg.sender == owner); return token.transfer(to, amount); } function transferEther(address to, uint256 amount) public returns (bool) { require(msg.sender == owner); return to.call.value(amount)(); } function() public payable {} }