Skip to content

Commit

Permalink
Dev (#14)
Browse files Browse the repository at this point in the history
* moved contracts to uups proxy

* added tests

* updated package.json

* fixed issues

* LZ nonblocking app (#5)

* add nonblocking functionality lo LZ bridge

* refactored

---------

Co-authored-by: RuslanProgrammer <[email protected]>

* Cleanup files (#6)

* refactored

* added deploy all script

* added config parser

* fixed deploy all

* fixed token bridge

* fixed tests

* Merge events into dev (#8)

* Add events to contracts (#7)

* added events

* added tests for events

* moved events to specific functions

* added restriction for withdrawn after stake (#9)

* Fixes after TestingReports review (#10)

* fixed floating promises in tests

* fixed 'No Conflicting Inheritance'

* fixed 'unnecessarily permissive visibility'

* fixed tests

* fixed multiple issues

* added mainnet config

* added lint task (#11)

* added lint task

* changed order of ci tasks

* StETH mock changes (#12)

* Update StETHMock and WStETHMock contracts, and config files

* Updated tests

* fixed config

* change implementation of StETH to almost real

---------

Co-authored-by: David Johnston <[email protected]>
Co-authored-by: Oleksandr Fedorenko <[email protected]>
  • Loading branch information
3 people authored Jan 12, 2024
1 parent 78b68b7 commit b211516
Show file tree
Hide file tree
Showing 43 changed files with 2,092 additions and 474 deletions.
6 changes: 4 additions & 2 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
"sourceType": "module",
"project": "./tsconfig.json"
},
"plugins": ["@typescript-eslint"],
"extends": [
Expand All @@ -11,7 +12,8 @@
"plugin:prettier/recommended"
],
"rules": {
"@typescript-eslint/no-unused-vars": "error"
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/no-floating-promises": "error"
},
"env": {
"browser": true,
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@ jobs:
uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup
- name: Run lint
run: npm run lint
- name: Run tests
run: npm run test-without-fork
run: npm run test
58 changes: 37 additions & 21 deletions contracts/Distribution.sol
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
// 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 {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/IDistribution.sol";
import {IMOR} from "./interfaces/IMOR.sol";
import {L1Sender} from "./L1Sender.sol";
import {IDistribution} from "./interfaces/IDistribution.sol";

contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable {
using SafeERC20 for IERC20;
Expand Down Expand Up @@ -54,7 +54,7 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable {
__Ownable_init();
__UUPSUpgradeable_init();

for (uint256 i = 0; i < poolsInfo_.length; i++) {
for (uint256 i; i < poolsInfo_.length; ++i) {
createPool(poolsInfo_[i]);
}

Expand All @@ -70,6 +70,8 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable {

_validatePool(pool_);
pools.push(pool_);

emit PoolCreated(pools.length - 1, pool_);
}

function editPool(uint256 poolId_, Pool calldata pool_) external onlyOwner poolExists(poolId_) {
Expand All @@ -84,6 +86,8 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable {
poolData.lastUpdate = uint128(block.timestamp);

pools[poolId_] = pool_;

emit PoolEdited(poolId_, pool_);
}

function getPeriodReward(uint256 poolId_, uint128 startTime_, uint128 endTime_) public view returns (uint256) {
Expand All @@ -104,7 +108,7 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable {
);
}

function _validatePool(Pool calldata pool_) internal pure {
function _validatePool(Pool calldata pool_) private pure {
if (pool_.rewardDecrease > 0) {
require(pool_.decreaseInterval > 0, "DS: invalid reward decrease");
}
Expand All @@ -123,7 +127,7 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable {

uint256 currentPoolRate_ = _getCurrentPoolRate(poolId_);

for (uint256 i = 0; i < users_.length; i++) {
for (uint256 i; i < users_.length; ++i) {
address user_ = users_[i];
uint256 amount_ = amounts_[i];

Expand Down Expand Up @@ -165,6 +169,8 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable {

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

emit UserClaimed(poolId_, user_, pendingRewards_);
}

function withdraw(uint256 poolId_, uint256 amount_) external poolExists(poolId_) poolPublic(poolId_) {
Expand All @@ -182,7 +188,7 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable {
return _getCurrentUserReward(currentPoolRate_, userData);
}

function _stake(address user_, uint256 poolId_, uint256 amount_, uint256 currentPoolRate_) internal {
function _stake(address user_, uint256 poolId_, uint256 amount_, uint256 currentPoolRate_) private {
require(amount_ > 0, "DS: nothing to stake");

Pool storage pool = pools[poolId_];
Expand Down Expand Up @@ -210,11 +216,14 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable {
poolData.totalDeposited += amount_;

// Update user data
userData.lastStake = uint128(block.timestamp);
userData.rate = currentPoolRate_;
userData.deposited += amount_;

emit UserStaked(poolId_, user_, amount_);
}

function _withdraw(address user_, uint256 poolId_, uint256 amount_, uint256 currentPoolRate_) internal {
function _withdraw(address user_, uint256 poolId_, uint256 amount_, uint256 currentPoolRate_) private {
Pool storage pool = pools[poolId_];
PoolData storage poolData = poolsData[poolId_];
UserData storage userData = usersData[user_][poolId_];
Expand All @@ -229,7 +238,9 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable {
uint256 newDeposited_;
if (pool.isPublic) {
require(
block.timestamp < pool.payoutStart || block.timestamp > pool.payoutStart + pool.withdrawLockPeriod,
block.timestamp < pool.payoutStart ||
(block.timestamp > pool.payoutStart + pool.withdrawLockPeriod &&
block.timestamp > userData.lastStake + pool.withdrawLockPeriodAfterStake),
"DS: pool withdraw is locked"
);

Expand All @@ -240,10 +251,8 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable {

newDeposited_ = deposited_ - amount_;

require(
amount_ > 0 && (newDeposited_ >= pool.minimalStake || newDeposited_ == 0),
"DS: invalid withdraw amount"
);
require(amount_ > 0, "DS: nothing to withdraw");
require(newDeposited_ >= pool.minimalStake || newDeposited_ == 0, "DS: invalid withdraw amount");
} else {
newDeposited_ = deposited_ - amount_;
}
Expand All @@ -265,18 +274,17 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable {

IERC20(depositToken).safeTransfer(user_, amount_);
}

emit UserWithdrawn(poolId_, user_, amount_);
}

function _getCurrentUserReward(
uint256 currentPoolRate_,
UserData memory userData_
) internal pure returns (uint256) {
function _getCurrentUserReward(uint256 currentPoolRate_, UserData memory userData_) private pure returns (uint256) {
uint256 newRewards_ = ((currentPoolRate_ - userData_.rate) * userData_.deposited) / PRECISION;

return userData_.pendingRewards + newRewards_;
}

function _getCurrentPoolRate(uint256 poolId_) internal view returns (uint256) {
function _getCurrentPoolRate(uint256 poolId_) private view returns (uint256) {
PoolData storage poolData = poolsData[poolId_];

if (poolData.totalDeposited == 0) {
Expand All @@ -288,7 +296,7 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable {
return poolData.rate + (rewards_ * PRECISION) / poolData.totalDeposited;
}

function _poolExists(uint256 poolId_) internal view returns (bool) {
function _poolExists(uint256 poolId_) private view returns (bool) {
return poolId_ < pools.length;
}

Expand All @@ -315,7 +323,15 @@ contract Distribution is IDistribution, OwnableUpgradeable, UUPSUpgradeable {

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

return L1Sender(l1Sender).sendDepositToken(gasLimit_, maxFeePerGas_, maxSubmissionCost_);
bytes memory bridgeMessageId_ = L1Sender(l1Sender).sendDepositToken{value: msg.value}(
gasLimit_,
maxFeePerGas_,
maxSubmissionCost_
);

emit OverplusBridged(overplus_, bridgeMessageId_);

return bridgeMessageId_;
}

/**********************************************************************************************/
Expand Down
50 changes: 35 additions & 15 deletions contracts/L1Sender.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,43 @@ 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 {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.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 {IStETH} from "./interfaces/tokens/IStETH.sol";
import {IMOR} from "./interfaces/IMOR.sol";
import {IL1Sender} from "./interfaces/IL1Sender.sol";
import {IWStETH} from "./interfaces/tokens/IWStETH.sol";

contract L1Sender is IL1Sender, ERC165, Ownable {
contract L1Sender is IL1Sender, ERC165, OwnableUpgradeable, UUPSUpgradeable {
address public unwrappedDepositToken;
address public distribution;

DepositTokenConfig public depositTokenConfig;
RewardTokenConfig public rewardTokenConfig;

function setRewardTokenConfig(RewardTokenConfig calldata newConfig_) external onlyOwner {
function L1Sender__init(
address distribution_,
RewardTokenConfig calldata rewardTokenConfig_,
DepositTokenConfig calldata depositTokenConfig_
) external initializer {
__Ownable_init();
__UUPSUpgradeable_init();

setDistribution(distribution_);
setRewardTokenConfig(rewardTokenConfig_);
setDepositTokenConfig(depositTokenConfig_);
}

function setDistribution(address distribution_) public onlyOwner {
distribution = distribution_;
}

function setRewardTokenConfig(RewardTokenConfig calldata newConfig_) public onlyOwner {
rewardTokenConfig = newConfig_;
}

function setDepositTokenConfig(DepositTokenConfig calldata newConfig_) external onlyOwner {
function setDepositTokenConfig(DepositTokenConfig calldata newConfig_) public onlyOwner {
require(newConfig_.receiver != address(0), "L1S: invalid receiver");

DepositTokenConfig storage oldConfig = depositTokenConfig;
Expand Down Expand Up @@ -59,15 +76,14 @@ contract L1Sender is IL1Sender, ERC165, Ownable {
address oldToken_,
address newToken_
) private {
bool isTokenChanged_ = oldToken_ != newToken_;
bool isGatewayChanged_ = oldGateway_ != newGateway_;
bool isAllowedChanged_ = (oldToken_ != newToken_) || (oldGateway_ != newGateway_);

if (oldGateway_ != address(0) && (isTokenChanged_ || isGatewayChanged_)) {
IERC20(oldToken_).approve(oldGateway_, 0);
if (oldGateway_ != address(0) && isAllowedChanged_) {
IERC20(oldToken_).approve(IGatewayRouter(oldGateway_).getGateway(oldToken_), 0);
}

if (isTokenChanged_ || isGatewayChanged_) {
IERC20(newToken_).approve(newGateway_, type(uint256).max);
if (isAllowedChanged_) {
IERC20(newToken_).approve(IGatewayRouter(newGateway_).getGateway(newToken_), type(uint256).max);
}
}

Expand Down Expand Up @@ -96,7 +112,9 @@ contract L1Sender is IL1Sender, ERC165, Ownable {
);
}

function sendMintMessage(address user_, uint256 amount_, address refundTo_) external payable onlyOwner {
function sendMintMessage(address user_, uint256 amount_, address refundTo_) external payable {
require(_msgSender() == distribution, "L1S: invalid sender");

RewardTokenConfig storage config = rewardTokenConfig;

bytes memory receiverAndSenderAddresses_ = abi.encodePacked(config.receiver, address(this));
Expand All @@ -111,4 +129,6 @@ contract L1Sender is IL1Sender, ERC165, Ownable {
bytes("") // adapterParams (see "Advanced Features")
);
}

function _authorizeUpgrade(address) internal view override onlyOwner {}
}
Loading

0 comments on commit b211516

Please sign in to comment.