From 9731450d4dedb0b5b195f995a1cf70e85d9bad83 Mon Sep 17 00:00:00 2001 From: Ruslan Kasheparov Date: Thu, 4 Apr 2024 19:57:48 +0200 Subject: [PATCH 01/17] Base version --- contracts/L1/BaseFactoryL1.sol | 135 ++++++++++ contracts/L1/CorePropertiesL1.sol | 52 ++++ contracts/L1/Distribution.sol | 42 +-- contracts/L1/L1Sender.sol | 58 ++-- contracts/L1/Mor20FactoryL1.sol | 73 +++++ contracts/L2/BaseFactoryL2.sol | 148 ++++++++++ contracts/L2/CorePropertiesL2.sol | 19 ++ contracts/L2/{MOROFT.sol => ERC20MOR.sol} | 14 +- contracts/L2/L2MessageReceiver.sol | 19 +- contracts/L2/L2TokenReceiver.sol | 58 ++-- contracts/L2/L2TokenReceiverV2.sol | 183 ------------- contracts/L2/Mor20FactoryL2.sol | 88 ++++++ contracts/interfaces/IDistribution.sol | 11 - .../interfaces/{IMOROFT.sol => IERC20MOR.sol} | 4 +- contracts/interfaces/IL1Sender.sol | 35 +-- contracts/interfaces/IL2MessageReceiver.sol | 14 +- contracts/interfaces/IL2TokenReceiver.sol | 49 +++- contracts/interfaces/IL2TokenReceiverV2.sol | 143 ---------- contracts/interfaces/IMOR.sol | 23 -- contracts/libs/RewardTokenDeployer.sol | 39 +++ package-lock.json | 68 ++++- package.json | 2 +- test/L1/BaseFactoryL1.test.ts | 193 +++++++++++++ test/L1/Distribution.test.ts | 203 +++++++------- test/L1/L1Sender.test.ts | 168 ++++++------ test/L1/Mor20FactoryL1.test.ts | 188 +++++++++++++ test/L2/L2MessageReceiver.test.ts | 190 ++++++------- test/L2/L2TokenReceiver.test.ts | 250 ++++++++++------- test/L2/L2TokenReceiverV2.test.ts | 254 ------------------ 29 files changed, 1601 insertions(+), 1122 deletions(-) create mode 100644 contracts/L1/BaseFactoryL1.sol create mode 100644 contracts/L1/CorePropertiesL1.sol create mode 100644 contracts/L1/Mor20FactoryL1.sol create mode 100644 contracts/L2/BaseFactoryL2.sol create mode 100644 contracts/L2/CorePropertiesL2.sol rename contracts/L2/{MOROFT.sol => ERC20MOR.sol} (74%) delete mode 100644 contracts/L2/L2TokenReceiverV2.sol create mode 100644 contracts/L2/Mor20FactoryL2.sol rename contracts/interfaces/{IMOROFT.sol => IERC20MOR.sol} (90%) delete mode 100644 contracts/interfaces/IL2TokenReceiverV2.sol delete mode 100644 contracts/interfaces/IMOR.sol create mode 100644 contracts/libs/RewardTokenDeployer.sol create mode 100644 test/L1/BaseFactoryL1.test.ts create mode 100644 test/L1/Mor20FactoryL1.test.ts delete mode 100644 test/L2/L2TokenReceiverV2.test.ts diff --git a/contracts/L1/BaseFactoryL1.sol b/contracts/L1/BaseFactoryL1.sol new file mode 100644 index 0000000..8a21cb9 --- /dev/null +++ b/contracts/L1/BaseFactoryL1.sol @@ -0,0 +1,135 @@ +// 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 BaseFactoryL1 { + using EnumerableSet for EnumerableSet.AddressSet; + using Paginator for EnumerableSet.AddressSet; + + enum PoolType { + DISTRIBUTION, + L1_SENDER + } + + struct Mor20PredictedAddressesL1 { + 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) + ); + } + + /** + * @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"); + + 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(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 _calculatePoolSalt(address deployer, string memory poolName) private pure returns (bytes32) { + return keccak256(abi.encodePacked(deployer, poolName)); + } +} diff --git a/contracts/L1/CorePropertiesL1.sol b/contracts/L1/CorePropertiesL1.sol new file mode 100644 index 0000000..ae764fc --- /dev/null +++ b/contracts/L1/CorePropertiesL1.sol @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract CorePropertiesL1 is Ownable { + address public arbitrumGateway; + address public treasuryAddress; + + address public lZEnpointAddress; // L1 + uint256 public destinationChainId; // arbitrum + + mapping(address => uint256) private _fees; + + constructor( + address arbitrumGateway_, + address treasuryAddress_, + address lZEnpointAddress_, + uint256 destinationChainId_ + ) { + arbitrumGateway = arbitrumGateway_; + treasuryAddress = treasuryAddress_; + lZEnpointAddress = lZEnpointAddress_; + destinationChainId = destinationChainId_; + } + + function setFee(address token_, uint256 fee_) external onlyOwner { + _fees[token_] = fee_; + } + + function setTreasuryAddress(address treasuryAddress_) external onlyOwner { + treasuryAddress = treasuryAddress_; + } + + function getFeeAndTreadury(address distributionAddress_) external view returns (uint256, address) { + return (_fees[distributionAddress_], treasuryAddress); + } + + function setDeployParams( + address arbitrumGateway_, + address lZEnpointAddress_, + uint256 destinationChainId_ + ) external onlyOwner { + arbitrumGateway = arbitrumGateway_; + lZEnpointAddress = lZEnpointAddress_; + destinationChainId = destinationChainId_; + } + + function getDeployParams() external view returns (address, address) { + return (arbitrumGateway, lZEnpointAddress); + } +} diff --git a/contracts/L1/Distribution.sol b/contracts/L1/Distribution.sol index db20854..60722ee 100644 --- a/contracts/L1/Distribution.sol +++ b/contracts/L1/Distribution.sol @@ -2,22 +2,20 @@ pragma solidity ^0.8.20; import {SafeERC20, IERC20} 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 {PRECISION} from "@solarity/solidity-lib/utils/Globals.sol"; import {LinearDistributionIntervalDecrease} from "../libs/LinearDistributionIntervalDecrease.sol"; +import {L1Sender} from "./L1Sender.sol"; import {IDistribution} from "../interfaces/IDistribution.sol"; -import {L1Sender} from "./L1Sender.sol"; +import {CorePropertiesL1} from "./CorePropertiesL1.sol"; -contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable { +contract Distribution is IDistribution, OwnableUpgradeable { using SafeERC20 for IERC20; - bool public isNotUpgradeable; - address public depositToken; address public l1Sender; @@ -28,9 +26,10 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable { // User storage mapping(address => mapping(uint256 => UserData)) public usersData; - // Total deposited storage uint256 public totalDepositedInPublicPools; + CorePropertiesL1 public coreProperties; + /**********************************************************************************************/ /*** Modifiers ***/ /**********************************************************************************************/ @@ -58,7 +57,6 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable { Pool[] calldata poolsInfo_ ) external initializer { __Ownable_init(); - __UUPSUpgradeable_init(); for (uint256 i; i < poolsInfo_.length; ++i) { createPool(poolsInfo_[i]); @@ -82,7 +80,17 @@ 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 withdrawLockPeriod"); + require( + pool.withdrawLockPeriodAfterStake == pool_.withdrawLockPeriodAfterStake, + "DS: invalid withdrawLockPeriodAfterStake" + ); + } PoolData storage poolData = poolsData[poolId_]; uint256 currentPoolRate_ = _getCurrentPoolRate(poolId_); @@ -327,6 +335,12 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable { uint256 overplus_ = overplus(); require(overplus_ > 0, "DS: overplus is zero"); + (uint256 feePercent_, address treasuryAddress_) = coreProperties.getFeeAndTreadury(address(this)); + uint256 fee_ = _feeAmount(overplus_, feePercent_); + IERC20(depositToken).safeTransfer(treasuryAddress_, fee_); + + overplus_ -= fee_; + IERC20(depositToken).safeTransfer(l1Sender, overplus_); bytes memory bridgeMessageId_ = L1Sender(l1Sender).sendDepositToken{value: msg.value}( @@ -340,15 +354,7 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable { return bridgeMessageId_; } - /**********************************************************************************************/ - /*** UUPS ***/ - /**********************************************************************************************/ - - function removeUpgradeability() external onlyOwner { - isNotUpgradeable = true; - } - - function _authorizeUpgrade(address) internal view override onlyOwner { - require(!isNotUpgradeable, "DS: upgrade isn't available"); + function _feeAmount(uint256 amount_, uint256 feePercent_) internal pure returns (uint256) { + return (amount_ * feePercent_) / PRECISION; } } diff --git a/contracts/L1/L1Sender.sol b/contracts/L1/L1Sender.sol index d3cb2e9..2bab303 100644 --- a/contracts/L1/L1Sender.sol +++ b/contracts/L1/L1Sender.sol @@ -6,13 +6,12 @@ import {ILayerZeroEndpoint} from "@layerzerolabs/lz-evm-sdk-v1-0.7/contracts/int import {IGatewayRouter} from "@arbitrum/token-bridge-contracts/contracts/tokenbridge/libraries/gateway/IGatewayRouter.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; -import {IWStETH} from "../interfaces/tokens/IWStETH.sol"; import {IL1Sender, IERC165} from "../interfaces/IL1Sender.sol"; +import {IWStETH} from "../interfaces/tokens/IWStETH.sol"; -contract L1Sender is IL1Sender, OwnableUpgradeable, UUPSUpgradeable { +contract L1Sender is IL1Sender, OwnableUpgradeable { address public unwrappedDepositToken; address public distribution; @@ -34,36 +33,16 @@ contract L1Sender is IL1Sender, OwnableUpgradeable, UUPSUpgradeable { DepositTokenConfig calldata depositTokenConfig_ ) external initializer { __Ownable_init(); - __UUPSUpgradeable_init(); - setDistribution(distribution_); - setRewardTokenConfig(rewardTokenConfig_); - setDepositTokenConfig(depositTokenConfig_); + distribution = distribution_; + rewardTokenConfig = rewardTokenConfig_; + _setDepositTokenConfig(depositTokenConfig_); } function supportsInterface(bytes4 interfaceId_) external pure returns (bool) { return interfaceId_ == type(IL1Sender).interfaceId || interfaceId_ == type(IERC165).interfaceId; } - function setDistribution(address distribution_) public onlyOwner { - distribution = distribution_; - } - - function setRewardTokenConfig(RewardTokenConfig calldata newConfig_) public onlyOwner { - rewardTokenConfig = newConfig_; - } - - function setDepositTokenConfig(DepositTokenConfig calldata newConfig_) public onlyOwner { - require(newConfig_.receiver != address(0), "L1S: invalid receiver"); - - DepositTokenConfig storage oldConfig = depositTokenConfig; - - _replaceDepositToken(oldConfig.token, newConfig_.token); - _replaceDepositTokenGateway(oldConfig.gateway, newConfig_.gateway, oldConfig.token, newConfig_.token); - - depositTokenConfig = newConfig_; - } - function _replaceDepositToken(address oldToken_, address newToken_) private { bool isTokenChanged_ = oldToken_ != newToken_; @@ -140,5 +119,30 @@ contract L1Sender is IL1Sender, OwnableUpgradeable, UUPSUpgradeable { ); } - function _authorizeUpgrade(address) internal view override onlyOwner {} + function setRewardTokenLZParams(address zroPaymentAddress, bytes calldata adapterParams) external onlyOwner { + rewardTokenConfig.zroPaymentAddress = zroPaymentAddress; + rewardTokenConfig.adapterParams = adapterParams; + } + + function _setDepositTokenConfig(DepositTokenConfig calldata newConfig_) internal { + require(newConfig_.receiver != address(0), "L1S: invalid receiver"); + + _setDepositToken(newConfig_.token); + _setDepositTokenGateway(newConfig_.gateway, newConfig_.token); + + depositTokenConfig = newConfig_; + } + + function _setDepositToken(address newToken_) private { + // Get stETH from wstETH + address unwrappedToken_ = IWStETH(newToken_).stETH(); + // Increase allowance from stETH to wstETH. To exchange stETH for wstETH + IERC20(unwrappedToken_).approve(newToken_, type(uint256).max); + + unwrappedDepositToken = unwrappedToken_; + } + + function _setDepositTokenGateway(address newGateway_, address newToken_) private { + IERC20(newToken_).approve(IGatewayRouter(newGateway_).getGateway(newToken_), type(uint256).max); + } } diff --git a/contracts/L1/Mor20FactoryL1.sol b/contracts/L1/Mor20FactoryL1.sol new file mode 100644 index 0000000..b531864 --- /dev/null +++ b/contracts/L1/Mor20FactoryL1.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +import {BaseFactoryL1} from "./BaseFactoryL1.sol"; +import {CorePropertiesL1} from "./CorePropertiesL1.sol"; + +import {IDistribution} from "../interfaces/IDistribution.sol"; +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 { + (address arbitrumGateway_, address lZEnpointAddress_) = coreProperties.getDeployParams(); + + address distributionAddress_ = _deploy2(PoolType.DISTRIBUTION, parameters.name); + + address l1SenderAddress_ = _deploy2(PoolType.L1_SENDER, parameters.name); + + IDistribution(distributionAddress_).Distribution_init( + parameters.depositToken, + l1SenderAddress_, + parameters.poolsInfo + ); + + IL1Sender(l1SenderAddress_).L1Sender__init( + distributionAddress_, + IL1Sender.RewardTokenConfig( + lZEnpointAddress_, + parameters.messageReceiver, + parameters.l2EndpointId, + parameters.zroPaymentAddress, + parameters.adapterParams + ), + IL1Sender.DepositTokenConfig(parameters.wrappedToken, arbitrumGateway_, parameters.tokenReceiver) + ); + + _addDistribution(distributionAddress_); + + _updateSalt(parameters.name); + + emit Mor20Deployed(parameters.name, distributionAddress_, l1SenderAddress_); + } + + function setNewImplementations( + PoolType[] memory poolTypes_, + address[] calldata newImplementations_ + ) external onlyOwner { + _setNewImplementations(poolTypes_, newImplementations_); + } +} diff --git a/contracts/L2/BaseFactoryL2.sol b/contracts/L2/BaseFactoryL2.sol new file mode 100644 index 0000000..0501d2e --- /dev/null +++ b/contracts/L2/BaseFactoryL2.sol @@ -0,0 +1,148 @@ +// 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 {Paginator} from "@solarity/solidity-lib/libs/arrays/Paginator.sol"; +import {ProxyBeacon} from "@solarity/solidity-lib/proxy/beacon/ProxyBeacon.sol"; +import {PublicBeaconProxy} from "@solarity/solidity-lib/proxy/beacon/PublicBeaconProxy.sol"; + +import {ERC20MOR} from "./ERC20MOR.sol"; + +import {RewardTokenDeployer} from "../libs/RewardTokenDeployer.sol"; + +abstract contract BaseFactoryL2 { + using EnumerableSet for EnumerableSet.AddressSet; + using Paginator for EnumerableSet.AddressSet; + + enum PoolType { + L2_MESSAGE_RECEIVER, + L2_TOKEN_RECEIVER, + REWARD_TOKEN + } + + struct Mor20PredictedAddressesL2 { + address l2MessageReceiver; + address l2TokenReceiver; + address rewardToken; + } + mapping(bytes32 => bool) private _usedSalts; + + mapping(PoolType => ProxyBeacon) private _beacons; + mapping(PoolType => EnumerableSet.AddressSet) private _pools; + + function predictMor20Address( + address deployer, + string calldata mor20Name + ) external view returns (Mor20PredictedAddressesL2 memory predictedAddresses) { + if (bytes(mor20Name).length == 0) { + return predictedAddresses; + } + + bytes32 poolSalt = _calculatePoolSalt(deployer, mor20Name); + + return + Mor20PredictedAddressesL2( + _predictPoolAddress(PoolType.L2_MESSAGE_RECEIVER, poolSalt), + _predictPoolAddress(PoolType.L2_TOKEN_RECEIVER, poolSalt), + _predictPoolAddress(PoolType.REWARD_TOKEN, poolSalt) + ); + } + + /** + * @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"); + + 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(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 pools + * @param poolType_ the type of the pools + * @return the number of pools + */ + function countPools(PoolType 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( + PoolType poolType_, + uint256 offset_, + uint256 limit_ + ) public view returns (address[] memory pools_) { + return _pools[poolType_].part(offset_, limit_); + } + + function _addPool(PoolType poolType_, address pool_) internal { + _pools[poolType_].add(pool_); + } + + 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 _calculatePoolSalt(address deployer, string memory poolName) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(deployer, poolName)); + } +} diff --git a/contracts/L2/CorePropertiesL2.sol b/contracts/L2/CorePropertiesL2.sol new file mode 100644 index 0000000..83de5a7 --- /dev/null +++ b/contracts/L2/CorePropertiesL2.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {MultiOwnable} from "@solarity/solidity-lib/access/MultiOwnable.sol"; + +contract CorePropertiesL2 is MultiOwnable { + address public arbitrumGateway; + address public treasuryAddress; + + address public lZEnpointAddress; + address public lZGatewayAddress; + uint16 public l1ChainId; + + uint256 public destinationChainId; // arbitrum + + constructor() { + __MultiOwnable_init(); + } +} diff --git a/contracts/L2/MOROFT.sol b/contracts/L2/ERC20MOR.sol similarity index 74% rename from contracts/L2/MOROFT.sol rename to contracts/L2/ERC20MOR.sol index b7cacae..30766b2 100644 --- a/contracts/L2/MOROFT.sol +++ b/contracts/L2/ERC20MOR.sol @@ -3,18 +3,18 @@ pragma solidity ^0.8.20; import {OFT} from "../@layerzerolabs/lz-evm-oapp-v2/contracts/oft/OFT.sol"; -import {IMOROFT, IERC20, IERC165, IOAppCore} from "../interfaces/IMOROFT.sol"; +import {IERC20MOR, IERC20, IERC165, IOAppCore} from "../interfaces/IERC20MOR.sol"; -contract MOROFT is IMOROFT, OFT { +contract ERC20MOR is IERC20MOR, OFT { address private immutable _minter; constructor( + string memory name_, + string memory symbol_, address layerZeroEndpoint_, address delegate_, address minter_ - ) OFT("MOR", "MOR", layerZeroEndpoint_, delegate_) { - require(minter_ != address(0), "MOROFT: invalid minter"); - + ) OFT(name_, symbol_, layerZeroEndpoint_, delegate_) { _minter = minter_; transferOwnership(delegate_); @@ -22,7 +22,7 @@ contract MOROFT is IMOROFT, OFT { function supportsInterface(bytes4 interfaceId_) external pure returns (bool) { return - interfaceId_ == type(IMOROFT).interfaceId || + interfaceId_ == type(IERC20MOR).interfaceId || interfaceId_ == type(IERC20).interfaceId || interfaceId_ == type(IOAppCore).interfaceId || interfaceId_ == type(IERC165).interfaceId; @@ -33,7 +33,7 @@ contract MOROFT is IMOROFT, OFT { } function mint(address account_, uint256 amount_) public { - require(_msgSender() == minter(), "MOROFT: invalid caller"); + require(_msgSender() == minter(), "ERC20MOR: invalid caller"); _mint(account_, amount_); } diff --git a/contracts/L2/L2MessageReceiver.sol b/contracts/L2/L2MessageReceiver.sol index 6e9d831..9ac3419 100644 --- a/contracts/L2/L2MessageReceiver.sol +++ b/contracts/L2/L2MessageReceiver.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -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 {ContextUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; -import {IMOR} from "../interfaces/IMOR.sol"; +import {IERC20MOR} from "../interfaces/IERC20MOR.sol"; import {IL2MessageReceiver} from "../interfaces/IL2MessageReceiver.sol"; -contract L2MessageReceiver is IL2MessageReceiver, OwnableUpgradeable, UUPSUpgradeable { +contract L2MessageReceiver is IL2MessageReceiver, Initializable, ContextUpgradeable { address public rewardToken; Config public config; @@ -18,12 +18,7 @@ contract L2MessageReceiver is IL2MessageReceiver, OwnableUpgradeable, UUPSUpgrad _disableInitializers(); } - function L2MessageReceiver__init() external initializer { - __Ownable_init(); - __UUPSUpgradeable_init(); - } - - function setParams(address rewardToken_, Config calldata config_) external onlyOwner { + function L2MessageReceiver__init(address rewardToken_, Config calldata config_) external initializer { rewardToken = rewardToken_; config = config_; } @@ -102,8 +97,6 @@ contract L2MessageReceiver is IL2MessageReceiver, OwnableUpgradeable, UUPSUpgrad (address user_, uint256 amount_) = abi.decode(payload_, (address, uint256)); - IMOR(rewardToken).mint(user_, amount_); + IERC20MOR(rewardToken).mint(user_, amount_); } - - function _authorizeUpgrade(address) internal view override onlyOwner {} } diff --git a/contracts/L2/L2TokenReceiver.sol b/contracts/L2/L2TokenReceiver.sol index b58b1ac..fbf9954 100644 --- a/contracts/L2/L2TokenReceiver.sol +++ b/contracts/L2/L2TokenReceiver.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; +import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import {ISwapRouter} from "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol"; @@ -10,11 +10,12 @@ import {TransferHelper} from "@uniswap/v3-periphery/contracts/libraries/Transfer import {IL2TokenReceiver, IERC165, IERC721Receiver} from "../interfaces/IL2TokenReceiver.sol"; import {INonfungiblePositionManager} from "../interfaces/uniswap-v3/INonfungiblePositionManager.sol"; -contract L2TokenReceiver is IL2TokenReceiver, OwnableUpgradeable, UUPSUpgradeable { +contract L2TokenReceiver is IL2TokenReceiver, OwnableUpgradeable { address public router; address public nonfungiblePositionManager; - SwapParams public params; + SwapParams public firstSwapParams; + SwapParams public secondSwapParams; constructor() { _disableInitializers(); @@ -23,15 +24,16 @@ contract L2TokenReceiver is IL2TokenReceiver, OwnableUpgradeable, UUPSUpgradeabl function L2TokenReceiver__init( address router_, address nonfungiblePositionManager_, - SwapParams memory params_ + SwapParams memory firstSwapParams_, + SwapParams memory secondSwapParams_ ) external initializer { __Ownable_init(); - __UUPSUpgradeable_init(); router = router_; nonfungiblePositionManager = nonfungiblePositionManager_; - _editParams(params_); + _addAllowanceUpdateSwapParams(firstSwapParams_, true); + _addAllowanceUpdateSwapParams(secondSwapParams_, false); } function supportsInterface(bytes4 interfaceId_) external pure returns (bool) { @@ -41,25 +43,37 @@ contract L2TokenReceiver is IL2TokenReceiver, OwnableUpgradeable, UUPSUpgradeabl interfaceId_ == type(IERC165).interfaceId; } - function editParams(SwapParams memory newParams_) external onlyOwner { - if (params.tokenIn != newParams_.tokenIn) { - TransferHelper.safeApprove(params.tokenIn, router, 0); - TransferHelper.safeApprove(params.tokenIn, nonfungiblePositionManager, 0); + function editParams(SwapParams memory newParams_, bool isEditFirstParams_) external onlyOwner { + SwapParams memory params_ = _getSwapParams(isEditFirstParams_); + + if (params_.tokenIn != address(0) && params_.tokenIn != newParams_.tokenIn) { + TransferHelper.safeApprove(params_.tokenIn, router, 0); + TransferHelper.safeApprove(params_.tokenIn, nonfungiblePositionManager, 0); } - if (params.tokenOut != newParams_.tokenOut) { - TransferHelper.safeApprove(params.tokenOut, nonfungiblePositionManager, 0); + if (params_.tokenOut != address(0) && params_.tokenOut != newParams_.tokenOut) { + TransferHelper.safeApprove(params_.tokenOut, nonfungiblePositionManager, 0); } - _editParams(newParams_); + _addAllowanceUpdateSwapParams(newParams_, isEditFirstParams_); + } + + function withdrawToken(address recipient_, address token_, uint256 amount_) external onlyOwner { + // TODO: Add the cap for the amount + TransferHelper.safeTransfer(token_, recipient_, amount_); + } + + function withdrawTokenId(address recipient_, address token_, uint256 tokenId_) external onlyOwner { + IERC721(token_).safeTransferFrom(address(this), recipient_, tokenId_); } function swap( uint256 amountIn_, uint256 amountOutMinimum_, - uint256 deadline_ + uint256 deadline_, + bool isEditFirstParams_ ) external onlyOwner returns (uint256) { - SwapParams memory params_ = params; + SwapParams memory params_ = _getSwapParams(isEditFirstParams_); ISwapRouter.ExactInputSingleParams memory swapParams_ = ISwapRouter.ExactInputSingleParams({ tokenIn: params_.tokenIn, @@ -94,7 +108,7 @@ contract L2TokenReceiver is IL2TokenReceiver, OwnableUpgradeable, UUPSUpgradeabl (, , address token0_, , , , , , , , , ) = INonfungiblePositionManager(nonfungiblePositionManager).positions( tokenId_ ); - if (token0_ == params.tokenIn) { + if (token0_ == secondSwapParams.tokenIn) { amountAdd0_ = depositTokenAmountAdd_; amountAdd1_ = rewardTokenAmountAdd_; amountMin0_ = depositTokenAmountMin_; @@ -140,7 +154,7 @@ contract L2TokenReceiver is IL2TokenReceiver, OwnableUpgradeable, UUPSUpgradeabl return this.onERC721Received.selector; } - function _editParams(SwapParams memory newParams_) private { + function _addAllowanceUpdateSwapParams(SwapParams memory newParams_, bool isEditFirstParams_) private { require(newParams_.tokenIn != address(0), "L2TR: invalid tokenIn"); require(newParams_.tokenOut != address(0), "L2TR: invalid tokenOut"); @@ -149,8 +163,14 @@ contract L2TokenReceiver is IL2TokenReceiver, OwnableUpgradeable, UUPSUpgradeabl TransferHelper.safeApprove(newParams_.tokenOut, nonfungiblePositionManager, type(uint256).max); - params = newParams_; + if (isEditFirstParams_) { + firstSwapParams = newParams_; + } else { + secondSwapParams = newParams_; + } } - function _authorizeUpgrade(address) internal view override onlyOwner {} + function _getSwapParams(bool isEditFirstParams_) internal view returns (SwapParams memory) { + return isEditFirstParams_ ? firstSwapParams : secondSwapParams; + } } diff --git a/contracts/L2/L2TokenReceiverV2.sol b/contracts/L2/L2TokenReceiverV2.sol deleted file mode 100644 index d0e83ab..0000000 --- a/contracts/L2/L2TokenReceiverV2.sol +++ /dev/null @@ -1,183 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; -import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; -import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; - -import {ISwapRouter} from "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol"; -import {TransferHelper} from "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol"; - -import {IL2TokenReceiverV2, IERC165, IERC721Receiver} from "../interfaces/IL2TokenReceiverV2.sol"; -import {INonfungiblePositionManager} from "../interfaces/uniswap-v3/INonfungiblePositionManager.sol"; - -contract L2TokenReceiverV2 is IL2TokenReceiverV2, OwnableUpgradeable, UUPSUpgradeable { - address public router; - address public nonfungiblePositionManager; - - SwapParams public secondSwapParams; - - // Storage changes for L2TokenReceiverV2 - SwapParams public firstSwapParams; - - constructor() { - _disableInitializers(); - } - - function L2TokenReceiver__init( - address router_, - address nonfungiblePositionManager_, - SwapParams memory params_ - ) external initializer { - __Ownable_init(); - __UUPSUpgradeable_init(); - - router = router_; - nonfungiblePositionManager = nonfungiblePositionManager_; - - _addAllowanceUpdateSwapParams(params_, false); - } - - function supportsInterface(bytes4 interfaceId_) external pure returns (bool) { - return - interfaceId_ == type(IL2TokenReceiverV2).interfaceId || - interfaceId_ == type(IERC721Receiver).interfaceId || - interfaceId_ == type(IERC165).interfaceId; - } - - function editParams(SwapParams memory newParams_, bool isEditFirstParams_) external onlyOwner { - SwapParams memory params_ = _getSwapParams(isEditFirstParams_); - - if (params_.tokenIn != address(0) && params_.tokenIn != newParams_.tokenIn) { - TransferHelper.safeApprove(params_.tokenIn, router, 0); - TransferHelper.safeApprove(params_.tokenIn, nonfungiblePositionManager, 0); - } - - if (params_.tokenOut != address(0) && params_.tokenOut != newParams_.tokenOut) { - TransferHelper.safeApprove(params_.tokenOut, nonfungiblePositionManager, 0); - } - - _addAllowanceUpdateSwapParams(newParams_, isEditFirstParams_); - } - - function withdrawToken(address recipient_, address token_, uint256 amount_) external onlyOwner { - TransferHelper.safeTransfer(token_, recipient_, amount_); - } - - function withdrawTokenId(address recipient_, address token_, uint256 tokenId_) external onlyOwner { - IERC721(token_).safeTransferFrom(address(this), recipient_, tokenId_); - } - - function swap( - uint256 amountIn_, - uint256 amountOutMinimum_, - uint256 deadline_, - bool isEditFirstParams_ - ) external onlyOwner returns (uint256) { - SwapParams memory params_ = _getSwapParams(isEditFirstParams_); - - ISwapRouter.ExactInputSingleParams memory swapParams_ = ISwapRouter.ExactInputSingleParams({ - tokenIn: params_.tokenIn, - tokenOut: params_.tokenOut, - fee: params_.fee, - recipient: address(this), - deadline: deadline_, - amountIn: amountIn_, - amountOutMinimum: amountOutMinimum_, - sqrtPriceLimitX96: params_.sqrtPriceLimitX96 - }); - - uint256 amountOut_ = ISwapRouter(router).exactInputSingle(swapParams_); - - emit TokensSwapped(params_.tokenIn, params_.tokenOut, amountIn_, amountOut_, amountOutMinimum_); - - return amountOut_; - } - - function increaseLiquidityCurrentRange( - uint256 tokenId_, - uint256 depositTokenAmountAdd_, - uint256 rewardTokenAmountAdd_, - uint256 depositTokenAmountMin_, - uint256 rewardTokenAmountMin_ - ) external onlyOwner returns (uint128 liquidity_, uint256 amount0_, uint256 amount1_) { - uint256 amountAdd0_; - uint256 amountAdd1_; - uint256 amountMin0_; - uint256 amountMin1_; - - (, , address token0_, , , , , , , , , ) = INonfungiblePositionManager(nonfungiblePositionManager).positions( - tokenId_ - ); - if (token0_ == secondSwapParams.tokenIn) { - amountAdd0_ = depositTokenAmountAdd_; - amountAdd1_ = rewardTokenAmountAdd_; - amountMin0_ = depositTokenAmountMin_; - amountMin1_ = rewardTokenAmountMin_; - } else { - amountAdd0_ = rewardTokenAmountAdd_; - amountAdd1_ = depositTokenAmountAdd_; - amountMin0_ = rewardTokenAmountMin_; - amountMin1_ = depositTokenAmountMin_; - } - - INonfungiblePositionManager.IncreaseLiquidityParams memory params_ = INonfungiblePositionManager - .IncreaseLiquidityParams({ - tokenId: tokenId_, - amount0Desired: amountAdd0_, - amount1Desired: amountAdd1_, - amount0Min: amountMin0_, - amount1Min: amountMin1_, - deadline: block.timestamp - }); - - (liquidity_, amount0_, amount1_) = INonfungiblePositionManager(nonfungiblePositionManager).increaseLiquidity( - params_ - ); - - emit LiquidityIncreased(tokenId_, amount0_, amount1_, liquidity_, amountMin0_, amountMin1_); - } - - function collectFees(uint256 tokenId_) external returns (uint256 amount0_, uint256 amount1_) { - INonfungiblePositionManager.CollectParams memory params_ = INonfungiblePositionManager.CollectParams({ - tokenId: tokenId_, - recipient: address(this), - amount0Max: type(uint128).max, - amount1Max: type(uint128).max - }); - - (amount0_, amount1_) = INonfungiblePositionManager(nonfungiblePositionManager).collect(params_); - - emit FeesCollected(tokenId_, amount0_, amount1_); - } - - function version() external pure returns (uint256) { - return 2; - } - - function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4) { - return this.onERC721Received.selector; - } - - function _addAllowanceUpdateSwapParams(SwapParams memory newParams_, bool isEditFirstParams_) private { - require(newParams_.tokenIn != address(0), "L2TR: invalid tokenIn"); - require(newParams_.tokenOut != address(0), "L2TR: invalid tokenOut"); - - TransferHelper.safeApprove(newParams_.tokenIn, router, type(uint256).max); - TransferHelper.safeApprove(newParams_.tokenIn, nonfungiblePositionManager, type(uint256).max); - - TransferHelper.safeApprove(newParams_.tokenOut, nonfungiblePositionManager, type(uint256).max); - - if (isEditFirstParams_) { - firstSwapParams = newParams_; - } else { - secondSwapParams = newParams_; - } - } - - function _getSwapParams(bool isEditFirstParams_) internal view returns (SwapParams memory) { - return isEditFirstParams_ ? firstSwapParams : secondSwapParams; - } - - function _authorizeUpgrade(address) internal view override onlyOwner {} -} diff --git a/contracts/L2/Mor20FactoryL2.sol b/contracts/L2/Mor20FactoryL2.sol new file mode 100644 index 0000000..227f9dd --- /dev/null +++ b/contracts/L2/Mor20FactoryL2.sol @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +import {BaseFactoryL2, RewardTokenDeployer, Create2} from "./BaseFactoryL2.sol"; + +import {IL2MessageReceiver} from "../interfaces/IL2MessageReceiver.sol"; +import {IL2TokenReceiver} from "../interfaces/IL2TokenReceiver.sol"; + +import {CorePropertiesL2} from "./CorePropertiesL2.sol"; + +contract Mor20FactoryL2 is BaseFactoryL2, Ownable { + CorePropertiesL2 public coreProperties; + + struct Mor20DeployParams { + string name; + string symbol; + address rewardToken; + address rewardTokenDelegate; + ////// + address sender; + uint16 senderChainId; + ////// + address router_; + address nonfungiblePositionManager_; + IL2TokenReceiver.SwapParams firstSwapParams_; + IL2TokenReceiver.SwapParams secondSwapParams; + } + + event Mor20Deployed(string name, address l2MessageReceiver, address l2TokenReceiver, address rewardToken); + + function deployMor20OnL1(Mor20DeployParams calldata parameters) external onlyOwner { + address l2MessageReceiverAddress = _deploy2(PoolType.L2_MESSAGE_RECEIVER, parameters.name); + + address l2TokenReceiverAddress = _deploy2(PoolType.L2_TOKEN_RECEIVER, parameters.name); + + address rewardTokenAddress; + if (parameters.rewardToken == address(0)) { + rewardTokenAddress = _deployRewardToken( + parameters.name, + parameters.symbol, + coreProperties.lZEnpointAddress(), + parameters.rewardTokenDelegate, + l2MessageReceiverAddress + ); + } else { + rewardTokenAddress = parameters.rewardToken; + } + + IL2MessageReceiver(l2MessageReceiverAddress).L2MessageReceiver__init( + rewardTokenAddress, + IL2MessageReceiver.Config(coreProperties.lZGatewayAddress(), parameters.sender, coreProperties.l1ChainId()) + ); + + IL2TokenReceiver(l2TokenReceiverAddress).L2TokenReceiver__init( + parameters.router_, + parameters.nonfungiblePositionManager_, + parameters.firstSwapParams_, + parameters.secondSwapParams + ); + + _addPool(PoolType.L2_MESSAGE_RECEIVER, l2MessageReceiverAddress); + _addPool(PoolType.L2_TOKEN_RECEIVER, l2TokenReceiverAddress); + _addPool(PoolType.REWARD_TOKEN, rewardTokenAddress); + + emit Mor20Deployed(parameters.name, l2MessageReceiverAddress, l2TokenReceiverAddress, rewardTokenAddress); + } + + function setNewImplementations( + PoolType[] memory poolTypes_, + address[] calldata newImplementations_ + ) external onlyOwner { + _setNewImplementations(poolTypes_, newImplementations_); + } + + function _deployRewardToken( + string memory name_, + string memory symbol_, + address layerZeroEndpoint_, + address delegate_, + address minter_ + ) internal returns (address) { + bytes32 salt_ = _calculatePoolSalt(tx.origin, name_); + + return RewardTokenDeployer.deployRewardToken(salt_, name_, symbol_, layerZeroEndpoint_, delegate_, minter_); + } +} diff --git a/contracts/interfaces/IDistribution.sol b/contracts/interfaces/IDistribution.sol index 762d1f7..72638e3 100644 --- a/contracts/interfaces/IDistribution.sol +++ b/contracts/interfaces/IDistribution.sol @@ -186,17 +186,6 @@ interface IDistribution { uint256 maxSubmissionCost_ ) external payable returns (bytes memory); - /** - * The function to remove upgradeability. - */ - function removeUpgradeability() external; - - /** - * The function to check if the contract is upgradeable. - * @return The flag that indicates if the contract is upgradeable. - */ - function isNotUpgradeable() external view returns (bool); - /** * The function to get the address of deposit token. * @return The address of deposit token. diff --git a/contracts/interfaces/IMOROFT.sol b/contracts/interfaces/IERC20MOR.sol similarity index 90% rename from contracts/interfaces/IMOROFT.sol rename to contracts/interfaces/IERC20MOR.sol index 9d5a0b6..4321c1d 100644 --- a/contracts/interfaces/IMOROFT.sol +++ b/contracts/interfaces/IERC20MOR.sol @@ -6,9 +6,9 @@ import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import {IOAppCore} from ".././@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/interfaces/IOAppCore.sol"; /** - * This is the interface for MOROFT token contract. The token is ERC20 with burnable and Layer Zero OFT features. + * This is the interface for ERC20MOR token contract. The token is ERC20 burnable and Layer Zero OFT features. */ -interface IMOROFT is IERC20, IERC165 { +interface IERC20MOR is IERC20, IERC165 { /** * The function to get the minter address. * @return The minter address. diff --git a/contracts/interfaces/IL1Sender.sol b/contracts/interfaces/IL1Sender.sol index 47b086e..003998d 100644 --- a/contracts/interfaces/IL1Sender.sol +++ b/contracts/interfaces/IL1Sender.sol @@ -33,34 +33,21 @@ interface IL1Sender is IERC165 { } /** - * The function to get the deposit token's address. - */ - function unwrappedDepositToken() external view returns (address); - - /** - * The function to set the reward token's config. - * @param newConfig_ The new reward token's config. + * The function to initialize the contract. + * @param distribution_ The address of the distribution contract. + * @param rewardTokenConfig_ The reward token's config. + * @param depositTokenConfig_ The deposit token's config. */ - function setRewardTokenConfig(RewardTokenConfig calldata newConfig_) external; + function L1Sender__init( + address distribution_, + RewardTokenConfig calldata rewardTokenConfig_, + DepositTokenConfig calldata depositTokenConfig_ + ) external; /** - * The function to set the deposit token's config. - * @param newConfig_ The new deposit token's config. - */ - function setDepositTokenConfig(DepositTokenConfig calldata newConfig_) external; - - /** - * The function to send all current balance of the deposit token to the L2. - * @param gasLimit_ The gas limit for the L2 transaction. - * @param maxFeePerGas_ The max fee per gas for the L2 transaction. - * @param maxSubmissionCost_ The max submission cost for the L2 transaction. - * @return The unique identifier for withdrawal. + * The function to get the deposit token's address. */ - function sendDepositToken( - uint256 gasLimit_, - uint256 maxFeePerGas_, - uint256 maxSubmissionCost_ - ) external payable returns (bytes memory); + function unwrappedDepositToken() external view returns (address); /** * The function to send the message of mint of reward token to the L2. diff --git a/contracts/interfaces/IL2MessageReceiver.sol b/contracts/interfaces/IL2MessageReceiver.sol index 7aaece2..c1cf139 100644 --- a/contracts/interfaces/IL2MessageReceiver.sol +++ b/contracts/interfaces/IL2MessageReceiver.sol @@ -51,17 +51,17 @@ interface IL2MessageReceiver is ILayerZeroReceiver { } /** - * The function to get the reward token's address. - * @return The address of reward token. + * The function to initialize the contract. + * @param rewardToken_ The address of reward token. + * @param config_ The config data. */ - function rewardToken() external view returns (address); + function L2MessageReceiver__init(address rewardToken_, Config calldata config_) external; /** - * The function to set the params. - * @param rewardToken_ The address of reward token. - * @param config_ The config data. + * The function to get the reward token's address. + * @return The address of reward token. */ - function setParams(address rewardToken_, Config calldata config_) external; + function rewardToken() external view returns (address); /** * The function to call the nonblockingLzReceive. diff --git a/contracts/interfaces/IL2TokenReceiver.sol b/contracts/interfaces/IL2TokenReceiver.sol index 074bfb8..3ae9a93 100644 --- a/contracts/interfaces/IL2TokenReceiver.sol +++ b/contracts/interfaces/IL2TokenReceiver.sol @@ -64,20 +64,57 @@ interface IL2TokenReceiver is IERC165, IERC721Receiver { */ event FeesCollected(uint256 indexed tokenId, uint256 amount0, uint256 amount1); + /** + * The function to initialize the contract. + * @param router_ The address of the router. + * @param nonfungiblePositionManager_ The address of the nonfungible position manager. + * @param firstSwapParams_ The first path's part swap params. + * @param secondSwapParams_ The second path's part swap params. + */ + function L2TokenReceiver__init( + address router_, + address nonfungiblePositionManager_, + SwapParams memory firstSwapParams_, + SwapParams memory secondSwapParams_ + ) external; + /** * The function to edit the swap params. * @param params_ The new swap params. + * @param isEditFirstParams_ The flag to indicate if the swapParams is initial. */ - function editParams(SwapParams memory params_) external; + function editParams(SwapParams memory params_, bool isEditFirstParams_) external; /** * The function to swap current contract's tokens specified in the params. * @param amountIn_ The amount of tokens to swap. * @param amountOutMinimum_ The minimum amount of tokens to receive. * @param deadline_ The deadline for the swap. + * @param isEditFirstParams_ The flag to indicate if the swapParams is initial. * @return The amount of tokens received. */ - function swap(uint256 amountIn_, uint256 amountOutMinimum_, uint256 deadline_) external returns (uint256); + function swap( + uint256 amountIn_, + uint256 amountOutMinimum_, + uint256 deadline_, + bool isEditFirstParams_ + ) external returns (uint256); + + /** + * The function to withdraw tokens from the contract. + * @param recipient_ The address of the recipient. + * @param token_ The address of the token to withdraw. + * @param amount_ The amount of tokens to withdraw. + */ + function withdrawToken(address recipient_, address token_, uint256 amount_) external; + + /** + * The function to withdraw NFT token from the contract. + * @param recipient_ The address of the recipient. + * @param token_ The address of the token to withdraw. + * @param tokenId_ The ID of the token to withdraw. + */ + function withdrawTokenId(address recipient_, address token_, uint256 tokenId_) external; /** * The function to increase liquidity in the current price range. @@ -98,6 +135,14 @@ interface IL2TokenReceiver is IERC165, IERC721Receiver { uint256 rewardTokenAmountMin_ ) external returns (uint128 liquidity_, uint256 amount0_, uint256 amount1_); + /** + * The function to collect fees from the position. The fees are not transferred to the caller. + * @param tokenId_ The ID of the position. + * @return amount0_ The amount of token0 collected. + * @return amount1_ The amount of token1 collected. + */ + function collectFees(uint256 tokenId_) external returns (uint256 amount0_, uint256 amount1_); + /** * The function to get the router address. * @return The address of the router. diff --git a/contracts/interfaces/IL2TokenReceiverV2.sol b/contracts/interfaces/IL2TokenReceiverV2.sol deleted file mode 100644 index 268aeb4..0000000 --- a/contracts/interfaces/IL2TokenReceiverV2.sol +++ /dev/null @@ -1,143 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; -import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; - -/** - * This is Swap contract that swaps tokens using Uniswap V3. - */ -interface IL2TokenReceiverV2 is IERC165, IERC721Receiver { - /** - * The structure that stores the swap params. - * @param tokenIn The address of the token to swap from. - * @param tokenOut The address of the token to swap to. - * @param fee The fee of the swap. - * @param sqrtPriceLimitX96 The price limit of the swap. - */ - struct SwapParams { - address tokenIn; - address tokenOut; - uint24 fee; - uint160 sqrtPriceLimitX96; - } - - /** - * The event that is emitted when the swap is executed. - * @param tokenIn The address of the token to swap from. - * @param tokenOut The address of the token to swap to. - * @param amountIn The amount of tokens to swap. - * @param amountOut The amount of tokens received. - * @param amountOutMinimum The minimum amount of tokens to receive. - */ - event TokensSwapped( - address indexed tokenIn, - address indexed tokenOut, - uint256 amountIn, - uint256 amountOut, - uint256 amountOutMinimum - ); - - /** - * The event that is emitted when the liquidity is increased. - * @param tokenId The ID of the position. - * @param amount0 The amount of token0 added. - * @param amount1 The amount of token1 added. - * @param liquidity The amount of liquidity added. - * @param amount0Min The minimum amount of token0 to add. - * @param amount1Min The minimum amount of token1 to add. - */ - event LiquidityIncreased( - uint256 indexed tokenId, - uint256 amount0, - uint256 amount1, - uint256 liquidity, - uint256 amount0Min, - uint256 amount1Min - ); - - /** - * The event that is emitted when the fees are collected. - * @param tokenId The ID of the position. - * @param amount0 The amount of token0 collected. - * @param amount1 The amount of token1 collected. - */ - event FeesCollected(uint256 indexed tokenId, uint256 amount0, uint256 amount1); - - /** - * The function to edit the swap params. - * @param params_ The new swap params. - * @param isEditFirstParams_ The flag to indicate if the swapParams is initial. - */ - function editParams(SwapParams memory params_, bool isEditFirstParams_) external; - - /** - * The function to swap current contract's tokens specified in the params. - * @param amountIn_ The amount of tokens to swap. - * @param amountOutMinimum_ The minimum amount of tokens to receive. - * @param deadline_ The deadline for the swap. - * @param isEditFirstParams_ The flag to indicate if the swapParams is initial. - * @return The amount of tokens received. - */ - function swap( - uint256 amountIn_, - uint256 amountOutMinimum_, - uint256 deadline_, - bool isEditFirstParams_ - ) external returns (uint256); - - /** - * The function to withdraw tokens from the contract. - * @param recipient_ The address of the recipient. - * @param token_ The address of the token to withdraw. - * @param amount_ The amount of tokens to withdraw. - */ - function withdrawToken(address recipient_, address token_, uint256 amount_) external; - - /** - * The function to withdraw NFT token from the contract. - * @param recipient_ The address of the recipient. - * @param token_ The address of the token to withdraw. - * @param tokenId_ The ID of the token to withdraw. - */ - function withdrawTokenId(address recipient_, address token_, uint256 tokenId_) external; - - /** - * The function to increase liquidity in the current price range. - * @param tokenId The ID of the position. - * @param amountAdd0_ The amount of tokenIn to add. - * @param amountAdd1_ The amount of tokenOut to add. - * @param depositTokenAmountMin_ The minimum amount of deposit token to add. - * @param rewardTokenAmountMin_ The minimum amount of reward token to add. - * @return liquidity_ The amount of liquidity added. - * @return amount0_ The amount of token0 added. - * @return amount1_ The amount of token1 added. - */ - function increaseLiquidityCurrentRange( - uint256 tokenId, - uint256 amountAdd0_, - uint256 amountAdd1_, - uint256 depositTokenAmountMin_, - uint256 rewardTokenAmountMin_ - ) external returns (uint128 liquidity_, uint256 amount0_, uint256 amount1_); - - /** - * The function to collect fees from the position. The fees are not transferred to the caller. - * @param tokenId_ The ID of the position. - * @return amount0_ The amount of token0 collected. - * @return amount1_ The amount of token1 collected. - */ - function collectFees(uint256 tokenId_) external returns (uint256 amount0_, uint256 amount1_); - - /** - * The function to get the router address. - * @return The address of the router. - */ - function router() external view returns (address); - - /** - * The function to get the nonfungible position manager address. - * @return The address of the nonfungible position manager. - */ - function nonfungiblePositionManager() external view returns (address); -} diff --git a/contracts/interfaces/IMOR.sol b/contracts/interfaces/IMOR.sol deleted file mode 100644 index 49f138e..0000000 --- a/contracts/interfaces/IMOR.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; - -/** - * This is the MOR token contract. The token is ERC20 with cap and burnable features. - */ -interface IMOR is IERC20, IERC165 { - /** - * The function to get the cap of the token. - * @return The cap of the token. - */ - function cap() external view returns (uint256); - - /** - * The function to mint tokens. - * @param account_ The address of the account to mint tokens to. - * @param amount_ The amount of tokens to mint. - */ - function mint(address account_, uint256 amount_) external; -} diff --git a/contracts/libs/RewardTokenDeployer.sol b/contracts/libs/RewardTokenDeployer.sol new file mode 100644 index 0000000..3aba355 --- /dev/null +++ b/contracts/libs/RewardTokenDeployer.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import "@openzeppelin/contracts/utils/Create2.sol"; + +import "../L2/ERC20MOR.sol"; + +library RewardTokenDeployer { + function deployRewardToken( + bytes32 salt, + string memory name_, + string memory symbol_, + address layerZeroEndpoint_, + address delegate_, + address minter_ + ) external returns (address) { + ERC20MOR rewardToken = new ERC20MOR{salt: salt}(name_, symbol_, layerZeroEndpoint_, delegate_, minter_); + + return address(rewardToken); + } + + function predictRewardTokenAddress( + bytes32 salt, + string memory name_, + string memory symbol_, + address layerZeroEndpoint_, + address delegate_, + address minter_ + ) external view returns (address) { + bytes32 bytecodeHash = keccak256( + abi.encodePacked( + type(ERC20MOR).creationCode, + abi.encode(name_, symbol_, layerZeroEndpoint_, delegate_, minter_) + ) + ); + + return Create2.computeAddress(salt, bytecodeHash); + } +} diff --git a/package-lock.json b/package-lock.json index 403ee51..98b6049 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "@layerzerolabs/solidity-examples": "^1.0.0", "@openzeppelin/contracts": "4.9.2", "@openzeppelin/contracts-upgradeable": "4.9.2", - "@solarity/solidity-lib": "2.5.9", + "@solarity/solidity-lib": "2.7.2", "@uniswap/v3-core": "^1.0.1", "@uniswap/v3-periphery": "^1.4.4", "dotenv": "^10.0.0", @@ -3861,14 +3861,28 @@ } }, "node_modules/@solarity/solidity-lib": { - "version": "2.5.9", - "resolved": "https://registry.npmjs.org/@solarity/solidity-lib/-/solidity-lib-2.5.9.tgz", - "integrity": "sha512-zwUu3HR0oCOyAK2MaVoX38fpzUJxTFuif/ICtuRZcc1JIzLvRWQ7MnrbQVXWxjTL/Z1brNAqZa3wEI2U5+w01w==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@solarity/solidity-lib/-/solidity-lib-2.7.2.tgz", + "integrity": "sha512-P08xkimAcR5dG2ncqA9OEjmwNwQtJeH036wmkdpp9TDESo2KGPwGwAlcy7RpfTellE8RFDuAvOBj7sedFCkeOg==", "dependencies": { - "@openzeppelin/contracts": "4.9.2", - "@openzeppelin/contracts-upgradeable": "4.9.2" + "@openzeppelin/contracts": "4.9.5", + "@openzeppelin/contracts-upgradeable": "4.9.5", + "@uniswap/v2-core": "1.0.1", + "@uniswap/v2-periphery": "1.1.0-beta.0", + "@uniswap/v3-core": "1.0.1", + "@uniswap/v3-periphery": "1.4.4" } }, + "node_modules/@solarity/solidity-lib/node_modules/@openzeppelin/contracts": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.9.5.tgz", + "integrity": "sha512-ZK+W5mVhRppff9BE6YdR8CC52C8zAvsVAiWhEtQ5+oNxFE6h1WdeWo+FJSF8KKvtxxVYZ7MTP/5KoVpAU3aSWg==" + }, + "node_modules/@solarity/solidity-lib/node_modules/@openzeppelin/contracts-upgradeable": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.9.5.tgz", + "integrity": "sha512-f7L1//4sLlflAN7fVzJLoRedrf5Na3Oal5PZfIq55NFcVZ90EpV1q5xOvL4lFvg3MNICSDr2hH0JUBxwlxcoPg==" + }, "node_modules/@solidity-parser/parser": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.5.tgz", @@ -7183,6 +7197,34 @@ "node": ">=10" } }, + "node_modules/@uniswap/v2-periphery": { + "version": "1.1.0-beta.0", + "resolved": "https://registry.npmjs.org/@uniswap/v2-periphery/-/v2-periphery-1.1.0-beta.0.tgz", + "integrity": "sha512-6dkwAMKza8nzqYiXEr2D86dgW3TTavUvCR0w2Tu33bAbM8Ah43LKAzH7oKKPRT5VJQaMi1jtkGs1E8JPor1n5g==", + "dependencies": { + "@uniswap/lib": "1.1.1", + "@uniswap/v2-core": "1.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@uniswap/v2-periphery/node_modules/@uniswap/lib": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@uniswap/lib/-/lib-1.1.1.tgz", + "integrity": "sha512-2yK7sLpKIT91TiS5sewHtOa7YuM8IuBXVl4GZv2jZFys4D2sY7K5vZh6MqD25TPA95Od+0YzCVq6cTF2IKrOmg==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@uniswap/v2-periphery/node_modules/@uniswap/v2-core": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@uniswap/v2-core/-/v2-core-1.0.0.tgz", + "integrity": "sha512-BJiXrBGnN8mti7saW49MXwxDBRFiWemGetE58q8zgfnPPzQKq55ADltEILqOt6VFZ22kVeVKbF8gVd8aY3l7pA==", + "engines": { + "node": ">=10" + } + }, "node_modules/@uniswap/v3-core": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@uniswap/v3-core/-/v3-core-1.0.1.tgz", @@ -7247,6 +7289,7 @@ "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz", "integrity": "sha512-DnhQwcFEaYsvYDnACLZhMmCWd3rkOeEvglpa4q5i/5Jlm3UIsWaxVzuXvDLFCSCWRO3yy2/+V/G7FusFgejnfQ==", "dev": true, + "optional": true, "peer": true, "dependencies": { "buffer": "^6.0.3", @@ -7279,6 +7322,7 @@ "url": "https://feross.org/support" } ], + "optional": true, "peer": true, "dependencies": { "base64-js": "^1.3.1", @@ -8616,6 +8660,7 @@ "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==", "dev": true, + "optional": true, "peer": true, "engines": { "node": ">=6" @@ -9997,6 +10042,7 @@ "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.4.1.tgz", "integrity": "sha512-r4eRSeStEGf6M5SKdrQhhLK5bOwOBxQhIE3YSTnZE3GpKiLfnnhE+tPtrJE79+eDJgm39BM6LSoI8SCx4HbwlQ==", "dev": true, + "optional": true, "peer": true, "engines": { "node": ">=6" @@ -17295,6 +17341,7 @@ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz", "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==", "dev": true, + "optional": true, "peer": true }, "node_modules/immutable": { @@ -17519,6 +17566,7 @@ "url": "https://feross.org/support" } ], + "optional": true, "peer": true, "engines": { "node": ">=4" @@ -18185,6 +18233,7 @@ "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz", "integrity": "sha512-BWRCMHBxbIqPxJ8vHOvKUsaO0v1sLYZtjN3K2iZJsRBYtp+ONsY6Jfi6hy9K3+zolgQRryhIn2NRZjZnWJ9NmQ==", "dev": true, + "optional": true, "peer": true, "dependencies": { "catering": "^2.1.0" @@ -18300,6 +18349,7 @@ "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-2.1.0.tgz", "integrity": "sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA==", "dev": true, + "optional": true, "peer": true, "engines": { "node": ">=10" @@ -18322,6 +18372,7 @@ "integrity": "sha512-iB8O/7Db9lPaITU1aA2txU/cBEXAt4vWwKQRrrWuS6XDgbP4QZGj9BL2aNbwb002atoQ/lIotJkfyzz+ygQnUQ==", "dev": true, "hasInstallScript": true, + "optional": true, "peer": true, "dependencies": { "abstract-leveldown": "~6.2.1", @@ -18337,6 +18388,7 @@ "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz", "integrity": "sha512-BsLm5vFMRUrrLeCcRc+G0t2qOaTzpoJQLOubq2XM72eNpjF5UdU5o/5NvlNhx95XHcAvcl8OMXr4mlg/fRgUXQ==", "dev": true, + "optional": true, "peer": true, "dependencies": { "buffer": "^5.5.0", @@ -18354,6 +18406,7 @@ "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-2.0.1.tgz", "integrity": "sha512-OTKKOqeav2QWcERMJR7IS9CUo1sHnke2C0gkSmcR7QuEtFNLLzHQAvnMw8ykvEcv0Qtkg0p7FOwP1v9e5Smdcw==", "dev": true, + "optional": true, "peer": true, "engines": { "node": ">=6" @@ -18364,6 +18417,7 @@ "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-1.0.1.tgz", "integrity": "sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg==", "dev": true, + "optional": true, "peer": true, "dependencies": { "xtend": "^4.0.2" @@ -18377,6 +18431,7 @@ "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.1.1.tgz", "integrity": "sha512-dSq1xmcPDKPZ2EED2S6zw/b9NKsqzXRE6dVr8TVQnI3FJOTteUMuqF3Qqs6LZg+mLGYJWqQzMbIjMtJqTv87nQ==", "dev": true, + "optional": true, "peer": true, "bin": { "node-gyp-build": "bin.js", @@ -19260,6 +19315,7 @@ "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==", "dev": true, + "optional": true, "peer": true }, "node_modules/natural-compare": { diff --git a/package.json b/package.json index 26743be..e09bb3d 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "@layerzerolabs/solidity-examples": "^1.0.0", "@openzeppelin/contracts": "4.9.2", "@openzeppelin/contracts-upgradeable": "4.9.2", - "@solarity/solidity-lib": "2.5.9", + "@solarity/solidity-lib": "2.7.2", "@uniswap/v3-core": "^1.0.1", "@uniswap/v3-periphery": "^1.4.4", "dotenv": "^10.0.0", diff --git a/test/L1/BaseFactoryL1.test.ts b/test/L1/BaseFactoryL1.test.ts new file mode 100644 index 0000000..d5dbafc --- /dev/null +++ b/test/L1/BaseFactoryL1.test.ts @@ -0,0 +1,193 @@ +import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { Reverter } from '../helpers/reverter'; + +import { + CorePropertiesL1, + Distribution, + GatewayRouterMock, + L1Sender, + LinearDistributionIntervalDecrease, + Mor20FactoryL1, + StETHMock, + WStETHMock, +} from '@/generated-types/ethers'; +import { ETHER_ADDR, ZERO_ADDR } from '@/scripts/utils/constants'; + +enum PoolTypes { + DISTRIBUTION, + L1_SENDER, +} + +describe.only('BaseFactoryL1', () => { + const reverter = new Reverter(); + + let OWNER: SignerWithAddress; + let SECOND: SignerWithAddress; + + let mor20FactoryL1: Mor20FactoryL1; + + let l1SenderImplementation: L1Sender; + let distributionImplementation: Distribution; + let coreProperties: CorePropertiesL1; + + let stEthMock: StETHMock; + let wstEthMock: WStETHMock; + let gatewayRouterMock: GatewayRouterMock; + + let poolTypes: PoolTypes[]; + let poolImplementations: string[]; + + before(async () => { + [OWNER, SECOND] = await ethers.getSigners(); + + const [ + libFactory, + l1SenderFactory, + tokenDeployerFactory, + mor20FactoryL1Factory, + stEthMockFactory, + wstEthMockFactory, + gatewayRouterMockFactory, + corePropertiesFactory, + ] = await Promise.all([ + ethers.getContractFactory('LinearDistributionIntervalDecrease'), + ethers.getContractFactory('L1Sender'), + ethers.getContractFactory('RewardTokenDeployer'), + ethers.getContractFactory('Mor20FactoryL1'), + ethers.getContractFactory('StETHMock'), + ethers.getContractFactory('WStETHMock'), + ethers.getContractFactory('GatewayRouterMock'), + ethers.getContractFactory('CorePropertiesL1'), + ]); + + let lib: LinearDistributionIntervalDecrease; + [lib, l1SenderImplementation, stEthMock, gatewayRouterMock] = await Promise.all([ + libFactory.deploy(), + l1SenderFactory.deploy(), + stEthMockFactory.deploy(), + gatewayRouterMockFactory.deploy(), + ]); + wstEthMock = await wstEthMockFactory.deploy(stEthMock); + coreProperties = await corePropertiesFactory.deploy(gatewayRouterMock, SECOND, ZERO_ADDR, 1); + + const distributionFactory = await ethers.getContractFactory('Distribution', { + libraries: { + LinearDistributionIntervalDecrease: lib, + }, + }); + distributionImplementation = await distributionFactory.deploy(); + + mor20FactoryL1 = await mor20FactoryL1Factory.deploy(coreProperties); + + poolTypes = [PoolTypes.DISTRIBUTION, PoolTypes.L1_SENDER]; + poolImplementations = [await distributionImplementation.getAddress(), await l1SenderImplementation.getAddress()]; + + await reverter.snapshot(); + }); + + function getMor20DeployParams() { + const mor20DeployParams: Mor20FactoryL1.Mor20DeployParamsStruct = { + name: 'Mor20', + depositToken: stEthMock, + poolsInfo: [], + messageReceiver: ETHER_ADDR, + zroPaymentAddress: ZERO_ADDR, + l2EndpointId: 0, + adapterParams: '0x', + wrappedToken: wstEthMock, + tokenReceiver: ETHER_ADDR, + }; + + return mor20DeployParams; + } + + afterEach(reverter.revert); + + describe('#predictMor20Address', () => { + it('should return zero address if name is an empty string', async () => { + const predictedAddress = await mor20FactoryL1.predictMor20Address(OWNER, ''); + + expect(predictedAddress).to.be.deep.equal([ZERO_ADDR, ZERO_ADDR]); + }); + }); + + describe('#getImplementation', () => { + it('should return current implementation address', async () => { + await mor20FactoryL1.setNewImplementations(poolTypes, poolImplementations); + + const implementation = await mor20FactoryL1.getImplementation(PoolTypes.DISTRIBUTION); + + expect(implementation).to.be.equal(distributionImplementation); + + const implementation2 = await mor20FactoryL1.getImplementation(PoolTypes.L1_SENDER); + + expect(implementation2).to.be.equal(l1SenderImplementation); + }); + + it('should revert if implementation is not set', async () => { + const error = "BaseFactory: this mapping doesn't exist"; + + await expect(mor20FactoryL1.getImplementation(PoolTypes.DISTRIBUTION)).to.be.revertedWith(error); + + await expect(mor20FactoryL1.getImplementation(PoolTypes.L1_SENDER)).to.be.revertedWith(error); + }); + }); + + describe('#getBeaconProxy', () => { + it('should return beacon proxy address', async () => { + await mor20FactoryL1.setNewImplementations(poolTypes, poolImplementations); + + const beaconProxy = await mor20FactoryL1.getBeaconProxy(PoolTypes.DISTRIBUTION); + expect(beaconProxy).to.be.not.equal(ZERO_ADDR); + + const beaconProxy2 = await mor20FactoryL1.getBeaconProxy(PoolTypes.L1_SENDER); + expect(beaconProxy2).to.be.not.equal(ZERO_ADDR); + }); + + it('should revert if beacon is not set', async () => { + const error = 'BaseFactory: bad PublicBeaconProxy'; + + await expect(mor20FactoryL1.getBeaconProxy(PoolTypes.DISTRIBUTION)).to.be.revertedWith(error); + + await expect(mor20FactoryL1.getBeaconProxy(PoolTypes.L1_SENDER)).to.be.revertedWith(error); + }); + }); + + describe('#countDistributions', () => { + it('should return number of deployed distributions', async () => { + await mor20FactoryL1.setNewImplementations(poolTypes, poolImplementations); + + let params = getMor20DeployParams(); + + expect(await mor20FactoryL1.countDistributions()).to.be.equal(0); + + await mor20FactoryL1.deployMor20OnL1(params); + + expect(await mor20FactoryL1.countDistributions()).to.be.equal(1); + + params.name = 'Mor21'; + await mor20FactoryL1.deployMor20OnL1(params); + + expect(await mor20FactoryL1.countDistributions()).to.be.equal(2); + }); + }); + + describe('#listDistributions', () => { + it('should return list of deployed distributions', async () => { + await mor20FactoryL1.setNewImplementations(poolTypes, poolImplementations); + + let params = getMor20DeployParams(); + + expect(await mor20FactoryL1.listDistributions(0, 10)).to.be.deep.equal([]); + + await mor20FactoryL1.deployMor20OnL1(params); + + expect(await mor20FactoryL1.listDistributions(0, 10)).to.be.lengthOf(1); + + expect(await mor20FactoryL1.listDistributions(1, 10)).to.be.lengthOf(0); + }); + }); +}); diff --git a/test/L1/Distribution.test.ts b/test/L1/Distribution.test.ts index 8df6c9c..ded05e6 100644 --- a/test/L1/Distribution.test.ts +++ b/test/L1/Distribution.test.ts @@ -6,13 +6,15 @@ import { Distribution, DistributionV2, Distribution__factory, + ERC20MOR, GatewayRouterMock, IDistribution, IL1Sender, L1Sender, L2MessageReceiver, - L2TokenReceiverV2, + L2TokenReceiver, LZEndpointMock, + LayerZeroEndpointV2Mock, LinearDistributionIntervalDecrease, NonfungiblePositionManagerMock, StETHMock, @@ -39,16 +41,17 @@ describe('Distribution', () => { let lib: LinearDistributionIntervalDecrease; - let rewardToken: MOR; + let rewardToken: ERC20MOR; let depositToken: StETHMock; let wstETH: WStETHMock; let lZEndpointMockSender: LZEndpointMock; let lZEndpointMockReceiver: LZEndpointMock; + let lZEndpointMockOFT: LayerZeroEndpointV2Mock; let l1Sender: L1Sender; let l2MessageReceiver: L2MessageReceiver; - let l2TokenReceiver: L2TokenReceiverV2; + let l2TokenReceiver: L2TokenReceiver; before(async () => { await setTime(oneHour); @@ -67,25 +70,27 @@ describe('Distribution', () => { gatewayRouterMock, SwapRouterMock, NonfungiblePositionManagerMock, + LZEndpointMockOFT, ] = await Promise.all([ ethers.getContractFactory('LinearDistributionIntervalDecrease'), ethers.getContractFactory('ERC1967Proxy'), - ethers.getContractFactory('MOR'), + ethers.getContractFactory('ERC20MOR'), ethers.getContractFactory('StETHMock'), ethers.getContractFactory('WStETHMock'), ethers.getContractFactory('L1Sender'), ethers.getContractFactory('LZEndpointMock'), ethers.getContractFactory('L2MessageReceiver'), - ethers.getContractFactory('L2TokenReceiverV2'), + ethers.getContractFactory('L2TokenReceiver'), ethers.getContractFactory('GatewayRouterMock'), ethers.getContractFactory('SwapRouterMock'), ethers.getContractFactory('NonfungiblePositionManagerMock'), + ethers.getContractFactory('LayerZeroEndpointV2Mock'), ]); let gatewayRouter: GatewayRouterMock; let swapRouter: SwapRouterMock; let nonfungiblePositionManager: NonfungiblePositionManagerMock; - let l2TokenReceiverImplementation: L2TokenReceiverV2; + let l2TokenReceiverImplementation: L2TokenReceiver; let l2MessageReceiverImplementation: L2MessageReceiver; let l1SenderImplementation: L1Sender; // START deploy contracts without deps @@ -100,6 +105,7 @@ describe('Distribution', () => { l2TokenReceiverImplementation, l2MessageReceiverImplementation, l1SenderImplementation, + lZEndpointMockOFT, ] = await Promise.all([ libFactory.deploy(), stETHMockFactory.deploy(), @@ -111,8 +117,11 @@ describe('Distribution', () => { L2TokenReceiver.deploy(), L2MessageReceiver.deploy(), l1SenderFactory.deploy(), + LZEndpointMockOFT.deploy(receiverChainId, OWNER), ]); + lZEndpointMockOFT = await LZEndpointMockOFT.deploy(receiverChainId, OWNER); + distributionFactory = await ethers.getContractFactory('Distribution', { libraries: { LinearDistributionIntervalDecrease: await lib.getAddress(), @@ -128,7 +137,7 @@ describe('Distribution', () => { await l2MessageReceiver.L2MessageReceiver__init(); const l2TokenReceiverProxy = await ERC1967ProxyFactory.deploy(l2TokenReceiverImplementation, '0x'); - l2TokenReceiver = L2TokenReceiver.attach(l2TokenReceiverProxy) as L2TokenReceiverV2; + l2TokenReceiver = L2TokenReceiver.attach(l2TokenReceiverProxy) as L2TokenReceiver; await l2TokenReceiver.L2TokenReceiver__init(swapRouter, nonfungiblePositionManager, { tokenIn: depositToken, tokenOut: depositToken, @@ -159,7 +168,7 @@ describe('Distribution', () => { await l1Sender.L1Sender__init(distribution, rewardTokenConfig, depositTokenConfig); // Deploy reward token - rewardToken = await MORFactory.deploy(wei(1000000000)); + rewardToken = await MORFactory.deploy(lZEndpointMockOFT, OWNER, l2MessageReceiver); await rewardToken.transferOwnership(l2MessageReceiver); await l2MessageReceiver.setParams(rewardToken, { @@ -184,80 +193,80 @@ describe('Distribution', () => { afterEach(reverter.revert); - describe('UUPS proxy functionality', () => { - describe('#constructor', () => { - it('should disable initialize function', async () => { - const reason = 'Initializable: contract is already initialized'; - - const distribution = await distributionFactory.deploy(); - - await expect(distribution.Distribution_init(depositToken, l1Sender, [])).to.be.revertedWith(reason); - }); - }); - - describe('#Distribution_init', () => { - it('should set correct data after creation', async () => { - const depositToken_ = await distribution.depositToken(); - expect(depositToken_).to.eq(await depositToken.getAddress()); - }); - it('should create pools with correct data', async () => { - const pool1 = getDefaultPool(); - const pool2 = { - ...pool1, - isPublic: false, - minimalStake: wei(0), - payoutStart: oneDay * 2, - decreaseInterval: oneDay * 2, - }; - - const distributionProxy = await ( - await ethers.getContractFactory('ERC1967Proxy') - ).deploy(await distributionFactory.deploy(), '0x'); - - const distribution = distributionFactory.attach(await distributionProxy.getAddress()) as Distribution; - - await distribution.Distribution_init(depositToken, l1Sender, [pool1, pool2]); - - const pool1Data: IDistribution.PoolStruct = await distribution.pools(0); - expect(_comparePoolStructs(pool1, pool1Data)).to.be.true; - - const pool2Data: IDistribution.PoolStruct = await distribution.pools(1); - expect(_comparePoolStructs(pool2, pool2Data)).to.be.true; - }); - it('should revert if try to call init function twice', async () => { - const reason = 'Initializable: contract is already initialized'; - - await expect(distribution.Distribution_init(depositToken, l1Sender, [])).to.be.rejectedWith(reason); - }); - }); - - describe('#_authorizeUpgrade', () => { - it('should correctly upgrade', async () => { - const distributionV2Factory = await ethers.getContractFactory('DistributionV2', { - libraries: { - LinearDistributionIntervalDecrease: await lib.getAddress(), - }, - }); - const distributionV2Implementation = await distributionV2Factory.deploy(); - - await distribution.upgradeTo(await distributionV2Implementation.getAddress()); - - const distributionV2 = distributionV2Factory.attach(await distribution.getAddress()) as DistributionV2; - - expect(await distributionV2.version()).to.eq(2); - }); - it('should revert if caller is not the owner', async () => { - await expect(distribution.connect(SECOND).upgradeTo(ZERO_ADDR)).to.be.revertedWith( - 'Ownable: caller is not the owner', - ); - }); - it('should revert if `isNotUpgradeable == true`', async () => { - await distribution.removeUpgradeability(); - - await expect(distribution.upgradeTo(ZERO_ADDR)).to.be.revertedWith("DS: upgrade isn't available"); - }); - }); - }); + // describe("UUPS proxy functionality", () => { + // describe("#constructor", () => { + // it("should disable initialize function", async () => { + // const reason = "Initializable: contract is already initialized"; + + // const distribution = await distributionFactory.deploy(); + + // await expect(distribution.Distribution_init(depositToken, l1Sender, [])).to.be.revertedWith(reason); + // }); + // }); + + // describe("#Distribution_init", () => { + // it("should set correct data after creation", async () => { + // const depositToken_ = await distribution.depositToken(); + // expect(depositToken_).to.eq(await depositToken.getAddress()); + // }); + // it("should create pools with correct data", async () => { + // const pool1 = getDefaultPool(); + // const pool2 = { + // ...pool1, + // isPublic: false, + // minimalStake: wei(0), + // payoutStart: oneDay * 2, + // decreaseInterval: oneDay * 2, + // }; + + // const distributionProxy = await ( + // await ethers.getContractFactory("ERC1967Proxy") + // ).deploy(await distributionFactory.deploy(), "0x"); + + // const distribution = distributionFactory.attach(await distributionProxy.getAddress()) as Distribution; + + // await distribution.Distribution_init(depositToken, l1Sender, [pool1, pool2]); + + // const pool1Data: IDistribution.PoolStruct = await distribution.pools(0); + // expect(_comparePoolStructs(pool1, pool1Data)).to.be.true; + + // const pool2Data: IDistribution.PoolStruct = await distribution.pools(1); + // expect(_comparePoolStructs(pool2, pool2Data)).to.be.true; + // }); + // it("should revert if try to call init function twice", async () => { + // const reason = "Initializable: contract is already initialized"; + + // await expect(distribution.Distribution_init(depositToken, l1Sender, [])).to.be.rejectedWith(reason); + // }); + // }); + + // describe("#_authorizeUpgrade", () => { + // it("should correctly upgrade", async () => { + // const distributionV2Factory = await ethers.getContractFactory("DistributionV2", { + // libraries: { + // LinearDistributionIntervalDecrease: await lib.getAddress(), + // }, + // }); + // const distributionV2Implementation = await distributionV2Factory.deploy(); + + // await distribution.upgradeTo(await distributionV2Implementation.getAddress()); + + // const distributionV2 = distributionV2Factory.attach(await distribution.getAddress()) as DistributionV2; + + // expect(await distributionV2.version()).to.eq(2); + // }); + // it("should revert if caller is not the owner", async () => { + // await expect(distribution.connect(SECOND).upgradeTo(ZERO_ADDR)).to.be.revertedWith( + // "Ownable: caller is not the owner", + // ); + // }); + // it("should revert if `isNotUpgradeable == true`", async () => { + // await distribution.removeUpgradeability(); + + // await expect(distribution.upgradeTo(ZERO_ADDR)).to.be.revertedWith("DS: upgrade isn't available"); + // }); + // }); + // }); describe('#createPool', () => { it('should create pool with correct data', async () => { @@ -1098,27 +1107,27 @@ describe('Distribution', () => { expect(userData.deposited).to.eq(wei(1)); expect(userData.pendingRewards).to.eq(0); }); - it('should not save reward to pending reward if cannot mint reward token', async () => { - const amountToMintMaximum = (await rewardToken.cap()) - (await rewardToken.totalSupply()); + // it("should not save reward to pending reward if cannot mint reward token", async () => { + // const amountToMintMaximum = (await rewardToken.cap()) - (await rewardToken.totalSupply()); - await _getRewardTokenFromPool(distribution, amountToMintMaximum - wei(1), OWNER); + // await _getRewardTokenFromPool(distribution, amountToMintMaximum - wei(1), OWNER); - await distribution.stake(poolId, wei(10)); + // await distribution.stake(poolId, wei(10)); - await setNextTime(oneDay + oneDay); + // await setNextTime(oneDay + oneDay); - let tx = await distribution.claim(poolId, OWNER, { value: wei(0.5) }); - await expect(tx).to.changeTokenBalance(rewardToken, OWNER, wei(100)); - let userData = await distribution.usersData(OWNER, poolId); - expect(userData.pendingRewards).to.equal(wei(0)); + // let tx = await distribution.claim(poolId, OWNER, { value: wei(0.5) }); + // await expect(tx).to.changeTokenBalance(rewardToken, OWNER, wei(100)); + // let userData = await distribution.usersData(OWNER, poolId); + // expect(userData.pendingRewards).to.equal(wei(0)); - await setNextTime(oneDay + oneDay * 2); + // await setNextTime(oneDay + oneDay * 2); - tx = await distribution.claim(poolId, OWNER, { value: wei(0.5) }); - await expect(tx).to.changeTokenBalance(rewardToken, OWNER, wei(98)); - userData = await distribution.usersData(OWNER, poolId); - expect(userData.pendingRewards).to.equal(wei(0)); - }); + // tx = await distribution.claim(poolId, OWNER, { value: wei(0.5) }); + // await expect(tx).to.changeTokenBalance(rewardToken, OWNER, wei(98)); + // userData = await distribution.usersData(OWNER, poolId); + // expect(userData.pendingRewards).to.equal(wei(0)); + // }); it("should revert if pool doesn't exist", async () => { await expect(distribution.connect(SECOND).claim(1, SECOND)).to.be.revertedWith("DS: pool doesn't exist"); }); diff --git a/test/L1/L1Sender.test.ts b/test/L1/L1Sender.test.ts index 9ee2132..78818ac 100644 --- a/test/L1/L1Sender.test.ts +++ b/test/L1/L1Sender.test.ts @@ -3,12 +3,14 @@ import { expect } from 'chai'; import { ethers } from 'hardhat'; import { + ERC20MOR, GatewayRouterMock, IL1Sender, L1Sender, L1SenderV2, L2MessageReceiver, LZEndpointMock, + LayerZeroEndpointV2Mock, StETHMock, WStETHMock, } from '@/generated-types/ethers'; @@ -30,13 +32,14 @@ describe('L1Sender', () => { let lZEndpointMockL1: LZEndpointMock; let lZEndpointMockL2: LZEndpointMock; + let lZEndpointMockOFT: LayerZeroEndpointV2Mock; let gatewayRouter: GatewayRouterMock; let l1Sender: L1Sender; let l2MessageReceiver: L2MessageReceiver; - let rewardToken: MOR; + let rewardToken: ERC20MOR; before(async () => { [OWNER, SECOND] = await ethers.getSigners(); @@ -49,24 +52,27 @@ describe('L1Sender', () => { StETHMock, WStETHMock, L2MessageReceiver, + LZEndpointMockOFT, ] = await Promise.all([ ethers.getContractFactory('ERC1967Proxy'), ethers.getContractFactory('LZEndpointMock'), - ethers.getContractFactory('MOR'), + ethers.getContractFactory('ERC20MOR'), ethers.getContractFactory('L1Sender'), ethers.getContractFactory('GatewayRouterMock'), ethers.getContractFactory('StETHMock'), ethers.getContractFactory('WStETHMock'), ethers.getContractFactory('L2MessageReceiver'), + ethers.getContractFactory('LayerZeroEndpointV2Mock'), ]); + lZEndpointMockOFT = await LZEndpointMockOFT.deploy(receiverChainId, OWNER); + let l1SenderImplementation: L1Sender; let l2MessageReceiverImplementation: L2MessageReceiver; [ lZEndpointMockL1, lZEndpointMockL2, - rewardToken, l1SenderImplementation, unwrappedToken, l2MessageReceiverImplementation, @@ -74,7 +80,6 @@ describe('L1Sender', () => { ] = await Promise.all([ LZEndpointMock.deploy(senderChainId), LZEndpointMock.deploy(receiverChainId), - Mor.deploy(wei(100)), L1Sender.deploy(), StETHMock.deploy(), L2MessageReceiver.deploy(), @@ -84,7 +89,8 @@ describe('L1Sender', () => { const l2MessageReceiverProxy = await ERC1967ProxyFactory.deploy(l2MessageReceiverImplementation, '0x'); l2MessageReceiver = L2MessageReceiver.attach(l2MessageReceiverProxy) as L2MessageReceiver; - await l2MessageReceiver.L2MessageReceiver__init(); + + rewardToken = await Mor.deploy('MOR', 'MOR', lZEndpointMockOFT, OWNER, l2MessageReceiver); const rewardTokenConfig: IL1Sender.RewardTokenConfigStruct = { gateway: lZEndpointMockL1, @@ -103,7 +109,7 @@ describe('L1Sender', () => { l1Sender = L1Sender.attach(l1SenderProxy) as L1Sender; await l1Sender.L1Sender__init(OWNER, rewardTokenConfig, depositTokenConfig); - await l2MessageReceiver.setParams(rewardToken, { + await l2MessageReceiver.L2MessageReceiver__init(rewardToken, { gateway: lZEndpointMockL2, sender: l1Sender, senderChainId: senderChainId, @@ -120,81 +126,81 @@ describe('L1Sender', () => { await reverter.revert(); }); - describe('UUPS proxy functionality', () => { - let rewardTokenConfig: IL1Sender.RewardTokenConfigStruct; - let depositTokenConfig: IL1Sender.DepositTokenConfigStruct; - - before(async () => { - rewardTokenConfig = { - gateway: lZEndpointMockL1, - receiver: l2MessageReceiver, - receiverChainId: receiverChainId, - zroPaymentAddress: ZERO_ADDR, - adapterParams: '0x', - }; - depositTokenConfig = { - token: depositToken, - gateway: gatewayRouter, - receiver: SECOND, - }; - }); - - describe('#constructor', () => { - it('should disable initialize function', async () => { - const reason = 'Initializable: contract is already initialized'; - - const l1Sender = await (await ethers.getContractFactory('L1Sender')).deploy(); - - await expect(l1Sender.L1Sender__init(OWNER, rewardTokenConfig, depositTokenConfig)).to.be.rejectedWith(reason); - }); - }); - - describe('#L1Sender__init', () => { - it('should revert if try to call init function twice', async () => { - const reason = 'Initializable: contract is already initialized'; - - await expect(l1Sender.L1Sender__init(OWNER, rewardTokenConfig, depositTokenConfig)).to.be.rejectedWith(reason); - }); - it('should setup config', async () => { - expect(await l1Sender.distribution()).to.be.equal(OWNER.address); - - expect(await l1Sender.rewardTokenConfig()).to.be.deep.equal([ - await lZEndpointMockL1.getAddress(), - await l2MessageReceiver.getAddress(), - receiverChainId, - ZERO_ADDR, - '0x', - ]); - - expect(await l1Sender.depositTokenConfig()).to.be.deep.equal([ - await depositToken.getAddress(), - await gatewayRouter.getAddress(), - SECOND.address, - ]); - - expect(await unwrappedToken.allowance(l1Sender, depositToken)).to.be.equal(ethers.MaxUint256); - expect(await depositToken.allowance(l1Sender, gatewayRouter)).to.be.equal(ethers.MaxUint256); - }); - }); - - describe('#_authorizeUpgrade', () => { - it('should correctly upgrade', async () => { - const l1SenderV2Factory = await ethers.getContractFactory('L1SenderV2'); - const l1SenderV2Implementation = await l1SenderV2Factory.deploy(); - - await l1Sender.upgradeTo(l1SenderV2Implementation); - - const l1SenderV2 = l1SenderV2Factory.attach(l1Sender) as L1SenderV2; - - expect(await l1SenderV2.version()).to.eq(2); - }); - it('should revert if caller is not the owner', async () => { - await expect(l1Sender.connect(SECOND).upgradeTo(ZERO_ADDR)).to.be.revertedWith( - 'Ownable: caller is not the owner', - ); - }); - }); - }); + // describe("UUPS proxy functionality", () => { + // let rewardTokenConfig: IL1Sender.RewardTokenConfigStruct; + // let depositTokenConfig: IL1Sender.DepositTokenConfigStruct; + + // before(async () => { + // rewardTokenConfig = { + // gateway: lZEndpointMockL1, + // receiver: l2MessageReceiver, + // receiverChainId: receiverChainId, + // zroPaymentAddress: ZERO_ADDR, + // adapterParams: "0x", + // }; + // depositTokenConfig = { + // token: depositToken, + // gateway: gatewayRouter, + // receiver: SECOND, + // }; + // }); + + // describe("#constructor", () => { + // it("should disable initialize function", async () => { + // const reason = "Initializable: contract is already initialized"; + + // const l1Sender = await (await ethers.getContractFactory("L1Sender")).deploy(); + + // await expect(l1Sender.L1Sender__init(OWNER, rewardTokenConfig, depositTokenConfig)).to.be.rejectedWith(reason); + // }); + // }); + + // describe("#L1Sender__init", () => { + // it("should revert if try to call init function twice", async () => { + // const reason = "Initializable: contract is already initialized"; + + // await expect(l1Sender.L1Sender__init(OWNER, rewardTokenConfig, depositTokenConfig)).to.be.rejectedWith(reason); + // }); + // it("should setup config", async () => { + // expect(await l1Sender.distribution()).to.be.equal(OWNER.address); + + // expect(await l1Sender.rewardTokenConfig()).to.be.deep.equal([ + // await lZEndpointMockL1.getAddress(), + // await l2MessageReceiver.getAddress(), + // receiverChainId, + // ZERO_ADDR, + // "0x", + // ]); + + // expect(await l1Sender.depositTokenConfig()).to.be.deep.equal([ + // await depositToken.getAddress(), + // await gatewayRouter.getAddress(), + // SECOND.address, + // ]); + + // expect(await unwrappedToken.allowance(l1Sender, depositToken)).to.be.equal(ethers.MaxUint256); + // expect(await depositToken.allowance(l1Sender, gatewayRouter)).to.be.equal(ethers.MaxUint256); + // }); + // }); + + // describe("#_authorizeUpgrade", () => { + // it("should correctly upgrade", async () => { + // const l1SenderV2Factory = await ethers.getContractFactory("L1SenderV2"); + // const l1SenderV2Implementation = await l1SenderV2Factory.deploy(); + + // await l1Sender.upgradeTo(l1SenderV2Implementation); + + // const l1SenderV2 = l1SenderV2Factory.attach(l1Sender) as L1SenderV2; + + // expect(await l1SenderV2.version()).to.eq(2); + // }); + // it("should revert if caller is not the owner", async () => { + // await expect(l1Sender.connect(SECOND).upgradeTo(ZERO_ADDR)).to.be.revertedWith( + // "Ownable: caller is not the owner", + // ); + // }); + // }); + // }); describe('supportsInterface', () => { it('should support IL1Sender', async () => { diff --git a/test/L1/Mor20FactoryL1.test.ts b/test/L1/Mor20FactoryL1.test.ts new file mode 100644 index 0000000..16f9a18 --- /dev/null +++ b/test/L1/Mor20FactoryL1.test.ts @@ -0,0 +1,188 @@ +import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { Reverter } from '../helpers/reverter'; + +import { + CorePropertiesL1, + Distribution, + GatewayRouterMock, + L1Sender, + LinearDistributionIntervalDecrease, + Mor20FactoryL1, + StETHMock, + WStETHMock, +} from '@/generated-types/ethers'; +import { ETHER_ADDR, ZERO_ADDR } from '@/scripts/utils/constants'; + +enum PoolTypes { + DISTRIBUTION, + L1_SENDER, +} + +describe.only('Mor20FactoryL1', () => { + const reverter = new Reverter(); + + let OWNER: SignerWithAddress; + let SECOND: SignerWithAddress; + + let mor20FactoryL1: Mor20FactoryL1; + + let l1SenderImplementation: L1Sender; + let distributionImplementation: Distribution; + let coreProperties: CorePropertiesL1; + + let stEthMock: StETHMock; + let wstEthMock: WStETHMock; + let gatewayRouterMock: GatewayRouterMock; + let poolTypes: PoolTypes[]; + let poolImplementations: string[]; + let lib: LinearDistributionIntervalDecrease; + + before(async () => { + [OWNER, SECOND] = await ethers.getSigners(); + + const [ + libFactory, + l1SenderFactory, + mor20FactoryL1Factory, + stEthMockFactory, + wstEthMockFactory, + gatewayRouterMockFactory, + corePropertiesFactory, + ] = await Promise.all([ + ethers.getContractFactory('LinearDistributionIntervalDecrease'), + ethers.getContractFactory('L1Sender'), + ethers.getContractFactory('Mor20FactoryL1'), + ethers.getContractFactory('StETHMock'), + ethers.getContractFactory('WStETHMock'), + ethers.getContractFactory('GatewayRouterMock'), + ethers.getContractFactory('CorePropertiesL1'), + ]); + + [lib, l1SenderImplementation, stEthMock, gatewayRouterMock] = await Promise.all([ + libFactory.deploy(), + l1SenderFactory.deploy(), + stEthMockFactory.deploy(), + gatewayRouterMockFactory.deploy(), + ]); + wstEthMock = await wstEthMockFactory.deploy(stEthMock); + coreProperties = await corePropertiesFactory.deploy(gatewayRouterMock, SECOND, ZERO_ADDR, 1); + + const distributionFactory = await ethers.getContractFactory('Distribution', { + libraries: { + LinearDistributionIntervalDecrease: lib, + }, + }); + distributionImplementation = await distributionFactory.deploy(); + + mor20FactoryL1 = await mor20FactoryL1Factory.deploy(coreProperties); + + poolTypes = [PoolTypes.DISTRIBUTION, PoolTypes.L1_SENDER]; + poolImplementations = [await distributionImplementation.getAddress(), await l1SenderImplementation.getAddress()]; + + await reverter.snapshot(); + }); + + afterEach(reverter.revert); + + function getMor20DeployParams() { + const mor20DeployParams: Mor20FactoryL1.Mor20DeployParamsStruct = { + name: 'Mor20', + depositToken: stEthMock, + poolsInfo: [], + messageReceiver: ETHER_ADDR, + zroPaymentAddress: ZERO_ADDR, + l2EndpointId: 0, + adapterParams: '0x', + wrappedToken: wstEthMock, + tokenReceiver: ETHER_ADDR, + }; + + return mor20DeployParams; + } + + describe('#deployMor20OnL1', () => { + it('should deploy and initialize a Mor20 on L1', async () => { + await mor20FactoryL1.setNewImplementations(poolTypes, poolImplementations); + + const deployParams = getMor20DeployParams(); + + const predictedMor20Address = await mor20FactoryL1.predictMor20Address(OWNER, deployParams.name); + + const tx = await mor20FactoryL1.deployMor20OnL1(deployParams); + + await expect(tx) + .to.emit(mor20FactoryL1, 'Mor20Deployed') + .withArgs(deployParams.name, ...predictedMor20Address); + + const distribution = await ethers.getContractAt('Distribution', predictedMor20Address[0]); + const l1Sender = await ethers.getContractAt('L1Sender', predictedMor20Address[1]); + + expect(await distribution.depositToken()).to.equal(deployParams.depositToken); + expect(await distribution.l1Sender()).to.equal(l1Sender); + + expect(await l1Sender.unwrappedDepositToken()).to.equal(deployParams.depositToken); + expect(await l1Sender.distribution()).to.equal(distribution); + }); + + it('should revert if name is an empty string', async () => { + const deployParams = getMor20DeployParams(); + deployParams.name = ''; + + await expect(mor20FactoryL1.deployMor20OnL1(deployParams)).to.be.revertedWith( + 'BaseFactory: pool name cannot be empty', + ); + }); + + it('should revert if Mor20 with the same name already exists', async () => { + await mor20FactoryL1.setNewImplementations(poolTypes, poolImplementations); + + const deployParams = getMor20DeployParams(); + + await mor20FactoryL1.deployMor20OnL1(deployParams); + + await expect(mor20FactoryL1.deployMor20OnL1(deployParams)).to.be.revertedWith( + 'BaseFactory: pool name is already taken', + ); + }); + + it('should revert if called by a non-owner', async () => { + const deployParams = getMor20DeployParams(); + + await expect(mor20FactoryL1.connect(SECOND).deployMor20OnL1(deployParams)).to.be.revertedWith( + 'Ownable: caller is not the owner', + ); + }); + }); + + describe('#setNewImplementations', () => { + it('should set new implementations', async () => { + await mor20FactoryL1.setNewImplementations(poolTypes, poolImplementations); + + const deployParams = getMor20DeployParams(); + const distributionAddress = (await mor20FactoryL1.predictMor20Address(OWNER, deployParams.name)).distribution; + await mor20FactoryL1.deployMor20OnL1(deployParams); + + const distributionV2Factory = await ethers.getContractFactory('DistributionV2', { + libraries: { + LinearDistributionIntervalDecrease: lib, + }, + }); + const distributionV2Implementation = await distributionV2Factory.deploy(); + + await mor20FactoryL1.setNewImplementations(poolTypes, [distributionV2Implementation, l1SenderImplementation]); + + const distribution = await ethers.getContractAt('DistributionV2', distributionAddress); + + expect(await distribution.version()).to.equal(2); + }); + + it('should revert if called by a non-owner', async () => { + await expect( + mor20FactoryL1.connect(SECOND).setNewImplementations(poolTypes, poolImplementations), + ).to.be.revertedWith('Ownable: caller is not the owner'); + }); + }); +}); diff --git a/test/L2/L2MessageReceiver.test.ts b/test/L2/L2MessageReceiver.test.ts index 9ff7245..1bdcad5 100644 --- a/test/L2/L2MessageReceiver.test.ts +++ b/test/L2/L2MessageReceiver.test.ts @@ -2,7 +2,7 @@ import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; import { expect } from 'chai'; import { ethers } from 'hardhat'; -import { L2MessageReceiver, L2MessageReceiverV2, LayerZeroEndpointV2Mock, MOR, MOROFT } from '@/generated-types/ethers'; +import { ERC20MOR, L2MessageReceiver, L2MessageReceiverV2, LayerZeroEndpointV2Mock } from '@/generated-types/ethers'; import { ZERO_ADDR, ZERO_BYTES32 } from '@/scripts/utils/constants'; import { wei } from '@/scripts/utils/utils'; import { Reverter } from '@/test/helpers/reverter'; @@ -14,42 +14,33 @@ describe('L2MessageReceiver', () => { let SECOND: SignerWithAddress; let THIRD: SignerWithAddress; - // MOR let l2MessageReceiver: L2MessageReceiver; - let mor: MOR; - // MOROFT - let moroft: MOROFT; + let mor: ERC20MOR; let lZEndpointMock: LayerZeroEndpointV2Mock; before(async () => { [OWNER, SECOND, THIRD] = await ethers.getSigners(); - const [ERC1967ProxyFactory, L2MessageReceiver, MOR, MOROFT, LayerZeroEndpointV2Mock] = await Promise.all([ + const [ERC1967ProxyFactory, L2MessageReceiver, MOR, LayerZeroEndpointV2Mock] = await Promise.all([ ethers.getContractFactory('ERC1967Proxy'), ethers.getContractFactory('L2MessageReceiver'), - ethers.getContractFactory('MOR'), - ethers.getContractFactory('MOROFT'), + ethers.getContractFactory('ERC20MOR'), ethers.getContractFactory('LayerZeroEndpointV2Mock'), ]); - mor = await MOR.deploy(wei(100)); - const l2MessageReceiverImplementation = await L2MessageReceiver.deploy(); const l2MessageReceiverProxy = await ERC1967ProxyFactory.deploy(l2MessageReceiverImplementation, '0x'); l2MessageReceiver = L2MessageReceiver.attach(l2MessageReceiverProxy) as L2MessageReceiver; - await l2MessageReceiver.L2MessageReceiver__init(); - await l2MessageReceiver.setParams(mor, { + // Setup ERC20MOR token + lZEndpointMock = await LayerZeroEndpointV2Mock.deploy(1, SECOND); + mor = await MOR.deploy('MOR', 'MOR', lZEndpointMock, OWNER, l2MessageReceiver); + + await l2MessageReceiver.L2MessageReceiver__init(mor, { gateway: THIRD, sender: OWNER, senderChainId: 2, }); - await mor.transferOwnership(l2MessageReceiver); - - // Setup MOROFT token - lZEndpointMock = await LayerZeroEndpointV2Mock.deploy(1, SECOND.address); - moroft = await MOROFT.deploy(await lZEndpointMock.getAddress(), SECOND.address, l2MessageReceiver); - await reverter.snapshot(); }); @@ -57,65 +48,43 @@ describe('L2MessageReceiver', () => { await reverter.revert(); }); - describe('UUPS proxy functionality', () => { - describe('#constructor', () => { - it('should disable initialize function', async () => { - const reason = 'Initializable: contract is already initialized'; + // describe("UUPS proxy functionality", () => { + // describe("#constructor", () => { + // it("should disable initialize function", async () => { + // const reason = "Initializable: contract is already initialized"; - const l2MessageReceiver = await (await ethers.getContractFactory('L2MessageReceiver')).deploy(); + // const l2MessageReceiver = await (await ethers.getContractFactory("L2MessageReceiver")).deploy(); - await expect(l2MessageReceiver.L2MessageReceiver__init()).to.be.rejectedWith(reason); - }); - }); + // await expect(l2MessageReceiver.L2MessageReceiver__init()).to.be.rejectedWith(reason); + // }); + // }); - describe('#L2MessageReceiver__init', () => { - it('should revert if try to call init function twice', async () => { - const reason = 'Initializable: contract is already initialized'; + // describe("#L2MessageReceiver__init", () => { + // it("should revert if try to call init function twice", async () => { + // const reason = "Initializable: contract is already initialized"; - await expect(l2MessageReceiver.L2MessageReceiver__init()).to.be.rejectedWith(reason); - }); - }); - - describe('#_authorizeUpgrade', () => { - it('should correctly upgrade', async () => { - const l2MessageReceiverV2Factory = await ethers.getContractFactory('L2MessageReceiverV2'); - const l2MessageReceiverV2Implementation = await l2MessageReceiverV2Factory.deploy(); + // await expect(l2MessageReceiver.L2MessageReceiver__init()).to.be.rejectedWith(reason); + // }); + // }); - await l2MessageReceiver.upgradeTo(l2MessageReceiverV2Implementation); + // describe("#_authorizeUpgrade", () => { + // it("should correctly upgrade", async () => { + // const l2MessageReceiverV2Factory = await ethers.getContractFactory("L2MessageReceiverV2"); + // const l2MessageReceiverV2Implementation = await l2MessageReceiverV2Factory.deploy(); - const l2MessageReceiverV2 = l2MessageReceiverV2Factory.attach(l2MessageReceiver) as L2MessageReceiverV2; - - expect(await l2MessageReceiverV2.version()).to.eq(2); - }); - it('should revert if caller is not the owner', async () => { - await expect(l2MessageReceiver.connect(SECOND).upgradeTo(ZERO_ADDR)).to.be.revertedWith( - 'Ownable: caller is not the owner', - ); - }); - }); - }); + // await l2MessageReceiver.upgradeTo(l2MessageReceiverV2Implementation); - describe('#setParams', () => { - it('should set params', async () => { - await l2MessageReceiver.setParams(mor, { - gateway: ZERO_ADDR, - sender: SECOND, - senderChainId: 1, - }); + // const l2MessageReceiverV2 = l2MessageReceiverV2Factory.attach(l2MessageReceiver) as L2MessageReceiverV2; - expect(await l2MessageReceiver.rewardToken()).to.be.equal(await mor.getAddress()); - expect(await l2MessageReceiver.config()).to.be.deep.equal([ZERO_ADDR, SECOND.address, 1n]); - }); - it('should revert if not owner', async () => { - await expect( - l2MessageReceiver.connect(SECOND).setParams(ZERO_ADDR, { - gateway: ZERO_ADDR, - sender: OWNER, - senderChainId: 0, - }), - ).to.be.revertedWith('Ownable: caller is not the owner'); - }); - }); + // expect(await l2MessageReceiverV2.version()).to.eq(2); + // }); + // it("should revert if caller is not the owner", async () => { + // await expect(l2MessageReceiver.connect(SECOND).upgradeTo(ZERO_ADDR)).to.be.revertedWith( + // "Ownable: caller is not the owner", + // ); + // }); + // }); + // }); describe('#lzReceive', () => { it('should mint tokens', async () => { @@ -140,11 +109,9 @@ describe('L2MessageReceiver', () => { await expect(tx).to.changeTokenBalance(mor, SECOND, wei(2)); payload = ethers.AbiCoder.defaultAbiCoder().encode(['address', 'uint256'], [SECOND.address, wei(5)]); tx = await l2MessageReceiver.connect(THIRD).lzReceive(2, address, 7, payload); - await expect(tx).to.changeTokenBalance(mor, SECOND, 0); - expect(await l2MessageReceiver.failedMessages(2, address, 7)).to.eq(ethers.keccak256(payload)); }); - it('should mint tokens, MOROFT', async () => { - await l2MessageReceiver.setParams(moroft, { + it('should mint tokens, ERC20MOR', async () => { + await l2MessageReceiver.setParams(mor, { gateway: THIRD, sender: OWNER, senderChainId: 2, @@ -156,52 +123,51 @@ describe('L2MessageReceiver', () => { ); let payload = ethers.AbiCoder.defaultAbiCoder().encode(['address', 'uint256'], [SECOND.address, wei(95)]); let tx = await l2MessageReceiver.connect(THIRD).lzReceive(2, address, 5, payload); - await expect(tx).to.changeTokenBalance(moroft, SECOND, wei(95)); + await expect(tx).to.changeTokenBalance(mor, SECOND, wei(95)); payload = ethers.AbiCoder.defaultAbiCoder().encode(['address', 'uint256'], [SECOND.address, wei(2)]); tx = await l2MessageReceiver.connect(THIRD).lzReceive(2, address, 6, payload); - await expect(tx).to.changeTokenBalance(moroft, SECOND, wei(2)); + await expect(tx).to.changeTokenBalance(mor, SECOND, wei(2)); payload = ethers.AbiCoder.defaultAbiCoder().encode(['address', 'uint256'], [SECOND.address, wei(5)]); }); it('should revert if provided wrong lzEndpoint', async () => { await expect(l2MessageReceiver.lzReceive(0, '0x', 1, '0x')).to.be.revertedWith('L2MR: invalid gateway'); }); - it('should fail if provided wrong mint amount', async () => { - const address = ethers.solidityPacked( - ['address', 'address'], - [OWNER.address, await l2MessageReceiver.getAddress()], - ); - const payload = ethers.AbiCoder.defaultAbiCoder().encode(['address', 'uint256'], [SECOND.address, wei(100)]); - - let tx = await l2MessageReceiver.connect(THIRD).lzReceive(2, address, 5, payload); - await expect(tx).to.changeTokenBalance(mor, SECOND, wei(100)); - - expect(await l2MessageReceiver.failedMessages(2, address, 5)).to.eq(ZERO_BYTES32); - await l2MessageReceiver.connect(THIRD).lzReceive(2, address, 5, payload); - expect(await l2MessageReceiver.failedMessages(2, address, 5)).to.eq(ethers.keccak256(payload)); - - await mor.connect(SECOND).burn(wei(100)); - - tx = await l2MessageReceiver.connect(THIRD).lzReceive(2, address, 6, payload); - expect(await l2MessageReceiver.failedMessages(2, address, 6)).to.eq(ZERO_BYTES32); - await expect(tx).to.changeTokenBalance(mor, SECOND, wei(100)); - }); - it('should fail if provided wrong mint amount', async () => { - const address = ethers.solidityPacked( - ['address', 'address'], - [OWNER.address, await l2MessageReceiver.getAddress()], - ); - const payload = ethers.AbiCoder.defaultAbiCoder().encode(['address', 'uint256'], [SECOND.address, wei(100)]); - - await l2MessageReceiver.connect(THIRD).lzReceive(2, address, 5, payload); - - expect(await l2MessageReceiver.failedMessages(2, address, 5)).to.eq(ZERO_BYTES32); - await l2MessageReceiver.connect(THIRD).lzReceive(2, address, 5, payload); - expect(await l2MessageReceiver.failedMessages(2, address, 5)).to.eq(ethers.keccak256(payload)); - - await mor.connect(SECOND).burn(wei(100)); - - await l2MessageReceiver.connect(THIRD).lzReceive(2, address, 5, payload); - }); + // it("should fail if provided wrong mint amount", async () => { + // const address = ethers.solidityPacked( + // ["address", "address"], + // [OWNER.address, await l2MessageReceiver.getAddress()], + // ); + // const payload = ethers.AbiCoder.defaultAbiCoder().encode(["address", "uint256"], [SECOND.address, wei(100)]); + + // let tx = await l2MessageReceiver.connect(THIRD).lzReceive(2, address, 5, payload); + // await expect(tx).to.changeTokenBalance(mor, SECOND, wei(100)); + + // expect(await l2MessageReceiver.failedMessages(2, address, 5)).to.eq(ZERO_BYTES32); + // await l2MessageReceiver.connect(THIRD).lzReceive(2, address, 5, payload); + // expect(await l2MessageReceiver.failedMessages(2, address, 5)).to.eq(ethers.keccak256(payload)); + + // await mor.connect(SECOND).burn(wei(100)); + + // tx = await l2MessageReceiver.connect(THIRD).lzReceive(2, address, 6, payload); + // expect(await l2MessageReceiver.failedMessages(2, address, 6)).to.eq(ZERO_BYTES32); + // await expect(tx).to.changeTokenBalance(mor, SECOND, wei(100)); + // }); + // it("should fail if provided wrong mint amount", async () => { + // const address = ethers.solidityPacked( + // ["address", "address"], + // [OWNER.address, await l2MessageReceiver.getAddress()], + // ); + // const payload = ethers.AbiCoder.defaultAbiCoder().encode(["address", "uint256"], [SECOND.address, wei(100)]); + + // await l2MessageReceiver.connect(THIRD).lzReceive(2, address, 5, payload); + + // expect(await l2MessageReceiver.failedMessages(2, address, 5)).to.eq(ZERO_BYTES32); + // await l2MessageReceiver.connect(THIRD).lzReceive(2, address, 5, payload); + + // await mor.connect(SECOND).burn(wei(100)); + + // await l2MessageReceiver.connect(THIRD).lzReceive(2, address, 5, payload); + // }); }); describe('#nonblockingLzReceive', () => { diff --git a/test/L2/L2TokenReceiver.test.ts b/test/L2/L2TokenReceiver.test.ts index d1bce70..96d5d19 100644 --- a/test/L2/L2TokenReceiver.test.ts +++ b/test/L2/L2TokenReceiver.test.ts @@ -6,15 +6,16 @@ import { getDefaultSwapParams } from '../helpers/distribution-helper'; import { Reverter } from '../helpers/reverter'; import { + ERC20MOR, IL2TokenReceiver, L2TokenReceiver, L2TokenReceiverV2, + LayerZeroEndpointV2Mock, NonfungiblePositionManagerMock, StETHMock, SwapRouterMock, } from '@/generated-types/ethers'; import { ZERO_ADDR } from '@/scripts/utils/constants'; -import { wei } from '@/scripts/utils/utils'; describe('L2TokenReceiver', () => { const reverter = new Reverter(); @@ -23,31 +24,43 @@ describe('L2TokenReceiver', () => { let OWNER: SignerWithAddress; let SECOND: SignerWithAddress; + let lZEndpointMockOFT: LayerZeroEndpointV2Mock; + let swapRouter: SwapRouterMock; let nonfungiblePositionManager: NonfungiblePositionManagerMock; let l2TokenReceiver: L2TokenReceiver; let inputToken: StETHMock; - let outputToken: MOR; + let outputToken: ERC20MOR; before(async () => { [OWNER, SECOND] = await ethers.getSigners(); - const [ERC1967ProxyFactory, L2TokenReceiver, StETHMock, Mor, SwapRouterMock, NonfungiblePositionManagerMock] = - await Promise.all([ - ethers.getContractFactory('ERC1967Proxy'), - ethers.getContractFactory('L2TokenReceiver'), - ethers.getContractFactory('StETHMock'), - ethers.getContractFactory('MOR'), - ethers.getContractFactory('SwapRouterMock'), - ethers.getContractFactory('NonfungiblePositionManagerMock'), - ]); + const [ + ERC1967ProxyFactory, + L2TokenReceiver, + StETHMock, + Mor, + SwapRouterMock, + NonfungiblePositionManagerMock, + LZEndpointMockOFT, + ] = await Promise.all([ + ethers.getContractFactory('ERC1967Proxy'), + ethers.getContractFactory('L2TokenReceiver'), + ethers.getContractFactory('StETHMock'), + ethers.getContractFactory('ERC20MOR'), + ethers.getContractFactory('SwapRouterMock'), + ethers.getContractFactory('NonfungiblePositionManagerMock'), + ethers.getContractFactory('LayerZeroEndpointV2Mock'), + ]); let l2TokenReceiverImplementation: L2TokenReceiver; + lZEndpointMockOFT = await LZEndpointMockOFT.deploy(1, OWNER); + [inputToken, outputToken, swapRouter, nonfungiblePositionManager, l2TokenReceiverImplementation] = await Promise.all([ StETHMock.deploy(), - Mor.deploy(wei(100)), + Mor.deploy('MOR', 'MOR', lZEndpointMockOFT, OWNER, OWNER), SwapRouterMock.deploy(), NonfungiblePositionManagerMock.deploy(), L2TokenReceiver.deploy(), @@ -55,12 +68,22 @@ describe('L2TokenReceiver', () => { const l2TokenReceiverProxy = await ERC1967ProxyFactory.deploy(l2TokenReceiverImplementation, '0x'); l2TokenReceiver = L2TokenReceiver.attach(l2TokenReceiverProxy) as L2TokenReceiver; - await l2TokenReceiver.L2TokenReceiver__init(swapRouter, nonfungiblePositionManager, { - tokenIn: inputToken, - tokenOut: outputToken, - fee: 500, - sqrtPriceLimitX96: 0, - }); + await l2TokenReceiver.L2TokenReceiver__init( + swapRouter, + nonfungiblePositionManager, + { + tokenIn: inputToken, + tokenOut: outputToken, + fee: 500, + sqrtPriceLimitX96: 0, + }, + { + tokenIn: inputToken, + tokenOut: outputToken, + fee: 500, + sqrtPriceLimitX96: 0, + }, + ); await reverter.snapshot(); }); @@ -69,76 +92,96 @@ describe('L2TokenReceiver', () => { await reverter.revert(); }); - describe('UUPS proxy functionality', () => { - it('should disable initialize function', async () => { - const reason = 'Initializable: contract is already initialized'; - - const l2TokenReceiver = await (await ethers.getContractFactory('L2TokenReceiver')).deploy(); - - await expect( - l2TokenReceiver.L2TokenReceiver__init(swapRouter, nonfungiblePositionManager, { - tokenIn: inputToken, - tokenOut: outputToken, - fee: 500, - sqrtPriceLimitX96: 0, - }), - ).to.be.rejectedWith(reason); - }); - - describe('#L2TokenReceiver__init', () => { - it('should revert if try to call init function twice', async () => { - const reason = 'Initializable: contract is already initialized'; - - await expect( - l2TokenReceiver.L2TokenReceiver__init(swapRouter, nonfungiblePositionManager, { - tokenIn: inputToken, - tokenOut: outputToken, - fee: 500, - sqrtPriceLimitX96: 0, - }), - ).to.be.rejectedWith(reason); - }); - it('should set router', async () => { - expect(await l2TokenReceiver.router()).to.equal(await swapRouter.getAddress()); - }); - it('should set params', async () => { - const defaultParams = getDefaultSwapParams(await inputToken.getAddress(), await outputToken.getAddress()); - const params = await l2TokenReceiver.params(); - - expect(params.tokenIn).to.equal(defaultParams.tokenIn); - expect(params.tokenOut).to.equal(defaultParams.tokenOut); - expect(params.fee).to.equal(defaultParams.fee); - expect(params.sqrtPriceLimitX96).to.equal(defaultParams.sqrtPriceLimitX96); - }); - it('should give allowance', async () => { - expect(await inputToken.allowance(l2TokenReceiver, swapRouter)).to.equal(ethers.MaxUint256); - expect(await inputToken.allowance(l2TokenReceiver, nonfungiblePositionManager)).to.equal(ethers.MaxUint256); - expect(await outputToken.allowance(l2TokenReceiver, nonfungiblePositionManager)).to.equal(ethers.MaxUint256); - }); - }); - - describe('#_authorizeUpgrade', () => { - it('should correctly upgrade', async () => { - const l2TokenReceiverV2Factory = await ethers.getContractFactory('L2TokenReceiverV2'); - const l2TokenReceiverV2Implementation = await l2TokenReceiverV2Factory.deploy(); - - await l2TokenReceiver.upgradeTo(l2TokenReceiverV2Implementation); - - const l2TokenReceiverV2 = l2TokenReceiverV2Factory.attach(l2TokenReceiver) as L2TokenReceiverV2; - - expect(await l2TokenReceiverV2.version()).to.eq(2); - }); - it('should revert if caller is not the owner', async () => { - await expect(l2TokenReceiver.connect(SECOND).upgradeTo(ZERO_ADDR)).to.be.revertedWith( - 'Ownable: caller is not the owner', - ); - }); - }); - }); + // describe("UUPS proxy functionality", () => { + // it("should disable initialize function", async () => { + // const reason = "Initializable: contract is already initialized"; + + // const l2TokenReceiver = await (await ethers.getContractFactory("L2TokenReceiver")).deploy(); + + // await expect( + // l2TokenReceiver.L2TokenReceiver__init( + // swapRouter, + // nonfungiblePositionManager, + // { + // tokenIn: inputToken, + // tokenOut: outputToken, + // fee: 500, + // sqrtPriceLimitX96: 0, + // }, + // { + // tokenIn: inputToken, + // tokenOut: outputToken, + // fee: 500, + // sqrtPriceLimitX96: 0, + // }, + // ), + // ).to.be.rejectedWith(reason); + // }); + + // describe("#L2TokenReceiver__init", () => { + // it("should revert if try to call init function twice", async () => { + // const reason = "Initializable: contract is already initialized"; + + // await expect( + // l2TokenReceiver.L2TokenReceiver__init( + // swapRouter, + // nonfungiblePositionManager, + // { + // tokenIn: inputToken, + // tokenOut: outputToken, + // fee: 500, + // sqrtPriceLimitX96: 0, + // }, + // { + // tokenIn: inputToken, + // tokenOut: outputToken, + // fee: 500, + // sqrtPriceLimitX96: 0, + // }, + // ), + // ).to.be.rejectedWith(reason); + // }); + // it("should set router", async () => { + // expect(await l2TokenReceiver.router()).to.equal(await swapRouter.getAddress()); + // }); + // it("should set params", async () => { + // const defaultParams = getDefaultSwapParams(await inputToken.getAddress(), await outputToken.getAddress()); + // const params = await l2TokenReceiver.secondSwapParams(); + + // expect(params.tokenIn).to.equal(defaultParams.tokenIn); + // expect(params.tokenOut).to.equal(defaultParams.tokenOut); + // expect(params.fee).to.equal(defaultParams.fee); + // expect(params.sqrtPriceLimitX96).to.equal(defaultParams.sqrtPriceLimitX96); + // }); + // it("should give allowance", async () => { + // expect(await inputToken.allowance(l2TokenReceiver, swapRouter)).to.equal(ethers.MaxUint256); + // expect(await inputToken.allowance(l2TokenReceiver, nonfungiblePositionManager)).to.equal(ethers.MaxUint256); + // expect(await outputToken.allowance(l2TokenReceiver, nonfungiblePositionManager)).to.equal(ethers.MaxUint256); + // }); + // }); + + // describe("#_authorizeUpgrade", () => { + // it("should correctly upgrade", async () => { + // const l2TokenReceiverV2Factory = await ethers.getContractFactory("L2TokenReceiverV2"); + // const l2TokenReceiverV2Implementation = await l2TokenReceiverV2Factory.deploy(); + + // await l2TokenReceiver.upgradeTo(l2TokenReceiverV2Implementation); + + // const l2TokenReceiverV2 = l2TokenReceiverV2Factory.attach(l2TokenReceiver) as L2TokenReceiverV2; + + // expect(await l2TokenReceiverV2.version()).to.eq(2); + // }); + // it("should revert if caller is not the owner", async () => { + // await expect(l2TokenReceiver.connect(SECOND).upgradeTo(ZERO_ADDR)).to.be.revertedWith( + // "Ownable: caller is not the owner", + // ); + // }); + // }); + // }); describe('supportsInterface', () => { it('should support IL2TokenReceiver', async () => { - expect(await l2TokenReceiver.supportsInterface('0x067ef141')).to.be.true; + expect(await l2TokenReceiver.supportsInterface('0x2f958df3')).to.be.true; }); it('should support IERC165', async () => { expect(await l2TokenReceiver.supportsInterface('0x01ffc9a7')).to.be.true; @@ -157,9 +200,9 @@ describe('L2TokenReceiver', () => { sqrtPriceLimitX96: 1, }; - await l2TokenReceiver.editParams(newParams); + await l2TokenReceiver.editParams(newParams, false); - const params = await l2TokenReceiver.params(); + const params = await l2TokenReceiver.secondSwapParams(); expect(params.tokenIn).to.equal(newParams.tokenIn); expect(params.tokenOut).to.equal(newParams.tokenOut); @@ -174,7 +217,7 @@ describe('L2TokenReceiver', () => { sqrtPriceLimitX96: 1, }; - await l2TokenReceiver.editParams(newParams); + await l2TokenReceiver.editParams(newParams, false); expect(await inputToken.allowance(l2TokenReceiver, swapRouter)).to.equal(0); expect(await inputToken.allowance(l2TokenReceiver, nonfungiblePositionManager)).to.equal(ethers.MaxUint256); @@ -183,24 +226,24 @@ describe('L2TokenReceiver', () => { }); it('should revert if caller is not owner', async () => { await expect( - l2TokenReceiver.connect(SECOND).editParams(getDefaultSwapParams(ZERO_ADDR, ZERO_ADDR)), + l2TokenReceiver.connect(SECOND).editParams(getDefaultSwapParams(ZERO_ADDR, ZERO_ADDR), false), ).to.be.revertedWith('Ownable: caller is not the owner'); }); it('should revert if tokenIn is zero address', async () => { await expect( - l2TokenReceiver.editParams(getDefaultSwapParams(ZERO_ADDR, await outputToken.getAddress())), + l2TokenReceiver.editParams(getDefaultSwapParams(ZERO_ADDR, await outputToken.getAddress()), false), ).to.be.revertedWith('L2TR: invalid tokenIn'); }); it('should revert if tokenOut is zero address', async () => { await expect( - l2TokenReceiver.editParams(getDefaultSwapParams(await inputToken.getAddress(), ZERO_ADDR)), + l2TokenReceiver.editParams(getDefaultSwapParams(await inputToken.getAddress(), ZERO_ADDR), false), ).to.be.revertedWith('L2TR: invalid tokenOut'); }); }); describe('#swap', () => { it('should return if caller is not the owner', async () => { - await expect(l2TokenReceiver.connect(SECOND).swap(1, 1, 1)).to.be.revertedWith( + await expect(l2TokenReceiver.connect(SECOND).swap(1, 1, 1, false)).to.be.revertedWith( 'Ownable: caller is not the owner', ); }); @@ -213,6 +256,29 @@ describe('L2TokenReceiver', () => { ); }); }); + + describe('#withdrawToken', () => { + it('should withdraw token', async () => { + await inputToken.mint(l2TokenReceiver, 1); + + const tx = await l2TokenReceiver.withdrawToken(OWNER, inputToken, 1); + + await expect(tx).to.changeTokenBalances(inputToken, [l2TokenReceiver, OWNER], [-1, 1]); + }); + it('should return if caller is not the owner', async () => { + await expect(l2TokenReceiver.connect(SECOND).withdrawToken(OWNER, inputToken, 1)).to.be.revertedWith( + 'Ownable: caller is not the owner', + ); + }); + }); + + describe('#withdrawTokenId', () => { + it('should return if caller is not the owner', async () => { + await expect(l2TokenReceiver.connect(SECOND).withdrawTokenId(OWNER, OWNER, 0)).to.be.revertedWith( + 'Ownable: caller is not the owner', + ); + }); + }); }); // npx hardhat test "test/L2TokenReceiver.test.ts" diff --git a/test/L2/L2TokenReceiverV2.test.ts b/test/L2/L2TokenReceiverV2.test.ts deleted file mode 100644 index 4a3b00b..0000000 --- a/test/L2/L2TokenReceiverV2.test.ts +++ /dev/null @@ -1,254 +0,0 @@ -import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; -import { expect } from 'chai'; -import { ethers } from 'hardhat'; - -import { getDefaultSwapParams } from '../helpers/distribution-helper'; -import { Reverter } from '../helpers/reverter'; - -import { - IL2TokenReceiverV2, - L2TokenReceiverV2, - NonfungiblePositionManagerMock, - StETHMock, - SwapRouterMock, -} from '@/generated-types/ethers'; -import { ZERO_ADDR } from '@/scripts/utils/constants'; -import { wei } from '@/scripts/utils/utils'; - -describe('L2TokenReceiverV2', () => { - const reverter = new Reverter(); - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - let OWNER: SignerWithAddress; - let SECOND: SignerWithAddress; - - let swapRouter: SwapRouterMock; - let nonfungiblePositionManager: NonfungiblePositionManagerMock; - - let l2TokenReceiver: L2TokenReceiverV2; - let inputToken: StETHMock; - let outputToken: MOR; - before(async () => { - [OWNER, SECOND] = await ethers.getSigners(); - - const [ERC1967ProxyFactory, L2TokenReceiver, StETHMock, Mor, SwapRouterMock, NonfungiblePositionManagerMock] = - await Promise.all([ - ethers.getContractFactory('ERC1967Proxy'), - ethers.getContractFactory('L2TokenReceiverV2'), - ethers.getContractFactory('StETHMock'), - ethers.getContractFactory('MOR'), - ethers.getContractFactory('SwapRouterMock'), - ethers.getContractFactory('NonfungiblePositionManagerMock'), - ]); - - let l2TokenReceiverImplementation: L2TokenReceiverV2; - - [inputToken, outputToken, swapRouter, nonfungiblePositionManager, l2TokenReceiverImplementation] = - await Promise.all([ - StETHMock.deploy(), - Mor.deploy(wei(100)), - SwapRouterMock.deploy(), - NonfungiblePositionManagerMock.deploy(), - L2TokenReceiver.deploy(), - ]); - - const l2TokenReceiverProxy = await ERC1967ProxyFactory.deploy(l2TokenReceiverImplementation, '0x'); - l2TokenReceiver = L2TokenReceiver.attach(l2TokenReceiverProxy) as L2TokenReceiverV2; - await l2TokenReceiver.L2TokenReceiver__init(swapRouter, nonfungiblePositionManager, { - tokenIn: inputToken, - tokenOut: outputToken, - fee: 500, - sqrtPriceLimitX96: 0, - }); - - await reverter.snapshot(); - }); - - beforeEach(async () => { - await reverter.revert(); - }); - - describe('UUPS proxy functionality', () => { - it('should disable initialize function', async () => { - const reason = 'Initializable: contract is already initialized'; - - const l2TokenReceiver = await (await ethers.getContractFactory('L2TokenReceiver')).deploy(); - - await expect( - l2TokenReceiver.L2TokenReceiver__init(swapRouter, nonfungiblePositionManager, { - tokenIn: inputToken, - tokenOut: outputToken, - fee: 500, - sqrtPriceLimitX96: 0, - }), - ).to.be.rejectedWith(reason); - }); - - describe('#L2TokenReceiver__init', () => { - it('should revert if try to call init function twice', async () => { - const reason = 'Initializable: contract is already initialized'; - - await expect( - l2TokenReceiver.L2TokenReceiver__init(swapRouter, nonfungiblePositionManager, { - tokenIn: inputToken, - tokenOut: outputToken, - fee: 500, - sqrtPriceLimitX96: 0, - }), - ).to.be.rejectedWith(reason); - }); - it('should set router', async () => { - expect(await l2TokenReceiver.router()).to.equal(await swapRouter.getAddress()); - }); - it('should set params', async () => { - const defaultParams = getDefaultSwapParams(await inputToken.getAddress(), await outputToken.getAddress()); - const params = await l2TokenReceiver.secondSwapParams(); - - expect(params.tokenIn).to.equal(defaultParams.tokenIn); - expect(params.tokenOut).to.equal(defaultParams.tokenOut); - expect(params.fee).to.equal(defaultParams.fee); - expect(params.sqrtPriceLimitX96).to.equal(defaultParams.sqrtPriceLimitX96); - }); - it('should give allowance', async () => { - expect(await inputToken.allowance(l2TokenReceiver, swapRouter)).to.equal(ethers.MaxUint256); - expect(await inputToken.allowance(l2TokenReceiver, nonfungiblePositionManager)).to.equal(ethers.MaxUint256); - expect(await outputToken.allowance(l2TokenReceiver, nonfungiblePositionManager)).to.equal(ethers.MaxUint256); - }); - }); - - describe('#_authorizeUpgrade', () => { - it('should correctly upgrade', async () => { - const l2TokenReceiverV2Factory = await ethers.getContractFactory('L2TokenReceiverV2'); - const l2TokenReceiverV2Implementation = await l2TokenReceiverV2Factory.deploy(); - - await l2TokenReceiver.upgradeTo(l2TokenReceiverV2Implementation); - - const l2TokenReceiverV2 = l2TokenReceiverV2Factory.attach(l2TokenReceiver) as L2TokenReceiverV2; - - expect(await l2TokenReceiverV2.version()).to.eq(2); - expect(await l2TokenReceiverV2.router()).to.eq(await swapRouter.getAddress()); - expect(await l2TokenReceiverV2.nonfungiblePositionManager()).to.eq( - await nonfungiblePositionManager.getAddress(), - ); - const secondSwapParams = await l2TokenReceiverV2.secondSwapParams(); - expect(secondSwapParams.tokenIn).to.eq(await inputToken.getAddress()); - expect(secondSwapParams.tokenOut).to.eq(await outputToken.getAddress()); - expect(secondSwapParams.fee).to.eq(500); - expect(secondSwapParams.sqrtPriceLimitX96).to.eq(0); - const firstSwapParams = await l2TokenReceiverV2.firstSwapParams(); - expect(firstSwapParams.tokenIn).to.eq(ZERO_ADDR); - expect(firstSwapParams.tokenOut).to.eq(ZERO_ADDR); - expect(firstSwapParams.fee).to.eq(0); - expect(firstSwapParams.sqrtPriceLimitX96).to.eq(0); - }); - it('should revert if caller is not the owner', async () => { - await expect(l2TokenReceiver.connect(SECOND).upgradeTo(ZERO_ADDR)).to.be.revertedWith( - 'Ownable: caller is not the owner', - ); - }); - }); - }); - - describe('supportsInterface', () => { - it('should support IL2TokenReceiver', async () => { - expect(await l2TokenReceiver.supportsInterface('0x2f958df3')).to.be.true; - }); - it('should support IERC165', async () => { - expect(await l2TokenReceiver.supportsInterface('0x01ffc9a7')).to.be.true; - }); - it('should support IERC721Receiver', async () => { - expect(await l2TokenReceiver.supportsInterface('0x150b7a02')).to.be.true; - }); - }); - - describe('#editParams', () => { - it('should edit params', async () => { - const newParams: IL2TokenReceiverV2.SwapParamsStruct = { - tokenIn: await outputToken.getAddress(), - tokenOut: await inputToken.getAddress(), - fee: 1, - sqrtPriceLimitX96: 1, - }; - - await l2TokenReceiver.editParams(newParams, false); - - const params = await l2TokenReceiver.secondSwapParams(); - - expect(params.tokenIn).to.equal(newParams.tokenIn); - expect(params.tokenOut).to.equal(newParams.tokenOut); - expect(params.fee).to.equal(newParams.fee); - expect(params.sqrtPriceLimitX96).to.equal(newParams.sqrtPriceLimitX96); - }); - it('should set new allowance', async () => { - const newParams: IL2TokenReceiverV2.SwapParamsStruct = { - tokenIn: await outputToken.getAddress(), - tokenOut: await inputToken.getAddress(), - fee: 1, - sqrtPriceLimitX96: 1, - }; - - await l2TokenReceiver.editParams(newParams, false); - - expect(await inputToken.allowance(l2TokenReceiver, swapRouter)).to.equal(0); - expect(await inputToken.allowance(l2TokenReceiver, nonfungiblePositionManager)).to.equal(ethers.MaxUint256); - expect(await outputToken.allowance(l2TokenReceiver, swapRouter)).to.equal(ethers.MaxUint256); - expect(await outputToken.allowance(l2TokenReceiver, nonfungiblePositionManager)).to.equal(ethers.MaxUint256); - }); - it('should revert if caller is not owner', async () => { - await expect( - l2TokenReceiver.connect(SECOND).editParams(getDefaultSwapParams(ZERO_ADDR, ZERO_ADDR), false), - ).to.be.revertedWith('Ownable: caller is not the owner'); - }); - it('should revert if tokenIn is zero address', async () => { - await expect( - l2TokenReceiver.editParams(getDefaultSwapParams(ZERO_ADDR, await outputToken.getAddress()), false), - ).to.be.revertedWith('L2TR: invalid tokenIn'); - }); - it('should revert if tokenOut is zero address', async () => { - await expect( - l2TokenReceiver.editParams(getDefaultSwapParams(await inputToken.getAddress(), ZERO_ADDR), false), - ).to.be.revertedWith('L2TR: invalid tokenOut'); - }); - }); - - describe('#swap', () => { - it('should return if caller is not the owner', async () => { - await expect(l2TokenReceiver.connect(SECOND).swap(1, 1, 1, false)).to.be.revertedWith( - 'Ownable: caller is not the owner', - ); - }); - }); - - describe('#increaseLiquidityCurrentRange', () => { - it('should return if caller is not the owner', async () => { - await expect(l2TokenReceiver.connect(SECOND).increaseLiquidityCurrentRange(1, 1, 1, 0, 0)).to.be.revertedWith( - 'Ownable: caller is not the owner', - ); - }); - }); - - describe('#withdrawToken', () => { - it('should withdraw token', async () => { - await inputToken.mint(l2TokenReceiver, 1); - - const tx = await l2TokenReceiver.withdrawToken(OWNER, inputToken, 1); - - await expect(tx).to.changeTokenBalances(inputToken, [l2TokenReceiver, OWNER], [-1, 1]); - }); - it('should return if caller is not the owner', async () => { - await expect(l2TokenReceiver.connect(SECOND).withdrawToken(OWNER, inputToken, 1)).to.be.revertedWith( - 'Ownable: caller is not the owner', - ); - }); - }); - - describe('#withdrawTokenId', () => { - it('should return if caller is not the owner', async () => { - await expect(l2TokenReceiver.connect(SECOND).withdrawTokenId(OWNER, OWNER, 0)).to.be.revertedWith( - 'Ownable: caller is not the owner', - ); - }); - }); -}); - -// npx hardhat test "test/L2TokenReceiverV2.test.ts" From e2f5406aa7c9ef4093322fea43c9fb38ea7dbd42 Mon Sep 17 00:00:00 2001 From: Ruslan Kasheparov Date: Fri, 5 Apr 2024 07:57:41 +0200 Subject: [PATCH 02/17] Added BaseFactory --- contracts/BaseFactory.sol | 111 +++++++++++++++++++++++++ contracts/L1/BaseFactoryL1.sol | 131 ++++++------------------------ contracts/L1/Mor20FactoryL1.sol | 59 +++++++------- contracts/L2/BaseFactoryL2.sol | 139 ++++++-------------------------- contracts/L2/Mor20FactoryL2.sol | 73 +++++++++-------- 5 files changed, 226 insertions(+), 287 deletions(-) create mode 100644 contracts/BaseFactory.sol diff --git a/contracts/BaseFactory.sol b/contracts/BaseFactory.sol new file mode 100644 index 0000000..e52e73d --- /dev/null +++ b/contracts/BaseFactory.sol @@ -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_)); + } +} diff --git a/contracts/L1/BaseFactoryL1.sol b/contracts/L1/BaseFactoryL1.sol index 8a21cb9..1eedd7e 100644 --- a/contracts/L1/BaseFactoryL1.sol +++ b/contracts/L1/BaseFactoryL1.sol @@ -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, @@ -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_); } } diff --git a/contracts/L1/Mor20FactoryL1.sol b/contracts/L1/Mor20FactoryL1.sol index b531864..f40005b 100644 --- a/contracts/L1/Mor20FactoryL1.sol +++ b/contracts/L1/Mor20FactoryL1.sol @@ -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_) + ); + } } diff --git a/contracts/L2/BaseFactoryL2.sol b/contracts/L2/BaseFactoryL2.sol index 0501d2e..d27d7f9 100644 --- a/contracts/L2/BaseFactoryL2.sol +++ b/contracts/L2/BaseFactoryL2.sol @@ -1,20 +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 {Paginator} from "@solarity/solidity-lib/libs/arrays/Paginator.sol"; -import {ProxyBeacon} from "@solarity/solidity-lib/proxy/beacon/ProxyBeacon.sol"; -import {PublicBeaconProxy} from "@solarity/solidity-lib/proxy/beacon/PublicBeaconProxy.sol"; +import {BaseFactory} from "../BaseFactory.sol"; -import {ERC20MOR} from "./ERC20MOR.sol"; +import {IL2TokenReceiver} from "../interfaces/IL2TokenReceiver.sol"; -import {RewardTokenDeployer} from "../libs/RewardTokenDeployer.sol"; - -abstract contract BaseFactoryL2 { +abstract contract BaseFactoryL2 is BaseFactory { using EnumerableSet for EnumerableSet.AddressSet; - using Paginator for EnumerableSet.AddressSet; enum PoolType { L2_MESSAGE_RECEIVER, @@ -27,122 +21,37 @@ abstract contract BaseFactoryL2 { address l2TokenReceiver; address rewardToken; } - mapping(bytes32 => bool) private _usedSalts; - - mapping(PoolType => ProxyBeacon) private _beacons; - mapping(PoolType => EnumerableSet.AddressSet) private _pools; - - function predictMor20Address( - address deployer, - string calldata mor20Name - ) external view returns (Mor20PredictedAddressesL2 memory predictedAddresses) { - if (bytes(mor20Name).length == 0) { - return predictedAddresses; - } - - bytes32 poolSalt = _calculatePoolSalt(deployer, mor20Name); - - return - Mor20PredictedAddressesL2( - _predictPoolAddress(PoolType.L2_MESSAGE_RECEIVER, poolSalt), - _predictPoolAddress(PoolType.L2_TOKEN_RECEIVER, poolSalt), - _predictPoolAddress(PoolType.REWARD_TOKEN, poolSalt) - ); - } - /** - * @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"); - - 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(PoolType poolType_) public view returns (address) { - address beacon_ = address(_beacons[poolType_]); - - require(beacon_ != address(0), "BaseFactory: bad PublicBeaconProxy"); - - return beacon_; + struct Mor20DeployParams { + string name; + string symbol; + address rewardToken; + address rewardTokenDelegate; + ////// + address sender; + uint16 senderChainId; + ////// + address router_; + address nonfungiblePositionManager_; + IL2TokenReceiver.SwapParams firstSwapParams_; + IL2TokenReceiver.SwapParams secondSwapParams; } - /** - * @notice The function to count pools - * @param poolType_ the type of the pools - * @return the number of pools - */ - function countPools(PoolType poolType_) public view returns (uint256) { - return _pools[poolType_].length(); - } + event Mor20Deployed(string name, address l2MessageReceiver, address l2TokenReceiver, address rewardToken); - /** - * @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( - PoolType poolType_, - uint256 offset_, - uint256 limit_ - ) public view returns (address[] memory pools_) { - return _pools[poolType_].part(offset_, limit_); + function _predictPoolAddress(PoolType poolType_, bytes32 poolSalt_) internal view returns (address) { + return _predictPoolAddress(uint8(poolType_), poolSalt_); } function _addPool(PoolType poolType_, address pool_) internal { - _pools[poolType_].add(pool_); - } - - 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]); - } - } + _pools[uint8(poolType_)].add(pool_); } - 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 _setNewImplementation(uint8 poolType_, address newImplementation_) internal { + _setNewImplementation(poolType_, newImplementation_); } - function _calculatePoolSalt(address deployer, string memory poolName) internal pure returns (bytes32) { - return keccak256(abi.encodePacked(deployer, poolName)); + function _deploy2(PoolType poolType_, string memory name_) internal returns (address) { + return _deploy2(uint8(poolType_), name_); } } diff --git a/contracts/L2/Mor20FactoryL2.sol b/contracts/L2/Mor20FactoryL2.sol index 227f9dd..7c98016 100644 --- a/contracts/L2/Mor20FactoryL2.sol +++ b/contracts/L2/Mor20FactoryL2.sol @@ -3,77 +3,80 @@ pragma solidity ^0.8.20; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; -import {BaseFactoryL2, RewardTokenDeployer, Create2} from "./BaseFactoryL2.sol"; +import {BaseFactoryL2} from "./BaseFactoryL2.sol"; import {IL2MessageReceiver} from "../interfaces/IL2MessageReceiver.sol"; import {IL2TokenReceiver} from "../interfaces/IL2TokenReceiver.sol"; import {CorePropertiesL2} from "./CorePropertiesL2.sol"; +import {RewardTokenDeployer} from "../libs/RewardTokenDeployer.sol"; + contract Mor20FactoryL2 is BaseFactoryL2, Ownable { CorePropertiesL2 public coreProperties; - struct Mor20DeployParams { - string name; - string symbol; - address rewardToken; - address rewardTokenDelegate; - ////// - address sender; - uint16 senderChainId; - ////// - address router_; - address nonfungiblePositionManager_; - IL2TokenReceiver.SwapParams firstSwapParams_; - IL2TokenReceiver.SwapParams secondSwapParams; - } - - event Mor20Deployed(string name, address l2MessageReceiver, address l2TokenReceiver, address rewardToken); + function deployMor20OnL1(Mor20DeployParams calldata parameters_) external onlyOwner { + address l2MessageReceiverAddress = _deploy2(PoolType.L2_MESSAGE_RECEIVER, parameters_.name); - function deployMor20OnL1(Mor20DeployParams calldata parameters) external onlyOwner { - address l2MessageReceiverAddress = _deploy2(PoolType.L2_MESSAGE_RECEIVER, parameters.name); - - address l2TokenReceiverAddress = _deploy2(PoolType.L2_TOKEN_RECEIVER, parameters.name); + address l2TokenReceiverAddress = _deploy2(PoolType.L2_TOKEN_RECEIVER, parameters_.name); address rewardTokenAddress; - if (parameters.rewardToken == address(0)) { + if (parameters_.rewardToken == address(0)) { rewardTokenAddress = _deployRewardToken( - parameters.name, - parameters.symbol, + parameters_.name, + parameters_.symbol, coreProperties.lZEnpointAddress(), - parameters.rewardTokenDelegate, + parameters_.rewardTokenDelegate, l2MessageReceiverAddress ); } else { - rewardTokenAddress = parameters.rewardToken; + rewardTokenAddress = parameters_.rewardToken; } IL2MessageReceiver(l2MessageReceiverAddress).L2MessageReceiver__init( rewardTokenAddress, - IL2MessageReceiver.Config(coreProperties.lZGatewayAddress(), parameters.sender, coreProperties.l1ChainId()) + IL2MessageReceiver.Config(coreProperties.lZGatewayAddress(), parameters_.sender, coreProperties.l1ChainId()) ); IL2TokenReceiver(l2TokenReceiverAddress).L2TokenReceiver__init( - parameters.router_, - parameters.nonfungiblePositionManager_, - parameters.firstSwapParams_, - parameters.secondSwapParams + parameters_.router_, + parameters_.nonfungiblePositionManager_, + parameters_.firstSwapParams_, + parameters_.secondSwapParams ); _addPool(PoolType.L2_MESSAGE_RECEIVER, l2MessageReceiverAddress); _addPool(PoolType.L2_TOKEN_RECEIVER, l2TokenReceiverAddress); _addPool(PoolType.REWARD_TOKEN, rewardTokenAddress); - emit Mor20Deployed(parameters.name, l2MessageReceiverAddress, l2TokenReceiverAddress, rewardTokenAddress); + emit Mor20Deployed(parameters_.name, l2MessageReceiverAddress, l2TokenReceiverAddress, rewardTokenAddress); } 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 (Mor20PredictedAddressesL2 memory predictedAddresses) { + if (bytes(mor20Name_).length == 0) { + return predictedAddresses; + } + + bytes32 poolSalt_ = _calculatePoolSalt(deployer_, mor20Name_); + + return + Mor20PredictedAddressesL2( + _predictPoolAddress(PoolType.L2_MESSAGE_RECEIVER, poolSalt_), + _predictPoolAddress(PoolType.L2_TOKEN_RECEIVER, poolSalt_), + _predictPoolAddress(PoolType.REWARD_TOKEN, poolSalt_) + ); + } + function _deployRewardToken( string memory name_, string memory symbol_, @@ -81,8 +84,8 @@ contract Mor20FactoryL2 is BaseFactoryL2, Ownable { address delegate_, address minter_ ) internal returns (address) { - bytes32 salt_ = _calculatePoolSalt(tx.origin, name_); + bytes32 poolSalt_ = _calculatePoolSalt(tx.origin, name_); - return RewardTokenDeployer.deployRewardToken(salt_, name_, symbol_, layerZeroEndpoint_, delegate_, minter_); + return RewardTokenDeployer.deployRewardToken(poolSalt_, name_, symbol_, layerZeroEndpoint_, delegate_, minter_); } } From 67283a1f83a920e502645d044f28e6edefa8e2d9 Mon Sep 17 00:00:00 2001 From: Ruslan Kasheparov Date: Fri, 5 Apr 2024 08:13:21 +0200 Subject: [PATCH 03/17] Refactored code --- contracts/BaseFactory.sol | 1 - contracts/L1/CorePropertiesL1.sol | 8 +++--- contracts/L1/Distribution.sol | 2 +- contracts/L2/CorePropertiesL2.sol | 21 ++++++++++------ contracts/L2/Mor20FactoryL2.sol | 41 +++++++++++++++++-------------- 5 files changed, 41 insertions(+), 32 deletions(-) diff --git a/contracts/BaseFactory.sol b/contracts/BaseFactory.sol index e52e73d..bbcba3b 100644 --- a/contracts/BaseFactory.sol +++ b/contracts/BaseFactory.sol @@ -84,7 +84,6 @@ abstract contract BaseFactory { * @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)) { diff --git a/contracts/L1/CorePropertiesL1.sol b/contracts/L1/CorePropertiesL1.sol index ae764fc..f6a0852 100644 --- a/contracts/L1/CorePropertiesL1.sol +++ b/contracts/L1/CorePropertiesL1.sol @@ -32,10 +32,6 @@ contract CorePropertiesL1 is Ownable { treasuryAddress = treasuryAddress_; } - function getFeeAndTreadury(address distributionAddress_) external view returns (uint256, address) { - return (_fees[distributionAddress_], treasuryAddress); - } - function setDeployParams( address arbitrumGateway_, address lZEnpointAddress_, @@ -46,6 +42,10 @@ contract CorePropertiesL1 is Ownable { destinationChainId = destinationChainId_; } + function getFeeAndTreasury(address distributionAddress_) external view returns (uint256, address) { + return (_fees[distributionAddress_], treasuryAddress); + } + function getDeployParams() external view returns (address, address) { return (arbitrumGateway, lZEnpointAddress); } diff --git a/contracts/L1/Distribution.sol b/contracts/L1/Distribution.sol index 60722ee..6dbb402 100644 --- a/contracts/L1/Distribution.sol +++ b/contracts/L1/Distribution.sol @@ -335,7 +335,7 @@ contract Distribution is IDistribution, OwnableUpgradeable { uint256 overplus_ = overplus(); require(overplus_ > 0, "DS: overplus is zero"); - (uint256 feePercent_, address treasuryAddress_) = coreProperties.getFeeAndTreadury(address(this)); + (uint256 feePercent_, address treasuryAddress_) = coreProperties.getFeeAndTreasury(address(this)); uint256 fee_ = _feeAmount(overplus_, feePercent_); IERC20(depositToken).safeTransfer(treasuryAddress_, fee_); diff --git a/contracts/L2/CorePropertiesL2.sol b/contracts/L2/CorePropertiesL2.sol index 83de5a7..41d3133 100644 --- a/contracts/L2/CorePropertiesL2.sol +++ b/contracts/L2/CorePropertiesL2.sol @@ -1,19 +1,24 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import {MultiOwnable} from "@solarity/solidity-lib/access/MultiOwnable.sol"; - -contract CorePropertiesL2 is MultiOwnable { - address public arbitrumGateway; - address public treasuryAddress; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +contract CorePropertiesL2 is Ownable { address public lZEnpointAddress; address public lZGatewayAddress; uint16 public l1ChainId; - uint256 public destinationChainId; // arbitrum + function setDeployParams( + address lZEnpointAddress_, + address lZGatewayAddress_, + uint16 l1ChainId_ + ) external onlyOwner { + lZEnpointAddress = lZEnpointAddress_; + lZGatewayAddress = lZGatewayAddress_; + l1ChainId = l1ChainId_; + } - constructor() { - __MultiOwnable_init(); + function getDeployParams() external view returns (address, address, uint16) { + return (lZEnpointAddress, lZGatewayAddress, l1ChainId); } } diff --git a/contracts/L2/Mor20FactoryL2.sol b/contracts/L2/Mor20FactoryL2.sol index 7c98016..6453073 100644 --- a/contracts/L2/Mor20FactoryL2.sol +++ b/contracts/L2/Mor20FactoryL2.sol @@ -4,52 +4,57 @@ pragma solidity ^0.8.20; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {BaseFactoryL2} from "./BaseFactoryL2.sol"; +import {CorePropertiesL2} from "./CorePropertiesL2.sol"; -import {IL2MessageReceiver} from "../interfaces/IL2MessageReceiver.sol"; import {IL2TokenReceiver} from "../interfaces/IL2TokenReceiver.sol"; - -import {CorePropertiesL2} from "./CorePropertiesL2.sol"; +import {IL2MessageReceiver} from "../interfaces/IL2MessageReceiver.sol"; import {RewardTokenDeployer} from "../libs/RewardTokenDeployer.sol"; contract Mor20FactoryL2 is BaseFactoryL2, Ownable { CorePropertiesL2 public coreProperties; + constructor(address coreProperties_) { + coreProperties = CorePropertiesL2(coreProperties_); + } + function deployMor20OnL1(Mor20DeployParams calldata parameters_) external onlyOwner { - address l2MessageReceiverAddress = _deploy2(PoolType.L2_MESSAGE_RECEIVER, parameters_.name); + (address lZEnpointAddress_, address lZGatewayAddress_, uint16 l1ChainId_) = coreProperties.getDeployParams(); + + address l2MessageReceiverAddress_ = _deploy2(PoolType.L2_MESSAGE_RECEIVER, parameters_.name); - address l2TokenReceiverAddress = _deploy2(PoolType.L2_TOKEN_RECEIVER, parameters_.name); + address l2TokenReceiverAddress_ = _deploy2(PoolType.L2_TOKEN_RECEIVER, parameters_.name); - address rewardTokenAddress; + address rewardTokenAddress_; if (parameters_.rewardToken == address(0)) { - rewardTokenAddress = _deployRewardToken( + rewardTokenAddress_ = _deployRewardToken( parameters_.name, parameters_.symbol, - coreProperties.lZEnpointAddress(), + lZEnpointAddress_, parameters_.rewardTokenDelegate, - l2MessageReceiverAddress + l2MessageReceiverAddress_ ); } else { - rewardTokenAddress = parameters_.rewardToken; + rewardTokenAddress_ = parameters_.rewardToken; } - IL2MessageReceiver(l2MessageReceiverAddress).L2MessageReceiver__init( - rewardTokenAddress, - IL2MessageReceiver.Config(coreProperties.lZGatewayAddress(), parameters_.sender, coreProperties.l1ChainId()) + IL2MessageReceiver(l2MessageReceiverAddress_).L2MessageReceiver__init( + rewardTokenAddress_, + IL2MessageReceiver.Config(lZGatewayAddress_, parameters_.sender, l1ChainId_) ); - IL2TokenReceiver(l2TokenReceiverAddress).L2TokenReceiver__init( + IL2TokenReceiver(l2TokenReceiverAddress_).L2TokenReceiver__init( parameters_.router_, parameters_.nonfungiblePositionManager_, parameters_.firstSwapParams_, parameters_.secondSwapParams ); - _addPool(PoolType.L2_MESSAGE_RECEIVER, l2MessageReceiverAddress); - _addPool(PoolType.L2_TOKEN_RECEIVER, l2TokenReceiverAddress); - _addPool(PoolType.REWARD_TOKEN, rewardTokenAddress); + _addPool(PoolType.L2_MESSAGE_RECEIVER, l2MessageReceiverAddress_); + _addPool(PoolType.L2_TOKEN_RECEIVER, l2TokenReceiverAddress_); + _addPool(PoolType.REWARD_TOKEN, rewardTokenAddress_); - emit Mor20Deployed(parameters_.name, l2MessageReceiverAddress, l2TokenReceiverAddress, rewardTokenAddress); + emit Mor20Deployed(parameters_.name, l2MessageReceiverAddress_, l2TokenReceiverAddress_, rewardTokenAddress_); } function setNewImplementations( From 27a351a982cb9fed3206305f40d52402837dc4e9 Mon Sep 17 00:00:00 2001 From: Ruslan Kasheparov Date: Fri, 5 Apr 2024 08:38:22 +0200 Subject: [PATCH 04/17] Set CoreProperties upgradeable --- contracts/L1/CorePropertiesL1.sol | 14 ++++++++++---- contracts/L2/CorePropertiesL2.sol | 20 ++++++++++++++++++-- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/contracts/L1/CorePropertiesL1.sol b/contracts/L1/CorePropertiesL1.sol index f6a0852..5aab225 100644 --- a/contracts/L1/CorePropertiesL1.sol +++ b/contracts/L1/CorePropertiesL1.sol @@ -1,9 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; -contract CorePropertiesL1 is Ownable { +contract CorePropertiesL1 is UUPSUpgradeable, OwnableUpgradeable { address public arbitrumGateway; address public treasuryAddress; @@ -12,12 +13,15 @@ contract CorePropertiesL1 is Ownable { mapping(address => uint256) private _fees; - constructor( + function __CorePropertiesL1_init( address arbitrumGateway_, address treasuryAddress_, address lZEnpointAddress_, uint256 destinationChainId_ - ) { + ) external initializer { + __Ownable_init(); + __UUPSUpgradeable_init(); + arbitrumGateway = arbitrumGateway_; treasuryAddress = treasuryAddress_; lZEnpointAddress = lZEnpointAddress_; @@ -49,4 +53,6 @@ contract CorePropertiesL1 is Ownable { function getDeployParams() external view returns (address, address) { return (arbitrumGateway, lZEnpointAddress); } + + function _authorizeUpgrade(address) internal override onlyOwner {} } diff --git a/contracts/L2/CorePropertiesL2.sol b/contracts/L2/CorePropertiesL2.sol index 41d3133..963adb1 100644 --- a/contracts/L2/CorePropertiesL2.sol +++ b/contracts/L2/CorePropertiesL2.sol @@ -1,13 +1,27 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; -contract CorePropertiesL2 is Ownable { +contract CorePropertiesL2 is UUPSUpgradeable, OwnableUpgradeable { address public lZEnpointAddress; address public lZGatewayAddress; uint16 public l1ChainId; + function __CorePropertiesL2_init( + address lZEnpointAddress_, + address lZGatewayAddress_, + uint16 l1ChainId_ + ) external initializer { + __Ownable_init(); + __UUPSUpgradeable_init(); + + lZEnpointAddress = lZEnpointAddress_; + lZGatewayAddress = lZGatewayAddress_; + l1ChainId = l1ChainId_; + } + function setDeployParams( address lZEnpointAddress_, address lZGatewayAddress_, @@ -21,4 +35,6 @@ contract CorePropertiesL2 is Ownable { function getDeployParams() external view returns (address, address, uint16) { return (lZEnpointAddress, lZGatewayAddress, l1ChainId); } + + function _authorizeUpgrade(address) internal override onlyOwner {} } From d43e4902aea46e3dd9ff16fe2346c1d69db2d924 Mon Sep 17 00:00:00 2001 From: Ruslan Kasheparov Date: Thu, 25 Apr 2024 16:33:50 +0200 Subject: [PATCH 05/17] fixes --- contracts/BaseFactory.sol | 77 ++++--------------------------- contracts/L1/BaseFactoryL1.sol | 11 +---- contracts/L1/CorePropertiesL1.sol | 58 ----------------------- contracts/L1/Distribution.sol | 27 +++++------ contracts/L1/FeeParams.sol | 50 ++++++++++++++++++++ contracts/L1/Mor20FactoryL1.sol | 44 ++++++++++-------- 6 files changed, 99 insertions(+), 168 deletions(-) delete mode 100644 contracts/L1/CorePropertiesL1.sol create mode 100644 contracts/L1/FeeParams.sol diff --git a/contracts/BaseFactory.sol b/contracts/BaseFactory.sol index bbcba3b..259c1cf 100644 --- a/contracts/BaseFactory.sol +++ b/contracts/BaseFactory.sol @@ -2,10 +2,9 @@ pragma solidity ^0.8.20; import {Create2} from "@openzeppelin/contracts/utils/Create2.sol"; +import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.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 { @@ -13,9 +12,8 @@ abstract contract BaseFactory { using Paginator for EnumerableSet.AddressSet; mapping(bytes32 => bool) private _usedSalts; - - mapping(uint8 => ProxyBeacon) internal _beacons; - mapping(uint8 => EnumerableSet.AddressSet) internal _pools; + mapping(address => mapping(string => mapping(uint8 => address))) public pools; + mapping(uint8 => address) internal _implementations; /** * @notice The function to get implementation of the specific pools @@ -23,46 +21,13 @@ abstract contract BaseFactory { * @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(_implementations[poolType_] != address(0), "BaseFactory: this mapping doesn't exist"); - require(beacon_ != address(0), "BaseFactory: bad PublicBeaconProxy"); - - return beacon_; + return _implementations[poolType_]; } - /** - * @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 _addPool(address deployer_, uint8 poolType_, string memory poolName_, address pool_) internal { + pools[deployer_][poolName_][poolType_] = pool_; } function _deploy2(uint8 poolType_, string memory poolName_) internal returns (address) { @@ -71,37 +36,15 @@ abstract contract BaseFactory { 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(""))); + return address(new ERC1967Proxy{salt: salt_}(getImplementation(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 _getImplementation(uint8 poolType_) internal view returns (address) { + return _implementations[poolType_]; } function _calculatePoolSalt(address deployer_, string memory poolName_) internal pure returns (bytes32) { diff --git a/contracts/L1/BaseFactoryL1.sol b/contracts/L1/BaseFactoryL1.sol index 1eedd7e..002675c 100644 --- a/contracts/L1/BaseFactoryL1.sol +++ b/contracts/L1/BaseFactoryL1.sol @@ -26,9 +26,6 @@ abstract contract BaseFactoryL1 is BaseFactory { IDistribution.Pool[] poolsInfo; ////// address messageReceiver; - address zroPaymentAddress; - uint16 l2EndpointId; - bytes adapterParams; ////// address wrappedToken; address tokenReceiver; @@ -36,12 +33,8 @@ abstract contract BaseFactoryL1 is BaseFactory { event Mor20Deployed(string name, address distribution, address l1Sender); - function _predictPoolAddress(PoolType poolType_, bytes32 poolSalt_) internal view returns (address) { - return _predictPoolAddress(uint8(poolType_), poolSalt_); - } - - function _addDistribution(address distribution_) internal { - _pools[uint8(PoolType.DISTRIBUTION)].add(distribution_); + function _addPool(PoolType poolType_, string memory poolName_, address pool_) internal { + _addPool(tx.origin, uint8(poolType_), poolName_, pool_); } function _deploy2(PoolType poolType_, string memory name_) internal returns (address) { diff --git a/contracts/L1/CorePropertiesL1.sol b/contracts/L1/CorePropertiesL1.sol deleted file mode 100644 index 5aab225..0000000 --- a/contracts/L1/CorePropertiesL1.sol +++ /dev/null @@ -1,58 +0,0 @@ -// 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"; - -contract CorePropertiesL1 is UUPSUpgradeable, OwnableUpgradeable { - address public arbitrumGateway; - address public treasuryAddress; - - address public lZEnpointAddress; // L1 - uint256 public destinationChainId; // arbitrum - - mapping(address => uint256) private _fees; - - function __CorePropertiesL1_init( - address arbitrumGateway_, - address treasuryAddress_, - address lZEnpointAddress_, - uint256 destinationChainId_ - ) external initializer { - __Ownable_init(); - __UUPSUpgradeable_init(); - - arbitrumGateway = arbitrumGateway_; - treasuryAddress = treasuryAddress_; - lZEnpointAddress = lZEnpointAddress_; - destinationChainId = destinationChainId_; - } - - function setFee(address token_, uint256 fee_) external onlyOwner { - _fees[token_] = fee_; - } - - function setTreasuryAddress(address treasuryAddress_) external onlyOwner { - treasuryAddress = treasuryAddress_; - } - - function setDeployParams( - address arbitrumGateway_, - address lZEnpointAddress_, - uint256 destinationChainId_ - ) external onlyOwner { - arbitrumGateway = arbitrumGateway_; - lZEnpointAddress = lZEnpointAddress_; - destinationChainId = destinationChainId_; - } - - function getFeeAndTreasury(address distributionAddress_) external view returns (uint256, address) { - return (_fees[distributionAddress_], treasuryAddress); - } - - function getDeployParams() external view returns (address, address) { - return (arbitrumGateway, lZEnpointAddress); - } - - function _authorizeUpgrade(address) internal override onlyOwner {} -} diff --git a/contracts/L1/Distribution.sol b/contracts/L1/Distribution.sol index 6dbb402..8be76ea 100644 --- a/contracts/L1/Distribution.sol +++ b/contracts/L1/Distribution.sol @@ -11,13 +11,14 @@ import {LinearDistributionIntervalDecrease} from "../libs/LinearDistributionInte import {L1Sender} from "./L1Sender.sol"; import {IDistribution} from "../interfaces/IDistribution.sol"; -import {CorePropertiesL1} from "./CorePropertiesL1.sol"; +import {FeeParams} from "./FeeParams.sol"; contract Distribution is IDistribution, OwnableUpgradeable { using SafeERC20 for IERC20; address public depositToken; address public l1Sender; + address public feeParams; // Pool storage Pool[] public pools; @@ -28,8 +29,6 @@ contract Distribution is IDistribution, OwnableUpgradeable { uint256 public totalDepositedInPublicPools; - CorePropertiesL1 public coreProperties; - /**********************************************************************************************/ /*** Modifiers ***/ /**********************************************************************************************/ @@ -84,12 +83,9 @@ contract Distribution is IDistribution, OwnableUpgradeable { 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.payoutStart == pool_.payoutStart, "DS: invalid payout start value"); require(pool.withdrawLockPeriod == pool_.withdrawLockPeriod, "DS: invalid withdrawLockPeriod"); - require( - pool.withdrawLockPeriodAfterStake == pool_.withdrawLockPeriodAfterStake, - "DS: invalid withdrawLockPeriodAfterStake" - ); + require(pool.withdrawLockPeriodAfterStake == pool_.withdrawLockPeriodAfterStake, "DS: invalid WLPAS value"); } PoolData storage poolData = poolsData[poolId_]; @@ -335,11 +331,14 @@ contract Distribution is IDistribution, OwnableUpgradeable { uint256 overplus_ = overplus(); require(overplus_ > 0, "DS: overplus is zero"); - (uint256 feePercent_, address treasuryAddress_) = coreProperties.getFeeAndTreasury(address(this)); - uint256 fee_ = _feeAmount(overplus_, feePercent_); - IERC20(depositToken).safeTransfer(treasuryAddress_, fee_); + (uint256 feePercent_, address treasuryAddress_) = FeeParams(feeParams).getFeeAndTreasury(address(this)); - overplus_ -= fee_; + uint256 fee_ = (overplus_ * feePercent_) / PRECISION; + if (fee_ != 0) { + IERC20(depositToken).safeTransfer(treasuryAddress_, fee_); + + overplus_ -= fee_; + } IERC20(depositToken).safeTransfer(l1Sender, overplus_); @@ -353,8 +352,4 @@ contract Distribution is IDistribution, OwnableUpgradeable { return bridgeMessageId_; } - - function _feeAmount(uint256 amount_, uint256 feePercent_) internal pure returns (uint256) { - return (amount_ * feePercent_) / PRECISION; - } } diff --git a/contracts/L1/FeeParams.sol b/contracts/L1/FeeParams.sol new file mode 100644 index 0000000..d0af416 --- /dev/null +++ b/contracts/L1/FeeParams.sol @@ -0,0 +1,50 @@ +// 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"; + +contract FeeParams is UUPSUpgradeable, OwnableUpgradeable { + address public treasuryAddress; + + uint256 public baseFee; + + mapping(address => uint256) public fees; + + function __FeeParams_init(address treasuryAddress_, uint256 baseFee_) external initializer { + __Ownable_init(); + __UUPSUpgradeable_init(); + + treasuryAddress = treasuryAddress_; + baseFee = baseFee_; + } + + function setFee(address token_, uint256 fee_) external onlyOwner { + require(fee_ < PRECISION, "FeeParams: invalid fee"); + + fees[token_] = fee_; + } + + function setTreasury(address treasuryAddress_) external onlyOwner { + treasuryAddress = treasuryAddress_; + } + + function setBaseFee(uint256 baseFee_) external onlyOwner { + require(baseFee_ < PRECISION, "FeeParams: invalid fee"); + + baseFee = baseFee_; + } + + function getFeeAndTreasury(address distributionAddress_) external view returns (uint256, address) { + uint256 fee_ = fees[distributionAddress_]; + if (fee_ == 0) { + fee_ = baseFee; + } + + return (fee_, treasuryAddress); + } + + function _authorizeUpgrade(address) internal override onlyOwner {} +} diff --git a/contracts/L1/Mor20FactoryL1.sol b/contracts/L1/Mor20FactoryL1.sol index f40005b..02cbd29 100644 --- a/contracts/L1/Mor20FactoryL1.sol +++ b/contracts/L1/Mor20FactoryL1.sol @@ -4,21 +4,27 @@ pragma solidity ^0.8.20; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {BaseFactoryL1} from "./BaseFactoryL1.sol"; -import {CorePropertiesL1} from "./CorePropertiesL1.sol"; import {IDistribution} from "../interfaces/IDistribution.sol"; import {IL1Sender} from "../interfaces/IL1Sender.sol"; contract Mor20FactoryL1 is BaseFactoryL1, Ownable { - CorePropertiesL1 public coreProperties; + address public arbitrumGateway; - constructor(address coreProperties_) { - coreProperties = CorePropertiesL1(coreProperties_); + address public lZEnpointAddress; // L1 + uint256 public destinationChainId; // arbitrum + + address zroPaymentAddress; // LZ + uint16 l2EndpointId; + bytes adapterParams; + + constructor(address arbitrumGateway_, address lZEnpointAddress_, uint256 destinationChainId_) { + arbitrumGateway = arbitrumGateway_; + lZEnpointAddress = lZEnpointAddress_; + destinationChainId = destinationChainId_; } function deployMor20OnL1(Mor20DeployParams calldata parameters_) external onlyOwner { - (address arbitrumGateway_, address lZEnpointAddress_) = coreProperties.getDeployParams(); - address distributionAddress_ = _deploy2(PoolType.DISTRIBUTION, parameters_.name); address l1SenderAddress_ = _deploy2(PoolType.L1_SENDER, parameters_.name); @@ -32,27 +38,29 @@ contract Mor20FactoryL1 is BaseFactoryL1, Ownable { IL1Sender(l1SenderAddress_).L1Sender__init( distributionAddress_, IL1Sender.RewardTokenConfig( - lZEnpointAddress_, + lZEnpointAddress, parameters_.messageReceiver, - parameters_.l2EndpointId, - parameters_.zroPaymentAddress, - parameters_.adapterParams + l2EndpointId, + zroPaymentAddress, + adapterParams ), - IL1Sender.DepositTokenConfig(parameters_.wrappedToken, arbitrumGateway_, parameters_.tokenReceiver) + IL1Sender.DepositTokenConfig(parameters_.wrappedToken, arbitrumGateway, parameters_.tokenReceiver) ); - _addDistribution(distributionAddress_); - - _updateSalt(parameters_.name); + _addPool(PoolType.DISTRIBUTION, parameters_.name, distributionAddress_); + _addPool(PoolType.L1_SENDER, parameters_.name, distributionAddress_); emit Mor20Deployed(parameters_.name, distributionAddress_, l1SenderAddress_); } - function setNewImplementations( - uint8[] memory poolTypes_, - address[] calldata newImplementations_ + function setDeployParams( + address arbitrumGateway_, + address lZEnpointAddress_, + uint256 destinationChainId_ ) external onlyOwner { - _setNewImplementations(poolTypes_, newImplementations_); + arbitrumGateway = arbitrumGateway_; + lZEnpointAddress = lZEnpointAddress_; + destinationChainId = destinationChainId_; } function predictMor20Address( From 57e7175f6a4965c1eaa836509be41718f17e1f53 Mon Sep 17 00:00:00 2001 From: Oleksandr Fedorenko Date: Tue, 30 Apr 2024 19:10:32 +0300 Subject: [PATCH 06/17] refactor logic --- contracts/BaseFactory.sol | 53 --------- contracts/Factory.sol | 96 ++++++++++++++++ contracts/L1/BaseFactoryL1.sol | 43 ------- contracts/L1/Distribution.sol | 28 ++++- contracts/L1/{FeeParams.sol => FeeConfig.sol} | 29 ++--- contracts/L1/L1Factory.sol | 105 ++++++++++++++++++ contracts/L1/L1Sender.sol | 81 +++++--------- contracts/L1/Mor20FactoryL1.sol | 82 -------------- contracts/L2/BaseFactoryL2.sol | 57 ---------- contracts/L2/CorePropertiesL2.sol | 40 ------- contracts/L2/L2Factory.sol | 96 ++++++++++++++++ contracts/L2/L2MessageReceiver.sol | 20 +++- ...okenReceiver.sol => L2TokenReceiverV2.sol} | 63 ++++------- contracts/L2/{ERC20MOR.sol => MOR20.sol} | 8 +- contracts/L2/Mor20FactoryL2.sol | 96 ---------------- contracts/interfaces/IOwnable.sol | 10 ++ .../interfaces/{ => L1}/IDistribution.sol | 0 contracts/interfaces/{ => L1}/IL1Sender.sol | 2 +- .../{ => L2}/IL2MessageReceiver.sol | 0 .../IL2TokenReceiverV2.sol} | 32 ++---- .../{IERC20MOR.sol => L2/IMOR20.sol} | 6 +- contracts/libs/RewardTokenDeployer.sol | 39 ------- 22 files changed, 422 insertions(+), 564 deletions(-) delete mode 100644 contracts/BaseFactory.sol create mode 100644 contracts/Factory.sol delete mode 100644 contracts/L1/BaseFactoryL1.sol rename contracts/L1/{FeeParams.sol => FeeConfig.sol} (50%) create mode 100644 contracts/L1/L1Factory.sol delete mode 100644 contracts/L1/Mor20FactoryL1.sol delete mode 100644 contracts/L2/BaseFactoryL2.sol delete mode 100644 contracts/L2/CorePropertiesL2.sol create mode 100644 contracts/L2/L2Factory.sol rename contracts/L2/{L2TokenReceiver.sol => L2TokenReceiverV2.sol} (74%) rename contracts/L2/{ERC20MOR.sol => MOR20.sol} (82%) delete mode 100644 contracts/L2/Mor20FactoryL2.sol create mode 100644 contracts/interfaces/IOwnable.sol rename contracts/interfaces/{ => L1}/IDistribution.sol (100%) rename contracts/interfaces/{ => L1}/IL1Sender.sol (96%) rename contracts/interfaces/{ => L2}/IL2MessageReceiver.sol (100%) rename contracts/interfaces/{IL2TokenReceiver.sol => L2/IL2TokenReceiverV2.sol} (82%) rename contracts/interfaces/{IERC20MOR.sol => L2/IMOR20.sol} (83%) delete mode 100644 contracts/libs/RewardTokenDeployer.sol diff --git a/contracts/BaseFactory.sol b/contracts/BaseFactory.sol deleted file mode 100644 index 259c1cf..0000000 --- a/contracts/BaseFactory.sol +++ /dev/null @@ -1,53 +0,0 @@ -// 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 {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.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(address => mapping(string => mapping(uint8 => address))) public pools; - mapping(uint8 => address) internal _implementations; - - /** - * @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(_implementations[poolType_] != address(0), "BaseFactory: this mapping doesn't exist"); - - return _implementations[poolType_]; - } - - function _addPool(address deployer_, uint8 poolType_, string memory poolName_, address pool_) internal { - pools[deployer_][poolName_][poolType_] = 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 ERC1967Proxy{salt: salt_}(getImplementation(poolType_), bytes(""))); - } - - function _updateSalt(string memory poolName_) internal { - _usedSalts[_calculatePoolSalt(tx.origin, poolName_)] = true; - } - - function _getImplementation(uint8 poolType_) internal view returns (address) { - return _implementations[poolType_]; - } - - function _calculatePoolSalt(address deployer_, string memory poolName_) internal pure returns (bytes32) { - return keccak256(abi.encodePacked(deployer_, poolName_)); - } -} diff --git a/contracts/Factory.sol b/contracts/Factory.sol new file mode 100644 index 0000000..d1189f5 --- /dev/null +++ b/contracts/Factory.sol @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +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"; + +abstract contract Factory is OwnableUpgradeable, PausableUpgradeable, UUPSUpgradeable { + /** + * The event is emitted when the proxy is deployed. + * @param proxy The proxy address. + * @param implementation The implementation. + * @param poolType The `poolType`. + * @param poolName The `poolName`. + */ + event ProxyDeployed(address proxy, address indexed implementation, uint8 indexed poolType, string poolName); + + 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 {} + + function __Factory_init_unchained() internal onlyInitializing { + _pause(); + } + + /** + * @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 memory poolName_) internal returns (address) { + require(bytes(poolName_).length != 0, "BF: 'poolName_' is empty"); + bytes32 salt_ = keccak256(abi.encodePacked(_msgSender(), poolName_)); + + address implementation_ = _implementations[poolType_]; + require(implementation_ != address(0), "BF: implementation not found"); + + require(!_usedSalts[salt_], "BF: salt used"); + _usedSalts[salt_] = true; + + address proxy_ = address(new ERC1967Proxy{salt: salt_}(getImplementation(poolType_), bytes(""))); + + deployedProxies[_msgSender()][poolName_][poolType_] = proxy_; + + emit ProxyDeployed(proxy_, implementation_, poolType_, poolName_); + + return proxy_; + } + + function _authorizeUpgrade(address) internal view override onlyOwner {} +} diff --git a/contracts/L1/BaseFactoryL1.sol b/contracts/L1/BaseFactoryL1.sol deleted file mode 100644 index 002675c..0000000 --- a/contracts/L1/BaseFactoryL1.sol +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; - -import {BaseFactory} from "../BaseFactory.sol"; - -import {IDistribution} from "../interfaces/IDistribution.sol"; - -abstract contract BaseFactoryL1 is BaseFactory { - using EnumerableSet for EnumerableSet.AddressSet; - - enum PoolType { - DISTRIBUTION, - L1_SENDER - } - - struct Mor20PredictedAddressesL1 { - address distribution; - address l1Sender; - } - - struct Mor20DeployParams { - string name; - address depositToken; - IDistribution.Pool[] poolsInfo; - ////// - address messageReceiver; - ////// - address wrappedToken; - address tokenReceiver; - } - - event Mor20Deployed(string name, address distribution, address l1Sender); - - function _addPool(PoolType poolType_, string memory poolName_, address pool_) internal { - _addPool(tx.origin, uint8(poolType_), poolName_, pool_); - } - - function _deploy2(PoolType poolType_, string memory name_) internal returns (address) { - return _deploy2(uint8(poolType_), name_); - } -} diff --git a/contracts/L1/Distribution.sol b/contracts/L1/Distribution.sol index 8be76ea..ec9fe51 100644 --- a/contracts/L1/Distribution.sol +++ b/contracts/L1/Distribution.sol @@ -2,23 +2,26 @@ pragma solidity ^0.8.20; import {SafeERC20, IERC20} 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 {PRECISION} from "@solarity/solidity-lib/utils/Globals.sol"; import {LinearDistributionIntervalDecrease} from "../libs/LinearDistributionIntervalDecrease.sol"; +import {IDistribution} from "../interfaces/L1/IDistribution.sol"; import {L1Sender} from "./L1Sender.sol"; -import {IDistribution} from "../interfaces/IDistribution.sol"; -import {FeeParams} from "./FeeParams.sol"; +import {FeeConfig} from "./FeeConfig.sol"; -contract Distribution is IDistribution, OwnableUpgradeable { +contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable { using SafeERC20 for IERC20; + bool public isNotUpgradeable; + address public depositToken; address public l1Sender; - address public feeParams; + address public feeConfig; // Pool storage Pool[] public pools; @@ -27,6 +30,7 @@ contract Distribution is IDistribution, OwnableUpgradeable { // User storage mapping(address => mapping(uint256 => UserData)) public usersData; + // Total deposited storage uint256 public totalDepositedInPublicPools; /**********************************************************************************************/ @@ -56,6 +60,7 @@ contract Distribution is IDistribution, OwnableUpgradeable { Pool[] calldata poolsInfo_ ) external initializer { __Ownable_init(); + __UUPSUpgradeable_init(); for (uint256 i; i < poolsInfo_.length; ++i) { createPool(poolsInfo_[i]); @@ -84,7 +89,7 @@ contract Distribution is IDistribution, OwnableUpgradeable { 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 withdrawLockPeriod"); + require(pool.withdrawLockPeriod == pool_.withdrawLockPeriod, "DS: invalid WLP value"); require(pool.withdrawLockPeriodAfterStake == pool_.withdrawLockPeriodAfterStake, "DS: invalid WLPAS value"); } @@ -331,7 +336,7 @@ contract Distribution is IDistribution, OwnableUpgradeable { uint256 overplus_ = overplus(); require(overplus_ > 0, "DS: overplus is zero"); - (uint256 feePercent_, address treasuryAddress_) = FeeParams(feeParams).getFeeAndTreasury(address(this)); + (uint256 feePercent_, address treasuryAddress_) = FeeConfig(feeConfig).getFeeAndTreasury(address(this)); uint256 fee_ = (overplus_ * feePercent_) / PRECISION; if (fee_ != 0) { @@ -352,4 +357,15 @@ contract Distribution is IDistribution, OwnableUpgradeable { return bridgeMessageId_; } + + /**********************************************************************************************/ + /*** UUPS ***/ + /**********************************************************************************************/ + function removeUpgradeability() external onlyOwner { + isNotUpgradeable = true; + } + + function _authorizeUpgrade(address) internal view override onlyOwner { + require(!isNotUpgradeable, "DS: upgrade isn't available"); + } } diff --git a/contracts/L1/FeeParams.sol b/contracts/L1/FeeConfig.sol similarity index 50% rename from contracts/L1/FeeParams.sol rename to contracts/L1/FeeConfig.sol index d0af416..2b94069 100644 --- a/contracts/L1/FeeParams.sol +++ b/contracts/L1/FeeConfig.sol @@ -6,44 +6,45 @@ import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/U import {PRECISION} from "@solarity/solidity-lib/utils/Globals.sol"; -contract FeeParams is UUPSUpgradeable, OwnableUpgradeable { - address public treasuryAddress; - +contract FeeConfig is OwnableUpgradeable, UUPSUpgradeable { + address public treasury; uint256 public baseFee; mapping(address => uint256) public fees; - function __FeeParams_init(address treasuryAddress_, uint256 baseFee_) external initializer { + function __FeeConfig_init(address treasury_, uint256 baseFee_) external initializer { __Ownable_init(); __UUPSUpgradeable_init(); - treasuryAddress = treasuryAddress_; + treasury = treasury_; baseFee = baseFee_; } - function setFee(address token_, uint256 fee_) external onlyOwner { - require(fee_ < PRECISION, "FeeParams: invalid fee"); + function setFee(address sender_, uint256 fee_) external onlyOwner { + require(fee_ <= PRECISION, "FC: invalid fee"); - fees[token_] = fee_; + fees[sender_] = fee_; } - function setTreasury(address treasuryAddress_) external onlyOwner { - treasuryAddress = treasuryAddress_; + function setTreasury(address treasury_) external onlyOwner { + require(treasury_ != address(0), "FC: invalid treasury"); + + treasury = treasury_; } function setBaseFee(uint256 baseFee_) external onlyOwner { - require(baseFee_ < PRECISION, "FeeParams: invalid fee"); + require(baseFee_ < PRECISION, "FC: invalid base fee"); baseFee = baseFee_; } - function getFeeAndTreasury(address distributionAddress_) external view returns (uint256, address) { - uint256 fee_ = fees[distributionAddress_]; + function getFeeAndTreasury(address sender_) external view returns (uint256, address) { + uint256 fee_ = fees[sender_]; if (fee_ == 0) { fee_ = baseFee; } - return (fee_, treasuryAddress); + return (fee_, treasury); } function _authorizeUpgrade(address) internal override onlyOwner {} diff --git a/contracts/L1/L1Factory.sol b/contracts/L1/L1Factory.sol new file mode 100644 index 0000000..8805106 --- /dev/null +++ b/contracts/L1/L1Factory.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Factory} from "../Factory.sol"; + +import {IDistribution} from "../interfaces/L1/IDistribution.sol"; +import {IL1Sender} from "../interfaces/L1/IL1Sender.sol"; +import {IOwnable} from "../interfaces/IOwnable.sol"; + +contract L1Factory is Factory { + enum PoolType { + DISTRIBUTION, + L1_SENDER + } + + struct L1Params { + string protocolName; + IDistribution.Pool[] poolsInfo; + address l2TokenReceiver; + address l2MessageReceiver; + } + + struct DepositTokenExternalDeps { + address token; + address wToken; + } + + struct LzExternalDeps { + address endpoint; + address zroPaymentAddress; + bytes adapterParams; + uint16 destinationChainId; + } + + struct ArbExternalDeps { + address endpoint; + } + + 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 setLzTokenExternalDeps(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 setArbTokenExternalDeps(ArbExternalDeps calldata arbExternalDeps_) external onlyOwner { + require(arbExternalDeps_.endpoint != address(0), "L1F: invalid ARB endpoint"); + + arbExternalDeps = arbExternalDeps_; + } + + 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_, + 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); + + IOwnable(distributionProxy_).transferOwnership(_msgSender()); + IOwnable(l1SenderProxy_).transferOwnership(_msgSender()); + } +} diff --git a/contracts/L1/L1Sender.sol b/contracts/L1/L1Sender.sol index 2bab303..f801745 100644 --- a/contracts/L1/L1Sender.sol +++ b/contracts/L1/L1Sender.sol @@ -6,12 +6,13 @@ import {ILayerZeroEndpoint} from "@layerzerolabs/lz-evm-sdk-v1-0.7/contracts/int import {IGatewayRouter} from "@arbitrum/token-bridge-contracts/contracts/tokenbridge/libraries/gateway/IGatewayRouter.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; -import {IL1Sender, IERC165} from "../interfaces/IL1Sender.sol"; import {IWStETH} from "../interfaces/tokens/IWStETH.sol"; +import {IL1Sender, IERC165} from "../interfaces/L1/IL1Sender.sol"; -contract L1Sender is IL1Sender, OwnableUpgradeable { +contract L1Sender is IL1Sender, OwnableUpgradeable, UUPSUpgradeable { address public unwrappedDepositToken; address public distribution; @@ -33,6 +34,7 @@ contract L1Sender is IL1Sender, OwnableUpgradeable { DepositTokenConfig calldata depositTokenConfig_ ) external initializer { __Ownable_init(); + __UUPSUpgradeable_init(); distribution = distribution_; rewardTokenConfig = rewardTokenConfig_; @@ -43,39 +45,31 @@ contract L1Sender is IL1Sender, OwnableUpgradeable { return interfaceId_ == type(IL1Sender).interfaceId || interfaceId_ == type(IERC165).interfaceId; } - function _replaceDepositToken(address oldToken_, address newToken_) private { - bool isTokenChanged_ = oldToken_ != newToken_; + function setRewardTokenLZParams(address zroPaymentAddress_, bytes calldata adapterParams_) external onlyOwner { + rewardTokenConfig.zroPaymentAddress = zroPaymentAddress_; + rewardTokenConfig.adapterParams = adapterParams_; + } - if (oldToken_ != address(0) && isTokenChanged_) { - // Remove allowance from stETH to wstETH - IERC20(unwrappedDepositToken).approve(oldToken_, 0); - } + function _setDepositTokenConfig(DepositTokenConfig calldata newConfig_) private { + require(newConfig_.receiver != address(0), "L1S: invalid receiver"); - if (isTokenChanged_) { - // Get stETH from wstETH - address unwrappedToken_ = IWStETH(newToken_).stETH(); - // Increase allowance from stETH to wstETH. To exchange stETH for wstETH - IERC20(unwrappedToken_).approve(newToken_, type(uint256).max); + _setDepositToken(newConfig_.token); + _setDepositTokenGateway(newConfig_.gateway, newConfig_.token); - unwrappedDepositToken = unwrappedToken_; - } + depositTokenConfig = newConfig_; } - function _replaceDepositTokenGateway( - address oldGateway_, - address newGateway_, - address oldToken_, - address newToken_ - ) private { - bool isAllowedChanged_ = (oldToken_ != newToken_) || (oldGateway_ != newGateway_); - - if (oldGateway_ != address(0) && isAllowedChanged_) { - IERC20(oldToken_).approve(IGatewayRouter(oldGateway_).getGateway(oldToken_), 0); - } - - if (isAllowedChanged_) { - IERC20(newToken_).approve(IGatewayRouter(newGateway_).getGateway(newToken_), type(uint256).max); - } + function _setDepositToken(address newToken_) private { + // Get stETH from wstETH + address unwrappedToken_ = IWStETH(newToken_).stETH(); + // Increase allowance from stETH to wstETH. To exchange stETH for wstETH + IERC20(unwrappedToken_).approve(newToken_, type(uint256).max); + + unwrappedDepositToken = unwrappedToken_; + } + + function _setDepositTokenGateway(address newGateway_, address newToken_) private { + IERC20(newToken_).approve(IGatewayRouter(newGateway_).getGateway(newToken_), type(uint256).max); } function sendDepositToken( @@ -119,30 +113,5 @@ contract L1Sender is IL1Sender, OwnableUpgradeable { ); } - function setRewardTokenLZParams(address zroPaymentAddress, bytes calldata adapterParams) external onlyOwner { - rewardTokenConfig.zroPaymentAddress = zroPaymentAddress; - rewardTokenConfig.adapterParams = adapterParams; - } - - function _setDepositTokenConfig(DepositTokenConfig calldata newConfig_) internal { - require(newConfig_.receiver != address(0), "L1S: invalid receiver"); - - _setDepositToken(newConfig_.token); - _setDepositTokenGateway(newConfig_.gateway, newConfig_.token); - - depositTokenConfig = newConfig_; - } - - function _setDepositToken(address newToken_) private { - // Get stETH from wstETH - address unwrappedToken_ = IWStETH(newToken_).stETH(); - // Increase allowance from stETH to wstETH. To exchange stETH for wstETH - IERC20(unwrappedToken_).approve(newToken_, type(uint256).max); - - unwrappedDepositToken = unwrappedToken_; - } - - function _setDepositTokenGateway(address newGateway_, address newToken_) private { - IERC20(newToken_).approve(IGatewayRouter(newGateway_).getGateway(newToken_), type(uint256).max); - } + function _authorizeUpgrade(address) internal view override onlyOwner {} } diff --git a/contracts/L1/Mor20FactoryL1.sol b/contracts/L1/Mor20FactoryL1.sol deleted file mode 100644 index 02cbd29..0000000 --- a/contracts/L1/Mor20FactoryL1.sol +++ /dev/null @@ -1,82 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; - -import {BaseFactoryL1} from "./BaseFactoryL1.sol"; - -import {IDistribution} from "../interfaces/IDistribution.sol"; -import {IL1Sender} from "../interfaces/IL1Sender.sol"; - -contract Mor20FactoryL1 is BaseFactoryL1, Ownable { - address public arbitrumGateway; - - address public lZEnpointAddress; // L1 - uint256 public destinationChainId; // arbitrum - - address zroPaymentAddress; // LZ - uint16 l2EndpointId; - bytes adapterParams; - - constructor(address arbitrumGateway_, address lZEnpointAddress_, uint256 destinationChainId_) { - arbitrumGateway = arbitrumGateway_; - lZEnpointAddress = lZEnpointAddress_; - destinationChainId = destinationChainId_; - } - - function deployMor20OnL1(Mor20DeployParams calldata parameters_) external onlyOwner { - address distributionAddress_ = _deploy2(PoolType.DISTRIBUTION, parameters_.name); - - address l1SenderAddress_ = _deploy2(PoolType.L1_SENDER, parameters_.name); - - IDistribution(distributionAddress_).Distribution_init( - parameters_.depositToken, - l1SenderAddress_, - parameters_.poolsInfo - ); - - IL1Sender(l1SenderAddress_).L1Sender__init( - distributionAddress_, - IL1Sender.RewardTokenConfig( - lZEnpointAddress, - parameters_.messageReceiver, - l2EndpointId, - zroPaymentAddress, - adapterParams - ), - IL1Sender.DepositTokenConfig(parameters_.wrappedToken, arbitrumGateway, parameters_.tokenReceiver) - ); - - _addPool(PoolType.DISTRIBUTION, parameters_.name, distributionAddress_); - _addPool(PoolType.L1_SENDER, parameters_.name, distributionAddress_); - - emit Mor20Deployed(parameters_.name, distributionAddress_, l1SenderAddress_); - } - - function setDeployParams( - address arbitrumGateway_, - address lZEnpointAddress_, - uint256 destinationChainId_ - ) external onlyOwner { - arbitrumGateway = arbitrumGateway_; - lZEnpointAddress = lZEnpointAddress_; - destinationChainId = destinationChainId_; - } - - 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_) - ); - } -} diff --git a/contracts/L2/BaseFactoryL2.sol b/contracts/L2/BaseFactoryL2.sol deleted file mode 100644 index d27d7f9..0000000 --- a/contracts/L2/BaseFactoryL2.sol +++ /dev/null @@ -1,57 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; - -import {BaseFactory} from "../BaseFactory.sol"; - -import {IL2TokenReceiver} from "../interfaces/IL2TokenReceiver.sol"; - -abstract contract BaseFactoryL2 is BaseFactory { - using EnumerableSet for EnumerableSet.AddressSet; - - enum PoolType { - L2_MESSAGE_RECEIVER, - L2_TOKEN_RECEIVER, - REWARD_TOKEN - } - - struct Mor20PredictedAddressesL2 { - address l2MessageReceiver; - address l2TokenReceiver; - address rewardToken; - } - - struct Mor20DeployParams { - string name; - string symbol; - address rewardToken; - address rewardTokenDelegate; - ////// - address sender; - uint16 senderChainId; - ////// - address router_; - address nonfungiblePositionManager_; - IL2TokenReceiver.SwapParams firstSwapParams_; - IL2TokenReceiver.SwapParams secondSwapParams; - } - - event Mor20Deployed(string name, address l2MessageReceiver, address l2TokenReceiver, address rewardToken); - - function _predictPoolAddress(PoolType poolType_, bytes32 poolSalt_) internal view returns (address) { - return _predictPoolAddress(uint8(poolType_), poolSalt_); - } - - function _addPool(PoolType poolType_, address pool_) internal { - _pools[uint8(poolType_)].add(pool_); - } - - function _setNewImplementation(uint8 poolType_, address newImplementation_) internal { - _setNewImplementation(poolType_, newImplementation_); - } - - function _deploy2(PoolType poolType_, string memory name_) internal returns (address) { - return _deploy2(uint8(poolType_), name_); - } -} diff --git a/contracts/L2/CorePropertiesL2.sol b/contracts/L2/CorePropertiesL2.sol deleted file mode 100644 index 963adb1..0000000 --- a/contracts/L2/CorePropertiesL2.sol +++ /dev/null @@ -1,40 +0,0 @@ -// 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"; - -contract CorePropertiesL2 is UUPSUpgradeable, OwnableUpgradeable { - address public lZEnpointAddress; - address public lZGatewayAddress; - uint16 public l1ChainId; - - function __CorePropertiesL2_init( - address lZEnpointAddress_, - address lZGatewayAddress_, - uint16 l1ChainId_ - ) external initializer { - __Ownable_init(); - __UUPSUpgradeable_init(); - - lZEnpointAddress = lZEnpointAddress_; - lZGatewayAddress = lZGatewayAddress_; - l1ChainId = l1ChainId_; - } - - function setDeployParams( - address lZEnpointAddress_, - address lZGatewayAddress_, - uint16 l1ChainId_ - ) external onlyOwner { - lZEnpointAddress = lZEnpointAddress_; - lZGatewayAddress = lZGatewayAddress_; - l1ChainId = l1ChainId_; - } - - function getDeployParams() external view returns (address, address, uint16) { - return (lZEnpointAddress, lZGatewayAddress, l1ChainId); - } - - function _authorizeUpgrade(address) internal override onlyOwner {} -} diff --git a/contracts/L2/L2Factory.sol b/contracts/L2/L2Factory.sol new file mode 100644 index 0000000..c934f8c --- /dev/null +++ b/contracts/L2/L2Factory.sol @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Factory} from "../Factory.sol"; +import {MOR20} from "./MOR20.sol"; + +import {IL2MessageReceiver} from "../interfaces/L2/IL2MessageReceiver.sol"; +import {IL2TokenReceiverV2} from "../interfaces/L2/IL2TokenReceiverV2.sol"; +import {IMOR20} from "../interfaces/L2/IMOR20.sol"; +import {IOwnable} from "../interfaces/IOwnable.sol"; + +contract L2Factory is Factory { + enum PoolType { + L2_MESSAGE_RECEIVER, + L2_TOKEN_RECEIVER + } + + struct L2Params { + string protocolName; + string mor20Name; + string mor20Symbol; + } + + struct UniswapExternalDeps { + address router; + address nonfungiblePositionManager; + } + + struct LzExternalDeps { + address endpoint; + address oftEndpoint; + uint16 senderChainId; + } + + event Mor20Deployed(address token); + + UniswapExternalDeps public uniswapExternalDeps; + LzExternalDeps public lzExternalDeps; + + constructor() { + _disableInitializers(); + } + + function L2Factory_init() external initializer { + __Pausable_init(); + __Ownable_init(); + __UUPSUpgradeable_init(); + __Factory_init(); + } + + function setLzTokenExternalDeps(LzExternalDeps calldata lzExternalDeps_) external onlyOwner { + require(lzExternalDeps_.endpoint != address(0), "L2F: invalid LZ endpoint"); + require(lzExternalDeps_.oftEndpoint != address(0), "L2F: invalid LZ OFT endpoint"); + require(lzExternalDeps_.senderChainId != 0, "L2F: invalid chain ID"); + + lzExternalDeps = lzExternalDeps_; + } + + function setLzTokenExternalDeps(UniswapExternalDeps calldata uniswapExternalDeps_) external onlyOwner { + require(uniswapExternalDeps.router != address(0), "L2F: invalid UNI router"); + require(uniswapExternalDeps.nonfungiblePositionManager != address(0), "L2F: invalid NPM"); + + uniswapExternalDeps = uniswapExternalDeps_; + } + + function deploy(L2Params calldata l2Params_) external whenNotPaused { + address l2MessageReceiver = _deploy2(uint8(PoolType.L2_MESSAGE_RECEIVER), l2Params_.protocolName); + address l2TokenReceiverProxy = _deploy2(uint8(PoolType.L2_TOKEN_RECEIVER), l2Params_.protocolName); + + address mor20 = address( + new MOR20( + l2Params_.mor20Name, + l2Params_.mor20Symbol, + lzExternalDeps.oftEndpoint, + _msgSender(), + l2MessageReceiver + ) + ); + + emit Mor20Deployed(mor20); + + IL2MessageReceiver(l2MessageReceiver).L2MessageReceiver__init( + mor20, + IL2MessageReceiver.Config(lzExternalDeps.endpoint, address(0), lzExternalDeps.senderChainId) + ); + + IL2TokenReceiverV2(l2TokenReceiverProxy).L2TokenReceiver__init( + uniswapExternalDeps.router, + uniswapExternalDeps.nonfungiblePositionManager + ); + + IOwnable(l2MessageReceiver).transferOwnership(_msgSender()); + IOwnable(l2TokenReceiverProxy).transferOwnership(_msgSender()); + IOwnable(mor20).transferOwnership(_msgSender()); + } +} diff --git a/contracts/L2/L2MessageReceiver.sol b/contracts/L2/L2MessageReceiver.sol index 9ac3419..57df3ca 100644 --- a/contracts/L2/L2MessageReceiver.sol +++ b/contracts/L2/L2MessageReceiver.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; -import {ContextUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; -import {IERC20MOR} from "../interfaces/IERC20MOR.sol"; -import {IL2MessageReceiver} from "../interfaces/IL2MessageReceiver.sol"; +import {IMOR20} from "../interfaces/L2/IMOR20.sol"; +import {IL2MessageReceiver} from "../interfaces/L2/IL2MessageReceiver.sol"; -contract L2MessageReceiver is IL2MessageReceiver, Initializable, ContextUpgradeable { +contract L2MessageReceiver is IL2MessageReceiver, OwnableUpgradeable, UUPSUpgradeable { address public rewardToken; Config public config; @@ -23,6 +23,12 @@ contract L2MessageReceiver is IL2MessageReceiver, Initializable, ContextUpgradea config = config_; } + function setLzSender(address lzSender_) external onlyOwner { + require(lzSender_ != address(0), "L2MR: invalid sender"); + + config.sender = lzSender_; + } + function lzReceive( uint16 senderChainId_, bytes memory senderAndReceiverAddresses_, @@ -97,6 +103,8 @@ contract L2MessageReceiver is IL2MessageReceiver, Initializable, ContextUpgradea (address user_, uint256 amount_) = abi.decode(payload_, (address, uint256)); - IERC20MOR(rewardToken).mint(user_, amount_); + IMOR20(rewardToken).mint(user_, amount_); } + + function _authorizeUpgrade(address) internal view override onlyOwner {} } diff --git a/contracts/L2/L2TokenReceiver.sol b/contracts/L2/L2TokenReceiverV2.sol similarity index 74% rename from contracts/L2/L2TokenReceiver.sol rename to contracts/L2/L2TokenReceiverV2.sol index fbf9954..e1cf068 100644 --- a/contracts/L2/L2TokenReceiver.sol +++ b/contracts/L2/L2TokenReceiverV2.sol @@ -2,43 +2,37 @@ pragma solidity ^0.8.20; import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import {ISwapRouter} from "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol"; import {TransferHelper} from "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol"; -import {IL2TokenReceiver, IERC165, IERC721Receiver} from "../interfaces/IL2TokenReceiver.sol"; +import {IL2TokenReceiverV2, IERC165, IERC721Receiver} from "../interfaces/L2/IL2TokenReceiverV2.sol"; import {INonfungiblePositionManager} from "../interfaces/uniswap-v3/INonfungiblePositionManager.sol"; -contract L2TokenReceiver is IL2TokenReceiver, OwnableUpgradeable { +contract L2TokenReceiverV2 is IL2TokenReceiverV2, OwnableUpgradeable, UUPSUpgradeable { address public router; address public nonfungiblePositionManager; - SwapParams public firstSwapParams; SwapParams public secondSwapParams; + SwapParams public firstSwapParams; constructor() { _disableInitializers(); } - function L2TokenReceiver__init( - address router_, - address nonfungiblePositionManager_, - SwapParams memory firstSwapParams_, - SwapParams memory secondSwapParams_ - ) external initializer { + function L2TokenReceiver__init(address router_, address nonfungiblePositionManager_) external initializer { __Ownable_init(); + __UUPSUpgradeable_init(); router = router_; nonfungiblePositionManager = nonfungiblePositionManager_; - - _addAllowanceUpdateSwapParams(firstSwapParams_, true); - _addAllowanceUpdateSwapParams(secondSwapParams_, false); } function supportsInterface(bytes4 interfaceId_) external pure returns (bool) { return - interfaceId_ == type(IL2TokenReceiver).interfaceId || + interfaceId_ == type(IL2TokenReceiverV2).interfaceId || interfaceId_ == type(IERC721Receiver).interfaceId || interfaceId_ == type(IERC165).interfaceId; } @@ -59,7 +53,6 @@ contract L2TokenReceiver is IL2TokenReceiver, OwnableUpgradeable { } function withdrawToken(address recipient_, address token_, uint256 amount_) external onlyOwner { - // TODO: Add the cap for the amount TransferHelper.safeTransfer(token_, recipient_, amount_); } @@ -71,9 +64,9 @@ contract L2TokenReceiver is IL2TokenReceiver, OwnableUpgradeable { uint256 amountIn_, uint256 amountOutMinimum_, uint256 deadline_, - bool isEditFirstParams_ + bool isUseFirstSwapParams_ ) external onlyOwner returns (uint256) { - SwapParams memory params_ = _getSwapParams(isEditFirstParams_); + SwapParams memory params_ = _getSwapParams(isUseFirstSwapParams_); ISwapRouter.ExactInputSingleParams memory swapParams_ = ISwapRouter.ExactInputSingleParams({ tokenIn: params_.tokenIn, @@ -95,31 +88,11 @@ contract L2TokenReceiver is IL2TokenReceiver, OwnableUpgradeable { function increaseLiquidityCurrentRange( uint256 tokenId_, - uint256 depositTokenAmountAdd_, - uint256 rewardTokenAmountAdd_, - uint256 depositTokenAmountMin_, - uint256 rewardTokenAmountMin_ + uint256 amountAdd0_, + uint256 amountAdd1_, + uint256 amountMin0_, + uint256 amountMin1_ ) external onlyOwner returns (uint128 liquidity_, uint256 amount0_, uint256 amount1_) { - uint256 amountAdd0_; - uint256 amountAdd1_; - uint256 amountMin0_; - uint256 amountMin1_; - - (, , address token0_, , , , , , , , , ) = INonfungiblePositionManager(nonfungiblePositionManager).positions( - tokenId_ - ); - if (token0_ == secondSwapParams.tokenIn) { - amountAdd0_ = depositTokenAmountAdd_; - amountAdd1_ = rewardTokenAmountAdd_; - amountMin0_ = depositTokenAmountMin_; - amountMin1_ = rewardTokenAmountMin_; - } else { - amountAdd0_ = rewardTokenAmountAdd_; - amountAdd1_ = depositTokenAmountAdd_; - amountMin0_ = rewardTokenAmountMin_; - amountMin1_ = depositTokenAmountMin_; - } - INonfungiblePositionManager.IncreaseLiquidityParams memory params_ = INonfungiblePositionManager .IncreaseLiquidityParams({ tokenId: tokenId_, @@ -150,6 +123,10 @@ contract L2TokenReceiver is IL2TokenReceiver, OwnableUpgradeable { emit FeesCollected(tokenId_, amount0_, amount1_); } + function version() external pure returns (uint256) { + return 2; + } + function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4) { return this.onERC721Received.selector; } @@ -170,7 +147,9 @@ contract L2TokenReceiver is IL2TokenReceiver, OwnableUpgradeable { } } - function _getSwapParams(bool isEditFirstParams_) internal view returns (SwapParams memory) { - return isEditFirstParams_ ? firstSwapParams : secondSwapParams; + function _getSwapParams(bool isUseFirstSwapParams_) internal view returns (SwapParams memory) { + return isUseFirstSwapParams_ ? firstSwapParams : secondSwapParams; } + + function _authorizeUpgrade(address) internal view override onlyOwner {} } diff --git a/contracts/L2/ERC20MOR.sol b/contracts/L2/MOR20.sol similarity index 82% rename from contracts/L2/ERC20MOR.sol rename to contracts/L2/MOR20.sol index 30766b2..8ca8042 100644 --- a/contracts/L2/ERC20MOR.sol +++ b/contracts/L2/MOR20.sol @@ -3,9 +3,9 @@ pragma solidity ^0.8.20; import {OFT} from "../@layerzerolabs/lz-evm-oapp-v2/contracts/oft/OFT.sol"; -import {IERC20MOR, IERC20, IERC165, IOAppCore} from "../interfaces/IERC20MOR.sol"; +import {IMOR20, IERC20, IERC165, IOAppCore} from "../interfaces/L2/IMOR20.sol"; -contract ERC20MOR is IERC20MOR, OFT { +contract MOR20 is IMOR20, OFT { address private immutable _minter; constructor( @@ -22,7 +22,7 @@ contract ERC20MOR is IERC20MOR, OFT { function supportsInterface(bytes4 interfaceId_) external pure returns (bool) { return - interfaceId_ == type(IERC20MOR).interfaceId || + interfaceId_ == type(IMOR20).interfaceId || interfaceId_ == type(IERC20).interfaceId || interfaceId_ == type(IOAppCore).interfaceId || interfaceId_ == type(IERC165).interfaceId; @@ -33,7 +33,7 @@ contract ERC20MOR is IERC20MOR, OFT { } function mint(address account_, uint256 amount_) public { - require(_msgSender() == minter(), "ERC20MOR: invalid caller"); + require(_msgSender() == minter(), "MOR20: invalid caller"); _mint(account_, amount_); } diff --git a/contracts/L2/Mor20FactoryL2.sol b/contracts/L2/Mor20FactoryL2.sol deleted file mode 100644 index 6453073..0000000 --- a/contracts/L2/Mor20FactoryL2.sol +++ /dev/null @@ -1,96 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; - -import {BaseFactoryL2} from "./BaseFactoryL2.sol"; -import {CorePropertiesL2} from "./CorePropertiesL2.sol"; - -import {IL2TokenReceiver} from "../interfaces/IL2TokenReceiver.sol"; -import {IL2MessageReceiver} from "../interfaces/IL2MessageReceiver.sol"; - -import {RewardTokenDeployer} from "../libs/RewardTokenDeployer.sol"; - -contract Mor20FactoryL2 is BaseFactoryL2, Ownable { - CorePropertiesL2 public coreProperties; - - constructor(address coreProperties_) { - coreProperties = CorePropertiesL2(coreProperties_); - } - - function deployMor20OnL1(Mor20DeployParams calldata parameters_) external onlyOwner { - (address lZEnpointAddress_, address lZGatewayAddress_, uint16 l1ChainId_) = coreProperties.getDeployParams(); - - address l2MessageReceiverAddress_ = _deploy2(PoolType.L2_MESSAGE_RECEIVER, parameters_.name); - - address l2TokenReceiverAddress_ = _deploy2(PoolType.L2_TOKEN_RECEIVER, parameters_.name); - - address rewardTokenAddress_; - if (parameters_.rewardToken == address(0)) { - rewardTokenAddress_ = _deployRewardToken( - parameters_.name, - parameters_.symbol, - lZEnpointAddress_, - parameters_.rewardTokenDelegate, - l2MessageReceiverAddress_ - ); - } else { - rewardTokenAddress_ = parameters_.rewardToken; - } - - IL2MessageReceiver(l2MessageReceiverAddress_).L2MessageReceiver__init( - rewardTokenAddress_, - IL2MessageReceiver.Config(lZGatewayAddress_, parameters_.sender, l1ChainId_) - ); - - IL2TokenReceiver(l2TokenReceiverAddress_).L2TokenReceiver__init( - parameters_.router_, - parameters_.nonfungiblePositionManager_, - parameters_.firstSwapParams_, - parameters_.secondSwapParams - ); - - _addPool(PoolType.L2_MESSAGE_RECEIVER, l2MessageReceiverAddress_); - _addPool(PoolType.L2_TOKEN_RECEIVER, l2TokenReceiverAddress_); - _addPool(PoolType.REWARD_TOKEN, rewardTokenAddress_); - - emit Mor20Deployed(parameters_.name, l2MessageReceiverAddress_, l2TokenReceiverAddress_, rewardTokenAddress_); - } - - function setNewImplementations( - uint8[] memory poolTypes_, - address[] calldata newImplementations_ - ) external onlyOwner { - _setNewImplementations(poolTypes_, newImplementations_); - } - - function predictMor20Address( - address deployer_, - string calldata mor20Name_ - ) external view returns (Mor20PredictedAddressesL2 memory predictedAddresses) { - if (bytes(mor20Name_).length == 0) { - return predictedAddresses; - } - - bytes32 poolSalt_ = _calculatePoolSalt(deployer_, mor20Name_); - - return - Mor20PredictedAddressesL2( - _predictPoolAddress(PoolType.L2_MESSAGE_RECEIVER, poolSalt_), - _predictPoolAddress(PoolType.L2_TOKEN_RECEIVER, poolSalt_), - _predictPoolAddress(PoolType.REWARD_TOKEN, poolSalt_) - ); - } - - function _deployRewardToken( - string memory name_, - string memory symbol_, - address layerZeroEndpoint_, - address delegate_, - address minter_ - ) internal returns (address) { - bytes32 poolSalt_ = _calculatePoolSalt(tx.origin, name_); - - return RewardTokenDeployer.deployRewardToken(poolSalt_, name_, symbol_, layerZeroEndpoint_, delegate_, minter_); - } -} diff --git a/contracts/interfaces/IOwnable.sol b/contracts/interfaces/IOwnable.sol new file mode 100644 index 0000000..32fda58 --- /dev/null +++ b/contracts/interfaces/IOwnable.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +interface IOwnable { + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner_) external; +} diff --git a/contracts/interfaces/IDistribution.sol b/contracts/interfaces/L1/IDistribution.sol similarity index 100% rename from contracts/interfaces/IDistribution.sol rename to contracts/interfaces/L1/IDistribution.sol diff --git a/contracts/interfaces/IL1Sender.sol b/contracts/interfaces/L1/IL1Sender.sol similarity index 96% rename from contracts/interfaces/IL1Sender.sol rename to contracts/interfaces/L1/IL1Sender.sol index 003998d..611a369 100644 --- a/contracts/interfaces/IL1Sender.sol +++ b/contracts/interfaces/L1/IL1Sender.sol @@ -5,7 +5,7 @@ import {IERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; interface IL1Sender is IERC165 { /** - * The structure that stores the deposit token's data. + * The structure that stores the deposit token's data (stETH). * @param token The address of wrapped deposit token. * @param gateway The address of token's gateway. * @param receiver The address of wrapped token's receiver on L2. diff --git a/contracts/interfaces/IL2MessageReceiver.sol b/contracts/interfaces/L2/IL2MessageReceiver.sol similarity index 100% rename from contracts/interfaces/IL2MessageReceiver.sol rename to contracts/interfaces/L2/IL2MessageReceiver.sol diff --git a/contracts/interfaces/IL2TokenReceiver.sol b/contracts/interfaces/L2/IL2TokenReceiverV2.sol similarity index 82% rename from contracts/interfaces/IL2TokenReceiver.sol rename to contracts/interfaces/L2/IL2TokenReceiverV2.sol index 3ae9a93..47f9c4a 100644 --- a/contracts/interfaces/IL2TokenReceiver.sol +++ b/contracts/interfaces/L2/IL2TokenReceiverV2.sol @@ -7,7 +7,7 @@ import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Recei /** * This is Swap contract that swaps tokens using Uniswap V3. */ -interface IL2TokenReceiver is IERC165, IERC721Receiver { +interface IL2TokenReceiverV2 is IERC165, IERC721Receiver { /** * The structure that stores the swap params. * @param tokenIn The address of the token to swap from. @@ -64,19 +64,7 @@ interface IL2TokenReceiver is IERC165, IERC721Receiver { */ event FeesCollected(uint256 indexed tokenId, uint256 amount0, uint256 amount1); - /** - * The function to initialize the contract. - * @param router_ The address of the router. - * @param nonfungiblePositionManager_ The address of the nonfungible position manager. - * @param firstSwapParams_ The first path's part swap params. - * @param secondSwapParams_ The second path's part swap params. - */ - function L2TokenReceiver__init( - address router_, - address nonfungiblePositionManager_, - SwapParams memory firstSwapParams_, - SwapParams memory secondSwapParams_ - ) external; + function L2TokenReceiver__init(address router_, address nonfungiblePositionManager_) external; /** * The function to edit the swap params. @@ -90,14 +78,14 @@ interface IL2TokenReceiver is IERC165, IERC721Receiver { * @param amountIn_ The amount of tokens to swap. * @param amountOutMinimum_ The minimum amount of tokens to receive. * @param deadline_ The deadline for the swap. - * @param isEditFirstParams_ The flag to indicate if the swapParams is initial. + * @param isUseFirstSwapParams_ The flag to indicate if the swapParams is initial. * @return The amount of tokens received. */ function swap( uint256 amountIn_, uint256 amountOutMinimum_, uint256 deadline_, - bool isEditFirstParams_ + bool isUseFirstSwapParams_ ) external returns (uint256); /** @@ -119,10 +107,10 @@ interface IL2TokenReceiver is IERC165, IERC721Receiver { /** * The function to increase liquidity in the current price range. * @param tokenId The ID of the position. - * @param amountAdd0_ The amount of tokenIn to add. - * @param amountAdd1_ The amount of tokenOut to add. - * @param depositTokenAmountMin_ The minimum amount of deposit token to add. - * @param rewardTokenAmountMin_ The minimum amount of reward token to add. + * @param amountAdd0_ The amount of token0 to add. + * @param amountAdd1_ The amount of token1 to add. + * @param amountMin0_ The minimum amount of token0 to add. + * @param amountMin1_ The minimum amount of token1 to add. * @return liquidity_ The amount of liquidity added. * @return amount0_ The amount of token0 added. * @return amount1_ The amount of token1 added. @@ -131,8 +119,8 @@ interface IL2TokenReceiver is IERC165, IERC721Receiver { uint256 tokenId, uint256 amountAdd0_, uint256 amountAdd1_, - uint256 depositTokenAmountMin_, - uint256 rewardTokenAmountMin_ + uint256 amountMin0_, + uint256 amountMin1_ ) external returns (uint128 liquidity_, uint256 amount0_, uint256 amount1_); /** diff --git a/contracts/interfaces/IERC20MOR.sol b/contracts/interfaces/L2/IMOR20.sol similarity index 83% rename from contracts/interfaces/IERC20MOR.sol rename to contracts/interfaces/L2/IMOR20.sol index 4321c1d..fd98c06 100644 --- a/contracts/interfaces/IERC20MOR.sol +++ b/contracts/interfaces/L2/IMOR20.sol @@ -3,12 +3,12 @@ pragma solidity ^0.8.20; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; -import {IOAppCore} from ".././@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/interfaces/IOAppCore.sol"; +import {IOAppCore} from "../../@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/interfaces/IOAppCore.sol"; /** - * This is the interface for ERC20MOR token contract. The token is ERC20 burnable and Layer Zero OFT features. + * This is the interface for IMOR20 token contract. The token is ERC20 burnable and Layer Zero OFT features. */ -interface IERC20MOR is IERC20, IERC165 { +interface IMOR20 is IERC20, IERC165 { /** * The function to get the minter address. * @return The minter address. diff --git a/contracts/libs/RewardTokenDeployer.sol b/contracts/libs/RewardTokenDeployer.sol deleted file mode 100644 index 3aba355..0000000 --- a/contracts/libs/RewardTokenDeployer.sol +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import "@openzeppelin/contracts/utils/Create2.sol"; - -import "../L2/ERC20MOR.sol"; - -library RewardTokenDeployer { - function deployRewardToken( - bytes32 salt, - string memory name_, - string memory symbol_, - address layerZeroEndpoint_, - address delegate_, - address minter_ - ) external returns (address) { - ERC20MOR rewardToken = new ERC20MOR{salt: salt}(name_, symbol_, layerZeroEndpoint_, delegate_, minter_); - - return address(rewardToken); - } - - function predictRewardTokenAddress( - bytes32 salt, - string memory name_, - string memory symbol_, - address layerZeroEndpoint_, - address delegate_, - address minter_ - ) external view returns (address) { - bytes32 bytecodeHash = keccak256( - abi.encodePacked( - type(ERC20MOR).creationCode, - abi.encode(name_, symbol_, layerZeroEndpoint_, delegate_, minter_) - ) - ); - - return Create2.computeAddress(salt, bytecodeHash); - } -} From 2f08e6e66e51ad93f79059651fa6533a5e536b4b Mon Sep 17 00:00:00 2001 From: Ruslan Kasheparov Date: Mon, 13 May 2024 19:02:27 +0200 Subject: [PATCH 07/17] updated --- contracts/Factory.sol | 23 +- contracts/L1/Distribution.sol | 13 +- contracts/L1/FeeConfig.sol | 4 +- contracts/L1/L1Factory.sol | 42 +- contracts/L2/L2Factory.sol | 78 ++-- contracts/L2/L2MessageReceiver.sol | 7 +- ...okenReceiverV2.sol => L2TokenReceiver.sol} | 64 ++- contracts/L2/MOR20.sol | 49 ++- contracts/interfaces/IFactory.sol | 27 ++ contracts/interfaces/L1/IDistribution.sol | 13 +- contracts/interfaces/L1/IFeeConfig.sol | 50 +++ contracts/interfaces/L1/IL1Factory.sol | 103 +++++ contracts/interfaces/L1/IL1Sender.sol | 12 + contracts/interfaces/L2/IL2Factory.sol | 79 ++++ ...kenReceiverV2.sol => IL2TokenReceiver.sol} | 67 ++- contracts/interfaces/L2/IMOR20.sol | 7 +- .../INonfungiblePositionManager.sol | 12 + contracts/libs/MOR20Deployer.sol | 20 + contracts/mock/FactoryMock.sol | 21 + contracts/mock/FactoryMockV2.sol | 17 + contracts/mock/FeeConfigV2.sol | 12 + contracts/mock/L1FactoryV2.sol | 12 + contracts/mock/L2FactoryV2.sol | 12 + contracts/mock/L2TokenRecevierV2.sol | 12 + hardhat.config.ts | 3 +- package-lock.json | 4 +- package.json | 4 +- test/Factory.test.ts | 153 +++++++ test/L1/BaseFactoryL1.test.ts | 193 --------- test/L1/Distribution.test.ts | 289 +++++++------ test/L1/FeeConfig.test.ts | 137 +++++++ test/L1/L1Factory.test.ts | 326 +++++++++++++++ test/L1/L1Sender.test.ts | 381 +++++------------- test/L1/Mor20FactoryL1.test.ts | 188 --------- test/L2/L2Factory.test.ts | 302 ++++++++++++++ test/L2/L2MessageReceiver.test.ts | 223 ++++++---- test/L2/L2TokenReceiver.test.ts | 188 ++++----- test/L2/MOR20.test.ts | 130 ++++++ test/L2/MOROFT.test.ts | 113 ------ test/fork/L1Sender.fork.test.ts | 2 +- test/fork/L2TokenReceiver.fork.test.ts | 212 +++++++--- test/fork/L2TokenReceiverV2.fork.test.ts | 247 ------------ ...MOROFT.fork.test.ts => MOR20.fork.test.ts} | 18 +- test/helpers/helper.ts | 10 + 44 files changed, 2358 insertions(+), 1521 deletions(-) rename contracts/L2/{L2TokenReceiverV2.sol => L2TokenReceiver.sol} (74%) create mode 100644 contracts/interfaces/IFactory.sol create mode 100644 contracts/interfaces/L1/IFeeConfig.sol create mode 100644 contracts/interfaces/L1/IL1Factory.sol create mode 100644 contracts/interfaces/L2/IL2Factory.sol rename contracts/interfaces/L2/{IL2TokenReceiverV2.sol => IL2TokenReceiver.sol} (69%) create mode 100644 contracts/libs/MOR20Deployer.sol create mode 100644 contracts/mock/FactoryMock.sol create mode 100644 contracts/mock/FactoryMockV2.sol create mode 100644 contracts/mock/FeeConfigV2.sol create mode 100644 contracts/mock/L1FactoryV2.sol create mode 100644 contracts/mock/L2FactoryV2.sol create mode 100644 contracts/mock/L2TokenRecevierV2.sol create mode 100644 test/Factory.test.ts delete mode 100644 test/L1/BaseFactoryL1.test.ts create mode 100644 test/L1/FeeConfig.test.ts create mode 100644 test/L1/L1Factory.test.ts delete mode 100644 test/L1/Mor20FactoryL1.test.ts create mode 100644 test/L2/L2Factory.test.ts create mode 100644 test/L2/MOR20.test.ts delete mode 100644 test/L2/MOROFT.test.ts delete mode 100644 test/fork/L2TokenReceiverV2.fork.test.ts rename test/fork/{MOROFT.fork.test.ts => MOR20.fork.test.ts} (87%) create mode 100644 test/helpers/helper.ts diff --git a/contracts/Factory.sol b/contracts/Factory.sol index d1189f5..a615504 100644 --- a/contracts/Factory.sol +++ b/contracts/Factory.sol @@ -6,16 +6,9 @@ import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/U import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; -abstract contract Factory is OwnableUpgradeable, PausableUpgradeable, UUPSUpgradeable { - /** - * The event is emitted when the proxy is deployed. - * @param proxy The proxy address. - * @param implementation The implementation. - * @param poolType The `poolType`. - * @param poolName The `poolName`. - */ - event ProxyDeployed(address proxy, address indexed implementation, uint8 indexed poolType, string poolName); +import {IFactory} from "./interfaces/IFactory.sol"; +abstract contract Factory is IFactory, OwnableUpgradeable, PausableUpgradeable, UUPSUpgradeable { mapping(uint8 => address) internal _implementations; mapping(bytes32 => bool) private _usedSalts; @@ -28,10 +21,6 @@ abstract contract Factory is OwnableUpgradeable, PausableUpgradeable, UUPSUpgrad function __Factory_init() internal onlyInitializing {} - function __Factory_init_unchained() internal onlyInitializing { - _pause(); - } - /** * @notice Returns contract to normal state. */ @@ -74,13 +63,13 @@ abstract contract Factory is OwnableUpgradeable, PausableUpgradeable, UUPSUpgrad * @return proxy the proxy address for the `poolType_`. */ function _deploy2(uint8 poolType_, string memory poolName_) internal returns (address) { - require(bytes(poolName_).length != 0, "BF: 'poolName_' is empty"); - bytes32 salt_ = keccak256(abi.encodePacked(_msgSender(), poolName_)); + require(bytes(poolName_).length != 0, "F: poolName_ is empty"); + bytes32 salt_ = keccak256(abi.encodePacked(_msgSender(), poolName_, poolType_)); address implementation_ = _implementations[poolType_]; - require(implementation_ != address(0), "BF: implementation not found"); + require(implementation_ != address(0), "F: implementation not found"); - require(!_usedSalts[salt_], "BF: salt used"); + require(!_usedSalts[salt_], "F: salt used"); _usedSalts[salt_] = true; address proxy_ = address(new ERC1967Proxy{salt: salt_}(getImplementation(poolType_), bytes(""))); diff --git a/contracts/L1/Distribution.sol b/contracts/L1/Distribution.sol index ec9fe51..b37fe86 100644 --- a/contracts/L1/Distribution.sol +++ b/contracts/L1/Distribution.sol @@ -10,9 +10,8 @@ import {PRECISION} from "@solarity/solidity-lib/utils/Globals.sol"; import {LinearDistributionIntervalDecrease} from "../libs/LinearDistributionIntervalDecrease.sol"; import {IDistribution} from "../interfaces/L1/IDistribution.sol"; -import {L1Sender} from "./L1Sender.sol"; - -import {FeeConfig} from "./FeeConfig.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; @@ -57,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(); @@ -68,6 +68,7 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable { depositToken = depositToken_; l1Sender = l1Sender_; + feeConfig = feeConfig_; } /**********************************************************************************************/ @@ -183,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_); } @@ -336,7 +337,7 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable { uint256 overplus_ = overplus(); require(overplus_ > 0, "DS: overplus is zero"); - (uint256 feePercent_, address treasuryAddress_) = FeeConfig(feeConfig).getFeeAndTreasury(address(this)); + (uint256 feePercent_, address treasuryAddress_) = IFeeConfig(feeConfig).getFeeAndTreasury(address(this)); uint256 fee_ = (overplus_ * feePercent_) / PRECISION; if (fee_ != 0) { @@ -347,7 +348,7 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable { 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_ diff --git a/contracts/L1/FeeConfig.sol b/contracts/L1/FeeConfig.sol index 2b94069..a7a0689 100644 --- a/contracts/L1/FeeConfig.sol +++ b/contracts/L1/FeeConfig.sol @@ -6,7 +6,9 @@ import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/U import {PRECISION} from "@solarity/solidity-lib/utils/Globals.sol"; -contract FeeConfig is OwnableUpgradeable, UUPSUpgradeable { +import {IFeeConfig} from "../interfaces/L1/IFeeConfig.sol"; + +contract FeeConfig is IFeeConfig, OwnableUpgradeable, UUPSUpgradeable { address public treasury; uint256 public baseFee; diff --git a/contracts/L1/L1Factory.sol b/contracts/L1/L1Factory.sol index 8805106..0b15a18 100644 --- a/contracts/L1/L1Factory.sol +++ b/contracts/L1/L1Factory.sol @@ -1,40 +1,15 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import {Factory} from "../Factory.sol"; - 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"; -contract L1Factory is Factory { - enum PoolType { - DISTRIBUTION, - L1_SENDER - } - - struct L1Params { - string protocolName; - IDistribution.Pool[] poolsInfo; - address l2TokenReceiver; - address l2MessageReceiver; - } - - struct DepositTokenExternalDeps { - address token; - address wToken; - } - - struct LzExternalDeps { - address endpoint; - address zroPaymentAddress; - bytes adapterParams; - uint16 destinationChainId; - } +import {Factory} from "../Factory.sol"; - struct ArbExternalDeps { - address endpoint; - } +contract L1Factory is IL1Factory, Factory { + address public feeConfig; DepositTokenExternalDeps public depositTokenExternalDeps; ArbExternalDeps public arbExternalDeps; @@ -60,14 +35,14 @@ contract L1Factory is Factory { depositTokenExternalDeps = depositTokenExternalDeps_; } - function setLzTokenExternalDeps(LzExternalDeps calldata lzExternalDeps_) external onlyOwner { + 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 setArbTokenExternalDeps(ArbExternalDeps calldata arbExternalDeps_) external onlyOwner { + function setArbExternalDeps(ArbExternalDeps calldata arbExternalDeps_) external onlyOwner { require(arbExternalDeps_.endpoint != address(0), "L1F: invalid ARB endpoint"); arbExternalDeps = arbExternalDeps_; @@ -80,6 +55,7 @@ contract L1Factory is Factory { IDistribution(distributionProxy_).Distribution_init( depositTokenExternalDeps.token, l1SenderProxy_, + feeConfig, l1Params_.poolsInfo ); @@ -99,6 +75,10 @@ contract L1Factory is Factory { IL1Sender(l1SenderProxy_).L1Sender__init(distributionProxy_, lzConfig_, arbConfig); + if (l1Params_.isNotUpgradeable) { + IDistribution(distributionProxy_).removeUpgradeability(); + } + IOwnable(distributionProxy_).transferOwnership(_msgSender()); IOwnable(l1SenderProxy_).transferOwnership(_msgSender()); } diff --git a/contracts/L2/L2Factory.sol b/contracts/L2/L2Factory.sol index c934f8c..ef17d33 100644 --- a/contracts/L2/L2Factory.sol +++ b/contracts/L2/L2Factory.sol @@ -1,39 +1,16 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import {Factory} from "../Factory.sol"; -import {MOR20} from "./MOR20.sol"; - import {IL2MessageReceiver} from "../interfaces/L2/IL2MessageReceiver.sol"; -import {IL2TokenReceiverV2} from "../interfaces/L2/IL2TokenReceiverV2.sol"; -import {IMOR20} from "../interfaces/L2/IMOR20.sol"; +import {IL2TokenReceiver} from "../interfaces/L2/IL2TokenReceiver.sol"; +import {IL2Factory} from "../interfaces/L2/IL2Factory.sol"; import {IOwnable} from "../interfaces/IOwnable.sol"; +import {IMOR20} from "../interfaces/L2/IMOR20.sol"; -contract L2Factory is Factory { - enum PoolType { - L2_MESSAGE_RECEIVER, - L2_TOKEN_RECEIVER - } - - struct L2Params { - string protocolName; - string mor20Name; - string mor20Symbol; - } - - struct UniswapExternalDeps { - address router; - address nonfungiblePositionManager; - } - - struct LzExternalDeps { - address endpoint; - address oftEndpoint; - uint16 senderChainId; - } - - event Mor20Deployed(address token); +import {Factory} from "../Factory.sol"; +import {MOR20Deployer} from "../libs/MOR20Deployer.sol"; +contract L2Factory is IL2Factory, Factory { UniswapExternalDeps public uniswapExternalDeps; LzExternalDeps public lzExternalDeps; @@ -48,7 +25,7 @@ contract L2Factory is Factory { __Factory_init(); } - function setLzTokenExternalDeps(LzExternalDeps calldata lzExternalDeps_) external onlyOwner { + function setLzExternalDeps(LzExternalDeps calldata lzExternalDeps_) external onlyOwner { require(lzExternalDeps_.endpoint != address(0), "L2F: invalid LZ endpoint"); require(lzExternalDeps_.oftEndpoint != address(0), "L2F: invalid LZ OFT endpoint"); require(lzExternalDeps_.senderChainId != 0, "L2F: invalid chain ID"); @@ -56,41 +33,44 @@ contract L2Factory is Factory { lzExternalDeps = lzExternalDeps_; } - function setLzTokenExternalDeps(UniswapExternalDeps calldata uniswapExternalDeps_) external onlyOwner { - require(uniswapExternalDeps.router != address(0), "L2F: invalid UNI router"); - require(uniswapExternalDeps.nonfungiblePositionManager != address(0), "L2F: invalid NPM"); + function setUniswapExternalDeps(UniswapExternalDeps calldata uniswapExternalDeps_) external onlyOwner { + require(uniswapExternalDeps_.router != address(0), "L2F: invalid UNI router"); + require(uniswapExternalDeps_.nonfungiblePositionManager != address(0), "L2F: invalid NPM"); uniswapExternalDeps = uniswapExternalDeps_; } function deploy(L2Params calldata l2Params_) external whenNotPaused { address l2MessageReceiver = _deploy2(uint8(PoolType.L2_MESSAGE_RECEIVER), l2Params_.protocolName); - address l2TokenReceiverProxy = _deploy2(uint8(PoolType.L2_TOKEN_RECEIVER), l2Params_.protocolName); - - address mor20 = address( - new MOR20( - l2Params_.mor20Name, - l2Params_.mor20Symbol, - lzExternalDeps.oftEndpoint, - _msgSender(), - l2MessageReceiver - ) + address l2TokenReceiver = _deploy2(uint8(PoolType.L2_TOKEN_RECEIVER), l2Params_.protocolName); + + address mor20 = MOR20Deployer.deployMOR20( + l2Params_.mor20Name, + l2Params_.mor20Symbol, + lzExternalDeps.oftEndpoint, + _msgSender(), + l2MessageReceiver ); - - emit Mor20Deployed(mor20); + deployedProxies[_msgSender()][l2Params_.protocolName][uint8(PoolType.MOR20)] = mor20; IL2MessageReceiver(l2MessageReceiver).L2MessageReceiver__init( mor20, IL2MessageReceiver.Config(lzExternalDeps.endpoint, address(0), lzExternalDeps.senderChainId) ); - IL2TokenReceiverV2(l2TokenReceiverProxy).L2TokenReceiver__init( + IL2TokenReceiver(l2TokenReceiver).L2TokenReceiver__init( uniswapExternalDeps.router, - uniswapExternalDeps.nonfungiblePositionManager + uniswapExternalDeps.nonfungiblePositionManager, + l2Params_.firstSwapParams_, + IL2TokenReceiver.SwapParams( + l2Params_.firstSwapParams_.tokenOut, + mor20, + l2Params_.secondSwapFee, + l2Params_.secondSwapSqrtPriceLimitX96 + ) ); IOwnable(l2MessageReceiver).transferOwnership(_msgSender()); - IOwnable(l2TokenReceiverProxy).transferOwnership(_msgSender()); - IOwnable(mor20).transferOwnership(_msgSender()); + IOwnable(l2TokenReceiver).transferOwnership(_msgSender()); } } diff --git a/contracts/L2/L2MessageReceiver.sol b/contracts/L2/L2MessageReceiver.sol index 57df3ca..9825669 100644 --- a/contracts/L2/L2MessageReceiver.sol +++ b/contracts/L2/L2MessageReceiver.sol @@ -19,6 +19,9 @@ contract L2MessageReceiver is IL2MessageReceiver, OwnableUpgradeable, UUPSUpgrad } function L2MessageReceiver__init(address rewardToken_, Config calldata config_) external initializer { + __Ownable_init(); + __UUPSUpgradeable_init(); + rewardToken = rewardToken_; config = config_; } @@ -60,10 +63,10 @@ contract L2MessageReceiver is IL2MessageReceiver, OwnableUpgradeable, UUPSUpgrad require(payloadHash_ != bytes32(0), "L2MR: no stored message"); require(keccak256(payload_) == payloadHash_, "L2MR: invalid payload"); - _nonblockingLzReceive(senderChainId_, senderAndReceiverAddresses_, payload_); - delete failedMessages[senderChainId_][senderAndReceiverAddresses_][nonce_]; + _nonblockingLzReceive(senderChainId_, senderAndReceiverAddresses_, payload_); + emit RetryMessageSuccess(senderChainId_, senderAndReceiverAddresses_, nonce_, payload_); } diff --git a/contracts/L2/L2TokenReceiverV2.sol b/contracts/L2/L2TokenReceiver.sol similarity index 74% rename from contracts/L2/L2TokenReceiverV2.sol rename to contracts/L2/L2TokenReceiver.sol index e1cf068..b28a1bc 100644 --- a/contracts/L2/L2TokenReceiverV2.sol +++ b/contracts/L2/L2TokenReceiver.sol @@ -8,31 +8,39 @@ import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Own import {ISwapRouter} from "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol"; import {TransferHelper} from "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol"; -import {IL2TokenReceiverV2, IERC165, IERC721Receiver} from "../interfaces/L2/IL2TokenReceiverV2.sol"; +import {IL2TokenReceiver, IERC165, IERC721Receiver} from "../interfaces/L2/IL2TokenReceiver.sol"; import {INonfungiblePositionManager} from "../interfaces/uniswap-v3/INonfungiblePositionManager.sol"; -contract L2TokenReceiverV2 is IL2TokenReceiverV2, OwnableUpgradeable, UUPSUpgradeable { +contract L2TokenReceiver is IL2TokenReceiver, OwnableUpgradeable, UUPSUpgradeable { address public router; address public nonfungiblePositionManager; - SwapParams public secondSwapParams; SwapParams public firstSwapParams; + SwapParams public secondSwapParams; constructor() { _disableInitializers(); } - function L2TokenReceiver__init(address router_, address nonfungiblePositionManager_) external initializer { + function L2TokenReceiver__init( + address router_, + address nonfungiblePositionManager_, + SwapParams memory firstSwapParams_, + SwapParams memory secondSwapParams_ + ) external initializer { __Ownable_init(); __UUPSUpgradeable_init(); router = router_; nonfungiblePositionManager = nonfungiblePositionManager_; + + _addAllowanceUpdateSwapParams(firstSwapParams_, true); + _addAllowanceUpdateSwapParams(secondSwapParams_, false); } function supportsInterface(bytes4 interfaceId_) external pure returns (bool) { return - interfaceId_ == type(IL2TokenReceiverV2).interfaceId || + interfaceId_ == type(IL2TokenReceiver).interfaceId || interfaceId_ == type(IERC721Receiver).interfaceId || interfaceId_ == type(IERC165).interfaceId; } @@ -88,18 +96,18 @@ contract L2TokenReceiverV2 is IL2TokenReceiverV2, OwnableUpgradeable, UUPSUpgrad function increaseLiquidityCurrentRange( uint256 tokenId_, - uint256 amountAdd0_, - uint256 amountAdd1_, - uint256 amountMin0_, - uint256 amountMin1_ + uint256 amount0Add_, + uint256 amount1Add_, + uint256 amount0Min_, + uint256 amount1Min_ ) external onlyOwner returns (uint128 liquidity_, uint256 amount0_, uint256 amount1_) { INonfungiblePositionManager.IncreaseLiquidityParams memory params_ = INonfungiblePositionManager .IncreaseLiquidityParams({ tokenId: tokenId_, - amount0Desired: amountAdd0_, - amount1Desired: amountAdd1_, - amount0Min: amountMin0_, - amount1Min: amountMin1_, + amount0Desired: amount0Add_, + amount1Desired: amount1Add_, + amount0Min: amount0Min_, + amount1Min: amount1Min_, deadline: block.timestamp }); @@ -107,10 +115,32 @@ contract L2TokenReceiverV2 is IL2TokenReceiverV2, OwnableUpgradeable, UUPSUpgrad params_ ); - emit LiquidityIncreased(tokenId_, amount0_, amount1_, liquidity_, amountMin0_, amountMin1_); + emit LiquidityIncreased(tokenId_, amount0_, amount1_, liquidity_, amount0Min_, amount1Min_); + } + + function decreaseLiquidityCurrentRange( + uint256 tokenId_, + uint128 liquidity_, + uint256 amount0Min_, + uint256 amount1Min_ + ) external onlyOwner returns (uint256 amount0_, uint256 amount1_) { + INonfungiblePositionManager.DecreaseLiquidityParams memory params_ = INonfungiblePositionManager + .DecreaseLiquidityParams({ + tokenId: tokenId_, + liquidity: liquidity_, + amount0Min: amount0Min_, + amount1Min: amount1Min_, + deadline: block.timestamp + }); + + (amount0_, amount1_) = INonfungiblePositionManager(nonfungiblePositionManager).decreaseLiquidity(params_); + + collectFees(tokenId_); + + emit LiquidityDecreased(tokenId_, amount0_, amount1_, liquidity_, amount0Min_, amount1Min_); } - function collectFees(uint256 tokenId_) external returns (uint256 amount0_, uint256 amount1_) { + function collectFees(uint256 tokenId_) public returns (uint256 amount0_, uint256 amount1_) { INonfungiblePositionManager.CollectParams memory params_ = INonfungiblePositionManager.CollectParams({ tokenId: tokenId_, recipient: address(this), @@ -123,10 +153,6 @@ contract L2TokenReceiverV2 is IL2TokenReceiverV2, OwnableUpgradeable, UUPSUpgrad emit FeesCollected(tokenId_, amount0_, amount1_); } - function version() external pure returns (uint256) { - return 2; - } - function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4) { return this.onERC721Received.selector; } diff --git a/contracts/L2/MOR20.sol b/contracts/L2/MOR20.sol index 8ca8042..da0f46f 100644 --- a/contracts/L2/MOR20.sol +++ b/contracts/L2/MOR20.sol @@ -6,7 +6,7 @@ import {OFT} from "../@layerzerolabs/lz-evm-oapp-v2/contracts/oft/OFT.sol"; import {IMOR20, IERC20, IERC165, IOAppCore} from "../interfaces/L2/IMOR20.sol"; contract MOR20 is IMOR20, OFT { - address private immutable _minter; + mapping(address => bool) public isMinter; constructor( string memory name_, @@ -15,11 +15,21 @@ contract MOR20 is IMOR20, OFT { address delegate_, address minter_ ) OFT(name_, symbol_, layerZeroEndpoint_, delegate_) { - _minter = minter_; + require(minter_ != address(0), "MOR20: invalid minter"); + + isMinter[minter_] = true; transferOwnership(delegate_); } + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ function supportsInterface(bytes4 interfaceId_) external pure returns (bool) { return interfaceId_ == type(IMOR20).interfaceId || @@ -28,20 +38,49 @@ contract MOR20 is IMOR20, OFT { interfaceId_ == type(IERC165).interfaceId; } - function minter() public view returns (address) { - return _minter; + /** + * @notice The function update `minter` addresses. + * @param minter_ The upadted minter address. + * @param status_ The new status. True or false. + */ + function updateMinter(address minter_, bool status_) external onlyOwner { + isMinter[minter_] = status_; } + /** + * @notice The function to mint tokens. + * @param account_ The address of the account to mint tokens to. + * @param amount_ The amount of tokens to mint. + */ function mint(address account_, uint256 amount_) public { - require(_msgSender() == minter(), "MOR20: invalid caller"); + require(isMinter[_msgSender()], "MOR20: invalid caller"); _mint(account_, amount_); } + /** + * @notice The function to destroys `amount` tokens from the caller. + * See {ERC20-_burn}. + * @param amount_ The amount of tokens to burn. + */ function burn(uint256 amount_) public { _burn(_msgSender(), amount_); } + /** + * @notice The function to destroys `amount` tokens from `account`, deducting from the caller's + * allowance. + * + * See {ERC20-_burn} and {ERC20-allowance}. + * + * Requirements: + * + * - the caller must have allowance for ``accounts``'s tokens of at least + * `amount`. + * + * @param account_ The address of the account to burn tokens from. + * @param amount_ The amount of tokens to burn. + */ function burnFrom(address account_, uint256 amount_) public { _spendAllowance(account_, _msgSender(), amount_); _burn(account_, amount_); diff --git a/contracts/interfaces/IFactory.sol b/contracts/interfaces/IFactory.sol new file mode 100644 index 0000000..c693972 --- /dev/null +++ b/contracts/interfaces/IFactory.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +interface IFactory { + /** + * The event is emitted when the proxy is deployed. + * @param proxy The proxy address. + * @param implementation The implementation. + * @param poolType The `poolType`. + * @param poolName The `poolName`. + */ + event ProxyDeployed(address proxy, address indexed implementation, uint8 indexed poolType, string poolName); + + /** + * The function to set the 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_) external; + + /** + * The function to get the implementation of the specific pools. + * @param poolType_ The type of the pools. + * @return The implementation which the pool points to. + */ + function getImplementation(uint8 poolType_) external view returns (address); +} diff --git a/contracts/interfaces/L1/IDistribution.sol b/contracts/interfaces/L1/IDistribution.sol index 72638e3..ebf81de 100644 --- a/contracts/interfaces/L1/IDistribution.sol +++ b/contracts/interfaces/L1/IDistribution.sol @@ -104,9 +104,15 @@ interface IDistribution { * The function to initialize the contract. * @param depositToken_ The address of deposit token. * @param l1Sender_ The address of bridge contract. + * @param feeConfig_ The address of fee config contract. * @param poolsInfo_ The array of initial pools. */ - function Distribution_init(address depositToken_, address l1Sender_, Pool[] calldata poolsInfo_) external; + function Distribution_init( + address depositToken_, + address l1Sender_, + address feeConfig_, + Pool[] calldata poolsInfo_ + ) external; /** * The function to create a new pool. @@ -186,6 +192,11 @@ interface IDistribution { uint256 maxSubmissionCost_ ) external payable returns (bytes memory); + /** + * The function to remove the upgradeability of the contract. + */ + function removeUpgradeability() external; + /** * The function to get the address of deposit token. * @return The address of deposit token. diff --git a/contracts/interfaces/L1/IFeeConfig.sol b/contracts/interfaces/L1/IFeeConfig.sol new file mode 100644 index 0000000..fdab411 --- /dev/null +++ b/contracts/interfaces/L1/IFeeConfig.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +/** + * This is FeeConfig contract that stores all the fees and treasury data. + */ +interface IFeeConfig { + /** + * The function that initializes the contract. + * @param treasury_ The treasury address. + * @param baseFee_ The base fee. + */ + function __FeeConfig_init(address treasury_, uint256 baseFee_) external; + + /** + * The function that returns the treasury address. + */ + function treasury() external view returns (address); + + /** + * The function that returns the base fee. + */ + function baseFee() external view returns (uint256); + + /** + * The function that returns the fee for the sender. + * @dev If the fee is 0, the base fee is used. + */ + function fees(address sender_) external view returns (uint256); + + /** + * The function that returns the fee and treasury address for the sender. + */ + function getFeeAndTreasury(address sender_) external view returns (uint256, address); + + /** + * The function that sets the fee for the sender. + */ + function setFee(address sender_, uint256 fee_) external; + + /** + * The function that sets the treasury address. + */ + function setTreasury(address treasury_) external; + + /** + * The function that sets the base fee. + */ + function setBaseFee(uint256 baseFee_) external; +} diff --git a/contracts/interfaces/L1/IL1Factory.sol b/contracts/interfaces/L1/IL1Factory.sol new file mode 100644 index 0000000..cd868b3 --- /dev/null +++ b/contracts/interfaces/L1/IL1Factory.sol @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {IDistribution} from "./IDistribution.sol"; + +/** + * This is L1Factory contract that deploys the L1 contracts. + */ +interface IL1Factory { + /** + * The struct that represents the deployed L1 contract. + */ + enum PoolType { + DISTRIBUTION, + L1_SENDER + } + + /** + * The struct that represents the parameters for + * deploying specific L1 contracts. + * @param protocolName The protocol name. + * @param isNotUpgradeable The flag that indicates if the contract is not upgradeable. + * @param poolsInfo The pools information. + * @param l2TokenReceiver The L2 token receiver address. + * @param l2MessageReceiver The L2 message receiver address. + */ + struct L1Params { + string protocolName; + bool isNotUpgradeable; + IDistribution.Pool[] poolsInfo; + address l2TokenReceiver; + address l2MessageReceiver; + } + + /** + * The struct that represents the external dependencies for the deposit token. + * @param token The token address. + * @param wToken The wrapped token address. + */ + struct DepositTokenExternalDeps { + address token; + address wToken; + } + + /** + * The struct that represents the external dependencies for the LZ contract. + * @param endpoint The endpoint address. + * @param zroPaymentAddress The ZRO payment address. + * @param adapterParams The adapter parameters. + * @param destinationChainId The destination chain ID. + */ + struct LzExternalDeps { + address endpoint; + address zroPaymentAddress; + bytes adapterParams; + uint16 destinationChainId; + } + + /** + * The struct that represents the external dependencies for the Arbitrub contract. + * @param endpoint The endpoint address. + */ + struct ArbExternalDeps { + address endpoint; + } + + /** + * The function that initializes the contract. + */ + function L1Factory_init() external; + + /** + * The function to get fee config address. + * @return The fee config address. + */ + function feeConfig() external view returns (address); + + /** + * The function that sets the deposit token external dependencies. + * @param depositTokenExternalDeps_ The deposit token external dependencies. + */ + function setDepositTokenExternalDeps( + IL1Factory.DepositTokenExternalDeps calldata depositTokenExternalDeps_ + ) external; + + /** + * The function that sets the LZ external dependencies. + * @param lzExternalDeps_ The LZ external dependencies. + */ + function setLzExternalDeps(IL1Factory.LzExternalDeps calldata lzExternalDeps_) external; + + /** + * The function that sets the Arbitrum external dependencies. + * @param arbExternalDeps_ The Arbitrum external dependencies. + */ + function setArbExternalDeps(IL1Factory.ArbExternalDeps calldata arbExternalDeps_) external; + + /** + * The function that deploys the L1 contracts. + * @param l1Params_ The L1 parameters. + */ + function deploy(IL1Factory.L1Params calldata l1Params_) external; +} diff --git a/contracts/interfaces/L1/IL1Sender.sol b/contracts/interfaces/L1/IL1Sender.sol index 611a369..a7c3f46 100644 --- a/contracts/interfaces/L1/IL1Sender.sol +++ b/contracts/interfaces/L1/IL1Sender.sol @@ -56,4 +56,16 @@ interface IL1Sender is IERC165 { * @param refundTo_ The address to refund the overpaid gas. */ function sendMintMessage(address user_, uint256 amount_, address refundTo_) external payable; + + /** + * The function to set the deposit token to the L2. + * @param gasLimit_ The gas limit for the transaction. + * @param maxFeePerGas_ The maximum fee per gas for the transaction. + * @param maxSubmissionCost_ The maximum submission cost for the transaction. + */ + function sendDepositToken( + uint256 gasLimit_, + uint256 maxFeePerGas_, + uint256 maxSubmissionCost_ + ) external payable returns (bytes memory); } diff --git a/contracts/interfaces/L2/IL2Factory.sol b/contracts/interfaces/L2/IL2Factory.sol new file mode 100644 index 0000000..6017220 --- /dev/null +++ b/contracts/interfaces/L2/IL2Factory.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {IL2TokenReceiver} from "./IL2TokenReceiver.sol"; + +interface IL2Factory { + /** + * The enum that represents the deployed L2 contract. + */ + enum PoolType { + L2_MESSAGE_RECEIVER, + L2_TOKEN_RECEIVER, + MOR20 + } + + /** + * The struct that represents the parameters for + * deploying specific L2 contracts. + * @param protocolName The protocol name. + * @param mor20Name The MOR20 name. + * @param mor20Symbol The MOR20 symbol. + * @param firstSwapParams_ The first swap parameters. + * @param secondSwapFee The second swap fee. + * @param secondSwapSqrtPriceLimitX96 The second swap square root price limit. + */ + struct L2Params { + string protocolName; + string mor20Name; + string mor20Symbol; + IL2TokenReceiver.SwapParams firstSwapParams_; + uint24 secondSwapFee; + uint160 secondSwapSqrtPriceLimitX96; + } + + /** + * The struct that represents the external dependencies for the Uniswap contract. + * @param router The router address. + * @param nonfungiblePositionManager The nonfungible position manager address. + */ + struct UniswapExternalDeps { + address router; + address nonfungiblePositionManager; + } + + /** + * The struct that represents the external dependencies for the LZ contract. + * @param endpoint The endpoint address. + * @param oftEndpoint The OFT endpoint address. + * @param senderChainId The sender chain ID. + */ + struct LzExternalDeps { + address endpoint; + address oftEndpoint; + uint16 senderChainId; + } + + /** + * The function that initializes the contract. + */ + function L2Factory_init() external; + + /** + * The function that sets the LZ external dependencies. + * @param lzExternalDeps_ The LZ external dependencies. + */ + function setLzExternalDeps(LzExternalDeps calldata lzExternalDeps_) external; + + /** + * The function that sets the Uniswap external dependencies. + * @param uniswapExternalDeps_ The Uniswap external dependencies. + */ + function setUniswapExternalDeps(UniswapExternalDeps calldata uniswapExternalDeps_) external; + + /** + * The function that deploys the L2 contracts. + * @param l2Params_ The L2 parameters. + */ + function deploy(L2Params calldata l2Params_) external; +} diff --git a/contracts/interfaces/L2/IL2TokenReceiverV2.sol b/contracts/interfaces/L2/IL2TokenReceiver.sol similarity index 69% rename from contracts/interfaces/L2/IL2TokenReceiverV2.sol rename to contracts/interfaces/L2/IL2TokenReceiver.sol index 47f9c4a..8aea131 100644 --- a/contracts/interfaces/L2/IL2TokenReceiverV2.sol +++ b/contracts/interfaces/L2/IL2TokenReceiver.sol @@ -7,7 +7,7 @@ import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Recei /** * This is Swap contract that swaps tokens using Uniswap V3. */ -interface IL2TokenReceiverV2 is IERC165, IERC721Receiver { +interface IL2TokenReceiver is IERC165, IERC721Receiver { /** * The structure that stores the swap params. * @param tokenIn The address of the token to swap from. @@ -56,6 +56,24 @@ interface IL2TokenReceiverV2 is IERC165, IERC721Receiver { uint256 amount1Min ); + /** + * The event that is emitted when the liquidity is decreased. + * @param tokenId The ID of the position. + * @param amount0 The amount of token0 received back. + * @param amount1 The amount of token1 received back. + * @param liquidity The amount of liquidity to receive back. + * @param amount0Min The minimum amount of token0 to receive back. + * @param amount1Min The minimum amount of token1 to receive back. + */ + event LiquidityDecreased( + uint256 indexed tokenId, + uint256 amount0, + uint256 amount1, + uint256 liquidity, + uint256 amount0Min, + uint256 amount1Min + ); + /** * The event that is emitted when the fees are collected. * @param tokenId The ID of the position. @@ -64,7 +82,19 @@ interface IL2TokenReceiverV2 is IERC165, IERC721Receiver { */ event FeesCollected(uint256 indexed tokenId, uint256 amount0, uint256 amount1); - function L2TokenReceiver__init(address router_, address nonfungiblePositionManager_) external; + /** + * The function to initialize the contract. + * @param router_ The address of the router. + * @param nonfungiblePositionManager_ The address of the nonfungible position manager. + * @param firstSwapParams_ The initial swap params. + * @param secondSwapParams_ The secondary swap params. + */ + function L2TokenReceiver__init( + address router_, + address nonfungiblePositionManager_, + SwapParams memory firstSwapParams_, + SwapParams memory secondSwapParams_ + ) external; /** * The function to edit the swap params. @@ -107,22 +137,33 @@ interface IL2TokenReceiverV2 is IERC165, IERC721Receiver { /** * The function to increase liquidity in the current price range. * @param tokenId The ID of the position. - * @param amountAdd0_ The amount of token0 to add. - * @param amountAdd1_ The amount of token1 to add. - * @param amountMin0_ The minimum amount of token0 to add. - * @param amountMin1_ The minimum amount of token1 to add. - * @return liquidity_ The amount of liquidity added. - * @return amount0_ The amount of token0 added. - * @return amount1_ The amount of token1 added. + * @param amount0Add_ The amount of token0 to add. + * @param amount1Add_ The amount of token1 to add. + * @param amount0Min_ The minimum amount of token0 to add. + * @param amount1Min_ The minimum amount of token1 to add. */ function increaseLiquidityCurrentRange( uint256 tokenId, - uint256 amountAdd0_, - uint256 amountAdd1_, - uint256 amountMin0_, - uint256 amountMin1_ + uint256 amount0Add_, + uint256 amount1Add_, + uint256 amount0Min_, + uint256 amount1Min_ ) external returns (uint128 liquidity_, uint256 amount0_, uint256 amount1_); + /** + * The function to decrease liquidity in the current price range. + * @param tokenId_ The ID of the position. + * @param liquidity_ The amount of liquidity to receive back. + * @param amount0Min_ The minimum amount of token0 to receive back. + * @param amount1Min_ The minimum amount of token1 to receive back. + */ + function decreaseLiquidityCurrentRange( + uint256 tokenId_, + uint128 liquidity_, + uint256 amount0Min_, + uint256 amount1Min_ + ) external returns (uint256 amount0_, uint256 amount1_); + /** * The function to collect fees from the position. The fees are not transferred to the caller. * @param tokenId_ The ID of the position. diff --git a/contracts/interfaces/L2/IMOR20.sol b/contracts/interfaces/L2/IMOR20.sol index fd98c06..b34d640 100644 --- a/contracts/interfaces/L2/IMOR20.sol +++ b/contracts/interfaces/L2/IMOR20.sol @@ -10,10 +10,11 @@ import {IOAppCore} from "../../@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/inte */ interface IMOR20 is IERC20, IERC165 { /** - * The function to get the minter address. - * @return The minter address. + * The function to update `minter` addresses. + * @param minter_ The updated minter address. + * @param status_ The new status. True or false. */ - function minter() external view returns (address); + function updateMinter(address minter_, bool status_) external; /** * The function to mint tokens. diff --git a/contracts/interfaces/uniswap-v3/INonfungiblePositionManager.sol b/contracts/interfaces/uniswap-v3/INonfungiblePositionManager.sol index 79aabf2..9825386 100644 --- a/contracts/interfaces/uniswap-v3/INonfungiblePositionManager.sol +++ b/contracts/interfaces/uniswap-v3/INonfungiblePositionManager.sol @@ -13,6 +13,14 @@ interface INonfungiblePositionManager is IERC721 { uint256 deadline; } + struct DecreaseLiquidityParams { + uint256 tokenId; + uint128 liquidity; + uint256 amount0Min; + uint256 amount1Min; + uint256 deadline; + } + struct CollectParams { uint256 tokenId; address recipient; @@ -38,6 +46,10 @@ interface INonfungiblePositionManager is IERC721 { IncreaseLiquidityParams calldata params ) external payable returns (uint128 liquidity, uint256 amount0, uint256 amount1); + function decreaseLiquidity( + DecreaseLiquidityParams calldata params + ) external payable returns (uint256 amount0, uint256 amount1); + function collect(CollectParams calldata params) external payable returns (uint256 amount0, uint256 amount1); function positions( diff --git a/contracts/libs/MOR20Deployer.sol b/contracts/libs/MOR20Deployer.sol new file mode 100644 index 0000000..89b119a --- /dev/null +++ b/contracts/libs/MOR20Deployer.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {MOR20} from "../L2/MOR20.sol"; + +library MOR20Deployer { + event Mor20Deployed(address token); + + function deployMOR20( + string calldata mor20Name_, + string calldata mor20Symbol, + address oftEndpoint_, + address delegate_, + address l2MessageReceiver_ + ) external returns (address mor20) { + mor20 = address(new MOR20(mor20Name_, mor20Symbol, oftEndpoint_, delegate_, l2MessageReceiver_)); + + emit Mor20Deployed(mor20); + } +} diff --git a/contracts/mock/FactoryMock.sol b/contracts/mock/FactoryMock.sol new file mode 100644 index 0000000..ab813db --- /dev/null +++ b/contracts/mock/FactoryMock.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Factory} from "../Factory.sol"; + +contract FactoryMock is Factory { + function Factory_init() external initializer { + __Pausable_init(); + __Ownable_init(); + __UUPSUpgradeable_init(); + __Factory_init(); + } + + function mockInit() external { + __Factory_init(); + } + + function deploy2(uint8 poolType_, string memory poolName_) external returns (address) { + return _deploy2(poolType_, poolName_); + } +} diff --git a/contracts/mock/FactoryMockV2.sol b/contracts/mock/FactoryMockV2.sol new file mode 100644 index 0000000..e929f20 --- /dev/null +++ b/contracts/mock/FactoryMockV2.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {FactoryMock} from "./FactoryMock.sol"; + +contract FactoryMockV2 is FactoryMock { + function FactoryMockV2_init() external initializer { + __Pausable_init(); + __Ownable_init(); + __UUPSUpgradeable_init(); + __Factory_init(); + } + + function version() external pure returns (uint256) { + return 2; + } +} diff --git a/contracts/mock/FeeConfigV2.sol b/contracts/mock/FeeConfigV2.sol new file mode 100644 index 0000000..91dd2a5 --- /dev/null +++ b/contracts/mock/FeeConfigV2.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract FeeConfigV2 is UUPSUpgradeable { + function version() external pure returns (uint256) { + return 2; + } + + function _authorizeUpgrade(address) internal view override {} +} diff --git a/contracts/mock/L1FactoryV2.sol b/contracts/mock/L1FactoryV2.sol new file mode 100644 index 0000000..ec9e9cc --- /dev/null +++ b/contracts/mock/L1FactoryV2.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract L1FactoryV2 is UUPSUpgradeable { + function version() external pure returns (uint256) { + return 2; + } + + function _authorizeUpgrade(address) internal view override {} +} diff --git a/contracts/mock/L2FactoryV2.sol b/contracts/mock/L2FactoryV2.sol new file mode 100644 index 0000000..849f7d4 --- /dev/null +++ b/contracts/mock/L2FactoryV2.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract L2FactoryV2 is UUPSUpgradeable { + function version() external pure returns (uint256) { + return 2; + } + + function _authorizeUpgrade(address) internal view override {} +} diff --git a/contracts/mock/L2TokenRecevierV2.sol b/contracts/mock/L2TokenRecevierV2.sol new file mode 100644 index 0000000..3695d42 --- /dev/null +++ b/contracts/mock/L2TokenRecevierV2.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +contract L2TokenReceiverV2 is UUPSUpgradeable { + function version() external pure returns (uint256) { + return 2; + } + + function _authorizeUpgrade(address) internal view override {} +} diff --git a/hardhat.config.ts b/hardhat.config.ts index a2ba9d2..f3b7323 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -33,7 +33,8 @@ const config: HardhatUserConfig = { hardhat: { initialDate: '1970-01-01T00:00:00Z', // forking: { - // url: `https://mainnet.infura.io/v3/${process.env.INFURA_KEY}`, + // url: `https://eth-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_KEY}`, + // blockNumber: 19842819, // }, // forking: { // url: `https://arbitrum-sepolia.infura.io/v3/${process.env.INFURA_KEY}`, diff --git a/package-lock.json b/package-lock.json index 98b6049..38017e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,8 +25,8 @@ }, "devDependencies": { "@metamask/eth-sig-util": "^7.0.0", - "@nomicfoundation/hardhat-chai-matchers": "^2.0.2", - "@nomicfoundation/hardhat-ethers": "^3.0.4", + "@nomicfoundation/hardhat-chai-matchers": "^2.0.6", + "@nomicfoundation/hardhat-ethers": "^3.0.5", "@nomicfoundation/hardhat-network-helpers": "^1.0.9", "@nomiclabs/hardhat-truffle5": "^2.0.7", "@nomiclabs/hardhat-web3": "^2.0.0", diff --git a/package.json b/package.json index e09bb3d..737e24d 100644 --- a/package.json +++ b/package.json @@ -53,8 +53,8 @@ }, "devDependencies": { "@metamask/eth-sig-util": "^7.0.0", - "@nomicfoundation/hardhat-chai-matchers": "^2.0.2", - "@nomicfoundation/hardhat-ethers": "^3.0.4", + "@nomicfoundation/hardhat-chai-matchers": "^2.0.6", + "@nomicfoundation/hardhat-ethers": "^3.0.5", "@nomicfoundation/hardhat-network-helpers": "^1.0.9", "@nomiclabs/hardhat-truffle5": "^2.0.7", "@nomiclabs/hardhat-web3": "^2.0.0", diff --git a/test/Factory.test.ts b/test/Factory.test.ts new file mode 100644 index 0000000..33a5c77 --- /dev/null +++ b/test/Factory.test.ts @@ -0,0 +1,153 @@ +import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { Reverter } from './helpers/reverter'; + +import { FactoryMock, FactoryMockV2 } from '@/generated-types/ethers'; +import { ZERO_ADDR } from '@/scripts/utils/constants'; + +describe('Factory', () => { + const reverter = new Reverter(); + + let OWNER: SignerWithAddress; + let SECOND: SignerWithAddress; + + let factory: FactoryMock; + + before(async () => { + [OWNER, SECOND] = await ethers.getSigners(); + + const [FactoryMockFactory, ERC1967ProxyFactory] = await Promise.all([ + ethers.getContractFactory('FactoryMock'), + ethers.getContractFactory('ERC1967Proxy'), + ]); + + const factoryImpl = await FactoryMockFactory.deploy(); + const factoryProxy = await ERC1967ProxyFactory.deploy(factoryImpl, '0x'); + factory = FactoryMockFactory.attach(factoryProxy) as FactoryMock; + + await factory.Factory_init(); + + await reverter.snapshot(); + }); + + afterEach(reverter.revert); + + describe('UUPS proxy functionality', () => { + describe('#Factory_init', () => { + it('should revert if try to call init function twice', async () => { + const reason = 'Initializable: contract is already initialized'; + + await expect(factory.Factory_init()).to.be.rejectedWith(reason); + }); + it('should revert if call init function incorrect', async () => { + const reason = 'Initializable: contract is not initializing'; + + await expect(factory.mockInit()).to.be.rejectedWith(reason); + }); + }); + + describe('#_authorizeUpgrade', () => { + it('should correctly upgrade', async () => { + const factoryV2Factory = await ethers.getContractFactory('FactoryMockV2'); + const factoryV2Implementation = await factoryV2Factory.deploy(); + + await factory.upgradeTo(factoryV2Implementation); + + const factoryV2 = factoryV2Factory.attach(await factory.getAddress()) as FactoryMockV2; + + expect(await factoryV2.version()).to.eq(2); + }); + it('should revert if caller is not the owner', async () => { + await expect(factory.connect(SECOND).upgradeTo(ZERO_ADDR)).to.be.revertedWith( + 'Ownable: caller is not the owner', + ); + }); + }); + }); + + describe('pause', () => { + it('should pause', async () => { + expect(await factory.paused()).to.be.false; + await factory.pause(); + expect(await factory.paused()).to.be.true; + }); + it('should revert if called by non-owner', async () => { + await expect(factory.connect(SECOND).pause()).to.be.revertedWith('Ownable: caller is not the owner'); + }); + }); + + describe('unpause', () => { + it('should unpause', async () => { + await factory.pause(); + expect(await factory.paused()).to.be.true; + + await factory.unpause(); + expect(await factory.paused()).to.be.false; + }); + it('should revert if called by non-owner', async () => { + await factory.pause(); + await expect(factory.connect(SECOND).unpause()).to.be.revertedWith('Ownable: caller is not the owner'); + }); + }); + + describe('setImplementation', () => { + it('should set implementation', async () => { + await factory.setImplementation(0, SECOND); + + expect(await factory.getImplementation(0)).to.eq(SECOND); + + await factory.setImplementation(0, ZERO_ADDR); + + expect(await factory.getImplementation(0)).to.eq(ZERO_ADDR); + }); + it('should revert if called by non-owner', async () => { + await expect(factory.connect(SECOND).setImplementation(0, SECOND)).to.be.revertedWith( + 'Ownable: caller is not the owner', + ); + }); + }); + + describe('getImplementation', () => { + it('should get implementation', async () => { + expect(await factory.getImplementation(0)).to.eq(ZERO_ADDR); + + await factory.setImplementation(0, SECOND); + + expect(await factory.getImplementation(0)).to.eq(SECOND.address); + }); + }); + + describe('deploy2', () => { + beforeEach(async () => { + const L1SenderFactory = await ethers.getContractFactory('L1Sender'); + const L1SenderImplementation = await L1SenderFactory.deploy(); + + await factory.setImplementation(0, L1SenderImplementation); + }); + + it('should deploy contract', async () => { + const proxy = await factory.deploy2.staticCall(0, 'name'); + await factory.deploy2(0, 'name'); + + expect(await factory.deployedProxies(OWNER, 'name', 0)).to.eq(proxy); + }); + it('should deploy the same name for different addresses', async () => { + await factory.deploy2(0, 'name'); + + await factory.connect(SECOND).deploy2(0, 'name'); + }); + it('should revert if name is an empty string', async () => { + await expect(factory.deploy2(0, '')).to.be.revertedWith('F: poolName_ is empty'); + }); + it('should revert if implementation is not set', async () => { + await expect(factory.deploy2(1, 'name')).to.be.revertedWith('F: implementation not found'); + }); + it('should revert if called twice with the same name for same address', async () => { + await factory.deploy2(0, 'name'); + + await expect(factory.deploy2(0, 'name')).to.be.revertedWith('F: salt used'); + }); + }); +}); diff --git a/test/L1/BaseFactoryL1.test.ts b/test/L1/BaseFactoryL1.test.ts deleted file mode 100644 index d5dbafc..0000000 --- a/test/L1/BaseFactoryL1.test.ts +++ /dev/null @@ -1,193 +0,0 @@ -import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; -import { expect } from 'chai'; -import { ethers } from 'hardhat'; - -import { Reverter } from '../helpers/reverter'; - -import { - CorePropertiesL1, - Distribution, - GatewayRouterMock, - L1Sender, - LinearDistributionIntervalDecrease, - Mor20FactoryL1, - StETHMock, - WStETHMock, -} from '@/generated-types/ethers'; -import { ETHER_ADDR, ZERO_ADDR } from '@/scripts/utils/constants'; - -enum PoolTypes { - DISTRIBUTION, - L1_SENDER, -} - -describe.only('BaseFactoryL1', () => { - const reverter = new Reverter(); - - let OWNER: SignerWithAddress; - let SECOND: SignerWithAddress; - - let mor20FactoryL1: Mor20FactoryL1; - - let l1SenderImplementation: L1Sender; - let distributionImplementation: Distribution; - let coreProperties: CorePropertiesL1; - - let stEthMock: StETHMock; - let wstEthMock: WStETHMock; - let gatewayRouterMock: GatewayRouterMock; - - let poolTypes: PoolTypes[]; - let poolImplementations: string[]; - - before(async () => { - [OWNER, SECOND] = await ethers.getSigners(); - - const [ - libFactory, - l1SenderFactory, - tokenDeployerFactory, - mor20FactoryL1Factory, - stEthMockFactory, - wstEthMockFactory, - gatewayRouterMockFactory, - corePropertiesFactory, - ] = await Promise.all([ - ethers.getContractFactory('LinearDistributionIntervalDecrease'), - ethers.getContractFactory('L1Sender'), - ethers.getContractFactory('RewardTokenDeployer'), - ethers.getContractFactory('Mor20FactoryL1'), - ethers.getContractFactory('StETHMock'), - ethers.getContractFactory('WStETHMock'), - ethers.getContractFactory('GatewayRouterMock'), - ethers.getContractFactory('CorePropertiesL1'), - ]); - - let lib: LinearDistributionIntervalDecrease; - [lib, l1SenderImplementation, stEthMock, gatewayRouterMock] = await Promise.all([ - libFactory.deploy(), - l1SenderFactory.deploy(), - stEthMockFactory.deploy(), - gatewayRouterMockFactory.deploy(), - ]); - wstEthMock = await wstEthMockFactory.deploy(stEthMock); - coreProperties = await corePropertiesFactory.deploy(gatewayRouterMock, SECOND, ZERO_ADDR, 1); - - const distributionFactory = await ethers.getContractFactory('Distribution', { - libraries: { - LinearDistributionIntervalDecrease: lib, - }, - }); - distributionImplementation = await distributionFactory.deploy(); - - mor20FactoryL1 = await mor20FactoryL1Factory.deploy(coreProperties); - - poolTypes = [PoolTypes.DISTRIBUTION, PoolTypes.L1_SENDER]; - poolImplementations = [await distributionImplementation.getAddress(), await l1SenderImplementation.getAddress()]; - - await reverter.snapshot(); - }); - - function getMor20DeployParams() { - const mor20DeployParams: Mor20FactoryL1.Mor20DeployParamsStruct = { - name: 'Mor20', - depositToken: stEthMock, - poolsInfo: [], - messageReceiver: ETHER_ADDR, - zroPaymentAddress: ZERO_ADDR, - l2EndpointId: 0, - adapterParams: '0x', - wrappedToken: wstEthMock, - tokenReceiver: ETHER_ADDR, - }; - - return mor20DeployParams; - } - - afterEach(reverter.revert); - - describe('#predictMor20Address', () => { - it('should return zero address if name is an empty string', async () => { - const predictedAddress = await mor20FactoryL1.predictMor20Address(OWNER, ''); - - expect(predictedAddress).to.be.deep.equal([ZERO_ADDR, ZERO_ADDR]); - }); - }); - - describe('#getImplementation', () => { - it('should return current implementation address', async () => { - await mor20FactoryL1.setNewImplementations(poolTypes, poolImplementations); - - const implementation = await mor20FactoryL1.getImplementation(PoolTypes.DISTRIBUTION); - - expect(implementation).to.be.equal(distributionImplementation); - - const implementation2 = await mor20FactoryL1.getImplementation(PoolTypes.L1_SENDER); - - expect(implementation2).to.be.equal(l1SenderImplementation); - }); - - it('should revert if implementation is not set', async () => { - const error = "BaseFactory: this mapping doesn't exist"; - - await expect(mor20FactoryL1.getImplementation(PoolTypes.DISTRIBUTION)).to.be.revertedWith(error); - - await expect(mor20FactoryL1.getImplementation(PoolTypes.L1_SENDER)).to.be.revertedWith(error); - }); - }); - - describe('#getBeaconProxy', () => { - it('should return beacon proxy address', async () => { - await mor20FactoryL1.setNewImplementations(poolTypes, poolImplementations); - - const beaconProxy = await mor20FactoryL1.getBeaconProxy(PoolTypes.DISTRIBUTION); - expect(beaconProxy).to.be.not.equal(ZERO_ADDR); - - const beaconProxy2 = await mor20FactoryL1.getBeaconProxy(PoolTypes.L1_SENDER); - expect(beaconProxy2).to.be.not.equal(ZERO_ADDR); - }); - - it('should revert if beacon is not set', async () => { - const error = 'BaseFactory: bad PublicBeaconProxy'; - - await expect(mor20FactoryL1.getBeaconProxy(PoolTypes.DISTRIBUTION)).to.be.revertedWith(error); - - await expect(mor20FactoryL1.getBeaconProxy(PoolTypes.L1_SENDER)).to.be.revertedWith(error); - }); - }); - - describe('#countDistributions', () => { - it('should return number of deployed distributions', async () => { - await mor20FactoryL1.setNewImplementations(poolTypes, poolImplementations); - - let params = getMor20DeployParams(); - - expect(await mor20FactoryL1.countDistributions()).to.be.equal(0); - - await mor20FactoryL1.deployMor20OnL1(params); - - expect(await mor20FactoryL1.countDistributions()).to.be.equal(1); - - params.name = 'Mor21'; - await mor20FactoryL1.deployMor20OnL1(params); - - expect(await mor20FactoryL1.countDistributions()).to.be.equal(2); - }); - }); - - describe('#listDistributions', () => { - it('should return list of deployed distributions', async () => { - await mor20FactoryL1.setNewImplementations(poolTypes, poolImplementations); - - let params = getMor20DeployParams(); - - expect(await mor20FactoryL1.listDistributions(0, 10)).to.be.deep.equal([]); - - await mor20FactoryL1.deployMor20OnL1(params); - - expect(await mor20FactoryL1.listDistributions(0, 10)).to.be.lengthOf(1); - - expect(await mor20FactoryL1.listDistributions(1, 10)).to.be.lengthOf(0); - }); - }); -}); diff --git a/test/L1/Distribution.test.ts b/test/L1/Distribution.test.ts index ded05e6..4cfc2b5 100644 --- a/test/L1/Distribution.test.ts +++ b/test/L1/Distribution.test.ts @@ -6,21 +6,22 @@ import { Distribution, DistributionV2, Distribution__factory, - ERC20MOR, + FeeConfig, GatewayRouterMock, IDistribution, IL1Sender, L1Sender, L2MessageReceiver, - L2TokenReceiver, LZEndpointMock, LayerZeroEndpointV2Mock, LinearDistributionIntervalDecrease, + MOR20, NonfungiblePositionManagerMock, StETHMock, SwapRouterMock, WStETHMock, } from '@/generated-types/ethers'; +import { L2TokenReceiver } from '@/generated-types/ethers/contracts/L2/L2TokenReceiver'; import { ZERO_ADDR } from '@/scripts/utils/constants'; import { wei } from '@/scripts/utils/utils'; import { getCurrentBlockTime, setNextTime, setTime } from '@/test/helpers/block-helper'; @@ -41,7 +42,7 @@ describe('Distribution', () => { let lib: LinearDistributionIntervalDecrease; - let rewardToken: ERC20MOR; + let rewardToken: MOR20; let depositToken: StETHMock; let wstETH: WStETHMock; @@ -49,6 +50,7 @@ describe('Distribution', () => { let lZEndpointMockReceiver: LZEndpointMock; let lZEndpointMockOFT: LayerZeroEndpointV2Mock; + let feeConfig: FeeConfig; let l1Sender: L1Sender; let l2MessageReceiver: L2MessageReceiver; let l2TokenReceiver: L2TokenReceiver; @@ -71,10 +73,11 @@ describe('Distribution', () => { SwapRouterMock, NonfungiblePositionManagerMock, LZEndpointMockOFT, + feeConfigFactory, ] = await Promise.all([ ethers.getContractFactory('LinearDistributionIntervalDecrease'), ethers.getContractFactory('ERC1967Proxy'), - ethers.getContractFactory('ERC20MOR'), + ethers.getContractFactory('MOR20'), ethers.getContractFactory('StETHMock'), ethers.getContractFactory('WStETHMock'), ethers.getContractFactory('L1Sender'), @@ -85,6 +88,7 @@ describe('Distribution', () => { ethers.getContractFactory('SwapRouterMock'), ethers.getContractFactory('NonfungiblePositionManagerMock'), ethers.getContractFactory('LayerZeroEndpointV2Mock'), + ethers.getContractFactory('FeeConfig'), ]); let gatewayRouter: GatewayRouterMock; @@ -93,6 +97,7 @@ describe('Distribution', () => { let l2TokenReceiverImplementation: L2TokenReceiver; let l2MessageReceiverImplementation: L2MessageReceiver; let l1SenderImplementation: L1Sender; + let feeConfigImplementation: FeeConfig; // START deploy contracts without deps [ lib, @@ -106,6 +111,7 @@ describe('Distribution', () => { l2MessageReceiverImplementation, l1SenderImplementation, lZEndpointMockOFT, + feeConfigImplementation, ] = await Promise.all([ libFactory.deploy(), stETHMockFactory.deploy(), @@ -118,10 +124,9 @@ describe('Distribution', () => { L2MessageReceiver.deploy(), l1SenderFactory.deploy(), LZEndpointMockOFT.deploy(receiverChainId, OWNER), + feeConfigFactory.deploy(), ]); - lZEndpointMockOFT = await LZEndpointMockOFT.deploy(receiverChainId, OWNER); - distributionFactory = await ethers.getContractFactory('Distribution', { libraries: { LinearDistributionIntervalDecrease: await lib.getAddress(), @@ -130,20 +135,35 @@ describe('Distribution', () => { const distributionImplementation = await distributionFactory.deploy(); // END + lZEndpointMockOFT = await LZEndpointMockOFT.deploy(receiverChainId, OWNER); + wstETH = await wstETHMockFactory.deploy(depositToken); + const feeConfigProxy = await ERC1967ProxyFactory.deploy(feeConfigImplementation, '0x'); + feeConfig = feeConfigFactory.attach(feeConfigProxy) as FeeConfig; + await feeConfig.__FeeConfig_init(OWNER, wei(0.1, 25)); + const l2MessageReceiverProxy = await ERC1967ProxyFactory.deploy(l2MessageReceiverImplementation, '0x'); l2MessageReceiver = L2MessageReceiver.attach(l2MessageReceiverProxy) as L2MessageReceiver; - await l2MessageReceiver.L2MessageReceiver__init(); const l2TokenReceiverProxy = await ERC1967ProxyFactory.deploy(l2TokenReceiverImplementation, '0x'); l2TokenReceiver = L2TokenReceiver.attach(l2TokenReceiverProxy) as L2TokenReceiver; - await l2TokenReceiver.L2TokenReceiver__init(swapRouter, nonfungiblePositionManager, { - tokenIn: depositToken, - tokenOut: depositToken, - fee: 3000, - sqrtPriceLimitX96: 0, - }); + await l2TokenReceiver.L2TokenReceiver__init( + swapRouter, + nonfungiblePositionManager, + { + tokenIn: depositToken, + tokenOut: depositToken, + fee: 3000, + sqrtPriceLimitX96: 0, + }, + { + tokenIn: depositToken, + tokenOut: depositToken, + fee: 3000, + sqrtPriceLimitX96: 0, + }, + ); // START deploy distribution contract const distributionProxy = await ERC1967ProxyFactory.deploy(await distributionImplementation.getAddress(), '0x'); @@ -168,10 +188,10 @@ describe('Distribution', () => { await l1Sender.L1Sender__init(distribution, rewardTokenConfig, depositTokenConfig); // Deploy reward token - rewardToken = await MORFactory.deploy(lZEndpointMockOFT, OWNER, l2MessageReceiver); + rewardToken = await MORFactory.deploy('MOR', 'MOR', lZEndpointMockOFT, OWNER, l2MessageReceiver); await rewardToken.transferOwnership(l2MessageReceiver); - await l2MessageReceiver.setParams(rewardToken, { + await l2MessageReceiver.L2MessageReceiver__init(rewardToken, { gateway: lZEndpointMockReceiver, sender: l1Sender, senderChainId: senderChainId, @@ -179,7 +199,7 @@ describe('Distribution', () => { await lZEndpointMockSender.setDestLzEndpoint(l2MessageReceiver, lZEndpointMockReceiver); - await distribution.Distribution_init(depositToken, l1Sender, []); + await distribution.Distribution_init(depositToken, l1Sender, feeConfig, []); await Promise.all([depositToken.mint(OWNER.address, wei(1000)), depositToken.mint(SECOND.address, wei(1000))]); await Promise.all([ @@ -193,80 +213,80 @@ describe('Distribution', () => { afterEach(reverter.revert); - // describe("UUPS proxy functionality", () => { - // describe("#constructor", () => { - // it("should disable initialize function", async () => { - // const reason = "Initializable: contract is already initialized"; - - // const distribution = await distributionFactory.deploy(); - - // await expect(distribution.Distribution_init(depositToken, l1Sender, [])).to.be.revertedWith(reason); - // }); - // }); - - // describe("#Distribution_init", () => { - // it("should set correct data after creation", async () => { - // const depositToken_ = await distribution.depositToken(); - // expect(depositToken_).to.eq(await depositToken.getAddress()); - // }); - // it("should create pools with correct data", async () => { - // const pool1 = getDefaultPool(); - // const pool2 = { - // ...pool1, - // isPublic: false, - // minimalStake: wei(0), - // payoutStart: oneDay * 2, - // decreaseInterval: oneDay * 2, - // }; - - // const distributionProxy = await ( - // await ethers.getContractFactory("ERC1967Proxy") - // ).deploy(await distributionFactory.deploy(), "0x"); - - // const distribution = distributionFactory.attach(await distributionProxy.getAddress()) as Distribution; - - // await distribution.Distribution_init(depositToken, l1Sender, [pool1, pool2]); - - // const pool1Data: IDistribution.PoolStruct = await distribution.pools(0); - // expect(_comparePoolStructs(pool1, pool1Data)).to.be.true; - - // const pool2Data: IDistribution.PoolStruct = await distribution.pools(1); - // expect(_comparePoolStructs(pool2, pool2Data)).to.be.true; - // }); - // it("should revert if try to call init function twice", async () => { - // const reason = "Initializable: contract is already initialized"; - - // await expect(distribution.Distribution_init(depositToken, l1Sender, [])).to.be.rejectedWith(reason); - // }); - // }); - - // describe("#_authorizeUpgrade", () => { - // it("should correctly upgrade", async () => { - // const distributionV2Factory = await ethers.getContractFactory("DistributionV2", { - // libraries: { - // LinearDistributionIntervalDecrease: await lib.getAddress(), - // }, - // }); - // const distributionV2Implementation = await distributionV2Factory.deploy(); - - // await distribution.upgradeTo(await distributionV2Implementation.getAddress()); - - // const distributionV2 = distributionV2Factory.attach(await distribution.getAddress()) as DistributionV2; - - // expect(await distributionV2.version()).to.eq(2); - // }); - // it("should revert if caller is not the owner", async () => { - // await expect(distribution.connect(SECOND).upgradeTo(ZERO_ADDR)).to.be.revertedWith( - // "Ownable: caller is not the owner", - // ); - // }); - // it("should revert if `isNotUpgradeable == true`", async () => { - // await distribution.removeUpgradeability(); - - // await expect(distribution.upgradeTo(ZERO_ADDR)).to.be.revertedWith("DS: upgrade isn't available"); - // }); - // }); - // }); + describe('UUPS proxy functionality', () => { + describe('#constructor', () => { + it('should disable initialize function', async () => { + const reason = 'Initializable: contract is already initialized'; + + const distribution = await distributionFactory.deploy(); + + await expect(distribution.Distribution_init(depositToken, l1Sender, feeConfig, [])).to.be.revertedWith(reason); + }); + }); + + describe('#Distribution_init', () => { + it('should set correct data after creation', async () => { + const depositToken_ = await distribution.depositToken(); + expect(depositToken_).to.eq(await depositToken.getAddress()); + }); + it('should create pools with correct data', async () => { + const pool1 = getDefaultPool(); + const pool2 = { + ...pool1, + isPublic: false, + minimalStake: wei(0), + payoutStart: oneDay * 2, + decreaseInterval: oneDay * 2, + }; + + const distributionProxy = await ( + await ethers.getContractFactory('ERC1967Proxy') + ).deploy(await distributionFactory.deploy(), '0x'); + + const distribution = distributionFactory.attach(await distributionProxy.getAddress()) as Distribution; + + await distribution.Distribution_init(depositToken, l1Sender, feeConfig, [pool1, pool2]); + + const pool1Data: IDistribution.PoolStruct = await distribution.pools(0); + expect(_comparePoolStructs(pool1, pool1Data)).to.be.true; + + const pool2Data: IDistribution.PoolStruct = await distribution.pools(1); + expect(_comparePoolStructs(pool2, pool2Data)).to.be.true; + }); + it('should revert if try to call init function twice', async () => { + const reason = 'Initializable: contract is already initialized'; + + await expect(distribution.Distribution_init(depositToken, l1Sender, feeConfig, [])).to.be.rejectedWith(reason); + }); + }); + + describe('#_authorizeUpgrade', () => { + it('should correctly upgrade', async () => { + const distributionV2Factory = await ethers.getContractFactory('DistributionV2', { + libraries: { + LinearDistributionIntervalDecrease: await lib.getAddress(), + }, + }); + const distributionV2Implementation = await distributionV2Factory.deploy(); + + await distribution.upgradeTo(await distributionV2Implementation.getAddress()); + + const distributionV2 = distributionV2Factory.attach(await distribution.getAddress()) as DistributionV2; + + expect(await distributionV2.version()).to.eq(2); + }); + it('should revert if caller is not the owner', async () => { + await expect(distribution.connect(SECOND).upgradeTo(ZERO_ADDR)).to.be.revertedWith( + 'Ownable: caller is not the owner', + ); + }); + it('should revert if `isNotUpgradeable == true`', async () => { + await distribution.removeUpgradeability(); + + await expect(distribution.upgradeTo(ZERO_ADDR)).to.be.revertedWith("DS: upgrade isn't available"); + }); + }); + }); describe('#createPool', () => { it('should create pool with correct data', async () => { @@ -323,9 +343,7 @@ describe('Distribution', () => { it('should edit pool with correct data', async () => { const newPool = { ...defaultPool, - payoutStart: 10 * oneDay, decreaseInterval: 10 * oneDay, - withdrawLockPeriod: 10 * oneDay, initialReward: wei(111), rewardDecrease: wei(222), minimalStake: wei(333), @@ -352,6 +370,21 @@ describe('Distribution', () => { await expect(distribution.editPool(poolId, newPool)).to.be.rejectedWith('DS: invalid decrease interval'); }); + it('if `payoutStart changes`', async () => { + const newPool = { ...defaultPool, payoutStart: oneDay * 2 }; + + await expect(distribution.editPool(poolId, newPool)).to.be.rejectedWith('DS: invalid payout start value'); + }); + it('if `withdrawLockPeriod` changes', async () => { + const newPool = { ...defaultPool, withdrawLockPeriod: oneDay * 2 }; + + await expect(distribution.editPool(poolId, newPool)).to.be.rejectedWith('DS: invalid WLP value'); + }); + it('if `withdrawLockPeriodAfterStake` changes', async () => { + const newPool = { ...defaultPool, withdrawLockPeriodAfterStake: oneDay * 2 }; + + await expect(distribution.editPool(poolId, newPool)).to.be.rejectedWith('DS: invalid WLPAS value'); + }); }); it('should revert if caller is not owner', async () => { @@ -1107,27 +1140,6 @@ describe('Distribution', () => { expect(userData.deposited).to.eq(wei(1)); expect(userData.pendingRewards).to.eq(0); }); - // it("should not save reward to pending reward if cannot mint reward token", async () => { - // const amountToMintMaximum = (await rewardToken.cap()) - (await rewardToken.totalSupply()); - - // await _getRewardTokenFromPool(distribution, amountToMintMaximum - wei(1), OWNER); - - // await distribution.stake(poolId, wei(10)); - - // await setNextTime(oneDay + oneDay); - - // let tx = await distribution.claim(poolId, OWNER, { value: wei(0.5) }); - // await expect(tx).to.changeTokenBalance(rewardToken, OWNER, wei(100)); - // let userData = await distribution.usersData(OWNER, poolId); - // expect(userData.pendingRewards).to.equal(wei(0)); - - // await setNextTime(oneDay + oneDay * 2); - - // tx = await distribution.claim(poolId, OWNER, { value: wei(0.5) }); - // await expect(tx).to.changeTokenBalance(rewardToken, OWNER, wei(98)); - // userData = await distribution.usersData(OWNER, poolId); - // expect(userData.pendingRewards).to.equal(wei(0)); - // }); it("should revert if pool doesn't exist", async () => { await expect(distribution.connect(SECOND).claim(1, SECOND)).to.be.revertedWith("DS: pool doesn't exist"); }); @@ -1652,7 +1664,51 @@ describe('Distribution', () => { await distribution.createPool(pool); }); - it('should bridge overplus', async () => { + it('should bridge overplus with basic fee', async () => { + const l2TokenReceiverAddress = await l2TokenReceiver.getAddress(); + + await distribution.stake(1, wei(1)); + + await depositToken.setTotalPooledEther((await depositToken.totalPooledEther()) * 2n); + + let overplus = await distribution.overplus(); + expect(overplus).to.eq(wei(1)); + + const fee = (overplus * (await feeConfig.baseFee())) / wei(1, 25); + overplus -= fee; + + const bridgeMessageId = await distribution.bridgeOverplus.staticCall(1, 1, 1); + const tx = await distribution.bridgeOverplus(1, 1, 1); + await expect(tx).to.emit(distribution, 'OverplusBridged').withArgs(overplus, bridgeMessageId); + await expect(tx).to.changeTokenBalance(depositToken, distribution, wei(-1)); + expect(await wstETH.balanceOf(l2TokenReceiverAddress)).to.eq(overplus); + await expect(tx).to.changeTokenBalance(depositToken, OWNER, fee); + }); + it('should bridge overplus with custom fee', async () => { + await feeConfig.setFee(distribution, wei(0.5, 25)); + + const l2TokenReceiverAddress = await l2TokenReceiver.getAddress(); + + await distribution.stake(1, wei(1)); + + await depositToken.setTotalPooledEther((await depositToken.totalPooledEther()) * 2n); + + let overplus = await distribution.overplus(); + expect(overplus).to.eq(wei(1)); + + const fee = (overplus * wei(0.5, 25)) / wei(1, 25); + overplus -= fee; + + const bridgeMessageId = await distribution.bridgeOverplus.staticCall(1, 1, 1); + const tx = await distribution.bridgeOverplus(1, 1, 1); + await expect(tx).to.emit(distribution, 'OverplusBridged').withArgs(overplus, bridgeMessageId); + await expect(tx).to.changeTokenBalance(depositToken, distribution, wei(-1)); + expect(await wstETH.balanceOf(l2TokenReceiverAddress)).to.eq(overplus); + await expect(tx).to.changeTokenBalance(depositToken, OWNER, fee); + }); + it('should bridge full overplus if fee is 0', async () => { + await feeConfig.setBaseFee(0); + const l2TokenReceiverAddress = await l2TokenReceiver.getAddress(); await distribution.stake(1, wei(1)); @@ -1664,9 +1720,10 @@ describe('Distribution', () => { const bridgeMessageId = await distribution.bridgeOverplus.staticCall(1, 1, 1); const tx = await distribution.bridgeOverplus(1, 1, 1); - await expect(tx).to.emit(distribution, 'OverplusBridged').withArgs(wei(1), bridgeMessageId); + await expect(tx).to.emit(distribution, 'OverplusBridged').withArgs(overplus, bridgeMessageId); await expect(tx).to.changeTokenBalance(depositToken, distribution, wei(-1)); - expect(await wstETH.balanceOf(l2TokenReceiverAddress)).to.eq(wei(1)); + expect(await wstETH.balanceOf(l2TokenReceiverAddress)).to.eq(overplus); + await expect(tx).to.changeTokenBalance(depositToken, OWNER, 0); }); it('should revert if caller is not owner', async () => { await expect(distribution.connect(SECOND).bridgeOverplus(1, 1, 1)).to.be.revertedWith( diff --git a/test/L1/FeeConfig.test.ts b/test/L1/FeeConfig.test.ts new file mode 100644 index 0000000..d3f5fc1 --- /dev/null +++ b/test/L1/FeeConfig.test.ts @@ -0,0 +1,137 @@ +import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { Reverter } from '../helpers/reverter'; + +import { FeeConfig, FeeConfigV2 } from '@/generated-types/ethers'; +import { ZERO_ADDR } from '@/scripts/utils/constants'; +import { wei } from '@/scripts/utils/utils'; + +describe('FeeConfig', () => { + let OWNER: SignerWithAddress; + let SECOND: SignerWithAddress; + + let feeConfig: FeeConfig; + + const reverter = new Reverter(); + + before(async () => { + [OWNER, SECOND] = await ethers.getSigners(); + + const [feeConfigFactory, ERC1967ProxyFactory] = await Promise.all([ + ethers.getContractFactory('FeeConfig'), + ethers.getContractFactory('ERC1967Proxy'), + ]); + + const feeConfigImpl = await feeConfigFactory.deploy(); + const feeConfigProxy = await ERC1967ProxyFactory.deploy(feeConfigImpl, '0x'); + feeConfig = feeConfigFactory.attach(feeConfigProxy) as FeeConfig; + + await feeConfig.__FeeConfig_init(OWNER, wei(0.1, 25)); + + await reverter.snapshot(); + }); + + afterEach(reverter.revert); + + describe('UUPS proxy functionality', () => { + describe('#__FeeConfig_init', () => { + it('should revert if try to call init function twice', async () => { + const reason = 'Initializable: contract is already initialized'; + + await expect(feeConfig.__FeeConfig_init(SECOND, wei(0.1, 25))).to.be.rejectedWith(reason); + }); + + describe('#_authorizeUpgrade', () => { + it('should correctly upgrade', async () => { + const feeConfigV2Factory = await ethers.getContractFactory('FeeConfigV2'); + const feeConfigV2Implementation = await feeConfigV2Factory.deploy(); + + await feeConfig.upgradeTo(feeConfigV2Implementation); + + const feeConfigV2 = feeConfigV2Factory.attach(await feeConfigV2Implementation.getAddress()) as FeeConfigV2; + + expect(await feeConfigV2.version()).to.eq(2); + }); + it('should revert if caller is not the owner', async () => { + await expect(feeConfig.connect(SECOND).upgradeTo(ZERO_ADDR)).to.be.revertedWith( + 'Ownable: caller is not the owner', + ); + }); + }); + }); + }); + + describe('#setFee', () => { + it('should set the fee', async () => { + expect(await feeConfig.fees(SECOND)).to.be.equal(0); + + await feeConfig.setFee(SECOND, wei(0.2, 25)); + + expect(await feeConfig.fees(SECOND)).to.be.equal(wei(0.2, 25)); + + await feeConfig.setFee(SECOND, wei(0.1, 25)); + + expect(await feeConfig.fees(SECOND)).to.be.equal(wei(0.1, 25)); + }); + it('should revert if not called by the owner', async () => { + await expect(feeConfig.connect(SECOND).setFee(SECOND, wei(0.1, 25))).to.be.revertedWith( + 'Ownable: caller is not the owner', + ); + }); + it('should revert if fee is greater than1', async () => { + await expect(feeConfig.setFee(SECOND, wei(1.1, 25))).to.be.revertedWith('FC: invalid fee'); + }); + }); + + describe('#setTreasury', () => { + it('should set the treasury', async () => { + await feeConfig.setTreasury(SECOND); + + expect(await feeConfig.treasury()).to.be.equal(SECOND); + }); + it('should revert if not called by the owner', async () => { + await expect(feeConfig.connect(SECOND).setTreasury(SECOND.address)).to.be.revertedWith( + 'Ownable: caller is not the owner', + ); + }); + it('should revert if treasury is zero address', async () => { + await expect(feeConfig.setTreasury(ZERO_ADDR)).to.be.revertedWith('FC: invalid treasury'); + }); + }); + + describe('#setBaseFee', () => { + it('should set the base fee', async () => { + await feeConfig.setBaseFee(wei(0.2, 25)); + + expect(await feeConfig.baseFee()).to.be.equal(wei(0.2, 25)); + }); + it('should revert if not called by the owner', async () => { + await expect(feeConfig.connect(SECOND).setBaseFee(wei(0.1, 25))).to.be.revertedWith( + 'Ownable: caller is not the owner', + ); + }); + it('should revert if fee is >= 1', async () => { + await expect(feeConfig.setBaseFee(wei(1, 25))).to.be.revertedWith('FC: invalid base fee'); + }); + }); + + describe('#getFeeAndTreasury', () => { + it('should return the base fee and treasury', async () => { + const [fee, treasury] = await feeConfig.getFeeAndTreasury(SECOND); + + expect(fee).to.be.equal(wei(0.1, 25)); + expect(treasury).to.be.equal(OWNER); + }); + it('should return the specific fee and treasury', async () => { + await feeConfig.setFee(SECOND, wei(0.2, 25)); + await feeConfig.setTreasury(SECOND); + + const [fee, treasury] = await feeConfig.getFeeAndTreasury(SECOND); + + expect(fee).to.be.equal(wei(0.2, 25)); + expect(treasury).to.be.equal(SECOND); + }); + }); +}); diff --git a/test/L1/L1Factory.test.ts b/test/L1/L1Factory.test.ts new file mode 100644 index 0000000..5a63911 --- /dev/null +++ b/test/L1/L1Factory.test.ts @@ -0,0 +1,326 @@ +import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { PoolTypesL1 } from '../helpers/helper'; +import { Reverter } from '../helpers/reverter'; + +import { + Distribution, + Distribution__factory, + FeeConfig, + GatewayRouterMock, + L1Factory, + L1Sender, + L1Sender__factory, + LZEndpointMock, + LinearDistributionIntervalDecrease, + StETHMock, + WStETHMock, +} from '@/generated-types/ethers'; +import { L1FactoryV2 } from '@/generated-types/ethers/contracts/mock/L1FactoryV2'; +import { ZERO_ADDR } from '@/scripts/utils/constants'; +import { wei } from '@/scripts/utils/utils'; + +describe('L1Factory', () => { + const senderChainId = 101; + + const reverter = new Reverter(); + + let OWNER: SignerWithAddress; + let SECOND: SignerWithAddress; + + let l1Factory: L1Factory; + + let distributionFactory: Distribution__factory; + let l1SenderFactory: L1Sender__factory; + + let l1SenderImplementation: L1Sender; + let distributionImplementation: Distribution; + let feeConfig: FeeConfig; + + let stEthMock: StETHMock; + let wstEthMock: WStETHMock; + let gatewayRouterMock: GatewayRouterMock; + let lzEndpoint: LZEndpointMock; + + before(async () => { + [OWNER, SECOND] = await ethers.getSigners(); + + const [ + libFactory, + l1FactoryFactory, + stEthMockFactory, + wstEthMockFactory, + gatewayRouterMockFactory, + feeConfigFactory, + ERC1967ProxyFactory, + LZEndpointMockFactory, + ] = await Promise.all([ + ethers.getContractFactory('LinearDistributionIntervalDecrease'), + ethers.getContractFactory('L1Factory'), + ethers.getContractFactory('StETHMock'), + ethers.getContractFactory('WStETHMock'), + ethers.getContractFactory('GatewayRouterMock'), + ethers.getContractFactory('FeeConfig'), + ethers.getContractFactory('ERC1967Proxy'), + ethers.getContractFactory('LZEndpointMock'), + ]); + l1SenderFactory = await ethers.getContractFactory('L1Sender'); + + let lib: LinearDistributionIntervalDecrease; + [lib, l1SenderImplementation, stEthMock, gatewayRouterMock, lzEndpoint] = await Promise.all([ + libFactory.deploy(), + l1SenderFactory.deploy(), + stEthMockFactory.deploy(), + gatewayRouterMockFactory.deploy(), + LZEndpointMockFactory.deploy(senderChainId), + ]); + wstEthMock = await wstEthMockFactory.deploy(stEthMock); + + const feeConfigImpl = await feeConfigFactory.deploy(); + const feeConfigProxy = await ERC1967ProxyFactory.deploy(feeConfigImpl, '0x'); + feeConfig = feeConfigFactory.attach(feeConfigProxy) as FeeConfig; + + await feeConfig.__FeeConfig_init(OWNER, wei(0.1)); + + distributionFactory = await ethers.getContractFactory('Distribution', { + libraries: { + LinearDistributionIntervalDecrease: lib, + }, + }); + distributionImplementation = await distributionFactory.deploy(); + + const factoryImpl = await l1FactoryFactory.deploy(); + const factoryProxy = await ERC1967ProxyFactory.deploy(factoryImpl, '0x'); + l1Factory = l1FactoryFactory.attach(factoryProxy) as L1Factory; + + await l1Factory.L1Factory_init(); + + const poolTypes = [PoolTypesL1.DISTRIBUTION, PoolTypesL1.L1_SENDER]; + const poolImplementations = [ + await distributionImplementation.getAddress(), + await l1SenderImplementation.getAddress(), + ]; + + await l1Factory.setImplementation(poolTypes[0], poolImplementations[0]); + await l1Factory.setImplementation(poolTypes[1], poolImplementations[1]); + + await reverter.snapshot(); + }); + + afterEach(reverter.revert); + + function getL1FactoryParams() { + const depositTokenExternalDeps: L1Factory.DepositTokenExternalDepsStruct = { + token: stEthMock, + wToken: wstEthMock, + }; + + const lzExternalDeps: L1Factory.LzExternalDepsStruct = { + endpoint: lzEndpoint, + zroPaymentAddress: ZERO_ADDR, + adapterParams: '0x', + destinationChainId: 2, + }; + + const arbExternalDeps: L1Factory.ArbExternalDepsStruct = { + endpoint: gatewayRouterMock, + }; + + return { depositTokenExternalDeps, lzExternalDeps, arbExternalDeps }; + } + + function getL1DefaultParams() { + const l1Params: L1Factory.L1ParamsStruct = { + protocolName: 'Mor20', + isNotUpgradeable: false, + poolsInfo: [], + l2TokenReceiver: SECOND, + l2MessageReceiver: SECOND, + }; + + return l1Params; + } + + describe('UUPS proxy functionality', () => { + describe('#L1Factory_init', () => { + it('should revert if try to call init function twice', async () => { + const reason = 'Initializable: contract is already initialized'; + + await expect(l1Factory.L1Factory_init()).to.be.rejectedWith(reason); + }); + + describe('#_authorizeUpgrade', () => { + it('should correctly upgrade', async () => { + const l1FactoryV2Factory = await ethers.getContractFactory('FactoryMockV2'); + const l1FactoryV2Implementation = await l1FactoryV2Factory.deploy(); + + await l1Factory.upgradeTo(l1FactoryV2Implementation); + + const l1factoryV2 = l1FactoryV2Factory.attach(await l1FactoryV2Implementation.getAddress()) as L1FactoryV2; + + expect(await l1factoryV2.version()).to.eq(2); + }); + it('should revert if caller is not the owner', async () => { + await expect(l1Factory.connect(SECOND).upgradeTo(ZERO_ADDR)).to.be.revertedWith( + 'Ownable: caller is not the owner', + ); + }); + }); + }); + }); + + describe('setDepositTokenExternalDeps', () => { + it('should set deposit token external deps', async () => { + const { depositTokenExternalDeps } = getL1FactoryParams(); + + await l1Factory.setDepositTokenExternalDeps(depositTokenExternalDeps); + + const actualDepositTokenExternalDeps = await l1Factory.depositTokenExternalDeps(); + expect(actualDepositTokenExternalDeps.token).to.equal(depositTokenExternalDeps.token); + expect(actualDepositTokenExternalDeps.wToken).to.equal(depositTokenExternalDeps.wToken); + }); + it('should revert if called by non-owner', async () => { + const { depositTokenExternalDeps } = getL1FactoryParams(); + + await expect(l1Factory.connect(SECOND).setDepositTokenExternalDeps(depositTokenExternalDeps)).to.be.revertedWith( + 'Ownable: caller is not the owner', + ); + }); + it('should revert if token is zero address', async () => { + const { depositTokenExternalDeps } = getL1FactoryParams(); + depositTokenExternalDeps.token = ZERO_ADDR; + + await expect(l1Factory.setDepositTokenExternalDeps(depositTokenExternalDeps)).to.be.revertedWith( + 'L1F: invalid token', + ); + }); + it('should revert if wToken is zero address', async () => { + const { depositTokenExternalDeps } = getL1FactoryParams(); + depositTokenExternalDeps.wToken = ZERO_ADDR; + + await expect(l1Factory.setDepositTokenExternalDeps(depositTokenExternalDeps)).to.be.revertedWith( + 'L1F: invalid wtoken', + ); + }); + }); + + describe('setLzExternalDeps', () => { + it('should set lz external deps', async () => { + const { lzExternalDeps } = getL1FactoryParams(); + + await l1Factory.setLzExternalDeps(lzExternalDeps); + + const actualLzExternalDeps = await l1Factory.lzExternalDeps(); + expect(actualLzExternalDeps.endpoint).to.equal(lzExternalDeps.endpoint); + expect(actualLzExternalDeps.zroPaymentAddress).to.equal(lzExternalDeps.zroPaymentAddress); + expect(actualLzExternalDeps.adapterParams).to.equal(lzExternalDeps.adapterParams); + expect(actualLzExternalDeps.destinationChainId).to.equal(lzExternalDeps.destinationChainId); + }); + it('should revert if called by non-owner', async () => { + const { lzExternalDeps } = getL1FactoryParams(); + + await expect(l1Factory.connect(SECOND).setLzExternalDeps(lzExternalDeps)).to.be.revertedWith( + 'Ownable: caller is not the owner', + ); + }); + it('should revert if endpoint is zero address', async () => { + const { lzExternalDeps } = getL1FactoryParams(); + lzExternalDeps.endpoint = ZERO_ADDR; + + await expect(l1Factory.setLzExternalDeps(lzExternalDeps)).to.be.revertedWith('L1F: invalid LZ endpoint'); + }); + it('should revert if destinationChainId is zero', async () => { + const { lzExternalDeps } = getL1FactoryParams(); + lzExternalDeps.destinationChainId = 0; + + await expect(l1Factory.setLzExternalDeps(lzExternalDeps)).to.be.revertedWith('L1F: invalid chain ID'); + }); + }); + + describe('setArbExternalDeps', () => { + it('should set arb external deps', async () => { + const { arbExternalDeps } = getL1FactoryParams(); + + await l1Factory.setArbExternalDeps(arbExternalDeps); + + const actualArbExternalDeps = await l1Factory.arbExternalDeps(); + expect(actualArbExternalDeps).to.equal(arbExternalDeps.endpoint); + }); + it('should revert if called by non-owner', async () => { + const { arbExternalDeps } = getL1FactoryParams(); + + await expect(l1Factory.connect(SECOND).setArbExternalDeps(arbExternalDeps)).to.be.revertedWith( + 'Ownable: caller is not the owner', + ); + }); + it('should revert if endpoint is zero address', async () => { + const { arbExternalDeps } = getL1FactoryParams(); + arbExternalDeps.endpoint = ZERO_ADDR; + + await expect(l1Factory.setArbExternalDeps(arbExternalDeps)).to.be.revertedWith('L1F: invalid ARB endpoint'); + }); + }); + + describe('deploy', () => { + beforeEach(async () => { + const { depositTokenExternalDeps, lzExternalDeps, arbExternalDeps } = getL1FactoryParams(); + + await l1Factory.setDepositTokenExternalDeps(depositTokenExternalDeps); + await l1Factory.setLzExternalDeps(lzExternalDeps); + await l1Factory.setArbExternalDeps(arbExternalDeps); + }); + + it('should deploy', async () => { + const l1Params = getL1DefaultParams(); + + await l1Factory.deploy(l1Params); + + const distribution = distributionFactory.attach( + await l1Factory.deployedProxies(OWNER, l1Params.protocolName, PoolTypesL1.DISTRIBUTION), + ) as Distribution; + const l1Sender = l1SenderFactory.attach( + await l1Factory.deployedProxies(OWNER, l1Params.protocolName, PoolTypesL1.L1_SENDER), + ) as L1Sender; + + expect(await distribution.owner()).to.equal(OWNER); + expect(await l1Sender.owner()).to.equal(OWNER); + + expect(await distribution.depositToken()).to.equal((await l1Factory.depositTokenExternalDeps()).token); + expect(await distribution.l1Sender()).to.equal(l1Sender); + + expect(await l1Sender.unwrappedDepositToken()).to.equal((await l1Factory.depositTokenExternalDeps()).token); + expect(await l1Sender.distribution()).to.equal(distribution); + + const depositTokenConfig = await l1Sender.depositTokenConfig(); + expect(depositTokenConfig.token).to.equal((await l1Factory.depositTokenExternalDeps()).wToken); + expect(depositTokenConfig.gateway).to.equal(await l1Factory.arbExternalDeps()); + expect(depositTokenConfig.receiver).to.equal(l1Params.l2TokenReceiver); + + const rewardTokenConfig = await l1Sender.rewardTokenConfig(); + expect(rewardTokenConfig.gateway).to.equal((await l1Factory.lzExternalDeps()).endpoint); + expect(rewardTokenConfig.receiver).to.equal(l1Params.l2MessageReceiver); + expect(rewardTokenConfig.receiverChainId).to.equal((await l1Factory.lzExternalDeps()).destinationChainId); + expect(rewardTokenConfig.zroPaymentAddress).to.equal((await l1Factory.lzExternalDeps()).zroPaymentAddress); + expect(rewardTokenConfig.adapterParams).to.equal((await l1Factory.lzExternalDeps()).adapterParams); + }); + it('should remove upgradeable flag if isNotUpgradeable is true', async () => { + const l1Params = getL1DefaultParams(); + l1Params.isNotUpgradeable = true; + + await l1Factory.deploy(l1Params); + + const distribution = distributionFactory.attach( + await l1Factory.deployedProxies(OWNER, l1Params.protocolName, PoolTypesL1.DISTRIBUTION), + ) as Distribution; + + expect(await distribution.isNotUpgradeable()).to.be.true; + }); + it('should revert if contract is paused', async () => { + await l1Factory.pause(); + + await expect(l1Factory.deploy(getL1DefaultParams())).to.be.revertedWith('Pausable: paused'); + }); + }); +}); diff --git a/test/L1/L1Sender.test.ts b/test/L1/L1Sender.test.ts index 78818ac..9745748 100644 --- a/test/L1/L1Sender.test.ts +++ b/test/L1/L1Sender.test.ts @@ -3,7 +3,6 @@ import { expect } from 'chai'; import { ethers } from 'hardhat'; import { - ERC20MOR, GatewayRouterMock, IL1Sender, L1Sender, @@ -11,11 +10,11 @@ import { L2MessageReceiver, LZEndpointMock, LayerZeroEndpointV2Mock, + MOR20, StETHMock, WStETHMock, } from '@/generated-types/ethers'; import { ZERO_ADDR } from '@/scripts/utils/constants'; -import { wei } from '@/scripts/utils/utils'; import { Reverter } from '@/test/helpers/reverter'; describe('L1Sender', () => { @@ -39,7 +38,7 @@ describe('L1Sender', () => { let l1Sender: L1Sender; let l2MessageReceiver: L2MessageReceiver; - let rewardToken: ERC20MOR; + let rewardToken: MOR20; before(async () => { [OWNER, SECOND] = await ethers.getSigners(); @@ -56,7 +55,7 @@ describe('L1Sender', () => { ] = await Promise.all([ ethers.getContractFactory('ERC1967Proxy'), ethers.getContractFactory('LZEndpointMock'), - ethers.getContractFactory('ERC20MOR'), + ethers.getContractFactory('MOR20'), ethers.getContractFactory('L1Sender'), ethers.getContractFactory('GatewayRouterMock'), ethers.getContractFactory('StETHMock'), @@ -126,257 +125,122 @@ describe('L1Sender', () => { await reverter.revert(); }); - // describe("UUPS proxy functionality", () => { - // let rewardTokenConfig: IL1Sender.RewardTokenConfigStruct; - // let depositTokenConfig: IL1Sender.DepositTokenConfigStruct; - - // before(async () => { - // rewardTokenConfig = { - // gateway: lZEndpointMockL1, - // receiver: l2MessageReceiver, - // receiverChainId: receiverChainId, - // zroPaymentAddress: ZERO_ADDR, - // adapterParams: "0x", - // }; - // depositTokenConfig = { - // token: depositToken, - // gateway: gatewayRouter, - // receiver: SECOND, - // }; - // }); - - // describe("#constructor", () => { - // it("should disable initialize function", async () => { - // const reason = "Initializable: contract is already initialized"; - - // const l1Sender = await (await ethers.getContractFactory("L1Sender")).deploy(); - - // await expect(l1Sender.L1Sender__init(OWNER, rewardTokenConfig, depositTokenConfig)).to.be.rejectedWith(reason); - // }); - // }); - - // describe("#L1Sender__init", () => { - // it("should revert if try to call init function twice", async () => { - // const reason = "Initializable: contract is already initialized"; - - // await expect(l1Sender.L1Sender__init(OWNER, rewardTokenConfig, depositTokenConfig)).to.be.rejectedWith(reason); - // }); - // it("should setup config", async () => { - // expect(await l1Sender.distribution()).to.be.equal(OWNER.address); - - // expect(await l1Sender.rewardTokenConfig()).to.be.deep.equal([ - // await lZEndpointMockL1.getAddress(), - // await l2MessageReceiver.getAddress(), - // receiverChainId, - // ZERO_ADDR, - // "0x", - // ]); - - // expect(await l1Sender.depositTokenConfig()).to.be.deep.equal([ - // await depositToken.getAddress(), - // await gatewayRouter.getAddress(), - // SECOND.address, - // ]); - - // expect(await unwrappedToken.allowance(l1Sender, depositToken)).to.be.equal(ethers.MaxUint256); - // expect(await depositToken.allowance(l1Sender, gatewayRouter)).to.be.equal(ethers.MaxUint256); - // }); - // }); - - // describe("#_authorizeUpgrade", () => { - // it("should correctly upgrade", async () => { - // const l1SenderV2Factory = await ethers.getContractFactory("L1SenderV2"); - // const l1SenderV2Implementation = await l1SenderV2Factory.deploy(); - - // await l1Sender.upgradeTo(l1SenderV2Implementation); - - // const l1SenderV2 = l1SenderV2Factory.attach(l1Sender) as L1SenderV2; - - // expect(await l1SenderV2.version()).to.eq(2); - // }); - // it("should revert if caller is not the owner", async () => { - // await expect(l1Sender.connect(SECOND).upgradeTo(ZERO_ADDR)).to.be.revertedWith( - // "Ownable: caller is not the owner", - // ); - // }); - // }); - // }); + describe('UUPS proxy functionality', () => { + let rewardTokenConfig: IL1Sender.RewardTokenConfigStruct; + let depositTokenConfig: IL1Sender.DepositTokenConfigStruct; - describe('supportsInterface', () => { - it('should support IL1Sender', async () => { - expect(await l1Sender.supportsInterface('0x0d3ba6cb')).to.be.true; - }); - it('should support IERC165', async () => { - expect(await l1Sender.supportsInterface('0x01ffc9a7')).to.be.true; - }); - }); - - describe('setDistribution', () => { - it('should set distribution', async () => { - await l1Sender.setDistribution(SECOND); - expect(await l1Sender.distribution()).to.be.equal(SECOND.address); - }); - it('should revert if not called by the owner', async () => { - await expect(l1Sender.connect(SECOND).setDistribution(SECOND)).to.be.revertedWith( - 'Ownable: caller is not the owner', - ); - }); - }); - - describe('setRewardTokenConfig', () => { - it('should set new config', async () => { - const newConfig = { - gateway: l2MessageReceiver, - receiver: lZEndpointMockL1, - receiverChainId: 0, + before(async () => { + rewardTokenConfig = { + gateway: lZEndpointMockL1, + receiver: l2MessageReceiver, + receiverChainId: receiverChainId, zroPaymentAddress: ZERO_ADDR, adapterParams: '0x', }; - - await l1Sender.setRewardTokenConfig(newConfig); - - expect(await l1Sender.rewardTokenConfig()).to.be.deep.equal([ - await l2MessageReceiver.getAddress(), - await lZEndpointMockL1.getAddress(), - 0, - ZERO_ADDR, - '0x', - ]); - }); - it('should revert if not called by the owner', async () => { - await expect( - l1Sender.connect(SECOND).setRewardTokenConfig({ - gateway: lZEndpointMockL1, - receiver: l2MessageReceiver, - receiverChainId: receiverChainId, - zroPaymentAddress: ZERO_ADDR, - adapterParams: '0x', - }), - ).to.be.revertedWith('Ownable: caller is not the owner'); - }); - }); - - describe('setDepositTokenConfig', () => { - it('should reset allowances when token and gateway changed', async () => { - const [WStETHMock, GatewayRouterMock, StETHMock] = await Promise.all([ - ethers.getContractFactory('WStETHMock'), - ethers.getContractFactory('GatewayRouterMock'), - ethers.getContractFactory('StETHMock'), - ]); - - const newUnwrappedToken = await StETHMock.deploy(); - - const [newDepositToken, newGatewayRouter] = await Promise.all([ - WStETHMock.deploy(newUnwrappedToken), - GatewayRouterMock.deploy(), - ]); - - const newConfig = { - token: newDepositToken, - gateway: newGatewayRouter, - receiver: OWNER, + depositTokenConfig = { + token: depositToken, + gateway: gatewayRouter, + receiver: SECOND, }; - - await l1Sender.setDepositTokenConfig(newConfig); - - expect(await l1Sender.depositTokenConfig()).to.be.deep.equal([ - await newDepositToken.getAddress(), - await newGatewayRouter.getAddress(), - OWNER.address, - ]); - - expect(await unwrappedToken.allowance(l1Sender, depositToken)).to.be.equal(0); - expect(await depositToken.allowance(l1Sender, gatewayRouter)).to.be.equal(0); - - expect(await newUnwrappedToken.allowance(l1Sender, newDepositToken)).to.be.equal(ethers.MaxUint256); - expect(await newDepositToken.allowance(l1Sender, newGatewayRouter)).to.be.equal(ethers.MaxUint256); }); - it('should reset allowances when only token changed', async () => { - const [WStETHMock, StETHMock] = await Promise.all([ - ethers.getContractFactory('WStETHMock'), - ethers.getContractFactory('StETHMock'), - ]); - const newUnwrappedToken = await StETHMock.deploy(); - const [newDepositToken] = await Promise.all([WStETHMock.deploy(newUnwrappedToken)]); + describe('#constructor', () => { + it('should disable initialize function', async () => { + const reason = 'Initializable: contract is already initialized'; - const newConfig = { - token: newDepositToken, - gateway: gatewayRouter, - receiver: OWNER, - }; + const l1Sender = await (await ethers.getContractFactory('L1Sender')).deploy(); - await l1Sender.setDepositTokenConfig(newConfig); - - expect(await l1Sender.depositTokenConfig()).to.be.deep.equal([ - await newDepositToken.getAddress(), - await gatewayRouter.getAddress(), - OWNER.address, - ]); + await expect(l1Sender.L1Sender__init(OWNER, rewardTokenConfig, depositTokenConfig)).to.be.rejectedWith(reason); + }); + }); - expect(await unwrappedToken.allowance(l1Sender, depositToken)).to.be.equal(0); - expect(await depositToken.allowance(l1Sender, gatewayRouter)).to.be.equal(0); + describe('#L1Sender__init', () => { + it('should revert if try to call init function twice', async () => { + const reason = 'Initializable: contract is already initialized'; - expect(await newUnwrappedToken.allowance(l1Sender, newDepositToken)).to.be.equal(ethers.MaxUint256); + await expect(l1Sender.L1Sender__init(OWNER, rewardTokenConfig, depositTokenConfig)).to.be.rejectedWith(reason); + }); + it('should setup config', async () => { + expect(await l1Sender.distribution()).to.be.equal(OWNER.address); + + expect(await l1Sender.rewardTokenConfig()).to.be.deep.equal([ + await lZEndpointMockL1.getAddress(), + await l2MessageReceiver.getAddress(), + receiverChainId, + ZERO_ADDR, + '0x', + ]); + + expect(await l1Sender.depositTokenConfig()).to.be.deep.equal([ + await depositToken.getAddress(), + await gatewayRouter.getAddress(), + SECOND.address, + ]); + + expect(await unwrappedToken.allowance(l1Sender, depositToken)).to.be.equal(ethers.MaxUint256); + expect(await depositToken.allowance(l1Sender, gatewayRouter)).to.be.equal(ethers.MaxUint256); + }); + it('should revert if receiver is zero address', async () => { + const [ERC1967ProxyFactory, L1Sender] = await Promise.all([ + ethers.getContractFactory('ERC1967Proxy'), + ethers.getContractFactory('L1Sender'), + ]); + const l1SenderImplementation = await L1Sender.deploy(); + const l1SenderProxy = await ERC1967ProxyFactory.deploy(l1SenderImplementation, '0x'); + const l1Sender = L1Sender.attach(l1SenderProxy) as L1Sender; + + await expect( + l1Sender.L1Sender__init(OWNER, rewardTokenConfig, { + ...depositTokenConfig, + receiver: ZERO_ADDR, + }), + ).to.be.rejectedWith('L1S: invalid receiver'); + }); }); - it('should reset allowances when only gateway changed', async () => { - const [GatewayRouterMock] = await Promise.all([ethers.getContractFactory('GatewayRouterMock')]); - const [newGatewayRouter] = await Promise.all([GatewayRouterMock.deploy()]); - const newConfig = { - token: depositToken, - gateway: newGatewayRouter, - receiver: OWNER, - }; - - await l1Sender.setDepositTokenConfig(newConfig); + describe('#_authorizeUpgrade', () => { + it('should correctly upgrade', async () => { + const l1SenderV2Factory = await ethers.getContractFactory('L1SenderV2'); + const l1SenderV2Implementation = await l1SenderV2Factory.deploy(); - expect(await l1Sender.depositTokenConfig()).to.be.deep.equal([ - await depositToken.getAddress(), - await newGatewayRouter.getAddress(), - OWNER.address, - ]); + await l1Sender.upgradeTo(l1SenderV2Implementation); - expect(await depositToken.allowance(l1Sender, gatewayRouter)).to.be.equal(0); + const l1SenderV2 = l1SenderV2Factory.attach(l1Sender) as L1SenderV2; - expect(await unwrappedToken.allowance(l1Sender, depositToken)).to.be.equal(ethers.MaxUint256); - expect(await depositToken.allowance(l1Sender, newGatewayRouter)).to.be.equal(ethers.MaxUint256); + expect(await l1SenderV2.version()).to.eq(2); + }); + it('should revert if caller is not the owner', async () => { + await expect(l1Sender.connect(SECOND).upgradeTo(ZERO_ADDR)).to.be.revertedWith( + 'Ownable: caller is not the owner', + ); + }); }); - it('should not change allowances when only receiver changed', async () => { - const newConfig = { - token: depositToken, - gateway: gatewayRouter, - receiver: SECOND, - }; + }); - await l1Sender.setDepositTokenConfig(newConfig); + describe('supportsInterface', () => { + it('should support IL1Sender', async () => { + expect(await l1Sender.supportsInterface('0xb772d774')).to.be.true; + }); + it('should support IERC165', async () => { + expect(await l1Sender.supportsInterface('0x01ffc9a7')).to.be.true; + }); + }); - expect(await l1Sender.depositTokenConfig()).to.be.deep.equal([ - await depositToken.getAddress(), - await gatewayRouter.getAddress(), - SECOND.address, - ]); + describe('setRewardTokenLZParams', () => { + it('should update lz params', async () => { + await l1Sender.setRewardTokenLZParams(SECOND, '0x1234'); - expect(await unwrappedToken.allowance(l1Sender, depositToken)).to.be.equal(ethers.MaxUint256); - expect(await depositToken.allowance(l1Sender, gatewayRouter)).to.be.equal(ethers.MaxUint256); + const config = await l1Sender.rewardTokenConfig(); + expect(config.gateway).to.eq(await lZEndpointMockL1.getAddress()); + expect(config.receiver).to.eq(await l2MessageReceiver.getAddress()); + expect(config.receiverChainId).to.eq(receiverChainId); + expect(config.zroPaymentAddress).to.eq(await SECOND.getAddress()); + expect(config.adapterParams).to.eq('0x1234'); }); it('should revert if not called by the owner', async () => { - await expect( - l1Sender.connect(OWNER).setDepositTokenConfig({ - token: depositToken, - gateway: gatewayRouter, - receiver: ZERO_ADDR, - }), - ).to.be.revertedWith('L1S: invalid receiver'); - }); - it('should revert if not called by the owner', async () => { - await expect( - l1Sender.connect(SECOND).setDepositTokenConfig({ - token: depositToken, - gateway: gatewayRouter, - receiver: SECOND, - }), - ).to.be.revertedWith('Ownable: caller is not the owner'); + await expect(l1Sender.connect(SECOND).setRewardTokenLZParams(SECOND, '0x1234')).to.be.revertedWith( + 'Ownable: caller is not the owner', + ); }); }); @@ -404,57 +268,6 @@ describe('L1Sender', () => { l1Sender.connect(SECOND).sendMintMessage(SECOND, '999', OWNER, { value: ethers.parseEther('0.1') }), ).to.be.revertedWith('L1S: invalid sender'); }); - it('should not revert if not L2MessageReceiver sender', async () => { - await l2MessageReceiver.setParams(rewardToken, { - gateway: lZEndpointMockL2, - sender: OWNER, - senderChainId: senderChainId, - }); - - await l1Sender.sendMintMessage(SECOND, '999', OWNER, { value: ethers.parseEther('0.1') }); - expect(await rewardToken.balanceOf(SECOND)).to.eq(0); - }); - it('should `retryMessage` for failed message on the `L2MessageReceiver`', async () => { - const amount = '998'; - - // START send invalid call to L2MessageReceiver - // Set invalid sender in config - await l2MessageReceiver.setParams(rewardToken, { - gateway: lZEndpointMockL2, - sender: ZERO_ADDR, - senderChainId: senderChainId, - }); - - await l1Sender.sendMintMessage(SECOND, amount, OWNER, { value: ethers.parseEther('0.1') }); - expect(await rewardToken.balanceOf(SECOND)).to.eq('0'); - // END - - // Set valid sender in config - await l2MessageReceiver.setParams(rewardToken, { - gateway: lZEndpointMockL2, - sender: l1Sender, - senderChainId: senderChainId, - }); - - // Must send messages even though the previous one may be blocked - await l1Sender.sendMintMessage(SECOND, '1', OWNER, { value: ethers.parseEther('0.1') }); - expect(await rewardToken.balanceOf(SECOND)).to.eq('1'); - - // START retry to send invalid message - const senderAndReceiverAddress = ethers.solidityPacked( - ['address', 'address'], - [await l1Sender.getAddress(), await l2MessageReceiver.getAddress()], - ); - const payload = ethers.AbiCoder.defaultAbiCoder().encode(['address', 'uint256'], [SECOND.address, amount]); - - await l2MessageReceiver.retryMessage(senderChainId, senderAndReceiverAddress, 1, payload); - expect(await rewardToken.balanceOf(SECOND)).to.eq(Number(amount) + 1); - // END - - // Next messages shouldn't fail - await l1Sender.sendMintMessage(SECOND, '1', OWNER, { value: ethers.parseEther('0.1') }); - expect(await rewardToken.balanceOf(SECOND)).to.eq(Number(amount) + 2); - }); }); }); diff --git a/test/L1/Mor20FactoryL1.test.ts b/test/L1/Mor20FactoryL1.test.ts deleted file mode 100644 index 16f9a18..0000000 --- a/test/L1/Mor20FactoryL1.test.ts +++ /dev/null @@ -1,188 +0,0 @@ -import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; -import { expect } from 'chai'; -import { ethers } from 'hardhat'; - -import { Reverter } from '../helpers/reverter'; - -import { - CorePropertiesL1, - Distribution, - GatewayRouterMock, - L1Sender, - LinearDistributionIntervalDecrease, - Mor20FactoryL1, - StETHMock, - WStETHMock, -} from '@/generated-types/ethers'; -import { ETHER_ADDR, ZERO_ADDR } from '@/scripts/utils/constants'; - -enum PoolTypes { - DISTRIBUTION, - L1_SENDER, -} - -describe.only('Mor20FactoryL1', () => { - const reverter = new Reverter(); - - let OWNER: SignerWithAddress; - let SECOND: SignerWithAddress; - - let mor20FactoryL1: Mor20FactoryL1; - - let l1SenderImplementation: L1Sender; - let distributionImplementation: Distribution; - let coreProperties: CorePropertiesL1; - - let stEthMock: StETHMock; - let wstEthMock: WStETHMock; - let gatewayRouterMock: GatewayRouterMock; - let poolTypes: PoolTypes[]; - let poolImplementations: string[]; - let lib: LinearDistributionIntervalDecrease; - - before(async () => { - [OWNER, SECOND] = await ethers.getSigners(); - - const [ - libFactory, - l1SenderFactory, - mor20FactoryL1Factory, - stEthMockFactory, - wstEthMockFactory, - gatewayRouterMockFactory, - corePropertiesFactory, - ] = await Promise.all([ - ethers.getContractFactory('LinearDistributionIntervalDecrease'), - ethers.getContractFactory('L1Sender'), - ethers.getContractFactory('Mor20FactoryL1'), - ethers.getContractFactory('StETHMock'), - ethers.getContractFactory('WStETHMock'), - ethers.getContractFactory('GatewayRouterMock'), - ethers.getContractFactory('CorePropertiesL1'), - ]); - - [lib, l1SenderImplementation, stEthMock, gatewayRouterMock] = await Promise.all([ - libFactory.deploy(), - l1SenderFactory.deploy(), - stEthMockFactory.deploy(), - gatewayRouterMockFactory.deploy(), - ]); - wstEthMock = await wstEthMockFactory.deploy(stEthMock); - coreProperties = await corePropertiesFactory.deploy(gatewayRouterMock, SECOND, ZERO_ADDR, 1); - - const distributionFactory = await ethers.getContractFactory('Distribution', { - libraries: { - LinearDistributionIntervalDecrease: lib, - }, - }); - distributionImplementation = await distributionFactory.deploy(); - - mor20FactoryL1 = await mor20FactoryL1Factory.deploy(coreProperties); - - poolTypes = [PoolTypes.DISTRIBUTION, PoolTypes.L1_SENDER]; - poolImplementations = [await distributionImplementation.getAddress(), await l1SenderImplementation.getAddress()]; - - await reverter.snapshot(); - }); - - afterEach(reverter.revert); - - function getMor20DeployParams() { - const mor20DeployParams: Mor20FactoryL1.Mor20DeployParamsStruct = { - name: 'Mor20', - depositToken: stEthMock, - poolsInfo: [], - messageReceiver: ETHER_ADDR, - zroPaymentAddress: ZERO_ADDR, - l2EndpointId: 0, - adapterParams: '0x', - wrappedToken: wstEthMock, - tokenReceiver: ETHER_ADDR, - }; - - return mor20DeployParams; - } - - describe('#deployMor20OnL1', () => { - it('should deploy and initialize a Mor20 on L1', async () => { - await mor20FactoryL1.setNewImplementations(poolTypes, poolImplementations); - - const deployParams = getMor20DeployParams(); - - const predictedMor20Address = await mor20FactoryL1.predictMor20Address(OWNER, deployParams.name); - - const tx = await mor20FactoryL1.deployMor20OnL1(deployParams); - - await expect(tx) - .to.emit(mor20FactoryL1, 'Mor20Deployed') - .withArgs(deployParams.name, ...predictedMor20Address); - - const distribution = await ethers.getContractAt('Distribution', predictedMor20Address[0]); - const l1Sender = await ethers.getContractAt('L1Sender', predictedMor20Address[1]); - - expect(await distribution.depositToken()).to.equal(deployParams.depositToken); - expect(await distribution.l1Sender()).to.equal(l1Sender); - - expect(await l1Sender.unwrappedDepositToken()).to.equal(deployParams.depositToken); - expect(await l1Sender.distribution()).to.equal(distribution); - }); - - it('should revert if name is an empty string', async () => { - const deployParams = getMor20DeployParams(); - deployParams.name = ''; - - await expect(mor20FactoryL1.deployMor20OnL1(deployParams)).to.be.revertedWith( - 'BaseFactory: pool name cannot be empty', - ); - }); - - it('should revert if Mor20 with the same name already exists', async () => { - await mor20FactoryL1.setNewImplementations(poolTypes, poolImplementations); - - const deployParams = getMor20DeployParams(); - - await mor20FactoryL1.deployMor20OnL1(deployParams); - - await expect(mor20FactoryL1.deployMor20OnL1(deployParams)).to.be.revertedWith( - 'BaseFactory: pool name is already taken', - ); - }); - - it('should revert if called by a non-owner', async () => { - const deployParams = getMor20DeployParams(); - - await expect(mor20FactoryL1.connect(SECOND).deployMor20OnL1(deployParams)).to.be.revertedWith( - 'Ownable: caller is not the owner', - ); - }); - }); - - describe('#setNewImplementations', () => { - it('should set new implementations', async () => { - await mor20FactoryL1.setNewImplementations(poolTypes, poolImplementations); - - const deployParams = getMor20DeployParams(); - const distributionAddress = (await mor20FactoryL1.predictMor20Address(OWNER, deployParams.name)).distribution; - await mor20FactoryL1.deployMor20OnL1(deployParams); - - const distributionV2Factory = await ethers.getContractFactory('DistributionV2', { - libraries: { - LinearDistributionIntervalDecrease: lib, - }, - }); - const distributionV2Implementation = await distributionV2Factory.deploy(); - - await mor20FactoryL1.setNewImplementations(poolTypes, [distributionV2Implementation, l1SenderImplementation]); - - const distribution = await ethers.getContractAt('DistributionV2', distributionAddress); - - expect(await distribution.version()).to.equal(2); - }); - - it('should revert if called by a non-owner', async () => { - await expect( - mor20FactoryL1.connect(SECOND).setNewImplementations(poolTypes, poolImplementations), - ).to.be.revertedWith('Ownable: caller is not the owner'); - }); - }); -}); diff --git a/test/L2/L2Factory.test.ts b/test/L2/L2Factory.test.ts new file mode 100644 index 0000000..3593835 --- /dev/null +++ b/test/L2/L2Factory.test.ts @@ -0,0 +1,302 @@ +import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { PoolTypesL2 } from '../helpers/helper'; +import { Reverter } from '../helpers/reverter'; + +import { + L2Factory, + L2FactoryV2, + L2MessageReceiver, + L2MessageReceiver__factory, + L2TokenReceiver, + L2TokenReceiver__factory, + LZEndpointMock, + LayerZeroEndpointV2Mock, + MOR20, + MOR20Deployer, + MOR20__factory, + NonfungiblePositionManagerMock, + SwapRouterMock, +} from '@/generated-types/ethers'; +import { ETHER_ADDR, ZERO_ADDR } from '@/scripts/utils/constants'; + +describe('L2Factory', () => { + const senderChainId = 101; + + const reverter = new Reverter(); + + let OWNER: SignerWithAddress; + let SECOND: SignerWithAddress; + + let l2Factory: L2Factory; + + let lzEndpoint: LZEndpointMock; + let lzEndpointOFT: LayerZeroEndpointV2Mock; + + let swapRouter: SwapRouterMock; + let nonfungiblePositionManager: NonfungiblePositionManagerMock; + + let l2MessageReceiverFactory: L2MessageReceiver__factory; + let l2TokenReceiverFactory: L2TokenReceiver__factory; + let MOR20Factory: MOR20__factory; + + before(async () => { + [OWNER, SECOND] = await ethers.getSigners(); + + const [ + ERC1967ProxyFactory, + LZEndpointMockFactory, + LayerZeroEndpointV2Mock, + MOR20DeployerFactory, + SwapRouterMock, + NonfungiblePositionManagerMock, + ] = await Promise.all([ + ethers.getContractFactory('ERC1967Proxy'), + ethers.getContractFactory('LZEndpointMock'), + ethers.getContractFactory('LayerZeroEndpointV2Mock'), + ethers.getContractFactory('MOR20Deployer'), + ethers.getContractFactory('SwapRouterMock'), + ethers.getContractFactory('NonfungiblePositionManagerMock'), + ]); + + [l2MessageReceiverFactory, l2TokenReceiverFactory, MOR20Factory] = await Promise.all([ + ethers.getContractFactory('L2MessageReceiver'), + ethers.getContractFactory('L2TokenReceiver'), + ethers.getContractFactory('MOR20'), + ]); + + let l2MessageReceiver: L2MessageReceiver; + let l2TokenReceiver: L2TokenReceiver; + let MOR20Deployer: MOR20Deployer; + [ + lzEndpoint, + lzEndpointOFT, + l2MessageReceiver, + l2TokenReceiver, + MOR20Deployer, + swapRouter, + nonfungiblePositionManager, + ] = await Promise.all([ + LZEndpointMockFactory.deploy(senderChainId), + LayerZeroEndpointV2Mock.deploy(senderChainId, OWNER), + l2MessageReceiverFactory.deploy(), + l2TokenReceiverFactory.deploy(), + MOR20DeployerFactory.deploy(), + SwapRouterMock.deploy(), + NonfungiblePositionManagerMock.deploy(), + ]); + + const l2FactoryFactory = await ethers.getContractFactory('L2Factory', { + libraries: { + MOR20Deployer: MOR20Deployer, + }, + }); + const factoryImpl = await l2FactoryFactory.deploy(); + const factoryProxy = await ERC1967ProxyFactory.deploy(factoryImpl, '0x'); + l2Factory = l2FactoryFactory.attach(factoryProxy) as L2Factory; + + await l2Factory.L2Factory_init(); + + const poolTypes = [PoolTypesL2.L2_MESSAGE_RECEIVER, PoolTypesL2.L2_TOKEN_RECEIVER]; + const poolImplementations = [await l2MessageReceiver.getAddress(), await l2TokenReceiver.getAddress()]; + + await l2Factory.setImplementation(poolTypes[0], poolImplementations[0]); + await l2Factory.setImplementation(poolTypes[1], poolImplementations[1]); + + await reverter.snapshot(); + }); + + afterEach(reverter.revert); + + function getL2FactoryParams() { + const lzTokenExternalDeps: L2Factory.LzExternalDepsStruct = { + endpoint: lzEndpoint, + oftEndpoint: lzEndpointOFT, + senderChainId: senderChainId, + }; + + const uniswapExternalDeps: L2Factory.UniswapExternalDepsStruct = { + router: swapRouter, + nonfungiblePositionManager: nonfungiblePositionManager, + }; + + return { lzTokenExternalDeps, uniswapExternalDeps }; + } + + function getL2DefaultParams() { + const l2Params: L2Factory.L2ParamsStruct = { + protocolName: 'Mor20', + mor20Name: 'MOR20', + mor20Symbol: 'M20', + firstSwapParams_: { + tokenIn: ETHER_ADDR, + tokenOut: ETHER_ADDR, + fee: 100, + sqrtPriceLimitX96: 0, + }, + secondSwapFee: 3000, + secondSwapSqrtPriceLimitX96: 0, + }; + + return l2Params; + } + + describe('UUPS proxy functionality', () => { + describe('#L2Factory_init', () => { + it('should revert if try to call init function twice', async () => { + const reason = 'Initializable: contract is already initialized'; + + await expect(l2Factory.L2Factory_init()).to.be.rejectedWith(reason); + }); + + describe('#_authorizeUpgrade', () => { + it('should correctly upgrade', async () => { + const l2FactoryV2Factory = await ethers.getContractFactory('FactoryMockV2'); + const l2FactoryV2Implementation = await l2FactoryV2Factory.deploy(); + + await l2Factory.upgradeTo(l2FactoryV2Implementation); + + const l2factoryV2 = l2FactoryV2Factory.attach(await l2FactoryV2Implementation.getAddress()) as L2FactoryV2; + + expect(await l2factoryV2.version()).to.eq(2); + }); + it('should revert if caller is not the owner', async () => { + await expect(l2Factory.connect(SECOND).upgradeTo(ZERO_ADDR)).to.be.revertedWith( + 'Ownable: caller is not the owner', + ); + }); + }); + }); + }); + + describe('setLzExternalDeps', () => { + it('should set lz external deps', async () => { + const { lzTokenExternalDeps } = getL2FactoryParams(); + + await l2Factory.setLzExternalDeps(lzTokenExternalDeps); + + const actualLzTokenExternalDeps = await l2Factory.lzExternalDeps(); + expect(actualLzTokenExternalDeps.endpoint).to.equal(lzTokenExternalDeps.endpoint); + expect(actualLzTokenExternalDeps.oftEndpoint).to.equal(lzTokenExternalDeps.oftEndpoint); + expect(actualLzTokenExternalDeps.senderChainId).to.equal(lzTokenExternalDeps.senderChainId); + }); + it('should revert if `endpoint` is zero address', async () => { + const { lzTokenExternalDeps } = getL2FactoryParams(); + lzTokenExternalDeps.endpoint = ZERO_ADDR; + + await expect(l2Factory.setLzExternalDeps(lzTokenExternalDeps)).to.be.revertedWith('L2F: invalid LZ endpoint'); + }); + it('should revert if `oftEndpoint` is zero address', async () => { + const { lzTokenExternalDeps } = getL2FactoryParams(); + lzTokenExternalDeps.oftEndpoint = ZERO_ADDR; + + await expect(l2Factory.setLzExternalDeps(lzTokenExternalDeps)).to.be.revertedWith('L2F: invalid LZ OFT endpoint'); + }); + it('should revert if `senderChainId` is zero', async () => { + const { lzTokenExternalDeps } = getL2FactoryParams(); + lzTokenExternalDeps.senderChainId = 0; + + await expect(l2Factory.setLzExternalDeps(lzTokenExternalDeps)).to.be.revertedWith('L2F: invalid chain ID'); + }); + it('should revert if caller is not the owner', async () => { + await expect( + l2Factory.connect(SECOND).setLzExternalDeps(getL2FactoryParams().lzTokenExternalDeps), + ).to.be.revertedWith('Ownable: caller is not the owner'); + }); + }); + + describe('#setUniswapExternalDeps', () => { + it('should set uniswap external deps', async () => { + const { uniswapExternalDeps } = getL2FactoryParams(); + + await l2Factory.setUniswapExternalDeps(uniswapExternalDeps); + + const actualUniswapExternalDeps = await l2Factory.uniswapExternalDeps(); + expect(actualUniswapExternalDeps.router).to.equal(uniswapExternalDeps.router); + expect(actualUniswapExternalDeps.nonfungiblePositionManager).to.equal( + uniswapExternalDeps.nonfungiblePositionManager, + ); + }); + it('should revert if `router` is zero address', async () => { + const { uniswapExternalDeps } = getL2FactoryParams(); + uniswapExternalDeps.router = ZERO_ADDR; + + await expect(l2Factory.setUniswapExternalDeps(uniswapExternalDeps)).to.be.revertedWith('L2F: invalid UNI router'); + }); + it('should revert if `nonfungiblePositionManager` is zero address', async () => { + const { uniswapExternalDeps } = getL2FactoryParams(); + uniswapExternalDeps.nonfungiblePositionManager = ZERO_ADDR; + + await expect(l2Factory.setUniswapExternalDeps(uniswapExternalDeps)).to.be.revertedWith('L2F: invalid NPM'); + }); + it('should revert if caller is not the owner', async () => { + await expect( + l2Factory.connect(SECOND).setUniswapExternalDeps(getL2FactoryParams().uniswapExternalDeps), + ).to.be.revertedWith('Ownable: caller is not the owner'); + }); + }); + + describe('#deploy', () => { + beforeEach(async () => { + const { lzTokenExternalDeps, uniswapExternalDeps } = getL2FactoryParams(); + + await l2Factory.setLzExternalDeps(lzTokenExternalDeps); + await l2Factory.setUniswapExternalDeps(uniswapExternalDeps); + }); + + it('should deploy', async () => { + const l2Params = getL2DefaultParams(); + + await l2Factory.deploy(l2Params); + + const l2MessageReceiver = l2MessageReceiverFactory.attach( + await l2Factory.deployedProxies(OWNER, l2Params.protocolName, PoolTypesL2.L2_MESSAGE_RECEIVER), + ) as L2MessageReceiver; + const l2TokenReceiver = l2TokenReceiverFactory.attach( + await l2Factory.deployedProxies(OWNER, l2Params.protocolName, PoolTypesL2.L2_TOKEN_RECEIVER), + ) as L2TokenReceiver; + const MOR = MOR20Factory.attach( + await l2Factory.deployedProxies(OWNER, l2Params.protocolName, PoolTypesL2.MOR20), + ) as MOR20; + + expect(await l2MessageReceiver.owner()).to.equal(OWNER); + expect(await l2TokenReceiver.owner()).to.equal(OWNER); + + // expect(await l2MessageReceiver.rewardToken()).to.equal(MOR); + const config = await l2MessageReceiver.config(); + expect(config.gateway).to.equal((await l2Factory.lzExternalDeps()).endpoint); + // expect(config.sender).to.equal(); + expect(config.senderChainId).to.equal((await l2Factory.lzExternalDeps()).senderChainId); + + expect(await l2TokenReceiver.router()).to.equal((await l2Factory.uniswapExternalDeps()).router); + expect(await l2TokenReceiver.nonfungiblePositionManager()).to.equal( + (await l2Factory.uniswapExternalDeps()).nonfungiblePositionManager, + ); + + const firstSwapParams = await l2TokenReceiver.firstSwapParams(); + expect(firstSwapParams.tokenIn).to.equal(l2Params.firstSwapParams_.tokenIn); + expect(firstSwapParams.tokenOut).to.equal(l2Params.firstSwapParams_.tokenOut); + expect(firstSwapParams.fee).to.equal(l2Params.firstSwapParams_.fee); + expect(firstSwapParams.sqrtPriceLimitX96).to.equal(l2Params.firstSwapParams_.sqrtPriceLimitX96); + + const secondSwapParams = await l2TokenReceiver.secondSwapParams(); + expect(secondSwapParams.tokenIn).to.equal(l2Params.firstSwapParams_.tokenOut); + expect(secondSwapParams.tokenOut).to.equal(MOR); + expect(secondSwapParams.fee).to.equal(l2Params.secondSwapFee); + expect(secondSwapParams.sqrtPriceLimitX96).to.equal(l2Params.secondSwapSqrtPriceLimitX96); + + expect(await MOR.owner()).to.equal(OWNER); + expect(await MOR.name()).to.equal(l2Params.mor20Name); + expect(await MOR.symbol()).to.equal(l2Params.mor20Symbol); + expect(await MOR.endpoint()).to.equal((await l2Factory.lzExternalDeps()).oftEndpoint); + expect(await MOR.isMinter(l2MessageReceiver)).to.be.true; + }); + it('should revert if contract is paused', async () => { + await l2Factory.pause(); + + await expect(l2Factory.deploy(getL2DefaultParams())).to.be.revertedWith('Pausable: paused'); + }); + }); +}); diff --git a/test/L2/L2MessageReceiver.test.ts b/test/L2/L2MessageReceiver.test.ts index 1bdcad5..2775749 100644 --- a/test/L2/L2MessageReceiver.test.ts +++ b/test/L2/L2MessageReceiver.test.ts @@ -2,7 +2,16 @@ import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; import { expect } from 'chai'; import { ethers } from 'hardhat'; -import { ERC20MOR, L2MessageReceiver, L2MessageReceiverV2, LayerZeroEndpointV2Mock } from '@/generated-types/ethers'; +import { + ERC1967Proxy__factory, + L2MessageReceiver, + L2MessageReceiverV2, + L2MessageReceiver__factory, + LayerZeroEndpointV2Mock, + LayerZeroEndpointV2Mock__factory, + MOR20, + MOR20__factory, +} from '@/generated-types/ethers'; import { ZERO_ADDR, ZERO_BYTES32 } from '@/scripts/utils/constants'; import { wei } from '@/scripts/utils/utils'; import { Reverter } from '@/test/helpers/reverter'; @@ -15,21 +24,27 @@ describe('L2MessageReceiver', () => { let THIRD: SignerWithAddress; let l2MessageReceiver: L2MessageReceiver; - let mor: ERC20MOR; + let l2MessageReceiverFactory: L2MessageReceiver__factory; + let ERC1967ProxyFactory: ERC1967Proxy__factory; + + let mor: MOR20; let lZEndpointMock: LayerZeroEndpointV2Mock; + before(async () => { [OWNER, SECOND, THIRD] = await ethers.getSigners(); - const [ERC1967ProxyFactory, L2MessageReceiver, MOR, LayerZeroEndpointV2Mock] = await Promise.all([ + let MOR: MOR20__factory; + let LayerZeroEndpointV2Mock: LayerZeroEndpointV2Mock__factory; + [ERC1967ProxyFactory, l2MessageReceiverFactory, MOR, LayerZeroEndpointV2Mock] = await Promise.all([ ethers.getContractFactory('ERC1967Proxy'), ethers.getContractFactory('L2MessageReceiver'), - ethers.getContractFactory('ERC20MOR'), + ethers.getContractFactory('MOR20'), ethers.getContractFactory('LayerZeroEndpointV2Mock'), ]); - const l2MessageReceiverImplementation = await L2MessageReceiver.deploy(); + const l2MessageReceiverImplementation = await l2MessageReceiverFactory.deploy(); const l2MessageReceiverProxy = await ERC1967ProxyFactory.deploy(l2MessageReceiverImplementation, '0x'); - l2MessageReceiver = L2MessageReceiver.attach(l2MessageReceiverProxy) as L2MessageReceiver; + l2MessageReceiver = l2MessageReceiverFactory.attach(l2MessageReceiverProxy) as L2MessageReceiver; // Setup ERC20MOR token lZEndpointMock = await LayerZeroEndpointV2Mock.deploy(1, SECOND); @@ -48,43 +63,70 @@ describe('L2MessageReceiver', () => { await reverter.revert(); }); - // describe("UUPS proxy functionality", () => { - // describe("#constructor", () => { - // it("should disable initialize function", async () => { - // const reason = "Initializable: contract is already initialized"; + describe('UUPS proxy functionality', () => { + describe('#constructor', () => { + it('should disable initialize function', async () => { + const reason = 'Initializable: contract is already initialized'; - // const l2MessageReceiver = await (await ethers.getContractFactory("L2MessageReceiver")).deploy(); + const l2MessageReceiver = await (await ethers.getContractFactory('L2MessageReceiver')).deploy(); - // await expect(l2MessageReceiver.L2MessageReceiver__init()).to.be.rejectedWith(reason); - // }); - // }); + await expect( + l2MessageReceiver.L2MessageReceiver__init(ZERO_ADDR, { + gateway: ZERO_ADDR, + sender: ZERO_ADDR, + senderChainId: 0, + }), + ).to.be.rejectedWith(reason); + }); + }); - // describe("#L2MessageReceiver__init", () => { - // it("should revert if try to call init function twice", async () => { - // const reason = "Initializable: contract is already initialized"; + describe('#L2MessageReceiver__init', () => { + it('should revert if try to call init function twice', async () => { + const reason = 'Initializable: contract is already initialized'; + + await expect( + l2MessageReceiver.L2MessageReceiver__init(ZERO_ADDR, { + gateway: ZERO_ADDR, + sender: ZERO_ADDR, + senderChainId: 0, + }), + ).to.be.rejectedWith(reason); + }); + }); - // await expect(l2MessageReceiver.L2MessageReceiver__init()).to.be.rejectedWith(reason); - // }); - // }); + describe('#_authorizeUpgrade', () => { + it('should correctly upgrade', async () => { + const l2MessageReceiverV2Factory = await ethers.getContractFactory('L2MessageReceiverV2'); + const l2MessageReceiverV2Implementation = await l2MessageReceiverV2Factory.deploy(); - // describe("#_authorizeUpgrade", () => { - // it("should correctly upgrade", async () => { - // const l2MessageReceiverV2Factory = await ethers.getContractFactory("L2MessageReceiverV2"); - // const l2MessageReceiverV2Implementation = await l2MessageReceiverV2Factory.deploy(); + await l2MessageReceiver.upgradeTo(l2MessageReceiverV2Implementation); - // await l2MessageReceiver.upgradeTo(l2MessageReceiverV2Implementation); + const l2MessageReceiverV2 = l2MessageReceiverV2Factory.attach(l2MessageReceiver) as L2MessageReceiverV2; - // const l2MessageReceiverV2 = l2MessageReceiverV2Factory.attach(l2MessageReceiver) as L2MessageReceiverV2; + expect(await l2MessageReceiverV2.version()).to.eq(2); + }); + it('should revert if caller is not the owner', async () => { + await expect(l2MessageReceiver.connect(SECOND).upgradeTo(ZERO_ADDR)).to.be.revertedWith( + 'Ownable: caller is not the owner', + ); + }); + }); + }); - // expect(await l2MessageReceiverV2.version()).to.eq(2); - // }); - // it("should revert if caller is not the owner", async () => { - // await expect(l2MessageReceiver.connect(SECOND).upgradeTo(ZERO_ADDR)).to.be.revertedWith( - // "Ownable: caller is not the owner", - // ); - // }); - // }); - // }); + describe('#setLzSender', async () => { + it('should set the sender', async () => { + await l2MessageReceiver.setLzSender(SECOND); + expect((await l2MessageReceiver.config()).sender).to.eq(SECOND); + }); + it('should revert if not called by the owner', async () => { + await expect(l2MessageReceiver.connect(SECOND).setLzSender(SECOND)).to.be.revertedWith( + 'Ownable: caller is not the owner', + ); + }); + it('should revert if provided zero address', async () => { + await expect(l2MessageReceiver.setLzSender(ZERO_ADDR)).to.be.revertedWith('L2MR: invalid sender'); + }); + }); describe('#lzReceive', () => { it('should mint tokens', async () => { @@ -111,7 +153,11 @@ describe('L2MessageReceiver', () => { tx = await l2MessageReceiver.connect(THIRD).lzReceive(2, address, 7, payload); }); it('should mint tokens, ERC20MOR', async () => { - await l2MessageReceiver.setParams(mor, { + const l2MessageReceiverImplementation = await l2MessageReceiverFactory.deploy(); + const l2MessageReceiverProxy = await ERC1967ProxyFactory.deploy(l2MessageReceiverImplementation, '0x'); + const l2MessageReceiver = l2MessageReceiverFactory.attach(l2MessageReceiverProxy) as L2MessageReceiver; + await mor.updateMinter(l2MessageReceiver, true); + await l2MessageReceiver.L2MessageReceiver__init(mor, { gateway: THIRD, sender: OWNER, senderChainId: 2, @@ -132,42 +178,6 @@ describe('L2MessageReceiver', () => { it('should revert if provided wrong lzEndpoint', async () => { await expect(l2MessageReceiver.lzReceive(0, '0x', 1, '0x')).to.be.revertedWith('L2MR: invalid gateway'); }); - // it("should fail if provided wrong mint amount", async () => { - // const address = ethers.solidityPacked( - // ["address", "address"], - // [OWNER.address, await l2MessageReceiver.getAddress()], - // ); - // const payload = ethers.AbiCoder.defaultAbiCoder().encode(["address", "uint256"], [SECOND.address, wei(100)]); - - // let tx = await l2MessageReceiver.connect(THIRD).lzReceive(2, address, 5, payload); - // await expect(tx).to.changeTokenBalance(mor, SECOND, wei(100)); - - // expect(await l2MessageReceiver.failedMessages(2, address, 5)).to.eq(ZERO_BYTES32); - // await l2MessageReceiver.connect(THIRD).lzReceive(2, address, 5, payload); - // expect(await l2MessageReceiver.failedMessages(2, address, 5)).to.eq(ethers.keccak256(payload)); - - // await mor.connect(SECOND).burn(wei(100)); - - // tx = await l2MessageReceiver.connect(THIRD).lzReceive(2, address, 6, payload); - // expect(await l2MessageReceiver.failedMessages(2, address, 6)).to.eq(ZERO_BYTES32); - // await expect(tx).to.changeTokenBalance(mor, SECOND, wei(100)); - // }); - // it("should fail if provided wrong mint amount", async () => { - // const address = ethers.solidityPacked( - // ["address", "address"], - // [OWNER.address, await l2MessageReceiver.getAddress()], - // ); - // const payload = ethers.AbiCoder.defaultAbiCoder().encode(["address", "uint256"], [SECOND.address, wei(100)]); - - // await l2MessageReceiver.connect(THIRD).lzReceive(2, address, 5, payload); - - // expect(await l2MessageReceiver.failedMessages(2, address, 5)).to.eq(ZERO_BYTES32); - // await l2MessageReceiver.connect(THIRD).lzReceive(2, address, 5, payload); - - // await mor.connect(SECOND).burn(wei(100)); - - // await l2MessageReceiver.connect(THIRD).lzReceive(2, address, 5, payload); - // }); }); describe('#nonblockingLzReceive', () => { @@ -177,32 +187,43 @@ describe('L2MessageReceiver', () => { }); describe('#retryMessage', () => { - let senderAndReceiverAddresses = ''; let payload = ''; const chainId = 2; beforeEach(async () => { - senderAndReceiverAddresses = ethers.solidityPacked( + payload = ethers.AbiCoder.defaultAbiCoder().encode(['address', 'uint256'], [SECOND.address, wei(99)]); + }); + it('should have one blocked message', async () => { + const senderAndReceiverAddresses = ethers.solidityPacked( ['address', 'address'], [SECOND.address, await l2MessageReceiver.getAddress()], ); - payload = ethers.AbiCoder.defaultAbiCoder().encode(['address', 'uint256'], [SECOND.address, wei(99)]); - // Fail this call await l2MessageReceiver.connect(THIRD).lzReceive(chainId, senderAndReceiverAddresses, 999, payload); - }); - it('should have one blocked message', async () => { + expect(await l2MessageReceiver.failedMessages(chainId, senderAndReceiverAddresses, 999)).to.eq( ethers.keccak256(payload), ); }); it('should retry failed message', async () => { - await l2MessageReceiver.setParams(mor, { + const l2MessageReceiverImplementation = await l2MessageReceiverFactory.deploy(); + const l2MessageReceiverProxy = await ERC1967ProxyFactory.deploy(l2MessageReceiverImplementation, '0x'); + const l2MessageReceiver = l2MessageReceiverFactory.attach(l2MessageReceiverProxy) as L2MessageReceiver; + await l2MessageReceiver.L2MessageReceiver__init(mor, { gateway: THIRD, sender: SECOND, senderChainId: 2, }); + const senderAndReceiverAddresses = ethers.solidityPacked( + ['address', 'address'], + [SECOND.address, await l2MessageReceiver.getAddress()], + ); + // Fail this call + await l2MessageReceiver.connect(THIRD).lzReceive(chainId, senderAndReceiverAddresses, 999, payload); + + await mor.updateMinter(l2MessageReceiver, true); + const tx = await l2MessageReceiver.retryMessage(chainId, senderAndReceiverAddresses, 999, payload); await expect(tx).to.changeTokenBalance(mor, SECOND, wei(99)); @@ -214,38 +235,78 @@ describe('L2MessageReceiver', () => { ); }); it('should revert if provided wrong chainId', async () => { - await l2MessageReceiver.setParams(mor, { + const l2MessageReceiverImplementation = await l2MessageReceiverFactory.deploy(); + const l2MessageReceiverProxy = await ERC1967ProxyFactory.deploy(l2MessageReceiverImplementation, '0x'); + const l2MessageReceiver = l2MessageReceiverFactory.attach(l2MessageReceiverProxy) as L2MessageReceiver; + await mor.updateMinter(l2MessageReceiver, true); + await l2MessageReceiver.L2MessageReceiver__init(mor, { gateway: THIRD, sender: SECOND, senderChainId: 3, }); + const senderAndReceiverAddresses = ethers.solidityPacked( + ['address', 'address'], + [SECOND.address, await l2MessageReceiver.getAddress()], + ); + // Fail this call + await l2MessageReceiver.connect(THIRD).lzReceive(chainId, senderAndReceiverAddresses, 999, payload); + await expect( l2MessageReceiver.retryMessage(chainId, senderAndReceiverAddresses, 999, payload), ).to.be.revertedWith('L2MR: invalid sender chain ID'); }); it('should revert if provided wrong sender', async () => { + const senderAndReceiverAddresses = ethers.solidityPacked( + ['address', 'address'], + [SECOND.address, await l2MessageReceiver.getAddress()], + ); + // Fail this call + await l2MessageReceiver.connect(THIRD).lzReceive(chainId, senderAndReceiverAddresses, 999, payload); + await expect( l2MessageReceiver.retryMessage(chainId, senderAndReceiverAddresses, 999, payload), ).to.be.revertedWith('L2MR: invalid sender address'); }); it('should revert if provided wrong message', async () => { + const senderAndReceiverAddresses = ethers.solidityPacked( + ['address', 'address'], + [SECOND.address, await l2MessageReceiver.getAddress()], + ); await expect( l2MessageReceiver.retryMessage(chainId, senderAndReceiverAddresses, 998, payload), ).to.be.revertedWith('L2MR: no stored message'); }); it('should revert if provided wrong payload', async () => { + const senderAndReceiverAddresses = ethers.solidityPacked( + ['address', 'address'], + [SECOND.address, await l2MessageReceiver.getAddress()], + ); + // Fail this call + await l2MessageReceiver.connect(THIRD).lzReceive(chainId, senderAndReceiverAddresses, 999, payload); + await expect(l2MessageReceiver.retryMessage(chainId, senderAndReceiverAddresses, 999, '0x')).to.be.revertedWith( 'L2MR: invalid payload', ); }); it('should revert if try to retry already retried message', async () => { - await l2MessageReceiver.setParams(mor, { + const l2MessageReceiverImplementation = await l2MessageReceiverFactory.deploy(); + const l2MessageReceiverProxy = await ERC1967ProxyFactory.deploy(l2MessageReceiverImplementation, '0x'); + const l2MessageReceiver = l2MessageReceiverFactory.attach(l2MessageReceiverProxy) as L2MessageReceiver; + await l2MessageReceiver.L2MessageReceiver__init(mor, { gateway: THIRD, sender: SECOND, senderChainId: 2, }); + const senderAndReceiverAddresses = ethers.solidityPacked( + ['address', 'address'], + [SECOND.address, await l2MessageReceiver.getAddress()], + ); + // Fail this call + await l2MessageReceiver.connect(THIRD).lzReceive(chainId, senderAndReceiverAddresses, 999, payload); + await mor.updateMinter(l2MessageReceiver, true); + await l2MessageReceiver.retryMessage(chainId, senderAndReceiverAddresses, 999, payload); await expect( diff --git a/test/L2/L2TokenReceiver.test.ts b/test/L2/L2TokenReceiver.test.ts index 96d5d19..4fbbfa2 100644 --- a/test/L2/L2TokenReceiver.test.ts +++ b/test/L2/L2TokenReceiver.test.ts @@ -6,11 +6,11 @@ import { getDefaultSwapParams } from '../helpers/distribution-helper'; import { Reverter } from '../helpers/reverter'; import { - ERC20MOR, IL2TokenReceiver, L2TokenReceiver, L2TokenReceiverV2, LayerZeroEndpointV2Mock, + MOR20, NonfungiblePositionManagerMock, StETHMock, SwapRouterMock, @@ -31,7 +31,7 @@ describe('L2TokenReceiver', () => { let l2TokenReceiver: L2TokenReceiver; let inputToken: StETHMock; - let outputToken: ERC20MOR; + let outputToken: MOR20; before(async () => { [OWNER, SECOND] = await ethers.getSigners(); @@ -47,7 +47,7 @@ describe('L2TokenReceiver', () => { ethers.getContractFactory('ERC1967Proxy'), ethers.getContractFactory('L2TokenReceiver'), ethers.getContractFactory('StETHMock'), - ethers.getContractFactory('ERC20MOR'), + ethers.getContractFactory('MOR20'), ethers.getContractFactory('SwapRouterMock'), ethers.getContractFactory('NonfungiblePositionManagerMock'), ethers.getContractFactory('LayerZeroEndpointV2Mock'), @@ -92,96 +92,96 @@ describe('L2TokenReceiver', () => { await reverter.revert(); }); - // describe("UUPS proxy functionality", () => { - // it("should disable initialize function", async () => { - // const reason = "Initializable: contract is already initialized"; - - // const l2TokenReceiver = await (await ethers.getContractFactory("L2TokenReceiver")).deploy(); - - // await expect( - // l2TokenReceiver.L2TokenReceiver__init( - // swapRouter, - // nonfungiblePositionManager, - // { - // tokenIn: inputToken, - // tokenOut: outputToken, - // fee: 500, - // sqrtPriceLimitX96: 0, - // }, - // { - // tokenIn: inputToken, - // tokenOut: outputToken, - // fee: 500, - // sqrtPriceLimitX96: 0, - // }, - // ), - // ).to.be.rejectedWith(reason); - // }); - - // describe("#L2TokenReceiver__init", () => { - // it("should revert if try to call init function twice", async () => { - // const reason = "Initializable: contract is already initialized"; - - // await expect( - // l2TokenReceiver.L2TokenReceiver__init( - // swapRouter, - // nonfungiblePositionManager, - // { - // tokenIn: inputToken, - // tokenOut: outputToken, - // fee: 500, - // sqrtPriceLimitX96: 0, - // }, - // { - // tokenIn: inputToken, - // tokenOut: outputToken, - // fee: 500, - // sqrtPriceLimitX96: 0, - // }, - // ), - // ).to.be.rejectedWith(reason); - // }); - // it("should set router", async () => { - // expect(await l2TokenReceiver.router()).to.equal(await swapRouter.getAddress()); - // }); - // it("should set params", async () => { - // const defaultParams = getDefaultSwapParams(await inputToken.getAddress(), await outputToken.getAddress()); - // const params = await l2TokenReceiver.secondSwapParams(); - - // expect(params.tokenIn).to.equal(defaultParams.tokenIn); - // expect(params.tokenOut).to.equal(defaultParams.tokenOut); - // expect(params.fee).to.equal(defaultParams.fee); - // expect(params.sqrtPriceLimitX96).to.equal(defaultParams.sqrtPriceLimitX96); - // }); - // it("should give allowance", async () => { - // expect(await inputToken.allowance(l2TokenReceiver, swapRouter)).to.equal(ethers.MaxUint256); - // expect(await inputToken.allowance(l2TokenReceiver, nonfungiblePositionManager)).to.equal(ethers.MaxUint256); - // expect(await outputToken.allowance(l2TokenReceiver, nonfungiblePositionManager)).to.equal(ethers.MaxUint256); - // }); - // }); - - // describe("#_authorizeUpgrade", () => { - // it("should correctly upgrade", async () => { - // const l2TokenReceiverV2Factory = await ethers.getContractFactory("L2TokenReceiverV2"); - // const l2TokenReceiverV2Implementation = await l2TokenReceiverV2Factory.deploy(); - - // await l2TokenReceiver.upgradeTo(l2TokenReceiverV2Implementation); - - // const l2TokenReceiverV2 = l2TokenReceiverV2Factory.attach(l2TokenReceiver) as L2TokenReceiverV2; - - // expect(await l2TokenReceiverV2.version()).to.eq(2); - // }); - // it("should revert if caller is not the owner", async () => { - // await expect(l2TokenReceiver.connect(SECOND).upgradeTo(ZERO_ADDR)).to.be.revertedWith( - // "Ownable: caller is not the owner", - // ); - // }); - // }); - // }); + describe('UUPS proxy functionality', () => { + it('should disable initialize function', async () => { + const reason = 'Initializable: contract is already initialized'; + + const l2TokenReceiver = await (await ethers.getContractFactory('L2TokenReceiver')).deploy(); + + await expect( + l2TokenReceiver.L2TokenReceiver__init( + swapRouter, + nonfungiblePositionManager, + { + tokenIn: inputToken, + tokenOut: outputToken, + fee: 500, + sqrtPriceLimitX96: 0, + }, + { + tokenIn: inputToken, + tokenOut: outputToken, + fee: 500, + sqrtPriceLimitX96: 0, + }, + ), + ).to.be.rejectedWith(reason); + }); + + describe('#L2TokenReceiver__init', () => { + it('should revert if try to call init function twice', async () => { + const reason = 'Initializable: contract is already initialized'; + + await expect( + l2TokenReceiver.L2TokenReceiver__init( + swapRouter, + nonfungiblePositionManager, + { + tokenIn: inputToken, + tokenOut: outputToken, + fee: 500, + sqrtPriceLimitX96: 0, + }, + { + tokenIn: inputToken, + tokenOut: outputToken, + fee: 500, + sqrtPriceLimitX96: 0, + }, + ), + ).to.be.rejectedWith(reason); + }); + it('should set router', async () => { + expect(await l2TokenReceiver.router()).to.equal(await swapRouter.getAddress()); + }); + it('should set params', async () => { + const defaultParams = getDefaultSwapParams(await inputToken.getAddress(), await outputToken.getAddress()); + const params = await l2TokenReceiver.secondSwapParams(); + + expect(params.tokenIn).to.equal(defaultParams.tokenIn); + expect(params.tokenOut).to.equal(defaultParams.tokenOut); + expect(params.fee).to.equal(defaultParams.fee); + expect(params.sqrtPriceLimitX96).to.equal(defaultParams.sqrtPriceLimitX96); + }); + it('should give allowance', async () => { + expect(await inputToken.allowance(l2TokenReceiver, swapRouter)).to.equal(ethers.MaxUint256); + expect(await inputToken.allowance(l2TokenReceiver, nonfungiblePositionManager)).to.equal(ethers.MaxUint256); + expect(await outputToken.allowance(l2TokenReceiver, nonfungiblePositionManager)).to.equal(ethers.MaxUint256); + }); + }); + + describe('#_authorizeUpgrade', () => { + it('should correctly upgrade', async () => { + const l2TokenReceiverV2Factory = await ethers.getContractFactory('L2TokenReceiverV2'); + const l2TokenReceiverV2Implementation = await l2TokenReceiverV2Factory.deploy(); + + await l2TokenReceiver.upgradeTo(l2TokenReceiverV2Implementation); + + const l2TokenReceiverV2 = l2TokenReceiverV2Factory.attach(l2TokenReceiver) as L2TokenReceiverV2; + + expect(await l2TokenReceiverV2.version()).to.eq(2); + }); + it('should revert if caller is not the owner', async () => { + await expect(l2TokenReceiver.connect(SECOND).upgradeTo(ZERO_ADDR)).to.be.revertedWith( + 'Ownable: caller is not the owner', + ); + }); + }); + }); describe('supportsInterface', () => { it('should support IL2TokenReceiver', async () => { - expect(await l2TokenReceiver.supportsInterface('0x2f958df3')).to.be.true; + expect(await l2TokenReceiver.supportsInterface('0x710a2868')).to.be.true; }); it('should support IERC165', async () => { expect(await l2TokenReceiver.supportsInterface('0x01ffc9a7')).to.be.true; @@ -257,6 +257,14 @@ describe('L2TokenReceiver', () => { }); }); + describe('#decreaseLiquidityCurrentRange', () => { + it('should return if caller is not the owner', async () => { + await expect(l2TokenReceiver.connect(SECOND).decreaseLiquidityCurrentRange(1, 1, 0, 0)).to.be.revertedWith( + 'Ownable: caller is not the owner', + ); + }); + }); + describe('#withdrawToken', () => { it('should withdraw token', async () => { await inputToken.mint(l2TokenReceiver, 1); diff --git a/test/L2/MOR20.test.ts b/test/L2/MOR20.test.ts new file mode 100644 index 0000000..f718cd2 --- /dev/null +++ b/test/L2/MOR20.test.ts @@ -0,0 +1,130 @@ +import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { LayerZeroEndpointV2Mock, MOR20 } from '@/generated-types/ethers'; +import { ZERO_ADDR } from '@/scripts/utils/constants'; +import { wei } from '@/scripts/utils/utils'; +import { Reverter } from '@/test/helpers/reverter'; + +describe('MOR20', () => { + const reverter = new Reverter(); + + let OWNER: SignerWithAddress; + let SECOND: SignerWithAddress; + let MINTER: SignerWithAddress; + let DELEGATE: SignerWithAddress; + let LZ_ENDPOINT_OWNER: SignerWithAddress; + + let rewardToken: MOR20; + let lZEndpointMock: LayerZeroEndpointV2Mock; + + const chainId = 101; + + before(async () => { + [OWNER, SECOND, MINTER, DELEGATE, LZ_ENDPOINT_OWNER] = await ethers.getSigners(); + + const [LZEndpointMock, MOR20] = await Promise.all([ + ethers.getContractFactory('LayerZeroEndpointV2Mock'), + ethers.getContractFactory('MOR20'), + ]); + + lZEndpointMock = await LZEndpointMock.deploy(chainId, LZ_ENDPOINT_OWNER); + rewardToken = await MOR20.deploy('TEST', 'TST', lZEndpointMock, DELEGATE, MINTER); + + await reverter.snapshot(); + }); + + afterEach(async () => { + await reverter.revert(); + }); + + describe('constructor', () => { + it('should set the name and symbol', async () => { + expect(await rewardToken.name()).to.equal('TEST'); + expect(await rewardToken.symbol()).to.equal('TST'); + expect(await rewardToken.isMinter(MINTER)).to.be.true; + }); + it('should revert if LZ endpoint is zero address', async () => { + const MOR20 = await ethers.getContractFactory('MOR20'); + + await expect(MOR20.deploy('TEST', 'TST', lZEndpointMock, DELEGATE.address, ZERO_ADDR)).to.be.revertedWith( + 'MOR20: invalid minter', + ); + }); + }); + + describe('supportsInterface', () => { + it('should support IToken', async () => { + expect(await rewardToken.supportsInterface('0x38f90a90')).to.be.true; + }); + it('should support IERC20', async () => { + expect(await rewardToken.supportsInterface('0x36372b07')).to.be.true; + }); + it('should support IOAppCore', async () => { + expect(await rewardToken.supportsInterface('0x0c39d358')).to.be.true; + }); + it('should support IERC165', async () => { + expect(await rewardToken.supportsInterface('0x01ffc9a7')).to.be.true; + }); + }); + + describe('mint', () => { + it('should mint tokens', async () => { + const amount = wei('10'); + + const tx = await rewardToken.connect(MINTER).mint(SECOND.address, amount); + await expect(tx).to.changeTokenBalance(rewardToken, SECOND, amount); + }); + it('should revert if not called by the owner', async () => { + await expect(rewardToken.connect(SECOND).mint(SECOND.address, wei('10'))).to.be.revertedWith( + 'MOR20: invalid caller', + ); + }); + }); + + describe('#updateMinter', () => { + it('should update the minter', async () => { + await rewardToken.connect(DELEGATE).updateMinter(SECOND, true); + + expect(await rewardToken.isMinter(SECOND)).to.be.true; + + await rewardToken.connect(DELEGATE).updateMinter(SECOND, false); + + expect(await rewardToken.isMinter(SECOND)).to.be.false; + }); + it('should revert if not called by the owner', async () => { + await expect(rewardToken.connect(SECOND).updateMinter(SECOND, true)).to.be.revertedWith( + 'Ownable: caller is not the owner', + ); + }); + }); + + describe('burn', () => { + it('should burn tokens', async () => { + const amount = wei('10'); + + await rewardToken.connect(MINTER).mint(OWNER.address, amount); + + const tx = await rewardToken.burn(amount); + + await expect(tx).to.changeTokenBalance(rewardToken, OWNER, -amount); + }); + }); + + describe('burnFrom', () => { + it('should burn tokens from another account', async () => { + const amount = wei('10'); + + await rewardToken.connect(MINTER).mint(OWNER.address, amount); + + await rewardToken.approve(SECOND.address, amount); + + const tx = await rewardToken.connect(SECOND).burnFrom(OWNER.address, amount); + + await expect(tx).to.changeTokenBalance(rewardToken, OWNER, -amount); + + expect(await rewardToken.allowance(OWNER.address, SECOND.address)).to.equal(0); + }); + }); +}); diff --git a/test/L2/MOROFT.test.ts b/test/L2/MOROFT.test.ts deleted file mode 100644 index 7bfb458..0000000 --- a/test/L2/MOROFT.test.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; -import { ethers, expect } from 'hardhat'; - -import { LayerZeroEndpointV2Mock, MOROFT } from '@/generated-types/ethers'; -import { ZERO_ADDR } from '@/scripts/utils/constants'; -import { wei } from '@/scripts/utils/utils'; -import { Reverter } from '@/test/helpers/reverter'; - -describe('MOROFT', () => { - const reverter = new Reverter(); - - let OWNER: SignerWithAddress; - let SECOND: SignerWithAddress; - let MINTER: SignerWithAddress; - let DELEGATE: SignerWithAddress; - let LZ_ENDPOINT_OWNER: SignerWithAddress; - - let mor: MOROFT; - let lZEndpointMock: LayerZeroEndpointV2Mock; - - const chainId = 101; - - before(async () => { - [OWNER, SECOND, MINTER, DELEGATE, LZ_ENDPOINT_OWNER] = await ethers.getSigners(); - - const [LZEndpointMock, MOR] = await Promise.all([ - ethers.getContractFactory('LayerZeroEndpointV2Mock'), - ethers.getContractFactory('MOROFT'), - ]); - - lZEndpointMock = await LZEndpointMock.deploy(chainId, LZ_ENDPOINT_OWNER.address); - mor = await MOR.deploy(lZEndpointMock, DELEGATE.address, MINTER.address); - - await reverter.snapshot(); - }); - - afterEach(async () => { - await reverter.revert(); - }); - - describe('constructor', () => { - it('should set the name and symbol', async () => { - expect(await mor.name()).to.equal('MOR'); - expect(await mor.symbol()).to.equal('MOR'); - expect(await mor.minter()).to.equal(MINTER.address); - }); - it('should revert if LZ endpoint is zero address', async () => { - const MOR = await ethers.getContractFactory('MOROFT'); - - await expect(MOR.deploy(lZEndpointMock, DELEGATE.address, ZERO_ADDR)).to.be.revertedWith( - 'MOROFT: invalid minter', - ); - }); - }); - - describe('supportsInterface', () => { - it('should support IMOROFT', async () => { - expect(await mor.supportsInterface('0x7ccf6593')).to.be.true; - }); - it('should support IERC20', async () => { - expect(await mor.supportsInterface('0x36372b07')).to.be.true; - }); - it('should support IOAppCore', async () => { - expect(await mor.supportsInterface('0x0c39d358')).to.be.true; - }); - it('should support IERC165', async () => { - expect(await mor.supportsInterface('0x01ffc9a7')).to.be.true; - }); - }); - - describe('mint', () => { - it('should mint tokens', async () => { - const amount = wei('10'); - - const tx = await mor.connect(MINTER).mint(SECOND.address, amount); - await expect(tx).to.changeTokenBalance(mor, SECOND, amount); - }); - it('should revert if not called by the owner', async () => { - await expect(mor.connect(SECOND).mint(SECOND.address, wei('10'))).to.be.revertedWith('MOROFT: invalid caller'); - }); - }); - - describe('burn', () => { - it('should burn tokens', async () => { - const amount = wei('10'); - - await mor.connect(MINTER).mint(OWNER.address, amount); - - const tx = await mor.burn(amount); - - await expect(tx).to.changeTokenBalance(mor, OWNER, -amount); - }); - }); - - describe('burnFrom', () => { - it('should burn tokens from another account', async () => { - const amount = wei('10'); - - await mor.connect(MINTER).mint(OWNER.address, amount); - - await mor.approve(SECOND.address, amount); - - const tx = await mor.connect(SECOND).burnFrom(OWNER.address, amount); - - await expect(tx).to.changeTokenBalance(mor, OWNER, -amount); - - expect(await mor.allowance(OWNER.address, SECOND.address)).to.equal(0); - }); - }); -}); - -// npx hardhat test "test/MOROFT.test.ts" -// npx hardhat coverage --solcoverjs ./.solcover.ts --testfiles "test/MOROFT.test.ts" diff --git a/test/fork/L1Sender.fork.test.ts b/test/fork/L1Sender.fork.test.ts index 67cafa9..121bdb9 100644 --- a/test/fork/L1Sender.fork.test.ts +++ b/test/fork/L1Sender.fork.test.ts @@ -39,7 +39,7 @@ describe('L1Sender Fork', () => { await ethers.provider.send('hardhat_reset', [ { forking: { - jsonRpcUrl: `https://mainnet.infura.io/v3/${process.env.INFURA_KEY}`, + jsonRpcUrl: `https://eth-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_KEY}`, }, }, ]); diff --git a/test/fork/L2TokenReceiver.fork.test.ts b/test/fork/L2TokenReceiver.fork.test.ts index 61d496e..57442fd 100644 --- a/test/fork/L2TokenReceiver.fork.test.ts +++ b/test/fork/L2TokenReceiver.fork.test.ts @@ -11,9 +11,8 @@ import { IL2TokenReceiver, INonfungiblePositionManager, INonfungiblePositionManager__factory, - ISwapRouter, - ISwapRouter__factory, L2TokenReceiver, + MOR20, WStETHMock, WStETHMock__factory, } from '@/generated-types/ethers'; @@ -23,55 +22,108 @@ describe('L2TokenReceiver Fork', () => { const reverter = new Reverter(); let OWNER: SignerWithAddress; + let SECOND: SignerWithAddress; let l2TokenReceiver: L2TokenReceiver; - const swapRouterAddress = '0xE592427A0AEce92De3Edee1F18E0157C05861564'; + const router = '0xE592427A0AEce92De3Edee1F18E0157C05861564'; const nonfungiblePositionManagerAddress = '0xC36442b4a4522E871399CD717aBDD847Ab11FE88'; - const wstethAddress = '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0'; - const usdcAddress = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'; + const l1LzEndpointV2Address = '0x1a44076050125825900e736c501f859c50fe728c'; - const richAddress = '0x176F3DAb24a159341c0509bB36B833E7fdd0a132'; + const wethAddress = '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1'; + + const richAddress = '0xE74546162c7c58929b898575C378Fd7EC5B16998'; - let swapRouter: ISwapRouter; let nonfungiblePositionManager: INonfungiblePositionManager; let inputToken: WStETHMock; - let outputToken: IERC20; + let innerToken: IERC20; + let outputToken: MOR20; + + let poolId: bigint; before(async () => { await ethers.provider.send('hardhat_reset', [ { forking: { - jsonRpcUrl: `https://mainnet.infura.io/v3/${process.env.INFURA_KEY}`, - blockNumber: 19000000, + jsonRpcUrl: `https://arb-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_KEY}`, + blockNumber: 189500000, }, }, ]); OWNER = await ethers.getImpersonatedSigner(richAddress); + [SECOND] = await ethers.getSigners(); - swapRouter = ISwapRouter__factory.connect(swapRouterAddress, OWNER); - nonfungiblePositionManager = INonfungiblePositionManager__factory.connect(nonfungiblePositionManagerAddress, OWNER); + await SECOND.sendTransaction({ to: richAddress, value: wei(100) }); - inputToken = WStETHMock__factory.connect(wstethAddress, OWNER); - outputToken = IERC20__factory.connect(usdcAddress, OWNER); + nonfungiblePositionManager = INonfungiblePositionManager__factory.connect(nonfungiblePositionManagerAddress, OWNER); - const [ERC1967ProxyFactory, L2TokenReceiver] = await Promise.all([ - ethers.getContractFactory('ERC1967Proxy', OWNER), + const [L2TokenReceiver, MOR, ERC1967ProxyFactory] = await Promise.all([ ethers.getContractFactory('L2TokenReceiver', OWNER), + ethers.getContractFactory('MOR20', OWNER), + ethers.getContractFactory('ERC1967Proxy', OWNER), ]); - const l2TokenReceiverImplementation = await L2TokenReceiver.deploy(); - const l2TokenReceiverProxy = await ERC1967ProxyFactory.deploy(l2TokenReceiverImplementation, '0x'); + const l2TokenReceiverImpl = await L2TokenReceiver.deploy(); + const l2TokenReceiverProxy = await ERC1967ProxyFactory.deploy(l2TokenReceiverImpl, '0x'); l2TokenReceiver = L2TokenReceiver.attach(l2TokenReceiverProxy) as L2TokenReceiver; + + innerToken = IERC20__factory.connect(wethAddress, OWNER); + inputToken = WStETHMock__factory.connect('0x5979D7b546E38E414F7E9822514be443A4800529', OWNER); + outputToken = (await MOR.deploy('MOR20', 'MOR20', l1LzEndpointV2Address, OWNER, OWNER)).connect(OWNER); + await l2TokenReceiver.L2TokenReceiver__init( - swapRouter, + router, nonfungiblePositionManager, - getDefaultSwapParams(await inputToken.getAddress(), await outputToken.getAddress()), + getDefaultSwapParams(await inputToken.getAddress(), await innerToken.getAddress()), + getDefaultSwapParams(await innerToken.getAddress(), await outputToken.getAddress()), ); + await outputToken.mint(OWNER, wei(1000)); + + // Create a pool + + await innerToken.approve(nonfungiblePositionManagerAddress, wei(1000)); + await outputToken.approve(nonfungiblePositionManagerAddress, wei(1000)); + + const sqrtPrice = 2505413655765166104103837312489n; + + await nonfungiblePositionManager.createAndInitializePoolIfNecessary(innerToken, outputToken, 500, sqrtPrice); + + poolId = ( + await nonfungiblePositionManager.mint.staticCall({ + token0: innerToken, + token1: outputToken, + fee: 500, + tickLower: -887220, + tickUpper: 887220, + amount0Desired: wei(0.01), + amount1Desired: 9999993390433544889n, + amount0Min: 0, + amount1Min: 0, + recipient: OWNER, + deadline: (await getCurrentBlockTime()) + 100, + }) + ).tokenId; + + await nonfungiblePositionManager.mint({ + token0: innerToken, + token1: outputToken, + fee: 500, + tickLower: -887220, + tickUpper: 887220, + amount0Desired: wei(0.01), + amount1Desired: 9999993390433544889n, + amount0Min: 0, + amount1Min: 0, + recipient: OWNER, + deadline: (await getCurrentBlockTime()) + 100, + }); + + await nonfungiblePositionManager['safeTransferFrom(address,address,uint256)'](OWNER, l2TokenReceiver, poolId); + await reverter.snapshot(); }); @@ -84,28 +136,34 @@ describe('L2TokenReceiver Fork', () => { }); describe('#swap', () => { - const amount = wei(0.0001); + const amount = wei(0.00001); beforeEach('setup', async () => { await inputToken.transfer(l2TokenReceiver, amount); + await innerToken.transfer(l2TokenReceiver, amount); }); - it('should swap tokens', async () => { - const txResult = await l2TokenReceiver.swap.staticCall(amount, wei(0), (await getCurrentBlockTime()) + 100); - const tx = await l2TokenReceiver.swap(amount, wei(0), (await getCurrentBlockTime()) + 100); + it('should swap tokens 1', async () => { + const txResult = await l2TokenReceiver.swap.staticCall(amount, 0, (await getCurrentBlockTime()) + 100, true); + const tx = await l2TokenReceiver.swap(amount, 0, (await getCurrentBlockTime()) + 100, true); - await expect(tx).to.changeTokenBalance(outputToken, l2TokenReceiver, txResult); + await expect(tx).to.changeTokenBalance(innerToken, l2TokenReceiver, txResult); await expect(tx).to.changeTokenBalance(inputToken, l2TokenReceiver, -amount); }); + it('should swap tokens 2', async () => { + const txResult = await l2TokenReceiver.swap.staticCall(amount, 0, (await getCurrentBlockTime()) + 100, false); + const tx = await l2TokenReceiver.swap(amount, 0, (await getCurrentBlockTime()) + 100, false); + + await expect(tx).to.changeTokenBalance(outputToken, l2TokenReceiver, txResult); + await expect(tx).to.changeTokenBalance(innerToken, l2TokenReceiver, -amount); + }); }); describe('#increaseLiquidityCurrentRange', () => { - const amountInputToken = wei(0.0001); - const amountOutputToken = 541774411822; + const amountInputToken = wei(0.00001); + const amountOutputToken = wei(0.1); - // const poolId = '0x4622df6fb2d9bee0dcdacf545acdb6a2b2f4f863'; - const poolId = 376582; beforeEach('setup', async () => { - await inputToken.transfer(l2TokenReceiver, amountInputToken); + await innerToken.transfer(l2TokenReceiver, amountInputToken); await outputToken.transfer(l2TokenReceiver, amountOutputToken); }); @@ -121,17 +179,17 @@ describe('L2TokenReceiver Fork', () => { const tx = await l2TokenReceiver.increaseLiquidityCurrentRange(poolId, amountInputToken, amountOutputToken, 0, 0); await expect(tx).to.changeTokenBalance(outputToken, l2TokenReceiver, -txResult[2]); - await expect(tx).to.changeTokenBalance(inputToken, l2TokenReceiver, -txResult[1]); + await expect(tx).to.changeTokenBalance(innerToken, l2TokenReceiver, -txResult[1]); }); it('should set the amount correctly besides the tokens order', async () => { const newParams: IL2TokenReceiver.SwapParamsStruct = { tokenIn: await outputToken.getAddress(), - tokenOut: await inputToken.getAddress(), + tokenOut: await innerToken.getAddress(), fee: 1, sqrtPriceLimitX96: 1, }; - await l2TokenReceiver.editParams(newParams); + await l2TokenReceiver.editParams(newParams, false); const txResult = await l2TokenReceiver.increaseLiquidityCurrentRange.staticCall( poolId, @@ -142,35 +200,95 @@ describe('L2TokenReceiver Fork', () => { ); const tx = await l2TokenReceiver.increaseLiquidityCurrentRange(poolId, amountInputToken, amountOutputToken, 0, 0); - await expect(tx).to.changeTokenBalance(inputToken, l2TokenReceiver, -txResult[1]); + await expect(tx).to.changeTokenBalance(innerToken, l2TokenReceiver, -txResult[1]); await expect(tx).to.changeTokenBalance(outputToken, l2TokenReceiver, -txResult[2]); }); }); describe('#collectFees', () => { - const poolId = 376582; - beforeEach('setup', async () => { - const poolOwner = await nonfungiblePositionManager.ownerOf(poolId); - const poolOwnerSigner = await ethers.getImpersonatedSigner(poolOwner); - - await OWNER.sendTransaction({ to: poolOwner, value: wei(10) }); + await innerToken.transfer(l2TokenReceiver, wei(0.001)); - await nonfungiblePositionManager - .connect(poolOwnerSigner) - ['safeTransferFrom(address,address,uint256)'](poolOwner, l2TokenReceiver, poolId); + await l2TokenReceiver.swap(wei(0.0001), 0, (await getCurrentBlockTime()) + 100, false); }); it('should collect fees', async () => { const outputTokenBalance = await outputToken.balanceOf(l2TokenReceiver); - const inputTokenBalance = await inputToken.balanceOf(l2TokenReceiver); + const inputTokenBalance = await innerToken.balanceOf(l2TokenReceiver); await l2TokenReceiver.collectFees(poolId); - expect(await outputToken.balanceOf(l2TokenReceiver)).to.greaterThan(outputTokenBalance); - expect(await inputToken.balanceOf(l2TokenReceiver)).to.greaterThan(inputTokenBalance); + expect(await outputToken.balanceOf(l2TokenReceiver)).to.be.equal(outputTokenBalance); + expect(await innerToken.balanceOf(l2TokenReceiver)).to.be.greaterThan(inputTokenBalance); + }); + }); + + describe('#decreaseLiquidityCurrentRange', () => { + const amountInputToken = wei(0.00001); + const amountOutputToken = wei(0.1); + + beforeEach('setup', async () => { + await innerToken.transfer(l2TokenReceiver, amountInputToken); + await outputToken.transfer(l2TokenReceiver, amountOutputToken); + }); + + it('should descrease liquidity', async () => { + const liquidity = (await nonfungiblePositionManager.positions(poolId)).liquidity; + + const txResult = await l2TokenReceiver.decreaseLiquidityCurrentRange.staticCall( + poolId, + liquidity, + amountInputToken, + amountOutputToken, + ); + + const tx = await l2TokenReceiver.decreaseLiquidityCurrentRange( + poolId, + liquidity, + amountInputToken, + amountOutputToken, + ); + + await expect(tx).to.changeTokenBalance(outputToken, l2TokenReceiver, txResult[1]); + await expect(tx).to.changeTokenBalance(innerToken, l2TokenReceiver, txResult[0]); + }); + it('should collect fees', async () => { + await innerToken.transfer(l2TokenReceiver, wei(0.001)); + + await l2TokenReceiver.swap(wei(0.0001), 0, (await getCurrentBlockTime()) + 100, false); + + const liquidity = (await nonfungiblePositionManager.positions(poolId)).liquidity; + + const feeResult = await l2TokenReceiver.collectFees.staticCall(poolId); + + const txResult = await l2TokenReceiver.decreaseLiquidityCurrentRange.staticCall( + poolId, + liquidity, + amountInputToken, + amountOutputToken, + ); + + const tx = await l2TokenReceiver.decreaseLiquidityCurrentRange( + poolId, + liquidity, + amountInputToken, + amountOutputToken, + ); + + await expect(tx).to.changeTokenBalance(outputToken, l2TokenReceiver, txResult[1] + feeResult[1]); + await expect(tx).to.changeTokenBalance(innerToken, l2TokenReceiver, txResult[0] + feeResult[0]); + }); + }); + + describe('#withdrawTokenId', () => { + it('should withdraw position NFT', async () => { + expect(await nonfungiblePositionManager.ownerOf(poolId)).to.be.equal(await l2TokenReceiver.getAddress()); + + await l2TokenReceiver.withdrawTokenId(OWNER, nonfungiblePositionManager, poolId); + + expect(await nonfungiblePositionManager.ownerOf(poolId)).to.be.equal(await OWNER.getAddress()); }); }); }); -// npx hardhat test "test/fork/L2TokenReceiver.fork.test.ts" +// npx hardhat test "test/fork/L2TokenReceiverV2.fork.test.ts" diff --git a/test/fork/L2TokenReceiverV2.fork.test.ts b/test/fork/L2TokenReceiverV2.fork.test.ts deleted file mode 100644 index 092a40f..0000000 --- a/test/fork/L2TokenReceiverV2.fork.test.ts +++ /dev/null @@ -1,247 +0,0 @@ -import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; -import { assert } from 'console'; -import { ethers, expect } from 'hardhat'; - -import { getCurrentBlockTime } from '../helpers/block-helper'; -import { getDefaultSwapParams } from '../helpers/distribution-helper'; -import { Reverter } from '../helpers/reverter'; - -import { - IERC20, - IERC20__factory, - IL2TokenReceiver, - INonfungiblePositionManager, - INonfungiblePositionManager__factory, - L2TokenReceiverV2, - MOROFT, - WStETHMock, - WStETHMock__factory, -} from '@/generated-types/ethers'; -import { wei } from '@/scripts/utils/utils'; - -describe('L2TokenReceiverV2 Fork', () => { - const reverter = new Reverter(); - - let OWNER: SignerWithAddress; - let SECOND: SignerWithAddress; - - let l2TokenReceiver: L2TokenReceiverV2; - - const nonfungiblePositionManagerAddress = '0xC36442b4a4522E871399CD717aBDD847Ab11FE88'; - - const l1LzEndpointV2Address = '0x1a44076050125825900e736c501f859c50fe728c'; - - const wethAddress = '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1'; - - const richAddress = '0xE74546162c7c58929b898575C378Fd7EC5B16998'; - - let nonfungiblePositionManager: INonfungiblePositionManager; - - let inputToken: WStETHMock; - let innerToken: IERC20; - let outputToken: MOROFT; - - let poolId: bigint; - - before(async () => { - await ethers.provider.send('hardhat_reset', [ - { - forking: { - jsonRpcUrl: `https://arbitrum-mainnet.infura.io/v3/${process.env.INFURA_KEY}`, - blockNumber: 189500000, - }, - }, - ]); - - OWNER = await ethers.getImpersonatedSigner(richAddress); - [SECOND] = await ethers.getSigners(); - - await SECOND.sendTransaction({ to: richAddress, value: wei(100) }); - - nonfungiblePositionManager = INonfungiblePositionManager__factory.connect(nonfungiblePositionManagerAddress, OWNER); - - const [L2TokenReceiverV2, MOR] = await Promise.all([ - ethers.getContractFactory('L2TokenReceiverV2', OWNER), - ethers.getContractFactory('MOROFT', OWNER), - ]); - - l2TokenReceiver = L2TokenReceiverV2.attach('0x47176B2Af9885dC6C4575d4eFd63895f7Aaa4790') as L2TokenReceiverV2; - - // Upgrade to V2 - const contractOwner = await ethers.getImpersonatedSigner(await l2TokenReceiver.owner()); - await SECOND.sendTransaction({ to: contractOwner, value: wei(100) }); - await l2TokenReceiver.connect(contractOwner).transferOwnership(OWNER); - - const l2TokenReceiverImplementationV2 = await L2TokenReceiverV2.deploy(); - await l2TokenReceiver.upgradeTo(l2TokenReceiverImplementationV2); - - l2TokenReceiver = L2TokenReceiverV2.attach(l2TokenReceiver) as L2TokenReceiverV2; - - innerToken = IERC20__factory.connect(wethAddress, OWNER); - inputToken = WStETHMock__factory.connect((await l2TokenReceiver.secondSwapParams()).tokenIn, OWNER); - outputToken = (await MOR.deploy(l1LzEndpointV2Address, OWNER, OWNER)).connect(OWNER); - - await outputToken.mint(OWNER, wei(1000)); - - await l2TokenReceiver.editParams( - getDefaultSwapParams(await innerToken.getAddress(), await outputToken.getAddress()), - false, - ); - await l2TokenReceiver.editParams( - getDefaultSwapParams(await inputToken.getAddress(), await innerToken.getAddress()), - true, - ); - - // Create a pool - - await innerToken.approve(nonfungiblePositionManagerAddress, wei(1000)); - await outputToken.approve(nonfungiblePositionManagerAddress, wei(1000)); - - const sqrtPrice = 2505413655765166104103837312489n; - - await nonfungiblePositionManager.createAndInitializePoolIfNecessary(innerToken, outputToken, 500, sqrtPrice); - - poolId = ( - await nonfungiblePositionManager.mint.staticCall({ - token0: innerToken, - token1: outputToken, - fee: 500, - tickLower: -887220, - tickUpper: 887220, - amount0Desired: wei(0.01), - amount1Desired: 9999993390433544889n, - amount0Min: 0, - amount1Min: 0, - recipient: OWNER, - deadline: (await getCurrentBlockTime()) + 100, - }) - ).tokenId; - - await nonfungiblePositionManager.mint({ - token0: innerToken, - token1: outputToken, - fee: 500, - tickLower: -887220, - tickUpper: 887220, - amount0Desired: wei(0.01), - amount1Desired: 9999993390433544889n, - amount0Min: 0, - amount1Min: 0, - recipient: OWNER, - deadline: (await getCurrentBlockTime()) + 100, - }); - - await nonfungiblePositionManager['safeTransferFrom(address,address,uint256)'](OWNER, l2TokenReceiver, poolId); - assert((await l2TokenReceiver.version()) === 2n, 'L2TokenReceiver should be upgraded to V2'); - - await reverter.snapshot(); - }); - - beforeEach(async () => { - await reverter.revert(); - }); - - after(async () => { - await ethers.provider.send('hardhat_reset', []); - }); - - describe('#swap', () => { - const amount = wei(0.00001); - beforeEach('setup', async () => { - await inputToken.transfer(l2TokenReceiver, amount); - await innerToken.transfer(l2TokenReceiver, amount); - }); - - it('should swap tokens 1', async () => { - const txResult = await l2TokenReceiver.swap.staticCall(amount, 0, (await getCurrentBlockTime()) + 100, true); - const tx = await l2TokenReceiver.swap(amount, 0, (await getCurrentBlockTime()) + 100, true); - - await expect(tx).to.changeTokenBalance(innerToken, l2TokenReceiver, txResult); - await expect(tx).to.changeTokenBalance(inputToken, l2TokenReceiver, -amount); - }); - it('should swap tokens 2', async () => { - const txResult = await l2TokenReceiver.swap.staticCall(amount, 0, (await getCurrentBlockTime()) + 100, false); - const tx = await l2TokenReceiver.swap(amount, 0, (await getCurrentBlockTime()) + 100, false); - - await expect(tx).to.changeTokenBalance(outputToken, l2TokenReceiver, txResult); - await expect(tx).to.changeTokenBalance(innerToken, l2TokenReceiver, -amount); - }); - }); - - describe('#increaseLiquidityCurrentRange', () => { - const amountInputToken = wei(0.00001); - const amountOutputToken = wei(0.1); - - beforeEach('setup', async () => { - await innerToken.transfer(l2TokenReceiver, amountInputToken); - await outputToken.transfer(l2TokenReceiver, amountOutputToken); - }); - - it('should increase liquidity', async () => { - const txResult = await l2TokenReceiver.increaseLiquidityCurrentRange.staticCall( - poolId, - amountInputToken, - amountOutputToken, - 0, - 0, - ); - - const tx = await l2TokenReceiver.increaseLiquidityCurrentRange(poolId, amountInputToken, amountOutputToken, 0, 0); - - await expect(tx).to.changeTokenBalance(outputToken, l2TokenReceiver, -txResult[2]); - await expect(tx).to.changeTokenBalance(innerToken, l2TokenReceiver, -txResult[1]); - }); - it('should set the amount correctly besides the tokens order', async () => { - const newParams: IL2TokenReceiver.SwapParamsStruct = { - tokenIn: await outputToken.getAddress(), - tokenOut: await innerToken.getAddress(), - fee: 1, - sqrtPriceLimitX96: 1, - }; - - await l2TokenReceiver.editParams(newParams, false); - - const txResult = await l2TokenReceiver.increaseLiquidityCurrentRange.staticCall( - poolId, - amountInputToken, - amountOutputToken, - 0, - 0, - ); - const tx = await l2TokenReceiver.increaseLiquidityCurrentRange(poolId, amountInputToken, amountOutputToken, 0, 0); - - await expect(tx).to.changeTokenBalance(innerToken, l2TokenReceiver, -txResult[1]); - await expect(tx).to.changeTokenBalance(outputToken, l2TokenReceiver, -txResult[2]); - }); - }); - - describe('#collectFees', () => { - beforeEach('setup', async () => { - await innerToken.transfer(l2TokenReceiver, wei(0.001)); - - await l2TokenReceiver.swap(wei(0.0001), 0, (await getCurrentBlockTime()) + 100, false); - }); - - it('should collect fees', async () => { - const outputTokenBalance = await outputToken.balanceOf(l2TokenReceiver); - const inputTokenBalance = await innerToken.balanceOf(l2TokenReceiver); - - await l2TokenReceiver.collectFees(poolId); - - expect(await outputToken.balanceOf(l2TokenReceiver)).to.be.equal(outputTokenBalance); - expect(await innerToken.balanceOf(l2TokenReceiver)).to.be.greaterThan(inputTokenBalance); - }); - }); - - describe('#withdrawTokenId', () => { - it('should withdraw position NFT', async () => { - expect(await nonfungiblePositionManager.ownerOf(poolId)).to.be.equal(await l2TokenReceiver.getAddress()); - - await l2TokenReceiver.withdrawTokenId(OWNER, nonfungiblePositionManager, poolId); - - expect(await nonfungiblePositionManager.ownerOf(poolId)).to.be.equal(await OWNER.getAddress()); - }); - }); -}); - -// npx hardhat test "test/fork/L2TokenReceiverV2.fork.test.ts" diff --git a/test/fork/MOROFT.fork.test.ts b/test/fork/MOR20.fork.test.ts similarity index 87% rename from test/fork/MOROFT.fork.test.ts rename to test/fork/MOR20.fork.test.ts index f272728..4b22866 100644 --- a/test/fork/MOROFT.fork.test.ts +++ b/test/fork/MOR20.fork.test.ts @@ -1,11 +1,11 @@ import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; import { ethers, expect } from 'hardhat'; -import { MOROFT, OptionsGenerator } from '@/generated-types/ethers'; +import { MOR20, OptionsGenerator } from '@/generated-types/ethers'; import { wei } from '@/scripts/utils/utils'; import { Reverter } from '@/test/helpers/reverter'; -describe('MOROFT', () => { +describe('MOR20 Fork', () => { const reverter = new Reverter(); let SECOND: SignerWithAddress; @@ -14,8 +14,8 @@ describe('MOROFT', () => { let optionsGenerator: OptionsGenerator; - let l1Mor: MOROFT; - let l2Mor: MOROFT; + let l1Mor: MOR20; + let l2Mor: MOR20; // *** LZ CONFIG *** // https://docs.layerzero.network/contracts/endpoint-addresses @@ -31,7 +31,7 @@ describe('MOROFT', () => { await ethers.provider.send('hardhat_reset', [ { forking: { - jsonRpcUrl: `https://arbitrum-mainnet.infura.io/v3/${process.env.INFURA_KEY}`, + jsonRpcUrl: `https://eth-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_KEY}`, // blockNumber: 190000000, }, }, @@ -40,13 +40,13 @@ describe('MOROFT', () => { [SECOND, MINTER, DELEGATE] = await ethers.getSigners(); const [MOR, OptionsGenerator] = await Promise.all([ - ethers.getContractFactory('MOROFT'), + ethers.getContractFactory('MOR20'), ethers.getContractFactory('OptionsGenerator'), ]); optionsGenerator = await OptionsGenerator.deploy(); - l1Mor = await MOR.deploy(l1LzEndpointV2Address, DELEGATE.address, MINTER.address); - l2Mor = await MOR.deploy(l2LzEndpointV2Address, DELEGATE.address, MINTER.address); + l1Mor = await MOR.deploy('MOR20_1', 'MOR20_1', l1LzEndpointV2Address, DELEGATE.address, MINTER.address); + l2Mor = await MOR.deploy('MOR20_2', 'MOR20_2', l2LzEndpointV2Address, DELEGATE.address, MINTER.address); await reverter.snapshot(); }); @@ -114,4 +114,4 @@ describe('MOROFT', () => { }); }); -// npx hardhat test "test/fork/MOROFT.fork.test.ts" +// npx hardhat test "test/fork/MOR20.fork.test.ts" diff --git a/test/helpers/helper.ts b/test/helpers/helper.ts new file mode 100644 index 0000000..9d4d7da --- /dev/null +++ b/test/helpers/helper.ts @@ -0,0 +1,10 @@ +export enum PoolTypesL1 { + DISTRIBUTION, + L1_SENDER, +} + +export enum PoolTypesL2 { + L2_MESSAGE_RECEIVER, + L2_TOKEN_RECEIVER, + MOR20, +} From f52ec3474e38d7594e47420e24c794b46abe9173 Mon Sep 17 00:00:00 2001 From: Ruslan Kasheparov Date: Mon, 13 May 2024 19:04:53 +0200 Subject: [PATCH 08/17] removed scripts --- scripts/checkTokenBalance.ts | 23 ----- scripts/getOverplus.ts | 24 ----- scripts/retryPayload.ts | 41 -------- scripts/sendMOROFTToAnotherChain.ts | 150 ---------------------------- scripts/tryAddLiquidity.ts | 40 -------- scripts/tryTokensSwap.ts | 18 ---- 6 files changed, 296 deletions(-) delete mode 100644 scripts/checkTokenBalance.ts delete mode 100644 scripts/getOverplus.ts delete mode 100644 scripts/retryPayload.ts delete mode 100644 scripts/sendMOROFTToAnotherChain.ts delete mode 100644 scripts/tryAddLiquidity.ts delete mode 100644 scripts/tryTokensSwap.ts diff --git a/scripts/checkTokenBalance.ts b/scripts/checkTokenBalance.ts deleted file mode 100644 index 4bb22ed..0000000 --- a/scripts/checkTokenBalance.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ethers } from 'hardhat'; - -import { ERC20 } from '@/generated-types/ethers'; - -async function main() { - // const user = '0x901F2d23823730fb7F2356920e0E273EFdCdFe17'; // me - const user = '0xb6067C1B07e3Fe12d18C11a0cc6F1366BD70EC95'; // token receiver - // const tokenAddress = '0xCF84E18F1a2803C15675622B24600910dc2a1E13'; // MOR - const tokenAddress = '0x87726993938107d9B9ce08c99BDde8736D899a5D'; // wStETH - const ERC20Factory = await ethers.getContractFactory('ERC20'); - const token = ERC20Factory.attach(tokenAddress) as ERC20; - - const balance = await token.balanceOf(user); - - console.log(`token ${tokenAddress} balance of ${user}: ${balance}`); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); - -// npx hardhat run scripts/checkTokenBalance.ts --network arbitrum_goerli diff --git a/scripts/getOverplus.ts b/scripts/getOverplus.ts deleted file mode 100644 index 7bb3979..0000000 --- a/scripts/getOverplus.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { ethers } from 'hardhat'; - -import { IDistribution } from '@/generated-types/ethers'; - -async function main() { - const distributionFactory = await ethers.getContractFactory('Distribution', { - libraries: { - LinearDistributionIntervalDecrease: '0x7431aDa8a591C955a994a21710752EF9b882b8e3', - }, - }); - - const distribution = distributionFactory.attach('0x47176B2Af9885dC6C4575d4eFd63895f7Aaa4790') as IDistribution; - - console.log(await distribution.overplus()); - - console.log(')'); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); - -// npx hardhat run scripts/getOverplus.ts --network localhost diff --git a/scripts/retryPayload.ts b/scripts/retryPayload.ts deleted file mode 100644 index fcbee1c..0000000 --- a/scripts/retryPayload.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { ethers } from 'hardhat'; - -import { ILayerZeroEndpoint } from '@/generated-types/ethers/@layerzerolabs/solidity-examples/contracts/lzApp/interfaces'; - -async function getNonce() { - const l2MessageReceiver = await ethers.getContractAt( - 'L2MessageReceiver', - '0xc37ff39e5a50543ad01e42c4cd88c2939dd13002', - (await ethers.getSigners())[0], - ); - - console.log(await l2MessageReceiver.nonce()); -} - -async function main() { - await getNonce(); - const lzEndpoint = (await ethers.getContractAt( - '@layerzerolabs/lz-evm-sdk-v1-0.7/contracts/interfaces/ILayerZeroEndpoint.sol:ILayerZeroEndpoint', - '0x6098e96a28E02f27B1e6BD381f870F1C8Bd169d3', - (await ethers.getSigners())[0], - )) as unknown as ILayerZeroEndpoint; - - const remoteAndLocal = ethers.solidityPacked( - ['address', 'address'], - ['0xeec0df0991458274ff0ede917e9827ffc67a8332', '0xc37ff39e5a50543ad01e42c4cd88c2939dd13002'], - ); - const tx = await lzEndpoint.retryPayload( - '10161', - remoteAndLocal, - '0x000000000000000000000000901f2d23823730fb7f2356920e0e273efdcdfe1700000000000000000000000000000000000000000000000322994640a6175555', - ); - - console.log(tx); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); - -// npx hardhat run scripts/retryPayload.ts --network arbitrum_sepolia diff --git a/scripts/sendMOROFTToAnotherChain.ts b/scripts/sendMOROFTToAnotherChain.ts deleted file mode 100644 index 1f0bc8c..0000000 --- a/scripts/sendMOROFTToAnotherChain.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { HardhatEthersSigner } from '@nomicfoundation/hardhat-ethers/signers'; -import { ethers } from 'hardhat'; - -import { wei } from './utils/utils'; - -import { MOROFT } from '@/generated-types/ethers'; - -type NetworkConfig = { - moroftAddress: string; - moroftContract?: MOROFT; - chainId: string; -}; - -const arbitrumSepolia: NetworkConfig = { - moroftAddress: '0x51f970885e90DA7dc9E3Fee37A115aD04e94F5CE', - chainId: '40231', -}; - -const sepolia: NetworkConfig = { - moroftAddress: '0xAE5227BEfEE7292Ef1a5C2376629b32d65bB29be', - chainId: '40161', -}; - -const mumbai: NetworkConfig = { - moroftAddress: '0xACabF3283a8083868a817C24f17C3c3e2D3339B0', - chainId: '40109', -}; - -const sender = '0x19ec1E4b714990620edf41fE28e9a1552953a7F4'; -const receiver = '0x19ec1E4b714990620edf41fE28e9a1552953a7F4'; - -let tx; - -const sendTokens = async ( - signer: HardhatEthersSigner, - amount: bigint, - receiver: string, - fromConfig: NetworkConfig, - toConfig: NetworkConfig, -) => { - if (!fromConfig.moroftContract) { - console.log('Failed to attach contract.'); - - return; - } - - const receiverBytes32Address = ethers.zeroPadValue(receiver, 32); - - const sendParams = { - dstEid: toConfig.chainId, - to: receiverBytes32Address, - amountLD: amount, - minAmountLD: amount, - extraOptions: '0x', - composeMsg: '0x', - oftCmd: '0x', - }; - - const quoteRes = await fromConfig.moroftContract.quoteSend(sendParams, false); - - const messagingFee = { - nativeFee: quoteRes[0].toString(), - lzTokenFee: 0, - }; - - tx = await fromConfig.moroftContract.connect(signer).send(sendParams, messagingFee, sender, { - value: messagingFee.nativeFee, - }); - await tx.wait(); - - console.log('Success: ', tx.hash); -}; - -const configureBridge = async (signer: HardhatEthersSigner, fromConfig: NetworkConfig, toConfig: NetworkConfig) => { - if (!fromConfig.moroftContract) { - console.log('Failed to attach contract.'); - - return; - } - - // Add to contract as allowed peer - tx = await fromConfig.moroftContract - .connect(signer) - .setPeer(toConfig.chainId, ethers.zeroPadValue(toConfig.moroftAddress, 32)); - await tx.wait(); - console.log( - 'Is peer has set:', - await fromConfig.moroftContract.isPeer(toConfig.chainId, ethers.zeroPadValue(toConfig.moroftAddress, 32)), - ); - - // // !!!!! Use it only for forming `options`. !!!!! - // const OptionsGenerator = await ethers.getContractFactory('OptionsGenerator'); - // const optionsGenerator = await OptionsGenerator.deploy(); - - // // Detect options for enforce params - // const executorGas = 60000; // Gas limit for the executor - // const executorValue = 0; // msg.value for the lzReceive() function on destination in wei - // // https://docs.layerzero.network/v2/developers/evm/gas-settings/options - // const options = await optionsGenerator.createLzReceiveOption(executorGas, executorValue); - // console.log('Options for next step: ', options); - - // https://docs.layerzero.network/v2/developers/evm/oapp/overview#message-execution-options - const enforcedOptionParam = [ - { - eid: toConfig.chainId, - msgType: 1, - options: '0x0003010011010000000000000000000000000000ea60', - }, - ]; - - tx = await fromConfig.moroftContract.connect(signer).setEnforcedOptions(enforcedOptionParam); - await tx.wait(); -}; - -async function main() { - // Use `getImpersonatedSigner` for testing on fork - // const signer = await ethers.getImpersonatedSigner('0x19ec1E4b714990620edf41fE28e9a1552953a7F4'); - const [signer] = await ethers.getSigners(); - - const MOROFT = await ethers.getContractFactory('MOROFT'); - - arbitrumSepolia.moroftContract = MOROFT.attach(arbitrumSepolia.moroftAddress) as MOROFT; - sepolia.moroftContract = MOROFT.attach(sepolia.moroftAddress) as MOROFT; - mumbai.moroftContract = MOROFT.attach(mumbai.moroftAddress) as MOROFT; - - // **** STEP #1 **** - // Configure from `mumbai` to `sepolia`. Call it from `mumbai` - // await configureBridge(signer, mumbai, sepolia); - - // Configure from `sepolia` to `mumbai`. Call it from `sepolia` - // await configureBridge(signer, sepolia, mumbai); - // END - - // **** STEP #2 **** - // Send tokens from `mumbai` to `sepolia`. Call it from `mumbai` - // await sendTokens(signer, wei(100), receiver, mumbai, sepolia); - - // Send tokens from `sepolia` to `mumbai`. Call it from `sepolia` - await sendTokens(signer, wei(50), receiver, sepolia, mumbai); - // END -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); - -// npx hardhat run scripts/sendMOROFTToAnotherChain.ts -// npx hardhat run scripts/sendMOROFTToAnotherChain.ts --network mumbai -// npx hardhat run scripts/sendMOROFTToAnotherChain.ts --network sepolia diff --git a/scripts/tryAddLiquidity.ts b/scripts/tryAddLiquidity.ts deleted file mode 100644 index 69a17a8..0000000 --- a/scripts/tryAddLiquidity.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { ethers } from 'hardhat'; - -import { ERC20, L2TokenReceiver } from '@/generated-types/ethers'; - -const l2MessageReceiverAddress = '0x2C0f43E5C92459F62C102517956A95E88E177e95'; -const wstethAddress = '0x6320cD32aA674d2898A68ec82e869385Fc5f7E2f'; -const morAddress = '0x454AE850eE61a98BF16FABA3a73fb0dD02D75C40'; - -async function main() { - const L2TokenReceiver = await ethers.getContractFactory('L2TokenReceiver'); - const l2TokenReceiver = L2TokenReceiver.attach(l2MessageReceiverAddress) as L2TokenReceiver; - - const ERC20Factory = await ethers.getContractFactory('ERC20'); - const wsteth = ERC20Factory.attach(wstethAddress) as ERC20; - const mor = ERC20Factory.attach(morAddress) as ERC20; - - const wstethBalance = await wsteth.balanceOf(l2MessageReceiverAddress); - const morBalance = await mor.balanceOf(l2MessageReceiverAddress); - - console.log(`wsteth balance of ${l2MessageReceiverAddress}: ${wstethBalance}`); - console.log(`mor balance of ${l2MessageReceiverAddress}: ${morBalance}`); - - const tx = await l2TokenReceiver.increaseLiquidityCurrentRange(86416, wstethBalance, morBalance, 0, 0); - await tx.wait(); - - console.log('liquidity added'); - - const wstethBalanceAfter = await wsteth.balanceOf(l2MessageReceiverAddress); - const morBalanceAfter = await mor.balanceOf(l2MessageReceiverAddress); - - console.log(`wsteth balance of ${l2MessageReceiverAddress}: ${wstethBalanceAfter}`); - console.log(`mor balance of ${l2MessageReceiverAddress}: ${morBalanceAfter}`); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); - -// npx hardhat run scripts/tryAddLiquidity.ts --network arbitrum_goerli diff --git a/scripts/tryTokensSwap.ts b/scripts/tryTokensSwap.ts deleted file mode 100644 index ca822b4..0000000 --- a/scripts/tryTokensSwap.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { ethers } from 'hardhat'; - -import { L2TokenReceiver } from '@/generated-types/ethers'; - -async function main() { - const L2TokenReceiver = await ethers.getContractFactory('L2TokenReceiver'); - const l2TokenReceiver = L2TokenReceiver.attach('0x2C0f43E5C92459F62C102517956A95E88E177e95') as L2TokenReceiver; - - const tx = await l2TokenReceiver.swap(500, 0); - console.log(tx); -} - -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); - -// npx hardhat run scripts/tryTokensSwap.ts --network arbitrum_goerli From 5477fe7f448314fa35c11c6858eb3a6bfe9176a3 Mon Sep 17 00:00:00 2001 From: Ruslan Kasheparov Date: Mon, 13 May 2024 19:09:01 +0200 Subject: [PATCH 09/17] Updated package.json --- package-lock.json | 4 ++-- package.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 38017e8..98b6049 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,8 +25,8 @@ }, "devDependencies": { "@metamask/eth-sig-util": "^7.0.0", - "@nomicfoundation/hardhat-chai-matchers": "^2.0.6", - "@nomicfoundation/hardhat-ethers": "^3.0.5", + "@nomicfoundation/hardhat-chai-matchers": "^2.0.2", + "@nomicfoundation/hardhat-ethers": "^3.0.4", "@nomicfoundation/hardhat-network-helpers": "^1.0.9", "@nomiclabs/hardhat-truffle5": "^2.0.7", "@nomiclabs/hardhat-web3": "^2.0.0", diff --git a/package.json b/package.json index 737e24d..e09bb3d 100644 --- a/package.json +++ b/package.json @@ -53,8 +53,8 @@ }, "devDependencies": { "@metamask/eth-sig-util": "^7.0.0", - "@nomicfoundation/hardhat-chai-matchers": "^2.0.6", - "@nomicfoundation/hardhat-ethers": "^3.0.5", + "@nomicfoundation/hardhat-chai-matchers": "^2.0.2", + "@nomicfoundation/hardhat-ethers": "^3.0.4", "@nomicfoundation/hardhat-network-helpers": "^1.0.9", "@nomiclabs/hardhat-truffle5": "^2.0.7", "@nomiclabs/hardhat-web3": "^2.0.0", From 9832d66a9e132d33c31a9d998a43dd6d31e57d16 Mon Sep 17 00:00:00 2001 From: Ruslan Kasheparov Date: Tue, 14 May 2024 13:30:44 +0200 Subject: [PATCH 10/17] fixes --- contracts/Factory.sol | 27 ++++++++++++++++++++++++-- contracts/L1/L1Factory.sol | 13 +++++++++++-- contracts/L2/L2Factory.sol | 9 +++++++++ contracts/mock/FactoryMock.sol | 2 +- test/L1/L1Factory.test.ts | 35 ++++++++++++++++++++++++++++++---- test/L2/L2Factory.test.ts | 35 +++++++++++++++++++++++++++++++--- 6 files changed, 109 insertions(+), 12 deletions(-) diff --git a/contracts/Factory.sol b/contracts/Factory.sol index a615504..ee29c41 100644 --- a/contracts/Factory.sol +++ b/contracts/Factory.sol @@ -1,6 +1,7 @@ // 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"; @@ -62,9 +63,9 @@ abstract contract Factory is IFactory, OwnableUpgradeable, PausableUpgradeable, * @param poolName_ the name of the pool. * @return proxy the proxy address for the `poolType_`. */ - function _deploy2(uint8 poolType_, string memory poolName_) internal returns (address) { + function _deploy2(uint8 poolType_, string calldata poolName_) internal returns (address) { require(bytes(poolName_).length != 0, "F: poolName_ is empty"); - bytes32 salt_ = keccak256(abi.encodePacked(_msgSender(), poolName_, poolType_)); + bytes32 salt_ = _calculatePoolSalt(_msgSender(), poolName_, poolType_); address implementation_ = _implementations[poolType_]; require(implementation_ != address(0), "F: implementation not found"); @@ -81,5 +82,27 @@ abstract contract Factory is IFactory, OwnableUpgradeable, PausableUpgradeable, 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 {} } diff --git a/contracts/L1/L1Factory.sol b/contracts/L1/L1Factory.sol index 0b15a18..ff3b1d4 100644 --- a/contracts/L1/L1Factory.sol +++ b/contracts/L1/L1Factory.sol @@ -67,13 +67,13 @@ contract L1Factory is IL1Factory, Factory { lzExternalDeps.adapterParams ); - IL1Sender.DepositTokenConfig memory arbConfig = IL1Sender.DepositTokenConfig( + IL1Sender.DepositTokenConfig memory arbConfig_ = IL1Sender.DepositTokenConfig( depositTokenExternalDeps.wToken, arbExternalDeps.endpoint, l1Params_.l2TokenReceiver ); - IL1Sender(l1SenderProxy_).L1Sender__init(distributionProxy_, lzConfig_, arbConfig); + IL1Sender(l1SenderProxy_).L1Sender__init(distributionProxy_, lzConfig_, arbConfig_); if (l1Params_.isNotUpgradeable) { IDistribution(distributionProxy_).removeUpgradeability(); @@ -82,4 +82,13 @@ contract L1Factory is IL1Factory, Factory { 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_); + } } diff --git a/contracts/L2/L2Factory.sol b/contracts/L2/L2Factory.sol index ef17d33..969d8a6 100644 --- a/contracts/L2/L2Factory.sol +++ b/contracts/L2/L2Factory.sol @@ -73,4 +73,13 @@ contract L2Factory is IL2Factory, Factory { IOwnable(l2MessageReceiver).transferOwnership(_msgSender()); IOwnable(l2TokenReceiver).transferOwnership(_msgSender()); } + + function predictAddresses( + string calldata poolName_, + address sender_ + ) external view returns (address l2MessageReceiver_, address l2TokenReceiver_) { + l2MessageReceiver_ = _predictPoolAddress(uint8(PoolType.L2_MESSAGE_RECEIVER), poolName_, sender_); + + l2TokenReceiver_ = _predictPoolAddress(uint8(PoolType.L2_TOKEN_RECEIVER), poolName_, sender_); + } } diff --git a/contracts/mock/FactoryMock.sol b/contracts/mock/FactoryMock.sol index ab813db..65b3a99 100644 --- a/contracts/mock/FactoryMock.sol +++ b/contracts/mock/FactoryMock.sol @@ -15,7 +15,7 @@ contract FactoryMock is Factory { __Factory_init(); } - function deploy2(uint8 poolType_, string memory poolName_) external returns (address) { + function deploy2(uint8 poolType_, string calldata poolName_) external returns (address) { return _deploy2(poolType_, poolName_); } } diff --git a/test/L1/L1Factory.test.ts b/test/L1/L1Factory.test.ts index 5a63911..af44eac 100644 --- a/test/L1/L1Factory.test.ts +++ b/test/L1/L1Factory.test.ts @@ -10,6 +10,7 @@ import { Distribution__factory, FeeConfig, GatewayRouterMock, + IL1Factory, L1Factory, L1Sender, L1Sender__factory, @@ -112,19 +113,19 @@ describe('L1Factory', () => { afterEach(reverter.revert); function getL1FactoryParams() { - const depositTokenExternalDeps: L1Factory.DepositTokenExternalDepsStruct = { + const depositTokenExternalDeps: IL1Factory.DepositTokenExternalDepsStruct = { token: stEthMock, wToken: wstEthMock, }; - const lzExternalDeps: L1Factory.LzExternalDepsStruct = { + const lzExternalDeps: IL1Factory.LzExternalDepsStruct = { endpoint: lzEndpoint, zroPaymentAddress: ZERO_ADDR, adapterParams: '0x', destinationChainId: 2, }; - const arbExternalDeps: L1Factory.ArbExternalDepsStruct = { + const arbExternalDeps: IL1Factory.ArbExternalDepsStruct = { endpoint: gatewayRouterMock, }; @@ -132,7 +133,7 @@ describe('L1Factory', () => { } function getL1DefaultParams() { - const l1Params: L1Factory.L1ParamsStruct = { + const l1Params: IL1Factory.L1ParamsStruct = { protocolName: 'Mor20', isNotUpgradeable: false, poolsInfo: [], @@ -323,4 +324,30 @@ describe('L1Factory', () => { await expect(l1Factory.deploy(getL1DefaultParams())).to.be.revertedWith('Pausable: paused'); }); }); + + describe('#predictAddresses', () => { + beforeEach(async () => { + const { depositTokenExternalDeps, lzExternalDeps, arbExternalDeps } = getL1FactoryParams(); + + await l1Factory.setDepositTokenExternalDeps(depositTokenExternalDeps); + await l1Factory.setLzExternalDeps(lzExternalDeps); + await l1Factory.setArbExternalDeps(arbExternalDeps); + }); + + it('should predict addresses', async () => { + const l1Params = getL1DefaultParams(); + + const [distribution, l1Sender] = await l1Factory.predictAddresses(l1Params.protocolName, OWNER); + + expect(distribution).to.be.properAddress; + expect(l1Sender).to.be.properAddress; + + await l1Factory.deploy(l1Params); + + expect(await l1Factory.deployedProxies(OWNER, l1Params.protocolName, PoolTypesL1.DISTRIBUTION)).to.equal( + distribution, + ); + expect(await l1Factory.deployedProxies(OWNER, l1Params.protocolName, PoolTypesL1.L1_SENDER)).to.equal(l1Sender); + }); + }); }); diff --git a/test/L2/L2Factory.test.ts b/test/L2/L2Factory.test.ts index 3593835..572131f 100644 --- a/test/L2/L2Factory.test.ts +++ b/test/L2/L2Factory.test.ts @@ -6,6 +6,7 @@ import { PoolTypesL2 } from '../helpers/helper'; import { Reverter } from '../helpers/reverter'; import { + IL2Factory, L2Factory, L2FactoryV2, L2MessageReceiver, @@ -111,13 +112,13 @@ describe('L2Factory', () => { afterEach(reverter.revert); function getL2FactoryParams() { - const lzTokenExternalDeps: L2Factory.LzExternalDepsStruct = { + const lzTokenExternalDeps: IL2Factory.LzExternalDepsStruct = { endpoint: lzEndpoint, oftEndpoint: lzEndpointOFT, senderChainId: senderChainId, }; - const uniswapExternalDeps: L2Factory.UniswapExternalDepsStruct = { + const uniswapExternalDeps: IL2Factory.UniswapExternalDepsStruct = { router: swapRouter, nonfungiblePositionManager: nonfungiblePositionManager, }; @@ -126,7 +127,7 @@ describe('L2Factory', () => { } function getL2DefaultParams() { - const l2Params: L2Factory.L2ParamsStruct = { + const l2Params: IL2Factory.L2ParamsStruct = { protocolName: 'Mor20', mor20Name: 'MOR20', mor20Symbol: 'M20', @@ -299,4 +300,32 @@ describe('L2Factory', () => { await expect(l2Factory.deploy(getL2DefaultParams())).to.be.revertedWith('Pausable: paused'); }); }); + + describe('#predictAddresses', () => { + beforeEach(async () => { + const { lzTokenExternalDeps, uniswapExternalDeps } = getL2FactoryParams(); + + await l2Factory.setLzExternalDeps(lzTokenExternalDeps); + await l2Factory.setUniswapExternalDeps(uniswapExternalDeps); + }); + + it('should predict addresses', async () => { + const l2Params = getL2DefaultParams(); + + const [l2MessageReceiver, l2TokenReceiver] = await l2Factory.predictAddresses(l2Params.protocolName, OWNER); + + expect(l2MessageReceiver).to.be.properAddress; + expect(l2TokenReceiver).to.be.properAddress; + + await l2Factory.deploy(l2Params); + + expect(await l2Factory.deployedProxies(OWNER, l2Params.protocolName, PoolTypesL2.L2_MESSAGE_RECEIVER)).to.equal( + l2MessageReceiver, + ); + + expect(await l2Factory.deployedProxies(OWNER, l2Params.protocolName, PoolTypesL2.L2_TOKEN_RECEIVER)).to.equal( + l2TokenReceiver, + ); + }); + }); }); From fb72f0ee683384a0898a9de2781733e65aff3c7d Mon Sep 17 00:00:00 2001 From: Ruslan Kasheparov Date: Tue, 14 May 2024 15:07:38 +0200 Subject: [PATCH 11/17] added more tests --- contracts/Factory.sol | 4 +- contracts/L1/L1Factory.sol | 6 + contracts/L2/L2Factory.sol | 2 +- contracts/interfaces/L2/IL2Factory.sol | 2 + contracts/mock/tokens/WETHMock.sol | 12 ++ test/Integration.test.ts | 278 +++++++++++++++++++++++++ test/L1/L1Factory.test.ts | 18 +- test/L2/L2Factory.test.ts | 1 + 8 files changed, 319 insertions(+), 4 deletions(-) create mode 100644 contracts/mock/tokens/WETHMock.sol create mode 100644 test/Integration.test.ts diff --git a/contracts/Factory.sol b/contracts/Factory.sol index ee29c41..52a6702 100644 --- a/contracts/Factory.sol +++ b/contracts/Factory.sol @@ -67,13 +67,13 @@ abstract contract Factory is IFactory, OwnableUpgradeable, PausableUpgradeable, require(bytes(poolName_).length != 0, "F: poolName_ is empty"); bytes32 salt_ = _calculatePoolSalt(_msgSender(), poolName_, poolType_); - address implementation_ = _implementations[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_}(getImplementation(poolType_), bytes(""))); + address proxy_ = address(new ERC1967Proxy{salt: salt_}(implementation_, bytes(""))); deployedProxies[_msgSender()][poolName_][poolType_] = proxy_; diff --git a/contracts/L1/L1Factory.sol b/contracts/L1/L1Factory.sol index ff3b1d4..2385512 100644 --- a/contracts/L1/L1Factory.sol +++ b/contracts/L1/L1Factory.sol @@ -48,6 +48,12 @@ contract L1Factory is IL1Factory, Factory { 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); diff --git a/contracts/L2/L2Factory.sol b/contracts/L2/L2Factory.sol index 969d8a6..878ed8a 100644 --- a/contracts/L2/L2Factory.sol +++ b/contracts/L2/L2Factory.sol @@ -55,7 +55,7 @@ contract L2Factory is IL2Factory, Factory { IL2MessageReceiver(l2MessageReceiver).L2MessageReceiver__init( mor20, - IL2MessageReceiver.Config(lzExternalDeps.endpoint, address(0), lzExternalDeps.senderChainId) + IL2MessageReceiver.Config(lzExternalDeps.endpoint, l2Params_.l1Sender, lzExternalDeps.senderChainId) ); IL2TokenReceiver(l2TokenReceiver).L2TokenReceiver__init( diff --git a/contracts/interfaces/L2/IL2Factory.sol b/contracts/interfaces/L2/IL2Factory.sol index 6017220..4d6e8d5 100644 --- a/contracts/interfaces/L2/IL2Factory.sol +++ b/contracts/interfaces/L2/IL2Factory.sol @@ -19,6 +19,7 @@ interface IL2Factory { * @param protocolName The protocol name. * @param mor20Name The MOR20 name. * @param mor20Symbol The MOR20 symbol. + * @param l1Sender The L1 sender address. * @param firstSwapParams_ The first swap parameters. * @param secondSwapFee The second swap fee. * @param secondSwapSqrtPriceLimitX96 The second swap square root price limit. @@ -27,6 +28,7 @@ interface IL2Factory { string protocolName; string mor20Name; string mor20Symbol; + address l1Sender; IL2TokenReceiver.SwapParams firstSwapParams_; uint24 secondSwapFee; uint160 secondSwapSqrtPriceLimitX96; diff --git a/contracts/mock/tokens/WETHMock.sol b/contracts/mock/tokens/WETHMock.sol new file mode 100644 index 0000000..76e9f8d --- /dev/null +++ b/contracts/mock/tokens/WETHMock.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract WETHMock is ERC20 { + constructor() ERC20("WETH", "WETH") {} + + function mint(address account_, uint256 amount_) external { + _mint(account_, amount_); + } +} diff --git a/test/Integration.test.ts b/test/Integration.test.ts new file mode 100644 index 0000000..b8a53cf --- /dev/null +++ b/test/Integration.test.ts @@ -0,0 +1,278 @@ +import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers'; +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { setNextTime } from './helpers/block-helper'; +import { getDefaultPool, oneDay } from './helpers/distribution-helper'; +import { PoolTypesL1, PoolTypesL2 } from './helpers/helper'; +import { Reverter } from './helpers/reverter'; + +import { + FeeConfig, + IL1Factory, + IL2Factory, + L1Factory, + L2Factory, + LZEndpointMock, + WETHMock, + WStETHMock, +} from '@/generated-types/ethers'; +import { ZERO_ADDR } from '@/scripts/utils/constants'; +import { wei } from '@/scripts/utils/utils'; + +describe('Integration', () => { + const senderChainId = 101; + const receiverChainId = 102; + + const reverter = new Reverter(); + + let OWNER: SignerWithAddress; + + let l1Factory: L1Factory; + let l2Factory: L2Factory; + + let l2Weth: WETHMock; + let l1WstEth: WStETHMock; + let l2WstEth: WStETHMock; + + let l1LzEndpoint: LZEndpointMock; + let l2LzEndpoint: LZEndpointMock; + + let depositTokenExternalDeps: IL1Factory.DepositTokenExternalDepsStruct; + let lzExternalDeps: IL1Factory.LzExternalDepsStruct; + let arbExternalDeps: IL1Factory.ArbExternalDepsStruct; + + let lzTokenExternalDeps: IL2Factory.LzExternalDepsStruct; + let uniswapExternalDeps: IL2Factory.UniswapExternalDepsStruct; + + before(async () => { + [OWNER] = await ethers.getSigners(); + + const [ + L1Factory, + ERC1967ProxyFactory, + + LinearDistributionIntervalDecreaseFactory, + L1SenderFactory, + StEthMockFactory, + WstEthMockFactory, + GatewayRouterMockFactory, + FeeConfigFactory, + LZEndpointMockFactory, + + LayerZeroEndpointV2Mock, + MOR20DeployerFactory, + SwapRouterMockFactory, + NonfungiblePositionManagerMockFactory, + L2MessageReceiverFactory, + L2TokenReceiverFactory, + WETHMockFactory, + ] = await Promise.all([ + ethers.getContractFactory('L1Factory'), + ethers.getContractFactory('ERC1967Proxy'), + + ethers.getContractFactory('LinearDistributionIntervalDecrease'), + ethers.getContractFactory('L1Sender'), + ethers.getContractFactory('StETHMock'), + ethers.getContractFactory('WStETHMock'), + ethers.getContractFactory('GatewayRouterMock'), + ethers.getContractFactory('FeeConfig'), + ethers.getContractFactory('LZEndpointMock'), + + ethers.getContractFactory('LayerZeroEndpointV2Mock'), + ethers.getContractFactory('MOR20Deployer'), + ethers.getContractFactory('SwapRouterMock'), + ethers.getContractFactory('NonfungiblePositionManagerMock'), + ethers.getContractFactory('L2MessageReceiver'), + ethers.getContractFactory('L2TokenReceiver'), + ethers.getContractFactory('WETHMock'), + ]); + + const [ + linearDistributionIntervalDecrease, + l1SenderImplementation, + l1StEth, + l2StEth, + gatewayRouterMock, + feeConfigImplementation, + l1LzEndpointMock, + + l2LzEndpointMock, + l2LzEndpointOFT, + l2MessageReceiverImplementation, + l2TokenReceiverImplementation, + MOR20Deployer, + swapRouter, + nonfungiblePositionManager, + l2WethMock, + ] = await Promise.all([ + LinearDistributionIntervalDecreaseFactory.deploy(), + L1SenderFactory.deploy(), + StEthMockFactory.deploy(), + StEthMockFactory.deploy(), + GatewayRouterMockFactory.deploy(), + FeeConfigFactory.deploy(), + LZEndpointMockFactory.deploy(senderChainId), + + LZEndpointMockFactory.deploy(receiverChainId), + LayerZeroEndpointV2Mock.deploy(receiverChainId, OWNER), + L2MessageReceiverFactory.deploy(), + L2TokenReceiverFactory.deploy(), + MOR20DeployerFactory.deploy(), + SwapRouterMockFactory.deploy(), + NonfungiblePositionManagerMockFactory.deploy(), + WETHMockFactory.deploy(), + ]); + l2Weth = l2WethMock; + l1LzEndpoint = l1LzEndpointMock; + l2LzEndpoint = l2LzEndpointMock; + + const distributionFactory = await ethers.getContractFactory('Distribution', { + libraries: { + LinearDistributionIntervalDecrease: linearDistributionIntervalDecrease, + }, + }); + const distributionImplementation = await distributionFactory.deploy(); + + l1WstEth = await WstEthMockFactory.deploy(l1StEth); + l2WstEth = await WstEthMockFactory.deploy(l2StEth); + + const l1FactoryImpl = await L1Factory.deploy(); + const l1FactoryProxy = await ERC1967ProxyFactory.deploy(l1FactoryImpl, '0x'); + l1Factory = L1Factory.attach(l1FactoryProxy) as L1Factory; + await l1Factory.L1Factory_init(); + + await l1Factory.setImplementation(PoolTypesL1.DISTRIBUTION, distributionImplementation); + await l1Factory.setImplementation(PoolTypesL1.L1_SENDER, l1SenderImplementation); + + const feeConfigProxy = await ERC1967ProxyFactory.deploy(feeConfigImplementation, '0x'); + const feeConfig = FeeConfigFactory.attach(feeConfigProxy) as FeeConfig; + await feeConfig.__FeeConfig_init(OWNER, wei(0.1, 25)); + + const L2Factory = await ethers.getContractFactory('L2Factory', { + libraries: { + MOR20Deployer: MOR20Deployer, + }, + }); + const l2FactoryImpl = await L2Factory.deploy(); + const l2FactoryProxy = await ERC1967ProxyFactory.deploy(l2FactoryImpl, '0x'); + l2Factory = L2Factory.attach(l2FactoryProxy) as L2Factory; + await l2Factory.L2Factory_init(); + + await l2Factory.setImplementation(PoolTypesL2.L2_MESSAGE_RECEIVER, l2MessageReceiverImplementation); + await l2Factory.setImplementation(PoolTypesL2.L2_TOKEN_RECEIVER, l2TokenReceiverImplementation); + + depositTokenExternalDeps = { + token: l1StEth, + wToken: l1WstEth, + }; + lzExternalDeps = { + endpoint: l1LzEndpoint, + zroPaymentAddress: ZERO_ADDR, + adapterParams: '0x', + destinationChainId: receiverChainId, + }; + arbExternalDeps = { + endpoint: gatewayRouterMock, + }; + + await l1Factory.setDepositTokenExternalDeps(depositTokenExternalDeps); + await l1Factory.setLzExternalDeps(lzExternalDeps); + await l1Factory.setArbExternalDeps(arbExternalDeps); + await l1Factory.setFeeConfig(feeConfig); + + lzTokenExternalDeps = { + endpoint: l2LzEndpoint, + oftEndpoint: l2LzEndpointOFT, + senderChainId: senderChainId, + }; + uniswapExternalDeps = { + router: swapRouter, + nonfungiblePositionManager: nonfungiblePositionManager, + }; + await l2Factory.setLzExternalDeps(lzTokenExternalDeps); + await l2Factory.setUniswapExternalDeps(uniswapExternalDeps); + + await l1StEth.mint(OWNER, wei(1000)); + + await reverter.snapshot(); + }); + + afterEach(reverter.revert); + + describe('Should deploy L1 and L2', () => { + const protocolName = 'Mor20'; + + it('should deploy correctly', async () => { + const [l2MessageReceiverPredicted, l2TokenReceiverPredicted] = await l2Factory.predictAddresses( + protocolName, + OWNER, + ); + + const [distributionPredicted, l1SenderPredicted] = await l1Factory.predictAddresses(protocolName, OWNER); + + await l1LzEndpoint.setDestLzEndpoint(l2MessageReceiverPredicted, l2LzEndpoint); + + const l1Params: IL1Factory.L1ParamsStruct = { + protocolName: protocolName, + isNotUpgradeable: true, + poolsInfo: [], + l2TokenReceiver: l2TokenReceiverPredicted, + l2MessageReceiver: l2MessageReceiverPredicted, + }; + const l2Params: IL2Factory.L2ParamsStruct = { + protocolName: protocolName, + mor20Name: 'MOR20', + mor20Symbol: 'M20', + l1Sender: l1SenderPredicted, + firstSwapParams_: { + tokenIn: l2WstEth, + tokenOut: l2Weth, + fee: 100, + sqrtPriceLimitX96: 0, + }, + secondSwapFee: 3000, + secondSwapSqrtPriceLimitX96: 0, + }; + + await l1Factory.deploy(l1Params); + await l2Factory.deploy(l2Params); + + const distribution = await ethers.getContractAt('Distribution', distributionPredicted); + const MOR20 = await ethers.getContractAt( + 'MOR20', + await l2Factory.deployedProxies(OWNER, protocolName, PoolTypesL2.MOR20), + ); + + const pool = getDefaultPool(); + await distribution.createPool(pool); + + const l1StEth = await ethers.getContractAt('StETHMock', (await l1Factory.depositTokenExternalDeps()).token); + await l1StEth.approve(distribution, wei(1)); + await distribution.stake(0, wei(1)); + + await l1StEth.setTotalPooledEther((await l1StEth.totalPooledEther()) * 2n); + + const overplus = await distribution.overplus(); + expect(overplus).to.be.eq(wei(1)); + + let tx = await distribution.bridgeOverplus(1, 1, 1); + await expect(tx).to.changeTokenBalances(l1StEth, [distributionPredicted, OWNER], [wei(-1), wei(0.1)]); + // we made an assumption that the token address is l1WstEth + await expect(tx).to.changeTokenBalance(l1WstEth, l2TokenReceiverPredicted, wei(0.9)); + expect(await distribution.overplus()).to.be.eq(0); + + await setNextTime(2 * oneDay); + + tx = await distribution.withdraw(0, wei(1)); + await expect(tx).to.changeTokenBalances(l1StEth, [distributionPredicted, OWNER], [wei(-1), wei(1)]); + + const reward = await distribution.getCurrentUserReward(0, OWNER); + expect(reward).to.equal(wei(100)); + + await distribution.claim(0, OWNER, { value: wei(0.1) }); + + expect(await MOR20.balanceOf(OWNER)).to.be.eq(reward); + }); + }); +}); diff --git a/test/L1/L1Factory.test.ts b/test/L1/L1Factory.test.ts index af44eac..c24a92d 100644 --- a/test/L1/L1Factory.test.ts +++ b/test/L1/L1Factory.test.ts @@ -83,7 +83,7 @@ describe('L1Factory', () => { const feeConfigProxy = await ERC1967ProxyFactory.deploy(feeConfigImpl, '0x'); feeConfig = feeConfigFactory.attach(feeConfigProxy) as FeeConfig; - await feeConfig.__FeeConfig_init(OWNER, wei(0.1)); + await feeConfig.__FeeConfig_init(OWNER, wei(0.1, 25)); distributionFactory = await ethers.getContractFactory('Distribution', { libraries: { @@ -264,6 +264,22 @@ describe('L1Factory', () => { }); }); + describe('#setFeeConfig', () => { + it('should set fee config', async () => { + await l1Factory.setFeeConfig(feeConfig); + + expect(await l1Factory.feeConfig()).to.equal(await feeConfig.getAddress()); + }); + it('should revert if provided fee config is zero address', async () => { + await expect(l1Factory.setFeeConfig(ZERO_ADDR)).to.be.revertedWith('L1F: invalid fee config'); + }); + it('should revert if called by non-owner', async () => { + await expect(l1Factory.connect(SECOND).setFeeConfig(feeConfig)).to.be.revertedWith( + 'Ownable: caller is not the owner', + ); + }); + }); + describe('deploy', () => { beforeEach(async () => { const { depositTokenExternalDeps, lzExternalDeps, arbExternalDeps } = getL1FactoryParams(); diff --git a/test/L2/L2Factory.test.ts b/test/L2/L2Factory.test.ts index 572131f..f48bde2 100644 --- a/test/L2/L2Factory.test.ts +++ b/test/L2/L2Factory.test.ts @@ -131,6 +131,7 @@ describe('L2Factory', () => { protocolName: 'Mor20', mor20Name: 'MOR20', mor20Symbol: 'M20', + l1Sender: ZERO_ADDR, firstSwapParams_: { tokenIn: ETHER_ADDR, tokenOut: ETHER_ADDR, From 5009610e35b7c085754919ea130615fd6e6b0a0e Mon Sep 17 00:00:00 2001 From: Ruslan Kasheparov Date: Tue, 14 May 2024 17:35:47 +0200 Subject: [PATCH 12/17] added config --- deploy/1_L1.migration.ts | 50 ++++++ deploy/1_L2.migration.ts | 38 +++++ deploy/1_bridge.migration.ts | 79 ---------- deploy/2_token.migration.ts | 93 ----------- deploy/3_init_bridge.migration.ts | 46 ------ deploy/4_moroft_testnet.migration.ts | 18 --- deploy/data/config.json | 226 +++------------------------ deploy/data/config_goerli.json | 56 ------- deploy/data/config_localhost.json | 60 +++---- deploy/data/config_sepolia.json | 68 +++----- deploy/deploy-all.sh | 9 -- deploy/helpers/config-parser.ts | 215 ++++++++++--------------- 12 files changed, 234 insertions(+), 724 deletions(-) create mode 100644 deploy/1_L1.migration.ts create mode 100644 deploy/1_L2.migration.ts delete mode 100644 deploy/1_bridge.migration.ts delete mode 100644 deploy/2_token.migration.ts delete mode 100644 deploy/3_init_bridge.migration.ts delete mode 100644 deploy/4_moroft_testnet.migration.ts delete mode 100644 deploy/data/config_goerli.json delete mode 100755 deploy/deploy-all.sh diff --git a/deploy/1_L1.migration.ts b/deploy/1_L1.migration.ts new file mode 100644 index 0000000..1217393 --- /dev/null +++ b/deploy/1_L1.migration.ts @@ -0,0 +1,50 @@ +import { Deployer, Reporter } from '@solarity/hardhat-migrate'; + +import { parseConfig } from './helpers/config-parser'; + +import { + Distribution__factory, + ERC1967Proxy__factory, + FeeConfig__factory, + L1Factory__factory, + L1Sender__factory, +} from '@/generated-types/ethers'; +import { PoolTypesL1 } from '@/test/helpers/helper'; + +module.exports = async function (deployer: Deployer) { + const config = parseConfig(await deployer.getChainId()); + + const distributionImpl = await deployer.deploy(Distribution__factory); + const L1SenderImpl = await deployer.deploy(L1Sender__factory); + + const feeConfigImpl = await deployer.deploy(FeeConfig__factory); + const feeConfigProxy = await deployer.deploy(ERC1967Proxy__factory, [await feeConfigImpl.getAddress(), '0x'], { + name: 'FeeConfigProxy', + }); + + const feeConfig = await deployer.deployed(FeeConfig__factory, await feeConfigProxy.getAddress()); + + await feeConfig.__FeeConfig_init(config.feeConfig.treasury, config.feeConfig.baseFee); + + const l1FactoryImpl = await deployer.deploy(L1Factory__factory); + const l1FactoryProxy = await deployer.deploy(ERC1967Proxy__factory, [await l1FactoryImpl.getAddress(), '0x'], { + name: 'L1FactoryProxy', + }); + const l1Factory = await deployer.deployed(L1Factory__factory, await l1FactoryProxy.getAddress()); + + await l1Factory.L1Factory_init(); + + await l1Factory.setDepositTokenExternalDeps(config.depositTokenExternalDeps); + await l1Factory.setLzExternalDeps(config.lzExternalDeps); + await l1Factory.setArbExternalDeps(config.arbExternalDeps); + + await l1Factory.setImplementation(PoolTypesL1.DISTRIBUTION, distributionImpl); + await l1Factory.setImplementation(PoolTypesL1.L1_SENDER, L1SenderImpl); + + Reporter.reportContracts( + ['l1Factory', await l1Factory.getAddress()], + ['FeeConfig', await feeConfig.getAddress()], + ['DistributionImpl', await distributionImpl.getAddress()], + ['L1SenderImpl', await L1SenderImpl.getAddress()], + ); +}; diff --git a/deploy/1_L2.migration.ts b/deploy/1_L2.migration.ts new file mode 100644 index 0000000..29a16d0 --- /dev/null +++ b/deploy/1_L2.migration.ts @@ -0,0 +1,38 @@ +import { Deployer, Reporter } from '@solarity/hardhat-migrate'; + +import { parseConfig } from './helpers/config-parser'; + +import { + ERC1967Proxy__factory, + L2Factory__factory, + L2MessageReceiver__factory, + L2TokenReceiver__factory, +} from '@/generated-types/ethers'; +import { PoolTypesL2 } from '@/test/helpers/helper'; + +module.exports = async function (deployer: Deployer) { + const config = parseConfig(await deployer.getChainId()); + + const l2MessageReceiverImpl = await deployer.deploy(L2MessageReceiver__factory); + const l2TokenReceiverImpl = await deployer.deploy(L2TokenReceiver__factory); + + const l2FactoryImpl = await deployer.deploy(L2Factory__factory); + const l2FactoryProxy = await deployer.deploy(ERC1967Proxy__factory, [await l2FactoryImpl.getAddress(), '0x'], { + name: 'L2FactoryProxy', + }); + const l2Factory = await deployer.deployed(L2Factory__factory, await l2FactoryProxy.getAddress()); + + await l2Factory.L2Factory_init(); + + await l2Factory.setLzExternalDeps(config.lzTokenExternalDeps); + await l2Factory.setUniswapExternalDeps(config.uniswapExternalDeps); + + await l2Factory.setImplementation(PoolTypesL2.L2_MESSAGE_RECEIVER, l2MessageReceiverImpl); + await l2Factory.setImplementation(PoolTypesL2.L2_TOKEN_RECEIVER, l2TokenReceiverImpl); + + Reporter.reportContracts( + ['l2Factory', await l2Factory.getAddress()], + ['L2MessageReceiverImpl', await l2MessageReceiverImpl.getAddress()], + ['L2TokenReceiverImpl', await l2TokenReceiverImpl.getAddress()], + ); +}; diff --git a/deploy/1_bridge.migration.ts b/deploy/1_bridge.migration.ts deleted file mode 100644 index 9f2b116..0000000 --- a/deploy/1_bridge.migration.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { Deployer, Reporter, UserStorage } from '@solarity/hardhat-migrate'; - -import { parseConfig } from './helpers/config-parser'; - -import { - ERC1967Proxy__factory, - L2MessageReceiver__factory, - L2TokenReceiver__factory, - MOR__factory, -} from '@/generated-types/ethers'; -import { IL2TokenReceiver } from '@/generated-types/ethers/contracts/L2TokenReceiver'; - -module.exports = async function (deployer: Deployer) { - const config = parseConfig(await deployer.getChainId()); - - let WStETH: string; - let swapRouter: string; - let nonfungiblePositionManager: string; - - if (config.L2) { - WStETH = config.L2.wStEth; - swapRouter = config.L2.swapRouter; - nonfungiblePositionManager = config.L2.nonfungiblePositionManager; - } else { - // deploy mock - // const stETHMock = await deployer.deploy(StETHMock__factory, [], { name: 'StETH on L2' }); - // const stETH = await stETHMock.getAddress(); - - // const wStEthMock = await deployer.deploy(WStETHMock__factory, [stETH], { name: 'Wrapped stETH on L2' }); - // WStETH = await wStEthMock.getAddress(); - - // const swapRouterMock = await deployer.deploy(SwapRouterMock__factory); - // swapRouter = await swapRouterMock.getAddress(); - - // const nonfungiblePositionManagerMock = await deployer.deploy(NonfungiblePositionManagerMock__factory); - // nonfungiblePositionManager = await nonfungiblePositionManagerMock.getAddress(); - return; - } - - const MOR = await deployer.deploy(MOR__factory, [config.cap]); - UserStorage.set('MOR', await MOR.getAddress()); - - const swapParams: IL2TokenReceiver.SwapParamsStruct = { - tokenIn: WStETH, - tokenOut: MOR, - fee: config.swapParams.fee, - sqrtPriceLimitX96: config.swapParams.sqrtPriceLimitX96, - }; - - const l2TokenReceiverImpl = await deployer.deploy(L2TokenReceiver__factory); - const l2TokenReceiverProxy = await deployer.deploy(ERC1967Proxy__factory, [l2TokenReceiverImpl, '0x'], { - name: 'L2TokenReceiver Proxy', - }); - UserStorage.set('L2TokenReceiver Proxy', await l2TokenReceiverProxy.getAddress()); - const l2TokenReceiver = L2TokenReceiver__factory.connect( - await l2TokenReceiverProxy.getAddress(), - await deployer.getSigner(), - ); - await l2TokenReceiver.L2TokenReceiver__init(swapRouter, nonfungiblePositionManager, swapParams); - - const l2MessageReceiverImpl = await deployer.deploy(L2MessageReceiver__factory); - const l2MessageReceiverProxy = await deployer.deploy(ERC1967Proxy__factory, [l2MessageReceiverImpl, '0x'], { - name: 'L2MessageReceiver Proxy', - }); - UserStorage.set('L2MessageReceiver Proxy', await l2MessageReceiverProxy.getAddress()); - const l2MessageReceiver = L2MessageReceiver__factory.connect( - await l2MessageReceiverProxy.getAddress(), - await deployer.getSigner(), - ); - await l2MessageReceiver.L2MessageReceiver__init(); - - await MOR.transferOwnership(l2MessageReceiver); - - Reporter.reportContracts( - ['L2TokenReceiver', await l2TokenReceiver.getAddress()], - ['L2MessageReceiver', await l2MessageReceiver.getAddress()], - ['MOR', await MOR.getAddress()], - ); -}; diff --git a/deploy/2_token.migration.ts b/deploy/2_token.migration.ts deleted file mode 100644 index f379eb9..0000000 --- a/deploy/2_token.migration.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { Deployer, Reporter, UserStorage } from '@solarity/hardhat-migrate'; - -import { parseConfig } from './helpers/config-parser'; - -import { Distribution__factory, ERC1967Proxy__factory, L1Sender__factory } from '@/generated-types/ethers'; -import { IL1Sender } from '@/generated-types/ethers/contracts/L1Sender'; -import { ZERO_ADDR } from '@/scripts/utils/constants'; - -module.exports = async function (deployer: Deployer) { - const config = parseConfig(await deployer.getChainId()); - - let stETH: string; - let wStEth: string; - - if (config.L1) { - stETH = config.L1.stEth; - wStEth = config.L1.wStEth; - } else { - // deploy mock - // const stETHMock = await deployer.deploy(StETHMock__factory, { name: 'StETH on L1' }); - // stETH = await stETHMock.getAddress(); - - // const wStEthMock = await deployer.deploy(WStETHMock__factory, [stETH], { name: 'wStETH on L1' }); - // wStEth = await wStEthMock.getAddress(); - return; - } - - let lzEndpointL1: string; - if (config.lzConfig) { - lzEndpointL1 = config.lzConfig.lzEndpointL1; - } else { - // deploy mock - // const LzEndpointL1Mock = await deployer.deploy(LZEndpointMock__factory, [config.chainsConfig.senderChainId], { - // name: 'LZEndpoint on L1', - // }); - // lzEndpointL1 = await LzEndpointL1Mock.getAddress(); - return; - } - - let arbitrumBridgeGatewayRouter: string; - if (config.arbitrumConfig) { - arbitrumBridgeGatewayRouter = config.arbitrumConfig.arbitrumBridgeGatewayRouter; - } else { - return; - } - - const distributionImpl = await deployer.deploy(Distribution__factory); - const distributionProxy = await deployer.deploy(ERC1967Proxy__factory, [distributionImpl, '0x'], { - name: 'Distribution Proxy', - }); - const distribution = Distribution__factory.connect(await distributionProxy.getAddress(), await deployer.getSigner()); - - const rewardTokenConfig: IL1Sender.RewardTokenConfigStruct = { - gateway: lzEndpointL1, - // receiver: '0xd4a8ECcBe696295e68572A98b1aA70Aa9277d427', - receiver: UserStorage.get('L2MessageReceiver Proxy'), - receiverChainId: config.chainsConfig.receiverChainId, - zroPaymentAddress: ZERO_ADDR, - adapterParams: '0x', - }; - const depositTokenConfig: IL1Sender.DepositTokenConfigStruct = { - token: wStEth, - gateway: arbitrumBridgeGatewayRouter, - // receiver: '0x47176B2Af9885dC6C4575d4eFd63895f7Aaa4790', - receiver: UserStorage.get('L2TokenReceiver Proxy'), - }; - - const l1SenderImpl = await deployer.deploy(L1Sender__factory); - const l1SenderProxy = await deployer.deploy(ERC1967Proxy__factory, [l1SenderImpl, '0x'], { - name: 'L1Sender Proxy', - }); - UserStorage.set('L1Sender Proxy', await l1SenderProxy.getAddress()); - const l1Sender = L1Sender__factory.connect(await l1SenderProxy.getAddress(), await deployer.getSigner()); - await l1Sender.L1Sender__init(distribution, rewardTokenConfig, depositTokenConfig); - - await distribution.Distribution_init(stETH, l1Sender, config.pools || []); - - if (config.pools) { - for (let i = 0; i < config.pools.length; i++) { - const pool = config.pools[i]; - - if (pool.whitelistedUsers && pool.whitelistedUsers.length > 0) { - const amounts = pool.amounts!; - await distribution.manageUsersInPrivatePool(i, pool.whitelistedUsers, amounts); - } - } - } - - Reporter.reportContracts( - ['Distribution', await distribution.getAddress()], - ['L1Sender', await l1Sender.getAddress()], - ); -}; diff --git a/deploy/3_init_bridge.migration.ts b/deploy/3_init_bridge.migration.ts deleted file mode 100644 index e053ebd..0000000 --- a/deploy/3_init_bridge.migration.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Deployer, Reporter, UserStorage } from '@solarity/hardhat-migrate'; - -import { parseConfig } from './helpers/config-parser'; - -import { L1Sender__factory, L2MessageReceiver__factory, MOR__factory } from '@/generated-types/ethers'; -import { IL2MessageReceiver } from '@/generated-types/ethers/contracts/L2MessageReceiver'; - -module.exports = async function (deployer: Deployer) { - const config = parseConfig(await deployer.getChainId()); - - let lzEndpointL2: string; - if (config.lzConfig) { - lzEndpointL2 = config.lzConfig.lzEndpointL2; - } else { - // deploy mock - // const lzEndpointL2Mock = await deployer.deploy(LZEndpointMock__factory, [config.chainsConfig.receiverChainId], { - // name: 'LZEndpoint on L2', - // }); - // lzEndpointL2 = await lzEndpointL2Mock.getAddress(); - return; - } - - const l2MessageReceiver = L2MessageReceiver__factory.connect( - // '0xd4a8ECcBe696295e68572A98b1aA70Aa9277d427', - UserStorage.get('L2MessageReceiver Proxy'), - await deployer.getSigner(), - ); - - // const l1Sender = L1Sender__factory.connect('0x2Efd4430489e1a05A89c2f51811aC661B7E5FF84', await deployer.getSigner()); - - // const mor = MOR__factory.connect('0x7431aDa8a591C955a994a21710752EF9b882b8e3', await deployer.getSigner()); - - const l1Sender = L1Sender__factory.connect(UserStorage.get('L1Sender Proxy'), await deployer.getSigner()); - - const mor = MOR__factory.connect(UserStorage.get('MOR'), await deployer.getSigner()); - - const l2MessageReceiverConfig: IL2MessageReceiver.ConfigStruct = { - gateway: lzEndpointL2, - sender: l1Sender, - senderChainId: config.chainsConfig.senderChainId, - }; - - const tx = await l2MessageReceiver.setParams(mor, l2MessageReceiverConfig); - - await Reporter.reportTransactionByHash(tx.hash); -}; diff --git a/deploy/4_moroft_testnet.migration.ts b/deploy/4_moroft_testnet.migration.ts deleted file mode 100644 index 787578b..0000000 --- a/deploy/4_moroft_testnet.migration.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Deployer, Reporter } from '@solarity/hardhat-migrate'; - -import { MOROFT__factory } from '@/generated-types/ethers'; - -const lzEndpointV2 = '0x6edce65403992e310a62460808c4b910d972f10f'; - -module.exports = async function (deployer: Deployer) { - const deployerAddress = await (await deployer.getSigner()).getAddress(); - - const mor = await deployer.deploy(MOROFT__factory, [lzEndpointV2, deployerAddress, deployerAddress]); - - Reporter.reportContracts(['MOROFT', await mor.getAddress()]); -}; - -// npx hardhat migrate --only 4 -// npx hardhat migrate --network arbitrum_sepolia --only 4 --verify -// npx hardhat migrate --network sepolia --only 4 --verify -// npx hardhat migrate --network mumbai --only 4 --verify diff --git a/deploy/data/config.json b/deploy/data/config.json index b521519..7c210b8 100644 --- a/deploy/data/config.json +++ b/deploy/data/config.json @@ -1,214 +1,28 @@ { - "cap": "42000000000000000000000000", - "chainsConfig": { - "senderChainId": 101, - "receiverChainId": 110 + "feeConfig": { + "baseFee": "1000000000000000000000000", + "treasury": "0x901F2d23823730fb7F2356920e0E273EFdCdFe17" }, - "pools": [ - { - "payoutStart": 1707393600, - "decreaseInterval": 86400, - "withdrawLockPeriod": 604800, - "claimLockPeriod": 7776000, - "withdrawLockPeriodAfterStake": 604800, - "initialReward": "3456000000000000000000", - "rewardDecrease": "592558728240000000", - "minimalStake": "10000000000000000", - "isPublic": true - }, - { - "payoutStart": 1707393600, - "decreaseInterval": 86400, - "withdrawLockPeriod": 0, - "claimLockPeriod": 7776000, - "withdrawLockPeriodAfterStake": 0, - "initialReward": "3456000000000000000000", - "rewardDecrease": "592558728240000000", - "minimalStake": "0", - "isPublic": false, - "whitelistedUsers": [ - "0x7aE68C76771131835e90AEfF44f1c03d07503B92", - "0xe27458C8Bb3D9Bf298BC8FE47F0Cfab40bc45963", - "0x98eFf980C57c9D333340b3856481bF7B8698987c", - "0xb75DB2216E7047C7b6bebE1057CF7c99e5D87eD0", - "0x01974549C9B9a30d47c548A16b120b1cAa7B586C", - "0xC16C04dE65E2EBA60B78294E23953f5EB17F9202", - "0x2ed6D479C15272438c38c7c47994e3e8df3138c8", - "0x48d0EAc727A7e478f792F16527012452a000f2bd", - "0xd8737632121D4C50b76FA3349B3C197c4574170a", - "0x8388298D1B9601CE2da78127605570b4878f2cFa", - "0x8d00121e79cBb741A7da7B0598762B8dE3394E62", - "0x683C0173BD2214E95cA9FFB1B437c12A9697ABe6", - "0xf3ed92789Ec71174FCDff6aA97239E5456a1b5c0", - "0x46266F255E49756847587eabDDFc4D336Ef268d2", - "0x704a10D661A0ce0be6C3379d93FC47f13be4ab50", - "0x05A1ff0a32bc24265BCB39499d0c5D9A6cb2011c", - "0xaBd9faA94384595ea304ddce2Ac8e097970eD5b3", - "0x63d45Be2F2828c0f8e2b4Cff745e89ae74A6d034", - "0x5EBe5223831523823528Ef0a7EdF67D288B1B070", - "0x931A833E7A699163907bfE8E36cbFbF2E6fa5fd1", - "0xe4D28FE30829A825B7379EF28d5d91174436C899", - "0x62aF7c48Cf412162465A8CaFdE44dFb17bA96038", - "0xED48BAcB38Aa79F0C44133baF73a74F44cEdD5F9", - "0x6c4eB02ac1060Cf486153c0c02829739E45409F3", - "0xA17b82286601825a5ac45Dcb01f38242D1a79548", - "0x0A094e2Cb26578E688a28e7040199ADC6cd490Da", - "0x5Ae426D938fDe32Ac9268d253F1Fe3Bb6AB9d5Dd", - "0xE9e3c537E405b1F40A3e8a8EcDC4dFEA720a6Bd0", - "0x26180446C2f754256ff383b4a2558a6774551295", - "0x905591EDa020c98E13fB3b52BCcB9277dD559FE8", - "0x6F3473a6B1d89a325Bf33D592ba3E4c2b90E4014", - "0x1461F599ecCeC516cf4704253Ab26dF69003439E", - "0xbA3777CF0832922F35A1a414875E3247e2608E3C", - "0x4e3CDA01A86922586326b84E6D156097AAA94043", - "0x42FeeC5c7e7D3c725864A2716CA357Fa9993CCC0", - "0x8979CdD44b96007753e4BBc429De6f7989DAD16C", - "0x4c496ea116A09651778e480B2e7E5aBA78514521", - "0xa4b427AF1952374b3527CeBcfDCC9D063DFe802c", - "0xDeb55cA4D98218aEC15764651eeEF5799356D63E", - "0x12E6F8DfdBb81F6285f0dF132165D46F20FC85e3", - "0xcCc442eDa69e466e1C54e3A7258AE8Aab508aefC", - "0x26798cB968c8aBC7155BBfC8AcB4485A9f121666", - "0xbE97d54Cfd1ff86E21F2aEB02AA5219Bc00486E0", - "0x7dDeBE7D0A896f4BBfeDB68b892c35BDF6F21d8e", - "0x8419aF9a5d31797368523aa568dAf064ba067dD1", - "0x0A1B78004Ab0254967855f6c60230f350757043a", - "0xa7e32D41f5b94352F4De412Ff6E5fA91ed7532A2", - "0xe4C6B02b6095A18D4FF867218A31ff7b11C3e828", - "0x6357B6C6E2d79b570a0C5A0b17e20Ab46f72BCf8", - "0x9cd4cde2D492f79FfFC62634ebd22994681743be", - "0xb3fDCCE55C5452F9E9F9dd7713a4B28dAae90bc3", - "0x70305F11944ba4622ce0AE2e4D9D8023f54CeA85", - "0xe36B28c72C1F7f8a4D87cA5d64B63233875173a4", - "0xD9A157cCF1415970020d15a8B45A0212ABb9c074", - "0x478aC52c212d5e98EdF0e5877f50AfF38f1f647E", - "0xCe1Aa48E8e502D1444C54603D96E79ce273c1933", - "0x852B214aa1eB0C10Bbd900d4390efe03ea95152A", - "0x4690158f5e6086017eed0c2854a0fb4571ed4f0e", - "0x4d2D9F00B82cC646bc388b5e8B33A82d4E5ffA0A", - "0x3B04546eC9f04f375B40d3b753894De5cC16e41b", - "0xb18Eb611f4C7d51420462c926Ae2Cc0b5d362e7A", - "0xFE55121BD7dcFc20258AFFA7bad42Bba1585d808", - "0xd5FB8fccF9F35B1bb881ccee141EC5243F814B98", - "0xEe8547dEbc268863d2e22c63f2d705b4Fe08ae5a", - "0x270c7F012566b850Afd00b2B7B4be743CF7Cdb95", - "0x1be920ef263005d1ade89ee090782e80a2ec7a4f", - "0x42A832e64270948700B92C8Ecc1c977eEe82af41", - "0x07e319ccc91028981a9d2fC1F682251Dfd20dA8b", - "0x552DfAaFBD72747DcD56DfDa79663BD23292E0b7", - "0xA28F9fe27F2E2a39ca0DB31381234f35e420e98E", - "0x20c08e787835c2F0BC7F273EF22A46FF2fd69cB5", - "0x1723a88158118AD1AE03A873B2dF1e8DE4FB921e", - "0xBb46dEF4367111fCa4cdcCfb34CE48DFABbe5e51", - "0x373A2b98B1FD70C62EFc7f3b27272eCDBDfD856F", - "0x1823e8af312D8d14CdCEDa785BF721a5438D0Cd3", - "0x0e50f6bc9691BB5c56eA4775322b177b655805c0", - "0x7289c33b3640E9928256c2ce237452Cb3C30D84a", - "0xD8A5529690cDf546FDcF07D593947cE298d60C51", - "0x81e94bB131b184Dcb2CEdC4Ac95622058176290A", - "0xc6A4CE513dD749FB25C35E044F00646abD8F8969", - "0x38c7e9E4917B521E5e13CEaB4Ff39448Cc85d7f0", - "0x3444085881C71ec2FB9696946872767FC321BE9D", - "0xf600a01dAd6c73dB4886b136B71ac39cE32B0244", - "0x236eC68fbB8D07a9Da4f025191Ac87458A9d00C1", - "0x0d449d300AfC0C1D488C79CB9E34ecC3042761ad", - "0xbdDE00C6545B0C2d658961441d0Fe83d894841a7", - "0x2440C6B5dBE0093E71c8563D399521d056460985", - "0xCC5e733cB2E7a59EFC5463575EfC3584D5922486", - "0x5df7eb97138Eb47c7674F939571465c5f02f636A", - "0xc2A09707c32C5C37aA069Dd62D23f1F8F8d0e525", - "0x5c134E4f25c1c592377F7e37eC0cF399B5D05753", - "0x20272088DaBf3d35D60331bfb359635d0Dd1f10B", - "0x5E2f339eaDf2b2E66043afc5DbAca3266FaD5860", - "0xAcC5E71Bcb4a79439D3b5B1AEBa011Ea82270301", - "0x972ca578545356A17646cB4D9BF50F469497E4C2", - "0x6C6bb551C4cBbC7B530a6253Fe0B9CeB0ea77f9A", - "0xe93075Bd6B16a681F9959BAe42C050Cd36600F9B", - "0x3a92f10694f38f2bea6A3794c3bD06880572Dc1f", - "0x0Ba7a85Af6323686a1fE29423bd72c2ce81Fe923", - "0x08f342A971aBe964eb73701b2FF5422b5FDAF5C0", - "0xeB25C57E67BDe01f58ca5056e8A3aE16B2bDB8B7", - "0x400e2c3097Aa82c0Ac8f8F2Cc4FaEe3A10fF382c", - "0x9e762109CD97f8CAD5323e6d6E3b15640Aa4B778", - "0x411A4D3B06ad7cEDd6dbC423112fe5586e096e56", - "0x9d28ABd25Ce3b65E8F1EC9818a230acEB604Bc82", - "0xe83A996F597f5EFAe542F293A2B3dbDdab5E75C3", - "0xc6E0D2162eA3a8a040455Bd471e925F184f1b4da", - "0x5694baAEaCa2C419306c9Bf5dbfdAC7F92c7704c", - "0x2969a7A704354E56124Cc18c9CC4847B0Dc7EB16", - "0x1002155825193612e972920338cF7C7bFcC15625", - "0xEbE2a63d8C69B16E58F75B6f221b8ea16745383e", - "0x07d4b4d9a2cc58085651dc66dca774b2f38b979e", - "0xfe17147301888fBEEc36be3a8e6E4f883496ed33" - ], - "amounts": [ - 41, 22, 50, 100, 32, 120, 280, 164, 80, 25, 20, 226, 80, 20, 10, 30, 22, - 16, 18, 275, 264, 165, 10, 10, 25, 10, 130, 52, 21, 20, 20, 25, 100, 11, - 12, 11, 12, 140, 190, 210, 240, 9, 470, 346, 10, 620, 483, 20, 200, 120, - 100, 310, 50, 25, 25, 20, 15, 10, 10, 10, 10, 10, 100, 10, 30, 50, 10, - 50, 50, 100, 20, 10, 10, 120, 120, 120, 120, 640, 20, 10, 390, 677, 410, - 319, 399, 398, 380, 860, 100, 100, 100, 100, 100, 100, 100, 100, 206, - 207, 40, 12, 32, 2, 410, 1, 10, 9, 740, 40, 10, 610, 1840, 80, 2582 - ] - }, - { - "payoutStart": 1707393600, - "decreaseInterval": 86400, - "withdrawLockPeriod": 0, - "claimLockPeriod": 7776000, - "withdrawLockPeriodAfterStake": 0, - "initialReward": "3456000000000000000000", - "rewardDecrease": "592558728240000000", - "minimalStake": "0", - "isPublic": false, - "whitelistedUsers": ["0x1FE04BC15Cf2c5A2d41a0b3a96725596676eBa1E"], - "amounts": ["1"] - }, - { - "payoutStart": 1707393600, - "decreaseInterval": 86400, - "withdrawLockPeriod": 0, - "claimLockPeriod": 7776000, - "withdrawLockPeriodAfterStake": 0, - "initialReward": "3456000000000000000000", - "rewardDecrease": "592558728240000000", - "minimalStake": "0", - "isPublic": false, - "whitelistedUsers": ["0x1FE04BC15Cf2c5A2d41a0b3a96725596676eBa1E"], - "amounts": ["1"] - }, - { - "payoutStart": 1707393600, - "decreaseInterval": 86400, - "withdrawLockPeriod": 0, - "claimLockPeriod": 7603200, - "withdrawLockPeriodAfterStake": 0, - "initialReward": "576000000000000000000", - "rewardDecrease": "98759788040000000", - "minimalStake": "0", - "isPublic": false, - "whitelistedUsers": ["0x1FE04BC15Cf2c5A2d41a0b3a96725596676eBa1E"], - "amounts": ["1"] - } - ], - "L1": { - "stEth": "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84", - "wStEth": "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0" + "depositTokenExternalDeps": { + "token": "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84", + "wToken": "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0" }, - "L2": { - "swapRouter": "0xE592427A0AEce92De3Edee1F18E0157C05861564", - "nonfungiblePositionManager": "0xC36442b4a4522E871399CD717aBDD847Ab11FE88", - "wStEth": "0x5979D7b546E38E414F7E9822514be443A4800529" + "lzExternalDeps": { + "endpoint": "0x66A71Dcef29A0fFBDBE3c6a460a3B5BC225Cd675", + "zroPaymentAddress": "0x0000000000000000000000000000000000000000", + "adapterParams": "0x", + "destinationChainId": 110 }, - "swapParams": { - "fee": 3000, - "sqrtPriceLimitX96": 0 + "arbExternalDeps": { + "endpoint": "0x72Ce9c846789fdB6fC1f34aC4AD25Dd9ef7031ef" }, - "arbitrumConfig": { - "arbitrumBridgeGatewayRouter": "0x72Ce9c846789fdB6fC1f34aC4AD25Dd9ef7031ef" + "lzTokenExternalDeps": { + "endpoint": "0x3c2269811836af69497E5F486A85D7316753cf62", + "oftEndpoint": "0x1a44076050125825900e736c501f859c50fE728c", + "senderChainId": 101 }, - "lzConfig": { - "lzEndpointL1": "0x66A71Dcef29A0fFBDBE3c6a460a3B5BC225Cd675", - "lzEndpointL2": "0x3c2269811836af69497E5F486A85D7316753cf62" + "uniswapExternalDeps": { + "router": "0xE592427A0AEce92De3Edee1F18E0157C05861564", + "nonfungiblePositionManager": "0xC36442b4a4522E871399CD717aBDD847Ab11FE88" } } diff --git a/deploy/data/config_goerli.json b/deploy/data/config_goerli.json deleted file mode 100644 index 9891da6..0000000 --- a/deploy/data/config_goerli.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "cap": "1000000000000000000000000", - "chainsConfig": { - "senderChainId": 10121, - "receiverChainId": 10143 - }, - "pools": [ - { - "payoutStart": 1735925178, - "decreaseInterval": 86400, - "withdrawLockPeriod": 120, - "claimLockPeriod": 60, - "withdrawLockPeriodAfterStake": 30, - "initialReward": "14400000000000000000000", - "rewardDecrease": "2468994701000000000", - "minimalStake": "1000000000000000", - "isPublic": true - }, - { - "payoutStart": 1735925178, - "decreaseInterval": 60, - "withdrawLockPeriod": 1, - "claimLockPeriod": 1, - "withdrawLockPeriodAfterStake": 30, - "initialReward": "100000000000000000000", - "rewardDecrease": "100000000000000000000", - "minimalStake": "1000000000000000", - "isPublic": false, - "whitelistedUsers": [ - "0x901F2d23823730fb7F2356920e0E273EFdCdFe17", - "0x19ec1E4b714990620edf41fE28e9a1552953a7F4" - ], - "amounts": ["1", "1"] - } - ], - "L1": { - "stEth": "0x1643E812aE58766192Cf7D2Cf9567dF2C37e9B7F", - "wStEth": "0x6320cD32aA674d2898A68ec82e869385Fc5f7E2f" - }, - "L2": { - "swapRouter": "0xE592427A0AEce92De3Edee1F18E0157C05861564", - "nonfungiblePositionManager": "0xC36442b4a4522E871399CD717aBDD847Ab11FE88", - "wStEth": "0xbED18985eC648Ce4b0C5Fc3061d1323116702BC4" - }, - "swapParams": { - "fee": 10000, - "sqrtPriceLimitX96": 0 - }, - "arbitrumConfig": { - "arbitrumBridgeGatewayRouter": "0x0ecCFbBEe34f04187361818832385EB4cC11b678" - }, - "lzConfig": { - "lzEndpointL1": "0xbfD2135BFfbb0B5378b56643c2Df8a87552Bfa23", - "lzEndpointL2": "0x6aB5Ae6822647046626e83ee6dB8187151E1d5ab" - } -} diff --git a/deploy/data/config_localhost.json b/deploy/data/config_localhost.json index 4c965c2..7c210b8 100644 --- a/deploy/data/config_localhost.json +++ b/deploy/data/config_localhost.json @@ -1,40 +1,28 @@ { - "cap": "1000000000000000000000000", - "chainsConfig": { - "senderChainId": 10121, - "receiverChainId": 10143 + "feeConfig": { + "baseFee": "1000000000000000000000000", + "treasury": "0x901F2d23823730fb7F2356920e0E273EFdCdFe17" }, - "pools": [ - { - "payoutStart": 1765790236, - "decreaseInterval": 86400, - "withdrawLockPeriod": 120, - "claimLockPeriod": 60, - "withdrawLockPeriodAfterStake": 30, - "initialReward": "14400000000000000000000", - "rewardDecrease": "2468994701000000000", - "minimalStake": "1000000000000000", - "isPublic": true - }, - { - "payoutStart": 1765790236, - "decreaseInterval": 60, - "withdrawLockPeriod": 1, - "claimLockPeriod": 1, - "withdrawLockPeriodAfterStake": 30, - "initialReward": "100000000000000000000", - "rewardDecrease": "100000000000000000000", - "minimalStake": "1000000000000000", - "isPublic": false, - "whitelistedUsers": [ - "0x901F2d23823730fb7F2356920e0E273EFdCdFe17", - "0x19ec1E4b714990620edf41fE28e9a1552953a7F4" - ], - "amounts": ["1", "1"] - } - ], - "swapParams": { - "fee": 10000, - "sqrtPriceLimitX96": 0 + "depositTokenExternalDeps": { + "token": "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84", + "wToken": "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0" + }, + "lzExternalDeps": { + "endpoint": "0x66A71Dcef29A0fFBDBE3c6a460a3B5BC225Cd675", + "zroPaymentAddress": "0x0000000000000000000000000000000000000000", + "adapterParams": "0x", + "destinationChainId": 110 + }, + "arbExternalDeps": { + "endpoint": "0x72Ce9c846789fdB6fC1f34aC4AD25Dd9ef7031ef" + }, + "lzTokenExternalDeps": { + "endpoint": "0x3c2269811836af69497E5F486A85D7316753cf62", + "oftEndpoint": "0x1a44076050125825900e736c501f859c50fE728c", + "senderChainId": 101 + }, + "uniswapExternalDeps": { + "router": "0xE592427A0AEce92De3Edee1F18E0157C05861564", + "nonfungiblePositionManager": "0xC36442b4a4522E871399CD717aBDD847Ab11FE88" } } diff --git a/deploy/data/config_sepolia.json b/deploy/data/config_sepolia.json index e07087a..2213c06 100644 --- a/deploy/data/config_sepolia.json +++ b/deploy/data/config_sepolia.json @@ -1,56 +1,28 @@ { - "cap": "1000000000000000000000000", - "chainsConfig": { - "senderChainId": 10161, - "receiverChainId": 10231 + "feeConfig": { + "baseFee": "1000000000000000000000000", + "treasury": "0x901F2d23823730fb7F2356920e0E273EFdCdFe17" }, - "pools": [ - { - "payoutStart": 1704360948, - "decreaseInterval": 86400, - "withdrawLockPeriod": 120, - "claimLockPeriod": 60, - "withdrawLockPeriodAfterStake": 30, - "initialReward": "14400000000000000000000", - "rewardDecrease": "2468994701000000000", - "minimalStake": "10000000000", - "isPublic": true - }, - { - "payoutStart": 1704360948, - "decreaseInterval": 60, - "withdrawLockPeriod": 1, - "claimLockPeriod": 1, - "withdrawLockPeriodAfterStake": 30, - "initialReward": "100000000000000000000", - "rewardDecrease": "100000000000000000000", - "minimalStake": "10000000000", - "isPublic": false, - "whitelistedUsers": [ - "0x901F2d23823730fb7F2356920e0E273EFdCdFe17", - "0x19ec1E4b714990620edf41fE28e9a1552953a7F4" - ], - "amounts": ["1", "1"] - } - ], - "L1": { - "stEth": "0xe6D01D086a844a61641C75f1BCA572e7aa70e154", - "wStEth": "0xE7d86F503F3dA0DEF5660420F667BF873d3D6A8f" + "depositTokenExternalDeps": { + "token": "0xe6D01D086a844a61641C75f1BCA572e7aa70e154", + "wToken": "0xE7d86F503F3dA0DEF5660420F667BF873d3D6A8f" }, - "L2": { - "swapRouter": "0xE592427A0AEce92De3Edee1F18E0157C05861564", - "nonfungiblePositionManager": "0xC36442b4a4522E871399CD717aBDD847Ab11FE88", - "wStEth": "0xfD5d8Dc9918e04673b9F5F332cE63BcC3BE427a2" + "lzExternalDeps": { + "endpoint": "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1", + "zroPaymentAddress": "0x0000000000000000000000000000000000000000", + "adapterParams": "0x", + "destinationChainId": 10231 }, - "swapParams": { - "fee": 10000, - "sqrtPriceLimitX96": 0 + "arbExternalDeps": { + "endpoint": "0xcE18836b233C83325Cc8848CA4487e94C6288264" }, - "arbitrumConfig": { - "arbitrumBridgeGatewayRouter": "0xcE18836b233C83325Cc8848CA4487e94C6288264" + "lzTokenExternalDeps": { + "endpoint": "0x6098e96a28E02f27B1e6BD381f870F1C8Bd169d3", + "oftEndpoint": "0x6EDCE65403992e310A62460808c4b910D972f10f", + "senderChainId": 10161 }, - "lzConfig": { - "lzEndpointL1": "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1", - "lzEndpointL2": "0x6098e96a28E02f27B1e6BD381f870F1C8Bd169d3" + "uniswapExternalDeps": { + "router": "0xE592427A0AEce92De3Edee1F18E0157C05861564", + "nonfungiblePositionManager": "0xC36442b4a4522E871399CD717aBDD847Ab11FE88" } } diff --git a/deploy/deploy-all.sh b/deploy/deploy-all.sh deleted file mode 100755 index 15372bc..0000000 --- a/deploy/deploy-all.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -set -e - -verifyL1=$([ '$1' = 'localhost' ] && echo --verify || echo '') -verifyL2=$([ '$2' = 'localhost' ] && echo --verify || echo '') - -npx hardhat migrate --network $2 --only 1 $verifyL2 $3 -npx hardhat migrate --network $1 --only 2 $verifyL1 --continue -npx hardhat migrate --network $2 --only 3 $verifyL2 --continue diff --git a/deploy/helpers/config-parser.ts b/deploy/helpers/config-parser.ts index a12adfc..bf16007 100644 --- a/deploy/helpers/config-parser.ts +++ b/deploy/helpers/config-parser.ts @@ -1,41 +1,24 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import { BigNumberish } from 'ethers'; import { readFileSync } from 'fs'; -import { IDistribution } from '@/generated-types/ethers'; +import { IL1Factory, IL2Factory } from '@/generated-types/ethers'; import { ZERO_ADDR } from '@/scripts/utils/constants'; -export type Config = { - cap: number; - chainsConfig: { - senderChainId: number; - receiverChainId: number; - }; - pools?: PoolInitInfo[]; - L1?: { - stEth: string; - wStEth: string; - }; - L2?: { - swapRouter: string; - nonfungiblePositionManager: string; - wStEth: string; - }; - swapParams: { - fee: string; - sqrtPriceLimitX96: string; - }; - arbitrumConfig?: { - arbitrumBridgeGatewayRouter: string; - }; - lzConfig?: { - lzEndpointL1: string; - lzEndpointL2: string; - }; +type FeeConfig = { + baseFee: BigNumberish; + treasury: string; }; -type PoolInitInfo = IDistribution.PoolStruct & { - whitelistedUsers: string[]; - amounts: BigNumberish[]; +export type Config = { + feeConfig: FeeConfig; + + depositTokenExternalDeps: IL1Factory.DepositTokenExternalDepsStruct; + lzExternalDeps: IL1Factory.LzExternalDepsStruct; + arbExternalDeps: IL1Factory.ArbExternalDepsStruct; + + lzTokenExternalDeps: IL2Factory.LzExternalDepsStruct; + uniswapExternalDeps: IL2Factory.UniswapExternalDepsStruct; }; export function parseConfig(chainId: bigint): Config { @@ -57,130 +40,96 @@ export function parseConfig(chainId: bigint): Config { const config: Config = JSON.parse(readFileSync(configPath, 'utf-8')) as Config; - if (config.cap == undefined) { - throw new Error(`Invalid 'cap' value.`); - } + validateFeeConfig(config.feeConfig); - if (config.chainsConfig == undefined) { - throw new Error(`Invalid 'chainsConfig' value.`); - } - if (config.chainsConfig.receiverChainId == undefined) { - throw new Error(`Invalid 'chainsConfig.receiverChainId' value.`); - } - if (config.chainsConfig.senderChainId == undefined) { - throw new Error(`Invalid 'chainsConfig.senderChainId' value.`); - } + validateDepositTokenExternalDeps(config.depositTokenExternalDeps); + validateLzExternalDeps(config.lzExternalDeps); + validateArbExternalDeps(config.arbExternalDeps); - if (config.pools != undefined) { - validatePools(config.pools); - } + validateLzTokenExternalDeps(config.lzTokenExternalDeps); + validateUniswapExternalDeps(config.uniswapExternalDeps); + + return config; +} - if (config.L1 != undefined) { - if (config.L1.stEth == undefined) { - nonZeroAddr(config.L1.stEth, 'L1.stEth'); - } +function nonNumber(value: BigNumberish) { + return !(typeof value === 'number' || typeof value === 'bigint' || typeof BigInt(value) === 'bigint'); +} - if (config.L1.wStEth == undefined) { - nonZeroAddr(config.L1.wStEth, 'L1.wStEth'); - } +function nonZeroAddr(filedDataRaw: any, filedName: string) { + if (isZeroAddr(filedDataRaw)) { + throw new Error(`Invalid ${filedName} filed.`); } +} - if (config.L2 != undefined) { - if (config.L2.swapRouter == undefined) { - nonZeroAddr(config.L2.swapRouter, 'L2.swapRouter'); - } +function isZeroAddr(filedDataRaw: string | undefined) { + return isEmptyField(filedDataRaw) || filedDataRaw === ZERO_ADDR; +} - if (config.L2.nonfungiblePositionManager == undefined) { - nonZeroAddr(config.L2.nonfungiblePositionManager, 'L2.nonfungiblePositionManager'); - } +function isEmptyField(filedDataRaw: any) { + return !filedDataRaw || filedDataRaw == ''; +} - if (config.L2.wStEth == undefined) { - nonZeroAddr(config.L2.wStEth, 'L2.wStEth'); - } +function validateFeeConfig(feeConfig: FeeConfig) { + if (feeConfig === undefined) { + throw new Error(`Invalid feeConfig.`); } - - if ( - config.swapParams == undefined || - nonNumber(config.swapParams.fee) || - nonNumber(config.swapParams.sqrtPriceLimitX96) - ) { - throw new Error('Invalid `swapParams`'); + if (nonNumber(feeConfig.baseFee)) { + throw new Error(`Invalid feeConfig.baseFee.`); } + nonZeroAddr(feeConfig.treasury, 'feeConfig.treasury'); +} - if (config.lzConfig != undefined) { - if (config.lzConfig.lzEndpointL1 == undefined) { - throw new Error('Invalid `lzConfig.lzEndpointL1`'); - } - if (config.lzConfig.lzEndpointL2 == undefined) { - throw new Error('Invalid `lzConfig.lzEndpointL2`'); - } +function validateDepositTokenExternalDeps(depositTokenExternalDeps: IL1Factory.DepositTokenExternalDepsStruct) { + if (depositTokenExternalDeps === undefined) { + throw new Error(`Invalid depositTokenExternalDeps.`); } + nonZeroAddr(depositTokenExternalDeps.token, 'depositTokenExternalDeps.token'); + nonZeroAddr(depositTokenExternalDeps.wToken, 'depositTokenExternalDeps.wToken'); +} - if (config.arbitrumConfig != undefined) { - if (config.arbitrumConfig.arbitrumBridgeGatewayRouter == undefined) { - throw new Error('Invalid `arbitrumConfig.arbitrumBridgeGatewayRouter`'); - } +function validateLzExternalDeps(lzExternalDeps: IL1Factory.LzExternalDepsStruct) { + if (lzExternalDeps === undefined) { + throw new Error(`Invalid lzExternalDeps.`); } - return config; -} + nonZeroAddr(lzExternalDeps.endpoint, 'lzExternalDeps.endpoint'); -function nonNumber(value: BigNumberish) { - return !(typeof value === 'number' || typeof value === 'bigint' || typeof BigInt(value) === 'bigint'); + if (isEmptyField(lzExternalDeps.zroPaymentAddress)) { + throw new Error(`Invalid lzExternalDeps.zroPaymentAddress.`); + } + if (isEmptyField(lzExternalDeps.adapterParams)) { + throw new Error(`Invalid lzExternalDeps.adapterParams.`); + } + if (nonNumber(lzExternalDeps.destinationChainId)) { + throw new Error(`Invalid lzExternalDeps.destinationChainId.`); + } } -function nonZeroAddr(filedDataRaw: string | undefined, filedName: string) { - if (isZeroAddr(filedDataRaw)) { - throw new Error(`Invalid ${filedName} filed.`); +function validateArbExternalDeps(arbExternalDeps: IL1Factory.ArbExternalDepsStruct) { + if (arbExternalDeps === undefined) { + throw new Error(`Invalid arbExternalDeps.`); } + nonZeroAddr(arbExternalDeps.endpoint, 'arbExternalDeps.endpoint'); } -function isZeroAddr(filedDataRaw: string | undefined) { - return isEmptyField(filedDataRaw) || filedDataRaw === ZERO_ADDR; -} +function validateLzTokenExternalDeps(lzTokenExternalDeps: IL2Factory.LzExternalDepsStruct) { + if (lzTokenExternalDeps === undefined) { + throw new Error(`Invalid lzTokenExternalDeps.`); + } -function isEmptyField(filedDataRaw: string | undefined) { - return !filedDataRaw || filedDataRaw == ''; + nonZeroAddr(lzTokenExternalDeps.endpoint, 'lzTokenExternalDeps.endpoint'); + nonZeroAddr(lzTokenExternalDeps.oftEndpoint, 'lzTokenExternalDeps.oftEndpoint'); + if (nonNumber(lzTokenExternalDeps.senderChainId)) { + throw new Error(`Invalid lzTokenExternalDeps.senderChainId.`); + } } -function validatePools(pools: PoolInitInfo[]) { - pools.forEach((pool: PoolInitInfo) => { - if ( - nonNumber(pool.payoutStart) || - nonNumber(pool.decreaseInterval) || - nonNumber(pool.withdrawLockPeriod) || - nonNumber(pool.claimLockPeriod) || - typeof pool.isPublic !== 'boolean' || - nonNumber(pool.initialReward) || - nonNumber(pool.rewardDecrease) || - nonNumber(pool.minimalStake) - ) { - throw new Error(`Invalid pool.`); - } - - if (pool.whitelistedUsers != undefined) { - if (pool.amounts == undefined || pool.amounts.length != pool.whitelistedUsers.length) { - throw new Error(`Invalid pool amounts.`); - } - - if (pool.isPublic) { - if ((pool.whitelistedUsers && pool.whitelistedUsers.length > 0) || (pool.amounts && pool.amounts.length > 0)) { - throw new Error(`Invalid pool whitelistedUsers.`); - } - } else { - pool.whitelistedUsers.forEach((user: string) => { - nonZeroAddr(user, 'whitelistedUsers'); - }); - pool.amounts.forEach((amount: BigNumberish) => { - if (nonNumber(amount)) { - throw new Error(`Invalid pool amounts.`); - } - }); - } - } else { - if (pool.amounts != undefined) { - throw new Error(`Invalid pool amounts.`); - } - } - }); +function validateUniswapExternalDeps(uniswapExternalDeps: IL2Factory.UniswapExternalDepsStruct) { + if (uniswapExternalDeps === undefined) { + throw new Error(`Invalid uniswapExternalDeps.`); + } + + nonZeroAddr(uniswapExternalDeps.router, 'uniswapExternalDeps.router'); + nonZeroAddr(uniswapExternalDeps.nonfungiblePositionManager, 'uniswapExternalDeps.nonfungiblePositionManager'); } From f624e3e31da476ee09c0a917c3add2efa972b89d Mon Sep 17 00:00:00 2001 From: Ruslan Kasheparov Date: Tue, 14 May 2024 21:29:48 +0200 Subject: [PATCH 13/17] changed swap params --- contracts/L2/L2Factory.sol | 7 +------ contracts/L2/L2TokenReceiver.sol | 3 ++- contracts/interfaces/L2/IL2Factory.sol | 2 -- contracts/interfaces/L2/IL2TokenReceiver.sol | 4 ++-- test/Integration.test.ts | 2 -- test/L1/Distribution.test.ts | 2 -- test/L2/L2Factory.test.ts | 4 ---- test/L2/L2TokenReceiver.test.ts | 14 ++------------ test/fork/L2TokenReceiver.fork.test.ts | 13 ++++++------- test/helpers/distribution-helper.ts | 1 - 10 files changed, 13 insertions(+), 39 deletions(-) diff --git a/contracts/L2/L2Factory.sol b/contracts/L2/L2Factory.sol index 878ed8a..a600c71 100644 --- a/contracts/L2/L2Factory.sol +++ b/contracts/L2/L2Factory.sol @@ -62,12 +62,7 @@ contract L2Factory is IL2Factory, Factory { uniswapExternalDeps.router, uniswapExternalDeps.nonfungiblePositionManager, l2Params_.firstSwapParams_, - IL2TokenReceiver.SwapParams( - l2Params_.firstSwapParams_.tokenOut, - mor20, - l2Params_.secondSwapFee, - l2Params_.secondSwapSqrtPriceLimitX96 - ) + IL2TokenReceiver.SwapParams(l2Params_.firstSwapParams_.tokenOut, mor20, l2Params_.secondSwapFee) ); IOwnable(l2MessageReceiver).transferOwnership(_msgSender()); diff --git a/contracts/L2/L2TokenReceiver.sol b/contracts/L2/L2TokenReceiver.sol index b28a1bc..96a4bb1 100644 --- a/contracts/L2/L2TokenReceiver.sol +++ b/contracts/L2/L2TokenReceiver.sol @@ -72,6 +72,7 @@ contract L2TokenReceiver is IL2TokenReceiver, OwnableUpgradeable, UUPSUpgradeabl uint256 amountIn_, uint256 amountOutMinimum_, uint256 deadline_, + uint160 sqrtPriceLimitX96_, bool isUseFirstSwapParams_ ) external onlyOwner returns (uint256) { SwapParams memory params_ = _getSwapParams(isUseFirstSwapParams_); @@ -84,7 +85,7 @@ contract L2TokenReceiver is IL2TokenReceiver, OwnableUpgradeable, UUPSUpgradeabl deadline: deadline_, amountIn: amountIn_, amountOutMinimum: amountOutMinimum_, - sqrtPriceLimitX96: params_.sqrtPriceLimitX96 + sqrtPriceLimitX96: sqrtPriceLimitX96_ }); uint256 amountOut_ = ISwapRouter(router).exactInputSingle(swapParams_); diff --git a/contracts/interfaces/L2/IL2Factory.sol b/contracts/interfaces/L2/IL2Factory.sol index 4d6e8d5..df40cfd 100644 --- a/contracts/interfaces/L2/IL2Factory.sol +++ b/contracts/interfaces/L2/IL2Factory.sol @@ -22,7 +22,6 @@ interface IL2Factory { * @param l1Sender The L1 sender address. * @param firstSwapParams_ The first swap parameters. * @param secondSwapFee The second swap fee. - * @param secondSwapSqrtPriceLimitX96 The second swap square root price limit. */ struct L2Params { string protocolName; @@ -31,7 +30,6 @@ interface IL2Factory { address l1Sender; IL2TokenReceiver.SwapParams firstSwapParams_; uint24 secondSwapFee; - uint160 secondSwapSqrtPriceLimitX96; } /** diff --git a/contracts/interfaces/L2/IL2TokenReceiver.sol b/contracts/interfaces/L2/IL2TokenReceiver.sol index 8aea131..f55a99d 100644 --- a/contracts/interfaces/L2/IL2TokenReceiver.sol +++ b/contracts/interfaces/L2/IL2TokenReceiver.sol @@ -13,13 +13,11 @@ interface IL2TokenReceiver is IERC165, IERC721Receiver { * @param tokenIn The address of the token to swap from. * @param tokenOut The address of the token to swap to. * @param fee The fee of the swap. - * @param sqrtPriceLimitX96 The price limit of the swap. */ struct SwapParams { address tokenIn; address tokenOut; uint24 fee; - uint160 sqrtPriceLimitX96; } /** @@ -108,6 +106,7 @@ interface IL2TokenReceiver is IERC165, IERC721Receiver { * @param amountIn_ The amount of tokens to swap. * @param amountOutMinimum_ The minimum amount of tokens to receive. * @param deadline_ The deadline for the swap. + * @param sqrtPriceLimitX96_ The price limit of the swap. * @param isUseFirstSwapParams_ The flag to indicate if the swapParams is initial. * @return The amount of tokens received. */ @@ -115,6 +114,7 @@ interface IL2TokenReceiver is IERC165, IERC721Receiver { uint256 amountIn_, uint256 amountOutMinimum_, uint256 deadline_, + uint160 sqrtPriceLimitX96_, bool isUseFirstSwapParams_ ) external returns (uint256); diff --git a/test/Integration.test.ts b/test/Integration.test.ts index b8a53cf..2305922 100644 --- a/test/Integration.test.ts +++ b/test/Integration.test.ts @@ -229,10 +229,8 @@ describe('Integration', () => { tokenIn: l2WstEth, tokenOut: l2Weth, fee: 100, - sqrtPriceLimitX96: 0, }, secondSwapFee: 3000, - secondSwapSqrtPriceLimitX96: 0, }; await l1Factory.deploy(l1Params); diff --git a/test/L1/Distribution.test.ts b/test/L1/Distribution.test.ts index 4cfc2b5..a612186 100644 --- a/test/L1/Distribution.test.ts +++ b/test/L1/Distribution.test.ts @@ -155,13 +155,11 @@ describe('Distribution', () => { tokenIn: depositToken, tokenOut: depositToken, fee: 3000, - sqrtPriceLimitX96: 0, }, { tokenIn: depositToken, tokenOut: depositToken, fee: 3000, - sqrtPriceLimitX96: 0, }, ); diff --git a/test/L2/L2Factory.test.ts b/test/L2/L2Factory.test.ts index f48bde2..3d34329 100644 --- a/test/L2/L2Factory.test.ts +++ b/test/L2/L2Factory.test.ts @@ -136,10 +136,8 @@ describe('L2Factory', () => { tokenIn: ETHER_ADDR, tokenOut: ETHER_ADDR, fee: 100, - sqrtPriceLimitX96: 0, }, secondSwapFee: 3000, - secondSwapSqrtPriceLimitX96: 0, }; return l2Params; @@ -281,13 +279,11 @@ describe('L2Factory', () => { expect(firstSwapParams.tokenIn).to.equal(l2Params.firstSwapParams_.tokenIn); expect(firstSwapParams.tokenOut).to.equal(l2Params.firstSwapParams_.tokenOut); expect(firstSwapParams.fee).to.equal(l2Params.firstSwapParams_.fee); - expect(firstSwapParams.sqrtPriceLimitX96).to.equal(l2Params.firstSwapParams_.sqrtPriceLimitX96); const secondSwapParams = await l2TokenReceiver.secondSwapParams(); expect(secondSwapParams.tokenIn).to.equal(l2Params.firstSwapParams_.tokenOut); expect(secondSwapParams.tokenOut).to.equal(MOR); expect(secondSwapParams.fee).to.equal(l2Params.secondSwapFee); - expect(secondSwapParams.sqrtPriceLimitX96).to.equal(l2Params.secondSwapSqrtPriceLimitX96); expect(await MOR.owner()).to.equal(OWNER); expect(await MOR.name()).to.equal(l2Params.mor20Name); diff --git a/test/L2/L2TokenReceiver.test.ts b/test/L2/L2TokenReceiver.test.ts index 4fbbfa2..d7391cd 100644 --- a/test/L2/L2TokenReceiver.test.ts +++ b/test/L2/L2TokenReceiver.test.ts @@ -75,13 +75,11 @@ describe('L2TokenReceiver', () => { tokenIn: inputToken, tokenOut: outputToken, fee: 500, - sqrtPriceLimitX96: 0, }, { tokenIn: inputToken, tokenOut: outputToken, fee: 500, - sqrtPriceLimitX96: 0, }, ); @@ -106,13 +104,11 @@ describe('L2TokenReceiver', () => { tokenIn: inputToken, tokenOut: outputToken, fee: 500, - sqrtPriceLimitX96: 0, }, { tokenIn: inputToken, tokenOut: outputToken, fee: 500, - sqrtPriceLimitX96: 0, }, ), ).to.be.rejectedWith(reason); @@ -130,13 +126,11 @@ describe('L2TokenReceiver', () => { tokenIn: inputToken, tokenOut: outputToken, fee: 500, - sqrtPriceLimitX96: 0, }, { tokenIn: inputToken, tokenOut: outputToken, fee: 500, - sqrtPriceLimitX96: 0, }, ), ).to.be.rejectedWith(reason); @@ -151,7 +145,6 @@ describe('L2TokenReceiver', () => { expect(params.tokenIn).to.equal(defaultParams.tokenIn); expect(params.tokenOut).to.equal(defaultParams.tokenOut); expect(params.fee).to.equal(defaultParams.fee); - expect(params.sqrtPriceLimitX96).to.equal(defaultParams.sqrtPriceLimitX96); }); it('should give allowance', async () => { expect(await inputToken.allowance(l2TokenReceiver, swapRouter)).to.equal(ethers.MaxUint256); @@ -181,7 +174,7 @@ describe('L2TokenReceiver', () => { describe('supportsInterface', () => { it('should support IL2TokenReceiver', async () => { - expect(await l2TokenReceiver.supportsInterface('0x710a2868')).to.be.true; + expect(await l2TokenReceiver.supportsInterface('0xe15df538')).to.be.true; }); it('should support IERC165', async () => { expect(await l2TokenReceiver.supportsInterface('0x01ffc9a7')).to.be.true; @@ -197,7 +190,6 @@ describe('L2TokenReceiver', () => { tokenIn: await outputToken.getAddress(), tokenOut: await inputToken.getAddress(), fee: 1, - sqrtPriceLimitX96: 1, }; await l2TokenReceiver.editParams(newParams, false); @@ -207,14 +199,12 @@ describe('L2TokenReceiver', () => { expect(params.tokenIn).to.equal(newParams.tokenIn); expect(params.tokenOut).to.equal(newParams.tokenOut); expect(params.fee).to.equal(newParams.fee); - expect(params.sqrtPriceLimitX96).to.equal(newParams.sqrtPriceLimitX96); }); it('should set new allowance', async () => { const newParams: IL2TokenReceiver.SwapParamsStruct = { tokenIn: await outputToken.getAddress(), tokenOut: await inputToken.getAddress(), fee: 1, - sqrtPriceLimitX96: 1, }; await l2TokenReceiver.editParams(newParams, false); @@ -243,7 +233,7 @@ describe('L2TokenReceiver', () => { describe('#swap', () => { it('should return if caller is not the owner', async () => { - await expect(l2TokenReceiver.connect(SECOND).swap(1, 1, 1, false)).to.be.revertedWith( + await expect(l2TokenReceiver.connect(SECOND).swap(1, 1, 1, 0, false)).to.be.revertedWith( 'Ownable: caller is not the owner', ); }); diff --git a/test/fork/L2TokenReceiver.fork.test.ts b/test/fork/L2TokenReceiver.fork.test.ts index 57442fd..96ec7a6 100644 --- a/test/fork/L2TokenReceiver.fork.test.ts +++ b/test/fork/L2TokenReceiver.fork.test.ts @@ -143,15 +143,15 @@ describe('L2TokenReceiver Fork', () => { }); it('should swap tokens 1', async () => { - const txResult = await l2TokenReceiver.swap.staticCall(amount, 0, (await getCurrentBlockTime()) + 100, true); - const tx = await l2TokenReceiver.swap(amount, 0, (await getCurrentBlockTime()) + 100, true); + const txResult = await l2TokenReceiver.swap.staticCall(amount, 0, (await getCurrentBlockTime()) + 100, 0, true); + const tx = await l2TokenReceiver.swap(amount, 0, (await getCurrentBlockTime()) + 100, 0, true); await expect(tx).to.changeTokenBalance(innerToken, l2TokenReceiver, txResult); await expect(tx).to.changeTokenBalance(inputToken, l2TokenReceiver, -amount); }); it('should swap tokens 2', async () => { - const txResult = await l2TokenReceiver.swap.staticCall(amount, 0, (await getCurrentBlockTime()) + 100, false); - const tx = await l2TokenReceiver.swap(amount, 0, (await getCurrentBlockTime()) + 100, false); + const txResult = await l2TokenReceiver.swap.staticCall(amount, 0, (await getCurrentBlockTime()) + 100, 0, false); + const tx = await l2TokenReceiver.swap(amount, 0, (await getCurrentBlockTime()) + 100, 0, false); await expect(tx).to.changeTokenBalance(outputToken, l2TokenReceiver, txResult); await expect(tx).to.changeTokenBalance(innerToken, l2TokenReceiver, -amount); @@ -186,7 +186,6 @@ describe('L2TokenReceiver Fork', () => { tokenIn: await outputToken.getAddress(), tokenOut: await innerToken.getAddress(), fee: 1, - sqrtPriceLimitX96: 1, }; await l2TokenReceiver.editParams(newParams, false); @@ -209,7 +208,7 @@ describe('L2TokenReceiver Fork', () => { beforeEach('setup', async () => { await innerToken.transfer(l2TokenReceiver, wei(0.001)); - await l2TokenReceiver.swap(wei(0.0001), 0, (await getCurrentBlockTime()) + 100, false); + await l2TokenReceiver.swap(wei(0.0001), 0, (await getCurrentBlockTime()) + 100, 0, false); }); it('should collect fees', async () => { @@ -255,7 +254,7 @@ describe('L2TokenReceiver Fork', () => { it('should collect fees', async () => { await innerToken.transfer(l2TokenReceiver, wei(0.001)); - await l2TokenReceiver.swap(wei(0.0001), 0, (await getCurrentBlockTime()) + 100, false); + await l2TokenReceiver.swap(wei(0.0001), 0, (await getCurrentBlockTime()) + 100, 0, false); const liquidity = (await nonfungiblePositionManager.positions(poolId)).liquidity; diff --git a/test/helpers/distribution-helper.ts b/test/helpers/distribution-helper.ts index aa997b4..0833d14 100644 --- a/test/helpers/distribution-helper.ts +++ b/test/helpers/distribution-helper.ts @@ -23,6 +23,5 @@ export const getDefaultSwapParams = (tokenIn: string, tokenOut: string): IL2Toke tokenIn: tokenIn, tokenOut: tokenOut, fee: 500, - sqrtPriceLimitX96: 0, }; }; From d829693f4b2113a3842bdc52b59d4903de1cb639 Mon Sep 17 00:00:00 2001 From: Ruslan Kasheparov Date: Tue, 14 May 2024 22:09:40 +0200 Subject: [PATCH 14/17] changed package-lock.json --- package-lock.json | 545 ++++++++++++++++++++++++---------------------- 1 file changed, 285 insertions(+), 260 deletions(-) diff --git a/package-lock.json b/package-lock.json index 98b6049..cb1b7de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -61,15 +61,6 @@ "web3": "^1.7.5" } }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@adraffy/ens-normalize": { "version": "1.10.1", "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", @@ -343,15 +334,15 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@aws-sdk/types": { - "version": "3.535.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.535.0.tgz", - "integrity": "sha512-aY4MYfduNj+sRR37U7XxYR8wemfbKP6lx00ze2M2uubn7mZotuVrWYAafbMSXrdEMSToE5JDhr28vArSOoLcSg==", + "version": "3.575.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.575.0.tgz", + "integrity": "sha512-XrnolQGs0wXxdgNudirR14OgNOarH7WUif38+2Pd4onZH+L7XoILem0EgA1tRpgFpw2pFHlZCNaAHDNSBEal7g==", "dependencies": { - "@smithy/types": "^2.12.0", + "@smithy/types": "^3.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, "node_modules/@aws-sdk/types/node_modules/tslib": { @@ -417,13 +408,13 @@ } }, "node_modules/@babel/helper-function-name/node_modules/@babel/types": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", - "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz", + "integrity": "sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.24.1", + "@babel/helper-validator-identifier": "^7.24.5", "to-fast-properties": "^2.0.0" }, "engines": { @@ -443,13 +434,13 @@ } }, "node_modules/@babel/helper-hoist-variables/node_modules/@babel/types": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", - "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz", + "integrity": "sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.24.1", + "@babel/helper-validator-identifier": "^7.24.5", "to-fast-properties": "^2.0.0" }, "engines": { @@ -457,25 +448,25 @@ } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz", + "integrity": "sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration/node_modules/@babel/types": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", - "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz", + "integrity": "sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.24.1", + "@babel/helper-validator-identifier": "^7.24.5", "to-fast-properties": "^2.0.0" }, "engines": { @@ -492,21 +483,21 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", + "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", - "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", + "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.5", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -516,9 +507,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", - "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz", + "integrity": "sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -528,9 +519,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz", - "integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz", + "integrity": "sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==", "dev": true, "dependencies": { "regenerator-runtime": "^0.14.0" @@ -554,13 +545,13 @@ } }, "node_modules/@babel/template/node_modules/@babel/types": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", - "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz", + "integrity": "sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.24.1", + "@babel/helper-validator-identifier": "^7.24.5", "to-fast-properties": "^2.0.0" }, "engines": { @@ -589,12 +580,12 @@ } }, "node_modules/@babel/traverse/node_modules/@babel/generator": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", - "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.5.tgz", + "integrity": "sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==", "dev": true, "dependencies": { - "@babel/types": "^7.24.0", + "@babel/types": "^7.24.5", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" @@ -604,13 +595,13 @@ } }, "node_modules/@babel/traverse/node_modules/@babel/types": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", - "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz", + "integrity": "sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.24.1", + "@babel/helper-validator-identifier": "^7.24.5", "to-fast-properties": "^2.0.0" }, "engines": { @@ -1990,9 +1981,9 @@ } }, "node_modules/@layerzerolabs/lz-evm-protocol-v2": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/@layerzerolabs/lz-evm-protocol-v2/-/lz-evm-protocol-v2-2.1.27.tgz", - "integrity": "sha512-kJlPYILW/VLxeeWagFYJpP/4EFeCw7Yuqp+qpv/+lnGDSXflvanGVnCApBJtEmirMva4E0nEkTFd0x9rfu/1Dg==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/@layerzerolabs/lz-evm-protocol-v2/-/lz-evm-protocol-v2-2.3.7.tgz", + "integrity": "sha512-Nhe6XIqJNXT22yBcNxwigQAEFesUc3vYZircDmncWhD6iWvsJiul36B1sfON+8mMR2zjXKBXMk+Z8eGdSCdmKg==", "peerDependencies": { "@openzeppelin/contracts": "^4.8.1 || ^5.0.0", "@openzeppelin/contracts-upgradeable": "^4.8.1 || ^5.0.0", @@ -2450,17 +2441,17 @@ } }, "node_modules/@metamask/eth-sig-util": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-7.0.1.tgz", - "integrity": "sha512-59GSrMyFH2fPfu7nKeIQdZ150zxXNNhAQIUaFRUW+MGtVA4w/ONbiQobcRBLi+jQProfIyss51G8pfLPcQ0ylg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-7.0.2.tgz", + "integrity": "sha512-DhTDMNEtED0ihIc4Tysm6qUJTvArCdgSTeeJWdo526W/cAk5mrSAvEYYgv8idAiBumDtcPWGimMTaB7MvY64bg==", "dev": true, "dependencies": { "@ethereumjs/util": "^8.1.0", "@metamask/abi-utils": "^2.0.2", "@metamask/utils": "^8.1.0", + "@scure/base": "~1.1.3", "ethereum-cryptography": "^2.1.2", - "tweetnacl": "^1.0.3", - "tweetnacl-util": "^0.15.1" + "tweetnacl": "^1.0.3" }, "engines": { "node": "^16.20 || ^18.16 || >=20" @@ -2569,28 +2560,26 @@ } }, "node_modules/@nomicfoundation/edr": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.3.3.tgz", - "integrity": "sha512-zP+e+3B1nEUx6bW5BPnIzCQbkhmYfdMBJdiVggTqqTfAA82sOkdOG7wsOMcz5qF3fYfx/irNRM1kgc9HVFIbpQ==", + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.3.7.tgz", + "integrity": "sha512-v2JFWnFKRsnOa6PDUrD+sr8amcdhxnG/YbL7LzmgRGU1odWEyOF4/EwNeUajQr4ZNKVWrYnJ6XjydXtUge5OBQ==", "engines": { "node": ">= 18" }, "optionalDependencies": { - "@nomicfoundation/edr-darwin-arm64": "0.3.3", - "@nomicfoundation/edr-darwin-x64": "0.3.3", - "@nomicfoundation/edr-linux-arm64-gnu": "0.3.3", - "@nomicfoundation/edr-linux-arm64-musl": "0.3.3", - "@nomicfoundation/edr-linux-x64-gnu": "0.3.3", - "@nomicfoundation/edr-linux-x64-musl": "0.3.3", - "@nomicfoundation/edr-win32-arm64-msvc": "0.3.3", - "@nomicfoundation/edr-win32-ia32-msvc": "0.3.3", - "@nomicfoundation/edr-win32-x64-msvc": "0.3.3" + "@nomicfoundation/edr-darwin-arm64": "0.3.7", + "@nomicfoundation/edr-darwin-x64": "0.3.7", + "@nomicfoundation/edr-linux-arm64-gnu": "0.3.7", + "@nomicfoundation/edr-linux-arm64-musl": "0.3.7", + "@nomicfoundation/edr-linux-x64-gnu": "0.3.7", + "@nomicfoundation/edr-linux-x64-musl": "0.3.7", + "@nomicfoundation/edr-win32-x64-msvc": "0.3.7" } }, "node_modules/@nomicfoundation/edr-darwin-arm64": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.3.3.tgz", - "integrity": "sha512-E9VGsUD+1Ga4mn/5ooHsMi8JEfhZbKP6CXN/BhJ8kXbIC10NqTD1RuhCKGRtYq4vqH/3Nfq25Xg8E8RWOF4KBQ==", + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.3.7.tgz", + "integrity": "sha512-6tK9Lv/lSfyBvpEQ4nsTfgxyDT1y1Uv/x8Wa+aB+E8qGo3ToexQ1BMVjxJk6PChXCDOWxB3B4KhqaZFjdhl3Ow==", "cpu": [ "arm64" ], @@ -2603,9 +2592,9 @@ } }, "node_modules/@nomicfoundation/edr-darwin-x64": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.3.3.tgz", - "integrity": "sha512-vkZXZ1ydPg+Ijb2iyqENA+KCkxGTCUWG5itCSliiA0Li2YE7ujDMGhheEpFp1WVlZadviz0bfk1rZXbCqlirpg==", + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.3.7.tgz", + "integrity": "sha512-1RrQ/1JPwxrYO69e0tglFv5H+ggour5Ii3bb727+yBpBShrxtOTQ7fZyfxA5h62LCN+0Z9wYOPeQ7XFcVurMaQ==", "cpu": [ "x64" ], @@ -2618,9 +2607,9 @@ } }, "node_modules/@nomicfoundation/edr-linux-arm64-gnu": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.3.3.tgz", - "integrity": "sha512-gdIg0Yj1qqS9wVuywc5B/+DqKylfUGB6/CQn/shMqwAfsAVAVpchkhy66PR+REEx7fh/GkNctxLlENXPeLzDiA==", + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.3.7.tgz", + "integrity": "sha512-ds/CKlBoVXIihjhflhgPn13EdKWed6r5bgvMs/YwRqT5wldQAQJZWAfA2+nYm0Yi2gMGh1RUpBcfkyl4pq7G+g==", "cpu": [ "arm64" ], @@ -2633,9 +2622,9 @@ } }, "node_modules/@nomicfoundation/edr-linux-arm64-musl": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.3.3.tgz", - "integrity": "sha512-AXZ08MFvhNeBZbOBNmz1SJ/DMrMOE2mHEJtaNnsctlxIunjxfrWww4q+WXB34jbr9iaVYYlPsaWe5sueuw6s3Q==", + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.3.7.tgz", + "integrity": "sha512-e29udiRaPujhLkM3+R6ju7QISrcyOqpcaxb2FsDWBkuD7H8uU9JPZEyyUIpEp5uIY0Jh1eEJPKZKIXQmQAEAuw==", "cpu": [ "arm64" ], @@ -2648,9 +2637,9 @@ } }, "node_modules/@nomicfoundation/edr-linux-x64-gnu": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.3.3.tgz", - "integrity": "sha512-xElOs1U+E6lBLtv1mnJ+E8nr2MxZgKiLo8bZAgBboy9odYtmkDVwhMjtsFKSuZbGxFtsSyGRT4cXw3JAbtUDeA==", + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.3.7.tgz", + "integrity": "sha512-/xkjmTyv+bbJ4akBCW0qzFKxPOV4AqLOmqurov+s9umHb16oOv72osSa3SdzJED2gHDaKmpMITT4crxbar4Axg==", "cpu": [ "x64" ], @@ -2663,9 +2652,9 @@ } }, "node_modules/@nomicfoundation/edr-linux-x64-musl": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.3.3.tgz", - "integrity": "sha512-2Fe6gwm1RAGQ/PfMYiaSba2OrFp8zzYWh+am9lYObOFjV9D+A1zhIzfy0UC74glPks5eV8eY4pBPrVR042m2Nw==", + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.3.7.tgz", + "integrity": "sha512-QwBP9xlmsbf/ldZDGLcE4QiAb8Zt46E/+WLpxHBATFhGa7MrpJh6Zse+h2VlrT/SYLPbh2cpHgSmoSlqVxWG9g==", "cpu": [ "x64" ], @@ -2677,40 +2666,10 @@ "node": ">= 18" } }, - "node_modules/@nomicfoundation/edr-win32-arm64-msvc": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-arm64-msvc/-/edr-win32-arm64-msvc-0.3.3.tgz", - "integrity": "sha512-8NHyxIsFrl0ufSQ/ErqF2lKIa/gz1gaaa1a2vKkDEqvqCUcPhBTYhA5NHgTPhLETFTnCFr0z+YbctFCyjh4qrA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/edr-win32-ia32-msvc": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-ia32-msvc/-/edr-win32-ia32-msvc-0.3.3.tgz", - "integrity": "sha512-0F6hM0kGia4dQVb/kauho9JcP1ozWisY2/She+ISR5ceuhzmAwQJluM0g+0TYDME0LtxBxiMPq/yPiZMQeq31w==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 18" - } - }, "node_modules/@nomicfoundation/edr-win32-x64-msvc": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.3.3.tgz", - "integrity": "sha512-d75q1uaMb6z9i+GQZoblbOfFBvlBnWc+5rB13UWRkCOJSnoYwyFWhGJx5GeM59gC7aIblc5VD9qOAhHuvM9N+w==", + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.3.7.tgz", + "integrity": "sha512-j/80DEnkxrF2ewdbk/gQ2EOPvgF0XSsg8D0o4+6cKhUVAW6XwtWKzIphNL6dyD2YaWEPgIrNvqiJK/aln0ww4Q==", "cpu": [ "x64" ], @@ -2846,9 +2805,9 @@ } }, "node_modules/@nomicfoundation/hardhat-ethers": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ethers/-/hardhat-ethers-3.0.5.tgz", - "integrity": "sha512-RNFe8OtbZK6Ila9kIlHp0+S80/0Bu/3p41HUpaRIoHLm6X3WekTd83vob3rE54Duufu1edCiBDxspBzi2rxHHw==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ethers/-/hardhat-ethers-3.0.6.tgz", + "integrity": "sha512-/xzkFQAaHQhmIAYOQmvHBPwL+NkwLzT9gRZBsgWUYeV+E6pzXsBQsHfRYbAZ3XEYare+T7S+5Tg/1KDJgepSkA==", "dev": true, "dependencies": { "debug": "^4.1.1", @@ -3299,9 +3258,9 @@ } }, "node_modules/@openzeppelin/upgrades-core": { - "version": "1.32.5", - "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.32.5.tgz", - "integrity": "sha512-R0wprsyJ4xWiRW05kaTfZZkRVpG2g0af3/hpjE7t2mX0Eb2n40MQLokTwqIk4LDzpp910JfLSpB0vBuZ6WNPog==", + "version": "1.33.1", + "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.33.1.tgz", + "integrity": "sha512-YRxIRhTY1b+j7+NUUu8Uuem5ugxKexEMVd8dBRWNgWeoN1gS1OCrhgUg0ytL+54vzQ+SGWZDfNnzjVuI1Cj1Zw==", "dependencies": { "cbor": "^9.0.0", "chalk": "^4.1.0", @@ -3799,14 +3758,14 @@ } }, "node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.0.0.tgz", + "integrity": "sha512-VvWuQk2RKFuOr98gFhjca7fkBS+xLLURT8bUjk5XQoV0ZLm7WPwWPPY3/AwzTLuUBDeoKDCthfe1AsTUWaSEhw==", "dependencies": { "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, "node_modules/@smithy/types/node_modules/tslib": { @@ -3860,6 +3819,78 @@ "typechain": "^8.0.0" } }, + "node_modules/@solarity/hardhat-migrate/node_modules/@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "dev": true, + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@solarity/hardhat-migrate/node_modules/@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "dev": true, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@solarity/hardhat-migrate/node_modules/@nomicfoundation/hardhat-ethers": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ethers/-/hardhat-ethers-3.0.5.tgz", + "integrity": "sha512-RNFe8OtbZK6Ila9kIlHp0+S80/0Bu/3p41HUpaRIoHLm6X3WekTd83vob3rE54Duufu1edCiBDxspBzi2rxHHw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "lodash.isequal": "^4.5.0" + }, + "peerDependencies": { + "ethers": "^6.1.0", + "hardhat": "^2.0.0" + } + }, + "node_modules/@solarity/hardhat-migrate/node_modules/@types/node": { + "version": "18.15.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz", + "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==", + "dev": true + }, + "node_modules/@solarity/hardhat-migrate/node_modules/ethers": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.11.1.tgz", + "integrity": "sha512-mxTAE6wqJQAbp5QAe/+o+rXOID7Nw91OZXvgpjDa1r4fAbq2Nu314oEZSbjoRLacuCzs7kUC3clEvkCQowffGg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/ethers-io/" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@adraffy/ens-normalize": "1.10.1", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", + "@types/node": "18.15.13", + "aes-js": "4.0.0-beta.5", + "tslib": "2.4.0", + "ws": "8.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@solarity/solidity-lib": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/@solarity/solidity-lib/-/solidity-lib-2.7.2.tgz", @@ -6739,9 +6770,9 @@ } }, "node_modules/@types/chai": { - "version": "4.3.14", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.14.tgz", - "integrity": "sha512-Wj71sXE4Q4AkGdG9Tvq1u/fquNz9EdG4LIJMwVVII7ashjD/8cf8fyIfJAjRr6YcsXnSE8cOGQPq1gqeR8z+3w==", + "version": "4.3.16", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.16.tgz", + "integrity": "sha512-PatH4iOdyh3MyWtmHVFXLWCCIhUbopaltqddG9BzB+gMIzee2MJrvd+jouii9Z3wzQJruGWAm7WOMjgfG8hQlQ==", "dev": true }, "node_modules/@types/chai-as-promised": { @@ -6804,9 +6835,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.43", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz", - "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==", + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz", + "integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==", "dev": true, "optional": true, "peer": true, @@ -6904,9 +6935,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.19.29", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.29.tgz", - "integrity": "sha512-5pAX7ggTmWZdhUrhRWLPf+5oM7F80bcKVCBbr0zwEkTNzTJL2CWQjznpFgHYy6GrzkYi2Yjy7DHKoynFxqPV8g==", + "version": "18.19.33", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.33.tgz", + "integrity": "sha512-NR9+KrpSajr2qBVp/Yt5TU/rp+b5Mayi3+OlMlcg2cVCfRmcG5PWZ7S4+MG9PZ5gWBoc9Pd0BKSRViuBCRPu0A==", "dependencies": { "undici-types": "~5.26.4" } @@ -6925,9 +6956,9 @@ "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==" }, "node_modules/@types/qs": { - "version": "6.9.14", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.14.tgz", - "integrity": "sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==" + "version": "6.9.15", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==" }, "node_modules/@types/range-parser": { "version": "1.2.7", @@ -7182,9 +7213,9 @@ "dev": true }, "node_modules/@uniswap/lib": { - "version": "4.0.1-alpha", - "resolved": "https://registry.npmjs.org/@uniswap/lib/-/lib-4.0.1-alpha.tgz", - "integrity": "sha512-f6UIliwBbRsgVLxIaBANF6w09tYqc6Y/qXdsrbEmXHyFA7ILiKrIwRFXe1yOg8M3cksgVsO9N7yuL2DdCGQKBA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@uniswap/lib/-/lib-1.1.1.tgz", + "integrity": "sha512-2yK7sLpKIT91TiS5sewHtOa7YuM8IuBXVl4GZv2jZFys4D2sY7K5vZh6MqD25TPA95Od+0YzCVq6cTF2IKrOmg==", "engines": { "node": ">=10" } @@ -7209,14 +7240,6 @@ "node": ">=10" } }, - "node_modules/@uniswap/v2-periphery/node_modules/@uniswap/lib": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@uniswap/lib/-/lib-1.1.1.tgz", - "integrity": "sha512-2yK7sLpKIT91TiS5sewHtOa7YuM8IuBXVl4GZv2jZFys4D2sY7K5vZh6MqD25TPA95Od+0YzCVq6cTF2IKrOmg==", - "engines": { - "node": ">=10" - } - }, "node_modules/@uniswap/v2-periphery/node_modules/@uniswap/v2-core": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@uniswap/v2-core/-/v2-core-1.0.0.tgz", @@ -7253,6 +7276,14 @@ "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-3.4.2-solc-0.7.tgz", "integrity": "sha512-W6QmqgkADuFcTLzHL8vVoNBtkwjvQRpYIAom7KiUNoLKghyx3FgH0GBjt8NRvigV1ZmMOBllvE1By1C+bi8WpA==" }, + "node_modules/@uniswap/v3-periphery/node_modules/@uniswap/lib": { + "version": "4.0.1-alpha", + "resolved": "https://registry.npmjs.org/@uniswap/lib/-/lib-4.0.1-alpha.tgz", + "integrity": "sha512-f6UIliwBbRsgVLxIaBANF6w09tYqc6Y/qXdsrbEmXHyFA7ILiKrIwRFXe1yOg8M3cksgVsO9N7yuL2DdCGQKBA==", + "engines": { + "node": ">=10" + } + }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", @@ -7289,7 +7320,6 @@ "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz", "integrity": "sha512-DnhQwcFEaYsvYDnACLZhMmCWd3rkOeEvglpa4q5i/5Jlm3UIsWaxVzuXvDLFCSCWRO3yy2/+V/G7FusFgejnfQ==", "dev": true, - "optional": true, "peer": true, "dependencies": { "buffer": "^6.0.3", @@ -7322,7 +7352,6 @@ "url": "https://feross.org/support" } ], - "optional": true, "peer": true, "dependencies": { "base64-js": "^1.3.1", @@ -7445,17 +7474,17 @@ } }, "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", + "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", "dev": true, "optional": true, "peer": true, "dependencies": { - "fast-deep-equal": "^3.1.1", + "fast-deep-equal": "^3.1.3", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "uri-js": "^4.4.1" }, "funding": { "type": "github", @@ -8660,7 +8689,6 @@ "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==", "dev": true, - "optional": true, "peer": true, "engines": { "node": ">=6" @@ -8696,15 +8724,15 @@ } }, "node_modules/chai-as-promised": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", - "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.2.tgz", + "integrity": "sha512-aBDHZxRzYnUYuIAIPBH2s511DjlKPzXNlXSGFC8CwmroWQLfrW0LtE1nK3MAwwNhJPa9raEjNCmRoFpG0Hurdw==", "dev": true, "dependencies": { "check-error": "^1.0.2" }, "peerDependencies": { - "chai": ">= 2.1.2 < 5" + "chai": ">= 2.1.2 < 6" } }, "node_modules/chalk": { @@ -8937,9 +8965,9 @@ } }, "node_modules/cli-table3": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.4.tgz", - "integrity": "sha512-Lm3L0p+/npIQWNIiyF/nAn7T5dnOwR3xNTHXYEBFBFVPXzCVNZ5lqEC/1eo/EVfpDsQ1I+TX4ORPQgp+UI0CRw==", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", "dependencies": { "string-width": "^4.2.0" }, @@ -9202,17 +9230,17 @@ } }, "node_modules/conf/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", + "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", "dev": true, "optional": true, "peer": true, "dependencies": { - "fast-deep-equal": "^3.1.1", + "fast-deep-equal": "^3.1.3", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "uri-js": "^4.4.1" }, "funding": { "type": "github", @@ -10042,7 +10070,6 @@ "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.4.1.tgz", "integrity": "sha512-r4eRSeStEGf6M5SKdrQhhLK5bOwOBxQhIE3YSTnZE3GpKiLfnnhE+tPtrJE79+eDJgm39BM6LSoI8SCx4HbwlQ==", "dev": true, - "optional": true, "peer": true, "engines": { "node": ">=6" @@ -11105,12 +11132,12 @@ } }, "node_modules/ethereum-bloom-filters": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz", - "integrity": "sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.1.0.tgz", + "integrity": "sha512-J1gDRkLpuGNvWYzWslBQR9cDV4nd4kfvVTE/Wy4Kkm4yb3EYRSlyi0eB/inTsSTTVyA0+HyzHgbr95Fn/Z1fSw==", "dev": true, "dependencies": { - "js-sha3": "^0.8.0" + "@noble/hashes": "^1.4.0" } }, "node_modules/ethereum-cryptography": { @@ -11253,9 +11280,9 @@ } }, "node_modules/ethers": { - "version": "6.11.1", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.11.1.tgz", - "integrity": "sha512-mxTAE6wqJQAbp5QAe/+o+rXOID7Nw91OZXvgpjDa1r4fAbq2Nu314oEZSbjoRLacuCzs7kUC3clEvkCQowffGg==", + "version": "6.12.1", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.12.1.tgz", + "integrity": "sha512-j6wcVoZf06nqEcBbDWkKg8Fp895SS96dSnTCjiXT+8vt2o02raTn4Lo9ERUuIVU5bAjoPYeA+7ytQFexFmLuVw==", "dev": true, "funding": [ { @@ -11267,6 +11294,7 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "peer": true, "dependencies": { "@adraffy/ens-normalize": "1.10.1", "@noble/curves": "1.2.0", @@ -11285,6 +11313,7 @@ "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", "dev": true, + "peer": true, "dependencies": { "@noble/hashes": "1.3.2" }, @@ -11297,6 +11326,7 @@ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", "dev": true, + "peer": true, "engines": { "node": ">= 16" }, @@ -11308,7 +11338,8 @@ "version": "18.15.13", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz", "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==", - "dev": true + "dev": true, + "peer": true }, "node_modules/ethjs-unit": { "version": "0.1.6", @@ -16153,11 +16184,12 @@ } }, "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dependencies": { - "define-properties": "^1.1.3" + "define-properties": "^1.2.1", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -16342,13 +16374,13 @@ } }, "node_modules/hardhat": { - "version": "2.22.2", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.22.2.tgz", - "integrity": "sha512-0xZ7MdCZ5sJem4MrvpQWLR3R3zGDoHw5lsR+pBFimqwagimIOn3bWuZv69KA+veXClwI1s/zpqgwPwiFrd4Dxw==", + "version": "2.22.4", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.22.4.tgz", + "integrity": "sha512-09qcXJFBHQUaraJkYNr7XlmwjOj27xBB0SL2rYS024hTj9tPMbp26AFjlf5quBMO9SR4AJFg+4qWahcYcvXBuQ==", "dependencies": { "@ethersproject/abi": "^5.1.2", "@metamask/eth-sig-util": "^4.0.0", - "@nomicfoundation/edr": "^0.3.1", + "@nomicfoundation/edr": "^0.3.7", "@nomicfoundation/ethereumjs-common": "4.0.4", "@nomicfoundation/ethereumjs-tx": "5.0.4", "@nomicfoundation/ethereumjs-util": "9.0.4", @@ -17341,13 +17373,12 @@ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz", "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==", "dev": true, - "optional": true, "peer": true }, "node_modules/immutable": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", - "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==" + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.6.tgz", + "integrity": "sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==" }, "node_modules/import-fresh": { "version": "3.3.0", @@ -17566,7 +17597,6 @@ "url": "https://feross.org/support" } ], - "optional": true, "peer": true, "engines": { "node": ">=4" @@ -18233,7 +18263,6 @@ "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz", "integrity": "sha512-BWRCMHBxbIqPxJ8vHOvKUsaO0v1sLYZtjN3K2iZJsRBYtp+ONsY6Jfi6hy9K3+zolgQRryhIn2NRZjZnWJ9NmQ==", "dev": true, - "optional": true, "peer": true, "dependencies": { "catering": "^2.1.0" @@ -18349,7 +18378,6 @@ "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-2.1.0.tgz", "integrity": "sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA==", "dev": true, - "optional": true, "peer": true, "engines": { "node": ">=10" @@ -18372,7 +18400,6 @@ "integrity": "sha512-iB8O/7Db9lPaITU1aA2txU/cBEXAt4vWwKQRrrWuS6XDgbP4QZGj9BL2aNbwb002atoQ/lIotJkfyzz+ygQnUQ==", "dev": true, "hasInstallScript": true, - "optional": true, "peer": true, "dependencies": { "abstract-leveldown": "~6.2.1", @@ -18388,7 +18415,6 @@ "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz", "integrity": "sha512-BsLm5vFMRUrrLeCcRc+G0t2qOaTzpoJQLOubq2XM72eNpjF5UdU5o/5NvlNhx95XHcAvcl8OMXr4mlg/fRgUXQ==", "dev": true, - "optional": true, "peer": true, "dependencies": { "buffer": "^5.5.0", @@ -18406,7 +18432,6 @@ "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-2.0.1.tgz", "integrity": "sha512-OTKKOqeav2QWcERMJR7IS9CUo1sHnke2C0gkSmcR7QuEtFNLLzHQAvnMw8ykvEcv0Qtkg0p7FOwP1v9e5Smdcw==", "dev": true, - "optional": true, "peer": true, "engines": { "node": ">=6" @@ -18417,7 +18442,6 @@ "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-1.0.1.tgz", "integrity": "sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg==", "dev": true, - "optional": true, "peer": true, "dependencies": { "xtend": "^4.0.2" @@ -18431,7 +18455,6 @@ "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.1.1.tgz", "integrity": "sha512-dSq1xmcPDKPZ2EED2S6zw/b9NKsqzXRE6dVr8TVQnI3FJOTteUMuqF3Qqs6LZg+mLGYJWqQzMbIjMtJqTv87nQ==", "dev": true, - "optional": true, "peer": true, "bin": { "node-gyp-build": "bin.js", @@ -18766,6 +18789,9 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "optional": true, + "peer": true, "dependencies": { "yallist": "^4.0.0" }, @@ -19315,7 +19341,6 @@ "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==", "dev": true, - "optional": true, "peer": true }, "node_modules/natural-compare": { @@ -19421,9 +19446,9 @@ } }, "node_modules/node-gyp-build": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz", - "integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz", + "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==", "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", @@ -19700,17 +19725,17 @@ } }, "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" @@ -20330,9 +20355,9 @@ "dev": true }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", "dev": true }, "node_modules/picomatch": { @@ -20482,9 +20507,9 @@ } }, "node_modules/pony-cause": { - "version": "2.1.10", - "resolved": "https://registry.npmjs.org/pony-cause/-/pony-cause-2.1.10.tgz", - "integrity": "sha512-3IKLNXclQgkU++2fSi93sQ6BznFuxSLB11HdvZQ6JW/spahf/P1pAHBQEahr20rs0htZW0UDkM1HmA+nZkXKsw==", + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/pony-cause/-/pony-cause-2.1.11.tgz", + "integrity": "sha512-M7LhCsdNbNgiLYiP4WjsfLUuFmCfnjdF6jKe2R9NKl4WFN+HZPGHJZ9lnLP7f9ZnKe3U9nuWD0szirmj+migUg==", "dev": true, "engines": { "node": ">=12.0.0" @@ -21062,9 +21087,9 @@ ] }, "node_modules/qs": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.0.tgz", - "integrity": "sha512-trVZiI6RMOkO476zLGaBIzszOdFPnCCXHPG9kn0yuS1uz6xdVxPfZdB3vUig9pxPFDM9BRAgz/YUIVQ1/vuiUg==", + "version": "6.12.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.1.tgz", + "integrity": "sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==", "dependencies": { "side-channel": "^1.0.6" }, @@ -21958,12 +21983,9 @@ } }, "node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "bin": { "semver": "bin/semver.js" }, @@ -22524,9 +22546,9 @@ } }, "node_modules/solhint": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/solhint/-/solhint-4.5.2.tgz", - "integrity": "sha512-o7MNYS5QPgE6l+PTGOTAUtCzo0ZLnffQsv586hntSHBe2JbSDfkoxfhAOcjZjN4OesTgaX4UEEjCjH9y/4BP5w==", + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-4.5.4.tgz", + "integrity": "sha512-Cu1XiJXub2q1eCr9kkJ9VPv1sGcmj3V7Zb76B0CoezDOB9bu3DxKIFFH7ggCl9fWpEPD6xBmRLfZrYijkVmujQ==", "dev": true, "dependencies": { "@solidity-parser/parser": "^0.18.0", @@ -22738,9 +22760,9 @@ "dev": true }, "node_modules/solidity-coverage": { - "version": "0.8.11", - "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.11.tgz", - "integrity": "sha512-yy0Yk+olovBbXn0Me8BWULmmv7A69ZKkP5aTOJGOO8u61Tu2zS989erfjtFlUjDnfWtxRAVkd8BsQD704yLWHw==", + "version": "0.8.12", + "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.12.tgz", + "integrity": "sha512-8cOB1PtjnjFRqOgwFiD8DaUsYJtVJ6+YdXQtSZDrLGf8cdhhh8xzTtGzVTGeBf15kTv0v7lYPJlV/az7zLEPJw==", "dev": true, "dependencies": { "@ethersproject/abi": "^5.0.9", @@ -22753,7 +22775,7 @@ "global-modules": "^2.0.0", "globby": "^10.0.1", "jsonschema": "^1.2.4", - "lodash": "^4.17.15", + "lodash": "^4.17.21", "mocha": "^10.2.0", "node-emoji": "^1.10.0", "pify": "^4.0.1", @@ -23467,14 +23489,14 @@ } }, "node_modules/table/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", + "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", "dependencies": { - "fast-deep-equal": "^3.1.1", + "fast-deep-equal": "^3.1.3", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "uri-js": "^4.4.1" }, "funding": { "type": "github", @@ -23698,9 +23720,9 @@ } }, "node_modules/tough-cookie": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", - "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", "dev": true, "optional": true, "peer": true, @@ -24335,9 +24357,9 @@ } }, "node_modules/typescript": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz", - "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -25213,14 +25235,14 @@ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/websocket": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz", - "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==", + "version": "1.0.35", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.35.tgz", + "integrity": "sha512-/REy6amwPZl44DDzvRCkaI1q1bIiQB0mEFQLUrhz3z2EK91cp3n72rAjUlrTP0zV22HJIUOVHQGPxhFRjxjt+Q==", "dev": true, "dependencies": { "bufferutil": "^4.0.1", "debug": "^2.2.0", - "es5-ext": "^0.10.50", + "es5-ext": "^0.10.63", "typedarray-to-buffer": "^3.1.5", "utf-8-validate": "^5.0.2", "yaeti": "^0.0.6" @@ -25643,7 +25665,10 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "optional": true, + "peer": true }, "node_modules/yaml": { "version": "1.10.2", From 21fc4f57ad8b273a487a80561d4e5700f809a6f4 Mon Sep 17 00:00:00 2001 From: Ruslan Kasheparov Date: Tue, 14 May 2024 22:19:07 +0200 Subject: [PATCH 15/17] changed package-lock.json --- package-lock.json | 757 ---------------------------------------------- 1 file changed, 757 deletions(-) diff --git a/package-lock.json b/package-lock.json index cb1b7de..53ec5d2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2311,103 +2311,6 @@ "events": "^3.2.0" } }, - "node_modules/@ledgerhq/hw-transport-node-hid": { - "version": "5.26.0", - "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-node-hid/-/hw-transport-node-hid-5.26.0.tgz", - "integrity": "sha512-qhaefZVZatJ6UuK8Wb6WSFNOLWc2mxcv/xgsfKi5HJCIr4bPF/ecIeN+7fRcEaycxj4XykY6Z4A7zDVulfFH4w==", - "optional": true, - "peer": true, - "dependencies": { - "@ledgerhq/devices": "^5.26.0", - "@ledgerhq/errors": "^5.26.0", - "@ledgerhq/hw-transport": "^5.26.0", - "@ledgerhq/hw-transport-node-hid-noevents": "^5.26.0", - "@ledgerhq/logs": "^5.26.0", - "lodash": "^4.17.20", - "node-hid": "1.3.0", - "usb": "^1.6.3" - } - }, - "node_modules/@ledgerhq/hw-transport-node-hid-noevents": { - "version": "5.51.1", - "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-node-hid-noevents/-/hw-transport-node-hid-noevents-5.51.1.tgz", - "integrity": "sha512-9wFf1L8ZQplF7XOY2sQGEeOhpmBRzrn+4X43kghZ7FBDoltrcK+s/D7S+7ffg3j2OySyP6vIIIgloXylao5Scg==", - "optional": true, - "peer": true, - "dependencies": { - "@ledgerhq/devices": "^5.51.1", - "@ledgerhq/errors": "^5.50.0", - "@ledgerhq/hw-transport": "^5.51.1", - "@ledgerhq/logs": "^5.50.0", - "node-hid": "2.1.1" - } - }, - "node_modules/@ledgerhq/hw-transport-node-hid-noevents/node_modules/@ledgerhq/hw-transport": { - "version": "5.51.1", - "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport/-/hw-transport-5.51.1.tgz", - "integrity": "sha512-6wDYdbWrw9VwHIcoDnqWBaDFyviyjZWv6H9vz9Vyhe4Qd7TIFmbTl/eWs6hZvtZBza9K8y7zD8ChHwRI4s9tSw==", - "optional": true, - "peer": true, - "dependencies": { - "@ledgerhq/devices": "^5.51.1", - "@ledgerhq/errors": "^5.50.0", - "events": "^3.3.0" - } - }, - "node_modules/@ledgerhq/hw-transport-node-hid-noevents/node_modules/node-addon-api": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", - "optional": true, - "peer": true - }, - "node_modules/@ledgerhq/hw-transport-node-hid-noevents/node_modules/node-hid": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/node-hid/-/node-hid-2.1.1.tgz", - "integrity": "sha512-Skzhqow7hyLZU93eIPthM9yjot9lszg9xrKxESleEs05V2NcbUptZc5HFqzjOkSmL0sFlZFr3kmvaYebx06wrw==", - "hasInstallScript": true, - "optional": true, - "peer": true, - "dependencies": { - "bindings": "^1.5.0", - "node-addon-api": "^3.0.2", - "prebuild-install": "^6.0.0" - }, - "bin": { - "hid-showdevices": "src/show-devices.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@ledgerhq/hw-transport-node-hid-noevents/node_modules/prebuild-install": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz", - "integrity": "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==", - "optional": true, - "peer": true, - "dependencies": { - "detect-libc": "^1.0.3", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^2.21.0", - "npmlog": "^4.0.1", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^3.0.3", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/@ledgerhq/hw-transport-u2f": { "version": "5.26.0", "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-u2f/-/hw-transport-u2f-5.26.0.tgz", @@ -2591,96 +2494,6 @@ "node": ">= 18" } }, - "node_modules/@nomicfoundation/edr-darwin-x64": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.3.7.tgz", - "integrity": "sha512-1RrQ/1JPwxrYO69e0tglFv5H+ggour5Ii3bb727+yBpBShrxtOTQ7fZyfxA5h62LCN+0Z9wYOPeQ7XFcVurMaQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 18" - } - }, - "node_modules/@nomicfoundation/edr-linux-arm64-gnu": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.3.7.tgz", - "integrity": "sha512-ds/CKlBoVXIihjhflhgPn13EdKWed6r5bgvMs/YwRqT5wldQAQJZWAfA2+nYm0Yi2gMGh1RUpBcfkyl4pq7G+g==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 18" - } - }, - "node_modules/@nomicfoundation/edr-linux-arm64-musl": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.3.7.tgz", - "integrity": "sha512-e29udiRaPujhLkM3+R6ju7QISrcyOqpcaxb2FsDWBkuD7H8uU9JPZEyyUIpEp5uIY0Jh1eEJPKZKIXQmQAEAuw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 18" - } - }, - "node_modules/@nomicfoundation/edr-linux-x64-gnu": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.3.7.tgz", - "integrity": "sha512-/xkjmTyv+bbJ4akBCW0qzFKxPOV4AqLOmqurov+s9umHb16oOv72osSa3SdzJED2gHDaKmpMITT4crxbar4Axg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 18" - } - }, - "node_modules/@nomicfoundation/edr-linux-x64-musl": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.3.7.tgz", - "integrity": "sha512-QwBP9xlmsbf/ldZDGLcE4QiAb8Zt46E/+WLpxHBATFhGa7MrpJh6Zse+h2VlrT/SYLPbh2cpHgSmoSlqVxWG9g==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 18" - } - }, - "node_modules/@nomicfoundation/edr-win32-x64-msvc": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.3.7.tgz", - "integrity": "sha512-j/80DEnkxrF2ewdbk/gQ2EOPvgF0XSsg8D0o4+6cKhUVAW6XwtWKzIphNL6dyD2YaWEPgIrNvqiJK/aln0ww4Q==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 18" - } - }, "node_modules/@nomicfoundation/ethereumjs-common": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.4.tgz", @@ -2894,141 +2707,6 @@ "node": ">= 10" } }, - "node_modules/@nomicfoundation/solidity-analyzer-darwin-x64": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.1.tgz", - "integrity": "sha512-XhQG4BaJE6cIbjAVtzGOGbK3sn1BO9W29uhk9J8y8fZF1DYz0Doj8QDMfpMu+A6TjPDs61lbsmeYodIDnfveSA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-freebsd-x64": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-freebsd-x64/-/solidity-analyzer-freebsd-x64-0.1.1.tgz", - "integrity": "sha512-GHF1VKRdHW3G8CndkwdaeLkVBi5A9u2jwtlS7SLhBc8b5U/GcoL39Q+1CSO3hYqePNP+eV5YI7Zgm0ea6kMHoA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.1.tgz", - "integrity": "sha512-g4Cv2fO37ZsUENQ2vwPnZc2zRenHyAxHcyBjKcjaSmmkKrFr64yvzeNO8S3GBFCo90rfochLs99wFVGT/0owpg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-musl": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.1.tgz", - "integrity": "sha512-WJ3CE5Oek25OGE3WwzK7oaopY8xMw9Lhb0mlYuJl/maZVo+WtP36XoQTb7bW/i8aAdHW5Z+BqrHMux23pvxG3w==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-gnu": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.1.tgz", - "integrity": "sha512-5WN7leSr5fkUBBjE4f3wKENUy9HQStu7HmWqbtknfXkkil+eNWiBV275IOlpXku7v3uLsXTOKpnnGHJYI2qsdA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-musl": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.1.tgz", - "integrity": "sha512-KdYMkJOq0SYPQMmErv/63CwGwMm5XHenEna9X9aB8mQmhDBrYrlAOSsIPgFCUSL0hjxE3xHP65/EPXR/InD2+w==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-win32-arm64-msvc": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-arm64-msvc/-/solidity-analyzer-win32-arm64-msvc-0.1.1.tgz", - "integrity": "sha512-VFZASBfl4qiBYwW5xeY20exWhmv6ww9sWu/krWSesv3q5hA0o1JuzmPHR4LPN6SUZj5vcqci0O6JOL8BPw+APg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-win32-ia32-msvc": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-ia32-msvc/-/solidity-analyzer-win32-ia32-msvc-0.1.1.tgz", - "integrity": "sha512-JnFkYuyCSA70j6Si6cS1A9Gh1aHTEb8kOTBApp/c7NRTFGNMH8eaInKlyuuiIbvYFhlXW4LicqyYuWNNq9hkpQ==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.1.tgz", - "integrity": "sha512-HrVJr6+WjIXGnw3Q9u6KQcbZCtk0caVWhCdFADySvRyUxJ8PnzlaP+MhwNE8oyT8OZ6ejHBRrrgjSqDCFXGirw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, "node_modules/@nomiclabs/hardhat-etherscan": { "version": "3.1.8", "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-etherscan/-/hardhat-etherscan-3.1.8.tgz", @@ -7871,64 +7549,6 @@ "dev": true, "peer": true }, - "node_modules/aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "optional": true, - "peer": true - }, - "node_modules/are-we-there-yet": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", - "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", - "optional": true, - "peer": true, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "node_modules/are-we-there-yet/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "optional": true, - "peer": true - }, - "node_modules/are-we-there-yet/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "optional": true, - "peer": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/are-we-there-yet/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "optional": true, - "peer": true - }, - "node_modules/are-we-there-yet/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "optional": true, - "peer": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -8269,16 +7889,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "optional": true, - "peer": true, - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, "node_modules/bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -9276,13 +8886,6 @@ "proto-list": "~1.2.1" } }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "optional": true, - "peer": true - }, "node_modules/constant-case": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-2.0.0.tgz", @@ -9659,19 +9262,6 @@ "node": ">=0.10" } }, - "node_modules/decompress-response": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", - "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", - "optional": true, - "peer": true, - "dependencies": { - "mimic-response": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/deep-eql": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", @@ -9831,13 +9421,6 @@ "node": ">=0.4.0" } }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "optional": true, - "peer": true - }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -9865,19 +9448,6 @@ "node": ">=4" } }, - "node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "optional": true, - "peer": true, - "bin": { - "detect-libc": "bin/detect-libc.js" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/diff": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", @@ -11419,16 +10989,6 @@ "safe-buffer": "^5.1.1" } }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "optional": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, "node_modules/express": { "version": "4.19.2", "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", @@ -11641,13 +11201,6 @@ "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "optional": true, - "peer": true - }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -11856,13 +11409,6 @@ "node": ">= 0.6" } }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "optional": true, - "peer": true - }, "node_modules/fs-extra": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", @@ -11895,19 +11441,6 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -15907,74 +15440,6 @@ "node": ">=8.0.0" } }, - "node_modules/gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==", - "optional": true, - "peer": true, - "dependencies": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "node_modules/gauge/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "optional": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gauge/node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", - "optional": true, - "peer": true, - "dependencies": { - "number-is-nan": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gauge/node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", - "optional": true, - "peer": true, - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gauge/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "optional": true, - "peer": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -16068,13 +15533,6 @@ "testrpc-sc": "index.js" } }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "optional": true, - "peer": true - }, "node_modules/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -17094,13 +16552,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "optional": true, - "peer": true - }, "node_modules/hash-base": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", @@ -18967,19 +18418,6 @@ "node": ">=6" } }, - "node_modules/mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", - "optional": true, - "peer": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/min-document": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", @@ -19059,13 +18497,6 @@ "mkdirp": "bin/cmd.js" } }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "optional": true, - "peer": true - }, "node_modules/mkdirp-promise": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz", @@ -19297,13 +18728,6 @@ "imul": "^1.0.0" } }, - "node_modules/nan": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz", - "integrity": "sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==", - "optional": true, - "peer": true - }, "node_modules/nano-base32": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/nano-base32/-/nano-base32-1.0.1.tgz", @@ -19329,13 +18753,6 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "optional": true, - "peer": true - }, "node_modules/napi-macros": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", @@ -19384,26 +18801,6 @@ "lower-case": "^1.1.1" } }, - "node_modules/node-abi": { - "version": "2.30.1", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz", - "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==", - "optional": true, - "peer": true, - "dependencies": { - "semver": "^5.4.1" - } - }, - "node_modules/node-abi/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "optional": true, - "peer": true, - "bin": { - "semver": "bin/semver" - } - }, "node_modules/node-abort-controller": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", @@ -19455,26 +18852,6 @@ "node-gyp-build-test": "build-test.js" } }, - "node_modules/node-hid": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/node-hid/-/node-hid-1.3.0.tgz", - "integrity": "sha512-BA6G4V84kiNd1uAChub/Z/5s/xS3EHBCxotQ0nyYrUG65mXewUDHE1tWOSqA2dp3N+mV0Ffq9wo2AW9t4p/G7g==", - "hasInstallScript": true, - "optional": true, - "peer": true, - "dependencies": { - "bindings": "^1.5.0", - "nan": "^2.14.0", - "node-abi": "^2.18.0", - "prebuild-install": "^5.3.4" - }, - "bin": { - "hid-showdevices": "src/show-devices.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/node-interval-tree": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/node-interval-tree/-/node-interval-tree-1.3.3.tgz", @@ -19496,13 +18873,6 @@ "node": ">=12.19" } }, - "node_modules/noop-logger": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", - "integrity": "sha512-6kM8CLXvuW5crTxsAtva2YLrRrDaiTIkIePWs9moLHqbFWT94WpNFjwS/5dfLfECg5i/lkmw3aoqVidxt23TEQ==", - "optional": true, - "peer": true - }, "node_modules/nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", @@ -19556,19 +18926,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "optional": true, - "peer": true, - "dependencies": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -20893,36 +20250,6 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/prebuild-install": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.6.tgz", - "integrity": "sha512-s8Aai8++QQGi4sSbs/M1Qku62PFK49Jm1CbgXklGz4nmHveDq0wzJkg7Na5QbnO1uNH8K7iqx2EQ/mV0MZEmOg==", - "optional": true, - "peer": true, - "dependencies": { - "detect-libc": "^1.0.3", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^2.7.0", - "noop-logger": "^0.1.1", - "npmlog": "^4.0.1", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^3.0.3", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0", - "which-pm-runs": "^1.0.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -22277,18 +21604,6 @@ } ] }, - "node_modules/simple-get": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", - "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", - "optional": true, - "peer": true, - "dependencies": { - "decompress-response": "^4.2.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -23553,36 +22868,6 @@ "node": ">=4.5" } }, - "node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "optional": true, - "peer": true, - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "optional": true, - "peer": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/tar/node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", @@ -24526,28 +23811,6 @@ "integrity": "sha512-3AChu4NiXquPfeckE5R5cGdiHCMWJx1dwCWOmWIL4KHAziJNOFIYJlpGFeKDvwLPHovZRCxK3cYlwzqI9Vp+Gg==", "dev": true }, - "node_modules/usb": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/usb/-/usb-1.9.2.tgz", - "integrity": "sha512-dryNz030LWBPAf6gj8vyq0Iev3vPbCLHCT8dBw3gQRXRzVNsIdeuU+VjPp3ksmSPkeMAl1k+kQ14Ij0QHyeiAg==", - "hasInstallScript": true, - "optional": true, - "peer": true, - "dependencies": { - "node-addon-api": "^4.2.0", - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=10.16.0" - } - }, - "node_modules/usb/node_modules/node-addon-api": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", - "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", - "optional": true, - "peer": true - }, "node_modules/utf-8-validate": { "version": "5.0.10", "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", @@ -25322,16 +24585,6 @@ "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", "dev": true }, - "node_modules/which-pm-runs": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", - "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==", - "optional": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, "node_modules/which-typed-array": { "version": "1.1.15", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", @@ -25350,16 +24603,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "optional": true, - "peer": true, - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, "node_modules/widest-line": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", From 60fac6a5c57b92bf09c613e79d79cc8c609237c7 Mon Sep 17 00:00:00 2001 From: Ruslan Kasheparov Date: Tue, 14 May 2024 22:26:38 +0200 Subject: [PATCH 16/17] changed ci --- .github/actions/setup/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 9e7f080..63650cb 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -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 From ecbede26e3bce6b165657b4fc65cbd2d35c4b130 Mon Sep 17 00:00:00 2001 From: Ruslan Kasheparov Date: Tue, 14 May 2024 22:48:18 +0200 Subject: [PATCH 17/17] changed package-lock.json --- package-lock.json | 815 ++++++++++++++++++++++++++++++++++++++++++++-- package.json | 58 ++-- 2 files changed, 815 insertions(+), 58 deletions(-) diff --git a/package-lock.json b/package-lock.json index 53ec5d2..8038342 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,45 +20,45 @@ "@uniswap/v3-core": "^1.0.1", "@uniswap/v3-periphery": "^1.4.4", "dotenv": "^10.0.0", - "hardhat": "^2.17.4", - "typechain": "^8.3.1" + "hardhat": "^2.22.4", + "typechain": "^8.3.2" }, "devDependencies": { - "@metamask/eth-sig-util": "^7.0.0", - "@nomicfoundation/hardhat-chai-matchers": "^2.0.2", - "@nomicfoundation/hardhat-ethers": "^3.0.4", - "@nomicfoundation/hardhat-network-helpers": "^1.0.9", + "@metamask/eth-sig-util": "^7.0.2", + "@nomicfoundation/hardhat-chai-matchers": "^2.0.6", + "@nomicfoundation/hardhat-ethers": "^3.0.6", + "@nomicfoundation/hardhat-network-helpers": "^1.0.10", "@nomiclabs/hardhat-truffle5": "^2.0.7", "@nomiclabs/hardhat-web3": "^2.0.0", - "@solarity/hardhat-markup": "^1.0.2", + "@solarity/hardhat-markup": "^1.0.7", "@solarity/hardhat-migrate": "2.1.7", "@trivago/prettier-plugin-sort-imports": "^4.3.0", - "@typechain/ethers-v6": "^0.5.0", - "@typechain/hardhat": "^9.0.0", - "@typechain/truffle-v5": "^8.0.6", - "@typechain/web3-v1": "^6.0.6", - "@types/chai": "^4.3.6", - "@types/mocha": "^10.0.2", - "@types/node": "^18.16.0", - "@typescript-eslint/eslint-plugin": "^6.13.1", - "@typescript-eslint/parser": "^6.13.1", - "chai": "^4.3.10", - "eslint": "^8.54.0", - "eslint-config-prettier": "^9.0.0", - "eslint-plugin-prettier": "^5.0.1", + "@typechain/ethers-v6": "^0.5.1", + "@typechain/hardhat": "^9.1.0", + "@typechain/truffle-v5": "^8.0.7", + "@typechain/web3-v1": "^6.0.7", + "@types/chai": "^4.3.16", + "@types/mocha": "^10.0.6", + "@types/node": "^18.19.33", + "@typescript-eslint/eslint-plugin": "^6.21.0", + "@typescript-eslint/parser": "^6.21.0", + "chai": "^4.4.1", + "eslint": "^8.57.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.1.3", "hardhat-contract-sizer": "^2.10.0", - "hardhat-gas-reporter": "^1.0.9", - "husky": "^8.0.2", - "mocha": "^10.2.0", - "prettier": "^3.1.0", + "hardhat-gas-reporter": "^1.0.10", + "husky": "^8.0.3", + "mocha": "^10.4.0", + "prettier": "^3.2.5", "prettier-plugin-solidity": "^1.3.1", - "solhint": "^4.0.0", + "solhint": "^4.5.4", "solhint-plugin-prettier": "^0.1.0", - "solidity-coverage": "^0.8.5", - "ts-node": "^10.9.1", + "solidity-coverage": "^0.8.12", + "ts-node": "^10.9.2", "tsconfig-paths": "^4.2.0", - "typescript": "^5.2.2", - "web3": "^1.7.5" + "typescript": "^5.4.5", + "web3": "^1.10.4" } }, "node_modules/@adraffy/ens-normalize": { @@ -2311,6 +2311,103 @@ "events": "^3.2.0" } }, + "node_modules/@ledgerhq/hw-transport-node-hid": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-node-hid/-/hw-transport-node-hid-5.26.0.tgz", + "integrity": "sha512-qhaefZVZatJ6UuK8Wb6WSFNOLWc2mxcv/xgsfKi5HJCIr4bPF/ecIeN+7fRcEaycxj4XykY6Z4A7zDVulfFH4w==", + "optional": true, + "peer": true, + "dependencies": { + "@ledgerhq/devices": "^5.26.0", + "@ledgerhq/errors": "^5.26.0", + "@ledgerhq/hw-transport": "^5.26.0", + "@ledgerhq/hw-transport-node-hid-noevents": "^5.26.0", + "@ledgerhq/logs": "^5.26.0", + "lodash": "^4.17.20", + "node-hid": "1.3.0", + "usb": "^1.6.3" + } + }, + "node_modules/@ledgerhq/hw-transport-node-hid-noevents": { + "version": "5.51.1", + "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-node-hid-noevents/-/hw-transport-node-hid-noevents-5.51.1.tgz", + "integrity": "sha512-9wFf1L8ZQplF7XOY2sQGEeOhpmBRzrn+4X43kghZ7FBDoltrcK+s/D7S+7ffg3j2OySyP6vIIIgloXylao5Scg==", + "optional": true, + "peer": true, + "dependencies": { + "@ledgerhq/devices": "^5.51.1", + "@ledgerhq/errors": "^5.50.0", + "@ledgerhq/hw-transport": "^5.51.1", + "@ledgerhq/logs": "^5.50.0", + "node-hid": "2.1.1" + } + }, + "node_modules/@ledgerhq/hw-transport-node-hid-noevents/node_modules/@ledgerhq/hw-transport": { + "version": "5.51.1", + "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport/-/hw-transport-5.51.1.tgz", + "integrity": "sha512-6wDYdbWrw9VwHIcoDnqWBaDFyviyjZWv6H9vz9Vyhe4Qd7TIFmbTl/eWs6hZvtZBza9K8y7zD8ChHwRI4s9tSw==", + "optional": true, + "peer": true, + "dependencies": { + "@ledgerhq/devices": "^5.51.1", + "@ledgerhq/errors": "^5.50.0", + "events": "^3.3.0" + } + }, + "node_modules/@ledgerhq/hw-transport-node-hid-noevents/node_modules/node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "optional": true, + "peer": true + }, + "node_modules/@ledgerhq/hw-transport-node-hid-noevents/node_modules/node-hid": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/node-hid/-/node-hid-2.1.1.tgz", + "integrity": "sha512-Skzhqow7hyLZU93eIPthM9yjot9lszg9xrKxESleEs05V2NcbUptZc5HFqzjOkSmL0sFlZFr3kmvaYebx06wrw==", + "hasInstallScript": true, + "optional": true, + "peer": true, + "dependencies": { + "bindings": "^1.5.0", + "node-addon-api": "^3.0.2", + "prebuild-install": "^6.0.0" + }, + "bin": { + "hid-showdevices": "src/show-devices.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@ledgerhq/hw-transport-node-hid-noevents/node_modules/prebuild-install": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz", + "integrity": "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==", + "optional": true, + "peer": true, + "dependencies": { + "detect-libc": "^1.0.3", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^2.21.0", + "npmlog": "^4.0.1", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^3.0.3", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@ledgerhq/hw-transport-u2f": { "version": "5.26.0", "resolved": "https://registry.npmjs.org/@ledgerhq/hw-transport-u2f/-/hw-transport-u2f-5.26.0.tgz", @@ -2494,6 +2591,96 @@ "node": ">= 18" } }, + "node_modules/@nomicfoundation/edr-darwin-x64": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.3.7.tgz", + "integrity": "sha512-1RrQ/1JPwxrYO69e0tglFv5H+ggour5Ii3bb727+yBpBShrxtOTQ7fZyfxA5h62LCN+0Z9wYOPeQ7XFcVurMaQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-arm64-gnu": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.3.7.tgz", + "integrity": "sha512-ds/CKlBoVXIihjhflhgPn13EdKWed6r5bgvMs/YwRqT5wldQAQJZWAfA2+nYm0Yi2gMGh1RUpBcfkyl4pq7G+g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-arm64-musl": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.3.7.tgz", + "integrity": "sha512-e29udiRaPujhLkM3+R6ju7QISrcyOqpcaxb2FsDWBkuD7H8uU9JPZEyyUIpEp5uIY0Jh1eEJPKZKIXQmQAEAuw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-x64-gnu": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.3.7.tgz", + "integrity": "sha512-/xkjmTyv+bbJ4akBCW0qzFKxPOV4AqLOmqurov+s9umHb16oOv72osSa3SdzJED2gHDaKmpMITT4crxbar4Axg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-x64-musl": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.3.7.tgz", + "integrity": "sha512-QwBP9xlmsbf/ldZDGLcE4QiAb8Zt46E/+WLpxHBATFhGa7MrpJh6Zse+h2VlrT/SYLPbh2cpHgSmoSlqVxWG9g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-win32-x64-msvc": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.3.7.tgz", + "integrity": "sha512-j/80DEnkxrF2ewdbk/gQ2EOPvgF0XSsg8D0o4+6cKhUVAW6XwtWKzIphNL6dyD2YaWEPgIrNvqiJK/aln0ww4Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 18" + } + }, "node_modules/@nomicfoundation/ethereumjs-common": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.4.tgz", @@ -2707,6 +2894,141 @@ "node": ">= 10" } }, + "node_modules/@nomicfoundation/solidity-analyzer-darwin-x64": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.1.tgz", + "integrity": "sha512-XhQG4BaJE6cIbjAVtzGOGbK3sn1BO9W29uhk9J8y8fZF1DYz0Doj8QDMfpMu+A6TjPDs61lbsmeYodIDnfveSA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-freebsd-x64": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-freebsd-x64/-/solidity-analyzer-freebsd-x64-0.1.1.tgz", + "integrity": "sha512-GHF1VKRdHW3G8CndkwdaeLkVBi5A9u2jwtlS7SLhBc8b5U/GcoL39Q+1CSO3hYqePNP+eV5YI7Zgm0ea6kMHoA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.1.tgz", + "integrity": "sha512-g4Cv2fO37ZsUENQ2vwPnZc2zRenHyAxHcyBjKcjaSmmkKrFr64yvzeNO8S3GBFCo90rfochLs99wFVGT/0owpg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-musl": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.1.tgz", + "integrity": "sha512-WJ3CE5Oek25OGE3WwzK7oaopY8xMw9Lhb0mlYuJl/maZVo+WtP36XoQTb7bW/i8aAdHW5Z+BqrHMux23pvxG3w==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-gnu": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.1.tgz", + "integrity": "sha512-5WN7leSr5fkUBBjE4f3wKENUy9HQStu7HmWqbtknfXkkil+eNWiBV275IOlpXku7v3uLsXTOKpnnGHJYI2qsdA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-musl": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.1.tgz", + "integrity": "sha512-KdYMkJOq0SYPQMmErv/63CwGwMm5XHenEna9X9aB8mQmhDBrYrlAOSsIPgFCUSL0hjxE3xHP65/EPXR/InD2+w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-arm64-msvc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-arm64-msvc/-/solidity-analyzer-win32-arm64-msvc-0.1.1.tgz", + "integrity": "sha512-VFZASBfl4qiBYwW5xeY20exWhmv6ww9sWu/krWSesv3q5hA0o1JuzmPHR4LPN6SUZj5vcqci0O6JOL8BPw+APg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-ia32-msvc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-ia32-msvc/-/solidity-analyzer-win32-ia32-msvc-0.1.1.tgz", + "integrity": "sha512-JnFkYuyCSA70j6Si6cS1A9Gh1aHTEb8kOTBApp/c7NRTFGNMH8eaInKlyuuiIbvYFhlXW4LicqyYuWNNq9hkpQ==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.1.tgz", + "integrity": "sha512-HrVJr6+WjIXGnw3Q9u6KQcbZCtk0caVWhCdFADySvRyUxJ8PnzlaP+MhwNE8oyT8OZ6ejHBRrrgjSqDCFXGirw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@nomiclabs/hardhat-etherscan": { "version": "3.1.8", "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-etherscan/-/hardhat-etherscan-3.1.8.tgz", @@ -7549,6 +7871,64 @@ "dev": true, "peer": true }, + "node_modules/aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "optional": true, + "peer": true + }, + "node_modules/are-we-there-yet": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", + "optional": true, + "peer": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "node_modules/are-we-there-yet/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "optional": true, + "peer": true + }, + "node_modules/are-we-there-yet/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "optional": true, + "peer": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/are-we-there-yet/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "optional": true, + "peer": true + }, + "node_modules/are-we-there-yet/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "optional": true, + "peer": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -7889,6 +8269,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "optional": true, + "peer": true, + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, "node_modules/bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -8886,6 +9276,13 @@ "proto-list": "~1.2.1" } }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "optional": true, + "peer": true + }, "node_modules/constant-case": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-2.0.0.tgz", @@ -9262,6 +9659,19 @@ "node": ">=0.10" } }, + "node_modules/decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "optional": true, + "peer": true, + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/deep-eql": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", @@ -9421,6 +9831,13 @@ "node": ">=0.4.0" } }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "optional": true, + "peer": true + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -9448,6 +9865,19 @@ "node": ">=4" } }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "optional": true, + "peer": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/diff": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", @@ -10989,6 +11419,16 @@ "safe-buffer": "^5.1.1" } }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "optional": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, "node_modules/express": { "version": "4.19.2", "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", @@ -11201,6 +11641,13 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "optional": true, + "peer": true + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -11409,6 +11856,13 @@ "node": ">= 0.6" } }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "optional": true, + "peer": true + }, "node_modules/fs-extra": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", @@ -11441,6 +11895,19 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -15440,6 +15907,74 @@ "node": ">=8.0.0" } }, + "node_modules/gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==", + "optional": true, + "peer": true, + "dependencies": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "node_modules/gauge/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "optional": true, + "peer": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "optional": true, + "peer": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "optional": true, + "peer": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -15533,6 +16068,13 @@ "testrpc-sc": "index.js" } }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "optional": true, + "peer": true + }, "node_modules/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -16552,6 +17094,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "optional": true, + "peer": true + }, "node_modules/hash-base": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", @@ -18418,6 +18967,19 @@ "node": ">=6" } }, + "node_modules/mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "optional": true, + "peer": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/min-document": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", @@ -18497,6 +19059,13 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "optional": true, + "peer": true + }, "node_modules/mkdirp-promise": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz", @@ -18728,6 +19297,13 @@ "imul": "^1.0.0" } }, + "node_modules/nan": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz", + "integrity": "sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==", + "optional": true, + "peer": true + }, "node_modules/nano-base32": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/nano-base32/-/nano-base32-1.0.1.tgz", @@ -18753,6 +19329,13 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "optional": true, + "peer": true + }, "node_modules/napi-macros": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", @@ -18801,6 +19384,26 @@ "lower-case": "^1.1.1" } }, + "node_modules/node-abi": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz", + "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==", + "optional": true, + "peer": true, + "dependencies": { + "semver": "^5.4.1" + } + }, + "node_modules/node-abi/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "optional": true, + "peer": true, + "bin": { + "semver": "bin/semver" + } + }, "node_modules/node-abort-controller": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", @@ -18852,6 +19455,26 @@ "node-gyp-build-test": "build-test.js" } }, + "node_modules/node-hid": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/node-hid/-/node-hid-1.3.0.tgz", + "integrity": "sha512-BA6G4V84kiNd1uAChub/Z/5s/xS3EHBCxotQ0nyYrUG65mXewUDHE1tWOSqA2dp3N+mV0Ffq9wo2AW9t4p/G7g==", + "hasInstallScript": true, + "optional": true, + "peer": true, + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.14.0", + "node-abi": "^2.18.0", + "prebuild-install": "^5.3.4" + }, + "bin": { + "hid-showdevices": "src/show-devices.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/node-interval-tree": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/node-interval-tree/-/node-interval-tree-1.3.3.tgz", @@ -18873,6 +19496,13 @@ "node": ">=12.19" } }, + "node_modules/noop-logger": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", + "integrity": "sha512-6kM8CLXvuW5crTxsAtva2YLrRrDaiTIkIePWs9moLHqbFWT94WpNFjwS/5dfLfECg5i/lkmw3aoqVidxt23TEQ==", + "optional": true, + "peer": true + }, "node_modules/nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", @@ -18926,6 +19556,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "optional": true, + "peer": true, + "dependencies": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -20250,6 +20893,36 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/prebuild-install": { + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.6.tgz", + "integrity": "sha512-s8Aai8++QQGi4sSbs/M1Qku62PFK49Jm1CbgXklGz4nmHveDq0wzJkg7Na5QbnO1uNH8K7iqx2EQ/mV0MZEmOg==", + "optional": true, + "peer": true, + "dependencies": { + "detect-libc": "^1.0.3", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^2.7.0", + "noop-logger": "^0.1.1", + "npmlog": "^4.0.1", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^3.0.3", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0", + "which-pm-runs": "^1.0.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -21604,6 +22277,18 @@ } ] }, + "node_modules/simple-get": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "optional": true, + "peer": true, + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -22868,6 +23553,36 @@ "node": ">=4.5" } }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "optional": true, + "peer": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "optional": true, + "peer": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/tar/node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", @@ -23811,6 +24526,28 @@ "integrity": "sha512-3AChu4NiXquPfeckE5R5cGdiHCMWJx1dwCWOmWIL4KHAziJNOFIYJlpGFeKDvwLPHovZRCxK3cYlwzqI9Vp+Gg==", "dev": true }, + "node_modules/usb": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/usb/-/usb-1.9.2.tgz", + "integrity": "sha512-dryNz030LWBPAf6gj8vyq0Iev3vPbCLHCT8dBw3gQRXRzVNsIdeuU+VjPp3ksmSPkeMAl1k+kQ14Ij0QHyeiAg==", + "hasInstallScript": true, + "optional": true, + "peer": true, + "dependencies": { + "node-addon-api": "^4.2.0", + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/usb/node_modules/node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", + "optional": true, + "peer": true + }, "node_modules/utf-8-validate": { "version": "5.0.10", "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", @@ -24585,6 +25322,16 @@ "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", "dev": true }, + "node_modules/which-pm-runs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", + "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==", + "optional": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, "node_modules/which-typed-array": { "version": "1.1.15", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", @@ -24603,6 +25350,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "optional": true, + "peer": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, "node_modules/widest-line": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", diff --git a/package.json b/package.json index e09bb3d..467c64a 100644 --- a/package.json +++ b/package.json @@ -48,44 +48,44 @@ "@uniswap/v3-core": "^1.0.1", "@uniswap/v3-periphery": "^1.4.4", "dotenv": "^10.0.0", - "hardhat": "^2.17.4", - "typechain": "^8.3.1" + "hardhat": "^2.22.4", + "typechain": "^8.3.2" }, "devDependencies": { - "@metamask/eth-sig-util": "^7.0.0", - "@nomicfoundation/hardhat-chai-matchers": "^2.0.2", - "@nomicfoundation/hardhat-ethers": "^3.0.4", - "@nomicfoundation/hardhat-network-helpers": "^1.0.9", + "@metamask/eth-sig-util": "^7.0.2", + "@nomicfoundation/hardhat-chai-matchers": "^2.0.6", + "@nomicfoundation/hardhat-ethers": "^3.0.6", + "@nomicfoundation/hardhat-network-helpers": "^1.0.10", "@nomiclabs/hardhat-truffle5": "^2.0.7", "@nomiclabs/hardhat-web3": "^2.0.0", - "@solarity/hardhat-markup": "^1.0.2", + "@solarity/hardhat-markup": "^1.0.7", "@solarity/hardhat-migrate": "2.1.7", "@trivago/prettier-plugin-sort-imports": "^4.3.0", - "@typechain/ethers-v6": "^0.5.0", - "@typechain/hardhat": "^9.0.0", - "@typechain/truffle-v5": "^8.0.6", - "@typechain/web3-v1": "^6.0.6", - "@types/chai": "^4.3.6", - "@types/mocha": "^10.0.2", - "@types/node": "^18.16.0", - "@typescript-eslint/eslint-plugin": "^6.13.1", - "@typescript-eslint/parser": "^6.13.1", - "chai": "^4.3.10", - "eslint": "^8.54.0", - "eslint-config-prettier": "^9.0.0", - "eslint-plugin-prettier": "^5.0.1", + "@typechain/ethers-v6": "^0.5.1", + "@typechain/hardhat": "^9.1.0", + "@typechain/truffle-v5": "^8.0.7", + "@typechain/web3-v1": "^6.0.7", + "@types/chai": "^4.3.16", + "@types/mocha": "^10.0.6", + "@types/node": "^18.19.33", + "@typescript-eslint/eslint-plugin": "^6.21.0", + "@typescript-eslint/parser": "^6.21.0", + "chai": "^4.4.1", + "eslint": "^8.57.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.1.3", "hardhat-contract-sizer": "^2.10.0", - "hardhat-gas-reporter": "^1.0.9", - "husky": "^8.0.2", - "mocha": "^10.2.0", - "prettier": "^3.1.0", + "hardhat-gas-reporter": "^1.0.10", + "husky": "^8.0.3", + "mocha": "^10.4.0", + "prettier": "^3.2.5", "prettier-plugin-solidity": "^1.3.1", - "solhint": "^4.0.0", + "solhint": "^4.5.4", "solhint-plugin-prettier": "^0.1.0", - "solidity-coverage": "^0.8.5", - "ts-node": "^10.9.1", + "solidity-coverage": "^0.8.12", + "ts-node": "^10.9.2", "tsconfig-paths": "^4.2.0", - "typescript": "^5.2.2", - "web3": "^1.7.5" + "typescript": "^5.4.5", + "web3": "^1.10.4" } }