Skip to content

Commit

Permalink
Base version (#1)
Browse files Browse the repository at this point in the history
* Base version

* Added BaseFactory

* Refactored code

* Set CoreProperties upgradeable

* fixes

* refactor logic

* updated

* removed scripts

* Updated package.json

* fixes

* added more tests

* added config

* changed swap params

* changed package-lock.json

* changed package-lock.json

* changed ci

* changed package-lock.json

---------

Co-authored-by: Oleksandr Fedorenko <[email protected]>
  • Loading branch information
RuslanProgrammer and FedOken authored May 15, 2024
1 parent 50e0813 commit f645ea0
Show file tree
Hide file tree
Showing 72 changed files with 3,632 additions and 2,932 deletions.
2 changes: 1 addition & 1 deletion .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ runs:
- name: Setup node
uses: actions/setup-node@v3
with:
node-version: "16.18.x"
node-version: "18.16.x"
cache: npm
- name: Install packages
run: npm install
Expand Down
108 changes: 108 additions & 0 deletions contracts/Factory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";

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

abstract contract Factory is IFactory, OwnableUpgradeable, PausableUpgradeable, UUPSUpgradeable {
mapping(uint8 => address) internal _implementations;
mapping(bytes32 => bool) private _usedSalts;

/**
* @dev It is used exclusively for storing information about the detached proxies.
*
* `_msgSender()` -> `poolName` -> `poolType` -> `proxy`
*/
mapping(address => mapping(string => mapping(uint8 => address))) public deployedProxies;

function __Factory_init() internal onlyInitializing {}

/**
* @notice Returns contract to normal state.
*/
function pause() external onlyOwner {
_pause();
}

/**
* @notice Triggers stopped state.
*/
function unpause() external onlyOwner {
_unpause();
}

/**
* @notice The function to set implementation for the specific pool.
*
* @param poolType_ the type of the pool.
* @param implementation_ the implementation the pool will point to.
*/
function setImplementation(uint8 poolType_, address implementation_) public onlyOwner {
_implementations[poolType_] = implementation_;
}

/**
* @notice The function to get implementation of the specific pools.
*
* @param poolType_ the type of the pools.
* @return implementation the implementation which the pool points to.
*/
function getImplementation(uint8 poolType_) public view returns (address) {
return _implementations[poolType_];
}

/**
* @notice The function to deploy new `ERC1967Proxy`.
*
* @param poolType_ the type of the pool.
* @param poolName_ the name of the pool.
* @return proxy the proxy address for the `poolType_`.
*/
function _deploy2(uint8 poolType_, string calldata poolName_) internal returns (address) {
require(bytes(poolName_).length != 0, "F: poolName_ is empty");
bytes32 salt_ = _calculatePoolSalt(_msgSender(), poolName_, poolType_);

address implementation_ = getImplementation(poolType_);
require(implementation_ != address(0), "F: implementation not found");

require(!_usedSalts[salt_], "F: salt used");
_usedSalts[salt_] = true;

address proxy_ = address(new ERC1967Proxy{salt: salt_}(implementation_, bytes("")));

deployedProxies[_msgSender()][poolName_][poolType_] = proxy_;

emit ProxyDeployed(proxy_, implementation_, poolType_, poolName_);

return proxy_;
}

function _predictPoolAddress(
uint8 poolType_,
string calldata poolName_,
address sender_
) internal view returns (address) {
bytes32 salt_ = _calculatePoolSalt(sender_, poolName_, uint8(poolType_));

bytes32 bytecodeHash_ = keccak256(
abi.encodePacked(type(ERC1967Proxy).creationCode, abi.encode(getImplementation(poolType_), bytes("")))
);

return Create2.computeAddress(salt_, bytecodeHash_);
}

function _calculatePoolSalt(
address sender_,
string calldata poolName_,
uint8 poolType_
) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(sender_, poolName_, poolType_));
}

function _authorizeUpgrade(address) internal view override onlyOwner {}
}
32 changes: 25 additions & 7 deletions contracts/L1/Distribution.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import {PRECISION} from "@solarity/solidity-lib/utils/Globals.sol";

import {LinearDistributionIntervalDecrease} from "../libs/LinearDistributionIntervalDecrease.sol";

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

import {L1Sender} from "./L1Sender.sol";
import {IDistribution} from "../interfaces/L1/IDistribution.sol";
import {IFeeConfig} from "../interfaces/L1/IFeeConfig.sol";
import {IL1Sender} from "../interfaces/L1/IL1Sender.sol";

contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable {
using SafeERC20 for IERC20;
Expand All @@ -20,6 +20,7 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable {

address public depositToken;
address public l1Sender;
address public feeConfig;

// Pool storage
Pool[] public pools;
Expand Down Expand Up @@ -55,6 +56,7 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable {
function Distribution_init(
address depositToken_,
address l1Sender_,
address feeConfig_,
Pool[] calldata poolsInfo_
) external initializer {
__Ownable_init();
Expand All @@ -66,6 +68,7 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable {

depositToken = depositToken_;
l1Sender = l1Sender_;
feeConfig = feeConfig_;
}

/**********************************************************************************************/
Expand All @@ -82,7 +85,14 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable {

function editPool(uint256 poolId_, Pool calldata pool_) external onlyOwner poolExists(poolId_) {
_validatePool(pool_);
require(pools[poolId_].isPublic == pool_.isPublic, "DS: invalid pool type");

Pool storage pool = pools[poolId_];
require(pool.isPublic == pool_.isPublic, "DS: invalid pool type");
if (pool_.payoutStart > block.timestamp) {
require(pool.payoutStart == pool_.payoutStart, "DS: invalid payout start value");
require(pool.withdrawLockPeriod == pool_.withdrawLockPeriod, "DS: invalid WLP value");
require(pool.withdrawLockPeriodAfterStake == pool_.withdrawLockPeriodAfterStake, "DS: invalid WLPAS value");
}

PoolData storage poolData = poolsData[poolId_];
uint256 currentPoolRate_ = _getCurrentPoolRate(poolId_);
Expand Down Expand Up @@ -174,7 +184,7 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable {
userData.pendingRewards = 0;

// Transfer rewards
L1Sender(l1Sender).sendMintMessage{value: msg.value}(receiver_, pendingRewards_, user_);
IL1Sender(l1Sender).sendMintMessage{value: msg.value}(receiver_, pendingRewards_, user_);

emit UserClaimed(poolId_, user_, receiver_, pendingRewards_);
}
Expand Down Expand Up @@ -327,9 +337,18 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable {
uint256 overplus_ = overplus();
require(overplus_ > 0, "DS: overplus is zero");

(uint256 feePercent_, address treasuryAddress_) = IFeeConfig(feeConfig).getFeeAndTreasury(address(this));

uint256 fee_ = (overplus_ * feePercent_) / PRECISION;
if (fee_ != 0) {
IERC20(depositToken).safeTransfer(treasuryAddress_, fee_);

overplus_ -= fee_;
}

IERC20(depositToken).safeTransfer(l1Sender, overplus_);

bytes memory bridgeMessageId_ = L1Sender(l1Sender).sendDepositToken{value: msg.value}(
bytes memory bridgeMessageId_ = IL1Sender(l1Sender).sendDepositToken{value: msg.value}(
gasLimit_,
maxFeePerGas_,
maxSubmissionCost_
Expand All @@ -343,7 +362,6 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable {
/**********************************************************************************************/
/*** UUPS ***/
/**********************************************************************************************/

function removeUpgradeability() external onlyOwner {
isNotUpgradeable = true;
}
Expand Down
53 changes: 53 additions & 0 deletions contracts/L1/FeeConfig.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

import {PRECISION} from "@solarity/solidity-lib/utils/Globals.sol";

import {IFeeConfig} from "../interfaces/L1/IFeeConfig.sol";

contract FeeConfig is IFeeConfig, OwnableUpgradeable, UUPSUpgradeable {
address public treasury;
uint256 public baseFee;

mapping(address => uint256) public fees;

function __FeeConfig_init(address treasury_, uint256 baseFee_) external initializer {
__Ownable_init();
__UUPSUpgradeable_init();

treasury = treasury_;
baseFee = baseFee_;
}

function setFee(address sender_, uint256 fee_) external onlyOwner {
require(fee_ <= PRECISION, "FC: invalid fee");

fees[sender_] = fee_;
}

function setTreasury(address treasury_) external onlyOwner {
require(treasury_ != address(0), "FC: invalid treasury");

treasury = treasury_;
}

function setBaseFee(uint256 baseFee_) external onlyOwner {
require(baseFee_ < PRECISION, "FC: invalid base fee");

baseFee = baseFee_;
}

function getFeeAndTreasury(address sender_) external view returns (uint256, address) {
uint256 fee_ = fees[sender_];
if (fee_ == 0) {
fee_ = baseFee;
}

return (fee_, treasury);
}

function _authorizeUpgrade(address) internal override onlyOwner {}
}
100 changes: 100 additions & 0 deletions contracts/L1/L1Factory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {IDistribution} from "../interfaces/L1/IDistribution.sol";
import {IL1Factory} from "../interfaces/L1/IL1Factory.sol";
import {IL1Sender} from "../interfaces/L1/IL1Sender.sol";
import {IOwnable} from "../interfaces/IOwnable.sol";

import {Factory} from "../Factory.sol";

contract L1Factory is IL1Factory, Factory {
address public feeConfig;

DepositTokenExternalDeps public depositTokenExternalDeps;
ArbExternalDeps public arbExternalDeps;
LzExternalDeps public lzExternalDeps;

constructor() {
_disableInitializers();
}

function L1Factory_init() external initializer {
__Pausable_init();
__Ownable_init();
__UUPSUpgradeable_init();
__Factory_init();
}

function setDepositTokenExternalDeps(
DepositTokenExternalDeps calldata depositTokenExternalDeps_
) external onlyOwner {
require(depositTokenExternalDeps_.token != address(0), "L1F: invalid token");
require(depositTokenExternalDeps_.wToken != address(0), "L1F: invalid wtoken");

depositTokenExternalDeps = depositTokenExternalDeps_;
}

function setLzExternalDeps(LzExternalDeps calldata lzExternalDeps_) external onlyOwner {
require(lzExternalDeps_.endpoint != address(0), "L1F: invalid LZ endpoint");
require(lzExternalDeps_.destinationChainId != 0, "L1F: invalid chain ID");

lzExternalDeps = lzExternalDeps_;
}

function setArbExternalDeps(ArbExternalDeps calldata arbExternalDeps_) external onlyOwner {
require(arbExternalDeps_.endpoint != address(0), "L1F: invalid ARB endpoint");

arbExternalDeps = arbExternalDeps_;
}

function setFeeConfig(address feeConfig_) external onlyOwner {
require(feeConfig_ != address(0), "L1F: invalid fee config");

feeConfig = feeConfig_;
}

function deploy(L1Params calldata l1Params_) external whenNotPaused {
address distributionProxy_ = _deploy2(uint8(PoolType.DISTRIBUTION), l1Params_.protocolName);
address l1SenderProxy_ = _deploy2(uint8(PoolType.L1_SENDER), l1Params_.protocolName);

IDistribution(distributionProxy_).Distribution_init(
depositTokenExternalDeps.token,
l1SenderProxy_,
feeConfig,
l1Params_.poolsInfo
);

IL1Sender.RewardTokenConfig memory lzConfig_ = IL1Sender.RewardTokenConfig(
lzExternalDeps.endpoint,
l1Params_.l2MessageReceiver,
lzExternalDeps.destinationChainId,
lzExternalDeps.zroPaymentAddress,
lzExternalDeps.adapterParams
);

IL1Sender.DepositTokenConfig memory arbConfig_ = IL1Sender.DepositTokenConfig(
depositTokenExternalDeps.wToken,
arbExternalDeps.endpoint,
l1Params_.l2TokenReceiver
);

IL1Sender(l1SenderProxy_).L1Sender__init(distributionProxy_, lzConfig_, arbConfig_);

if (l1Params_.isNotUpgradeable) {
IDistribution(distributionProxy_).removeUpgradeability();
}

IOwnable(distributionProxy_).transferOwnership(_msgSender());
IOwnable(l1SenderProxy_).transferOwnership(_msgSender());
}

function predictAddresses(
string calldata poolName_,
address sender_
) external view returns (address distribution_, address l1Sender_) {
distribution_ = _predictPoolAddress(uint8(PoolType.DISTRIBUTION), poolName_, sender_);

l1Sender_ = _predictPoolAddress(uint8(PoolType.L1_SENDER), poolName_, sender_);
}
}
Loading

0 comments on commit f645ea0

Please sign in to comment.