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

Fetch latest develop #26

Merged
merged 17 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
3057de7
Merge pull request #17 from soramitsu/feature/erc721lockupstakingpool
SergeyPoslavskiy May 14, 2024
2f5f0b1
Merge pull request #22 from soramitsu/develop
SergeyPoslavskiy May 14, 2024
c7b2ff3
[CI] Added coverage workflow
SergeyPoslavskiy May 14, 2024
835449f
[Fix] Added coverage to hh config
SergeyPoslavskiy May 14, 2024
49d87bf
[Update] Added ERC721 factories, code refactoring
SergeyPoslavskiy May 14, 2024
9847461
[Fix] Fixed case sensitive impotrs
SergeyPoslavskiy May 14, 2024
fe64f16
Rename ERC721LockupFactory.sol to ERC721LockUpFactory.sol
SergeyPoslavskiy May 14, 2024
22d5d16
Rename ERC721NoLockupFactory.sol to ERC721NoLockUpFactory.sol
SergeyPoslavskiy May 14, 2024
7833584
Rename IERC20NoLockupPool.sol to IERC20NoLockUpPool.sol
SergeyPoslavskiy May 14, 2024
5f5bcc0
Rename IERC721NoLockupPool.sol to IERC721NoLockUpPool.sol
SergeyPoslavskiy May 14, 2024
c656988
Rename ILockupFactory.sol to ILockUpFactory.sol
SergeyPoslavskiy May 14, 2024
bcdba86
Rename INoLockupFactory.sol to INoLockUpFactory.sol
SergeyPoslavskiy May 14, 2024
55d6919
Merge pull request #23 from soramitsu/feature/request_based_factory
SergeyPoslavskiy May 14, 2024
e2c1f42
[Update] Unified interfaces
SergeyPoslavskiy May 15, 2024
97cacc8
[Update] Removed nolockup related contracts
SergeyPoslavskiy May 15, 2024
193e504
[Update] Interfaces refactored, removed nolockup remaining contracts
SergeyPoslavskiy May 15, 2024
3631a24
Merge pull request #25 from soramitsu/feature/code_refactor
SergeyPoslavskiy May 16, 2024
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
30 changes: 30 additions & 0 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Solidity Coverage

on:
push:
branches: [ develop ]
pull_request:
branches: [ master, develop ]

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [ 20.x ]

steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set .env
run: cp .env.example .env

- name: Run tests
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run coverage
- uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
73 changes: 40 additions & 33 deletions contracts/factories/ERC20LockUpFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,33 @@ SPDX-License-Identifier: MIT
*/

pragma solidity 0.8.25;
import {ERC20LockupPool} from "../pools/ERC20LockUpStakingPool.sol";
import {IERC20LockUpFactory} from "../interfaces/IERC20Factories/IERC20LockUpFactory.sol";
import {ERC20LockUpPool} from "../pools/ERC20LockUpStakingPool.sol";
import {ILockUpFactory} from "../interfaces/IFactories/ILockUpFactory.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

/// @title ERC20LockUpStakingFactory
/// @notice A smart contract for deploying ERC20 lockup staking pools.
/// @notice A smart contract for deploying ERC20 LockUp staking pools.
/// @author Ayooluwa Akindeko, Soramitsu team
contract ERC20LockUpStakingFactory is Ownable, IERC20LockUpFactory {
contract ERC20LockUpStakingFactory is Ownable, ILockUpFactory {
using SafeERC20 for IERC20;

address[] public stakingPools;
Request[] public requests;
LockUpRequest[] public requests;
mapping(uint256 id => address pool) public poolById;

constructor() Ownable(msg.sender) {}

/// @notice Function allows users to deploy the lockup staking pool with specified parameters
/// @notice Function allows users to deploy the LockUp staking pool with specified parameters
function deploy(uint256 id) public returns (address newPoolAddress) {
if (requests.length < id) revert InvalidId();
Request memory req = requests[id];
if (req.requestStatus != Status.APPROVED) revert InvalidRequestStatus();
if (msg.sender != req.deployer) revert InvalidCaller();
LockUpRequest memory req = requests[id];
if (req.info.requestStatus != Status.APPROVED)
revert InvalidRequestStatus();
if (msg.sender != req.info.deployer) revert InvalidCaller();
newPoolAddress = address(
new ERC20LockupPool{
new ERC20LockUpPool{
salt: keccak256(
abi.encode(
req.data.stakeToken,
Expand All @@ -44,17 +45,17 @@ contract ERC20LockUpStakingFactory is Ownable, IERC20LockUpFactory {
req.data.rewardToken,
req.data.poolStartTime,
req.data.poolEndTime,
req.data.unstakeLockupTime,
req.data.claimLockupTime,
req.data.unstakeLockUpTime,
req.data.claimLockUpTime,
req.data.rewardPerSecond
)
);
stakingPools.push(newPoolAddress);
requests[id].requestStatus = Status.DEPLOYED;
requests[id].info.requestStatus = Status.DEPLOYED;
poolById[id] = newPoolAddress;
uint256 rewardAmount = (req.data.poolEndTime - req.data.poolStartTime) *
req.data.rewardPerSecond;
ERC20LockupPool(newPoolAddress).transferOwnership(msg.sender);
ERC20LockUpPool(newPoolAddress).transferOwnership(msg.sender);
// Transfer reward tokens from the owner to the contract
// slither-disable-next-line arbitrary-send-erc20
IERC20(req.data.rewardToken).safeTransferFrom(
Expand All @@ -65,14 +66,20 @@ contract ERC20LockUpStakingFactory is Ownable, IERC20LockUpFactory {
emit StakingPoolDeployed(newPoolAddress, id);
}

function requestDeployment(DeploymentData calldata data) external {
function requestDeployment(
bytes32 ipfsHash,
DeploymentData calldata data
) external {
if (data.stakeToken == address(0) || data.rewardToken == address(0))
revert InvalidTokenAddress();
if (data.rewardPerSecond == 0) revert InvalidRewardRate();
requests.push(
Request({
deployer: msg.sender,
requestStatus: Status.CREATED,
LockUpRequest({
info: RequestInfo({
ipfsHash: ipfsHash,
deployer: msg.sender,
requestStatus: Status.CREATED
}),
data: data
})
);
Expand All @@ -86,33 +93,33 @@ contract ERC20LockUpStakingFactory is Ownable, IERC20LockUpFactory {

function approveRequest(uint256 id) external onlyOwner {
if (requests.length < id) revert InvalidId();
Request storage req = requests[id];
if (req.requestStatus != Status.CREATED) revert InvalidRequestStatus();
req.requestStatus = Status.APPROVED;
emit RequestStatusChanged(id, req.requestStatus);
LockUpRequest storage req = requests[id];
if (req.info.requestStatus != Status.CREATED) revert InvalidRequestStatus();
req.info.requestStatus = Status.APPROVED;
emit RequestStatusChanged(id, req.info.requestStatus);
}

function denyRequest(uint256 id) external onlyOwner {
if (requests.length < id) revert InvalidId();
Request storage req = requests[id];
if (req.requestStatus != Status.CREATED) revert InvalidRequestStatus();
req.requestStatus = Status.DENIED;
emit RequestStatusChanged(id, req.requestStatus);
LockUpRequest storage req = requests[id];
if (req.info.requestStatus != Status.CREATED) revert InvalidRequestStatus();
req.info.requestStatus = Status.DENIED;
emit RequestStatusChanged(id, req.info.requestStatus);
}

function cancelRequest(uint256 id) external {
if (requests.length < id) revert InvalidId();
Request storage req = requests[id];
if (msg.sender != req.deployer) revert InvalidCaller();
LockUpRequest storage req = requests[id];
if (msg.sender != req.info.deployer) revert InvalidCaller();
if (
req.requestStatus != Status.CREATED &&
req.requestStatus != Status.APPROVED
req.info.requestStatus != Status.CREATED &&
req.info.requestStatus != Status.APPROVED
) revert InvalidRequestStatus();
req.requestStatus = Status.CANCELED;
emit RequestStatusChanged(id, req.requestStatus);
req.info.requestStatus = Status.CANCELED;
emit RequestStatusChanged(id, req.info.requestStatus);
}

function getRequests() external view returns (Request[] memory reqs) {
function getRequests() external view returns (LockUpRequest[] memory reqs) {
reqs = requests;
}

Expand Down
55 changes: 29 additions & 26 deletions contracts/factories/ERC20PenaltyFeeFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,29 @@ SPDX-License-Identifier: MIT

pragma solidity 0.8.25;
import {ERC20PenaltyFeePool} from "../pools/ERC20PenaltyFeePool.sol";
import {IERC20PenaltyFeeFactory} from "../interfaces/IERC20Factories/IERC20PenaltyFeeFactory.sol";
import {IPenaltyFeeFactory} from "../interfaces/IFactories/IPenaltyFeeFactory.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

/// @title ERC20LockUpStakingFactory
/// @title ERC20PenaltyFeeStakingFactory
/// @notice A smart contract for deploying ERC20 staking pools with penalty fees.
/// @author Ayooluwa Akindeko, Soramitsu team
contract ERC20PenaltyFeeStakingFactory is Ownable, IERC20PenaltyFeeFactory {
contract ERC20PenaltyFeeStakingFactory is Ownable, IPenaltyFeeFactory {
using SafeERC20 for IERC20;

address[] public stakingPools;
Request[] public requests;
PenaltyFeeRequest[] public requests;
mapping(uint256 id => address pool) public poolById;

constructor() Ownable(msg.sender) {}

/// @notice Function allows users to deploy the penaltyFee staking pool with specified parameters
function deploy(uint256 id) public returns (address newPoolAddress) {
if (requests.length < id) revert InvalidId();
Request memory req = requests[id];
if (req.requestStatus != Status.APPROVED) revert InvalidRequestStatus();
if (msg.sender != req.deployer) revert InvalidCaller();
PenaltyFeeRequest memory req = requests[id];
if (req.info.requestStatus != Status.APPROVED) revert InvalidRequestStatus();
if (msg.sender != req.info.deployer) revert InvalidCaller();
newPoolAddress = address(
new ERC20PenaltyFeePool{
salt: keccak256(
Expand All @@ -54,14 +54,17 @@ contract ERC20PenaltyFeeStakingFactory is Ownable, IERC20PenaltyFeeFactory {
emit StakingPoolDeployed(newPoolAddress, id);
}

function requestDeployment(DeploymentData calldata data) external {
function requestDeployment(bytes32 ipfsHash, DeploymentData calldata data) external {
if (data.stakeToken == address(0) || data.rewardToken == address(0))
revert InvalidTokenAddress();
if (data.rewardPerSecond == 0) revert InvalidRewardRate();
requests.push(
Request({
deployer: msg.sender,
requestStatus: Status.CREATED,
PenaltyFeeRequest({
info: RequestInfo({
ipfsHash: ipfsHash,
deployer: msg.sender,
requestStatus: Status.CREATED
}),
data: data
})
);
Expand All @@ -75,33 +78,33 @@ contract ERC20PenaltyFeeStakingFactory is Ownable, IERC20PenaltyFeeFactory {

function approveRequest(uint256 id) external onlyOwner {
if (requests.length < id) revert InvalidId();
Request storage req = requests[id];
if (req.requestStatus != Status.CREATED) revert InvalidRequestStatus();
req.requestStatus = Status.APPROVED;
emit RequestStatusChanged(id, req.requestStatus);
PenaltyFeeRequest storage req = requests[id];
if (req.info.requestStatus != Status.CREATED) revert InvalidRequestStatus();
req.info.requestStatus = Status.APPROVED;
emit RequestStatusChanged(id, req.info.requestStatus);
}

function denyRequest(uint256 id) external onlyOwner {
if (requests.length < id) revert InvalidId();
Request storage req = requests[id];
if (req.requestStatus != Status.CREATED) revert InvalidRequestStatus();
req.requestStatus = Status.DENIED;
emit RequestStatusChanged(id, req.requestStatus);
PenaltyFeeRequest storage req = requests[id];
if (req.info.requestStatus != Status.CREATED) revert InvalidRequestStatus();
req.info.requestStatus = Status.DENIED;
emit RequestStatusChanged(id, req.info.requestStatus);
}

function cancelRequest(uint256 id) external {
if (requests.length < id) revert InvalidId();
Request storage req = requests[id];
if (msg.sender != req.deployer) revert InvalidCaller();
PenaltyFeeRequest storage req = requests[id];
if (msg.sender != req.info.deployer) revert InvalidCaller();
if (
req.requestStatus != Status.CREATED ||
req.requestStatus != Status.APPROVED
req.info.requestStatus != Status.CREATED ||
req.info.requestStatus != Status.APPROVED
) revert InvalidRequestStatus();
req.requestStatus = Status.CANCELED;
emit RequestStatusChanged(id, req.requestStatus);
req.info.requestStatus = Status.CANCELED;
emit RequestStatusChanged(id, req.info.requestStatus);
}

function getRequests() external view returns (Request[] memory reqs) {
function getRequests() external view returns (PenaltyFeeRequest[] memory reqs) {
reqs = requests;
}

Expand Down
Loading
Loading