# USDs

## USDs

* ERC20 contract
* USDs is a stablecoin yield aggregator that provides auto-yield natively.
* USDs is a rebasing token with two modes of accounting for users:
  * **Rebasing wallets**

    * Users holding tokens in their EOA are by default in this category and are eligible for auto-yield via a rebasing mechanism.
    * Any contract opted-in for rebase also comes in this category.
    * Balance for this category is tracked via a credit system, as described below :

    $$
    creditsPerToken = C\_t \ creditBalance = C\_b \ userBalance = C\_b/C\_t
    $$

    * creditsPerToken is tracked at a global level and is updated when doing a rebase.
    * creditBalance is tracked at an account level and is updated via token transfer, mint, redemption of USDs
  * **Non-Rebasing wallets**
    * For Non-Rebasing wallets this token acts as a normal ERC20 token and tracks the balance of the wallet as usual.
* **Rebasing Mechanism**
  * Users mint USDs using approved list of collaterals
  * These collaterals accumulated in the USDs vault are then deployed to various yield on-chain earning opportunities.
  * Yield is harvested periodically and is used to buyback USDs from the market of which 70% goes for USDs auto yield, and rest is used for SPA buyback and burn.
  * While doing a rebase the x amount of USDs is partially burnt (without changing the overall total supply) and the `creditsPerToken` value is adjusted such that the burnt amount is proportionally distributed across all rebasing wallets.

## Contract Documentation

**Inherits:** ERC20PermitUpgradeable, OwnableUpgradeable, ReentrancyGuardUpgradeable, [IUSDs](https://file+.vscode-resource.vscode-cdn.net/contracts/interfaces/IUSDs.sol/interface.IUSDs.md)

**Author:** Sperax Foundation

*ERC20 compatible contract for USDs supporting the rebase feature. This ERC20 token represents USDs on the Arbitrum (L2) network. Note that the invariant holds that the sum of balanceOf(x) for all x is not greater than totalSupply(). This is a consequence of the rebasing design. Integrations with USDs should be aware of this feature.*&#x20;

*Inspired by OUSD:* [*https://github.com/OriginProtocol/origindollar/blob/master/contracts/contracts/token/OUSD.sol*](https://github.com/OriginProtocol/origin-dollar/blob/master/contracts/contracts/token/OUSD.sol)

### **State Variables**

#### **MAX\_SUPPLY**

```solidity
uint256 private constant MAX_SUPPLY = ~uint128(0);

```

#### **\_totalSupply**

```solidity
uint256 internal _totalSupply;

```

#### **\_deprecated\_vars**

```solidity
uint256[4] private _deprecated_vars;

```

#### **\_allowances**

```solidity
mapping(address => mapping(address => uint256)) private _allowances;

```

#### **vault**

```solidity
address public vault;

```

#### **\_creditBalances**

```solidity
mapping(address => uint256) private _creditBalances;

```

#### **\_deprecated\_rebasingCredits**

```solidity
uint256 private _deprecated_rebasingCredits;

```

#### **rebasingCreditsPerToken**

```solidity
uint256 public rebasingCreditsPerToken;

```

#### **nonRebasingSupply**

```solidity
uint256 public nonRebasingSupply;

```

#### **nonRebasingCreditsPerToken**

```solidity
mapping(address => uint256) public nonRebasingCreditsPerToken;

```

#### **rebaseState**

```solidity
mapping(address => RebaseOptions) public rebaseState;

```

#### **\_deprecated\_gatewayAddr**

```solidity
address[2] private _deprecated_gatewayAddr;

```

#### **\_deprecated\_isUpgraded**

```solidity
mapping(address => bool) private _deprecated_isUpgraded;

```

#### **paused**

```solidity
bool public paused;

```

### **Functions**

#### **onlyVault**

Verifies that the caller is the Savings Manager contract.

```solidity
modifier onlyVault();

```

#### **constructor**

```solidity
constructor();

```

#### **initialize**

Initializes the contract with the provided name, symbol, and vault address.

```solidity
function initialize(string memory _nameArg, string memory _symbolArg, address _vaultAddress) external initializer;

```

**Parameters**

| Name           | Type    | Description                                                                                               |
| -------------- | ------- | --------------------------------------------------------------------------------------------------------- |
| \_nameArg      | string  | The name of the USDs token.                                                                               |
| \_symbolArg    | string  | The symbol of the USDs token.                                                                             |
| \_vaultAddress | address | The address where collaterals of USDs protocol reside, and major actions like USDs minting are initiated. |

#### **mint**

Mints new USDs tokens, increasing totalSupply.

```solidity
function mint(address _account, uint256 _amount) external override onlyVault nonReentrant;

```

**Parameters**

| Name      | Type    | Description                                                            |
| --------- | ------- | ---------------------------------------------------------------------- |
| \_account | address | The account address to which the newly minted USDs will be attributed. |
| \_amount  | uint256 | The amount of USDs to be minted.                                       |

#### **burn**

Burns tokens, decreasing totalSupply.

```solidity
function burn(uint256 _amount) external override nonReentrant;

```

**Parameters**

| Name     | Type    | Description         |
| -------- | ------- | ------------------- |
| \_amount | uint256 | The amount to burn. |

#### **rebaseOptIn**

Voluntary opt-in for rebase.

*Useful for smart-contract wallets.*

```solidity
function rebaseOptIn() external;

```

#### **rebaseOptOut**

Voluntary opt-out from rebase.

```solidity
function rebaseOptOut() external;

```

#### **rebaseOptIn**

Adds `_account` to the rebasing account list.

```solidity
function rebaseOptIn(address _account) external onlyOwner;

```

**Parameters**

| Name      | Type    | Description                     |
| --------- | ------- | ------------------------------- |
| \_account | address | Address of the desired account. |

#### **rebaseOptOut**

Adds `_account` to the non-rebasing account list.

```solidity
function rebaseOptOut(address _account) external onlyOwner;

```

**Parameters**

| Name      | Type    | Description                     |
| --------- | ------- | ------------------------------- |
| \_account | address | Address of the desired account. |

#### **rebase**

The rebase function. Modifies the supply without minting new tokens. This uses a change in the exchange rate between "credits" and USDs tokens to change balances.

```solidity
function rebase(uint256 _rebaseAmt) external override onlyVault nonReentrant;

```

**Parameters**

| Name        | Type    | Description                        |
| ----------- | ------- | ---------------------------------- |
| \_rebaseAmt | uint256 | The amount of USDs to rebase with. |

#### **updateVault**

Change the vault address.

```solidity
function updateVault(address _newVault) external onlyOwner;

```

**Parameters**

| Name       | Type    | Description            |
| ---------- | ------- | ---------------------- |
| \_newVault | address | The new vault address. |

#### **pauseSwitch**

Called by the owner to pause or unpause the contract.

```solidity
function pauseSwitch(bool _pause) external onlyOwner;

```

**Parameters**

| Name    | Type | Description                    |
| ------- | ---- | ------------------------------ |
| \_pause | bool | The state of the pause switch. |

#### **transfer**

Transfer tokens to a specified address.

```solidity
function transfer(address _to, uint256 _value) public override returns (bool);

```

**Parameters**

| Name    | Type    | Description                   |
| ------- | ------- | ----------------------------- |
| \_to    | address | The address to transfer to.   |
| \_value | uint256 | The amount to be transferred. |

**Returns**

| Name | Type | Description      |
| ---- | ---- | ---------------- |
|      | bool | True on success. |

#### **transferFrom**

Transfer tokens from one address to another.

```solidity
function transferFrom(address _from, address _to, uint256 _value) public override returns (bool);

```

**Parameters**

| Name    | Type    | Description                                          |
| ------- | ------- | ---------------------------------------------------- |
| \_from  | address | The address from which you want to send tokens.      |
| \_to    | address | The address to which the tokens will be transferred. |
| \_value | uint256 | The amount of tokens to be transferred.              |

**Returns**

| Name | Type | Description      |
| ---- | ---- | ---------------- |
|      | bool | true on success. |

#### **approve**

Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. This method is included for ERC20 compatibility.

*increaseAllowance and decreaseAllowance should be used instead. Changing an allowance with this method brings the risk that someone may transfer both the old and the new allowance - if they are both greater than zero - if a transfer transaction is mined before the later approve() call is mined.*

```solidity
function approve(address _spender, uint256 _value) public override returns (bool);

```

**Parameters**

| Name      | Type    | Description                            |
| --------- | ------- | -------------------------------------- |
| \_spender | address | The address that will spend the funds. |
| \_value   | uint256 | The amount of tokens to be spent.      |

**Returns**

| Name | Type | Description      |
| ---- | ---- | ---------------- |
|      | bool | true on success. |

#### **increaseAllowance**

Increase the amount of tokens that an owner has allowed a `_spender` to spend. This method should be used instead of approve() to avoid the double approval vulnerability described above.

```solidity
function increaseAllowance(address _spender, uint256 _addedValue) public override returns (bool);

```

**Parameters**

| Name         | Type    | Description                                        |
| ------------ | ------- | -------------------------------------------------- |
| \_spender    | address | The address that will spend the funds.             |
| \_addedValue | uint256 | The amount of tokens to increase the allowance by. |

**Returns**

| Name | Type | Description      |
| ---- | ---- | ---------------- |
|      | bool | true on success. |

#### **decreaseAllowance**

Decrease the amount of tokens that an owner has allowed a `_spender` to spend.

```solidity
function decreaseAllowance(address _spender, uint256 _subtractedValue) public override returns (bool);

```

**Parameters**

| Name              | Type    | Description                                        |
| ----------------- | ------- | -------------------------------------------------- |
| \_spender         | address | The address that will spend the funds.             |
| \_subtractedValue | uint256 | The amount of tokens to decrease the allowance by. |

**Returns**

| Name | Type | Description      |
| ---- | ---- | ---------------- |
|      | bool | true on success. |

#### **totalSupply**

Check the current total supply of USDs.

```solidity
function totalSupply() public view override(ERC20Upgradeable, IUSDs) returns (uint256);

```

**Returns**

| Name | Type    | Description               |
| ---- | ------- | ------------------------- |
|      | uint256 | The total supply of USDs. |

#### **balanceOf**

Gets the USDs balance of the specified address.

```solidity
function balanceOf(address _account) public view override returns (uint256);

```

**Parameters**

| Name      | Type    | Description                          |
| --------- | ------- | ------------------------------------ |
| \_account | address | The address to query the balance of. |

**Returns**

| Name | Type    | Description                                                                     |
| ---- | ------- | ------------------------------------------------------------------------------- |
|      | uint256 | A uint256 representing the amount of base units owned by the specified address. |

#### **creditsBalanceOf**

Gets the credits balance of the specified address.

```solidity
function creditsBalanceOf(address _account) public view returns (uint256, uint256);

```

**Parameters**

| Name      | Type    | Description                          |
| --------- | ------- | ------------------------------------ |
| \_account | address | The address to query the balance of. |

**Returns**

| Name | Type    | Description                                                             |
| ---- | ------- | ----------------------------------------------------------------------- |
|      | uint256 | (uint256, uint256) Credit balance and credits per token of the address. |
|      | uint256 |                                                                         |

#### **allowance**

Function to check the amount of tokens that an owner has allowed a spender.

```solidity
function allowance(address _owner, address _spender) public view override returns (uint256);

```

**Parameters**

| Name      | Type    | Description                            |
| --------- | ------- | -------------------------------------- |
| \_owner   | address | The address that owns the funds.       |
| \_spender | address | The address that will spend the funds. |

**Returns**

| Name | Type    | Description                                           |
| ---- | ------- | ----------------------------------------------------- |
|      | uint256 | The number of tokens still available for the spender. |

#### **\_mint**

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.*

```solidity
function _mint(address _account, uint256 _amount) internal override;

```

**Parameters**

| Name      | Type    | Description                                                            |
| --------- | ------- | ---------------------------------------------------------------------- |
| \_account | address | The account address to which the newly minted USDs will be attributed. |
| \_amount  | uint256 | The amount of USDs that will be minted.                                |

#### **\_burn**

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.\*

```solidity
function _burn(address _account, uint256 _amount) internal override;

```

**Parameters**

| Name      | Type    | Description                                            |
| --------- | ------- | ------------------------------------------------------ |
| \_account | address | The account address from which the USDs will be burnt. |
| \_amount  | uint256 | The amount of USDs that will be burnt.                 |

#### **\_executeTransfer**

For non-rebasing accounts credit amount = \_amount

Update the count of non-rebasing credits in response to a transfer

```solidity
function _executeTransfer(address _from, address _to, uint256 _value) private;

```

**Parameters**

| Name    | Type    | Description                                          |
| ------- | ------- | ---------------------------------------------------- |
| \_from  | address | The address from which you want to send tokens.      |
| \_to    | address | The address to which the tokens will be transferred. |
| \_value | uint256 | Amount of USDs to transfer                           |

#### **\_rebaseOptIn**

Add a contract address to the non-rebasing exception list. I.e., the address's balance will be part of rebases so the account will be exposed to upside and downside.

```solidity
function _rebaseOptIn(address _account) private;

```

**Parameters**

| Name      | Type    | Description                                  |
| --------- | ------- | -------------------------------------------- |
| \_account | address | address of the account opting in for rebase. |

#### **\_rebaseOptOut**

Remove a contract address from the non-rebasing exception list.

```solidity
function _rebaseOptOut(address _account) private;

```

#### **\_isNonRebasingAccount**

Is an account using rebasing accounting or non-rebasing accounting? Also, ensure contracts are non-rebasing if they have not opted in.

```solidity
function _isNonRebasingAccount(address _account) private returns (bool);

```

**Parameters**

| Name      | Type    | Description             |
| --------- | ------- | ----------------------- |
| \_account | address | Address of the account. |

#### **\_ensureNonRebasingMigration**

Ensures internal account for rebasing and non-rebasing credits and supply is updated following the deployment of frozen yield change.

```solidity
function _ensureNonRebasingMigration(address _account) private;

```

**Parameters**

| Name      | Type    | Description             |
| --------- | ------- | ----------------------- |
| \_account | address | Address of the account. |

#### **\_balanceOf**

Calculates the balance of the account.

*Function assumes the \_account is already upgraded.*

```solidity
function _balanceOf(address _account) private view returns (uint256);

```

**Parameters**

| Name      | Type    | Description             |
| --------- | ------- | ----------------------- |
| \_account | address | Address of the account. |

#### **\_creditsPerToken**

Get the credits per token for an account. Returns a fixed amount if the account is non-rebasing.

```solidity
function _creditsPerToken(address _account) private view returns (uint256);

```

**Parameters**

| Name      | Type    | Description             |
| --------- | ------- | ----------------------- |
| \_account | address | Address of the account. |

#### **\_isNotPaused**

Validates if the contract is not paused.

```solidity
function _isNotPaused() private view;

```

### **Events**

#### **TotalSupplyUpdated**

```solidity
event TotalSupplyUpdated(uint256 totalSupply, uint256 rebasingCredits, uint256 rebasingCreditsPerToken);

```

#### **Paused**

```solidity
event Paused(bool isPaused);

```

#### **VaultUpdated**

```solidity
event VaultUpdated(address newVault);

```

#### **RebaseOptIn**

```solidity
event RebaseOptIn(address indexed account);

```

#### **RebaseOptOut**

```solidity
event RebaseOptOut(address indexed account);

```

### **Errors**

#### **CallerNotVault**

```solidity
error CallerNotVault(address caller);

```

#### **ContractPaused**

```solidity
error ContractPaused();

```

#### **IsAlreadyRebasingAccount**

```solidity
error IsAlreadyRebasingAccount(address account);

```

#### **IsAlreadyNonRebasingAccount**

```solidity
error IsAlreadyNonRebasingAccount(address account);

```

#### **CannotIncreaseZeroSupply**

```solidity
error CannotIncreaseZeroSupply();

```

#### **InvalidRebase**

```solidity
error InvalidRebase();

```

#### **TransferToZeroAddr**

```solidity
error TransferToZeroAddr();

```

#### **TransferGreaterThanBal**

```solidity
error TransferGreaterThanBal(uint256 val, uint256 bal);

```

#### **MintToZeroAddr**

```solidity
error MintToZeroAddr();

```

#### **MaxSupplyReached**

```solidity
error MaxSupplyReached(uint256 totalSupply);

```

### **Enums**

#### **RebaseOptions**

```solidity
enum RebaseOptions {
    NotSet,
    OptOut,
    OptIn
}
```
