ETH Price: $1,870.50 (+0.55%)

Transaction Decoder

Block:
10598636 at Aug-05-2020 08:18:46 AM +UTC
Transaction Fee:
0.001988071 ETH $3.72
Gas Used:
28,001 Gas / 71 Gwei

Emitted Events:

30 FiatTokenProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x00000000000000000000000033be0b7df68da13daf2687fb9e9f902b0e0b03a2, 0x0000000000000000000000006cc8dcbca746a6e4fdefb98e1d0df903b107fd21, 000000000000000000000000000000000000000000000000000000003b9aca00 )

Account State Difference:

  Address   Before After State Difference Code
0x33Be0b7d...b0E0B03a2
0.003114144 Eth
Nonce: 0
0.001126073 Eth
Nonce: 1
0.001988071
0xA0b86991...E3606eB48
(Ethermine)
770.05959239052537582 Eth770.06158046152537582 Eth0.001988071

Execution Trace

FiatTokenProxy.a9059cbb( )
  • FiatTokenV1.transfer( _to=0x6cc8dCbCA746a6E4Fdefb98E1d0DF903b107fd21, _value=1000000000 ) => ( True )
    File 1 of 2: FiatTokenProxy
    pragma solidity ^0.4.24;
    
    // File: zos-lib/contracts/upgradeability/Proxy.sol
    
    /**
     * @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.
     */
    contract Proxy {
      /**
       * @dev Fallback function.
       * Implemented entirely in `_fallback`.
       */
      function () payable external {
        _fallback();
      }
    
      /**
       * @return The Address of the implementation.
       */
      function _implementation() internal 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 {
      }
    
      /**
       * @dev fallback implementation.
       * Extracted to enable manual triggering.
       */
      function _fallback() internal {
        _willFallback();
        _delegate(_implementation());
      }
    }
    
    // File: openzeppelin-solidity/contracts/AddressUtils.sol
    
    /**
     * Utility library of inline functions on addresses
     */
    library AddressUtils {
    
      /**
       * Returns whether the target address is a contract
       * @dev This function will return false if invoked during the constructor of a contract,
       * as the code is not actually created until after the constructor finishes.
       * @param addr address to check
       * @return whether the target address is a contract
       */
      function isContract(address addr) internal view returns (bool) {
        uint256 size;
        // XXX Currently there is no better way to check if there is a contract in an address
        // than to check the size of the code at that address.
        // See https://ethereum.stackexchange.com/a/14016/36603
        // for more details about how this works.
        // TODO Check this again before the Serenity release, because all addresses will be
        // contracts then.
        // solium-disable-next-line security/no-inline-assembly
        assembly { size := extcodesize(addr) }
        return size > 0;
      }
    
    }
    
    // File: zos-lib/contracts/upgradeability/UpgradeabilityProxy.sol
    
    /**
     * @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 Emitted when the implementation is upgraded.
       * @param implementation Address of the new implementation.
       */
      event Upgraded(address implementation);
    
      /**
       * @dev Storage slot with the address of the current implementation.
       * This is the keccak-256 hash of "org.zeppelinos.proxy.implementation", and is
       * validated in the constructor.
       */
      bytes32 private constant IMPLEMENTATION_SLOT = 0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3;
    
      /**
       * @dev Contract constructor.
       * @param _implementation Address of the initial implementation.
       */
      constructor(address _implementation) public {
        assert(IMPLEMENTATION_SLOT == keccak256("org.zeppelinos.proxy.implementation"));
    
        _setImplementation(_implementation);
      }
    
      /**
       * @dev Returns the current implementation.
       * @return Address of the current implementation
       */
      function _implementation() internal 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) private {
        require(AddressUtils.isContract(newImplementation), "Cannot set a proxy implementation to a non-contract address");
    
        bytes32 slot = IMPLEMENTATION_SLOT;
    
        assembly {
          sstore(slot, newImplementation)
        }
      }
    }
    
    // File: zos-lib/contracts/upgradeability/AdminUpgradeabilityProxy.sol
    
    /**
     * @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 {
      /**
       * @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 "org.zeppelinos.proxy.admin", and is
       * validated in the constructor.
       */
      bytes32 private constant ADMIN_SLOT = 0x10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b;
    
      /**
       * @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();
        }
      }
    
      /**
       * Contract constructor.
       * It sets the `msg.sender` as the proxy administrator.
       * @param _implementation address of the initial implementation.
       */
      constructor(address _implementation) UpgradeabilityProxy(_implementation) public {
        assert(ADMIN_SLOT == keccak256("org.zeppelinos.proxy.admin"));
    
        _setAdmin(msg.sender);
      }
    
      /**
       * @return The address of the proxy admin.
       */
      function admin() external view ifAdmin returns (address) {
        return _admin();
      }
    
      /**
       * @return The address of the implementation.
       */
      function implementation() external view 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/develop/abi-spec.html#function-selector-and-argument-encoding.
       */
      function upgradeToAndCall(address newImplementation, bytes data) payable external ifAdmin {
        _upgradeTo(newImplementation);
        require(address(this).call.value(msg.value)(data));
      }
    
      /**
       * @return 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 {
        require(msg.sender != _admin(), "Cannot call fallback function from the proxy admin");
        super._willFallback();
      }
    }
    
    // File: contracts/FiatTokenProxy.sol
    
    /**
    * Copyright CENTRE SECZ 2018
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy 
    * of this software and associated documentation files (the "Software"), to deal 
    * in the Software without restriction, including without limitation the rights 
    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
    * copies of the Software, and to permit persons to whom the Software is furnished to 
    * do so, subject to the following conditions:
    *
    * The above copyright notice and this permission notice shall be included in all 
    * copies or substantial portions of the Software.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
    * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
    * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
    * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
    * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
    
    pragma solidity ^0.4.24;
    
    
    /**
     * @title FiatTokenProxy
     * @dev This contract proxies FiatToken calls and enables FiatToken upgrades
    */ 
    contract FiatTokenProxy is AdminUpgradeabilityProxy {
        constructor(address _implementation) public AdminUpgradeabilityProxy(_implementation) {
        }
    }

    File 2 of 2: FiatTokenV1
    pragma solidity ^0.4.24;
    
    // File: contracts/Ownable.sol
    
    /**
    * Copyright CENTRE SECZ 2018
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy 
    * of this software and associated documentation files (the "Software"), to deal 
    * in the Software without restriction, including without limitation the rights 
    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
    * copies of the Software, and to permit persons to whom the Software is furnished to 
    * do so, subject to the following conditions:
    *
    * The above copyright notice and this permission notice shall be included in all 
    * copies or substantial portions of the Software.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
    * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
    * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
    * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
    * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
    
    pragma solidity ^0.4.24;
    
    /**
     * @title Ownable
     * @dev The Ownable contract from https://github.com/zeppelinos/labs/blob/master/upgradeability_ownership/contracts/ownership/Ownable.sol 
     * branch: master commit: 3887ab77b8adafba4a26ace002f3a684c1a3388b modified to:
     * 1) Add emit prefix to OwnershipTransferred event (7/13/18)
     * 2) Replace constructor with constructor syntax (7/13/18)
     * 3) consolidate OwnableStorage into this contract
     */
    contract Ownable {
    
      // Owner of the contract
      address private _owner;
    
      /**
      * @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 OwnershipTransferred(address previousOwner, address newOwner);
    
      /**
      * @dev The constructor sets the original owner of the contract to the sender account.
      */
      constructor() public {
        setOwner(msg.sender);
      }
    
      /**
     * @dev Tells the address of the owner
     * @return the address of the owner
     */
      function owner() public view returns (address) {
        return _owner;
      }
    
      /**
       * @dev Sets a new owner address
       */
      function setOwner(address newOwner) internal {
        _owner = newOwner;
      }
    
      /**
      * @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);
        setOwner(newOwner);
      }
    }
    
    // File: contracts/Blacklistable.sol
    
    /**
    * Copyright CENTRE SECZ 2018
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy 
    * of this software and associated documentation files (the "Software"), to deal 
    * in the Software without restriction, including without limitation the rights 
    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
    * copies of the Software, and to permit persons to whom the Software is furnished to 
    * do so, subject to the following conditions:
    *
    * The above copyright notice and this permission notice shall be included in all 
    * copies or substantial portions of the Software.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
    * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
    * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
    * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
    * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
    
    pragma solidity ^0.4.24;
    
    
    /**
     * @title Blacklistable Token
     * @dev Allows accounts to be blacklisted by a "blacklister" role
    */
    contract Blacklistable is Ownable {
    
        address public blacklister;
        mapping(address => bool) internal blacklisted;
    
        event Blacklisted(address indexed _account);
        event UnBlacklisted(address indexed _account);
        event BlacklisterChanged(address indexed newBlacklister);
    
        /**
         * @dev Throws if called by any account other than the blacklister
        */
        modifier onlyBlacklister() {
            require(msg.sender == blacklister);
            _;
        }
    
        /**
         * @dev Throws if argument account is blacklisted
         * @param _account The address to check
        */
        modifier notBlacklisted(address _account) {
            require(blacklisted[_account] == false);
            _;
        }
    
        /**
         * @dev Checks if account is blacklisted
         * @param _account The address to check    
        */
        function isBlacklisted(address _account) public view returns (bool) {
            return blacklisted[_account];
        }
    
        /**
         * @dev Adds account to blacklist
         * @param _account The address to blacklist
        */
        function blacklist(address _account) public onlyBlacklister {
            blacklisted[_account] = true;
            emit Blacklisted(_account);
        }
    
        /**
         * @dev Removes account from blacklist
         * @param _account The address to remove from the blacklist
        */
        function unBlacklist(address _account) public onlyBlacklister {
            blacklisted[_account] = false;
            emit UnBlacklisted(_account);
        }
    
        function updateBlacklister(address _newBlacklister) public onlyOwner {
            require(_newBlacklister != address(0));
            blacklister = _newBlacklister;
            emit BlacklisterChanged(blacklister);
        }
    }
    
    // File: contracts/Pausable.sol
    
    /**
    * Copyright CENTRE SECZ 2018
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy 
    * of this software and associated documentation files (the "Software"), to deal 
    * in the Software without restriction, including without limitation the rights 
    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
    * copies of the Software, and to permit persons to whom the Software is furnished to 
    * do so, subject to the following conditions:
    *
    * The above copyright notice and this permission notice shall be included in all 
    * copies or substantial portions of the Software.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
    * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
    * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
    * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
    * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
    
    pragma solidity ^0.4.24;
    
    
    /**
     * @title Pausable
     * @dev Base contract which allows children to implement an emergency stop mechanism.
     * Based on openzeppelin tag v1.10.0 commit: feb665136c0dae9912e08397c1a21c4af3651ef3
     * Modifications:
     * 1) Added pauser role, switched pause/unpause to be onlyPauser (6/14/2018)
     * 2) Removed whenNotPause/whenPaused from pause/unpause (6/14/2018)
     * 3) Removed whenPaused (6/14/2018)
     * 4) Switches ownable library to use zeppelinos (7/12/18)
     * 5) Remove constructor (7/13/18)
     */
    contract Pausable is Ownable {
      event Pause();
      event Unpause();
      event PauserChanged(address indexed newAddress);
    
    
      address public pauser;
      bool public paused = false;
    
      /**
       * @dev Modifier to make a function callable only when the contract is not paused.
       */
      modifier whenNotPaused() {
        require(!paused);
        _;
      }
    
      /**
       * @dev throws if called by any account other than the pauser
       */
      modifier onlyPauser() {
        require(msg.sender == pauser);
        _;
      }
    
      /**
       * @dev called by the owner to pause, triggers stopped state
       */
      function pause() onlyPauser public {
        paused = true;
        emit Pause();
      }
    
      /**
       * @dev called by the owner to unpause, returns to normal state
       */
      function unpause() onlyPauser public {
        paused = false;
        emit Unpause();
      }
    
      /**
       * @dev update the pauser role
       */
      function updatePauser(address _newPauser) onlyOwner public {
        require(_newPauser != address(0));
        pauser = _newPauser;
        emit PauserChanged(pauser);
      }
    
    }
    
    // File: openzeppelin-solidity/contracts/math/SafeMath.sol
    
    /**
     * @title SafeMath
     * @dev Math operations with safety checks that throw on error
     */
    library SafeMath {
    
      /**
      * @dev Multiplies two numbers, throws on overflow.
      */
      function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
        // Gas optimization: this is cheaper than asserting 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
        if (a == 0) {
          return 0;
        }
    
        c = a * b;
        assert(c / a == b);
        return c;
      }
    
      /**
      * @dev Integer division of two numbers, truncating the quotient.
      */
      function div(uint256 a, uint256 b) internal pure returns (uint256) {
        // assert(b > 0); // Solidity automatically throws when dividing by 0
        // uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold
        return a / b;
      }
    
      /**
      * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
      */
      function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        assert(b <= a);
        return a - b;
      }
    
      /**
      * @dev Adds two numbers, throws on overflow.
      */
      function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
        c = a + b;
        assert(c >= a);
        return c;
      }
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol
    
    /**
     * @title ERC20Basic
     * @dev Simpler version of ERC20 interface
     * See https://github.com/ethereum/EIPs/issues/179
     */
    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);
    }
    
    // File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol
    
    /**
     * @title ERC20 interface
     * @dev see https://github.com/ethereum/EIPs/issues/20
     */
    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
      );
    }
    
    // File: contracts/FiatTokenV1.sol
    
    /**
    * Copyright CENTRE SECZ 2018
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy 
    * of this software and associated documentation files (the "Software"), to deal 
    * in the Software without restriction, including without limitation the rights 
    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
    * copies of the Software, and to permit persons to whom the Software is furnished to 
    * do so, subject to the following conditions:
    *
    * The above copyright notice and this permission notice shall be included in all 
    * copies or substantial portions of the Software.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
    * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
    * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
    * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
    * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    */
    
    pragma solidity ^0.4.24;
    
    
    
    
    
    
    /**
     * @title FiatToken
     * @dev ERC20 Token backed by fiat reserves
     */
    contract FiatTokenV1 is Ownable, ERC20, Pausable, Blacklistable {
        using SafeMath for uint256;
    
        string public name;
        string public symbol;
        uint8 public decimals;
        string public currency;
        address public masterMinter;
        bool internal initialized;
    
        mapping(address => uint256) internal balances;
        mapping(address => mapping(address => uint256)) internal allowed;
        uint256 internal totalSupply_ = 0;
        mapping(address => bool) internal minters;
        mapping(address => uint256) internal minterAllowed;
    
        event Mint(address indexed minter, address indexed to, uint256 amount);
        event Burn(address indexed burner, uint256 amount);
        event MinterConfigured(address indexed minter, uint256 minterAllowedAmount);
        event MinterRemoved(address indexed oldMinter);
        event MasterMinterChanged(address indexed newMasterMinter);
    
        function initialize(
            string _name,
            string _symbol,
            string _currency,
            uint8 _decimals,
            address _masterMinter,
            address _pauser,
            address _blacklister,
            address _owner
        ) public {
            require(!initialized);
            require(_masterMinter != address(0));
            require(_pauser != address(0));
            require(_blacklister != address(0));
            require(_owner != address(0));
    
            name = _name;
            symbol = _symbol;
            currency = _currency;
            decimals = _decimals;
            masterMinter = _masterMinter;
            pauser = _pauser;
            blacklister = _blacklister;
            setOwner(_owner);
            initialized = true;
        }
    
        /**
         * @dev Throws if called by any account other than a minter
        */
        modifier onlyMinters() {
            require(minters[msg.sender] == true);
            _;
        }
    
        /**
         * @dev Function to mint tokens
         * @param _to The address that will receive the minted tokens.
         * @param _amount The amount of tokens to mint. Must be less than or equal to the minterAllowance of the caller.
         * @return A boolean that indicates if the operation was successful.
        */
        function mint(address _to, uint256 _amount) whenNotPaused onlyMinters notBlacklisted(msg.sender) notBlacklisted(_to) public returns (bool) {
            require(_to != address(0));
            require(_amount > 0);
    
            uint256 mintingAllowedAmount = minterAllowed[msg.sender];
            require(_amount <= mintingAllowedAmount);
    
            totalSupply_ = totalSupply_.add(_amount);
            balances[_to] = balances[_to].add(_amount);
            minterAllowed[msg.sender] = mintingAllowedAmount.sub(_amount);
            emit Mint(msg.sender, _to, _amount);
            emit Transfer(0x0, _to, _amount);
            return true;
        }
    
        /**
         * @dev Throws if called by any account other than the masterMinter
        */
        modifier onlyMasterMinter() {
            require(msg.sender == masterMinter);
            _;
        }
    
        /**
         * @dev Get minter allowance for an account
         * @param minter The address of the minter
        */
        function minterAllowance(address minter) public view returns (uint256) {
            return minterAllowed[minter];
        }
    
        /**
         * @dev Checks if account is a minter
         * @param account The address to check    
        */
        function isMinter(address account) public view returns (bool) {
            return minters[account];
        }
    
        /**
         * @dev Get allowed amount for an account
         * @param owner address The account owner
         * @param spender address The account spender
        */
        function allowance(address owner, address spender) public view returns (uint256) {
            return allowed[owner][spender];
        }
    
        /**
         * @dev Get totalSupply of token
        */
        function totalSupply() public view returns (uint256) {
            return totalSupply_;
        }
    
        /**
         * @dev Get token balance of an account
         * @param account address The account
        */
        function balanceOf(address account) public view returns (uint256) {
            return balances[account];
        }
    
        /**
         * @dev Adds blacklisted check to approve
         * @return True if the operation was successful.
        */
        function approve(address _spender, uint256 _value) whenNotPaused notBlacklisted(msg.sender) notBlacklisted(_spender) public returns (bool) {
            allowed[msg.sender][_spender] = _value;
            emit Approval(msg.sender, _spender, _value);
            return true;
        }
    
        /**
         * @dev Transfer tokens from one address to another.
         * @param _from address The address which you want to send tokens from
         * @param _to address The address which you want to transfer to
         * @param _value uint256 the amount of tokens to be transferred
         * @return bool success
        */
        function transferFrom(address _from, address _to, uint256 _value) whenNotPaused notBlacklisted(_to) notBlacklisted(msg.sender) notBlacklisted(_from) public returns (bool) {
            require(_to != address(0));
            require(_value <= balances[_from]);
            require(_value <= allowed[_from][msg.sender]);
    
            balances[_from] = balances[_from].sub(_value);
            balances[_to] = balances[_to].add(_value);
            allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
            emit Transfer(_from, _to, _value);
            return true;
        }
    
        /**
         * @dev transfer token for a specified address
         * @param _to The address to transfer to.
         * @param _value The amount to be transferred.
         * @return bool success
        */
        function transfer(address _to, uint256 _value) whenNotPaused notBlacklisted(msg.sender) notBlacklisted(_to) public returns (bool) {
            require(_to != address(0));
            require(_value <= balances[msg.sender]);
    
            balances[msg.sender] = balances[msg.sender].sub(_value);
            balances[_to] = balances[_to].add(_value);
            emit Transfer(msg.sender, _to, _value);
            return true;
        }
    
        /**
         * @dev Function to add/update a new minter
         * @param minter The address of the minter
         * @param minterAllowedAmount The minting amount allowed for the minter
         * @return True if the operation was successful.
        */
        function configureMinter(address minter, uint256 minterAllowedAmount) whenNotPaused onlyMasterMinter public returns (bool) {
            minters[minter] = true;
            minterAllowed[minter] = minterAllowedAmount;
            emit MinterConfigured(minter, minterAllowedAmount);
            return true;
        }
    
        /**
         * @dev Function to remove a minter
         * @param minter The address of the minter to remove
         * @return True if the operation was successful.
        */
        function removeMinter(address minter) onlyMasterMinter public returns (bool) {
            minters[minter] = false;
            minterAllowed[minter] = 0;
            emit MinterRemoved(minter);
            return true;
        }
    
        /**
         * @dev allows a minter to burn some of its own tokens
         * Validates that caller is a minter and that sender is not blacklisted
         * amount is less than or equal to the minter's account balance
         * @param _amount uint256 the amount of tokens to be burned
        */
        function burn(uint256 _amount) whenNotPaused onlyMinters notBlacklisted(msg.sender) public {
            uint256 balance = balances[msg.sender];
            require(_amount > 0);
            require(balance >= _amount);
    
            totalSupply_ = totalSupply_.sub(_amount);
            balances[msg.sender] = balance.sub(_amount);
            emit Burn(msg.sender, _amount);
            emit Transfer(msg.sender, address(0), _amount);
        }
    
        function updateMasterMinter(address _newMasterMinter) onlyOwner public {
            require(_newMasterMinter != address(0));
            masterMinter = _newMasterMinter;
            emit MasterMinterChanged(masterMinter);
        }
    }