Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add base implementation #40

Open
wants to merge 9 commits into
base: fix/session-approval-delegation
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 24 additions & 18 deletions smart-contracts/contracts/delegate/DelegatorFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,26 @@ import {UpgradeableBeacon} from "@openzeppelin/contracts/proxy/beacon/Upgradeabl
import {BeaconProxy} from "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";

import {IProvidersDelegator} from "../interfaces/delegate/IProvidersDelegator.sol";
import {IDelegatorFactory} from "../interfaces/delegate/IDelegatorFactory.sol";
import {IOwnable} from "../interfaces/utils/IOwnable.sol";

contract DelegatorFactory is OwnableUpgradeable, PausableUpgradeable, UUPSUpgradeable {
contract DelegatorFactory is IDelegatorFactory, OwnableUpgradeable, PausableUpgradeable, UUPSUpgradeable {
address public lumerinDiamond;
address public beacon;
mapping(address => address[]) public proxies;
RuslanProgrammer marked this conversation as resolved.
Show resolved Hide resolved

event ProxyDeployed(address indexed proxyAddress);
event ImplementationUpdated(address indexed newImplementation);

constructor() {
_disableInitializers();
}

function DelegatorFactory_init(address _lumerinDiamond, address _implementation) external initializer {
function DelegatorFactory_init(address lumerinDiamond_, address implementation_) external initializer {
__Pausable_init();
__Ownable_init();
__UUPSUpgradeable_init();

lumerinDiamond = _lumerinDiamond;
lumerinDiamond = lumerinDiamond_;

beacon = address(new UpgradeableBeacon(_implementation));
beacon = address(new UpgradeableBeacon(implementation_));
}

function pause() external onlyOwner {
Expand All @@ -45,23 +43,33 @@ contract DelegatorFactory is OwnableUpgradeable, PausableUpgradeable, UUPSUpgrad
address feeTreasury_,
uint256 fee_,
string memory name_,
string memory endpoint_
string memory endpoint_,
uint128 deregistrationTimeout_,
uint128 deregistrationNonFeePeriod_
) external whenNotPaused returns (address) {
bytes32 salt_ = _calculatePoolSalt(_msgSender());
address proxy_ = address(new BeaconProxy{salt: salt_}(beacon, bytes("")));
FedokDL marked this conversation as resolved.
Show resolved Hide resolved

proxies[_msgSender()].push(address(proxy_));
proxies[_msgSender()].push(proxy_);

IProvidersDelegator(proxy_).ProvidersDelegator_init(lumerinDiamond, feeTreasury_, fee_, name_, endpoint_);
IProvidersDelegator(proxy_).ProvidersDelegator_init(
lumerinDiamond,
feeTreasury_,
fee_,
name_,
endpoint_,
deregistrationTimeout_,
deregistrationNonFeePeriod_
);
IOwnable(proxy_).transferOwnership(_msgSender());

emit ProxyDeployed(address(proxy_));
emit ProxyDeployed(proxy_);

return address(proxy_);
return proxy_;
}

function predictProxyAddress(address _deployer) external view returns (address) {
bytes32 salt_ = _calculatePoolSalt(_deployer);
function predictProxyAddress(address deployer_) external view returns (address) {
bytes32 salt_ = _calculatePoolSalt(deployer_);

bytes32 bytecodeHash_ = keccak256(
abi.encodePacked(type(BeaconProxy).creationCode, abi.encode(address(beacon), bytes("")))
Expand All @@ -70,10 +78,8 @@ contract DelegatorFactory is OwnableUpgradeable, PausableUpgradeable, UUPSUpgrad
return Create2.computeAddress(salt_, bytecodeHash_);
}

function updateImplementation(address _newImplementation) external onlyOwner {
UpgradeableBeacon(beacon).upgradeTo(_newImplementation);

emit ImplementationUpdated(_newImplementation);
function updateImplementation(address newImplementation_) external onlyOwner {
UpgradeableBeacon(beacon).upgradeTo(newImplementation_);
}

function version() external pure returns (uint256) {
Expand Down
85 changes: 52 additions & 33 deletions smart-contracts/contracts/delegate/ProvidersDelegator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,34 +16,26 @@ contract ProvidersDelegator is IProvidersDelegator, OwnableUpgradeable {
using SafeERC20 for IERC20;
using Math for uint256;

/**
* @dev The Lumerin protocol data
*/
address public lumerinDiamond;
address public token;

/**
* @dev The fee data
*/
address public feeTreasury;
uint256 public fee;

/**
* @dev Provider metadata
*/
string public name;
string public endpoint;


/**
* @dev The main contract logic data
*/
uint256 public totalStaked;
uint256 public totalRate;
uint256 public lastContractBalance;
bool public isStakeClosed;
mapping(address => Staker) public stakers;

uint128 public deregistrationOpenAt;
RuslanProgrammer marked this conversation as resolved.
Show resolved Hide resolved
uint128 public deregistrationTimeout;
uint128 public deregistrationNonFeeOpened;
uint128 public deregistrationNonFeePeriod;

constructor() {
_disableInitializers();
}
Expand All @@ -53,7 +45,9 @@ contract ProvidersDelegator is IProvidersDelegator, OwnableUpgradeable {
address feeTreasury_,
uint256 fee_,
string memory name_,
string memory endpoint_
string memory endpoint_,
uint128 deregistrationTimeout_,
uint128 deregistrationNonFeePeriod_
) external initializer {
__Ownable_init();

Expand All @@ -62,9 +56,18 @@ contract ProvidersDelegator is IProvidersDelegator, OwnableUpgradeable {

setName(name_);
setEndpoint(endpoint_);
setFee(feeTreasury_, fee_);
setFeeTreasury(feeTreasury_);

if (fee_ > PRECISION) {
revert InvalidFee(fee_, PRECISION);
}
fee = fee_;

IERC20(token).approve(lumerinDiamond_, type(uint256).max);

deregistrationTimeout = deregistrationTimeout_;
deregistrationOpenAt = uint128(block.timestamp) + deregistrationTimeout_;
deregistrationNonFeePeriod = deregistrationNonFeePeriod_;
}

function setName(string memory name_) public onlyOwner {
Expand All @@ -87,18 +90,14 @@ contract ProvidersDelegator is IProvidersDelegator, OwnableUpgradeable {
emit EndpointUpdated(endpoint_);
}

function setFee(address feeTreasury_, uint256 fee_) public onlyOwner {
function setFeeTreasury(address feeTreasury_) public onlyOwner {
if (feeTreasury_ == address(0)) {
revert InvalidFeeTreasuryAddress();
}
if (fee_ > PRECISION) {
revert InvalidFee(fee_, PRECISION);
}

fee = fee_;
feeTreasury = feeTreasury_;

emit FeeUpdated(fee_, feeTreasury_);
emit FeeTreasuryUpdated(feeTreasury_);
}

function setIsStakeClosed(bool isStakeClosed_) public onlyOwner {
Expand All @@ -117,10 +116,11 @@ contract ProvidersDelegator is IProvidersDelegator, OwnableUpgradeable {
if (isStakeClosed) {
revert StakeClosed();
}

if (amount_ == 0) {
revert InsufficientAmount();
}

address user_ = _msgSender();
Staker storage staker = stakers[user_];

Expand Down Expand Up @@ -168,6 +168,7 @@ contract ProvidersDelegator is IProvidersDelegator, OwnableUpgradeable {

staker.rate = currentRate_;
staker.staked += amount_;
staker.claimed += amount_;
staker.pendingRewards = pendingRewards_ - amount_;

IProviderRegistry(lumerinDiamond).providerRegister(address(this), amount_, endpoint);
Expand All @@ -192,9 +193,10 @@ contract ProvidersDelegator is IProvidersDelegator, OwnableUpgradeable {

staker.rate = currentRate_;
staker.pendingRewards = pendingRewards_ - amount_;
staker.claimed += amount_;

uint256 feeAmount_ = (amount_ * fee) / PRECISION;
if (feeAmount_ != 0) {
if (feeAmount_ != 0 && block.timestamp > deregistrationNonFeeOpened + deregistrationNonFeePeriod) {
IERC20(token).safeTransfer(feeTreasury, feeAmount_);

amount_ -= feeAmount_;
Expand All @@ -221,25 +223,42 @@ contract ProvidersDelegator is IProvidersDelegator, OwnableUpgradeable {
}

function getCurrentStakerRewards(address staker_) public view returns (uint256) {
Staker memory staker = stakers[staker_];
(uint256 currentRate_,) = getCurrentRate();
(uint256 currentRate_, ) = getCurrentRate();

return _getCurrentStakerRewards(currentRate_, staker);
return _getCurrentStakerRewards(currentRate_, stakers[staker_]);
}

function providerDeregister() external onlyOwner {
function providerDeregister(bytes32[] calldata bidIds_) external {
if (block.timestamp < deregistrationOpenAt) {
_checkOwner();
} else {
deregistrationOpenAt = uint128(block.timestamp) + deregistrationTimeout;
}

_deleteModelBids(bidIds_);
IProviderRegistry(lumerinDiamond).providerDeregister(address(this));

deregistrationNonFeeOpened = uint128(block.timestamp);
}

function postModelBid(
bytes32 modelId_,
uint256 pricePerSecond_
) external onlyOwner returns (bytes32) {
function postModelBid(bytes32 modelId_, uint256 pricePerSecond_) external onlyOwner returns (bytes32) {
return IMarketplace(lumerinDiamond).postModelBid(address(this), modelId_, pricePerSecond_);
}

function deleteModelBid(bytes32 bidId_) external onlyOwner {
return IMarketplace(lumerinDiamond).deleteModelBid(bidId_);
function deleteModelBids(bytes32[] calldata bidIds_) external {
if (block.timestamp < deregistrationOpenAt) {
_checkOwner();
}

_deleteModelBids(bidIds_);
}

function _deleteModelBids(bytes32[] calldata bidIds_) private {
address lumerinDiamond_ = lumerinDiamond;

for (uint256 i = 0; i < bidIds_.length; i++) {
IMarketplace(lumerinDiamond_).deleteModelBid(bidIds_[i]);
}
}

function _getCurrentStakerRewards(uint256 delegatorRate_, Staker memory staker_) private pure returns (uint256) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

interface IDelegatorFactory {
event ProxyDeployed(address indexed proxyAddress);
FedokDL marked this conversation as resolved.
Show resolved Hide resolved
event ImplementationUpdated(address indexed newImplementation);
FedokDL marked this conversation as resolved.
Show resolved Hide resolved

/**
* The function to initialize the contract.
* @param lumerinDiamond_ The Lumerin protocol address.
* @param implementation_ The implementation address.
*/
function DelegatorFactory_init(address lumerinDiamond_, address implementation_) external;

/**
* Triggers stopped state.
*/
function pause() external;
RuslanProgrammer marked this conversation as resolved.
Show resolved Hide resolved

/**
* Returns to normal state.
*/
function unpause() external;

/**
* The function to deploy the new proxy contract.
* @param feeTreasury_ The subnet fee treasury.
* @param fee_ The fee percent where 100% = 10^25.
* @param name_ The Subnet name.
* @param endpoint_ The subnet endpoint.
* @param deregistrationTimeout_ Provider deregistration will be available after this timeout.
* @param deregistrationNonFeePeriod_ Period after deregistration when Stakers can claim rewards without fee.
*/
function deployProxy(
FedokDL marked this conversation as resolved.
Show resolved Hide resolved
address feeTreasury_,
uint256 fee_,
string memory name_,
string memory endpoint_,
uint128 deregistrationTimeout_,
uint128 deregistrationNonFeePeriod_
) external returns (address);

/**
* The function to predict new proxy address.
* @param _deployer The deployer address.
*/
function predictProxyAddress(address _deployer) external view returns (address);
FedokDL marked this conversation as resolved.
Show resolved Hide resolved

/**
* The function to upgrade the implementation.
* @param _newImplementation The new implementation address.
*/
function updateImplementation(address _newImplementation) external;

/**
* The function to get contract version.
*/
function version() external pure returns (uint256);
}
Loading