ETH Price: $2,406.74 (+7.07%)

Transaction Decoder

Block:
14193992 at Feb-12-2022 10:31:03 PM +UTC
Transaction Fee:
0.004067295314528576 ETH $9.79
Gas Used:
63,752 Gas / 63.798709288 Gwei

Emitted Events:

76 MiniMeToken.Approval( _owner=[Sender] 0x7591325515c7650b963eaa11a3da7ba7ce6c1d14, _spender=0xa3A7B6F8...E78d60EeC, _amount=115792089237316195423570985008687907853269984665640564039457584007913129639935 )

Account State Difference:

  Address   Before After State Difference Code
(Poolin 3)
3,268.533406318926547385 Eth3,268.533501946926547385 Eth0.000095628
0x3472A5A7...852C6E53d
0x75913255...7CE6C1D14
0.041092364210192219 Eth
Nonce: 4
0.037025068895663643 Eth
Nonce: 5
0.004067295314528576

Execution Trace

MiniMeToken.approve( _spender=0xa3A7B6F88361F48403514059F1F16C8E78d60EeC, _amount=115792089237316195423570985008687907853269984665640564039457584007913129639935 ) => ( success=True )
  • AdminUpgradeabilityProxy.da682aeb( )
    • GatedMiniMeController.onApprove( 0x7591325515C7650B963EaA11a3DA7ba7CE6C1D14, 0xa3A7B6F88361F48403514059F1F16C8E78d60EeC, 115792089237316195423570985008687907853269984665640564039457584007913129639935 ) => ( True )
      File 1 of 3: MiniMeToken
      pragma solidity ^0.4.24;
      // File: @aragon/apps-shared-minime/contracts/ITokenController.sol
      /// @dev The token controller contract must implement these functions
      
      
      interface ITokenController {
          /// @notice Called when `_owner` sends ether to the MiniMe Token contract
          /// @param _owner The address that sent the ether to create tokens
          /// @return True if the ether is accepted, false if it throws
          function proxyPayment(address _owner) external payable returns(bool);
      
          /// @notice Notifies the controller about a token transfer allowing the
          ///  controller to react if desired
          /// @param _from The origin of the transfer
          /// @param _to The destination of the transfer
          /// @param _amount The amount of the transfer
          /// @return False if the controller does not authorize the transfer
          function onTransfer(address _from, address _to, uint _amount) external returns(bool);
      
          /// @notice Notifies the controller about an approval allowing the
          ///  controller to react if desired
          /// @param _owner The address that calls `approve()`
          /// @param _spender The spender in the `approve()` call
          /// @param _amount The amount in the `approve()` call
          /// @return False if the controller does not authorize the approval
          function onApprove(address _owner, address _spender, uint _amount) external returns(bool);
      }
      // File: @aragon/apps-shared-minime/contracts/MiniMeToken.sol
      /*
          Copyright 2016, Jordi Baylina
          This program is free software: you can redistribute it and/or modify
          it under the terms of the GNU General Public License as published by
          the Free Software Foundation, either version 3 of the License, or
          (at your option) any later version.
          This program is distributed in the hope that it will be useful,
          but WITHOUT ANY WARRANTY; without even the implied warranty of
          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
          GNU General Public License for more details.
          You should have received a copy of the GNU General Public License
          along with this program.  If not, see <http://www.gnu.org/licenses/>.
       */
      
      /// @title MiniMeToken Contract
      /// @author Jordi Baylina
      /// @dev This token contract's goal is to make it easy for anyone to clone this
      ///  token using the token distribution at a given block, this will allow DAO's
      ///  and DApps to upgrade their features in a decentralized manner without
      ///  affecting the original token
      /// @dev It is ERC20 compliant, but still needs to under go further testing.
      
      
      contract Controlled {
          /// @notice The address of the controller is the only address that can call
          ///  a function with this modifier
          modifier onlyController {
              require(msg.sender == controller);
              _;
          }
      
          address public controller;
      
          function Controlled()  public { controller = msg.sender;}
      
          /// @notice Changes the controller of the contract
          /// @param _newController The new controller of the contract
          function changeController(address _newController) onlyController  public {
              controller = _newController;
          }
      }
      
      contract ApproveAndCallFallBack {
          function receiveApproval(
              address from,
              uint256 _amount,
              address _token,
              bytes _data
          ) public;
      }
      
      /// @dev The actual token contract, the default controller is the msg.sender
      ///  that deploys the contract, so usually this token will be deployed by a
      ///  token controller contract, which Giveth will call a "Campaign"
      contract MiniMeToken is Controlled {
      
          string public name;                //The Token's name: e.g. DigixDAO Tokens
          uint8 public decimals;             //Number of decimals of the smallest unit
          string public symbol;              //An identifier: e.g. REP
          string public version = "MMT_0.1"; //An arbitrary versioning scheme
      
      
          /// @dev `Checkpoint` is the structure that attaches a block number to a
          ///  given value, the block number attached is the one that last changed the
          ///  value
          struct Checkpoint {
      
              // `fromBlock` is the block number that the value was generated from
              uint128 fromBlock;
      
              // `value` is the amount of tokens at a specific block number
              uint128 value;
          }
      
          // `parentToken` is the Token address that was cloned to produce this token;
          //  it will be 0x0 for a token that was not cloned
          MiniMeToken public parentToken;
      
          // `parentSnapShotBlock` is the block number from the Parent Token that was
          //  used to determine the initial distribution of the Clone Token
          uint public parentSnapShotBlock;
      
          // `creationBlock` is the block number that the Clone Token was created
          uint public creationBlock;
      
          // `balances` is the map that tracks the balance of each address, in this
          //  contract when the balance changes the block number that the change
          //  occurred is also included in the map
          mapping (address => Checkpoint[]) balances;
      
          // `allowed` tracks any extra transfer rights as in all ERC20 tokens
          mapping (address => mapping (address => uint256)) allowed;
      
          // Tracks the history of the `totalSupply` of the token
          Checkpoint[] totalSupplyHistory;
      
          // Flag that determines if the token is transferable or not.
          bool public transfersEnabled;
      
          // The factory used to create new clone tokens
          MiniMeTokenFactory public tokenFactory;
      
      ////////////////
      // Constructor
      ////////////////
      
          /// @notice Constructor to create a MiniMeToken
          /// @param _tokenFactory The address of the MiniMeTokenFactory contract that
          ///  will create the Clone token contracts, the token factory needs to be
          ///  deployed first
          /// @param _parentToken Address of the parent token, set to 0x0 if it is a
          ///  new token
          /// @param _parentSnapShotBlock Block of the parent token that will
          ///  determine the initial distribution of the clone token, set to 0 if it
          ///  is a new token
          /// @param _tokenName Name of the new token
          /// @param _decimalUnits Number of decimals of the new token
          /// @param _tokenSymbol Token Symbol for the new token
          /// @param _transfersEnabled If true, tokens will be able to be transferred
          function MiniMeToken(
              MiniMeTokenFactory _tokenFactory,
              MiniMeToken _parentToken,
              uint _parentSnapShotBlock,
              string _tokenName,
              uint8 _decimalUnits,
              string _tokenSymbol,
              bool _transfersEnabled
          )  public
          {
              tokenFactory = _tokenFactory;
              name = _tokenName;                                 // Set the name
              decimals = _decimalUnits;                          // Set the decimals
              symbol = _tokenSymbol;                             // Set the symbol
              parentToken = _parentToken;
              parentSnapShotBlock = _parentSnapShotBlock;
              transfersEnabled = _transfersEnabled;
              creationBlock = block.number;
          }
      
      
      ///////////////////
      // ERC20 Methods
      ///////////////////
      
          /// @notice Send `_amount` tokens to `_to` from `msg.sender`
          /// @param _to The address of the recipient
          /// @param _amount The amount of tokens to be transferred
          /// @return Whether the transfer was successful or not
          function transfer(address _to, uint256 _amount) public returns (bool success) {
              require(transfersEnabled);
              return doTransfer(msg.sender, _to, _amount);
          }
      
          /// @notice Send `_amount` tokens to `_to` from `_from` on the condition it
          ///  is approved by `_from`
          /// @param _from The address holding the tokens being transferred
          /// @param _to The address of the recipient
          /// @param _amount The amount of tokens to be transferred
          /// @return True if the transfer was successful
          function transferFrom(address _from, address _to, uint256 _amount) public returns (bool success) {
      
              // The controller of this contract can move tokens around at will,
              //  this is important to recognize! Confirm that you trust the
              //  controller of this contract, which in most situations should be
              //  another open source smart contract or 0x0
              if (msg.sender != controller) {
                  require(transfersEnabled);
      
                  // The standard ERC 20 transferFrom functionality
                  if (allowed[_from][msg.sender] < _amount)
                      return false;
                  allowed[_from][msg.sender] -= _amount;
              }
              return doTransfer(_from, _to, _amount);
          }
      
          /// @dev This is the actual transfer function in the token contract, it can
          ///  only be called by other functions in this contract.
          /// @param _from The address holding the tokens being transferred
          /// @param _to The address of the recipient
          /// @param _amount The amount of tokens to be transferred
          /// @return True if the transfer was successful
          function doTransfer(address _from, address _to, uint _amount) internal returns(bool) {
              if (_amount == 0) {
                  return true;
              }
              require(parentSnapShotBlock < block.number);
              // Do not allow transfer to 0x0 or the token contract itself
              require((_to != 0) && (_to != address(this)));
              // If the amount being transfered is more than the balance of the
              //  account the transfer returns false
              var previousBalanceFrom = balanceOfAt(_from, block.number);
              if (previousBalanceFrom < _amount) {
                  return false;
              }
              // Alerts the token controller of the transfer
              if (isContract(controller)) {
                  // Adding the ` == true` makes the linter shut up so...
                  require(ITokenController(controller).onTransfer(_from, _to, _amount) == true);
              }
              // First update the balance array with the new value for the address
              //  sending the tokens
              updateValueAtNow(balances[_from], previousBalanceFrom - _amount);
              // Then update the balance array with the new value for the address
              //  receiving the tokens
              var previousBalanceTo = balanceOfAt(_to, block.number);
              require(previousBalanceTo + _amount >= previousBalanceTo); // Check for overflow
              updateValueAtNow(balances[_to], previousBalanceTo + _amount);
              // An event to make the transfer easy to find on the blockchain
              Transfer(_from, _to, _amount);
              return true;
          }
      
          /// @param _owner The address that's balance is being requested
          /// @return The balance of `_owner` at the current block
          function balanceOf(address _owner) public constant returns (uint256 balance) {
              return balanceOfAt(_owner, block.number);
          }
      
          /// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on
          ///  its behalf. This is a modified version of the ERC20 approve function
          ///  to be a little bit safer
          /// @param _spender The address of the account able to transfer the tokens
          /// @param _amount The amount of tokens to be approved for transfer
          /// @return True if the approval was successful
          function approve(address _spender, uint256 _amount) public returns (bool success) {
              require(transfersEnabled);
      
              // To change the approve amount you first have to reduce the addresses`
              //  allowance to zero by calling `approve(_spender,0)` if it is not
              //  already 0 to mitigate the race condition described here:
              //  https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
              require((_amount == 0) || (allowed[msg.sender][_spender] == 0));
      
              // Alerts the token controller of the approve function call
              if (isContract(controller)) {
                  // Adding the ` == true` makes the linter shut up so...
                  require(ITokenController(controller).onApprove(msg.sender, _spender, _amount) == true);
              }
      
              allowed[msg.sender][_spender] = _amount;
              Approval(msg.sender, _spender, _amount);
              return true;
          }
      
          /// @dev This function makes it easy to read the `allowed[]` map
          /// @param _owner The address of the account that owns the token
          /// @param _spender The address of the account able to transfer the tokens
          /// @return Amount of remaining tokens of _owner that _spender is allowed
          ///  to spend
          function allowance(address _owner, address _spender) public constant returns (uint256 remaining) {
              return allowed[_owner][_spender];
          }
      
          /// @notice `msg.sender` approves `_spender` to send `_amount` tokens on
          ///  its behalf, and then a function is triggered in the contract that is
          ///  being approved, `_spender`. This allows users to use their tokens to
          ///  interact with contracts in one function call instead of two
          /// @param _spender The address of the contract able to transfer the tokens
          /// @param _amount The amount of tokens to be approved for transfer
          /// @return True if the function call was successful
          function approveAndCall(ApproveAndCallFallBack _spender, uint256 _amount, bytes _extraData) public returns (bool success) {
              require(approve(_spender, _amount));
      
              _spender.receiveApproval(
                  msg.sender,
                  _amount,
                  this,
                  _extraData
              );
      
              return true;
          }
      
          /// @dev This function makes it easy to get the total number of tokens
          /// @return The total number of tokens
          function totalSupply() public constant returns (uint) {
              return totalSupplyAt(block.number);
          }
      
      
      ////////////////
      // Query balance and totalSupply in History
      ////////////////
      
          /// @dev Queries the balance of `_owner` at a specific `_blockNumber`
          /// @param _owner The address from which the balance will be retrieved
          /// @param _blockNumber The block number when the balance is queried
          /// @return The balance at `_blockNumber`
          function balanceOfAt(address _owner, uint _blockNumber) public constant returns (uint) {
      
              // These next few lines are used when the balance of the token is
              //  requested before a check point was ever created for this token, it
              //  requires that the `parentToken.balanceOfAt` be queried at the
              //  genesis block for that token as this contains initial balance of
              //  this token
              if ((balances[_owner].length == 0) || (balances[_owner][0].fromBlock > _blockNumber)) {
                  if (address(parentToken) != 0) {
                      return parentToken.balanceOfAt(_owner, min(_blockNumber, parentSnapShotBlock));
                  } else {
                      // Has no parent
                      return 0;
                  }
      
              // This will return the expected balance during normal situations
              } else {
                  return getValueAt(balances[_owner], _blockNumber);
              }
          }
      
          /// @notice Total amount of tokens at a specific `_blockNumber`.
          /// @param _blockNumber The block number when the totalSupply is queried
          /// @return The total amount of tokens at `_blockNumber`
          function totalSupplyAt(uint _blockNumber) public constant returns(uint) {
      
              // These next few lines are used when the totalSupply of the token is
              //  requested before a check point was ever created for this token, it
              //  requires that the `parentToken.totalSupplyAt` be queried at the
              //  genesis block for this token as that contains totalSupply of this
              //  token at this block number.
              if ((totalSupplyHistory.length == 0) || (totalSupplyHistory[0].fromBlock > _blockNumber)) {
                  if (address(parentToken) != 0) {
                      return parentToken.totalSupplyAt(min(_blockNumber, parentSnapShotBlock));
                  } else {
                      return 0;
                  }
      
              // This will return the expected totalSupply during normal situations
              } else {
                  return getValueAt(totalSupplyHistory, _blockNumber);
              }
          }
      
      ////////////////
      // Clone Token Method
      ////////////////
      
          /// @notice Creates a new clone token with the initial distribution being
          ///  this token at `_snapshotBlock`
          /// @param _cloneTokenName Name of the clone token
          /// @param _cloneDecimalUnits Number of decimals of the smallest unit
          /// @param _cloneTokenSymbol Symbol of the clone token
          /// @param _snapshotBlock Block when the distribution of the parent token is
          ///  copied to set the initial distribution of the new clone token;
          ///  if the block is zero than the actual block, the current block is used
          /// @param _transfersEnabled True if transfers are allowed in the clone
          /// @return The address of the new MiniMeToken Contract
          function createCloneToken(
              string _cloneTokenName,
              uint8 _cloneDecimalUnits,
              string _cloneTokenSymbol,
              uint _snapshotBlock,
              bool _transfersEnabled
          ) public returns(MiniMeToken)
          {
              uint256 snapshot = _snapshotBlock == 0 ? block.number - 1 : _snapshotBlock;
      
              MiniMeToken cloneToken = tokenFactory.createCloneToken(
                  this,
                  snapshot,
                  _cloneTokenName,
                  _cloneDecimalUnits,
                  _cloneTokenSymbol,
                  _transfersEnabled
              );
      
              cloneToken.changeController(msg.sender);
      
              // An event to make the token easy to find on the blockchain
              NewCloneToken(address(cloneToken), snapshot);
              return cloneToken;
          }
      
      ////////////////
      // Generate and destroy tokens
      ////////////////
      
          /// @notice Generates `_amount` tokens that are assigned to `_owner`
          /// @param _owner The address that will be assigned the new tokens
          /// @param _amount The quantity of tokens generated
          /// @return True if the tokens are generated correctly
          function generateTokens(address _owner, uint _amount) onlyController public returns (bool) {
              uint curTotalSupply = totalSupply();
              require(curTotalSupply + _amount >= curTotalSupply); // Check for overflow
              uint previousBalanceTo = balanceOf(_owner);
              require(previousBalanceTo + _amount >= previousBalanceTo); // Check for overflow
              updateValueAtNow(totalSupplyHistory, curTotalSupply + _amount);
              updateValueAtNow(balances[_owner], previousBalanceTo + _amount);
              Transfer(0, _owner, _amount);
              return true;
          }
      
      
          /// @notice Burns `_amount` tokens from `_owner`
          /// @param _owner The address that will lose the tokens
          /// @param _amount The quantity of tokens to burn
          /// @return True if the tokens are burned correctly
          function destroyTokens(address _owner, uint _amount) onlyController public returns (bool) {
              uint curTotalSupply = totalSupply();
              require(curTotalSupply >= _amount);
              uint previousBalanceFrom = balanceOf(_owner);
              require(previousBalanceFrom >= _amount);
              updateValueAtNow(totalSupplyHistory, curTotalSupply - _amount);
              updateValueAtNow(balances[_owner], previousBalanceFrom - _amount);
              Transfer(_owner, 0, _amount);
              return true;
          }
      
      ////////////////
      // Enable tokens transfers
      ////////////////
      
      
          /// @notice Enables token holders to transfer their tokens freely if true
          /// @param _transfersEnabled True if transfers are allowed in the clone
          function enableTransfers(bool _transfersEnabled) onlyController public {
              transfersEnabled = _transfersEnabled;
          }
      
      ////////////////
      // Internal helper functions to query and set a value in a snapshot array
      ////////////////
      
          /// @dev `getValueAt` retrieves the number of tokens at a given block number
          /// @param checkpoints The history of values being queried
          /// @param _block The block number to retrieve the value at
          /// @return The number of tokens being queried
          function getValueAt(Checkpoint[] storage checkpoints, uint _block) constant internal returns (uint) {
              if (checkpoints.length == 0)
                  return 0;
      
              // Shortcut for the actual value
              if (_block >= checkpoints[checkpoints.length-1].fromBlock)
                  return checkpoints[checkpoints.length-1].value;
              if (_block < checkpoints[0].fromBlock)
                  return 0;
      
              // Binary search of the value in the array
              uint min = 0;
              uint max = checkpoints.length-1;
              while (max > min) {
                  uint mid = (max + min + 1) / 2;
                  if (checkpoints[mid].fromBlock<=_block) {
                      min = mid;
                  } else {
                      max = mid-1;
                  }
              }
              return checkpoints[min].value;
          }
      
          /// @dev `updateValueAtNow` used to update the `balances` map and the
          ///  `totalSupplyHistory`
          /// @param checkpoints The history of data being updated
          /// @param _value The new number of tokens
          function updateValueAtNow(Checkpoint[] storage checkpoints, uint _value) internal {
              if ((checkpoints.length == 0) || (checkpoints[checkpoints.length - 1].fromBlock < block.number)) {
                  Checkpoint storage newCheckPoint = checkpoints[checkpoints.length++];
                  newCheckPoint.fromBlock = uint128(block.number);
                  newCheckPoint.value = uint128(_value);
              } else {
                  Checkpoint storage oldCheckPoint = checkpoints[checkpoints.length - 1];
                  oldCheckPoint.value = uint128(_value);
              }
          }
      
          /// @dev Internal function to determine if an address is a contract
          /// @param _addr The address being queried
          /// @return True if `_addr` is a contract
          function isContract(address _addr) constant internal returns(bool) {
              uint size;
              if (_addr == 0)
                  return false;
      
              assembly {
                  size := extcodesize(_addr)
              }
      
              return size>0;
          }
      
          /// @dev Helper function to return a min betwen the two uints
          function min(uint a, uint b) pure internal returns (uint) {
              return a < b ? a : b;
          }
      
          /// @notice The fallback function: If the contract's controller has not been
          ///  set to 0, then the `proxyPayment` method is called which relays the
          ///  ether and creates tokens as described in the token controller contract
          function () external payable {
              require(isContract(controller));
              // Adding the ` == true` makes the linter shut up so...
              require(ITokenController(controller).proxyPayment.value(msg.value)(msg.sender) == true);
          }
      
      //////////
      // Safety Methods
      //////////
      
          /// @notice This method can be used by the controller to extract mistakenly
          ///  sent tokens to this contract.
          /// @param _token The address of the token contract that you want to recover
          ///  set to 0 in case you want to extract ether.
          function claimTokens(address _token) onlyController public {
              if (_token == 0x0) {
                  controller.transfer(this.balance);
                  return;
              }
      
              MiniMeToken token = MiniMeToken(_token);
              uint balance = token.balanceOf(this);
              token.transfer(controller, balance);
              ClaimedTokens(_token, controller, balance);
          }
      
      ////////////////
      // Events
      ////////////////
          event ClaimedTokens(address indexed _token, address indexed _controller, uint _amount);
          event Transfer(address indexed _from, address indexed _to, uint256 _amount);
          event NewCloneToken(address indexed _cloneToken, uint _snapshotBlock);
          event Approval(
              address indexed _owner,
              address indexed _spender,
              uint256 _amount
              );
      
      }
      
      
      ////////////////
      // MiniMeTokenFactory
      ////////////////
      
      /// @dev This contract is used to generate clone contracts from a contract.
      ///  In solidity this is the way to create a contract from a contract of the
      ///  same class
      contract MiniMeTokenFactory {
      
          /// @notice Update the DApp by creating a new token with new functionalities
          ///  the msg.sender becomes the controller of this clone token
          /// @param _parentToken Address of the token being cloned
          /// @param _snapshotBlock Block of the parent token that will
          ///  determine the initial distribution of the clone token
          /// @param _tokenName Name of the new token
          /// @param _decimalUnits Number of decimals of the new token
          /// @param _tokenSymbol Token Symbol for the new token
          /// @param _transfersEnabled If true, tokens will be able to be transferred
          /// @return The address of the new token contract
          function createCloneToken(
              MiniMeToken _parentToken,
              uint _snapshotBlock,
              string _tokenName,
              uint8 _decimalUnits,
              string _tokenSymbol,
              bool _transfersEnabled
          ) public returns (MiniMeToken)
          {
              MiniMeToken newToken = new MiniMeToken(
                  this,
                  _parentToken,
                  _snapshotBlock,
                  _tokenName,
                  _decimalUnits,
                  _tokenSymbol,
                  _transfersEnabled
              );
      
              newToken.changeController(msg.sender);
              return newToken;
          }
      }

      File 2 of 3: AdminUpgradeabilityProxy
      /**
       *Submitted for verification at Etherscan.io on 2020-10-09
      */
      
      // SPDX-License-Identifier: MIT
      
      pragma solidity ^0.6.2;
      
      /**
       * @dev Collection of functions related to the address type
       */
      library Address {
          /**
           * @dev Returns true if `account` is a contract.
           *
           * [IMPORTANT]
           * ====
           * It is unsafe to assume that an address for which this function returns
           * false is an externally-owned account (EOA) and not a contract.
           *
           * Among others, `isContract` will return false for the following
           * types of addresses:
           *
           *  - an externally-owned account
           *  - a contract in construction
           *  - an address where a contract will be created
           *  - an address where a contract lived, but was destroyed
           * ====
           */
          function isContract(address account) internal view returns (bool) {
              // This method relies on extcodesize, which returns 0 for contracts in
              // construction, since the code is only stored at the end of the
              // constructor execution.
      
              uint256 size;
              // solhint-disable-next-line no-inline-assembly
              assembly { size := extcodesize(account) }
              return size > 0;
          }
      
      }
      /**
       * @title Proxy
       * @dev Implements delegation of calls to other contracts, with proper
       * forwarding of return values and bubbling of failures.
       * It defines a fallback function that delegates all calls to the address
       * returned by the abstract _implementation() internal function.
       */
      abstract contract Proxy {
        /**
         * @dev Fallback function.
         * Implemented entirely in `_fallback`.
         */
        fallback () payable external {
          _fallback();
        }
      
        /**
         * @dev Receive function.
         * Implemented entirely in `_fallback`.
         */
        receive () payable external {
          _fallback();
        }
      
        /**
         * @return The Address of the implementation.
         */
        function _implementation() internal virtual view returns (address);
      
        /**
         * @dev Delegates execution to an implementation contract.
         * This is a low level function that doesn't return to its internal call site.
         * It will return to the external caller whatever the implementation returns.
         * @param implementation Address to delegate.
         */
        function _delegate(address implementation) internal {
          assembly {
            // Copy msg.data. We take full control of memory in this inline assembly
            // block because it will not return to Solidity code. We overwrite the
            // Solidity scratch pad at memory position 0.
            calldatacopy(0, 0, calldatasize())
      
            // Call the implementation.
            // out and outsize are 0 because we don't know the size yet.
            let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
      
            // Copy the returned data.
            returndatacopy(0, 0, returndatasize())
      
            switch result
            // delegatecall returns 0 on error.
            case 0 { revert(0, returndatasize()) }
            default { return(0, returndatasize()) }
          }
        }
      
        /**
         * @dev Function that is run as the first thing in the fallback function.
         * Can be redefined in derived contracts to add functionality.
         * Redefinitions must call super._willFallback().
         */
        function _willFallback() internal virtual {
        }
      
        /**
         * @dev fallback implementation.
         * Extracted to enable manual triggering.
         */
        function _fallback() internal {
          _willFallback();
          _delegate(_implementation());
        }
      }
      
      /**
       * @title UpgradeabilityProxy
       * @dev This contract implements a proxy that allows to change the
       * implementation address to which it will delegate.
       * Such a change is called an implementation upgrade.
       */
      contract UpgradeabilityProxy is Proxy {
        /**
         * @dev Contract constructor.
         * @param _logic Address of the initial implementation.
         * @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
         * It should include the signature and the parameters of the function to be called, as described in
         * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
         * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
         */
        constructor(address _logic, bytes memory _data) public payable {
          assert(IMPLEMENTATION_SLOT == bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1));
          _setImplementation(_logic);
          if(_data.length > 0) {
            (bool success,) = _logic.delegatecall(_data);
            require(success);
          }
        }  
      
        /**
         * @dev Emitted when the implementation is upgraded.
         * @param implementation Address of the new implementation.
         */
        event Upgraded(address indexed implementation);
      
        /**
         * @dev Storage slot with the address of the current implementation.
         * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
         * validated in the constructor.
         */
        bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
      
        /**
         * @dev Returns the current implementation.
         * @return impl Address of the current implementation
         */
        function _implementation() internal override view returns (address impl) {
          bytes32 slot = IMPLEMENTATION_SLOT;
          assembly {
            impl := sload(slot)
          }
        }
      
        /**
         * @dev Upgrades the proxy to a new implementation.
         * @param newImplementation Address of the new implementation.
         */
        function _upgradeTo(address newImplementation) internal {
          _setImplementation(newImplementation);
          emit Upgraded(newImplementation);
        }
      
        /**
         * @dev Sets the implementation address of the proxy.
         * @param newImplementation Address of the new implementation.
         */
        function _setImplementation(address newImplementation) internal {
          require(Address.isContract(newImplementation), "Cannot set a proxy implementation to a non-contract address");
      
          bytes32 slot = IMPLEMENTATION_SLOT;
      
          assembly {
            sstore(slot, newImplementation)
          }
        }
      }
      
      /**
       * @title AdminUpgradeabilityProxy
       * @dev This contract combines an upgradeability proxy with an authorization
       * mechanism for administrative tasks.
       * All external functions in this contract must be guarded by the
       * `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity
       * feature proposal that would enable this to be done automatically.
       */
      contract AdminUpgradeabilityProxy is UpgradeabilityProxy {
        /**
         * Contract constructor.
         * @param _logic address of the initial implementation.
         * @param _admin Address of the proxy administrator.
         * @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
         * It should include the signature and the parameters of the function to be called, as described in
         * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
         * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
         */
        constructor(address _logic, address _admin, bytes memory _data) UpgradeabilityProxy(_logic, _data) public payable {
          assert(ADMIN_SLOT == bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1));
          _setAdmin(_admin);
        }
      
        /**
         * @dev Emitted when the administration has been transferred.
         * @param previousAdmin Address of the previous admin.
         * @param newAdmin Address of the new admin.
         */
        event AdminChanged(address previousAdmin, address newAdmin);
      
        /**
         * @dev Storage slot with the admin of the contract.
         * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
         * validated in the constructor.
         */
      
        bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
      
        /**
         * @dev Modifier to check whether the `msg.sender` is the admin.
         * If it is, it will run the function. Otherwise, it will delegate the call
         * to the implementation.
         */
        modifier ifAdmin() {
          if (msg.sender == _admin()) {
            _;
          } else {
            _fallback();
          }
        }
      
        /**
         * @return The address of the proxy admin.
         */
        function admin() external ifAdmin returns (address) {
          return _admin();
        }
      
        /**
         * @return The address of the implementation.
         */
        function implementation() external ifAdmin returns (address) {
          return _implementation();
        }
      
        /**
         * @dev Changes the admin of the proxy.
         * Only the current admin can call this function.
         * @param newAdmin Address to transfer proxy administration to.
         */
        function changeAdmin(address newAdmin) external ifAdmin {
          require(newAdmin != address(0), "Cannot change the admin of a proxy to the zero address");
          emit AdminChanged(_admin(), newAdmin);
          _setAdmin(newAdmin);
        }
      
        /**
         * @dev Upgrade the backing implementation of the proxy.
         * Only the admin can call this function.
         * @param newImplementation Address of the new implementation.
         */
        function upgradeTo(address newImplementation) external ifAdmin {
          _upgradeTo(newImplementation);
        }
      
        /**
         * @dev Upgrade the backing implementation of the proxy and call a function
         * on the new implementation.
         * This is useful to initialize the proxied contract.
         * @param newImplementation Address of the new implementation.
         * @param data Data to send as msg.data in the low level call.
         * It should include the signature and the parameters of the function to be called, as described in
         * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
         */
        function upgradeToAndCall(address newImplementation, bytes calldata data) payable external ifAdmin {
          _upgradeTo(newImplementation);
          (bool success,) = newImplementation.delegatecall(data);
          require(success);
        }
      
        /**
         * @return adm The admin slot.
         */
        function _admin() internal view returns (address adm) {
          bytes32 slot = ADMIN_SLOT;
          assembly {
            adm := sload(slot)
          }
        }
      
        /**
         * @dev Sets the address of the proxy admin.
         * @param newAdmin Address of the new proxy admin.
         */
        function _setAdmin(address newAdmin) internal {
          bytes32 slot = ADMIN_SLOT;
      
          assembly {
            sstore(slot, newAdmin)
          }
        }
      
        /**
         * @dev Only fall back when the sender is not the admin.
         */
        function _willFallback() internal override virtual {
          require(msg.sender != _admin(), "Cannot call fallback function from the proxy admin");
          super._willFallback();
        }
      }

      File 3 of 3: GatedMiniMeController
      // Sources flattened with hardhat v2.6.0 https://hardhat.org
      
      // File deps/@openzeppelin/contracts-upgradeable/proxy/Initializable.sol
      
      // SPDX-License-Identifier: MIT
      
      pragma solidity >=0.4.24 <0.7.0;
      
      
      /**
       * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
       * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
       * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
       * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
       * 
       * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
       * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}.
       * 
       * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
       * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
       */
      abstract contract Initializable {
      
          /**
           * @dev Indicates that the contract has been initialized.
           */
          bool private _initialized;
      
          /**
           * @dev Indicates that the contract is in the process of being initialized.
           */
          bool private _initializing;
      
          /**
           * @dev Modifier to protect an initializer function from being invoked twice.
           */
          modifier initializer() {
              require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized");
      
              bool isTopLevelCall = !_initializing;
              if (isTopLevelCall) {
                  _initializing = true;
                  _initialized = true;
              }
      
              _;
      
              if (isTopLevelCall) {
                  _initializing = false;
              }
          }
      
          /// @dev Returns true if and only if the function is running in the constructor
          function _isConstructor() private view returns (bool) {
              // extcodesize checks the size of the code stored in an address, and
              // address returns the current address. Since the code is still not
              // deployed when running a constructor, any checks on its code size will
              // yield zero, making it an effective way to detect if a contract is
              // under construction or not.
              address self = address(this);
              uint256 cs;
              // solhint-disable-next-line no-inline-assembly
              assembly { cs := extcodesize(self) }
              return cs == 0;
          }
      }
      
      
      // File deps/@openzeppelin/contracts-upgradeable/GSN/ContextUpgradeable.sol
      
      
      
      pragma solidity ^0.6.0;
      
      /*
       * @dev Provides information about the current execution context, including the
       * sender of the transaction and its data. While these are generally available
       * via msg.sender and msg.data, they should not be accessed in such a direct
       * manner, since when dealing with GSN meta-transactions the account sending and
       * paying for execution may not be the actual sender (as far as an application
       * is concerned).
       *
       * This contract is only required for intermediate, library-like contracts.
       */
      abstract contract ContextUpgradeable is Initializable {
          function __Context_init() internal initializer {
              __Context_init_unchained();
          }
      
          function __Context_init_unchained() internal initializer {
          }
          function _msgSender() internal view virtual returns (address payable) {
              return msg.sender;
          }
      
          function _msgData() internal view virtual returns (bytes memory) {
              this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
              return msg.data;
          }
          uint256[50] private __gap;
      }
      
      
      // File deps/@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol
      
      
      
      pragma solidity ^0.6.0;
      
      
      /**
       * @dev Contract module which provides a basic access control mechanism, where
       * there is an account (an owner) that can be granted exclusive access to
       * specific functions.
       *
       * By default, the owner account will be the one that deploys the contract. This
       * can later be changed with {transferOwnership}.
       *
       * This module is used through inheritance. It will make available the modifier
       * `onlyOwner`, which can be applied to your functions to restrict their use to
       * the owner.
       */
      contract OwnableUpgradeable is Initializable, ContextUpgradeable {
          address private _owner;
      
          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
      
          /**
           * @dev Initializes the contract setting the deployer as the initial owner.
           */
          function __Ownable_init() internal initializer {
              __Context_init_unchained();
              __Ownable_init_unchained();
          }
      
          function __Ownable_init_unchained() internal initializer {
              address msgSender = _msgSender();
              _owner = msgSender;
              emit OwnershipTransferred(address(0), msgSender);
          }
      
          /**
           * @dev Returns the address of the current owner.
           */
          function owner() public view returns (address) {
              return _owner;
          }
      
          /**
           * @dev Throws if called by any account other than the owner.
           */
          modifier onlyOwner() {
              require(_owner == _msgSender(), "Ownable: caller is not the owner");
              _;
          }
      
          /**
           * @dev Leaves the contract without owner. It will not be possible to call
           * `onlyOwner` functions anymore. Can only be called by the current owner.
           *
           * NOTE: Renouncing ownership will leave the contract without an owner,
           * thereby removing any functionality that is only available to the owner.
           */
          function renounceOwnership() public virtual onlyOwner {
              emit OwnershipTransferred(_owner, address(0));
              _owner = address(0);
          }
      
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`).
           * Can only be called by the current owner.
           */
          function transferOwnership(address newOwner) public virtual onlyOwner {
              require(newOwner != address(0), "Ownable: new owner is the zero address");
              emit OwnershipTransferred(_owner, newOwner);
              _owner = newOwner;
          }
          uint256[49] private __gap;
      }
      
      
      // File interfaces/badger/IMiniMe.sol
      
      
      
      
      pragma solidity >=0.5.0 <0.8.0;
      
      interface IMiniMe {
          event ClaimedTokens(address indexed _token, address indexed _controller, uint256 _amount);
          event Transfer(address indexed _from, address indexed _to, uint256 _amount);
          event NewCloneToken(address indexed _cloneToken, uint256 _snapshotBlock);
          event Approval(address indexed _owner, address indexed _spender, uint256 _amount);
      
          function claimTokens(address _token) external;
      
          function controller() external view returns (address);
      
          function enableTransfers(bool _transfersEnabled) external;
      
          function generateTokens(address _owner, uint256 _amount) external returns (bool);
      
          function destroyTokens(address _owner, uint256 _amount) external returns (bool);
      
          function changeController(address _newController) external returns (address);
      }
      
      
      // File interfaces/erc20/IERC20.sol
      
      
      
      pragma solidity ^0.6.0;
      
      /**
       * @dev Interface of the ERC20 standard as defined in the EIP.
       */
      interface IERC20 {
          /**
           * @dev Returns the amount of tokens in existence.
           */
          function totalSupply() external view returns (uint256);
      
          function name() external view returns (string memory);
          function symbol() external view returns (string memory);
          function decimals() external view returns (uint256);
      
          /**
           * @dev Returns the amount of tokens owned by `account`.
           */
          function balanceOf(address account) external view returns (uint256);
      
          /**
           * @dev Moves `amount` tokens from the caller's account to `recipient`.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * Emits a {Transfer} event.
           */
          function transfer(address recipient, uint256 amount) external returns (bool);
      
          /**
           * @dev Returns the remaining number of tokens that `spender` will be
           * allowed to spend on behalf of `owner` through {transferFrom}. This is
           * zero by default.
           *
           * This value changes when {approve} or {transferFrom} are called.
           */
          function allowance(address owner, address spender) external view returns (uint256);
      
          /**
           * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * IMPORTANT: Beware that changing an allowance with this method brings the risk
           * that someone may use both the old and the new allowance by unfortunate
           * transaction ordering. One possible solution to mitigate this race
           * condition is to first reduce the spender's allowance to 0 and set the
           * desired value afterwards:
           * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
           *
           * Emits an {Approval} event.
           */
          function approve(address spender, uint256 amount) external returns (bool);
      
          /**
           * @dev Moves `amount` tokens from `sender` to `recipient` using the
           * allowance mechanism. `amount` is then deducted from the caller's
           * allowance.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * Emits a {Transfer} event.
           */
          function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
      
          /**
           * @dev Emitted when `value` tokens are moved from one account (`from`) to
           * another (`to`).
           *
           * Note that `value` may be zero.
           */
          event Transfer(address indexed from, address indexed to, uint256 value);
      
          /**
           * @dev Emitted when the allowance of a `spender` for an `owner` is set by
           * a call to {approve}. `value` is the new allowance.
           */
          event Approval(address indexed owner, address indexed spender, uint256 value);
      }
      
      interface ITokenController {
          /// @notice Called when `_owner` sends ether to the MiniMe Token contract
          /// @param _owner The address that sent the ether to create tokens
          /// @return True if the ether is accepted, false if it throws
          function proxyPayment(address _owner) external payable returns(bool);
      
          /// @notice Notifies the controller about a token transfer allowing the
          ///  controller to react if desired
          /// @param _from The origin of the transfer
          /// @param _to The destination of the transfer
          /// @param _amount The amount of the transfer
          /// @return False if the controller does not authorize the transfer
          function onTransfer(address _from, address _to, uint _amount) external returns(bool);
      
          /// @notice Notifies the controller about an approval allowing the
          ///  controller to react if desired
          /// @param _owner The address that calls `approve()`
          /// @param _spender The spender in the `approve()` call
          /// @param _amount The amount in the `approve()` call
          /// @return False if the controller does not authorize the approval
          function onApprove(address _owner, address _spender, uint _amount) external returns(bool);
      }
      
      
      // File contracts/badger-core/GatedMiniMeController.sol
      
      pragma solidity 0.6.12;
      
      /*
          === Gated MiniMe Controller ===
          Limits the functinality of the MiniMe controller address by serving as an intermediate contract.
      
          The owner maintains the ability to mint and burn tokens from it's own balance, losing the ability to mint and burn to/from arbitrary accounts.
          The MiniMe controller can no longer be changed.
          The owner maintains the ability to claim other tokens sent to the MiniMe contract.
      
          This contract is designed to be upgradeable, this ability can be removed by transferring the proxyAdmin to 0x0.
          Minting and burning can be permanently removed by the disableMinting() function.
      
          claimTokens() is designed to be retained. It ability can be removed (along with minting and burning), by burning the owner() address.
      */
      contract GatedMiniMeController is OwnableUpgradeable {
          IMiniMe public minime;
          bool public mintingEnabled;
          function initialize(address token_) external initializer {
              __Ownable_init();
              minime = IMiniMe(token_);
              mintingEnabled = true;
          }
      
          modifier onlyWhenMintingEnabled() {
              require(mintingEnabled == true, "minting disabled");
              _;
          }
      
          modifier onlyToken() {
              require(msg.sender == address(minime), "TM_CALLER_NOT_TOKEN");
              _;
          }
      
          /// @dev Minting and burning can be permanently disabled by the owner
          function disableMinting() external onlyOwner {
              mintingEnabled = false;
          }
      
          /// @dev Mint tokens to governance
          function mint(uint256 amount) external onlyOwner onlyWhenMintingEnabled {
              require(minime.generateTokens(owner(), amount), "mint failed");
          }
          
          /// @dev Burn tokens from governance
          function burn(uint256 amount) external onlyOwner onlyWhenMintingEnabled {
              require(minime.destroyTokens(owner(), amount), "burn failed");
          }
      
          function onTransfer(address, address, uint256) external onlyToken returns (bool) {
              return true;
          }
      
          /**
          * @dev Notifies the controller about an approval allowing the controller to react if desired
          *      Initialization check is implicitly provided by `onlyToken()`.
          * @return False if the controller does not authorize the approval
          */
          function onApprove(address, address, uint) external onlyToken returns (bool) {
              return true;
          }
      
          /**
          * @dev Called when ether is sent to the MiniMe Token contract
          *      Initialization check is implicitly provided by `onlyToken()`.
          * @return True if the ether is accepted, false for it to throw
          */
          function proxyPayment(address) external payable onlyToken returns (bool) {
              return false;
          }
      
          /// @dev Claim other tokens
          function claimTokens(address token) external onlyOwner {
              minime.claimTokens(token);
              require(IERC20(token).transfer(owner(), IERC20(token).balanceOf(address(this))), "claim tokens transfer to owner failed");
          }
      }