ETH Price: $2,072.14 (+8.34%)

Transaction Decoder

Block:
16557372 at Feb-04-2023 07:01:35 PM +UTC
Transaction Fee:
0.00183252 ETH $3.80
Gas Used:
61,084 Gas / 30 Gwei

Emitted Events:

326 OwnedUpgradeabilityProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000834db0fcde9d8028692551d5ca5086c92cb555b8, 0x00000000000000000000000029d5527caa78f1946a409fa6acaf14a0a4a0274b, 000000000000000000000000000000000000000000000064856ac0268101bb98 )

Account State Difference:

  Address   Before After State Difference Code
0x00000000...ecd22b376
(Flashbots: Builder)
1.230143062614055069 Eth1.230147036278460625 Eth0.000003973664405556
0xf24C621e...a76c7B3C9
(Bitso: Deployer 1)
46.934648489120526841 Eth
Nonce: 274141
46.932815969120526841 Eth
Nonce: 274142
0.00183252

Execution Trace

0x834db0fcde9d8028692551d5ca5086c92cb555b8.afef944f( )
  • 0x64b29dc43e817817cf77468c8dda63d98ce08fb2.afef944f( )
    • 0x1b3968e3f543bba37339953e8ae975a6f581f5e0.CALL( )
    • 0x79c82bc011b957a186221831d669b96efda7bb25.afef944f( )
      • 0x2b3e08774e9874f6e3487889651553dd2e4467da.2d3e579a( )
      • OwnedUpgradeabilityProxy.70a08231( )
        • TrueUSD.balanceOf( account=0x834DB0FCDE9d8028692551D5ca5086C92cb555B8 ) => ( 1854288114997136571288 )
        • OwnedUpgradeabilityProxy.a9059cbb( )
          • TrueUSD.transfer( recipient=0x29D5527CaA78f1946a409FA6aCaf14A0a4A0274b, amount=1854288114997136571288 ) => ( True )
            File 1 of 2: OwnedUpgradeabilityProxy
            pragma solidity ^0.4.23;
            
            // This is the proxy contract for the TrustToken Registry
            
            // File: contracts/Proxy/Proxy.sol
            
            /**
             * @title Proxy
             * @dev Gives the possibility to delegate any call to a foreign implementation.
             */
            contract Proxy {
                
                /**
                * @dev Tells the address of the implementation where every call will be delegated.
                * @return address of the implementation to which it will be delegated
                */
                function implementation() public view returns (address);
            
                /**
                * @dev Fallback function allowing to perform a delegatecall to the given implementation.
                * This function will return whatever the implementation call returns
                */
                function() external payable {
                    address _impl = implementation();
                    require(_impl != address(0), "implementation contract not set");
                    
                    assembly {
                        let ptr := mload(0x40)
                        calldatacopy(ptr, 0, calldatasize)
                        let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0)
                        let size := returndatasize
                        returndatacopy(ptr, 0, size)
            
                        switch result
                        case 0 { revert(ptr, size) }
                        default { return(ptr, size) }
                    }
                }
            }
            
            // File: contracts/Proxy/UpgradeabilityProxy.sol
            
            /**
             * @title UpgradeabilityProxy
             * @dev This contract represents a proxy where the implementation address to which it will delegate can be upgraded
             */
            contract UpgradeabilityProxy is Proxy {
                /**
                * @dev This event will be emitted every time the implementation gets upgraded
                * @param implementation representing the address of the upgraded implementation
                */
                event Upgraded(address indexed implementation);
            
                // Storage position of the address of the current implementation
                bytes32 private constant implementationPosition = keccak256("trueUSD.proxy.implementation");
            
                /**
                * @dev Tells the address of the current implementation
                * @return address of the current implementation
                */
                function implementation() public view returns (address impl) {
                    bytes32 position = implementationPosition;
                    assembly {
                      impl := sload(position)
                    }
                }
            
                /**
                * @dev Sets the address of the current implementation
                * @param newImplementation address representing the new implementation to be set
                */
                function _setImplementation(address newImplementation) internal {
                    bytes32 position = implementationPosition;
                    assembly {
                      sstore(position, newImplementation)
                    }
                }
            
                /**
                * @dev Upgrades the implementation address
                * @param newImplementation representing the address of the new implementation to be set
                */
                function _upgradeTo(address newImplementation) internal {
                    address currentImplementation = implementation();
                    require(currentImplementation != newImplementation);
                    _setImplementation(newImplementation);
                    emit Upgraded(newImplementation);
                }
            }
            
            // File: contracts/Proxy/OwnedUpgradeabilityProxy.sol
            
            /**
             * @title OwnedUpgradeabilityProxy
             * @dev This contract combines an upgradeability proxy with basic authorization control functionalities
             */
            contract OwnedUpgradeabilityProxy is UpgradeabilityProxy {
                /**
                * @dev Event to show ownership has been transferred
                * @param previousOwner representing the address of the previous owner
                * @param newOwner representing the address of the new owner
                */
                event ProxyOwnershipTransferred(address indexed previousOwner, address indexed newOwner);
            
                /**
                * @dev Event to show ownership transfer is pending
                * @param currentOwner representing the address of the current owner
                * @param pendingOwner representing the address of the pending owner
                */
                event NewPendingOwner(address currentOwner, address pendingOwner);
                
                // Storage position of the owner and pendingOwner of the contract
                bytes32 private constant proxyOwnerPosition = keccak256("trueUSD.proxy.owner");
                bytes32 private constant pendingProxyOwnerPosition = keccak256("trueUSD.pending.proxy.owner");
            
                /**
                * @dev the constructor sets the original owner of the contract to the sender account.
                */
                constructor() public {
                    _setUpgradeabilityOwner(msg.sender);
                }
            
                /**
                * @dev Throws if called by any account other than the owner.
                */
                modifier onlyProxyOwner() {
                    require(msg.sender == proxyOwner(), "only Proxy Owner");
                    _;
                }
            
                /**
                * @dev Throws if called by any account other than the pending owner.
                */
                modifier onlyPendingProxyOwner() {
                    require(msg.sender == pendingProxyOwner(), "only pending Proxy Owner");
                    _;
                }
            
                /**
                * @dev Tells the address of the owner
                * @return the address of the owner
                */
                function proxyOwner() public view returns (address owner) {
                    bytes32 position = proxyOwnerPosition;
                    assembly {
                        owner := sload(position)
                    }
                }
            
                /**
                * @dev Tells the address of the owner
                * @return the address of the owner
                */
                function pendingProxyOwner() public view returns (address pendingOwner) {
                    bytes32 position = pendingProxyOwnerPosition;
                    assembly {
                        pendingOwner := sload(position)
                    }
                }
            
                /**
                * @dev Sets the address of the owner
                */
                function _setUpgradeabilityOwner(address newProxyOwner) internal {
                    bytes32 position = proxyOwnerPosition;
                    assembly {
                        sstore(position, newProxyOwner)
                    }
                }
            
                /**
                * @dev Sets the address of the owner
                */
                function _setPendingUpgradeabilityOwner(address newPendingProxyOwner) internal {
                    bytes32 position = pendingProxyOwnerPosition;
                    assembly {
                        sstore(position, newPendingProxyOwner)
                    }
                }
            
                /**
                * @dev Allows the current owner to transfer control of the contract to a newOwner.
                *changes the pending owner to newOwner. But doesn't actually transfer
                * @param newOwner The address to transfer ownership to.
                */
                function transferProxyOwnership(address newOwner) external onlyProxyOwner {
                    require(newOwner != address(0));
                    _setPendingUpgradeabilityOwner(newOwner);
                    emit NewPendingOwner(proxyOwner(), newOwner);
                }
            
                /**
                * @dev Allows the pendingOwner to claim ownership of the proxy
                */
                function claimProxyOwnership() external onlyPendingProxyOwner {
                    emit ProxyOwnershipTransferred(proxyOwner(), pendingProxyOwner());
                    _setUpgradeabilityOwner(pendingProxyOwner());
                    _setPendingUpgradeabilityOwner(address(0));
                }
            
                /**
                * @dev Allows the proxy owner to upgrade the current version of the proxy.
                * @param implementation representing the address of the new implementation to be set.
                */
                function upgradeTo(address implementation) external onlyProxyOwner {
                    _upgradeTo(implementation);
                }
            }

            File 2 of 2: TrueUSD
            /**
             *Submitted for verification at Etherscan.io on 2020-09-25
            */
            
            /**
             *  :::==== :::====  :::  === :::===== :::  === :::===  :::====
             *  :::==== :::  === :::  === :::      :::  === :::     :::  ===
             *    ===   =======  ===  === ======   ===  ===  =====  ===  ===
             *    ===   === ===  ===  === ===      ===  ===     === ===  ===
             *    ===   ===  ===  ======  ========  ======  ======  =======
             */
            
            pragma solidity 0.6.10;
            
            /**
             * Defines the storage layout of the token implementation contract. Any
             * newly declared state variables in future upgrades should be appended
             * to the bottom. Never remove state variables from this list, however variables
             * can be renamed. Please add _Deprecated to deprecated variables.
             */
            contract ProxyStorage {
                address public owner;
                address public pendingOwner;
            
                bool initialized;
            
                address balances_Deprecated;
                address allowances_Deprecated;
            
                uint256 _totalSupply;
            
                bool private paused_Deprecated = false;
                address private globalPause_Deprecated;
            
                uint256 public burnMin = 0;
                uint256 public burnMax = 0;
            
                address registry_Deprecated;
            
                string name_Deprecated;
                string symbol_Deprecated;
            
                uint256[] gasRefundPool_Deprecated;
                uint256 private redemptionAddressCount_Deprecated;
                uint256 minimumGasPriceForFutureRefunds_Deprecated;
            
                mapping(address => uint256) _balances;
                mapping(address => mapping(address => uint256)) _allowances;
                mapping(bytes32 => mapping(address => uint256)) attributes_Deprecated;
            
                // reward token storage
                mapping(address => address) finOps_Deprecated;
                mapping(address => mapping(address => uint256)) finOpBalances_Deprecated;
                mapping(address => uint256) finOpSupply_Deprecated;
            
                // true reward allocation
                // proportion: 1000 = 100%
                struct RewardAllocation {
                    uint256 proportion;
                    address finOp;
                }
                mapping(address => RewardAllocation[]) _rewardDistribution_Deprecated;
                uint256 maxRewardProportion_Deprecated = 1000;
            
                mapping(address => bool) isBlacklisted;
                mapping(address => bool) public canBurn;
            
                /* Additionally, we have several keccak-based storage locations.
                 * If you add more keccak-based storage mappings, such as mappings, you must document them here.
                 * If the length of the keccak input is the same as an existing mapping, it is possible there could be a preimage collision.
                 * A preimage collision can be used to attack the contract by treating one storage location as another,
                 * which would always be a critical issue.
                 * Carefully examine future keccak-based storage to ensure there can be no preimage collisions.
                 *******************************************************************************************************
                 ** length     input                                                         usage
                 *******************************************************************************************************
                 ** 19         "trueXXX.proxy.owner"                                         Proxy Owner
                 ** 27         "trueXXX.pending.proxy.owner"                                 Pending Proxy Owner
                 ** 28         "trueXXX.proxy.implementation"                                Proxy Implementation
                 ** 32         uint256(11)                                                   gasRefundPool_Deprecated
                 ** 64         uint256(address),uint256(14)                                  balanceOf
                 ** 64         uint256(address),keccak256(uint256(address),uint256(15))      allowance
                 ** 64         uint256(address),keccak256(bytes32,uint256(16))               attributes
                 **/
            }
            
            pragma solidity 0.6.10;
            
            /**
             * @title ClamableOwnable
             * @dev The ClamableOwnable contract is a copy of Claimable Contract by Zeppelin.
             * and provides basic authorization control functions. Inherits storage layout of
             * ProxyStorage.
             */
            contract ClaimableOwnable is ProxyStorage {
                /**
                 * @dev emitted when ownership is transferred
                 * @param previousOwner previous owner of this contract
                 * @param newOwner new owner of this contract
                 */
                event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
            
                /**
                 * @dev sets the original `owner` of the contract to the sender
                 * at construction. Must then be reinitialized
                 */
                constructor() public {
                    owner = msg.sender;
                    emit OwnershipTransferred(address(0), owner);
                }
            
                /**
                 * @dev Throws if called by any account other than the owner.
                 */
                modifier onlyOwner() {
                    require(msg.sender == owner, "only Owner");
                    _;
                }
            
                /**
                 * @dev Modifier throws if called by any account other than the pendingOwner.
                 */
                modifier onlyPendingOwner() {
                    require(msg.sender == pendingOwner, "only pending owner");
                    _;
                }
            
                /**
                 * @dev Allows the current owner to set the pendingOwner address.
                 * @param newOwner The address to transfer ownership to.
                 */
                function transferOwnership(address newOwner) public onlyOwner {
                    pendingOwner = newOwner;
                }
            
                /**
                 * @dev Allows the pendingOwner address to finalize the transfer.
                 */
                function claimOwnership() public onlyPendingOwner {
                    emit OwnershipTransferred(owner, pendingOwner);
                    owner = pendingOwner;
                    pendingOwner = address(0);
                }
            }
            
            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);
            
                /**
                 * @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);
            }
            
            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 Context {
                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;
                }
            }
            
            pragma solidity ^0.6.0;
            
            /**
             * @dev Wrappers over Solidity's arithmetic operations with added overflow
             * checks.
             *
             * Arithmetic operations in Solidity wrap on overflow. This can easily result
             * in bugs, because programmers usually assume that an overflow raises an
             * error, which is the standard behavior in high level programming languages.
             * `SafeMath` restores this intuition by reverting the transaction when an
             * operation overflows.
             *
             * Using this library instead of the unchecked operations eliminates an entire
             * class of bugs, so it's recommended to use it always.
             */
            library SafeMath {
                /**
                 * @dev Returns the addition of two unsigned integers, reverting on
                 * overflow.
                 *
                 * Counterpart to Solidity's `+` operator.
                 *
                 * Requirements:
                 *
                 * - Addition cannot overflow.
                 */
                function add(uint256 a, uint256 b) internal pure returns (uint256) {
                    uint256 c = a + b;
                    require(c >= a, "SafeMath: addition overflow");
            
                    return c;
                }
            
                /**
                 * @dev Returns the subtraction of two unsigned integers, reverting on
                 * overflow (when the result is negative).
                 *
                 * Counterpart to Solidity's `-` operator.
                 *
                 * Requirements:
                 *
                 * - Subtraction cannot overflow.
                 */
                function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                    return sub(a, b, "SafeMath: subtraction overflow");
                }
            
                /**
                 * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
                 * overflow (when the result is negative).
                 *
                 * Counterpart to Solidity's `-` operator.
                 *
                 * Requirements:
                 *
                 * - Subtraction cannot overflow.
                 */
                function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                    require(b <= a, errorMessage);
                    uint256 c = a - b;
            
                    return c;
                }
            
                /**
                 * @dev Returns the multiplication of two unsigned integers, reverting on
                 * overflow.
                 *
                 * Counterpart to Solidity's `*` operator.
                 *
                 * Requirements:
                 *
                 * - Multiplication cannot overflow.
                 */
                function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                    // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                    // benefit is lost if 'b' is also tested.
                    // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                    if (a == 0) {
                        return 0;
                    }
            
                    uint256 c = a * b;
                    require(c / a == b, "SafeMath: multiplication overflow");
            
                    return c;
                }
            
                /**
                 * @dev Returns the integer division of two unsigned integers. Reverts on
                 * division by zero. The result is rounded towards zero.
                 *
                 * Counterpart to Solidity's `/` operator. Note: this function uses a
                 * `revert` opcode (which leaves remaining gas untouched) while Solidity
                 * uses an invalid opcode to revert (consuming all remaining gas).
                 *
                 * Requirements:
                 *
                 * - The divisor cannot be zero.
                 */
                function div(uint256 a, uint256 b) internal pure returns (uint256) {
                    return div(a, b, "SafeMath: division by zero");
                }
            
                /**
                 * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
                 * division by zero. The result is rounded towards zero.
                 *
                 * Counterpart to Solidity's `/` operator. Note: this function uses a
                 * `revert` opcode (which leaves remaining gas untouched) while Solidity
                 * uses an invalid opcode to revert (consuming all remaining gas).
                 *
                 * Requirements:
                 *
                 * - The divisor cannot be zero.
                 */
                function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                    require(b > 0, errorMessage);
                    uint256 c = a / b;
                    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
            
                    return c;
                }
            
                /**
                 * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                 * Reverts when dividing by zero.
                 *
                 * Counterpart to Solidity's `%` operator. This function uses a `revert`
                 * opcode (which leaves remaining gas untouched) while Solidity uses an
                 * invalid opcode to revert (consuming all remaining gas).
                 *
                 * Requirements:
                 *
                 * - The divisor cannot be zero.
                 */
                function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                    return mod(a, b, "SafeMath: modulo by zero");
                }
            
                /**
                 * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                 * Reverts with custom message when dividing by zero.
                 *
                 * Counterpart to Solidity's `%` operator. This function uses a `revert`
                 * opcode (which leaves remaining gas untouched) while Solidity uses an
                 * invalid opcode to revert (consuming all remaining gas).
                 *
                 * Requirements:
                 *
                 * - The divisor cannot be zero.
                 */
                function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                    require(b != 0, errorMessage);
                    return a % b;
                }
            }
            
            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) {
                    // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
                    // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
                    // for accounts without code, i.e. `keccak256('')`
                    bytes32 codehash;
                    bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
                    // solhint-disable-next-line no-inline-assembly
                    assembly { codehash := extcodehash(account) }
                    return (codehash != accountHash && codehash != 0x0);
                }
            
                /**
                 * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                 * `recipient`, forwarding all available gas and reverting on errors.
                 *
                 * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                 * of certain opcodes, possibly making contracts go over the 2300 gas limit
                 * imposed by `transfer`, making them unable to receive funds via
                 * `transfer`. {sendValue} removes this limitation.
                 *
                 * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                 *
                 * IMPORTANT: because control is transferred to `recipient`, care must be
                 * taken to not create reentrancy vulnerabilities. Consider using
                 * {ReentrancyGuard} or the
                 * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                 */
                function sendValue(address payable recipient, uint256 amount) internal {
                    require(address(this).balance >= amount, "Address: insufficient balance");
            
                    // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                    (bool success, ) = recipient.call{ value: amount }("");
                    require(success, "Address: unable to send value, recipient may have reverted");
                }
            
                /**
                 * @dev Performs a Solidity function call using a low level `call`. A
                 * plain`call` is an unsafe replacement for a function call: use this
                 * function instead.
                 *
                 * If `target` reverts with a revert reason, it is bubbled up by this
                 * function (like regular Solidity function calls).
                 *
                 * Returns the raw returned data. To convert to the expected return value,
                 * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                 *
                 * Requirements:
                 *
                 * - `target` must be a contract.
                 * - calling `target` with `data` must not revert.
                 *
                 * _Available since v3.1._
                 */
                function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                    return functionCall(target, data, "Address: low-level call failed");
                }
            
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                 * `errorMessage` as a fallback revert reason when `target` reverts.
                 *
                 * _Available since v3.1._
                 */
                function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                    return _functionCallWithValue(target, data, 0, errorMessage);
                }
            
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but also transferring `value` wei to `target`.
                 *
                 * Requirements:
                 *
                 * - the calling contract must have an ETH balance of at least `value`.
                 * - the called Solidity function must be `payable`.
                 *
                 * _Available since v3.1._
                 */
                function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                    return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                }
            
                /**
                 * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                 * with `errorMessage` as a fallback revert reason when `target` reverts.
                 *
                 * _Available since v3.1._
                 */
                function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
                    require(address(this).balance >= value, "Address: insufficient balance for call");
                    return _functionCallWithValue(target, data, value, errorMessage);
                }
            
                function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
                    require(isContract(target), "Address: call to non-contract");
            
                    // solhint-disable-next-line avoid-low-level-calls
                    (bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
                    if (success) {
                        return returndata;
                    } else {
                        // Look for revert reason and bubble it up if present
                        if (returndata.length > 0) {
                            // The easiest way to bubble the revert reason is using memory via assembly
            
                            // solhint-disable-next-line no-inline-assembly
                            assembly {
                                let returndata_size := mload(returndata)
                                revert(add(32, returndata), returndata_size)
                            }
                        } else {
                            revert(errorMessage);
                        }
                    }
                }
            }
            
            /**
             * @notice This is a copy of openzeppelin ERC20 contract with removed state variables.
             * Removing state variables has been necessary due to proxy pattern usage.
             * Changes to Openzeppelin ERC20 https://github.com/OpenZeppelin/openzeppelin-contracts/blob/de99bccbfd4ecd19d7369d01b070aa72c64423c9/contracts/token/ERC20/ERC20.sol:
             * - Remove state variables _name, _symbol, _decimals
             * - Use state variables _balances, _allowances, _totalSupply from ProxyStorage
             * - Remove constructor
             * - Solidity version changed from ^0.6.0 to 0.6.10
             * - Contract made abstract
             *
             * See also: ClaimableOwnable.sol and ProxyStorage.sol
             */
            
            pragma solidity 0.6.10;
            
            /**
             * @dev Implementation of the {IERC20} interface.
             *
             * This implementation is agnostic to the way tokens are created. This means
             * that a supply mechanism has to be added in a derived contract using {_mint}.
             * For a generic mechanism see {ERC20PresetMinterPauser}.
             *
             * TIP: For a detailed writeup see our guide
             * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
             * to implement supply mechanisms].
             *
             * We have followed general OpenZeppelin guidelines: functions revert instead
             * of returning `false` on failure. This behavior is nonetheless conventional
             * and does not conflict with the expectations of ERC20 applications.
             *
             * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
             * This allows applications to reconstruct the allowance for all accounts just
             * by listening to said events. Other implementations of the EIP may not emit
             * these events, as it isn't required by the specification.
             *
             * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
             * functions have been added to mitigate the well-known issues around setting
             * allowances. See {IERC20-approve}.
             */
            abstract contract ERC20 is ClaimableOwnable, Context, IERC20 {
                using SafeMath for uint256;
                using Address for address;
            
                /**
                 * @dev Returns the name of the token.
                 */
                function name() public virtual pure returns (string memory);
            
                /**
                 * @dev Returns the symbol of the token, usually a shorter version of the
                 * name.
                 */
                function symbol() public virtual pure returns (string memory);
            
                /**
                 * @dev Returns the number of decimals used to get its user representation.
                 * For example, if `decimals` equals `2`, a balance of `505` tokens should
                 * be displayed to a user as `5,05` (`505 / 10 ** 2`).
                 *
                 * Tokens usually opt for a value of 18, imitating the relationship between
                 * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
                 * called.
                 *
                 * NOTE: This information is only used for _display_ purposes: it in
                 * no way affects any of the arithmetic of the contract, including
                 * {IERC20-balanceOf} and {IERC20-transfer}.
                 */
                function decimals() public virtual pure returns (uint8) {
                    return 18;
                }
            
                /**
                 * @dev See {IERC20-totalSupply}.
                 */
                function totalSupply() public view virtual override returns (uint256) {
                    return _totalSupply;
                }
            
                /**
                 * @dev See {IERC20-balanceOf}.
                 */
                function balanceOf(address account) public view virtual override returns (uint256) {
                    return _balances[account];
                }
            
                /**
                 * @dev See {IERC20-transfer}.
                 *
                 * Requirements:
                 *
                 * - `recipient` cannot be the zero address.
                 * - the caller must have a balance of at least `amount`.
                 */
                function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
                    _transfer(_msgSender(), recipient, amount);
                    return true;
                }
            
                /**
                 * @dev See {IERC20-allowance}.
                 */
                function allowance(address owner, address spender) public view virtual override returns (uint256) {
                    return _allowances[owner][spender];
                }
            
                /**
                 * @dev See {IERC20-approve}.
                 *
                 * Requirements:
                 *
                 * - `spender` cannot be the zero address.
                 */
                function approve(address spender, uint256 amount) public virtual override returns (bool) {
                    _approve(_msgSender(), spender, amount);
                    return true;
                }
            
                /**
                 * @dev See {IERC20-transferFrom}.
                 *
                 * Emits an {Approval} event indicating the updated allowance. This is not
                 * required by the EIP. See the note at the beginning of {ERC20};
                 *
                 * Requirements:
                 * - `sender` and `recipient` cannot be the zero address.
                 * - `sender` must have a balance of at least `amount`.
                 * - the caller must have allowance for ``sender``'s tokens of at least
                 * `amount`.
                 */
                function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
                    _transfer(sender, recipient, amount);
                    _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
                    return true;
                }
            
                /**
                 * @dev Atomically increases the allowance granted to `spender` by the caller.
                 *
                 * This is an alternative to {approve} that can be used as a mitigation for
                 * problems described in {IERC20-approve}.
                 *
                 * Emits an {Approval} event indicating the updated allowance.
                 *
                 * Requirements:
                 *
                 * - `spender` cannot be the zero address.
                 */
                function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
                    _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
                    return true;
                }
            
                /**
                 * @dev Atomically decreases the allowance granted to `spender` by the caller.
                 *
                 * This is an alternative to {approve} that can be used as a mitigation for
                 * problems described in {IERC20-approve}.
                 *
                 * Emits an {Approval} event indicating the updated allowance.
                 *
                 * Requirements:
                 *
                 * - `spender` cannot be the zero address.
                 * - `spender` must have allowance for the caller of at least
                 * `subtractedValue`.
                 */
                function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
                    _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
                    return true;
                }
            
                /**
                 * @dev Moves tokens `amount` from `sender` to `recipient`.
                 *
                 * This is internal function is equivalent to {transfer}, and can be used to
                 * e.g. implement automatic token fees, slashing mechanisms, etc.
                 *
                 * Emits a {Transfer} event.
                 *
                 * Requirements:
                 *
                 * - `sender` cannot be the zero address.
                 * - `recipient` cannot be the zero address.
                 * - `sender` must have a balance of at least `amount`.
                 */
                function _transfer(address sender, address recipient, uint256 amount) internal virtual {
                    require(sender != address(0), "ERC20: transfer from the zero address");
                    require(recipient != address(0), "ERC20: transfer to the zero address");
            
                    _beforeTokenTransfer(sender, recipient, amount);
            
                    _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
                    _balances[recipient] = _balances[recipient].add(amount);
                    emit Transfer(sender, recipient, amount);
                }
            
                /** @dev Creates `amount` tokens and assigns them to `account`, increasing
                 * the total supply.
                 *
                 * Emits a {Transfer} event with `from` set to the zero address.
                 *
                 * Requirements
                 *
                 * - `to` cannot be the zero address.
                 */
                function _mint(address account, uint256 amount) internal virtual {
                    require(account != address(0), "ERC20: mint to the zero address");
            
                    _beforeTokenTransfer(address(0), account, amount);
            
                    _totalSupply = _totalSupply.add(amount);
                    _balances[account] = _balances[account].add(amount);
                    emit Transfer(address(0), account, amount);
                }
            
                /**
                 * @dev Destroys `amount` tokens from `account`, reducing the
                 * total supply.
                 *
                 * Emits a {Transfer} event with `to` set to the zero address.
                 *
                 * Requirements
                 *
                 * - `account` cannot be the zero address.
                 * - `account` must have at least `amount` tokens.
                 */
                function _burn(address account, uint256 amount) internal virtual {
                    require(account != address(0), "ERC20: burn from the zero address");
            
                    _beforeTokenTransfer(account, address(0), amount);
            
                    _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
                    _totalSupply = _totalSupply.sub(amount);
                    emit Transfer(account, address(0), amount);
                }
            
                /**
                 * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
                 *
                 * This is internal function is equivalent to `approve`, and can be used to
                 * e.g. set automatic allowances for certain subsystems, etc.
                 *
                 * Emits an {Approval} event.
                 *
                 * Requirements:
                 *
                 * - `owner` cannot be the zero address.
                 * - `spender` cannot be the zero address.
                 */
                function _approve(address owner, address spender, uint256 amount) internal virtual {
                    require(owner != address(0), "ERC20: approve from the zero address");
                    require(spender != address(0), "ERC20: approve to the zero address");
            
                    _allowances[owner][spender] = amount;
                    emit Approval(owner, spender, amount);
                }
            
                /**
                 * @dev Hook that is called before any transfer of tokens. This includes
                 * minting and burning.
                 *
                 * Calling conditions:
                 *
                 * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
                 * will be to transferred to `to`.
                 * - when `from` is zero, `amount` tokens will be minted for `to`.
                 * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
                 * - `from` and `to` are never both zero.
                 *
                 * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
                 */
                // solhint-disable-next-line no-empty-blocks
                function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
            }
            
            pragma solidity 0.6.10;
            
            /**
             * @title ReclaimerToken
             * @dev ERC20 token which allows owner to reclaim ERC20 tokens
             * or ether sent to this contract
             */
            abstract contract ReclaimerToken is ERC20 {
                /**
                 * @dev send all eth balance in the contract to another address
                 * @param _to address to send eth balance to
                 */
                function reclaimEther(address payable _to) external onlyOwner {
                    _to.transfer(address(this).balance);
                }
            
                /**
                 * @dev send all token balance of an arbitrary erc20 token
                 * in the contract to another address
                 * @param token token to reclaim
                 * @param _to address to send eth balance to
                 */
                function reclaimToken(IERC20 token, address _to) external onlyOwner {
                    uint256 balance = token.balanceOf(address(this));
                    token.transfer(_to, balance);
                }
            }
            
            pragma solidity 0.6.10;
            
            /**
             * @title BurnableTokenWithBounds
             * @dev Burning functions as redeeming money from the system.
             * The platform will keep track of who burns coins,
             * and will send them back the equivalent amount of money (rounded down to the nearest cent).
             */
            abstract contract BurnableTokenWithBounds is ReclaimerToken {
                /**
                 * @dev Emitted when `value` tokens are burnt from one account (`burner`)
                 * @param burner address which burned tokens
                 * @param value amount of tokens burned
                 */
                event Burn(address indexed burner, uint256 value);
            
                /**
                 * @dev Emitted when new burn bounds were set
                 * @param newMin new minimum burn amount
                 * @param newMax new maximum burn amount
                 * @notice `newMin` should never be greater than `newMax`
                 */
                event SetBurnBounds(uint256 newMin, uint256 newMax);
            
                /**
                 * @dev Destroys `amount` tokens from `msg.sender`, reducing the
                 * total supply.
                 * @param amount amount of tokens to burn
                 *
                 * Emits a {Transfer} event with `to` set to the zero address.
                 * Emits a {Burn} event with `burner` set to `msg.sender`
                 *
                 * Requirements
                 *
                 * - `msg.sender` must have at least `amount` tokens.
                 *
                 */
                function burn(uint256 amount) external {
                    _burn(msg.sender, amount);
                }
            
                /**
                 * @dev Change the minimum and maximum amount that can be burned at once.
                 * Burning may be disabled by setting both to 0 (this will not be done
                 * under normal operation, but we can't add checks to disallow it without
                 * losing a lot of flexibility since burning could also be as good as disabled
                 * by setting the minimum extremely high, and we don't want to lock
                 * in any particular cap for the minimum)
                 * @param _min minimum amount that can be burned at once
                 * @param _max maximum amount that can be burned at once
                 */
                function setBurnBounds(uint256 _min, uint256 _max) external onlyOwner {
                    require(_min <= _max, "BurnableTokenWithBounds: min > max");
                    burnMin = _min;
                    burnMax = _max;
                    emit SetBurnBounds(_min, _max);
                }
            
                /**
                 * @dev Checks if amount is within allowed burn bounds and
                 * destroys `amount` tokens from `account`, reducing the
                 * total supply.
                 * @param account account to burn tokens for
                 * @param amount amount of tokens to burn
                 *
                 * Emits a {Burn} event
                 */
                function _burn(address account, uint256 amount) internal virtual override {
                    require(amount >= burnMin, "BurnableTokenWithBounds: below min burn bound");
                    require(amount <= burnMax, "BurnableTokenWithBounds: exceeds max burn bound");
            
                    super._burn(account, amount);
                    emit Burn(account, amount);
                }
            }
            
            pragma solidity 0.6.10;
            
            /**
             * @title TrueCurrency
             * @dev TrueCurrency is an ERC20 with blacklist & redemption addresses
             *
             * TrueCurrency is a compliant stablecoin with blacklist and redemption
             * addresses. Only the owner can blacklist accounts. Redemption addresses
             * are assigned automatically to the first 0x100000 addresses. Sending
             * tokens to the redemption address will trigger a burn operation. Only
             * the owner can mint or blacklist accounts.
             *
             * This contract is owned by the TokenController, which manages token
             * minting & admin functionality. See TokenController.sol
             *
             * See also: BurnableTokenWithBounds.sol
             *
             * ~~~~ Features ~~~~
             *
             * Redemption Addresses
             * - The first 0x100000 addresses are redemption addresses
             * - Tokens sent to redemption addresses are burned
             * - Redemptions are tracked off-chain
             * - Cannot mint tokens to redemption addresses
             *
             * Blacklist
             * - Owner can blacklist accounts in accordance with local regulatory bodies
             * - Only a court order will merit a blacklist; blacklisting is extremely rare
             *
             * Burn Bounds & CanBurn
             * - Owner can set min & max burn amounts
             * - Only accounts flagged in canBurn are allowed to burn tokens
             * - canBurn prevents tokens from being sent to the incorrect address
             *
             * Reclaimer Token
             * - ERC20 Tokens and Ether sent to this contract can be reclaimed by the owner
             */
            abstract contract TrueCurrency is BurnableTokenWithBounds {
                uint256 constant CENT = 10**16;
                uint256 constant REDEMPTION_ADDRESS_COUNT = 0x100000;
            
                /**
                 * @dev Emitted when account blacklist status changes
                 */
                event Blacklisted(address indexed account, bool isBlacklisted);
            
                /**
                 * @dev Emitted when `value` tokens are minted for `to`
                 * @param to address to mint tokens for
                 * @param value amount of tokens to be minted
                 */
                event Mint(address indexed to, uint256 value);
            
                /**
                 * @dev Creates `amount` tokens and assigns them to `account`, increasing
                 * the total supply.
                 * @param account address to mint tokens for
                 * @param amount amount of tokens to be minted
                 *
                 * Emits a {Mint} event
                 *
                 * Requirements
                 *
                 * - `account` cannot be the zero address.
                 * - `account` cannot be blacklisted.
                 * - `account` cannot be a redemption address.
                 */
                function mint(address account, uint256 amount) external onlyOwner {
                    require(!isBlacklisted[account], "TrueCurrency: account is blacklisted");
                    require(!isRedemptionAddress(account), "TrueCurrency: account is a redemption address");
                    _mint(account, amount);
                    emit Mint(account, amount);
                }
            
                /**
                 * @dev Set blacklisted status for the account.
                 * @param account address to set blacklist flag for
                 * @param _isBlacklisted blacklist flag value
                 *
                 * Requirements:
                 *
                 * - `msg.sender` should be owner.
                 */
                function setBlacklisted(address account, bool _isBlacklisted) external onlyOwner {
                    require(uint256(account) >= REDEMPTION_ADDRESS_COUNT, "TrueCurrency: blacklisting of redemption address is not allowed");
                    isBlacklisted[account] = _isBlacklisted;
                    emit Blacklisted(account, _isBlacklisted);
                }
            
                /**
                 * @dev Set canBurn status for the account.
                 * @param account address to set canBurn flag for
                 * @param _canBurn canBurn flag value
                 *
                 * Requirements:
                 *
                 * - `msg.sender` should be owner.
                 */
                function setCanBurn(address account, bool _canBurn) external onlyOwner {
                    canBurn[account] = _canBurn;
                }
            
                /**
                 * @dev Check if neither account is blacklisted before performing transfer
                 * If transfer recipient is a redemption address, burns tokens
                 * @notice Transfer to redemption address will burn tokens with a 1 cent precision
                 * @param sender address of sender
                 * @param recipient address of recipient
                 * @param amount amount of tokens to transfer
                 */
                function _transfer(
                    address sender,
                    address recipient,
                    uint256 amount
                ) internal virtual override {
                    require(!isBlacklisted[sender], "TrueCurrency: sender is blacklisted");
                    require(!isBlacklisted[recipient], "TrueCurrency: recipient is blacklisted");
            
                    if (isRedemptionAddress(recipient)) {
                        super._transfer(sender, recipient, amount.sub(amount.mod(CENT)));
                        _burn(recipient, amount.sub(amount.mod(CENT)));
                    } else {
                        super._transfer(sender, recipient, amount);
                    }
                }
            
                /**
                 * @dev Requere neither accounts to be blacklisted before approval
                 * @param owner address of owner giving approval
                 * @param spender address of spender to approve for
                 * @param amount amount of tokens to approve
                 */
                function _approve(
                    address owner,
                    address spender,
                    uint256 amount
                ) internal override {
                    require(!isBlacklisted[owner], "TrueCurrency: tokens owner is blacklisted");
                    require(!isBlacklisted[spender] || amount == 0, "TrueCurrency: tokens spender is blacklisted");
            
                    super._approve(owner, spender, amount);
                }
            
                /**
                 * @dev Check if tokens can be burned at address before burning
                 * @param account account to burn tokens from
                 * @param amount amount of tokens to burn
                 */
                function _burn(address account, uint256 amount) internal override {
                    require(canBurn[account], "TrueCurrency: cannot burn from this address");
                    super._burn(account, amount);
                }
            
                /**
                 * @dev First 0x100000-1 addresses (0x0000000000000000000000000000000000000001 to 0x00000000000000000000000000000000000fffff)
                 * are the redemption addresses.
                 * @param account address to check is a redemption address
                 *
                 * All transfers to redemption address will trigger token burn.
                 *
                 * @notice For transfer to succeed, canBurn must be true for redemption address
                 *
                 * @return is `account` a redemption address
                 */
                function isRedemptionAddress(address account) internal pure returns (bool) {
                    return uint256(account) < REDEMPTION_ADDRESS_COUNT && uint256(account) != 0;
                }
            }
            
            pragma solidity 0.6.10;
            
            /**
             * @title DelegateERC20
             * Accept forwarding delegation calls from the old TrueUSD (V1) contract.
             * This way the all the ERC20 functions in the old contract still works
             * (except Burn).
             *
             * The original contract is at 0x8dd5fbCe2F6a956C3022bA3663759011Dd51e73E.
             * Lines 497-574 on-chain call these delegate functions to forward calls
             * This gives the delegate contract the power to change the state of the TrueUSD
             * contract. The owner of this contract is the TrueUSD TokenController
             * at 0x0000000000075efbee23fe2de1bd0b7690883cc9.
             *
             * Our audits for TrueCurrency can be found here: github.com/trusttoken/audits
             */
            abstract contract DelegateERC20 is TrueCurrency {
                // require msg.sender is the delegate smart contract
                modifier onlyDelegateFrom() {
                    revert("DelegateERC20: TrueUSD (V1) is not supported");
                    _;
                }
            
                /**
                 * @dev Delegate call to get total supply
                 * @return Total supply
                 */
                function delegateTotalSupply() public view returns (uint256) {
                    return totalSupply();
                }
            
                /**
                 * @dev Delegate call to get balance
                 * @param who Address to get balance for
                 * @return balance of account
                 */
                function delegateBalanceOf(address who) public view returns (uint256) {
                    return balanceOf(who);
                }
            
                /**
                 * @dev Delegate call to transfer
                 * @param to address to transfer to
                 * @param value amount to transfer
                 * @param origSender original msg.sender on delegate contract
                 * @return success
                 */
                function delegateTransfer(
                    address to,
                    uint256 value,
                    address origSender
                ) public onlyDelegateFrom returns (bool) {
                    _transfer(origSender, to, value);
                    return true;
                }
            
                /**
                 * @dev Delegate call to get allowance
                 * @param owner account owner
                 * @param spender account to check allowance for
                 * @return allowance
                 */
                function delegateAllowance(address owner, address spender) public view returns (uint256) {
                    return allowance(owner, spender);
                }
            
                /**
                 * @dev Delegate call to transfer from
                 * @param from account to transfer funds from
                 * @param to account to transfer funds to
                 * @param value value to transfer
                 * @param origSender original msg.sender on delegate contract
                 * @return success
                 */
                function delegateTransferFrom(
                    address from,
                    address to,
                    uint256 value,
                    address origSender
                ) public onlyDelegateFrom returns (bool) {
                    // ERC20 transferFrom with _msgSender() replaced by origSender
                    _transfer(from, to, value);
                    _approve(from, origSender, _allowances[from][origSender].sub(value, "ERC20: transfer amount exceeds allowance"));
                    return true;
                }
            
                /**
                 * @dev Delegate call to approve
                 * @param spender account to approve for
                 * @param value amount to approve
                 * @param origSender original msg.sender on delegate contract
                 * @return success
                 */
                function delegateApprove(
                    address spender,
                    uint256 value,
                    address origSender
                ) public onlyDelegateFrom returns (bool) {
                    _approve(origSender, spender, value);
                    return true;
                }
            
                /**
                 * @dev Delegate call to increase approval
                 * @param spender account to increase approval for
                 * @param addedValue amount of approval to add
                 * @param origSender original msg.sender on delegate contract
                 * @return success
                 */
                function delegateIncreaseApproval(
                    address spender,
                    uint256 addedValue,
                    address origSender
                ) public onlyDelegateFrom returns (bool) {
                    // ERC20 increaseAllowance() with _msgSender() replaced by origSender
                    _approve(origSender, spender, _allowances[origSender][spender].add(addedValue));
                    return true;
                }
            
                /**
                 * @dev Delegate call to decrease approval
                 * @param spender spender to decrease approval for
                 * @param subtractedValue value to subtract from approval
                 * @param origSender original msg.sender on delegate contract
                 * @return success
                 */
                function delegateDecreaseApproval(
                    address spender,
                    uint256 subtractedValue,
                    address origSender
                ) public onlyDelegateFrom returns (bool) {
                    // ERC20 decreaseAllowance() with _msgSender() replaced by origSender
                    _approve(origSender, spender, _allowances[origSender][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
                    return true;
                }
            }
            
            pragma solidity 0.6.10;
            
            /**
             * @dev Contract that prevents addresses that were previously using autosweep addresses from
             * making transfers on them.
             *
             * In older versions TrueCurrencies had a feature called Autosweep.
             * Given a single deposit address, it was possible to generate 16^5-1 autosweep addresses.
             * E.g. having deposit address 0xc257274276a4e539741ca11b590b9447b26a8051, you could generate
             * - 0xc257274276a4e539741ca11b590b9447b2600000
             * - 0xc257274276a4e539741ca11b590b9447b2600001
             * - ...
             * - 0xc257274276a4e539741ca11b590b9447b26fffff
             * Every transfer to an autosweep address resulted as a transfer to deposit address.
             * This feature got deprecated, but there were 4 addresses that still actively using the feature.
             *
             * This contract will reject a transfer to these 4*(16^5-1) addresses to prevent accidental token freeze.
             */
            abstract contract TrueCurrencyWithLegacyAutosweep is DelegateERC20 {
                function _transfer(
                    address sender,
                    address recipient,
                    uint256 amount
                ) internal override {
                    requireNotAutosweepAddress(recipient, 0x33091DE8341533468D13A80C5A670f4f47cC649f);
                    requireNotAutosweepAddress(recipient, 0x50E2719208914764087e68C32bC5AaC321f5B04d);
                    requireNotAutosweepAddress(recipient, 0x71d69e5481A9B7Be515E20B38a3f62Dab7170D78);
                    requireNotAutosweepAddress(recipient, 0x90fdaA85D52dB6065D466B86f16bF840D514a488);
            
                    super._transfer(sender, recipient, amount);
                }
            
                function requireNotAutosweepAddress(address recipient, address depositAddress) internal pure {
                    return
                      require(uint256(recipient) >> 20 != uint256(depositAddress) >> 20 || recipient == depositAddress, "Autosweep is disabled");
                }
            }
            
            pragma solidity 0.6.10;
            
            /**
             * @title TrueUSD
             * @dev This is the top-level ERC20 contract, but most of the interesting functionality is
             * inherited - see the documentation on the corresponding contracts.
             */
            contract TrueUSD is TrueCurrencyWithLegacyAutosweep {
                uint8 constant DECIMALS = 18;
                uint8 constant ROUNDING = 2;
            
                function decimals() public override pure returns (uint8) {
                    return DECIMALS;
                }
            
                function rounding() public pure returns (uint8) {
                    return ROUNDING;
                }
            
                function name() public override pure returns (string memory) {
                    return "TrueUSD";
                }
            
                function symbol() public override pure returns (string memory) {
                    return "TUSD";
                }
            }