ETH Price: $1,877.73 (-1.73%)

Transaction Decoder

Block:
14583637 at Apr-14-2022 12:48:18 PM +UTC
Transaction Fee:
0.015918571527724242 ETH $29.89
Gas Used:
397,602 Gas / 40.036447321 Gwei

Emitted Events:

219 OwnableDelegateProxy.Upgraded( implementation=AuthenticatedProxy )

Account State Difference:

  Address   Before After State Difference Code
(2Miners: PPLNS)
6,375.903895686798272865 Eth6,375.904492089798272865 Eth0.000596403
0x44EfA9b9...2083F7593
0 Eth
Nonce: 0
0 Eth
Nonce: 1
From: 0 To: 148626156065473025095191743690174335818757003543670648260319081772846327357014395081524796722453681305897049638199502549309557617666502487443176445607057472721919363635424003753082601184265174336044096480995480165730181175206010263154892415354089060188391349956655209425264648404287101541842435852273122691097883492738867349899315721349581174920590380379313091262156102310365772102400812835920691306305909401713332498260248932625674437723694779103205173115693532270526907326627690317240884972599378708615778394820630165861892798011856353090232311142447355985457143981464802617637023619209915425168487959870285675816872202728984943933332283849115413686851842110280274851790440167631149240637767718250336801263430633966698947342707675516741700674453085231944663812996500599991105461376184528483662292742217293994246771560165079438285247655293307318486102017475569531328538810847418387292589678894778221732836230846378940439463994542259444862100217690795453742473837485998574246481685783047289330822126618629446195170001007440127810676223487851663068944418972637648283477393189345485990654595104608003087231107965610449364559356225398587624044222692500663830812443981155512342471985596564233474034578836181618072629990899640813226260719975635549835679380676334694725203504813895378665727944408503256998153052628319622691812910994937597371311680622485385978764960277063998328310668961652945597188216220560937201423218547581816425906048492408656126133615870876129477761425689746139086388350292807552219066577864224927123952094314139538749496387888834544680466230666404964321922834958158188794861858179293588354615476192896754227766569300192532859479718364892829615653660536684049119511397285753477624775427681297799214735760843477975824557996980620799466959964128365781074901975891656684127891067051743311810647311800918077192474098289639792513264488047461888106536667411746931008360082233595918775817810272907131089072644503218551858487905835056504991052144110343868656580189409341264526342595146296125840345726197625694162134777093457486270212130440703212708707117733732314220419371443663382909205704712369192025129177097149669733325164162509368202390489683852217835228885429488185077313645713807364962325084403384550556102643143312588295703617578363318149623380873453266565389600528769681798840815665019389346596797642990422989770011629015035154145856693685470818764813239302722887971157968254258440897051548719659504196347859138503362710134212425078860529445282257463753559581304425396832784947134509243656173764068036870228180466522613628880743109581964658953920835355949579490551682793578448614140726370456898020443969621958523037050591483844840873564963821215726928195949816673543323689
0xa5409ec9...6DCB077c1
0xaB149a9d...5340C8B13
0.499678737697898 Eth
Nonce: 5
0.483760166170173758 Eth
Nonce: 6
0.015918571527724242

Execution Trace

WyvernProxyRegistry.CALL( )
  • OwnableDelegateProxy.60806040( )
    • AuthenticatedProxy.initialize( addrUser=0xaB149a9dAF6205Ce9C72C6580B3d0795340C8B13, addrRegistry=0xa5409ec958C83C3f309868babACA7c86DCB077c1 )
      File 1 of 3: WyvernProxyRegistry
      pragma solidity ^0.4.13;
      
      contract Ownable {
        address public owner;
      
      
        event OwnershipRenounced(address indexed previousOwner);
        event OwnershipTransferred(
          address indexed previousOwner,
          address indexed newOwner
        );
      
      
        /**
         * @dev The Ownable constructor sets the original `owner` of the contract to the sender
         * account.
         */
        constructor() public {
          owner = msg.sender;
        }
      
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
          require(msg.sender == owner);
          _;
        }
      
        /**
         * @dev Allows the current owner to transfer control of the contract to a newOwner.
         * @param newOwner The address to transfer ownership to.
         */
        function transferOwnership(address newOwner) public onlyOwner {
          require(newOwner != address(0));
          emit OwnershipTransferred(owner, newOwner);
          owner = newOwner;
        }
      
        /**
         * @dev Allows the current owner to relinquish control of the contract.
         */
        function renounceOwnership() public onlyOwner {
          emit OwnershipRenounced(owner);
          owner = address(0);
        }
      }
      
      contract ERC20Basic {
        function totalSupply() public view returns (uint256);
        function balanceOf(address who) public view returns (uint256);
        function transfer(address to, uint256 value) public returns (bool);
        event Transfer(address indexed from, address indexed to, uint256 value);
      }
      
      contract ERC20 is ERC20Basic {
        function allowance(address owner, address spender)
          public view returns (uint256);
      
        function transferFrom(address from, address to, uint256 value)
          public returns (bool);
      
        function approve(address spender, uint256 value) public returns (bool);
        event Approval(
          address indexed owner,
          address indexed spender,
          uint256 value
        );
      }
      
      contract TokenRecipient {
          event ReceivedEther(address indexed sender, uint amount);
          event ReceivedTokens(address indexed from, uint256 value, address indexed token, bytes extraData);
      
          /**
           * @dev Receive tokens and generate a log event
           * @param from Address from which to transfer tokens
           * @param value Amount of tokens to transfer
           * @param token Address of token
           * @param extraData Additional data to log
           */
          function receiveApproval(address from, uint256 value, address token, bytes extraData) public {
              ERC20 t = ERC20(token);
              require(t.transferFrom(from, this, value));
              emit ReceivedTokens(from, value, token, extraData);
          }
      
          /**
           * @dev Receive Ether and generate a log event
           */
          function () payable public {
              emit ReceivedEther(msg.sender, msg.value);
          }
      }
      
      contract ProxyRegistry is Ownable {
      
          /* DelegateProxy implementation contract. Must be initialized. */
          address public delegateProxyImplementation;
      
          /* Authenticated proxies by user. */
          mapping(address => OwnableDelegateProxy) public proxies;
      
          /* Contracts pending access. */
          mapping(address => uint) public pending;
      
          /* Contracts allowed to call those proxies. */
          mapping(address => bool) public contracts;
      
          /* Delay period for adding an authenticated contract.
             This mitigates a particular class of potential attack on the Wyvern DAO (which owns this registry) - if at any point the value of assets held by proxy contracts exceeded the value of half the WYV supply (votes in the DAO),
             a malicious but rational attacker could buy half the Wyvern and grant themselves access to all the proxy contracts. A delay period renders this attack nonthreatening - given two weeks, if that happened, users would have
             plenty of time to notice and transfer their assets.
          */
          uint public DELAY_PERIOD = 2 weeks;
      
          /**
           * Start the process to enable access for specified contract. Subject to delay period.
           *
           * @dev ProxyRegistry owner only
           * @param addr Address to which to grant permissions
           */
          function startGrantAuthentication (address addr)
              public
              onlyOwner
          {
              require(!contracts[addr] && pending[addr] == 0);
              pending[addr] = now;
          }
      
          /**
           * End the process to nable access for specified contract after delay period has passed.
           *
           * @dev ProxyRegistry owner only
           * @param addr Address to which to grant permissions
           */
          function endGrantAuthentication (address addr)
              public
              onlyOwner
          {
              require(!contracts[addr] && pending[addr] != 0 && ((pending[addr] + DELAY_PERIOD) < now));
              pending[addr] = 0;
              contracts[addr] = true;
          }
      
          /**
           * Revoke access for specified contract. Can be done instantly.
           *
           * @dev ProxyRegistry owner only
           * @param addr Address of which to revoke permissions
           */    
          function revokeAuthentication (address addr)
              public
              onlyOwner
          {
              contracts[addr] = false;
          }
      
          /**
           * Register a proxy contract with this registry
           *
           * @dev Must be called by the user which the proxy is for, creates a new AuthenticatedProxy
           * @return New AuthenticatedProxy contract
           */
          function registerProxy()
              public
              returns (OwnableDelegateProxy proxy)
          {
              require(proxies[msg.sender] == address(0));
              proxy = new OwnableDelegateProxy(msg.sender, delegateProxyImplementation, abi.encodeWithSignature("initialize(address,address)", msg.sender, address(this)));
              proxies[msg.sender] = proxy;
              return proxy;
          }
      
      }
      
      contract WyvernProxyRegistry is ProxyRegistry {
      
          string public constant name = "Project Wyvern Proxy Registry";
      
          /* Whether the initial auth address has been set. */
          bool public initialAddressSet = false;
      
          constructor ()
              public
          {
              delegateProxyImplementation = new AuthenticatedProxy();
          }
      
          /** 
           * Grant authentication to the initial Exchange protocol contract
           *
           * @dev No delay, can only be called once - after that the standard registry process with a delay must be used
           * @param authAddress Address of the contract to grant authentication
           */
          function grantInitialAuthentication (address authAddress)
              onlyOwner
              public
          {
              require(!initialAddressSet);
              initialAddressSet = true;
              contracts[authAddress] = true;
          }
      
      }
      
      contract OwnedUpgradeabilityStorage {
      
        // Current implementation
        address internal _implementation;
      
        // Owner of the contract
        address private _upgradeabilityOwner;
      
        /**
         * @dev Tells the address of the owner
         * @return the address of the owner
         */
        function upgradeabilityOwner() public view returns (address) {
          return _upgradeabilityOwner;
        }
      
        /**
         * @dev Sets the address of the owner
         */
        function setUpgradeabilityOwner(address newUpgradeabilityOwner) internal {
          _upgradeabilityOwner = newUpgradeabilityOwner;
        }
      
        /**
        * @dev Tells the address of the current implementation
        * @return address of the current implementation
        */
        function implementation() public view returns (address) {
          return _implementation;
        }
      
        /**
        * @dev Tells the proxy type (EIP 897)
        * @return Proxy type, 2 for forwarding proxy
        */
        function proxyType() public pure returns (uint256 proxyTypeId) {
          return 2;
        }
      }
      
      contract AuthenticatedProxy is TokenRecipient, OwnedUpgradeabilityStorage {
      
          /* Whether initialized. */
          bool initialized = false;
      
          /* Address which owns this proxy. */
          address public user;
      
          /* Associated registry with contract authentication information. */
          ProxyRegistry public registry;
      
          /* Whether access has been revoked. */
          bool public revoked;
      
          /* Delegate call could be used to atomically transfer multiple assets owned by the proxy contract with one order. */
          enum HowToCall { Call, DelegateCall }
      
          /* Event fired when the proxy access is revoked or unrevoked. */
          event Revoked(bool revoked);
      
          /**
           * Initialize an AuthenticatedProxy
           *
           * @param addrUser Address of user on whose behalf this proxy will act
           * @param addrRegistry Address of ProxyRegistry contract which will manage this proxy
           */
          function initialize (address addrUser, ProxyRegistry addrRegistry)
              public
          {
              require(!initialized);
              initialized = true;
              user = addrUser;
              registry = addrRegistry;
          }
      
          /**
           * Set the revoked flag (allows a user to revoke ProxyRegistry access)
           *
           * @dev Can be called by the user only
           * @param revoke Whether or not to revoke access
           */
          function setRevoke(bool revoke)
              public
          {
              require(msg.sender == user);
              revoked = revoke;
              emit Revoked(revoke);
          }
      
          /**
           * Execute a message call from the proxy contract
           *
           * @dev Can be called by the user, or by a contract authorized by the registry as long as the user has not revoked access
           * @param dest Address to which the call will be sent
           * @param howToCall Which kind of call to make
           * @param calldata Calldata to send
           * @return Result of the call (success or failure)
           */
          function proxy(address dest, HowToCall howToCall, bytes calldata)
              public
              returns (bool result)
          {
              require(msg.sender == user || (!revoked && registry.contracts(msg.sender)));
              if (howToCall == HowToCall.Call) {
                  result = dest.call(calldata);
              } else if (howToCall == HowToCall.DelegateCall) {
                  result = dest.delegatecall(calldata);
              }
              return result;
          }
      
          /**
           * Execute a message call and assert success
           * 
           * @dev Same functionality as `proxy`, just asserts the return value
           * @param dest Address to which the call will be sent
           * @param howToCall What kind of call to make
           * @param calldata Calldata to send
           */
          function proxyAssert(address dest, HowToCall howToCall, bytes calldata)
              public
          {
              require(proxy(dest, howToCall, calldata));
          }
      
      }
      
      contract Proxy {
      
        /**
        * @dev Tells the address of the implementation where every call will be delegated.
        * @return address of the implementation to which it will be delegated
        */
        function implementation() public view returns (address);
      
        /**
        * @dev Tells the type of proxy (EIP 897)
        * @return Type of proxy, 2 for upgradeable proxy
        */
        function proxyType() public pure returns (uint256 proxyTypeId);
      
        /**
        * @dev Fallback function allowing to perform a delegatecall to the given implementation.
        * This function will return whatever the implementation call returns
        */
        function () payable public {
          address _impl = implementation();
          require(_impl != address(0));
      
          assembly {
            let ptr := mload(0x40)
            calldatacopy(ptr, 0, calldatasize)
            let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0)
            let size := returndatasize
            returndatacopy(ptr, 0, size)
      
            switch result
            case 0 { revert(ptr, size) }
            default { return(ptr, size) }
          }
        }
      }
      
      contract OwnedUpgradeabilityProxy is Proxy, OwnedUpgradeabilityStorage {
        /**
        * @dev Event to show ownership has been transferred
        * @param previousOwner representing the address of the previous owner
        * @param newOwner representing the address of the new owner
        */
        event ProxyOwnershipTransferred(address previousOwner, address newOwner);
      
        /**
        * @dev This event will be emitted every time the implementation gets upgraded
        * @param implementation representing the address of the upgraded implementation
        */
        event Upgraded(address indexed implementation);
      
        /**
        * @dev Upgrades the implementation address
        * @param implementation representing the address of the new implementation to be set
        */
        function _upgradeTo(address implementation) internal {
          require(_implementation != implementation);
          _implementation = implementation;
          emit Upgraded(implementation);
        }
      
        /**
        * @dev Throws if called by any account other than the owner.
        */
        modifier onlyProxyOwner() {
          require(msg.sender == proxyOwner());
          _;
        }
      
        /**
         * @dev Tells the address of the proxy owner
         * @return the address of the proxy owner
         */
        function proxyOwner() public view returns (address) {
          return upgradeabilityOwner();
        }
      
        /**
         * @dev Allows the current owner to transfer control of the contract to a newOwner.
         * @param newOwner The address to transfer ownership to.
         */
        function transferProxyOwnership(address newOwner) public onlyProxyOwner {
          require(newOwner != address(0));
          emit ProxyOwnershipTransferred(proxyOwner(), newOwner);
          setUpgradeabilityOwner(newOwner);
        }
      
        /**
         * @dev Allows the upgradeability owner to upgrade the current implementation of the proxy.
         * @param implementation representing the address of the new implementation to be set.
         */
        function upgradeTo(address implementation) public onlyProxyOwner {
          _upgradeTo(implementation);
        }
      
        /**
         * @dev Allows the upgradeability owner to upgrade the current implementation of the proxy
         * and delegatecall the new implementation for initialization.
         * @param implementation representing the address of the new implementation to be set.
         * @param data represents the msg.data to bet sent in the low level call. This parameter may include the function
         * signature of the implementation to be called with the needed payload
         */
        function upgradeToAndCall(address implementation, bytes data) payable public onlyProxyOwner {
          upgradeTo(implementation);
          require(address(this).delegatecall(data));
        }
      }
      
      contract OwnableDelegateProxy is OwnedUpgradeabilityProxy {
      
          constructor(address owner, address initialImplementation, bytes calldata)
              public
          {
              setUpgradeabilityOwner(owner);
              _upgradeTo(initialImplementation);
              require(initialImplementation.delegatecall(calldata));
          }
      
      }

      File 2 of 3: OwnableDelegateProxy
      contract OwnedUpgradeabilityStorage {
      
        // Current implementation
        address internal _implementation;
      
        // Owner of the contract
        address private _upgradeabilityOwner;
      
        /**
         * @dev Tells the address of the owner
         * @return the address of the owner
         */
        function upgradeabilityOwner() public view returns (address) {
          return _upgradeabilityOwner;
        }
      
        /**
         * @dev Sets the address of the owner
         */
        function setUpgradeabilityOwner(address newUpgradeabilityOwner) internal {
          _upgradeabilityOwner = newUpgradeabilityOwner;
        }
      
        /**
        * @dev Tells the address of the current implementation
        * @return address of the current implementation
        */
        function implementation() public view returns (address) {
          return _implementation;
        }
      
        /**
        * @dev Tells the proxy type (EIP 897)
        * @return Proxy type, 2 for forwarding proxy
        */
        function proxyType() public pure returns (uint256 proxyTypeId) {
          return 2;
        }
      }
      
      
      
      contract Proxy {
      
        /**
        * @dev Tells the address of the implementation where every call will be delegated.
        * @return address of the implementation to which it will be delegated
        */
        function implementation() public view returns (address);
      
        /**
        * @dev Tells the type of proxy (EIP 897)
        * @return Type of proxy, 2 for upgradeable proxy
        */
        function proxyType() public pure returns (uint256 proxyTypeId);
      
        /**
        * @dev Fallback function allowing to perform a delegatecall to the given implementation.
        * This function will return whatever the implementation call returns
        */
        function () payable public {
          address _impl = implementation();
          require(_impl != address(0));
      
          assembly {
            let ptr := mload(0x40)
            calldatacopy(ptr, 0, calldatasize)
            let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0)
            let size := returndatasize
            returndatacopy(ptr, 0, size)
      
            switch result
            case 0 { revert(ptr, size) }
            default { return(ptr, size) }
          }
        }
      }
      
      contract OwnedUpgradeabilityProxy is Proxy, OwnedUpgradeabilityStorage {
        /**
        * @dev Event to show ownership has been transferred
        * @param previousOwner representing the address of the previous owner
        * @param newOwner representing the address of the new owner
        */
        event ProxyOwnershipTransferred(address previousOwner, address newOwner);
      
        /**
        * @dev This event will be emitted every time the implementation gets upgraded
        * @param implementation representing the address of the upgraded implementation
        */
        event Upgraded(address indexed implementation);
      
        /**
        * @dev Upgrades the implementation address
        * @param implementation representing the address of the new implementation to be set
        */
        function _upgradeTo(address implementation) internal {
          require(_implementation != implementation);
          _implementation = implementation;
          emit Upgraded(implementation);
        }
      
        /**
        * @dev Throws if called by any account other than the owner.
        */
        modifier onlyProxyOwner() {
          require(msg.sender == proxyOwner());
          _;
        }
      
        /**
         * @dev Tells the address of the proxy owner
         * @return the address of the proxy owner
         */
        function proxyOwner() public view returns (address) {
          return upgradeabilityOwner();
        }
      
        /**
         * @dev Allows the current owner to transfer control of the contract to a newOwner.
         * @param newOwner The address to transfer ownership to.
         */
        function transferProxyOwnership(address newOwner) public onlyProxyOwner {
          require(newOwner != address(0));
          emit ProxyOwnershipTransferred(proxyOwner(), newOwner);
          setUpgradeabilityOwner(newOwner);
        }
      
        /**
         * @dev Allows the upgradeability owner to upgrade the current implementation of the proxy.
         * @param implementation representing the address of the new implementation to be set.
         */
        function upgradeTo(address implementation) public onlyProxyOwner {
          _upgradeTo(implementation);
        }
      
        /**
         * @dev Allows the upgradeability owner to upgrade the current implementation of the proxy
         * and delegatecall the new implementation for initialization.
         * @param implementation representing the address of the new implementation to be set.
         * @param data represents the msg.data to bet sent in the low level call. This parameter may include the function
         * signature of the implementation to be called with the needed payload
         */
        function upgradeToAndCall(address implementation, bytes data) payable public onlyProxyOwner {
          upgradeTo(implementation);
          require(address(this).delegatecall(data));
        }
      }
      
      
      contract OwnableDelegateProxy is OwnedUpgradeabilityProxy {
      
          constructor(address owner, address initialImplementation, bytes calldata)
              public
          {
              setUpgradeabilityOwner(owner);
              _upgradeTo(initialImplementation);
              require(initialImplementation.delegatecall(calldata));
          }
      
      }

      File 3 of 3: AuthenticatedProxy
      pragma solidity ^0.4.13;
      
      contract Ownable {
        address public owner;
      
      
        event OwnershipRenounced(address indexed previousOwner);
        event OwnershipTransferred(
          address indexed previousOwner,
          address indexed newOwner
        );
      
      
        /**
         * @dev The Ownable constructor sets the original `owner` of the contract to the sender
         * account.
         */
        constructor() public {
          owner = msg.sender;
        }
      
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
          require(msg.sender == owner);
          _;
        }
      
        /**
         * @dev Allows the current owner to transfer control of the contract to a newOwner.
         * @param newOwner The address to transfer ownership to.
         */
        function transferOwnership(address newOwner) public onlyOwner {
          require(newOwner != address(0));
          emit OwnershipTransferred(owner, newOwner);
          owner = newOwner;
        }
      
        /**
         * @dev Allows the current owner to relinquish control of the contract.
         */
        function renounceOwnership() public onlyOwner {
          emit OwnershipRenounced(owner);
          owner = address(0);
        }
      }
      
      contract ERC20Basic {
        function totalSupply() public view returns (uint256);
        function balanceOf(address who) public view returns (uint256);
        function transfer(address to, uint256 value) public returns (bool);
        event Transfer(address indexed from, address indexed to, uint256 value);
      }
      
      contract ERC20 is ERC20Basic {
        function allowance(address owner, address spender)
          public view returns (uint256);
      
        function transferFrom(address from, address to, uint256 value)
          public returns (bool);
      
        function approve(address spender, uint256 value) public returns (bool);
        event Approval(
          address indexed owner,
          address indexed spender,
          uint256 value
        );
      }
      
      contract ProxyRegistry is Ownable {
      
          /* DelegateProxy implementation contract. Must be initialized. */
          address public delegateProxyImplementation;
      
          /* Authenticated proxies by user. */
          mapping(address => OwnableDelegateProxy) public proxies;
      
          /* Contracts pending access. */
          mapping(address => uint) public pending;
      
          /* Contracts allowed to call those proxies. */
          mapping(address => bool) public contracts;
      
          /* Delay period for adding an authenticated contract.
             This mitigates a particular class of potential attack on the Wyvern DAO (which owns this registry) - if at any point the value of assets held by proxy contracts exceeded the value of half the WYV supply (votes in the DAO),
             a malicious but rational attacker could buy half the Wyvern and grant themselves access to all the proxy contracts. A delay period renders this attack nonthreatening - given two weeks, if that happened, users would have
             plenty of time to notice and transfer their assets.
          */
          uint public DELAY_PERIOD = 2 weeks;
      
          /**
           * Start the process to enable access for specified contract. Subject to delay period.
           *
           * @dev ProxyRegistry owner only
           * @param addr Address to which to grant permissions
           */
          function startGrantAuthentication (address addr)
              public
              onlyOwner
          {
              require(!contracts[addr] && pending[addr] == 0);
              pending[addr] = now;
          }
      
          /**
           * End the process to nable access for specified contract after delay period has passed.
           *
           * @dev ProxyRegistry owner only
           * @param addr Address to which to grant permissions
           */
          function endGrantAuthentication (address addr)
              public
              onlyOwner
          {
              require(!contracts[addr] && pending[addr] != 0 && ((pending[addr] + DELAY_PERIOD) < now));
              pending[addr] = 0;
              contracts[addr] = true;
          }
      
          /**
           * Revoke access for specified contract. Can be done instantly.
           *
           * @dev ProxyRegistry owner only
           * @param addr Address of which to revoke permissions
           */    
          function revokeAuthentication (address addr)
              public
              onlyOwner
          {
              contracts[addr] = false;
          }
      
          /**
           * Register a proxy contract with this registry
           *
           * @dev Must be called by the user which the proxy is for, creates a new AuthenticatedProxy
           * @return New AuthenticatedProxy contract
           */
          function registerProxy()
              public
              returns (OwnableDelegateProxy proxy)
          {
              require(proxies[msg.sender] == address(0));
              proxy = new OwnableDelegateProxy(msg.sender, delegateProxyImplementation, abi.encodeWithSignature("initialize(address,address)", msg.sender, address(this)));
              proxies[msg.sender] = proxy;
              return proxy;
          }
      
      }
      
      contract TokenRecipient {
          event ReceivedEther(address indexed sender, uint amount);
          event ReceivedTokens(address indexed from, uint256 value, address indexed token, bytes extraData);
      
          /**
           * @dev Receive tokens and generate a log event
           * @param from Address from which to transfer tokens
           * @param value Amount of tokens to transfer
           * @param token Address of token
           * @param extraData Additional data to log
           */
          function receiveApproval(address from, uint256 value, address token, bytes extraData) public {
              ERC20 t = ERC20(token);
              require(t.transferFrom(from, this, value));
              emit ReceivedTokens(from, value, token, extraData);
          }
      
          /**
           * @dev Receive Ether and generate a log event
           */
          function () payable public {
              emit ReceivedEther(msg.sender, msg.value);
          }
      }
      
      contract OwnedUpgradeabilityStorage {
      
        // Current implementation
        address internal _implementation;
      
        // Owner of the contract
        address private _upgradeabilityOwner;
      
        /**
         * @dev Tells the address of the owner
         * @return the address of the owner
         */
        function upgradeabilityOwner() public view returns (address) {
          return _upgradeabilityOwner;
        }
      
        /**
         * @dev Sets the address of the owner
         */
        function setUpgradeabilityOwner(address newUpgradeabilityOwner) internal {
          _upgradeabilityOwner = newUpgradeabilityOwner;
        }
      
        /**
        * @dev Tells the address of the current implementation
        * @return address of the current implementation
        */
        function implementation() public view returns (address) {
          return _implementation;
        }
      
        /**
        * @dev Tells the proxy type (EIP 897)
        * @return Proxy type, 2 for forwarding proxy
        */
        function proxyType() public pure returns (uint256 proxyTypeId) {
          return 2;
        }
      }
      
      contract AuthenticatedProxy is TokenRecipient, OwnedUpgradeabilityStorage {
      
          /* Whether initialized. */
          bool initialized = false;
      
          /* Address which owns this proxy. */
          address public user;
      
          /* Associated registry with contract authentication information. */
          ProxyRegistry public registry;
      
          /* Whether access has been revoked. */
          bool public revoked;
      
          /* Delegate call could be used to atomically transfer multiple assets owned by the proxy contract with one order. */
          enum HowToCall { Call, DelegateCall }
      
          /* Event fired when the proxy access is revoked or unrevoked. */
          event Revoked(bool revoked);
      
          /**
           * Initialize an AuthenticatedProxy
           *
           * @param addrUser Address of user on whose behalf this proxy will act
           * @param addrRegistry Address of ProxyRegistry contract which will manage this proxy
           */
          function initialize (address addrUser, ProxyRegistry addrRegistry)
              public
          {
              require(!initialized);
              initialized = true;
              user = addrUser;
              registry = addrRegistry;
          }
      
          /**
           * Set the revoked flag (allows a user to revoke ProxyRegistry access)
           *
           * @dev Can be called by the user only
           * @param revoke Whether or not to revoke access
           */
          function setRevoke(bool revoke)
              public
          {
              require(msg.sender == user);
              revoked = revoke;
              emit Revoked(revoke);
          }
      
          /**
           * Execute a message call from the proxy contract
           *
           * @dev Can be called by the user, or by a contract authorized by the registry as long as the user has not revoked access
           * @param dest Address to which the call will be sent
           * @param howToCall Which kind of call to make
           * @param calldata Calldata to send
           * @return Result of the call (success or failure)
           */
          function proxy(address dest, HowToCall howToCall, bytes calldata)
              public
              returns (bool result)
          {
              require(msg.sender == user || (!revoked && registry.contracts(msg.sender)));
              if (howToCall == HowToCall.Call) {
                  result = dest.call(calldata);
              } else if (howToCall == HowToCall.DelegateCall) {
                  result = dest.delegatecall(calldata);
              }
              return result;
          }
      
          /**
           * Execute a message call and assert success
           * 
           * @dev Same functionality as `proxy`, just asserts the return value
           * @param dest Address to which the call will be sent
           * @param howToCall What kind of call to make
           * @param calldata Calldata to send
           */
          function proxyAssert(address dest, HowToCall howToCall, bytes calldata)
              public
          {
              require(proxy(dest, howToCall, calldata));
          }
      
      }
      
      contract Proxy {
      
        /**
        * @dev Tells the address of the implementation where every call will be delegated.
        * @return address of the implementation to which it will be delegated
        */
        function implementation() public view returns (address);
      
        /**
        * @dev Tells the type of proxy (EIP 897)
        * @return Type of proxy, 2 for upgradeable proxy
        */
        function proxyType() public pure returns (uint256 proxyTypeId);
      
        /**
        * @dev Fallback function allowing to perform a delegatecall to the given implementation.
        * This function will return whatever the implementation call returns
        */
        function () payable public {
          address _impl = implementation();
          require(_impl != address(0));
      
          assembly {
            let ptr := mload(0x40)
            calldatacopy(ptr, 0, calldatasize)
            let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0)
            let size := returndatasize
            returndatacopy(ptr, 0, size)
      
            switch result
            case 0 { revert(ptr, size) }
            default { return(ptr, size) }
          }
        }
      }
      
      contract OwnedUpgradeabilityProxy is Proxy, OwnedUpgradeabilityStorage {
        /**
        * @dev Event to show ownership has been transferred
        * @param previousOwner representing the address of the previous owner
        * @param newOwner representing the address of the new owner
        */
        event ProxyOwnershipTransferred(address previousOwner, address newOwner);
      
        /**
        * @dev This event will be emitted every time the implementation gets upgraded
        * @param implementation representing the address of the upgraded implementation
        */
        event Upgraded(address indexed implementation);
      
        /**
        * @dev Upgrades the implementation address
        * @param implementation representing the address of the new implementation to be set
        */
        function _upgradeTo(address implementation) internal {
          require(_implementation != implementation);
          _implementation = implementation;
          emit Upgraded(implementation);
        }
      
        /**
        * @dev Throws if called by any account other than the owner.
        */
        modifier onlyProxyOwner() {
          require(msg.sender == proxyOwner());
          _;
        }
      
        /**
         * @dev Tells the address of the proxy owner
         * @return the address of the proxy owner
         */
        function proxyOwner() public view returns (address) {
          return upgradeabilityOwner();
        }
      
        /**
         * @dev Allows the current owner to transfer control of the contract to a newOwner.
         * @param newOwner The address to transfer ownership to.
         */
        function transferProxyOwnership(address newOwner) public onlyProxyOwner {
          require(newOwner != address(0));
          emit ProxyOwnershipTransferred(proxyOwner(), newOwner);
          setUpgradeabilityOwner(newOwner);
        }
      
        /**
         * @dev Allows the upgradeability owner to upgrade the current implementation of the proxy.
         * @param implementation representing the address of the new implementation to be set.
         */
        function upgradeTo(address implementation) public onlyProxyOwner {
          _upgradeTo(implementation);
        }
      
        /**
         * @dev Allows the upgradeability owner to upgrade the current implementation of the proxy
         * and delegatecall the new implementation for initialization.
         * @param implementation representing the address of the new implementation to be set.
         * @param data represents the msg.data to bet sent in the low level call. This parameter may include the function
         * signature of the implementation to be called with the needed payload
         */
        function upgradeToAndCall(address implementation, bytes data) payable public onlyProxyOwner {
          upgradeTo(implementation);
          require(address(this).delegatecall(data));
        }
      }
      
      contract OwnableDelegateProxy is OwnedUpgradeabilityProxy {
      
          constructor(address owner, address initialImplementation, bytes calldata)
              public
          {
              setUpgradeabilityOwner(owner);
              _upgradeTo(initialImplementation);
              require(initialImplementation.delegatecall(calldata));
          }
      
      }