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

feat: contract upgrade progression #15

Merged
merged 8 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
[submodule "foundry/lib/openzeppelin-contracts-upgradeable"]
path = foundry/lib/openzeppelin-contracts-upgradeable
url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable
[submodule "foundry/lib/openzeppelin-foundry-upgrades"]
path = foundry/lib/openzeppelin-foundry-upgrades
url = https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades
4 changes: 3 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/"
"openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/",
"openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/",
"solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/"
]
}
4 changes: 4 additions & 0 deletions foundry/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,9 @@
src = "src"
out = "out"
libs = ["lib"]
ffi = true
ast = true
build_info = true
extra_output = ["storageLayout"]

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
1 change: 1 addition & 0 deletions foundry/lib/openzeppelin-foundry-upgrades
46 changes: 32 additions & 14 deletions foundry/src/FoxStaking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,29 @@
pragma solidity ^0.8.25;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import {IFoxStaking, StakingInfo} from "./IFoxStaking.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

contract FoxStaking is
IFoxStaking,
Ownable(msg.sender), // Deployer is the owner
Pausable
Initializable,
PausableUpgradeable,
UUPSUpgradeable,
OwnableUpgradeable
{
using SafeERC20 for IERC20;
uint256 public version;
IERC20 public foxToken;
mapping(address => StakingInfo) public stakingInfo;

bool public stakingPaused = false;
bool public withdrawalsPaused = false;
bool public unstakingPaused = false;

uint256 public cooldownPeriod = 28 days;
bool public stakingPaused;
bool public withdrawalsPaused;
bool public unstakingPaused;
uint256 public cooldownPeriod;
woodenfurniture marked this conversation as resolved.
Show resolved Hide resolved

event UpdateCooldownPeriod(uint256 newCooldownPeriod);

event Stake(
address indexed account,
uint256 amount,
Expand All @@ -37,10 +38,27 @@ contract FoxStaking is
string indexed newRuneAddress
);

constructor(address foxTokenAddress) {
/// @custom:oz-upgrades-unsafe-allow constructor
woodenfurniture marked this conversation as resolved.
Show resolved Hide resolved
constructor() {
_disableInitializers();
}

function initialize(address foxTokenAddress) external initializer {
__Ownable_init(msg.sender);
woodenfurniture marked this conversation as resolved.
Show resolved Hide resolved
__UUPSUpgradeable_init();
__Pausable_init();
version = 1;
foxToken = IERC20(foxTokenAddress);
stakingPaused = false;
withdrawalsPaused = false;
unstakingPaused = false;
cooldownPeriod = 28 days;
}

function _authorizeUpgrade(
address newImplementation
) internal override onlyOwner {}

function pauseStaking() external onlyOwner {
stakingPaused = true;
}
Expand Down
31 changes: 26 additions & 5 deletions foundry/test/FoxStaking.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol";
import {Upgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol";

contract MockFOXToken is ERC20 {
constructor() ERC20("Mock FOX Token", "FOX") {
Expand All @@ -26,7 +27,11 @@ contract FOXStakingTestRuneAddress is Test {

function setUp() public {
foxToken = new MockFOXToken();
foxStaking = new FoxStaking(address(foxToken));
address foxStakingProxy = Upgrades.deployUUPSProxy(
"FoxStaking.sol",
abi.encodeCall(FoxStaking.initialize, (address(foxToken)))
);
foxStaking = FoxStaking(foxStakingProxy);
}

function testCanSetRuneAddress() public {
Expand Down Expand Up @@ -88,7 +93,11 @@ contract FOXStakingTestOwnership is Test {

function setUp() public {
foxToken = new MockFOXToken();
foxStaking = new FoxStaking(address(foxToken));
address foxStakingProxy = Upgrades.deployUUPSProxy(
"FoxStaking.sol",
abi.encodeCall(FoxStaking.initialize, (address(foxToken)))
);
foxStaking = FoxStaking(foxStakingProxy);
}

function testOwnerCanUpdateCooldownPeriod() public {
Expand Down Expand Up @@ -122,7 +131,11 @@ contract FOXStakingTestStaking is Test {

function setUp() public {
foxToken = new MockFOXToken();
foxStaking = new FoxStaking(address(foxToken));
address foxStakingProxy = Upgrades.deployUUPSProxy(
"FoxStaking.sol",
abi.encodeCall(FoxStaking.initialize, (address(foxToken)))
);
foxStaking = FoxStaking(foxStakingProxy);
}

function testCannotStakeWhenStakingPaused() public {
Expand Down Expand Up @@ -345,7 +358,11 @@ contract FOXStakingTestUnstake is Test {

function setUp() public {
foxToken = new MockFOXToken();
foxStaking = new FoxStaking(address(foxToken));
address foxStakingProxy = Upgrades.deployUUPSProxy(
"FoxStaking.sol",
abi.encodeCall(FoxStaking.initialize, (address(foxToken)))
);
foxStaking = FoxStaking(foxStakingProxy);

// Free FOX tokens for user
foxToken.makeItRain(user, amount);
Expand Down Expand Up @@ -626,7 +643,11 @@ contract FOXStakingTestWithdraw is Test {

function setUp() public {
foxToken = new MockFOXToken();
foxStaking = new FoxStaking(address(foxToken));
address foxStakingProxy = Upgrades.deployUUPSProxy(
"FoxStaking.sol",
abi.encodeCall(FoxStaking.initialize, (address(foxToken)))
);
foxStaking = FoxStaking(foxStakingProxy);

// Free FOX tokens for user
foxToken.makeItRain(user, amount);
Expand Down
30 changes: 30 additions & 0 deletions foundry/test/FoxStakingTestUpgrades.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.25;

import "forge-std/Test.sol";
import "../src/FoxStaking.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol";
import {Upgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol";
import {MockFOXToken} from "./MockFOXToken.sol";

contract FOXStakingTestUpgrades is Test {
FoxStaking public foxStaking;
MockFOXToken public foxToken;
address user = address(0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045);

function setUp() public {
foxToken = new MockFOXToken();
address foxStakingProxy = Upgrades.deployUUPSProxy(
"FoxStaking.sol",
abi.encodeCall(FoxStaking.initialize, (address(foxToken)))
);
foxStaking = FoxStaking(foxStakingProxy);
}

function testCanDeploy() public view {
uint256 expectedVersion = 1;
assertEq(foxStaking.version(), expectedVersion);
}
}
16 changes: 16 additions & 0 deletions foundry/test/MockFOXToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.25;

import "forge-std/Test.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract MockFOXToken is ERC20 {
constructor() ERC20("Mock FOX Token", "FOX") {
// 1M FOX for testing, only in local chain can't use this as voting power soz
_mint(address(this), 1e24);
}

function makeItRain(address to, uint256 amount) public {
_transfer(address(this), to, amount);
}
}