Transaction Hash:
Block:
11956983 at Mar-02-2021 05:42:15 AM +UTC
Transaction Fee:
0.00557645 ETH
$14.13
Gas Used:
40,556 Gas / 137.5 Gwei
Emitted Events:
100 |
OwnedUpgradeabilityProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000f6555354957162f6cc9a7c91d9f4df141ed1edb3, 0x00000000000000000000000003488fe5391731b975a6e2cec37e0346cf59379b, 00000000000000000000000000000000000000000000017a85a7302cf43df000 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x00000000...ecd22b376 | |||||
0x5A0b54D5...D3E029c4c
Miner
| (Spark Pool) | 28.319875466796227022 Eth | 28.325451916796227022 Eth | 0.00557645 | |
0xF6555354...41ed1eDb3 |
0.456498089959029 Eth
Nonce: 12
|
0.450921639959029 Eth
Nonce: 13
| 0.00557645 |
Execution Trace
OwnedUpgradeabilityProxy.a9059cbb( )

-
TrueUSD.transfer( recipient=0x03488fE5391731B975a6E2ceC37E0346CF59379B, amount=6982499979160000000000 ) => ( True )
transfer[ERC20 (ln:632)]
_transfer[ERC20 (ln:633)]
_beforeTokenTransfer[ERC20 (ln:728)]
sub[ERC20 (ln:730)]
add[ERC20 (ln:731)]
Transfer[ERC20 (ln:732)]
_msgSender[ERC20 (ln:633)]
File 1 of 2: OwnedUpgradeabilityProxy
File 2 of 2: TrueUSD
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
/** * :::==== :::==== ::: === :::===== ::: === :::=== :::==== * :::==== ::: === ::: === ::: ::: === ::: ::: === * === ======= === === ====== === === ===== === === * === === === === === === === === === === === * === === === ====== ======== ====== ====== ======= */ 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 { address constant DELEGATE_FROM = 0x8dd5fbCe2F6a956C3022bA3663759011Dd51e73E; // require msg.sender is the delegate smart contract modifier onlyDelegateFrom() { require(msg.sender == DELEGATE_FROM); _; } /** * @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"; } }