diff --git a/foundry.toml b/foundry.toml index 6d5e0ad..5d231ed 100644 --- a/foundry.toml +++ b/foundry.toml @@ -3,6 +3,11 @@ src = "src" out = "out" libs = ["lib"] gas_reports = ["WanderStaking"] +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 [fuzz] diff --git a/src/WanderStaking.sol b/src/WanderStaking.sol index 023947f..89fd48b 100644 --- a/src/WanderStaking.sol +++ b/src/WanderStaking.sol @@ -3,24 +3,34 @@ pragma solidity ^0.8.13; import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; -import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol"; +import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; -contract WanderStaking is Ownable, Pausable { +contract WanderStaking is Initializable, PausableUpgradeable, OwnableUpgradeable, UUPSUpgradeable { using SafeERC20 for IERC20; - IERC20 public immutable token; - event Stake(address indexed user, uint256 amount); event Unstake(address indexed user, uint256 amount); error ZeroAmount(); error InsufficientBalance(); - mapping(address => uint256) userStake; + IERC20 public token; uint256 internal totalStaked; + mapping(address => uint256) userStake; + + // @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialOwner, IERC20 _token) public initializer { + __Pausable_init(); + __Ownable_init(initialOwner); + __UUPSUpgradeable_init(); - constructor(address initialOwner, IERC20 _token) Ownable(initialOwner) { token = _token; } @@ -32,6 +42,8 @@ contract WanderStaking is Ownable, Pausable { _unpause(); } + function _authorizeUpgrade(address newImplementation) internal override onlyOwner {} + function stake(uint256 amount) external whenNotPaused { if (amount == 0) { revert ZeroAmount(); diff --git a/test/WanderStaking.t.sol b/test/WanderStaking.t.sol index 5b2dc60..b667642 100644 --- a/test/WanderStaking.t.sol +++ b/test/WanderStaking.t.sol @@ -6,6 +6,7 @@ import {WanderStaking} from "../src/WanderStaking.sol"; import {TestToken} from "../src/TestToken.sol"; import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; contract WanderStakingTest is Test { WanderStaking public staking; @@ -14,7 +15,13 @@ contract WanderStakingTest is Test { function setUp() public { token = new TestToken(); - staking = new WanderStaking(address(this), IERC20(token)); + WanderStaking stakingImpl = new WanderStaking(); + + bytes memory data = abi.encodeWithSignature("initialize(address,address)", address(this), address(token)); + ERC1967Proxy proxy = new ERC1967Proxy(address(stakingImpl), data); + + staking = WanderStaking(address(proxy)); + token.approve(address(staking), ~uint256(0)); }