Skip to content

Commit

Permalink
Added BaseFactory
Browse files Browse the repository at this point in the history
  • Loading branch information
RuslanProgrammer committed Apr 5, 2024
1 parent 9731450 commit e2f5406
Show file tree
Hide file tree
Showing 5 changed files with 226 additions and 287 deletions.
111 changes: 111 additions & 0 deletions contracts/BaseFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

import {ProxyBeacon} from "@solarity/solidity-lib/proxy/beacon/ProxyBeacon.sol";
import {PublicBeaconProxy} from "@solarity/solidity-lib/proxy/beacon/PublicBeaconProxy.sol";
import {Paginator} from "@solarity/solidity-lib/libs/arrays/Paginator.sol";

abstract contract BaseFactory {
using EnumerableSet for EnumerableSet.AddressSet;
using Paginator for EnumerableSet.AddressSet;

mapping(bytes32 => bool) private _usedSalts;

mapping(uint8 => ProxyBeacon) internal _beacons;
mapping(uint8 => EnumerableSet.AddressSet) internal _pools;

/**
* @notice The function to get implementation of the specific pools
* @param poolType_ the type of the pools
* @return address_ the implementation these pools point to
*/
function getImplementation(uint8 poolType_) public view returns (address) {
require(address(_beacons[poolType_]) != address(0), "BaseFactory: this mapping doesn't exist");

return _beacons[poolType_].implementation();
}

/**
* @notice The function to get the BeaconProxy of the specific pools (mostly needed in the factories)
* @param poolType_ type name of the pools
* @return address the BeaconProxy address
*/
function getBeaconProxy(uint8 poolType_) public view returns (address) {
address beacon_ = address(_beacons[poolType_]);

require(beacon_ != address(0), "BaseFactory: bad PublicBeaconProxy");

return beacon_;
}

/**
* @notice The function to count pools
* @param poolType_ the type of the pools
* @return the number of pools
*/
function countPools(uint8 poolType_) public view returns (uint256) {
return _pools[poolType_].length();
}

/**
* @notice The paginated function to list pools (call `countPools()` to account for pagination)
* @param poolType_ the type of the pools
* @param offset_ the starting index in the address array
* @param limit_ the number of address
* @return pools_ the array of address proxies
*/
function listPools(uint8 poolType_, uint256 offset_, uint256 limit_) public view returns (address[] memory pools_) {
return _pools[poolType_].part(offset_, limit_);
}

function _addPool(uint8 poolType_, address pool_) internal {
_pools[poolType_].add(pool_);
}

function _deploy2(uint8 poolType_, string memory poolName_) internal returns (address) {
bytes32 salt_ = _calculatePoolSalt(tx.origin, poolName_);

require(bytes(poolName_).length != 0, "BaseFactory: pool name cannot be empty");
require(!_usedSalts[salt_], "BaseFactory: pool name is already taken");

return address(new PublicBeaconProxy{salt: salt_}(getBeaconProxy(poolType_), bytes("")));
}

function _updateSalt(string memory poolName_) internal {
_usedSalts[_calculatePoolSalt(tx.origin, poolName_)] = true;
}

/**
* @notice The function that sets pools' implementations. Deploys ProxyBeacons on the first set.
* This function is also used to upgrade pools
* @param poolTypes_ the types that are associated with the pools implementations
* @param newImplementations_ the new implementations of the pools (ProxyBeacons will point to these)
*/

function _setNewImplementations(uint8[] memory poolTypes_, address[] memory newImplementations_) internal {
for (uint256 i = 0; i < poolTypes_.length; i++) {
if (address(_beacons[poolTypes_[i]]) == address(0)) {
_beacons[poolTypes_[i]] = new ProxyBeacon();
}

if (_beacons[poolTypes_[i]].implementation() != newImplementations_[i]) {
_beacons[poolTypes_[i]].upgradeTo(newImplementations_[i]);
}
}
}

function _predictPoolAddress(uint8 poolType_, bytes32 salt_) internal view returns (address) {
bytes32 bytecodeHash_ = keccak256(
abi.encodePacked(type(PublicBeaconProxy).creationCode, abi.encode(getBeaconProxy(poolType_), bytes("")))
);

return Create2.computeAddress(salt_, bytecodeHash_);
}

function _calculatePoolSalt(address deployer_, string memory poolName_) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(deployer_, poolName_));
}
}
131 changes: 23 additions & 108 deletions contracts/L1/BaseFactoryL1.sol
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

import {ProxyBeacon} from "@solarity/solidity-lib/proxy/beacon/ProxyBeacon.sol";
import {PublicBeaconProxy} from "@solarity/solidity-lib/proxy/beacon/PublicBeaconProxy.sol";
import {Paginator} from "@solarity/solidity-lib/libs/arrays/Paginator.sol";
import {BaseFactory} from "../BaseFactory.sol";

abstract contract BaseFactoryL1 {
import {IDistribution} from "../interfaces/IDistribution.sol";

abstract contract BaseFactoryL1 is BaseFactory {
using EnumerableSet for EnumerableSet.AddressSet;
using Paginator for EnumerableSet.AddressSet;

enum PoolType {
DISTRIBUTION,
Expand All @@ -21,115 +19,32 @@ abstract contract BaseFactoryL1 {
address distribution;
address l1Sender;
}
mapping(bytes32 => bool) private _usedSalts;

mapping(PoolType => ProxyBeacon) private _beacons;
EnumerableSet.AddressSet internal _distributions;

function predictMor20Address(
address deployer,
string calldata mor20Name
) external view returns (Mor20PredictedAddressesL1 memory predictedAddresses) {
if (bytes(mor20Name).length == 0) {
return predictedAddresses;
}

bytes32 poolSalt = _calculatePoolSalt(deployer, mor20Name);

return
Mor20PredictedAddressesL1(
_predictPoolAddress(PoolType.DISTRIBUTION, poolSalt),
_predictPoolAddress(PoolType.L1_SENDER, poolSalt)
);
struct Mor20DeployParams {
string name;
address depositToken;
IDistribution.Pool[] poolsInfo;
//////
address messageReceiver;
address zroPaymentAddress;
uint16 l2EndpointId;
bytes adapterParams;
//////
address wrappedToken;
address tokenReceiver;
}

/**
* @notice The function to get implementation of the specific pools
* @param poolType_ the type of the pools
* @return address_ the implementation these pools point to
*/
function getImplementation(PoolType poolType_) public view returns (address) {
require(address(_beacons[poolType_]) != address(0), "BaseFactory: this mapping doesn't exist");
event Mor20Deployed(string name, address distribution, address l1Sender);

return _beacons[poolType_].implementation();
function _predictPoolAddress(PoolType poolType_, bytes32 poolSalt_) internal view returns (address) {
return _predictPoolAddress(uint8(poolType_), poolSalt_);
}

/**
* @notice The function to get the BeaconProxy of the specific pools (mostly needed in the factories)
* @param poolType_ type name of the pools
* @return address the BeaconProxy address
*/
function getBeaconProxy(PoolType poolType_) public view returns (address) {
address beacon_ = address(_beacons[poolType_]);

require(beacon_ != address(0), "BaseFactory: bad PublicBeaconProxy");

return beacon_;
}

/**
* @notice The function to count distributions
* @return the number of distributions
*/
function countDistributions() public view returns (uint256) {
return _distributions.length();
}

/**
* @notice The paginated function to list distributions (call `countDistributions()` to account for pagination)
* @param offset_ the starting index in the address array
* @param limit_ the number of address
* @return pools_ the array of address proxies
*/
function listDistributions(uint256 offset_, uint256 limit_) public view returns (address[] memory pools_) {
return _distributions.part(offset_, limit_);
}

function _addDistribution(address distribution) internal {
_distributions.add(distribution);
}

function _deploy2(PoolType poolType_, string memory poolName_) internal returns (address) {
bytes32 salt_ = _calculatePoolSalt(tx.origin, poolName_);

require(bytes(poolName_).length != 0, "BaseFactory: pool name cannot be empty");
require(!_usedSalts[salt_], "BaseFactory: pool name is already taken");

return address(new PublicBeaconProxy{salt: salt_}(getBeaconProxy(poolType_), bytes("")));
}

function _updateSalt(string memory poolName) internal {
_usedSalts[_calculatePoolSalt(tx.origin, poolName)] = true;
}

/**
* @notice The function that sets pools' implementations. Deploys ProxyBeacons on the first set.
* This function is also used to upgrade pools
* @param poolTypes_ the types that are associated with the pools implementations
* @param newImplementations_ the new implementations of the pools (ProxyBeacons will point to these)
*/

function _setNewImplementations(PoolType[] memory poolTypes_, address[] memory newImplementations_) internal {
for (uint256 i = 0; i < poolTypes_.length; i++) {
if (address(_beacons[poolTypes_[i]]) == address(0)) {
_beacons[poolTypes_[i]] = new ProxyBeacon();
}

if (_beacons[poolTypes_[i]].implementation() != newImplementations_[i]) {
_beacons[poolTypes_[i]].upgradeTo(newImplementations_[i]);
}
}
}

function _predictPoolAddress(PoolType poolType_, bytes32 salt_) internal view returns (address) {
bytes32 bytecodeHash = keccak256(
abi.encodePacked(type(PublicBeaconProxy).creationCode, abi.encode(getBeaconProxy(poolType_), bytes("")))
);

return Create2.computeAddress(salt_, bytecodeHash);
function _addDistribution(address distribution_) internal {
_pools[uint8(PoolType.DISTRIBUTION)].add(distribution_);
}

function _calculatePoolSalt(address deployer, string memory poolName) private pure returns (bytes32) {
return keccak256(abi.encodePacked(deployer, poolName));
function _deploy2(PoolType poolType_, string memory name_) internal returns (address) {
return _deploy2(uint8(poolType_), name_);
}
}
59 changes: 30 additions & 29 deletions contracts/L1/Mor20FactoryL1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,62 +12,63 @@ import {IL1Sender} from "../interfaces/IL1Sender.sol";
contract Mor20FactoryL1 is BaseFactoryL1, Ownable {
CorePropertiesL1 public coreProperties;

struct Mor20DeployParams {
string name;
address depositToken;
IDistribution.Pool[] poolsInfo;
//////
address messageReceiver;
address zroPaymentAddress;
uint16 l2EndpointId;
bytes adapterParams;
//////
address wrappedToken;
address tokenReceiver;
}

event Mor20Deployed(string name, address distribution, address l1Sender);

constructor(address coreProperties_) {
coreProperties = CorePropertiesL1(coreProperties_);
}

function deployMor20OnL1(Mor20DeployParams calldata parameters) external onlyOwner {
function deployMor20OnL1(Mor20DeployParams calldata parameters_) external onlyOwner {
(address arbitrumGateway_, address lZEnpointAddress_) = coreProperties.getDeployParams();

address distributionAddress_ = _deploy2(PoolType.DISTRIBUTION, parameters.name);
address distributionAddress_ = _deploy2(PoolType.DISTRIBUTION, parameters_.name);

address l1SenderAddress_ = _deploy2(PoolType.L1_SENDER, parameters.name);
address l1SenderAddress_ = _deploy2(PoolType.L1_SENDER, parameters_.name);

IDistribution(distributionAddress_).Distribution_init(
parameters.depositToken,
parameters_.depositToken,
l1SenderAddress_,
parameters.poolsInfo
parameters_.poolsInfo
);

IL1Sender(l1SenderAddress_).L1Sender__init(
distributionAddress_,
IL1Sender.RewardTokenConfig(
lZEnpointAddress_,
parameters.messageReceiver,
parameters.l2EndpointId,
parameters.zroPaymentAddress,
parameters.adapterParams
parameters_.messageReceiver,
parameters_.l2EndpointId,
parameters_.zroPaymentAddress,
parameters_.adapterParams
),
IL1Sender.DepositTokenConfig(parameters.wrappedToken, arbitrumGateway_, parameters.tokenReceiver)
IL1Sender.DepositTokenConfig(parameters_.wrappedToken, arbitrumGateway_, parameters_.tokenReceiver)
);

_addDistribution(distributionAddress_);

_updateSalt(parameters.name);
_updateSalt(parameters_.name);

emit Mor20Deployed(parameters.name, distributionAddress_, l1SenderAddress_);
emit Mor20Deployed(parameters_.name, distributionAddress_, l1SenderAddress_);
}

function setNewImplementations(
PoolType[] memory poolTypes_,
uint8[] memory poolTypes_,
address[] calldata newImplementations_
) external onlyOwner {
_setNewImplementations(poolTypes_, newImplementations_);
}

function predictMor20Address(
address deployer_,
string calldata mor20Name_
) external view returns (Mor20PredictedAddressesL1 memory predictedAddresses_) {
if (bytes(mor20Name_).length == 0) {
return predictedAddresses_;
}

bytes32 poolSalt_ = _calculatePoolSalt(deployer_, mor20Name_);

return
Mor20PredictedAddressesL1(
_predictPoolAddress(PoolType.DISTRIBUTION, poolSalt_),
_predictPoolAddress(PoolType.L1_SENDER, poolSalt_)
);
}
}
Loading

0 comments on commit e2f5406

Please sign in to comment.