簡體   English   中英

嘿,有人可以向我解釋一下這個智能合約嗎 - LP Staking Contract

[英]Hey Can someone explain something about this Smart contract to me - LP Staking Contract

嘿,所以我正在通過 github 尋找 LP staking 智能合約,我遇到了這個

// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";

contract StakingV2 is Ownable {
    using SafeMath for uint;
    using SafeERC20 for IERC20;

    struct Stake {
        uint amount;
        uint stakeTime;
        uint fraction;
        uint rewardOut;
    }

    mapping(uint => mapping(address => Stake)) public stakes;

    // Info of each pool.
    struct Pool {
        uint rewardAmount; // Pool reward tokens limit
        uint startTime;
        uint endTime;
        uint total;
        uint freezeTime;
        uint freezePercent;
    }

    Pool[] public pools;

    address public stakeToken; // Uniswap LP token from pool MRCH/USDT
    address public rewardToken; // MRCH token

    event AddPool(uint pid, uint reward, uint startTime, uint endTime, uint freezeTime, uint percent);
    event PoolTotal(uint pid, uint oldTotal, uint newTotal);
    event StakerFraction(uint pid, address staker, uint oldFraction, uint newFraction);
    event Staked(uint pid, address staker, uint amount);
    event RewardOut(uint pid, address staker, address token, uint amount);

    constructor(
        address stakeToken_,
        address rewardToken_
    ) {
        require(stakeToken_ != address(0), "MRCHStaking::constructor: stake token address is 0x0");
        stakeToken = stakeToken_;

        require(rewardToken_ != address(0), "MRCHStaking::constructor: reward token address is 0x0");
        rewardToken = rewardToken_;
    }

    function addPool(uint rewardAmount_, uint startTime_, uint endTime_, uint freezeTime_, uint freezePercent_) public onlyOwner {
        require(getTimeStamp() <= startTime_, "MRCHStaking::addPool: bad timing for the request");
        require(startTime_ < endTime_, "MRCHStaking::addPool: endTime > startTime");

        doTransferIn(msg.sender, rewardToken, rewardAmount_);

        pools.push(
            Pool({
                rewardAmount: rewardAmount_,
                startTime: startTime_,
                endTime: endTime_,
                total: 0,
                freezeTime: freezeTime_,
                freezePercent: freezePercent_ // scaled by 1e18, for example 5% = 5e18, 0.01% = 1e16
            })
        );

        emit AddPool(pools.length - 1, rewardAmount_, startTime_, endTime_, freezeTime_, freezePercent_);
    }

    function stake(uint pid, uint amount) public returns (bool) {
        require(amount > 0, "MRCHStaking::stake: amount must be positive");

        uint timeStamp = getTimeStamp();
        require(timeStamp < pools[pid].endTime, "MRCHStaking::stake: bad timing for the request");

        address staker = msg.sender;

        doTransferIn(staker, stakeToken, amount);

        // Transfer is completed
        stakes[pid][staker].amount = stakes[pid][staker].amount.add(amount);

        uint addition;

        if (timeStamp < pools[pid].startTime) {
            stakes[pid][staker].stakeTime = pools[pid].startTime;
            addition = (pools[pid].endTime.sub(pools[pid].startTime)).mul(amount);
        } else {
            stakes[pid][staker].stakeTime = timeStamp;
            addition = (pools[pid].endTime.sub(timeStamp)).mul(amount);
        }

        uint oldFraction = stakes[pid][staker].fraction;
        stakes[pid][staker].fraction = stakes[pid][staker].fraction.add(addition);

        uint oldTotal = pools[pid].total;
        pools[pid].total = pools[pid].total.add(addition);

        emit Staked(pid, staker, amount);
        emit StakerFraction(pid, staker, oldFraction, stakes[pid][staker].fraction);
        emit PoolTotal(pid, oldTotal, pools[pid].total);

        return true;
    }

    function withdraw(uint pid) public returns (bool) {
        require(claim(pid), "MRCHStaking::withdraw: claim error");

        uint amount = stakes[pid][msg.sender].amount;

        return withdrawWithoutReward(pid, amount);
    }

    function withdrawWithoutReward(uint pid, uint amount) public returns (bool) {
        return withdrawInternal(pid, msg.sender, amount);
    }

    function withdrawInternal(uint pid, address staker, uint amount) internal returns (bool) {
        require(amount > 0, "MRCHStaking::withdrawInternal: amount must be positive");
        require(amount <= stakes[pid][msg.sender].amount, "MRCHStaking::withdrawInternal: not enough balance");

        stakes[pid][staker].amount = stakes[pid][staker].amount.sub(amount);

        uint freezeTime = stakes[pid][staker].stakeTime.add(pools[pid].freezeTime);

        if (getTimeStamp() < freezeTime) {
            uint freezeAmount = amount.mul(pools[pid].freezePercent).div(100);
            amount = amount.sub(freezeAmount);
        }

        doTransferOut(stakeToken, staker, amount);

        return true;
    }

    function claim(uint pid) public returns (bool) {
        require(getTimeStamp() > pools[pid].endTime, "MRCHStaking::claim: bad timing for the request");

        address staker = msg.sender;

        uint rewardAmount = currentTotalReward(pid, staker);

        if (rewardAmount == 0) {
            return true;
        }

        doTransferOut(rewardToken, staker, rewardAmount);

        stakes[pid][staker].rewardOut = stakes[pid][staker].rewardOut.add(rewardAmount);

        emit RewardOut(pid, staker, rewardToken, rewardAmount);

        return true;
    }

    function currentTotalReward(uint pid, address staker) public view returns (uint) {
        uint totalRewardAmount = pools[pid].rewardAmount;
        uint total = pools[pid].total;

        if (total == 0) {
            return 0;
        }

        uint fraction = stakes[pid][staker].fraction;
        uint rewardOut = stakes[pid][staker].rewardOut;

        uint rewardAmount = totalRewardAmount.mul(fraction).div(total);

        return rewardAmount.sub(rewardOut);
    }

    function doTransferOut(address token, address to, uint amount) internal {
        if (amount == 0) {
            return;
        }

        IERC20 ERC20Interface = IERC20(token);
        ERC20Interface.safeTransfer(to, amount);
    }

    function doTransferIn(address from, address token, uint amount) internal {
        IERC20 ERC20Interface = IERC20(token);
        ERC20Interface.safeTransferFrom(from, address(this), amount);
    }

    function transferTokens(address token, address to, uint amount) public onlyOwner {
        doTransferOut(token, to, amount);
    }

    function getTimeStamp() public view virtual returns (uint) {
        return block.timestamp;
    }

    function getPoolLength() public view returns(uint) {
        return pools.length;
    }
}

所以在成功部署到 rinkeby 測試網后,我不確定這意味着什么(其中一些)。

所以我知道一個事實,rewardAmount_ - 是每個區塊將分配多少獎勵。

startTime_ 是池應該開始的時間(例如您可以使用https://www.epochconverter.com/的日期和時間。

startTime_是合約停止分配獎勵的時間。

凍結時間就像鎖定令牌,所以當用戶嘗試在凍結時間之前取出時,他們將無法取出。

凍結百分比是 Apy,它會隨着時間的推移而降低。

我不太了解它,所以如果錯了,請糾正。 我在這里的原因是; 如果我對 freezetime 和 freezepercentage 的理解是正確的,我將如何做到這一點或將其輸入到該字段中。

我知道可以像這樣輸入 freezePercentage 5% = 5e18。

但是 freezeTime 呢?

如果有人有更好的理解,請與我分享

要回答您的問題:

我知道可以像這樣輸入 freezePercentage 5% = 5e18。 -這是正確的。 您可以將百分比作為整數輸入並按此處理,例如,5 將是 0.05

但是凍結時間呢? 凍結時間是質押 LP 代幣凍結部分可以以 unix 時間戳格式釋放的結束日期。 在這種情況下,當有人提取他們的質押時,如果您使用 AddPool 創建池,並在凍結時間輸入諸如“1679505397(2023 年 3 月)”之類的值,它將提取他們的質押減去凍結的金額,在這種情況下上面,它被硬編碼為 5%。 例如,我質押了 10 個 LP 代幣。 我選擇今天提現,但我只會取回9.5,因為凍結百分比是5,並且時間戳小於凍結時間。 我將不得不等到 2023 年 3 月才能撤回最終的 0.5。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM