Skip to content

Commit

Permalink
Merge pull request #10 from stader-labs/feat/deploy-SD-L2
Browse files Browse the repository at this point in the history
Add SD token impl for L2
  • Loading branch information
blockgroot authored Sep 13, 2024
2 parents 5230676 + e2eb9c7 commit 709c5c0
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 0 deletions.
86 changes: 86 additions & 0 deletions contracts/Stader.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.22;

import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import { ERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";

import { IERC20Burnable } from "./IERC20Burnable.sol";

/**
* @title Stader token Contract for L2s
* @author Stader Labs
* @notice The ERC20 contract for the Stader token
*/
contract Stader is Initializable, ERC20Upgradeable, PausableUpgradeable, AccessControlUpgradeable, IERC20Burnable {
error ZeroAddress();

bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}

modifier requireNonZeroAddress(address _addr) {
if (_addr == address(0)) {
revert ZeroAddress();
}
_;
}

function initialize(address _admin) external initializer requireNonZeroAddress(_admin) {
__ERC20_init("Stader", "SD");
__Pausable_init();
__AccessControl_init();

_grantRole(DEFAULT_ADMIN_ROLE, _admin);
}

/**
* @notice Mints SD token when called by an authorized caller
* @param to the account to mint to
* @param amount the amount of SD token to mint
*/
function mint(address to, uint256 amount) external onlyRole(MINTER_ROLE) whenNotPaused {
_mint(to, amount);
}

/**
* @notice Burns SD token when called by an authorized caller
* @param account the account to burn from
* @param amount the amount of SD token to burn
*/
function burnFrom(address account, uint256 amount) external onlyRole(BURNER_ROLE) whenNotPaused {
_burn(account, amount);
}

/**
* used by certain bridge contracts to burn tokens
* @dev the caller must have the BURNER_ROLE as well
* as the number of requested tokens to burn
* @param amount the amount of SD token to burn
*/
function burn(uint256 amount) external onlyRole(BURNER_ROLE) whenNotPaused {
_burn(_msgSender(), amount);
}

/**
* @dev Triggers stopped state.
* Contract must not be paused.
*/
function pause() external onlyRole(PAUSER_ROLE) {
_pause();
}

/**
* @dev Returns to normal state.
* Contract must be paused
*/
function unpause() external onlyRole(DEFAULT_ADMIN_ROLE) {
_unpause();
}
}
69 changes: 69 additions & 0 deletions script/DeployStader.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// SPDX-License-Identifier: GNU-3.0-or-later
pragma solidity ^0.8.22;

import { Script, console } from "forge-std/Script.sol";

import { ProxyAdmin } from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";

import {
ITransparentUpgradeableProxy,
TransparentUpgradeableProxy
} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";

import { Stader } from "../contracts/Stader.sol";

contract DeployStader is Script {
event DeployedStader(address staderProxy, address sd);

function deployProxy() public {
address admin = vm.envAddress("STADER_ADMIN");
address proxyAdmin = vm.envAddress("PROXY_ADMIN");
console.log("ProxyAdmin: ", proxyAdmin);
address deploymentAdmin = msg.sender;
vm.startBroadcast();
Stader implementation = new Stader();
bytes memory initializationData = abi.encodeWithSelector(Stader.initialize.selector, deploymentAdmin);
TransparentUpgradeableProxy proxy =
new TransparentUpgradeableProxy(address(implementation), proxyAdmin, initializationData);
console.log("Stader deployed to proxy at: ", address(proxy));
emit DeployedStader(address(proxy), address(implementation));
Stader sd = Stader(address(proxy));
if (admin != deploymentAdmin) {
sd.grantRole(sd.DEFAULT_ADMIN_ROLE(), admin);
sd.renounceRole(sd.DEFAULT_ADMIN_ROLE(), deploymentAdmin);
console.log("Stader set admin to: ", admin);
console.log("Stader renounced admin: ", deploymentAdmin);
} else {
console.log("Stader set admin to: ", admin);
}
vm.stopBroadcast();
}

function upgradeProxy() public {
address proxy = vm.envAddress("STADER");
vm.startBroadcast();
Stader implementation = new Stader();
ITransparentUpgradeableProxy proxyInterface = ITransparentUpgradeableProxy(proxy);
proxyInterface.upgradeTo(address(implementation));
vm.stopBroadcast();
}

function deployImplementation() public {
vm.startBroadcast();
Stader implementation = new Stader();
console.log("Stader deployed at: ", address(implementation));
vm.stopBroadcast();
}

function setupGrants() public {
address proxy = vm.envAddress("STADER");
address ccipTokenPool = vm.envAddress("TOKEN_POOL");
address admin = vm.envAddress("STADER_ADMIN");
Stader sd = Stader(proxy);
vm.startBroadcast();
sd.grantRole(sd.MINTER_ROLE(), ccipTokenPool);
sd.grantRole(sd.BURNER_ROLE(), ccipTokenPool);
sd.grantRole(sd.PAUSER_ROLE(), admin);
vm.stopBroadcast();
}
}

0 comments on commit 709c5c0

Please sign in to comment.