ETH Price: $2,056.12 (-2.97%)

Transaction Decoder

Block:
10001977 at May-04-2020 08:43:16 PM +UTC
Transaction Fee:
0.000299144 ETH $0.62
Gas Used:
37,393 Gas / 8 Gwei

Account State Difference:

  Address   Before After State Difference Code
0x235909a5...6b3C919F7
0.379607213891957442 Eth
Nonce: 1146
0.379308069891957442 Eth
Nonce: 1147
0.000299144
(BaikalMine 1)
0.553796887974502177 Eth0.554096031974502177 Eth0.000299144

Execution Trace

MEV Bot: 0xa57...6CF.1cff79cd( )
  • 0x50b881ceafece2034b899205fbbd7bafc0c0d230.2fdc7315( )
    • FiatTokenProxy.70a08231( )
      • FiatTokenV1.balanceOf( account=0x97deC872013f6B5fB443861090ad931542878126 ) => ( 3000444968565 )
        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);
            }
        }