Skip to content

Commit

Permalink
Merge pull request #16 from mountainprotocol/fix/N-04
Browse files Browse the repository at this point in the history
N-04 Fix
  • Loading branch information
mattiascaricato committed Jun 23, 2023
2 parents 27b01e9 + c36d050 commit 500a2c9
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 91 deletions.
24 changes: 12 additions & 12 deletions README.md
@@ -1,13 +1,13 @@
# Mountain Protocol USD

This smart contract implements a custom rebasing ERC-20 token with additional features like pausing, blocklisting, access control, and upgradability. The contract aims to reflect the T-Bills APY into the token value through a reward multiplier mechanism. Users receive a proportional number of shares when they deposit tokens, and the number of tokens they can withdraw is calculated based on the current reward multiplier. The addRewardMultiplier function is called once a day to adjust the reward multiplier, ensuring accurate reflection of the yield from 3 months maturity T-Bills.
This smart contract implements a custom rebasing ERC-20 token with additional features like pausing, block/unblock, access control, and upgradability. The contract aims to reflect the T-Bills APY into the token value through a reward multiplier mechanism. Users receive a proportional number of shares when they deposit tokens, and the number of tokens they can withdraw is calculated based on the current reward multiplier. The addRewardMultiplier function is called once a day to adjust the reward multiplier, ensuring accurate reflection of the yield from 3 months maturity T-Bills.

## Features

- OpenZeppelin Access Control
- Rebasing token mechanism
- Minting and burning functionality
- Blocklisting accounts
- Block/Unblock accounts
- Pausing emergency stop mechanism
- Reward multiplier system
- EIP-2612 permit support
Expand Down Expand Up @@ -93,21 +93,21 @@ npx hardhat help
- `symbol()`: Returns the symbol of the token.
- `decimals()`: Returns the number of decimals the token uses.
- `convertToShares(uint256 amount)`: Converts an amount of tokens to shares.
- `convertToAmount(uint256 shares)`: Converts an amount of shares to tokens.
- `convertToTokens(uint256 shares)`: Converts an amount of shares to tokens.
- `totalShares()`: Returns the total amount of shares.
- `totalSupply()`: Returns the total supply.
- `balanceOf(address account)`: Returns the balance of account.
- `sharesOf(address account)`: Returns the shares of account.
- `mint(address to, uint256 amount)`: Creates new tokens to the specified address.
- `burn(address from, uint256 amount)`: Destroys tokens from the specified address.
- `transfer(address to, uint256 amount)`: Transfers tokens between addresses.
- `blocklistAccounts(address[] addresses)`: Blocklists multiple accounts at once.
- `unblocklistAccounts(address[] addresses)`: Unblocklists multiple accounts at once.
- `isBlocklisted(address account)`: Checks if account is blocklisted.
- `blockAccounts(address[] addresses)`: Blocks multiple accounts at once.
- `unblockAccounts(address[] addresses)`: Unblocks multiple accounts at once.
- `isBlocked(address account)`: Checks if account is blocked.
- `pause()`: Pauses the contract, halting token transfers.
- `unpause()`: Unpauses the contract, allowing token transfers.
- `setRewardMultiplier(uint256 rewardMultiplier_)`: Sets the reward multiplier.
- `addRewardMultiplier(uint256 rewardMultiplier_)`: Adds the provided interest rate to the current reward multiplier.
- `setRewardMultiplier(uint256 _rewardMultiplier)`: Sets the reward multiplier.
- `addRewardMultiplier(uint256 _rewardMultiplierIncrement)`: Adds the given amount to the current reward multiplier.
- `approve(address spender, uint256 amount)`: Approves an allowance for a spender.
- `allowance(address owner, address spender)`: Returns the allowance for a spender.
- `transferFrom(address from, address to, uint256 amount)`: Moves tokens from an address to another one using the allowance mechanism.
Expand All @@ -125,8 +125,8 @@ npx hardhat help
- `_beforeTokenTransfer(address from, address to, uint256 amount)`: Hook that is called before any transfer of tokens.
- `_afterTokenTransfer(address from, address to, uint256 amount)`: Hook that is called after any transfer of tokens.
- `_transfer(address from, address to, uint256 amount)`: Internal function to transfer tokens between addresses.
- `_blocklistAccount(address account)`: Internal function to blocklists account.
- `_unblocklistAccount(address account)`: Internal function to unblocklists account.
- `_blockAccount(address account)`: Internal function to block account.
- `_unblockAccount(address account)`: Internal function to unblock account.
- `_setRewardMultiplier(uint256 _rewardMultiplier)`: Internal function to sets the reward multiplier.
- `_spendAllowance(address owner, address spender, uint256 amount)`: Internal function to spend an allowance.
- `_useNonce(address owner)`: Increments and returns the current nonce for a given address.
Expand All @@ -137,8 +137,8 @@ npx hardhat help
- `Transfer(from indexed addr, to uint256, amount uint256)`: Emitted when transferring tokens.
- `RewardMultiplier(uint256 indexed value)`: Emitted when the reward multiplier has changed.
- `Approval(address indexed owner, address indexed spender, uint256 value)`: Emitted when the allowance of a spender for an owner is set.
- `AddressBlocklisted(address indexed addr)`: Emitted when an address is blocklisted.
- `AddressUnBlocklisted(address indexed addr)`: Emitted when an address is removed from the blocklist.
- `AddressBlocked(address indexed addr)`: Emitted when an address is blocked.
- `AddressUnBlocked(address indexed addr)`: Emitted when an address is removed from the blocklist.
- `Paused(address account)`: Emitted when the pause is triggered by account.
- `Unpaused(address account)`: Emitted when the unpause is triggered by account.

Expand Down
54 changes: 27 additions & 27 deletions contracts/USDM.sol
Expand Up @@ -45,8 +45,8 @@ contract USDM is
bytes32 public constant UPGRADE_ROLE = keccak256("UPGRADE_ROLE");
bytes32 public constant PAUSE_ROLE = keccak256("PAUSE_ROLE");

event AccountBlocklisted(address indexed addr);
event AccountUnblocklisted(address indexed addr);
event AccountBlocked(address indexed addr);
event AccountUnblocked(address indexed addr);
event RewardMultiplier(uint256 indexed value);

/**
Expand Down Expand Up @@ -124,7 +124,7 @@ contract USDM is
* @param shares The amount of shares to convert.
* @return The equivalent amount of tokens.
*/
function convertToAmount(uint256 shares) public view returns (uint256) {
function convertToTokens(uint256 shares) public view returns (uint256) {
return (shares * rewardMultiplier) / _BASE;
}

Expand All @@ -141,7 +141,7 @@ contract USDM is
* @return The total supply of tokens.
*/
function totalSupply() external view returns (uint256) {
return convertToAmount(_totalShares);
return convertToTokens(_totalShares);
}

/**
Expand All @@ -161,7 +161,7 @@ contract USDM is
* @return The balance of the specified address.
*/
function balanceOf(address account) external view returns (uint256) {
return convertToAmount(sharesOf(account));
return convertToTokens(sharesOf(account));
}

/**
Expand Down Expand Up @@ -260,7 +260,7 @@ contract USDM is
function _beforeTokenTransfer(address from, address /* to */, uint256 /* amount */) private view {
// Each blocklist check is an SLOAD, which is gas intensive.
// We only block sender not receiver, so we don't tax every user
require(!isBlocklisted(from), "Address is blocklisted");
require(!isBlocked(from), "Address is blocked");
// Useful for scenarios such as preventing trades until the end of an evaluation
// period, or having an emergency switch for freezing all token transfers in the
// event of a large bug.
Expand Down Expand Up @@ -329,33 +329,33 @@ contract USDM is
}

/**
* @dev Internal function that blocklists the specified address.
* @param account The address to blocklist.
* @dev Internal function that blocks the specified address.
* @param account The address to block.
*/
function _blocklistAccount(address account) private {
require(!_blocklist[account], "Address already blocklisted");
function _blockAccount(address account) private {
require(!_blocklist[account], "Address already blocked");
_blocklist[account] = true;
emit AccountBlocklisted(account);
emit AccountBlocked(account);
}

/**
* @dev Internal function that removes the specified address from the blocklist.
* @param account The address to remove from the blocklist.
*/
function _unblocklistAccount(address account) private {
require(_blocklist[account], "Address is not blocklisted");
function _unblockAccount(address account) private {
require(_blocklist[account], "Address is not blocked");
_blocklist[account] = false;
emit AccountUnblocklisted(account);
emit AccountUnblocked(account);
}

/**
* @notice Blocklists multiple accounts at once.
* @notice Blocks multiple accounts at once.
* @dev This function can only be called by an account with BLOCKLIST_ROLE.
* @param addresses An array of addresses to be blocklisted.
* @param addresses An array of addresses to be blocked.
*/
function blocklistAccounts(address[] calldata addresses) external onlyRole(BLOCKLIST_ROLE) {
function blockAccounts(address[] calldata addresses) external onlyRole(BLOCKLIST_ROLE) {
for (uint256 i = 0; i < addresses.length; i++) {
_blocklistAccount(addresses[i]);
_blockAccount(addresses[i]);
}
}

Expand All @@ -364,18 +364,18 @@ contract USDM is
* @dev This function can only be called by an account with BLOCKLIST_ROLE.
* @param addresses An array of addresses to be removed from the blocklist.
*/
function unblocklistAccounts(address[] calldata addresses) external onlyRole(BLOCKLIST_ROLE) {
function unblockAccounts(address[] calldata addresses) external onlyRole(BLOCKLIST_ROLE) {
for (uint256 i = 0; i < addresses.length; i++) {
_unblocklistAccount(addresses[i]);
_unblockAccount(addresses[i]);
}
}

/**
* @notice Checks if the specified address is blocklisted.
* @notice Checks if the specified address is blocked.
* @param account The address to check.
* @return A boolean value indicating whether the address is blocklisted.
* @return A boolean value indicating whether the address is blocked.
*/
function isBlocklisted(address account) public view returns (bool) {
function isBlocked(address account) public view returns (bool) {
return _blocklist[account];
}

Expand Down Expand Up @@ -420,12 +420,12 @@ contract USDM is
/**
* @notice Adds the given amount to the current reward multiplier.
* @dev This function can only be called by an account with ORACLE_ROLE.
* @param _rewardMultiplier The new reward multiplier.
* @param _rewardMultiplierIncrement The new reward multiplier.
*/
function addRewardMultiplier(uint256 _rewardMultiplier) external onlyRole(ORACLE_ROLE) {
require(_rewardMultiplier > 0, "Invalid reward multiplier");
function addRewardMultiplier(uint256 _rewardMultiplierIncrement) external onlyRole(ORACLE_ROLE) {
require(_rewardMultiplierIncrement > 0, "Invalid reward multiplier");

_setRewardMultiplier(rewardMultiplier + _rewardMultiplier);
_setRewardMultiplier(rewardMultiplier + _rewardMultiplierIncrement);
}

/**
Expand Down

0 comments on commit 500a2c9

Please sign in to comment.