Transaction Hash:
Block:
8655207 at Oct-01-2019 07:39:34 AM +UTC
Transaction Fee:
0.000442215 ETH
$1.12
Gas Used:
29,481 Gas / 15 Gwei
Emitted Events:
137 |
OwnedUpgradeabilityProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000d26a4d3ce34eef62a5eacc1f07b6e4ed11d0d516, 0x000000000000000000000000cff21a4cb1ca02504d86d406c16cb270a018bdd0, 00000000000000000000000000000000000000000000000010256dc90c98f346 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x00000000...ecd22b376 | |||||
0x09ab1303...240c70294
Miner
| (Minerall Pool) | 649.15755499289962221 Eth | 649.15799720789962221 Eth | 0.000442215 | |
0xD26A4D3C...d11d0d516 |
30.973617175340133136 Eth
Nonce: 839
|
30.973174960340133136 Eth
Nonce: 840
| 0.000442215 |
Execution Trace
TrueUSD.transfer( to=0xcFF21a4cB1cA02504d86d406c16cB270a018BDD0, value=1163456789012345670 ) => ( True )

OwnedUpgradeabilityProxy.9cd1a121( )
-
TrueUSD.delegateTransfer( to=0xcFF21a4cB1cA02504d86d406c16cB270a018BDD0, value=1163456789012345670, origSender=0xD26A4D3Ce34EeF62a5eaCC1f07B6e4Ed11d0d516 ) => ( True )
-
transfer[ERC20Basic (ln:293)]
File 1 of 3: TrueUSD
File 2 of 3: OwnedUpgradeabilityProxy
File 3 of 3: TrueUSD
pragma solidity ^0.4.18; contract DelegateERC20 { function delegateTotalSupply() public view returns (uint256); function delegateBalanceOf(address who) public view returns (uint256); function delegateTransfer(address to, uint256 value, address origSender) public returns (bool); function delegateAllowance(address owner, address spender) public view returns (uint256); function delegateTransferFrom(address from, address to, uint256 value, address origSender) public returns (bool); function delegateApprove(address spender, uint256 value, address origSender) public returns (bool); function delegateIncreaseApproval(address spender, uint addedValue, address origSender) public returns (bool); function delegateDecreaseApproval(address spender, uint subtractedValue, address origSender) public returns (bool); } library SafeMath { /** * @dev Multiplies two numbers, throws on overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; } uint256 c = a * b; assert(c / a == b); return c; } /** * @dev Integer division of two numbers, truncating the quotient. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // assert(b > 0); // Solidity automatically throws when dividing by 0 uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { assert(b <= a); return a - b; } /** * @dev Adds two numbers, throws on overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; assert(c >= a); return c; } } contract Ownable { address public owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ function Ownable() public { owner = msg.sender; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(msg.sender == owner); _; } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function transferOwnership(address newOwner) public onlyOwner { require(newOwner != address(0)); OwnershipTransferred(owner, newOwner); owner = newOwner; } } contract Pausable is Ownable { event Pause(); event Unpause(); bool public paused = false; /** * @dev Modifier to make a function callable only when the contract is not paused. */ modifier whenNotPaused() { require(!paused); _; } /** * @dev Modifier to make a function callable only when the contract is paused. */ modifier whenPaused() { require(paused); _; } /** * @dev called by the owner to pause, triggers stopped state */ function pause() onlyOwner whenNotPaused public { paused = true; Pause(); } /** * @dev called by the owner to unpause, returns to normal state */ function unpause() onlyOwner whenPaused public { paused = false; Unpause(); } } contract CanReclaimToken is Ownable { using SafeERC20 for ERC20Basic; /** * @dev Reclaim all ERC20Basic compatible tokens * @param token ERC20Basic The address of the token contract */ function reclaimToken(ERC20Basic token) external onlyOwner { uint256 balance = token.balanceOf(this); token.safeTransfer(owner, balance); } } contract Claimable is Ownable { address public pendingOwner; /** * @dev Modifier throws if called by any account other than the pendingOwner. */ modifier onlyPendingOwner() { require(msg.sender == pendingOwner); _; } /** * @dev Allows the current owner to set the pendingOwner address. * @param newOwner The address to transfer ownership to. */ function transferOwnership(address newOwner) onlyOwner public { pendingOwner = newOwner; } /** * @dev Allows the pendingOwner address to finalize the transfer. */ function claimOwnership() onlyPendingOwner public { OwnershipTransferred(owner, pendingOwner); owner = pendingOwner; pendingOwner = address(0); } } contract AddressList is Claimable { string public name; mapping (address => bool) public onList; function AddressList(string _name, bool nullValue) public { name = _name; onList[0x0] = nullValue; } event ChangeWhiteList(address indexed to, bool onList); // Set whether _to is on the list or not. Whether 0x0 is on the list // or not cannot be set here - it is set once and for all by the constructor. function changeList(address _to, bool _onList) onlyOwner public { require(_to != 0x0); if (onList[_to] != _onList) { onList[_to] = _onList; ChangeWhiteList(_to, _onList); } } } contract HasNoContracts is Ownable { /** * @dev Reclaim ownership of Ownable contracts * @param contractAddr The address of the Ownable to be reclaimed. */ function reclaimContract(address contractAddr) external onlyOwner { Ownable contractInst = Ownable(contractAddr); contractInst.transferOwnership(owner); } } contract HasNoEther is Ownable { /** * @dev Constructor that rejects incoming Ether * @dev The `payable` flag is added so we can access `msg.value` without compiler warning. If we * leave out payable, then Solidity will allow inheriting contracts to implement a payable * constructor. By doing it this way we prevent a payable constructor from working. Alternatively * we could use assembly to access msg.value. */ function HasNoEther() public payable { require(msg.value == 0); } /** * @dev Disallows direct send by settings a default function without the `payable` flag. */ function() external { } /** * @dev Transfer all Ether held by the contract to the owner. */ function reclaimEther() external onlyOwner { assert(owner.send(this.balance)); } } contract HasNoTokens is CanReclaimToken { /** * @dev Reject all ERC223 compatible tokens * @param from_ address The address that is transferring the tokens * @param value_ uint256 the amount of the specified token * @param data_ Bytes The data passed from the caller. */ function tokenFallback(address from_, uint256 value_, bytes data_) external { from_; value_; data_; revert(); } } contract NoOwner is HasNoEther, HasNoTokens, HasNoContracts { } contract AllowanceSheet is Claimable { using SafeMath for uint256; mapping (address => mapping (address => uint256)) public allowanceOf; function addAllowance(address tokenHolder, address spender, uint256 value) public onlyOwner { allowanceOf[tokenHolder][spender] = allowanceOf[tokenHolder][spender].add(value); } function subAllowance(address tokenHolder, address spender, uint256 value) public onlyOwner { allowanceOf[tokenHolder][spender] = allowanceOf[tokenHolder][spender].sub(value); } function setAllowance(address tokenHolder, address spender, uint256 value) public onlyOwner { allowanceOf[tokenHolder][spender] = value; } } contract BalanceSheet is Claimable { using SafeMath for uint256; mapping (address => uint256) public balanceOf; function addBalance(address addr, uint256 value) public onlyOwner { balanceOf[addr] = balanceOf[addr].add(value); } function subBalance(address addr, uint256 value) public onlyOwner { balanceOf[addr] = balanceOf[addr].sub(value); } function setBalance(address addr, uint256 value) public onlyOwner { balanceOf[addr] = value; } } contract ERC20Basic { function totalSupply() public view returns (uint256); function balanceOf(address who) public view returns (uint256); function transfer(address to, uint256 value) public returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); } contract BasicToken is ERC20Basic, Claimable { using SafeMath for uint256; BalanceSheet public balances; uint256 totalSupply_; function setBalanceSheet(address sheet) external onlyOwner { balances = BalanceSheet(sheet); balances.claimOwnership(); } /** * @dev total number of tokens in existence */ function totalSupply() public view returns (uint256) { return totalSupply_; } /** * @dev transfer token for a specified address * @param _to The address to transfer to. * @param _value The amount to be transferred. */ function transfer(address _to, uint256 _value) public returns (bool) { transferAllArgsNoAllowance(msg.sender, _to, _value); return true; } function transferAllArgsNoAllowance(address _from, address _to, uint256 _value) internal { require(_to != address(0)); require(_from != address(0)); require(_value <= balances.balanceOf(_from)); // SafeMath.sub will throw if there is not enough balance. balances.subBalance(_from, _value); balances.addBalance(_to, _value); Transfer(_from, _to, _value); } /** * @dev Gets the balance of the specified address. * @param _owner The address to query the the balance of. * @return An uint256 representing the amount owned by the passed address. */ function balanceOf(address _owner) public view returns (uint256 balance) { return balances.balanceOf(_owner); } } contract BurnableToken is BasicToken { event Burn(address indexed burner, uint256 value); /** * @dev Burns a specific amount of tokens. * @param _value The amount of token to be burned. */ function burn(uint256 _value) public { require(_value <= balances.balanceOf(msg.sender)); // no need to require value <= totalSupply, since that would imply the // sender's balance is greater than the totalSupply, which *should* be an assertion failure address burner = msg.sender; balances.subBalance(burner, _value); totalSupply_ = totalSupply_.sub(_value); Burn(burner, _value); Transfer(burner, address(0), _value); } } contract ERC20 is ERC20Basic { function allowance(address owner, address spender) public view returns (uint256); function transferFrom(address from, address to, uint256 value) public returns (bool); function approve(address spender, uint256 value) public returns (bool); event Approval(address indexed owner, address indexed spender, uint256 value); } library SafeERC20 { function safeTransfer(ERC20Basic token, address to, uint256 value) internal { assert(token.transfer(to, value)); } function safeTransferFrom(ERC20 token, address from, address to, uint256 value) internal { assert(token.transferFrom(from, to, value)); } function safeApprove(ERC20 token, address spender, uint256 value) internal { assert(token.approve(spender, value)); } } contract StandardToken is ERC20, BasicToken { AllowanceSheet public allowances; function setAllowanceSheet(address sheet) external onlyOwner { allowances = AllowanceSheet(sheet); allowances.claimOwnership(); } /** * @dev Transfer tokens from one address to another * @param _from address The address which you want to send tokens from * @param _to address The address which you want to transfer to * @param _value uint256 the amount of tokens to be transferred */ function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { transferAllArgsYesAllowance(_from, _to, _value, msg.sender); return true; } function transferAllArgsYesAllowance(address _from, address _to, uint256 _value, address spender) internal { require(_value <= allowances.allowanceOf(_from, spender)); allowances.subAllowance(_from, spender, _value); transferAllArgsNoAllowance(_from, _to, _value); } /** * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. * * 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 * @param _spender The address which will spend the funds. * @param _value The amount of tokens to be spent. */ function approve(address _spender, uint256 _value) public returns (bool) { approveAllArgs(_spender, _value, msg.sender); return true; } function approveAllArgs(address _spender, uint256 _value, address _tokenHolder) internal { allowances.setAllowance(_tokenHolder, _spender, _value); Approval(_tokenHolder, _spender, _value); } /** * @dev Function to check the amount of tokens that an owner allowed to a spender. * @param _owner address The address which owns the funds. * @param _spender address The address which will spend the funds. * @return A uint256 specifying the amount of tokens still available for the spender. */ function allowance(address _owner, address _spender) public view returns (uint256) { return allowances.allowanceOf(_owner, _spender); } /** * @dev Increase the amount of tokens that an owner allowed to a spender. * * approve should be called when allowed[_spender] == 0. To increment * allowed value is better to use this function to avoid 2 calls (and wait until * the first transaction is mined) * From MonolithDAO Token.sol * @param _spender The address which will spend the funds. * @param _addedValue The amount of tokens to increase the allowance by. */ function increaseApproval(address _spender, uint _addedValue) public returns (bool) { increaseApprovalAllArgs(_spender, _addedValue, msg.sender); return true; } function increaseApprovalAllArgs(address _spender, uint _addedValue, address tokenHolder) internal { allowances.addAllowance(tokenHolder, _spender, _addedValue); Approval(tokenHolder, _spender, allowances.allowanceOf(tokenHolder, _spender)); } /** * @dev Decrease the amount of tokens that an owner allowed to a spender. * * approve should be called when allowed[_spender] == 0. To decrement * allowed value is better to use this function to avoid 2 calls (and wait until * the first transaction is mined) * From MonolithDAO Token.sol * @param _spender The address which will spend the funds. * @param _subtractedValue The amount of tokens to decrease the allowance by. */ function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) { decreaseApprovalAllArgs(_spender, _subtractedValue, msg.sender); return true; } function decreaseApprovalAllArgs(address _spender, uint _subtractedValue, address tokenHolder) internal { uint oldValue = allowances.allowanceOf(tokenHolder, _spender); if (_subtractedValue > oldValue) { allowances.setAllowance(tokenHolder, _spender, 0); } else { allowances.subAllowance(tokenHolder, _spender, _subtractedValue); } Approval(tokenHolder, _spender, allowances.allowanceOf(tokenHolder, _spender)); } } contract CanDelegate is StandardToken { // If this contract needs to be upgraded, the new contract will be stored // in 'delegate' and any ERC20 calls to this contract will be delegated to that one. DelegateERC20 public delegate; event DelegatedTo(address indexed newContract); // Can undelegate by passing in newContract = address(0) function delegateToNewContract(DelegateERC20 newContract) public onlyOwner { delegate = newContract; DelegatedTo(delegate); } // If a delegate has been designated, all ERC20 calls are forwarded to it function transfer(address to, uint256 value) public returns (bool) { if (delegate == address(0)) { return super.transfer(to, value); } else { return delegate.delegateTransfer(to, value, msg.sender); } } function transferFrom(address from, address to, uint256 value) public returns (bool) { if (delegate == address(0)) { return super.transferFrom(from, to, value); } else { return delegate.delegateTransferFrom(from, to, value, msg.sender); } } function balanceOf(address who) public view returns (uint256) { if (delegate == address(0)) { return super.balanceOf(who); } else { return delegate.delegateBalanceOf(who); } } function approve(address spender, uint256 value) public returns (bool) { if (delegate == address(0)) { return super.approve(spender, value); } else { return delegate.delegateApprove(spender, value, msg.sender); } } function allowance(address _owner, address spender) public view returns (uint256) { if (delegate == address(0)) { return super.allowance(_owner, spender); } else { return delegate.delegateAllowance(_owner, spender); } } function totalSupply() public view returns (uint256) { if (delegate == address(0)) { return super.totalSupply(); } else { return delegate.delegateTotalSupply(); } } function increaseApproval(address spender, uint addedValue) public returns (bool) { if (delegate == address(0)) { return super.increaseApproval(spender, addedValue); } else { return delegate.delegateIncreaseApproval(spender, addedValue, msg.sender); } } function decreaseApproval(address spender, uint subtractedValue) public returns (bool) { if (delegate == address(0)) { return super.decreaseApproval(spender, subtractedValue); } else { return delegate.delegateDecreaseApproval(spender, subtractedValue, msg.sender); } } } contract StandardDelegate is StandardToken, DelegateERC20 { address public delegatedFrom; modifier onlySender(address source) { require(msg.sender == source); _; } function setDelegatedFrom(address addr) onlyOwner public { delegatedFrom = addr; } // All delegate ERC20 functions are forwarded to corresponding normal functions function delegateTotalSupply() public view returns (uint256) { return totalSupply(); } function delegateBalanceOf(address who) public view returns (uint256) { return balanceOf(who); } function delegateTransfer(address to, uint256 value, address origSender) onlySender(delegatedFrom) public returns (bool) { transferAllArgsNoAllowance(origSender, to, value); return true; } function delegateAllowance(address owner, address spender) public view returns (uint256) { return allowance(owner, spender); } function delegateTransferFrom(address from, address to, uint256 value, address origSender) onlySender(delegatedFrom) public returns (bool) { transferAllArgsYesAllowance(from, to, value, origSender); return true; } function delegateApprove(address spender, uint256 value, address origSender) onlySender(delegatedFrom) public returns (bool) { approveAllArgs(spender, value, origSender); return true; } function delegateIncreaseApproval(address spender, uint addedValue, address origSender) onlySender(delegatedFrom) public returns (bool) { increaseApprovalAllArgs(spender, addedValue, origSender); return true; } function delegateDecreaseApproval(address spender, uint subtractedValue, address origSender) onlySender(delegatedFrom) public returns (bool) { decreaseApprovalAllArgs(spender, subtractedValue, origSender); return true; } } contract PausableToken is StandardToken, Pausable { function transfer(address _to, uint256 _value) public whenNotPaused returns (bool) { return super.transfer(_to, _value); } function transferFrom(address _from, address _to, uint256 _value) public whenNotPaused returns (bool) { return super.transferFrom(_from, _to, _value); } function approve(address _spender, uint256 _value) public whenNotPaused returns (bool) { return super.approve(_spender, _value); } function increaseApproval(address _spender, uint _addedValue) public whenNotPaused returns (bool success) { return super.increaseApproval(_spender, _addedValue); } function decreaseApproval(address _spender, uint _subtractedValue) public whenNotPaused returns (bool success) { return super.decreaseApproval(_spender, _subtractedValue); } } contract TrueUSD is StandardDelegate, PausableToken, BurnableToken, NoOwner, CanDelegate { string public name = "TrueUSD"; string public symbol = "TUSD"; uint8 public constant decimals = 18; AddressList public canReceiveMintWhiteList; AddressList public canBurnWhiteList; AddressList public blackList; AddressList public noFeesList; uint256 public burnMin = 10000 * 10**uint256(decimals); uint256 public burnMax = 20000000 * 10**uint256(decimals); uint80 public transferFeeNumerator = 7; uint80 public transferFeeDenominator = 10000; uint80 public mintFeeNumerator = 0; uint80 public mintFeeDenominator = 10000; uint256 public mintFeeFlat = 0; uint80 public burnFeeNumerator = 0; uint80 public burnFeeDenominator = 10000; uint256 public burnFeeFlat = 0; address public staker; event ChangeBurnBoundsEvent(uint256 newMin, uint256 newMax); event Mint(address indexed to, uint256 amount); event WipedAccount(address indexed account, uint256 balance); function TrueUSD() public { totalSupply_ = 0; staker = msg.sender; } function setLists(AddressList _canReceiveMintWhiteList, AddressList _canBurnWhiteList, AddressList _blackList, AddressList _noFeesList) onlyOwner public { canReceiveMintWhiteList = _canReceiveMintWhiteList; canBurnWhiteList = _canBurnWhiteList; blackList = _blackList; noFeesList = _noFeesList; } function changeName(string _name, string _symbol) onlyOwner public { name = _name; symbol = _symbol; } //Burning functions as withdrawing 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). function burn(uint256 _value) public { require(canBurnWhiteList.onList(msg.sender)); require(_value >= burnMin); require(_value <= burnMax); uint256 fee = payStakingFee(msg.sender, _value, burnFeeNumerator, burnFeeDenominator, burnFeeFlat, 0x0); uint256 remaining = _value.sub(fee); super.burn(remaining); } //Create _amount new tokens and transfer them to _to. //Based on code by OpenZeppelin: https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/token/MintableToken.sol function mint(address _to, uint256 _amount) onlyOwner public { require(canReceiveMintWhiteList.onList(_to)); totalSupply_ = totalSupply_.add(_amount); balances.addBalance(_to, _amount); Mint(_to, _amount); Transfer(address(0), _to, _amount); payStakingFee(_to, _amount, mintFeeNumerator, mintFeeDenominator, mintFeeFlat, 0x0); } //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) function changeBurnBounds(uint newMin, uint newMax) onlyOwner public { require(newMin <= newMax); burnMin = newMin; burnMax = newMax; ChangeBurnBoundsEvent(newMin, newMax); } // transfer and transferFrom are both dispatched to this function, so we // check blacklist and pay staking fee here. function transferAllArgsNoAllowance(address _from, address _to, uint256 _value) internal { require(!blackList.onList(_from)); require(!blackList.onList(_to)); super.transferAllArgsNoAllowance(_from, _to, _value); payStakingFee(_to, _value, transferFeeNumerator, transferFeeDenominator, 0, _from); } function wipeBlacklistedAccount(address account) public onlyOwner { require(blackList.onList(account)); uint256 oldValue = balanceOf(account); balances.setBalance(account, 0); totalSupply_ = totalSupply_.sub(oldValue); WipedAccount(account, oldValue); } function payStakingFee(address payer, uint256 value, uint80 numerator, uint80 denominator, uint256 flatRate, address otherParticipant) private returns (uint256) { if (noFeesList.onList(payer) || noFeesList.onList(otherParticipant)) { return 0; } uint256 stakingFee = value.mul(numerator).div(denominator).add(flatRate); if (stakingFee > 0) { super.transferAllArgsNoAllowance(payer, staker, stakingFee); } return stakingFee; } function changeStakingFees(uint80 _transferFeeNumerator, uint80 _transferFeeDenominator, uint80 _mintFeeNumerator, uint80 _mintFeeDenominator, uint256 _mintFeeFlat, uint80 _burnFeeNumerator, uint80 _burnFeeDenominator, uint256 _burnFeeFlat) public onlyOwner { require(_transferFeeDenominator != 0); require(_mintFeeDenominator != 0); require(_burnFeeDenominator != 0); transferFeeNumerator = _transferFeeNumerator; transferFeeDenominator = _transferFeeDenominator; mintFeeNumerator = _mintFeeNumerator; mintFeeDenominator = _mintFeeDenominator; mintFeeFlat = _mintFeeFlat; burnFeeNumerator = _burnFeeNumerator; burnFeeDenominator = _burnFeeDenominator; burnFeeFlat = _burnFeeFlat; } function changeStaker(address newStaker) public onlyOwner { require(newStaker != address(0)); staker = newStaker; } }
File 2 of 3: 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 3 of 3: TrueUSD
pragma solidity ^0.4.23; // File: contracts/TrueCoinReceiver.sol contract TrueCoinReceiver { function tokenFallback( address from, uint256 value ) external; } // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol /** * @title ERC20Basic * @dev Simpler version of ERC20 interface * @dev see https://github.com/ethereum/EIPs/issues/179 */ contract ERC20Basic { function totalSupply() public view returns (uint256); function balanceOf(address who) public view returns (uint256); function transfer(address to, uint256 value) public returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); } // File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol /** * @title ERC20 interface * @dev see https://github.com/ethereum/EIPs/issues/20 */ contract ERC20 is ERC20Basic { function allowance(address owner, address spender) public view returns (uint256); function transferFrom(address from, address to, uint256 value) public returns (bool); function approve(address spender, uint256 value) public returns (bool); event Approval(address indexed owner, address indexed spender, uint256 value); } // File: registry/contracts/Registry.sol interface RegistryClone { function syncAttributeValue(address _who, bytes32 _attribute, uint256 _value) external; } contract Registry { struct AttributeData { uint256 value; bytes32 notes; address adminAddr; uint256 timestamp; } // never remove any storage variables address public owner; address public pendingOwner; bool initialized; // Stores arbitrary attributes for users. An example use case is an ERC20 // token that requires its users to go through a KYC/AML check - in this case // a validator can set an account's "hasPassedKYC/AML" attribute to 1 to indicate // that account can use the token. This mapping stores that value (1, in the // example) as well as which validator last set the value and at what time, // so that e.g. the check can be renewed at appropriate intervals. mapping(address => mapping(bytes32 => AttributeData)) attributes; // The logic governing who is allowed to set what attributes is abstracted as // this accessManager, so that it may be replaced by the owner as needed bytes32 constant WRITE_PERMISSION = keccak256("canWriteTo-"); mapping(bytes32 => RegistryClone[]) subscribers; event OwnershipTransferred( address indexed previousOwner, address indexed newOwner ); event SetAttribute(address indexed who, bytes32 attribute, uint256 value, bytes32 notes, address indexed adminAddr); event SetManager(address indexed oldManager, address indexed newManager); event StartSubscription(bytes32 indexed attribute, RegistryClone indexed subscriber); event StopSubscription(bytes32 indexed attribute, RegistryClone indexed subscriber); // Allows a write if either a) the writer is that Registry's owner, or // b) the writer is writing to attribute foo and that writer already has // the canWriteTo-foo attribute set (in that same Registry) function confirmWrite(bytes32 _attribute, address _admin) internal view returns (bool) { return (_admin == owner || hasAttribute(_admin, keccak256(WRITE_PERMISSION ^ _attribute))); } // Writes are allowed only if the accessManager approves function setAttribute(address _who, bytes32 _attribute, uint256 _value, bytes32 _notes) public { require(confirmWrite(_attribute, msg.sender)); attributes[_who][_attribute] = AttributeData(_value, _notes, msg.sender, block.timestamp); emit SetAttribute(_who, _attribute, _value, _notes, msg.sender); RegistryClone[] storage targets = subscribers[_attribute]; uint256 index = targets.length; while (index --> 0) { targets[index].syncAttributeValue(_who, _attribute, _value); } } function subscribe(bytes32 _attribute, RegistryClone _syncer) external onlyOwner { subscribers[_attribute].push(_syncer); emit StartSubscription(_attribute, _syncer); } function unsubscribe(bytes32 _attribute, uint256 _index) external onlyOwner { uint256 length = subscribers[_attribute].length; require(_index < length); emit StopSubscription(_attribute, subscribers[_attribute][_index]); subscribers[_attribute][_index] = subscribers[_attribute][length - 1]; subscribers[_attribute].length = length - 1; } function subscriberCount(bytes32 _attribute) public view returns (uint256) { return subscribers[_attribute].length; } function setAttributeValue(address _who, bytes32 _attribute, uint256 _value) public { require(confirmWrite(_attribute, msg.sender)); attributes[_who][_attribute] = AttributeData(_value, "", msg.sender, block.timestamp); emit SetAttribute(_who, _attribute, _value, "", msg.sender); RegistryClone[] storage targets = subscribers[_attribute]; uint256 index = targets.length; while (index --> 0) { targets[index].syncAttributeValue(_who, _attribute, _value); } } // Returns true if the uint256 value stored for this attribute is non-zero function hasAttribute(address _who, bytes32 _attribute) public view returns (bool) { return attributes[_who][_attribute].value != 0; } // Returns the exact value of the attribute, as well as its metadata function getAttribute(address _who, bytes32 _attribute) public view returns (uint256, bytes32, address, uint256) { AttributeData memory data = attributes[_who][_attribute]; return (data.value, data.notes, data.adminAddr, data.timestamp); } function getAttributeValue(address _who, bytes32 _attribute) public view returns (uint256) { return attributes[_who][_attribute].value; } function getAttributeAdminAddr(address _who, bytes32 _attribute) public view returns (address) { return attributes[_who][_attribute].adminAddr; } function getAttributeTimestamp(address _who, bytes32 _attribute) public view returns (uint256) { return attributes[_who][_attribute].timestamp; } function syncAttribute(bytes32 _attribute, uint256 _startIndex, address[] _addresses) external { RegistryClone[] storage targets = subscribers[_attribute]; uint256 index = targets.length; while (index --> _startIndex) { RegistryClone target = targets[index]; for (uint256 i = _addresses.length; i --> 0; ) { address who = _addresses[i]; target.syncAttributeValue(who, _attribute, attributes[who][_attribute].value); } } } function reclaimEther(address _to) external onlyOwner { _to.transfer(address(this).balance); } function reclaimToken(ERC20 token, address _to) external onlyOwner { uint256 balance = token.balanceOf(this); token.transfer(_to, balance); } /** * @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); _; } /** * @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); } } // File: openzeppelin-solidity/contracts/ownership/Ownable.sol /** * @title Ownable * @dev The Ownable contract has an owner address, and provides basic authorization control * functions, this simplifies the implementation of "user permissions". */ contract Ownable { address public owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ function Ownable() public { owner = msg.sender; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(msg.sender == owner); _; } /** * @dev Allows the current owner to transfer control of the contract to a newOwner. * @param newOwner The address to transfer ownership to. */ function transferOwnership(address newOwner) public onlyOwner { require(newOwner != address(0)); emit OwnershipTransferred(owner, newOwner); owner = newOwner; } } // File: openzeppelin-solidity/contracts/ownership/Claimable.sol /** * @title Claimable * @dev Extension for the Ownable contract, where the ownership needs to be claimed. * This allows the new owner to accept the transfer. */ contract Claimable is Ownable { address public pendingOwner; /** * @dev Modifier throws if called by any account other than the pendingOwner. */ modifier onlyPendingOwner() { require(msg.sender == pendingOwner); _; } /** * @dev Allows the current owner to set the pendingOwner address. * @param newOwner The address to transfer ownership to. */ function transferOwnership(address newOwner) onlyOwner public { pendingOwner = newOwner; } /** * @dev Allows the pendingOwner address to finalize the transfer. */ function claimOwnership() onlyPendingOwner public { emit OwnershipTransferred(owner, pendingOwner); owner = pendingOwner; pendingOwner = address(0); } } // File: openzeppelin-solidity/contracts/math/SafeMath.sol /** * @title SafeMath * @dev Math operations with safety checks that throw on error */ library SafeMath { /** * @dev Multiplies two numbers, throws on overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256 c) { if (a == 0) { return 0; } c = a * b; assert(c / a == b); return c; } /** * @dev Integer division of two numbers, truncating the quotient. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // assert(b > 0); // Solidity automatically throws when dividing by 0 // uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return a / b; } /** * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { assert(b <= a); return a - b; } /** * @dev Adds two numbers, throws on overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256 c) { c = a + b; assert(c >= a); return c; } } // File: contracts/modularERC20/BalanceSheet.sol // A wrapper around the balanceOf mapping. contract BalanceSheet is Claimable { using SafeMath for uint256; mapping (address => uint256) public balanceOf; function addBalance(address _addr, uint256 _value) public onlyOwner { balanceOf[_addr] = balanceOf[_addr].add(_value); } function subBalance(address _addr, uint256 _value) public onlyOwner { balanceOf[_addr] = balanceOf[_addr].sub(_value); } function setBalance(address _addr, uint256 _value) public onlyOwner { balanceOf[_addr] = _value; } } // File: contracts/modularERC20/AllowanceSheet.sol // A wrapper around the allowanceOf mapping. contract AllowanceSheet is Claimable { using SafeMath for uint256; mapping (address => mapping (address => uint256)) public allowanceOf; function addAllowance(address _tokenHolder, address _spender, uint256 _value) public onlyOwner { allowanceOf[_tokenHolder][_spender] = allowanceOf[_tokenHolder][_spender].add(_value); } function subAllowance(address _tokenHolder, address _spender, uint256 _value) public onlyOwner { allowanceOf[_tokenHolder][_spender] = allowanceOf[_tokenHolder][_spender].sub(_value); } function setAllowance(address _tokenHolder, address _spender, uint256 _value) public onlyOwner { allowanceOf[_tokenHolder][_spender] = _value; } } // File: contracts/ProxyStorage.sol /* Defines the storage layout of the token implementaiton contract. Any newly declared state variables in future upgrades should be appened to the bottom. Never remove state variables from this list */ contract ProxyStorage { address public owner; address public pendingOwner; bool initialized; BalanceSheet balances_Deprecated; AllowanceSheet allowances_Deprecated; uint256 totalSupply_; bool private paused_Deprecated = false; address private globalPause_Deprecated; uint256 public burnMin = 0; uint256 public burnMax = 0; Registry public registry; string name_Deprecated; string symbol_Deprecated; uint[] gasRefundPool_Deprecated; uint256 private redemptionAddressCount_Deprecated; uint256 public minimumGasPriceForFutureRefunds; mapping (address => uint256) _balanceOf; mapping (address => mapping (address => uint256)) _allowance; mapping (bytes32 => mapping (address => uint256)) attributes; /* 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 **/ } // File: contracts/HasOwner.sol /** * @title HasOwner * @dev The HasOwner contract is a copy of Claimable Contract by Zeppelin. and provides basic authorization control functions. Inherits storage layout of ProxyStorage. */ contract HasOwner is ProxyStorage { 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); _; } /** * @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); } } // File: contracts/ReclaimerToken.sol contract ReclaimerToken is HasOwner { /** *@dev send all eth balance in the contract to another address */ function reclaimEther(address _to) external onlyOwner { _to.transfer(address(this).balance); } /** *@dev send all token balance of an arbitary erc20 token in the contract to another address */ function reclaimToken(ERC20 token, address _to) external onlyOwner { uint256 balance = token.balanceOf(this); token.transfer(_to, balance); } /** *@dev allows owner of the contract to gain ownership of any contract that the contract currently owns */ function reclaimContract(Ownable _ownable) external onlyOwner { _ownable.transferOwnership(owner); } } // File: contracts/modularERC20/ModularBasicToken.sol // Fork of OpenZeppelin's BasicToken /** * @title Basic token * @dev Basic version of StandardToken, with no allowances. */ contract ModularBasicToken is HasOwner { using SafeMath for uint256; event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev total number of tokens in existence */ function totalSupply() public view returns (uint256) { return totalSupply_; } function balanceOf(address _who) public view returns (uint256) { return _getBalance(_who); } function _getBalance(address _who) internal view returns (uint256) { return _balanceOf[_who]; } function _addBalance(address _who, uint256 _value) internal returns (uint256 priorBalance) { priorBalance = _balanceOf[_who]; _balanceOf[_who] = priorBalance.add(_value); } function _subBalance(address _who, uint256 _value) internal returns (uint256 result) { result = _balanceOf[_who].sub(_value); _balanceOf[_who] = result; } function _setBalance(address _who, uint256 _value) internal { _balanceOf[_who] = _value; } } // File: contracts/modularERC20/ModularStandardToken.sol /** * @title Standard ERC20 token * * @dev Implementation of the basic standard token. * @dev https://github.com/ethereum/EIPs/issues/20 * @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol */ contract ModularStandardToken is ModularBasicToken { using SafeMath for uint256; event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. * * 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 * @param _spender The address which will spend the funds. * @param _value The amount of tokens to be spent. */ function approve(address _spender, uint256 _value) public returns (bool) { _approveAllArgs(_spender, _value, msg.sender); return true; } function _approveAllArgs(address _spender, uint256 _value, address _tokenHolder) internal { _setAllowance(_tokenHolder, _spender, _value); emit Approval(_tokenHolder, _spender, _value); } /** * @dev Increase the amount of tokens that an owner allowed to a spender. * * approve should be called when allowed[_spender] == 0. To increment * allowed value is better to use this function to avoid 2 calls (and wait until * the first transaction is mined) * From MonolithDAO Token.sol * @param _spender The address which will spend the funds. * @param _addedValue The amount of tokens to increase the allowance by. */ function increaseApproval(address _spender, uint _addedValue) public returns (bool) { _increaseApprovalAllArgs(_spender, _addedValue, msg.sender); return true; } function _increaseApprovalAllArgs(address _spender, uint256 _addedValue, address _tokenHolder) internal { _addAllowance(_tokenHolder, _spender, _addedValue); emit Approval(_tokenHolder, _spender, _getAllowance(_tokenHolder, _spender)); } /** * @dev Decrease the amount of tokens that an owner allowed to a spender. * * approve should be called when allowed[_spender] == 0. To decrement * allowed value is better to use this function to avoid 2 calls (and wait until * the first transaction is mined) * From MonolithDAO Token.sol * @param _spender The address which will spend the funds. * @param _subtractedValue The amount of tokens to decrease the allowance by. */ function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) { _decreaseApprovalAllArgs(_spender, _subtractedValue, msg.sender); return true; } function _decreaseApprovalAllArgs(address _spender, uint256 _subtractedValue, address _tokenHolder) internal { uint256 oldValue = _getAllowance(_tokenHolder, _spender); uint256 newValue; if (_subtractedValue > oldValue) { newValue = 0; } else { newValue = oldValue - _subtractedValue; } _setAllowance(_tokenHolder, _spender, newValue); emit Approval(_tokenHolder,_spender, newValue); } function allowance(address _who, address _spender) public view returns (uint256) { return _getAllowance(_who, _spender); } function _getAllowance(address _who, address _spender) internal view returns (uint256 value) { return _allowance[_who][_spender]; } function _addAllowance(address _who, address _spender, uint256 _value) internal { _allowance[_who][_spender] = _allowance[_who][_spender].add(_value); } function _subAllowance(address _who, address _spender, uint256 _value) internal returns (uint256 newAllowance){ newAllowance = _allowance[_who][_spender].sub(_value); _allowance[_who][_spender] = newAllowance; } function _setAllowance(address _who, address _spender, uint256 _value) internal { _allowance[_who][_spender] = _value; } } // File: contracts/modularERC20/ModularBurnableToken.sol /** * @title Burnable Token * @dev Token that can be irreversibly burned (destroyed). */ contract ModularBurnableToken is ModularStandardToken { event Burn(address indexed burner, uint256 value); event Mint(address indexed to, uint256 value); uint256 constant CENT = 10 ** 16; function burn(uint256 _value) external { _burnAllArgs(msg.sender, _value - _value % CENT); } function _burnAllArgs(address _from, uint256 _value) internal { // no need to require value <= totalSupply, since that would imply the // sender's balance is greater than the totalSupply, which *should* be an assertion failure _subBalance(_from, _value); totalSupply_ = totalSupply_.sub(_value); emit Burn(_from, _value); emit Transfer(_from, address(0), _value); } } // File: contracts/BurnableTokenWithBounds.sol /** * @title Burnable Token WithBounds * @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). */ contract BurnableTokenWithBounds is ModularBurnableToken { event SetBurnBounds(uint256 newMin, uint256 newMax); function _burnAllArgs(address _burner, uint256 _value) internal { require(_value >= burnMin, "below min burn bound"); require(_value <= burnMax, "exceeds max burn bound"); super._burnAllArgs(_burner, _value); } //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) function setBurnBounds(uint256 _min, uint256 _max) external onlyOwner { require(_min <= _max, "min > max"); burnMin = _min; burnMax = _max; emit SetBurnBounds(_min, _max); } } // File: contracts/GasRefundToken.sol /** @title Gas Refund Token Allow any user to sponsor gas refunds for transfer and mints. Utilitzes the gas refund mechanism in EVM Each time an non-empty storage slot is set to 0, evm refund 15,000 to the sender of the transaction. */ contract GasRefundToken is ProxyStorage { /** A buffer of "Sheep" runs from 0xffff...fffe down They suicide when you call them, if you are their parent */ function sponsorGas2() external { /** Deploy (9 bytes) PC Assembly Opcodes Stack 00 PUSH1(31) 60 1f 1f 02 DUP1 80 1f 1f 03 PUSH1(9) 60 09 1f 1f 09 05 RETURNDATASIZE 3d 1f 1f 09 00 06 CODECOPY 39 1f 07 RETURNDATASIZE 3d 1f 00 08 RETURN f3 Sheep (31 bytes = 3 + 20 + 8) PC Assembly Opcodes Stack 00 RETURNDATASIZE 3d 0 01 CALLER 33 0 caller 02 PUSH20(me) 73 memememememememememememememememememememe 0 caller me 17 EQ 14 0 valid 18 PUSH1(1d) 60 1d 0 valid 1d 1a JUMPI 57 0 1b DUP1 80 0 0 1c REVERT fd 1d JUMPDEST 5b 0 1e SELFDESTRUCT ff */ assembly { mstore(0, or(0x601f8060093d393df33d33730000000000000000000000000000000000000000, address)) mstore(32, 0x14601d5780fd5bff000000000000000000000000000000000000000000000000) let sheep := create(0, 0, 0x28) let offset := sload(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) let location := sub(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe, offset) sstore(location, sheep) sheep := create(0, 0, 0x28) sstore(sub(location, 1), sheep) sheep := create(0, 0, 0x28) sstore(sub(location, 2), sheep) sstore(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, add(offset, 3)) } } /** @dev refund 39,000 gas @dev costs slightly more than 16,100 gas */ function gasRefund39() internal { assembly { let offset := sload(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) if gt(offset, 0) { let location := sub(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff,offset) sstore(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, sub(offset, 1)) let sheep := sload(location) pop(call(gas, sheep, 0, 0, 0, 0, 0)) sstore(location, 0) } } } function sponsorGas() external { uint256 refundPrice = minimumGasPriceForFutureRefunds; require(refundPrice > 0); assembly { let offset := sload(0xfffff) let result := add(offset, 9) sstore(0xfffff, result) let position := add(offset, 0x100000) sstore(position, refundPrice) position := add(position, 1) sstore(position, refundPrice) position := add(position, 1) sstore(position, refundPrice) position := add(position, 1) sstore(position, refundPrice) position := add(position, 1) sstore(position, refundPrice) position := add(position, 1) sstore(position, refundPrice) position := add(position, 1) sstore(position, refundPrice) position := add(position, 1) sstore(position, refundPrice) position := add(position, 1) sstore(position, refundPrice) } } function minimumGasPriceForRefund() public view returns (uint256 result) { assembly { let offset := sload(0xfffff) let location := add(offset, 0xfffff) result := add(sload(location), 1) } } /** @dev refund 30,000 gas @dev costs slightly more than 15,400 gas */ function gasRefund30() internal { assembly { let offset := sload(0xfffff) if gt(offset, 1) { let location := add(offset, 0xfffff) if gt(gasprice,sload(location)) { sstore(location, 0) location := sub(location, 1) sstore(location, 0) sstore(0xfffff, sub(offset, 2)) } } } } /** @dev refund 15,000 gas @dev costs slightly more than 10,200 gas */ function gasRefund15() internal { assembly { let offset := sload(0xfffff) if gt(offset, 1) { let location := add(offset, 0xfffff) if gt(gasprice,sload(location)) { sstore(location, 0) sstore(0xfffff, sub(offset, 1)) } } } } /** *@dev Return the remaining sponsored gas slots */ function remainingGasRefundPool() public view returns (uint length) { assembly { length := sload(0xfffff) } } function gasRefundPool(uint256 _index) public view returns (uint256 gasPrice) { assembly { gasPrice := sload(add(0x100000, _index)) } } bytes32 constant CAN_SET_FUTURE_REFUND_MIN_GAS_PRICE = "canSetFutureRefundMinGasPrice"; function setMinimumGasPriceForFutureRefunds(uint256 _minimumGasPriceForFutureRefunds) public { require(registry.hasAttribute(msg.sender, CAN_SET_FUTURE_REFUND_MIN_GAS_PRICE)); minimumGasPriceForFutureRefunds = _minimumGasPriceForFutureRefunds; } } // File: contracts/CompliantDepositTokenWithHook.sol contract CompliantDepositTokenWithHook is ReclaimerToken, RegistryClone, BurnableTokenWithBounds, GasRefundToken { bytes32 constant IS_REGISTERED_CONTRACT = "isRegisteredContract"; bytes32 constant IS_DEPOSIT_ADDRESS = "isDepositAddress"; uint256 constant REDEMPTION_ADDRESS_COUNT = 0x100000; bytes32 constant IS_BLACKLISTED = "isBlacklisted"; function canBurn() internal pure returns (bytes32); /** * @dev transfer token for a specified address * @param _to The address to transfer to. * @param _value The amount to be transferred. */ function transfer(address _to, uint256 _value) public returns (bool) { _transferAllArgs(msg.sender, _to, _value); return true; } /** * @dev Transfer tokens from one address to another * @param _from address The address which you want to send tokens from * @param _to address The address which you want to transfer to * @param _value uint256 the amount of tokens to be transferred */ function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { _transferFromAllArgs(_from, _to, _value, msg.sender); return true; } function _burnFromAllowanceAllArgs(address _from, address _to, uint256 _value, address _spender) internal { _requireCanTransferFrom(_spender, _from, _to); _requireOnlyCanBurn(_to); require(_value >= burnMin, "below min burn bound"); require(_value <= burnMax, "exceeds max burn bound"); if (0 == _subBalance(_from, _value)) { if (0 == _subAllowance(_from, _spender, _value)) { // no refund } else { gasRefund15(); } } else { if (0 == _subAllowance(_from, _spender, _value)) { gasRefund15(); } else { gasRefund39(); } } emit Transfer(_from, _to, _value); totalSupply_ = totalSupply_.sub(_value); emit Burn(_to, _value); emit Transfer(_to, address(0), _value); } function _burnFromAllArgs(address _from, address _to, uint256 _value) internal { _requireCanTransfer(_from, _to); _requireOnlyCanBurn(_to); require(_value >= burnMin, "below min burn bound"); require(_value <= burnMax, "exceeds max burn bound"); if (0 == _subBalance(_from, _value)) { gasRefund15(); } else { gasRefund30(); } emit Transfer(_from, _to, _value); totalSupply_ = totalSupply_.sub(_value); emit Burn(_to, _value); emit Transfer(_to, address(0), _value); } function _transferFromAllArgs(address _from, address _to, uint256 _value, address _spender) internal { if (uint256(_to) < REDEMPTION_ADDRESS_COUNT) { _value -= _value % CENT; _burnFromAllowanceAllArgs(_from, _to, _value, _spender); } else { bool hasHook; address originalTo = _to; (_to, hasHook) = _requireCanTransferFrom(_spender, _from, _to); if (0 == _addBalance(_to, _value)) { if (0 == _subAllowance(_from, _spender, _value)) { if (0 == _subBalance(_from, _value)) { // do not refund } else { gasRefund30(); } } else { if (0 == _subBalance(_from, _value)) { gasRefund30(); } else { gasRefund39(); } } } else { if (0 == _subAllowance(_from, _spender, _value)) { if (0 == _subBalance(_from, _value)) { // do not refund } else { gasRefund15(); } } else { if (0 == _subBalance(_from, _value)) { gasRefund15(); } else { gasRefund39(); } } } emit Transfer(_from, originalTo, _value); if (originalTo != _to) { emit Transfer(originalTo, _to, _value); if (hasHook) { TrueCoinReceiver(_to).tokenFallback(originalTo, _value); } } else { if (hasHook) { TrueCoinReceiver(_to).tokenFallback(_from, _value); } } } } function _transferAllArgs(address _from, address _to, uint256 _value) internal { if (uint256(_to) < REDEMPTION_ADDRESS_COUNT) { _value -= _value % CENT; _burnFromAllArgs(_from, _to, _value); } else { bool hasHook; address finalTo; (finalTo, hasHook) = _requireCanTransfer(_from, _to); if (0 == _subBalance(_from, _value)) { if (0 == _addBalance(finalTo, _value)) { gasRefund30(); } else { // do not refund } } else { if (0 == _addBalance(finalTo, _value)) { gasRefund39(); } else { gasRefund30(); } } emit Transfer(_from, _to, _value); if (finalTo != _to) { emit Transfer(_to, finalTo, _value); if (hasHook) { TrueCoinReceiver(finalTo).tokenFallback(_to, _value); } } else { if (hasHook) { TrueCoinReceiver(finalTo).tokenFallback(_from, _value); } } } } function mint(address _to, uint256 _value) public onlyOwner { require(_to != address(0), "to address cannot be zero"); bool hasHook; address originalTo = _to; (_to, hasHook) = _requireCanMint(_to); totalSupply_ = totalSupply_.add(_value); emit Mint(originalTo, _value); emit Transfer(address(0), originalTo, _value); if (_to != originalTo) { emit Transfer(originalTo, _to, _value); } _addBalance(_to, _value); if (hasHook) { if (_to != originalTo) { TrueCoinReceiver(_to).tokenFallback(originalTo, _value); } else { TrueCoinReceiver(_to).tokenFallback(address(0), _value); } } } event WipeBlacklistedAccount(address indexed account, uint256 balance); event SetRegistry(address indexed registry); /** * @dev Point to the registry that contains all compliance related data @param _registry The address of the registry instance */ function setRegistry(Registry _registry) public onlyOwner { registry = _registry; emit SetRegistry(registry); } modifier onlyRegistry { require(msg.sender == address(registry)); _; } function syncAttributeValue(address _who, bytes32 _attribute, uint256 _value) public onlyRegistry { attributes[_attribute][_who] = _value; } function _burnAllArgs(address _from, uint256 _value) internal { _requireCanBurn(_from); super._burnAllArgs(_from, _value); } // Destroy the tokens owned by a blacklisted account function wipeBlacklistedAccount(address _account) public onlyOwner { require(_isBlacklisted(_account), "_account is not blacklisted"); uint256 oldValue = _getBalance(_account); _setBalance(_account, 0); totalSupply_ = totalSupply_.sub(oldValue); emit WipeBlacklistedAccount(_account, oldValue); emit Transfer(_account, address(0), oldValue); } function _isBlacklisted(address _account) internal view returns (bool blacklisted) { return attributes[IS_BLACKLISTED][_account] != 0; } function _requireCanTransfer(address _from, address _to) internal view returns (address, bool) { uint256 depositAddressValue = attributes[IS_DEPOSIT_ADDRESS][address(uint256(_to) >> 20)]; if (depositAddressValue != 0) { _to = address(depositAddressValue); } require (attributes[IS_BLACKLISTED][_to] == 0, "blacklisted"); require (attributes[IS_BLACKLISTED][_from] == 0, "blacklisted"); return (_to, attributes[IS_REGISTERED_CONTRACT][_to] != 0); } function _requireCanTransferFrom(address _spender, address _from, address _to) internal view returns (address, bool) { require (attributes[IS_BLACKLISTED][_spender] == 0, "blacklisted"); uint256 depositAddressValue = attributes[IS_DEPOSIT_ADDRESS][address(uint256(_to) >> 20)]; if (depositAddressValue != 0) { _to = address(depositAddressValue); } require (attributes[IS_BLACKLISTED][_to] == 0, "blacklisted"); require (attributes[IS_BLACKLISTED][_from] == 0, "blacklisted"); return (_to, attributes[IS_REGISTERED_CONTRACT][_to] != 0); } function _requireCanMint(address _to) internal view returns (address, bool) { uint256 depositAddressValue = attributes[IS_DEPOSIT_ADDRESS][address(uint256(_to) >> 20)]; if (depositAddressValue != 0) { _to = address(depositAddressValue); } require (attributes[IS_BLACKLISTED][_to] == 0, "blacklisted"); return (_to, attributes[IS_REGISTERED_CONTRACT][_to] != 0); } function _requireOnlyCanBurn(address _from) internal view { require (attributes[canBurn()][_from] != 0, "cannot burn from this address"); } function _requireCanBurn(address _from) internal view { require (attributes[IS_BLACKLISTED][_from] == 0, "blacklisted"); require (attributes[canBurn()][_from] != 0, "cannot burn from this address"); } function paused() public pure returns (bool) { return false; } } // File: contracts/DelegateERC20.sol /** @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). */ contract DelegateERC20 is CompliantDepositTokenWithHook { address constant DELEGATE_FROM = 0x8dd5fbCe2F6a956C3022bA3663759011Dd51e73E; modifier onlyDelegateFrom() { require(msg.sender == DELEGATE_FROM); _; } function delegateTotalSupply() public view returns (uint256) { return totalSupply(); } function delegateBalanceOf(address who) public view returns (uint256) { return _getBalance(who); } function delegateTransfer(address to, uint256 value, address origSender) public onlyDelegateFrom returns (bool) { _transferAllArgs(origSender, to, value); return true; } function delegateAllowance(address owner, address spender) public view returns (uint256) { return _getAllowance(owner, spender); } function delegateTransferFrom(address from, address to, uint256 value, address origSender) public onlyDelegateFrom returns (bool) { _transferFromAllArgs(from, to, value, origSender); return true; } function delegateApprove(address spender, uint256 value, address origSender) public onlyDelegateFrom returns (bool) { _approveAllArgs(spender, value, origSender); return true; } function delegateIncreaseApproval(address spender, uint addedValue, address origSender) public onlyDelegateFrom returns (bool) { _increaseApprovalAllArgs(spender, addedValue, origSender); return true; } function delegateDecreaseApproval(address spender, uint subtractedValue, address origSender) public onlyDelegateFrom returns (bool) { _decreaseApprovalAllArgs(spender, subtractedValue, origSender); return true; } } // File: contracts/TrueUSD.sol /** @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 CompliantDepositTokenWithHook, DelegateERC20 { uint8 constant DECIMALS = 18; uint8 constant ROUNDING = 2; function decimals() public pure returns (uint8) { return DECIMALS; } function rounding() public pure returns (uint8) { return ROUNDING; } function name() public pure returns (string) { return "TrueUSD"; } function symbol() public pure returns (string) { return "TUSD"; } function canBurn() internal pure returns (bytes32) { return "canBurn"; } }