1

The Tether token (USDT) has:

contract UpgradedStandardToken is StandardToken{
// those methods are called by the legacy contract
// and they must ensure msg.sender to be the contract address
function transferByLegacy(address from, address to, uint value) public;
function transferFromByLegacy(address sender, address from, address spender, uint value) public;
function approveByLegacy(address from, address spender, uint value) public;}

contract TetherToken is Pausable, StandardToken, BlackList {

string public name;
string public symbol;
uint public decimals;
address public upgradedAddress;
bool public deprecated;

//  The contract can be initialized with a number of tokens
//  All the tokens are deposited to the owner address
//
// @param _balance Initial supply of the contract
// @param _name Token Name
// @param _symbol Token symbol
// @param _decimals Token decimals
function TetherToken(uint _initialSupply, string _name, string _symbol, uint _decimals) public {
    _totalSupply = _initialSupply;
    name = _name;
    symbol = _symbol;
    decimals = _decimals;
    balances[owner] = _initialSupply;
    deprecated = false;
}

// Forward ERC20 methods to upgraded contract if this one is deprecated
function transfer(address _to, uint _value) public whenNotPaused {
    require(!isBlackListed[msg.sender]);
    if (deprecated) {
        return UpgradedStandardToken(upgradedAddress).transferByLegacy(msg.sender, _to, _value);
    } else {
        return super.transfer(_to, _value);
    }
}

// Forward ERC20 methods to upgraded contract if this one is deprecated
function transferFrom(address _from, address _to, uint _value) public whenNotPaused {
    require(!isBlackListed[_from]);
    if (deprecated) {
        return UpgradedStandardToken(upgradedAddress).transferFromByLegacy(msg.sender, _from, _to, _value);
    } else {
        return super.transferFrom(_from, _to, _value);
    }
}

// Forward ERC20 methods to upgraded contract if this one is deprecated
function balanceOf(address who) public constant returns (uint) {
    if (deprecated) {
        return UpgradedStandardToken(upgradedAddress).balanceOf(who);
    } else {
        return super.balanceOf(who);
    }
}

// Forward ERC20 methods to upgraded contract if this one is deprecated
function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {
    if (deprecated) {
        return UpgradedStandardToken(upgradedAddress).approveByLegacy(msg.sender, _spender, _value);
    } else {
        return super.approve(_spender, _value);
    }
}

// Forward ERC20 methods to upgraded contract if this one is deprecated
function allowance(address _owner, address _spender) public constant returns (uint remaining) {
    if (deprecated) {
        return StandardToken(upgradedAddress).allowance(_owner, _spender);
    } else {
        return super.allowance(_owner, _spender);
    }
}

// deprecate current contract in favour of a new one
function deprecate(address _upgradedAddress) public onlyOwner {
    deprecated = true;
    upgradedAddress = _upgradedAddress;
    Deprecate(_upgradedAddress);
}

// deprecate current contract if favour of a new one
function totalSupply() public constant returns (uint) {
    if (deprecated) {
        return StandardToken(upgradedAddress).totalSupply();
    } else {
        return _totalSupply;
    }
}

// Issue a new amount of tokens
// these tokens are deposited into the owner address
//
// @param _amount Number of tokens to be issued
function issue(uint amount) public onlyOwner {
    require(_totalSupply + amount > _totalSupply);
    require(balances[owner] + amount > balances[owner]);

    balances[owner] += amount;
    _totalSupply += amount;
    Issue(amount);
}

// Redeem tokens.
// These tokens are withdrawn from the owner address
// if the balance must be enough to cover the redeem
// or the call will fail.
// @param _amount Number of tokens to be issued
function redeem(uint amount) public onlyOwner {
    require(_totalSupply >= amount);
    require(balances[owner] >= amount);

    _totalSupply -= amount;
    balances[owner] -= amount;
    Redeem(amount);
}

function setParams(uint newBasisPoints, uint newMaxFee) public onlyOwner {
    // Ensure transparency by hardcoding limit beyond which fees can never be added
    require(newBasisPoints < 20);
    require(newMaxFee < 50);

    basisPointsRate = newBasisPoints;
    maximumFee = newMaxFee.mul(10**decimals);

    Params(basisPointsRate, maximumFee);
}

// Called when new token are issued
event Issue(uint amount);

// Called when tokens are redeemed
event Redeem(uint amount);

// Called when contract is deprecated
event Deprecate(address newAddress);

// Called if contract ever adds fees
event Params(uint feeBasisPoints, uint maxFee);}

I am not sure if I understood their contract properly. I ran two instances (two contract addresses) on the Remix IDE, then upgraded one contract to the new contract (using the deprecate function). As expected, calling getter functions (eg. totalSupply(), balanceOf(), etc.) on the deprecated contract returned the getter output of the upgraded contract.

Question: Lets say there are 3 addresses, two with 500 Tether tokens and one with 1000 tokens. Lets also say that the one address with 1000 tokens is the admin address (when new contract is deployed, 2000 tokens gets initialized to the admin address). Then, the Tether admins decide to upgrade the token. They use the deprecate function to upgrade. Now, wouldn't calling of the balanceOf function from the old contract return 0 for the two non-admin addresses and 2000 for the admin address? If so, wouldn't this be a big problem? How do they (Tether in specific) restore the old balances for every address? (for 3, you may be able to do it manually, but for 10000 addresses?)

It would be much appreciated if anyone can help me understand this! Thanks!

Tether Token Smart Contract Code

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.