Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deployment / upgrade script for StRIF version 2 #95

Merged
merged 7 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,8 @@ Successfully verified contract "contracts/EarlyAdopters.sol:EarlyAdopters" for n
| ---------------------------------------------- | ------------------------------------------ |
| GovernorRootstockCollective impl | 0x2109FF4a9D5548a21F877cA937Ac5847Fde49694 |
| GovernorRootstockCollective proxy | 0x91a8E4A070B4BA4bf2e2a51Cb42BdeDf8FFB9b5a |
| StRIFToken impl | 0x4861198e9A6814EBfb152552D1b1a37426C54D23 |
| StRIFToken proxy | 0xFff256c3451D5cF59653Cfe71950AE9ba2F5f0Ef |
| StRIFToken proxy | 0x4861198e9A6814EBfb152552D1b1a37426C54D23 |
| StRIFToken impl | 0xFff256c3451D5cF59653Cfe71950AE9ba2F5f0Ef |
| DaoTimelockUpgradableRootstockCollective impl | 0x2AEdf0B35651934cF3BEC855cbCE207bBA0C4aB5 |
| DaoTimelockUpgradableRootstockCollective proxy | 0x5eDA6fA73350291F7D7cFC7ad93F48189f1333ef |
| TreasuryRootstockCollective | 0x47C969d7ae7A377BeaD553c2899D9B83A90e0772 |
Expand Down
69 changes: 1 addition & 68 deletions contracts/StRIFToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,6 @@ import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Ini
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {ERC165Checker} from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";

import {ICollectiveRewardsCheck} from "./interfaces/ICollectiveRewardsCheck.sol";

contract StRIFToken is
Initializable,
Expand All @@ -25,24 +21,6 @@ contract StRIFToken is
OwnableUpgradeable,
UUPSUpgradeable
{
using Address for address;
using ERC165Checker for address;

/// @notice The address of the CollectiveRewards Contract
address public collectiveRewardsCheck;
/// @notice The flag indicating that the CollectiveRewards error
/// is desired to be skipped
bool private _shouldErrorBeSkipped;

error STRIFStakedInCollectiveRewardsCanWithdraw(bool canWithdraw);
error STRIFSupportsERC165(bool _supports);
error STRIFSupportsICollectiveRewardsCheck(bool _supports);
error CollectiveRewardsErrored(string reason);
error CollectiveRewardsErroredBytes(bytes reason);

event STRIFCollectiveRewardsErrorSkipChangedTo(bool shouldBeSkipped);
event CollectiveRewardsAddressHasBeenChanged(address collectiveRewardsAddress);

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
Expand Down Expand Up @@ -109,44 +87,6 @@ contract StRIFToken is
_delegate(to, to);
}

//checks CollectiveRewards for stake
modifier _checkCollectiveRewardsForStake(address staker, uint256 value) {
_;
if (collectiveRewardsCheck != address(0)) {
try ICollectiveRewardsCheck(collectiveRewardsCheck).canWithdraw(staker, value) returns (
bool canWithdraw
) {
if (!canWithdraw) {
revert STRIFStakedInCollectiveRewardsCanWithdraw(false);
}
} catch Error(string memory reason) {
if (!_shouldErrorBeSkipped) {
revert CollectiveRewardsErrored(reason);
}
} catch (bytes memory reason) {
if (!_shouldErrorBeSkipped) {
revert CollectiveRewardsErroredBytes(reason);
}
}
}
}

// checks that received address has method which can successfully be called
// before setting it to state
function setCollectiveRewardsAddress(address collectiveRewardsAddress) public onlyOwner {
if (!collectiveRewardsAddress.supportsInterface(type(ICollectiveRewardsCheck).interfaceId)) {
revert STRIFSupportsICollectiveRewardsCheck(false);
}

collectiveRewardsCheck = collectiveRewardsAddress;
emit CollectiveRewardsAddressHasBeenChanged(collectiveRewardsAddress);
}

function setCollectiveRewardsErrorSkipFlag(bool shouldBeSkipped) public onlyOwner {
_shouldErrorBeSkipped = shouldBeSkipped;
emit STRIFCollectiveRewardsErrorSkipChangedTo(shouldBeSkipped);
}

// The following functions are overrides required by Solidity.

//solhint-disable-next-line no-empty-blocks
Expand All @@ -160,17 +100,10 @@ contract StRIFToken is
address from,
address to,
uint256 value
) internal override(ERC20Upgradeable, ERC20VotesUpgradeable) _checkCollectiveRewardsForStake(from, value) {
) internal override(ERC20Upgradeable, ERC20VotesUpgradeable) {
super._update(from, to, value);
}

function withdrawTo(
address account,
uint256 value
) public virtual override _checkCollectiveRewardsForStake(account, value) returns (bool) {
return super.withdrawTo(account, value);
}

function nonces(
address owner
) public view override(ERC20PermitUpgradeable, NoncesUpgradeable) returns (uint256) {
Expand Down
188 changes: 188 additions & 0 deletions contracts/StRIFTokenV02.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.0.0
pragma solidity ^0.8.20;

import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import {ERC20PermitUpgradeable, NoncesUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol";
import {ERC20VotesUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20VotesUpgradeable.sol";
import {ERC20WrapperUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20WrapperUpgradeable.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {ERC165Checker} from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";

import {ICollectiveRewardsCheck} from "./interfaces/ICollectiveRewardsCheck.sol";

/**
* @dev StRIFTokenV02 adds support for CollectiveRewards
*/
contract StRIFTokenV02 is
Initializable,
ERC20Upgradeable,
ERC20PermitUpgradeable,
ERC20VotesUpgradeable,
ERC20WrapperUpgradeable,
OwnableUpgradeable,
UUPSUpgradeable
{
using Address for address;
using ERC165Checker for address;

/// @notice The address of the CollectiveRewards Contract
address public collectiveRewardsCheck;
/// @notice The flag indicating that the CollectiveRewards error
/// is desired to be skipped
bool private _shouldErrorBeSkipped;

error STRIFStakedInCollectiveRewardsCanWithdraw(bool canWithdraw);
error STRIFSupportsERC165(bool _supports);
error STRIFSupportsICollectiveRewardsCheck(bool _supports);
error CollectiveRewardsErrored(string reason);
error CollectiveRewardsErroredBytes(bytes reason);

event STRIFCollectiveRewardsErrorSkipChangedTo(bool shouldBeSkipped);
event CollectiveRewardsAddressHasBeenChanged(address collectiveRewardsAddress);

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

function initialize(IERC20 rifToken, address initialOwner) public initializer {
__ERC20_init("StRIFToken", "stRIF");
__ERC20Permit_init("StRIFToken");
__ERC20Votes_init();
__ERC20Wrapper_init(rifToken);
__Ownable_init(initialOwner);
__UUPSUpgradeable_init();
}

function initializeV2() public onlyProxy reinitializer(2) {}

function version() public pure virtual returns (uint64) {
return 2;
}

/**
* @dev Allows token holder to transfer tokens to another account, after which
* the recipient automatically delegates votes to themselves if they do
* not already have a delegate.
* Transfer and delegation happen within one transaction.
* @param to The address of the recipient of the token transfer
* @param value The amount of tokens being transferred
*/
function transferAndDelegate(address to, uint256 value) public virtual {
transfer(to, value);
_autoDelegate(to, value);
}

/**
* @dev Allows a token holder to transfer tokens from one account to another account,
* after which the recipient automatically delegates votes to themselves if they do
* not already have a delegate. This function is analogous to `transferAndDelegate` and
* exists as a counterpart to the `transferFrom` function from the ERC-20 standard.
*
* @param from The address of the account to transfer tokens from
* @param to The address of the recipient of the token transfer
* @param value The amount of tokens being transferred
*/
function transferFromAndDelegate(address from, address to, uint256 value) public virtual {
transferFrom(from, to, value);
_autoDelegate(to, value);
}

/**
* @dev Allows to mint stRIFs from underlying RIF tokens (stake)
* and delegate gained voting power to a provided address
* @param to a target address for minting and delegation
* @param value amount of RIF tokens to stake
*/
function depositAndDelegate(address to, uint256 value) public virtual {
depositFor(to, value);
_autoDelegate(to, value);
}

/**
* @dev Internal function to automatically delegate votes to the recipient
* after a token transfer, if the recipient does not already have a delegate.
* Delegation only occurs if the transfer amount is greater than zero.
*
* @param to The address of the recipient of the token transfer.
* @param value The amount of tokens being transferred.
*/
function _autoDelegate(address to, uint256 value) internal virtual {
if (value == 0 || delegates(to) != address(0)) return;
_delegate(to, to);
}

//checks CollectiveRewards for stake
modifier _checkCollectiveRewardsForStake(address staker, uint256 value) {
_;
if (collectiveRewardsCheck != address(0)) {
try ICollectiveRewardsCheck(collectiveRewardsCheck).canWithdraw(staker, value) returns (
bool canWithdraw
) {
if (!canWithdraw) {
revert STRIFStakedInCollectiveRewardsCanWithdraw(false);
}
} catch Error(string memory reason) {
if (!_shouldErrorBeSkipped) {
revert CollectiveRewardsErrored(reason);
}
} catch (bytes memory reason) {
if (!_shouldErrorBeSkipped) {
revert CollectiveRewardsErroredBytes(reason);
}
}
}
}

// checks that received address has method which can successfully be called
// before setting it to state
function setCollectiveRewardsAddress(address collectiveRewardsAddress) public onlyOwner {
if (!collectiveRewardsAddress.supportsInterface(type(ICollectiveRewardsCheck).interfaceId)) {
revert STRIFSupportsICollectiveRewardsCheck(false);
}

collectiveRewardsCheck = collectiveRewardsAddress;
emit CollectiveRewardsAddressHasBeenChanged(collectiveRewardsAddress);
}

function setCollectiveRewardsErrorSkipFlag(bool shouldBeSkipped) public onlyOwner {
_shouldErrorBeSkipped = shouldBeSkipped;
emit STRIFCollectiveRewardsErrorSkipChangedTo(shouldBeSkipped);
}

// The following functions are overrides required by Solidity.

//solhint-disable-next-line no-empty-blocks
function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}

function decimals() public view override(ERC20Upgradeable, ERC20WrapperUpgradeable) returns (uint8) {
return super.decimals();
}

function _update(
address from,
address to,
uint256 value
) internal override(ERC20Upgradeable, ERC20VotesUpgradeable) _checkCollectiveRewardsForStake(from, value) {
super._update(from, to, value);
}

function withdrawTo(
address account,
uint256 value
) public virtual override _checkCollectiveRewardsForStake(account, value) returns (bool) {
return super.withdrawTo(account, value);
}

function nonces(
address owner
) public view override(ERC20PermitUpgradeable, NoncesUpgradeable) returns (uint256) {
return super.nonces(owner);
}
}
21 changes: 21 additions & 0 deletions ignition/modules/StRifV02Module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* This Hardhat Ignition module upgrades StRIF contract v.1 to v.2
*/
import { buildModule } from '@nomicfoundation/hardhat-ignition/modules'

export const stRifV02Module = buildModule('StRIFTokenV02', m => {
const stRIFTokenProxyAddress = m.getParameter('StRifAddress')

const stRIFTokenProxy = m.contractAt('StRIFToken', stRIFTokenProxyAddress)

const newImplementation = m.contract('StRIFTokenV02', [], { id: 'Implementation' })

const reInitCall = m.encodeFunctionCall(newImplementation, 'initializeV2', [])

m.call(stRIFTokenProxy, 'upgradeToAndCall', [newImplementation, reInitCall], { id: 'Reinitialize' })

const stRifV02 = m.contractAt('StRIFTokenV02', stRIFTokenProxy, { id: 'Contract' })

return { stRifV02 }
})
export default stRifV02Module
5 changes: 5 additions & 0 deletions params/StRif/v2UpgradeTestnet.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"StRIFTokenV02": {
"StRifAddress": "0x47955BbC3a077FFA59BD7aedf25fcD1f2f0360e3"
}
}
Loading
Loading