1 质押挖矿的3个时期
? ? SushiSwap支持质押挖矿,它有3个时期:激励期、普通期、交叉期。激励期的奖励倍数为10,普通期的奖励倍数为1,交叉期的奖励倍数不固定。 ? ? 这3个时期是通过区块高度来进行区分的,不同时期的倍乘系数multiplier也不相同。 ? ? 在 MasterChef.sol合约里,通过getMultiplier()函数来计算倍乘系数multiplier,其计算方式如下:
function getMultiplier(uint256 _from, uint256 _to)
public
view
returns (uint256)
{
if (_to <= bonusEndBlock) {
return _to.sub(_from).mul(BONUS_MULTIPLIER);
} else if (_from >= bonusEndBlock) {
return _to.sub(_from);
} else {
return
bonusEndBlock.sub(_from).mul(BONUS_MULTIPLIER).add(
_to.sub(bonusEndBlock)
);
}
}
? ? 写成公式如下:
m
u
l
t
i
p
l
i
e
r
(
m
,
n
)
=
{
(
n
?
m
)
?
B
o
n
u
s
,
n?>?m?>?e?,?
??
激励期
n
?
m
,
e
>
n
>
m
,
??
普
通
期
(
e
?
m
)
?
B
o
n
u
s
+
n
?
e
,
n
>
e
>
m
,
??
交
叉
期
multiplier(m,n)= \begin{cases} (n-m)*Bonus, & \text{n > m > e , \;激励期} \\ n-m , & e > n> m , \;普通期\\ (e - m)*Bonus+n-e, & n > e > m , \;交叉期 \end{cases}
multiplier(m,n)=??????(n?m)?Bonus,n?m,(e?m)?Bonus+n?e,?n?>?m?>?e?,?激励期e>n>m,普通期n>e>m,交叉期?
? ? 倍乘系数 multiplier 与起点区块高度、终点区块高度、奖励截止高度、固定奖励系数这4个参数有关。 ? ? 在cn.etherscan.com里查询 MasterChef的部署参数可知,如图(1)所示:
图(1) MasterChef合约的部署参数
变量 | 含义 | 默认参数 |
---|
m | 质押时(deposit)的区块高度 | 未知数m | n | 提取时(withdraw)的区块高度 | 未知数n | s | 奖励起点区块高度 | 1075000 | e | 奖励截止区块高度 | 1085000 | Bonus | 固定奖励系数 | 100枚Sushi |
? ? 由图(1)可知,MasterChef在以太坊上的质押挖矿,用区块高度分为3个时期:
- 激励期:质押和提取,都在1075万~1085万区块高度内,即
m
、
n
∈
[
1075
w
,
1085
w
]
m、n \in [1075w, 1085w]
m、n∈[1075w,1085w],区块奖励 = 固定奖励x10 = 100x10 = 1000枚Sushi,固定。
- 普通期:质押和提取,都在1085万区块高度之上,即
m
、
n
∈
(
1085
w
,
+
∞
)
m、n \in (1085w,+\infty)
m、n∈(1085w,+∞), 区块奖励 = 固定奖励 = 100枚Sushi,固定。
- 交叉期:质押在[1075万, 1085万]区块高度内,提取在1085万区块高度之后,即
m
∈
[
1075
w
,
1085
w
]
,
n
∈
(
1085
w
,
+
∞
)
m \in [1075w, 1085w] , n \in (1085w,+\infty)
m∈[1075w,1085w],n∈(1085w,+∞)
,区块奖励 = 100或1000枚Sushi,不固定。
? ? 需要说明的是,这里的区块奖励,指的是每挖出一个区块,奖励的Sushi代币个数。
2 质押与提取
2.1 质押deposit
? ? MasterChef.sol的deposit()函数,用于将lpToken发送到MasterChef合约地址,同时将用户的待入账奖励币SuShi发送到用户地址,并发送质押事件给其他程序。
function deposit(uint256 _pid, uint256 _amount) public {
PoolInfo storage pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][msg.sender];
console.log("pid= %s, msg.sender= %s",_pid, msg.sender);
updatePool(_pid);
if (user.amount > 0) {
uint256 pending =
user.amount.mul(pool.accSushiPerShare).div(1e12).sub(
user.rewardDebt
);
safeSushiTransfer(msg.sender, pending);
}
pool.lpToken.safeTransferFrom(
address(msg.sender),
address(this),
_amount
);
user.amount = user.amount.add(_amount);
user.rewardDebt = user.amount.mul(pool.accSushiPerShare).div(1e12);
emit Deposit(msg.sender, _pid, _amount);
}
2.2 提取withdraw
? ? MasterChef.sol的withdraw()函数,用于提取本金lpToken与奖励币Sushi到用户地址,同时更新用户的账户余额amount与账务值rewardDebt,并发送提取事件给其他程序。
function withdraw(uint256 _pid, uint256 _amount) public {
PoolInfo storage pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][msg.sender];
require(user.amount >= _amount, "withdraw: not good");
updatePool(_pid);
uint256 pending =
user.amount.mul(pool.accSushiPerShare).div(1e12).sub(
user.rewardDebt
);
safeSushiTransfer(msg.sender, pending);
user.amount = user.amount.sub(_amount);
user.rewardDebt = user.amount.mul(pool.accSushiPerShare).div(1e12);
pool.lpToken.safeTransfer(address(msg.sender), _amount);
emit Withdraw(msg.sender, _pid, _amount);
}
|