Skip to content

Commit

Permalink
Merge pull request #95 from RootstockCollective/dao-709-upgrade
Browse files Browse the repository at this point in the history
Deployment / upgrade script for StRIF version 2
  • Loading branch information
shenshin authored Nov 14, 2024
2 parents f0a0602 + f5946b5 commit 5a4a6fc
Show file tree
Hide file tree
Showing 6 changed files with 351 additions and 170 deletions.
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

0 comments on commit 5a4a6fc

Please sign in to comment.