Skip to content

Instantly share code, notes, and snippets.

@stillmatic
Last active May 19, 2022 18:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stillmatic/1482a1eae8ae110f39c097add5cdff5a to your computer and use it in GitHub Desktop.
Save stillmatic/1482a1eae8ae110f39c097add5cdff5a to your computer and use it in GitHub Desktop.
stables

The USDC contract is at 0xdac17f958d2ee523a2206206994597c13d831ec7 -- code is pulled from https://etherscan.io/address/0xdac17f958d2ee523a2206206994597c13d831ec7#code

The mint/burn logic is controlled by issue and redeem

    // 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);
    }

In this case, it appears that only the Tether contract owner has the ability to issue/redeem.

Calling getOwner() on the contract returns 0xc6cde7c39eb2f0f0095f41570af89efc2c1ea828. Etherscan has this contract labeled as 'BitFinex MultiSig 2' - https://etherscan.io/address/0xc6cde7c39eb2f0f0095f41570af89efc2c1ea828

The USDC contract is a proxy contract which points to an implementation at 0xa2327a938Febf5FEC13baCFb16Ae10EcBc4cbDCF (this is a common pattern, which allows admins to 'upgrade' their contracts: https://docs.openzeppelin.com/upgrades-plugins/1.x/proxies)

The current contract defines a few events, which can be filtered in off-chain log storage, accessed by interfaces such as web3.py or Dune Analytics.

    event Mint(address indexed minter, address indexed to, uint256 amount);
    event Burn(address indexed burner, uint256 amount);
    event MinterConfigured(address indexed minter, uint256 minterAllowedAmount);
    event MinterRemoved(address indexed oldMinter);
    event MasterMinterChanged(address indexed newMasterMinter);

There is a MasterMinter which appears to have special rights. However, there are additional Minters which have senioriage rights, with limits: each Minter can only mint a certain amount. In the mint function:

    function mint(address _to, uint256 _amount)
        external
        whenNotPaused
        onlyMinters
        notBlacklisted(msg.sender)
        notBlacklisted(_to)
        returns (bool)
    {
        uint256 mintingAllowedAmount = minterAllowed[msg.sender];
        require(
            _amount <= mintingAllowedAmount,
            "FiatToken: mint amount exceeds minterAllowance"
        );
        # ...
        minterAllowed[msg.sender] = mintingAllowedAmount.sub(_amount);

This function is available only to Minters and caps the amount minted at the minter's allowance.

Minters can be added/updated/removed, but only by the MasterMinter.

    /**
     * @dev Function to add/update a new minter
     * @param minter The address of the minter
     * @param minterAllowedAmount The minting amount allowed for the minter
     * @return True if the operation was successful.
     */
    function configureMinter(address minter, uint256 minterAllowedAmount)
        external
        whenNotPaused
        onlyMasterMinter
        returns (bool)
    {
        minters[minter] = true;
        minterAllowed[minter] = minterAllowedAmount;
        emit MinterConfigured(minter, minterAllowedAmount);
        return true;
    }

Similarly burn is only callable by Minters. However, there is no cap to how much a single Minter can burn, unlike minting.

    /**
     * @dev allows a minter to burn some of its own tokens
     * Validates that caller is a minter and that sender is not blacklisted
     * amount is less than or equal to the minter's account balance
     * @param _amount uint256 the amount of tokens to be burned
     */
    function burn(uint256 _amount)
        external
        whenNotPaused
        onlyMinters
        notBlacklisted(msg.sender)
    {
        uint256 balance = balances[msg.sender];
        require(_amount > 0, "FiatToken: burn amount not greater than 0");
        require(balance >= _amount, "FiatToken: burn amount exceeds balance");

        totalSupply_ = totalSupply_.sub(_amount);
        balances[msg.sender] = balance.sub(_amount);
        emit Burn(msg.sender, _amount);
        emit Transfer(msg.sender, address(0), _amount);
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment