Skip to content

Commit

Permalink
add vault for pUSD
Browse files Browse the repository at this point in the history
  • Loading branch information
ungaro committed Nov 13, 2024
1 parent 2131910 commit e415bc9
Showing 1 changed file with 123 additions and 21 deletions.
144 changes: 123 additions & 21 deletions nest/src/token/pUSD.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,48 @@ import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/I
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import { ERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";

import { BoringVault } from "./BoringVault.sol";
import { SafeTransferLib } from "@solmate/utils/SafeTransferLib.sol";

/**
* @title pUSD
* @author Eugene Y. Q. Shen, Alp Guneysel
* @notice Unified Plume USD stablecoin
*/
contract pUSD is Initializable, ERC20Upgradeable, AccessControlUpgradeable, UUPSUpgradeable {

// Constants
using SafeTransferLib for ERC20;

// ========== ROLES ==========

/// @notice Role for the admin of pUSD
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
/// @notice Role for the upgrader of pUSD
bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE");
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
bytes32 public constant VAULT_ADMIN_ROLE = keccak256("VAULT_ADMIN_ROLE");
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");

// ========== STATE VARIABLES ==========

/// @notice The vault contract for internal accounting
IVault public vault;

/// @notice Whether transfers are paused
bool public paused;

// ========== EVENTS ==========

event VaultChanged(address oldVault, address newVault);
event Paused(address account);
event Unpaused(address account);

// Initializer
// ========== MODIFIERS ==========

modifier whenNotPaused() {
require(!paused, "PUSD: paused");
_;
}

// ========== CONSTRUCTOR & INITIALIZER ==========

/**
* @notice Prevent the implementation contract from being initialized or reinitialized
Expand All @@ -35,27 +62,23 @@ contract pUSD is Initializable, ERC20Upgradeable, AccessControlUpgradeable, UUPS
* @dev Give all roles to the admin address passed into the constructor
* @param owner_ Address of the owner of pUSD
*/
function initialize(
address owner_
) public initializer {
__ERC20_init("Plume USD", "pUSD");
function initialize(address _vault, address admin) external initializer {
__ERC20_init("", ""); // Empty strings since we override name() and symbol()
__AccessControl_init();
__UUPSUpgradeable_init();

_grantRole(DEFAULT_ADMIN_ROLE, owner_);
_grantRole(ADMIN_ROLE, owner_);
_grantRole(UPGRADER_ROLE, owner_);
}
vault = IVault(_vault);

// Override Functions
// Setup roles
_grantRole(DEFAULT_ADMIN_ROLE, admin);
_grantRole(UPGRADER_ROLE, admin);
_grantRole(MINTER_ROLE, admin);
_grantRole(BURNER_ROLE, admin);
_grantRole(VAULT_ADMIN_ROLE, admin);
_grantRole(PAUSER_ROLE, admin);
}

/**
* @notice Revert when `msg.sender` is not authorized to upgrade the contract
* @param newImplementation Address of the new implementation
*/
function _authorizeUpgrade(
address newImplementation
) internal override onlyRole(UPGRADER_ROLE) { }
// ========== METADATA OVERRIDES ==========

function decimals() public pure override returns (uint8) {
return 6;
Expand All @@ -69,4 +92,83 @@ contract pUSD is Initializable, ERC20Upgradeable, AccessControlUpgradeable, UUPS
return "pUSD";
}

// ========== ADMIN FUNCTIONS ==========

function setVault(
address newVault
) external onlyRole(VAULT_ADMIN_ROLE) {
address oldVault = address(vault);
vault = IVault(newVault);
emit VaultChanged(oldVault, newVault);
}

function pause() external onlyRole(PAUSER_ROLE) {
paused = true;
emit Paused(msg.sender);
}

function unpause() external onlyRole(PAUSER_ROLE) {
paused = false;
emit Unpaused(msg.sender);
}

// Required override for UUPSUpgradeable
function _authorizeUpgrade(
address newImplementation
) internal override onlyRole(UPGRADER_ROLE) { }

// ========== ERC20 OVERRIDES ==========

function transfer(address to, uint256 amount) public override whenNotPaused returns (bool) {
address owner = _msgSender();
bool success = super.transfer(to, amount);

// Perform actual transfer in vault
vault.transferFrom(owner, to, amount);

return success;
}

function transferFrom(address from, address to, uint256 amount) public override whenNotPaused returns (bool) {
bool success = super.transferFrom(from, to, amount);

// Perform actual transfer in vault
vault.transferFrom(from, to, amount);

return success;
}

function approve(address spender, uint256 amount) public override whenNotPaused returns (bool) {
bool success = super.approve(spender, amount);

// Approve in vault as well
vault.approve(spender, amount);

return success;
}

// ========== MINT/BURN ==========

function mint(address to, uint256 amount) external onlyRole(MINTER_ROLE) {
_mint(to, amount);

// Mint in vault
vault.enter(address(this), address(this), 0, to, amount);
}

function burn(address from, uint256 amount) external onlyRole(BURNER_ROLE) {
_burn(from, amount);

// Burn in vault
vault.exit(address(this), address(this), 0, from, amount);
}

// ========== INTERFACE SUPPORT ==========

function supportsInterface(
bytes4 interfaceId
) public view override(AccessControlUpgradeable) returns (bool) {
return super.supportsInterface(interfaceId);
}

}

0 comments on commit e415bc9

Please sign in to comment.