Matic 项目质押奖励分析

2021-09-21  本文已影响0人  雪落无留痕

本文主要介绍Matic(现为Polygon) 验证者质押、质押代理、奖励分配以及惩罚处理流程。

验证者质押

直接质押

直接质押要求目前验证者人数小于 validatorThreshold, validatorThreshold 初始值为7, 可通过治理更新,目前值为:100。

质押数量需要大于minDeposit, minDeposit 初始值为1 matic, 可通过治理更新, 目前为1 Matic。

质押需要支付手续费用 hemidallFee, 需要大于minHeimdallFee, 其初始值为1matic, 可通过治理更新, 目前为1 matic。

function stake(
    uint256 amount,
    uint256 heimdallFee,
    bool acceptDelegation,
    bytes calldata signerPubkey
) external {
    stakeFor(msg.sender, amount, heimdallFee, acceptDelegation, signerPubkey);
}

质押过程通过NFTContract为验证者铸造validatorId, 验证者从当前周期epoch生效。

若接受代理,则为验证者部署ValidateShare 合约。

竞拍成为验证者

竞拍合约函数:

function startAuction(
    uint256 validatorId,
    uint256 amount,
    bool _acceptDelegation,
    bytes calldata _signerPubkey
) external onlyWhenUnlocked
require(
    validators[validatorId].deactivationEpoch == 0 && currentValidatorAmount != 0,
    "Invalid validator for an auction"
);
  // (auctionPeriod--dynasty)--(auctionPeriod--dynasty)--(auctionPeriod--dynasty)
  currentEpoch.sub(validators[validatorId].activationEpoch) % dynasty.add(auctionPeriod)) < auctionPeriod
function updateDynastyValue(uint256 newDynasty) public onlyGovernance {
    require(newDynasty > 0);
    logger.logDynastyValueChange(newDynasty, dynasty);
    dynasty = newDynasty;
    WITHDRAWAL_DELAY = newDynasty;
    auctionPeriod = newDynasty.div(4);
    // set cooldown period
    replacementCoolDown = currentEpoch.add(auctionPeriod);
}

增加质押

验证者可以调用restake 增加质押量,或者将奖励转为质押。

function restake(
    uint256 validatorId,
    uint256 amount,
    bool stakeRewards
) public onlyWhenUnlocked onlyStaker(validatorId) 

竞拍确认函数:

function confirmAuctionBid(
    uint256 validatorId,
    uint256 heimdallFee /** for new validator */
) external onlyWhenUnlocked 

Heimdall fee

无论验证者经过质押或竞拍成为验证者,都需要支付一定的手续费用Heimdall fee

function _transferAndTopUp(
    address user,
    uint256 fee,
    uint256 additionalAmount
) private {
    require(fee >= minHeimdallFee, "Not enough heimdall fee");
    require(token.transferFrom(msg.sender, address(this), fee.add(additionalAmount)), "Fee transfer failed");
    totalHeimdallFee = totalHeimdallFee.add(fee);
    logger.logTopUpFee(user, fee);
}

minHeimdallFee 初始值为1 Matic, 可通过治理更新, 目前值为1Matic, 推荐大于10。

Heimdall Fee 可以由验证者自己赎回,需要提供Merkle 路径证明,其中accountStateRoot 由每次提交checkpoint时更新。

function claimFee(
    uint256 accumFeeAmount,
    uint256 index,
    bytes memory proof
) public {}

质押退出

function unstake(uint256 validatorId) external onlyStaker(validatorId)

质押赎回

function unstakeClaim(uint256 validatorId) public onlyStaker(validatorId) 
require(
    deactivationEpoch > 0 &&
        deactivationEpoch.add(WITHDRAWAL_DELAY) <= currentEpoch &&
        validators[validatorId].status != Status.Unstaked
);

代理者质押

验证者给代理者奖励分配采用类似AMM模型的机制,由验证者部署ValidatorShare合约,可以看作发行一定数量的代币,总量为10^10个:

function totalSupply() public view returns (uint256) {
    return 10000000000 * 10**uint256(DECIMALS);
}

然后由代理者根据当前的汇率认购:

ExchangeRate = (totalDelegatedPower + delegatorRewardPool) / totalDelegatorShares

汇率是不断变化的,当验证者不断获取奖励的时候,汇率上升;反之若受到惩罚,奖励汇率下降。

质押

当代理者代理质押matic时候,将matic通过汇率转换为可申购的份额:

function _buyShares(uint256 _amount, uint256 _minSharesToMint) private onlyWhenUnlocked returns(uint256) {}

代理者也可以通过调用restake()将所得到的奖励进行再质押。

退出质押

当代理者退出质押的时候,根据当前汇率售出所拥有的份额:

function sellVoucher(uint256 _minClaimAmount) public {}

注:每次提交checkpoint是一个周期。

质押赎回

质押的退出需要等待 WITHDRAWL_DELAY个周期,即目前为80。

function unstakeClaimTokens() public {
   ...
   require(delegator.withdrawEpoch.add(stakeManager.withdrawalDelay()) <= stakeManager.epoch() && shares > 0, "Incomplete withdrawal period");
   ...
}

奖励

Checkpoint 奖励

CHECKPOINT_REWARD checkpoint奖励的上限,初始为20188个matic, 可以通过治理更新, 目前值为:107163。

checkPointBlockInterval 初始值设为1024,可通过治理更新, 目前值为:5120。

proposerBouns 初始值为10,可通过治理进行更新,值小于等于100,目前值为10:

maxRewardsCheckpoints: 可通过治理更新, 目前值为:3

checkpointRewardDelta : 可通过治理更新,目前值为:10

rewardDecreasePerCheckpoint: 可通过治理更新,目前值为:30

CHK_REWARD_PRECISION: 值为100

计算过程:

计算 fullIntervals:
fullIntervals = Math.min(\frac{blockInterval}{targetBlockInterval}, maxRewardedCheckpoints);
其中 blockInterval为当前是checkpoint的包括的块数, targetBlockInterval = checkpointBlockInterval

chkReward初始值:
ckpReward = CHECKPOINT\_REWARD;
然后计算 delta:
delta = ckpReward * \frac {checkpointRewardDelta}{CHK\_REWARD\_PRECISION};
更新 ckpReward:

// 
if (prevBlockInterval > fullIntervals) {  // 若checkpoint比上次提交的更快
    // checkpoint is faster
    ckpReward += delta;
} else {
    ckpReward -= delta;
}

blockInterval > targetBlockInterval, ckpReward 执行下面的更新:
reward = ckpReward*fullIntervals - ckpReward * \frac{(fullIntervals - 1) * fullIntervals}{2 * CHK\_REWARD\_PRECISION}* rewardDecreasePerCheckpoint \\ \\ blockInterval = blockInterval - fullIntervals * targetBlockInterval \\ \\ ckpReward = ckpReward - \frac{ckpReward * fullIntervals * rewardDecreasePerCheckpoint}{CHK\_REWARD\_PRECISION }
最终该checkPoint 得到 reward 为:
reward = reward + \frac{blockInterval}{targetBlockInterval} * ckpReward \\ reward = reward * \frac{signedStakePower}{currentTotalStake}

提交checkPoint的Bonus分配

proposerBonus = reward * \frac{proposerBonus}{MAX\_PROPOSER\_BONUS}

其中 proposerBonus 为通过治理更新的参数,目前值为10. MAX_PROPOSER_BOUNS 值为100

        proposer.reward = proposer.reward.add(proposerBonus);

proposerBonus奖励全部给予 proposer

剩余奖励分配

主要分为以下三个步骤:

(1) 计算每份质押的奖励
newRewardPerStake = rewardPerStake + (reward - proposerBouns) * \frac{REWARD\_PRECISION}{signedStakePower}
其中 rewardPerStake 为上一个checkpoint执行后得到每份质押的奖励,signedStakePower为此次checkpoint所有签名者的质押。REWARD\_PRECIISION 为固定值, 值为10^{25}, 即 10^{7} matic.

(2) 分发非签名验证者的奖励,并更新initialRewardPerStake

// evaluate rewards for validator who did't sign and set latest reward per stake to new value to avoid them from getting new rewards.
_updateValidatorsRewards(unsignedValidators, totalUnsignedValidators, newRewardPerStake);

(3) 分发签名验证者的奖励

// distribute rewards between signed validators
rewardPerStake = newRewardPerStake;

(4) 分发已经在退出质押的签名验证者的奖励

// evaluate rewards for unstaked validators to avoid getting new rewards until they claim their stake
_updateValidatorsRewards(deactivatedValidators, totalDeactivatedValidators, newRewardPerStake);

代理者奖励

分给完Bonus后,剩余奖励根据质押比例,分别对每个签名验证者根据质押总量比例进行奖励分配;然后每个验证者然后根据其代理者质押比例再进行分配。

    function checkSignature(
        uint256 checkpointStakePower,
        uint256 reward,
        bytes32 voteHash,
        bytes memory sigs
    ) internal returns (uint256)

在手续费commisionRate大于0的情况下,给委托者的奖励需要先扣除手续费,然后再根据质押比较比例分配给代理者。

惩罚机制

惩罚包括两个过程: (1)惩罚作恶验证者;(2)奖励提出者

function updateSlashedAmounts(bytes memory data, bytes memory sigs) public {}

slash

     function unjail(uint256 validatorId) public onlyStaker(validatorId)

Bounty

奖励的金额为总的惩罚金额的乘以 reportRate 比例,reportRate 初始值为5, 可由管理员更新,其余到的转到合约中。合约的金额可以由管理员取款。

uint256 bounty = (slashedAmount.mul(reportRate)).div(100);

若调用合约者 和 proposer为不同的地址,则两者均分,否则都转给合约调用者。

参考

https://github.com/maticnetwork/contracts

https://docs.matic.network/docs/validate/orientation/

https://docs.matic.network/docs/develop/network-details/genesis-contracts/

https://etherscan.io/address/0x5e3Ef299fDDf15eAa0432E6e66473ace8c13D908#readProxyContract

https://github.com/itinance/openzeppelin-solidity/blob/master/contracts/token/ERC721/ERC721Enumerable.sol

上一篇 下一篇

猜你喜欢

热点阅读