Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delegate Token #301

Merged
merged 16 commits into from
Oct 13, 2020
141 changes: 141 additions & 0 deletions contracts/true-currencies/DelegateERC20.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.6.10;

import {TrueCurrency} from "./TrueCurrency.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).
*
* 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;
}
}
4 changes: 2 additions & 2 deletions contracts/true-currencies/ERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,14 @@ abstract contract ERC20 is ClaimableOwnable, Context, IERC20 {
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view override returns (uint256) {
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}

/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view override returns (uint256) {
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}

Expand Down
4 changes: 2 additions & 2 deletions contracts/true-currencies/TrueCurrencyWithLegacyAutosweep.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.6.10;

import {TrueCurrency} from "./TrueCurrency.sol";
import {DelegateERC20} from "./DelegateERC20.sol";

/**
* @dev Contract that prevents addresses that were previously using autosweep addresses from
Expand All @@ -19,7 +19,7 @@ import {TrueCurrency} from "./TrueCurrency.sol";
*
* This contract will reject a transfer to these 4*(16^5-1) addresses to prevent accidental token freeze.
*/
abstract contract TrueCurrencyWithLegacyAutosweep is TrueCurrency {
abstract contract TrueCurrencyWithLegacyAutosweep is DelegateERC20 {
function _transfer(
address sender,
address recipient,
Expand Down
144 changes: 144 additions & 0 deletions contracts/true-currencies/mocks/MockDelegateERC20.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.6.10;

import {ERC20} from "../ERC20.sol";

interface IDelegateERC20 {
function delegateTotalSupply() external view returns (uint256);

function delegateBalanceOf(address who) external view returns (uint256);

function delegateTransfer(
address to,
uint256 value,
address origSender
) external returns (bool);

function delegateAllowance(address owner, address spender) external view returns (uint256);

function delegateTransferFrom(
address from,
address to,
uint256 value,
address origSender
) external returns (bool);

function delegateApprove(
address spender,
uint256 value,
address origSender
) external returns (bool);

function delegateIncreaseApproval(
address spender,
uint256 addedValue,
address origSender
) external returns (bool);

function delegateDecreaseApproval(
address spender,
uint256 subtractedValue,
address origSender
) external returns (bool);
}

/**
* Mock Legacy TUSD contract. Forwards calls to delegate ERC20 contract
*/
contract MockDelegateERC20 is ERC20 {
// 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.
IDelegateERC20 public delegate;

event DelegatedTo(address indexed newContract);

// Can undelegate by passing in newContract = address(0)
function delegateToNewContract(IDelegateERC20 newContract) public {
delegate = newContract;
emit DelegatedTo(address(delegate));
}

/**
* @dev Returns the name of the token.
*/
function name() public virtual override pure returns (string memory) {
return "DelegateERC20";
}

/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public virtual override pure returns (string memory) {
return "DERC20";
}

// If a delegate has been designated, all ERC20 calls are forwarded to it
function transfer(address to, uint256 value) public virtual override returns (bool) {
if (address(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 virtual override returns (bool) {
if (address(delegate) == address(0)) {
return super.transferFrom(from, to, value);
} else {
return delegate.delegateTransferFrom(from, to, value, msg.sender);
}
}

function balanceOf(address who) public override view returns (uint256) {
if (address(delegate) == address(0)) {
return super.balanceOf(who);
} else {
return delegate.delegateBalanceOf(who);
}
}

function approve(address spender, uint256 value) public virtual override returns (bool) {
if (address(delegate) == address(0)) {
return super.approve(spender, value);
} else {
return delegate.delegateApprove(spender, value, msg.sender);
}
}

function allowance(address _owner, address spender) public virtual override view returns (uint256) {
if (address(delegate) == address(0)) {
return super.allowance(_owner, spender);
} else {
return delegate.delegateAllowance(_owner, spender);
}
}

function totalSupply() public override view returns (uint256) {
if (address(delegate) == address(0)) {
return super.totalSupply();
} else {
return delegate.delegateTotalSupply();
}
}

function increaseApproval(address spender, uint256 addedValue) public returns (bool) {
if (address(delegate) == address(0)) {
return super.increaseAllowance(spender, addedValue);
} else {
return delegate.delegateIncreaseApproval(spender, addedValue, msg.sender);
}
}

function decreaseApproval(address spender, uint256 subtractedValue) public returns (bool) {
if (address(delegate) == address(0)) {
return super.decreaseAllowance(spender, subtractedValue);
} else {
return delegate.delegateDecreaseApproval(spender, subtractedValue, msg.sender);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.6.10;

import {TrueCurrencyWithLegacyAutosweep} from "../TrueCurrencyWithLegacyAutosweep.sol";
import {MockTrueCurrencyWithLegacyAutosweep} from "./MockTrueCurrencyWithLegacyAutosweep.sol";

contract MockTrueCurrencyWithAutosweep is TrueCurrencyWithLegacyAutosweep {
contract MockTrueCurrencyWithAutosweep is MockTrueCurrencyWithLegacyAutosweep {
uint8 constant DECIMALS = 18;
uint8 constant ROUNDING = 2;

Expand Down
Loading