# LP质押奖励合约
目前 LP 质押奖励合约部署币安智能链测试网,打开 [Binance Smart Chain Testnet RPC and Chain settings | Chainlist](https://chainlist.org/zh/chain/97) 可将测试网络添加到 MetaMask 钱包。用户可以把 PancakeSwap 的 **tBNB-SIE LP** 代币或者 **tBNB-GAS LP** 代币质押到合约,系统会按照每个人的质押权重计算 **SIE** 代币奖励。合约地址列表如下:
* SIE 合约地址:`0xe29d4e3ca2dc5e91729c508fce5a3e20ed2c34ea`
* GAS 合约地址:`0x22d263c324c4613f09c7a8a9f8fa0d3cdc03f0d1`
* PancakeSwap tBNB-SIE LP(在BNB/SIE交易对添加流动性获得此代币):`0x32a829bbc5b3ced5cf76108ce537e4f9be3bbdb9`
* PancakeSwap tBNB-SIE LP 质押合约:`0x4D53fba2Ee413283E902176316858AB1aB522563`
* PancakeSwap tBNB-GAS LP(在BNB/GAS交易对添加流动性获得此代币):`0x1d9d1be6d1ec2319c8b90a5107d5421b557312cf`
* PancakeSwap tBNB-GAS LP 质押合约:`0xA0c96CE5984D3949eAdD517C2E2cD852104941C0`
PancakeSwap 测试网地址:[Home | PancakeSwap - $4.075](https://pancakeswap.finance/?chainId=97)
## 方法列表
### 查询方法
查询方法不会修改合约状态,通常使用 [eth_call](https://www.quicknode.com/docs/ethereum/eth_call) RPC 接口进行调用,当前可用的查询方法列表如下:
* `startBlock() uint256` 返回开始计算奖励的区块高度。值为 0 时合约未初始化,当前区块高度大于等于此值时开始计算奖励。
* `endBlock() uint256` 返回结束计算奖励的区块高度。值为 0 时合约未初始化,当前区块高度大于等于此值时结束计算奖励。
* `poolInfo(uint256 pid) PoolInfo` 返回指定池子信息(`accTokenPerShare uint128, lastRewardBlock uint64, allocPoint uint64, totalStaked uint256`)。`lastRewardBlock` 表示上次奖励的区块高度,`allocPoint` 表示池子的奖励点数。
* `totalAllocPoint() uint256` 返回所有池子的总计奖励点数,每个池子会根据奖励点数权重分配 **SIE** 代币奖励。
* `pendingReward(uint256 pid, address user) uint256` 返回用户在指定池子的未领取的 **SIE** 代币奖励数量。
* `userInfo(uint256 pid, address user) UserInfo` 返回用户在指定池子的质押信息(`amount uint256, rewardDebt int256`)。`amount` 表示质押代币数量。
* `tokenPerBlock() uint128` 返回每个区块奖励代币的总数量,根据每个池子的奖励点数分配给每个池子的质押用户。
在线合约工具:[StakingSharedPoolL2 | Address 0x4D53fba2Ee413283E902176316858AB1aB522563 | BscScan](https://testnet.bscscan.com/address/0x4D53fba2Ee413283E902176316858AB1aB522563#readContract)
### 写入方法
* `stake(uint256 pid, uint256 amount, address to)` 质押代币到指定池子。`pid` 表示池子的ID,`amount` 表示质押的数量,`to` 表示用户的地址。**注意**:调用此接口之前必须确保质押合约拥有用户足额的代币授权,参考 [ERC-20 Token Standard | ethereum.org](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/) 中 `approve` 方法。
* `unstake(uint256 pid, uint256 amount, address to)` 解除代币质押。`pid` 表示池子的ID,`amount` 表示质押的数量,`to` 表示用户到账地址。
* `claim(uint256 pid, address to)` 领取质押奖励。`pid` 表示池子的ID,`to` 表示用户到账地址。
* `unstakeAndClaim(uint256 pid, uint256 amount, address to)` 解除代币质押并领取质押奖励。`pid` 表示池子的ID,`amount` 表示质押的数量,`to` 表示用户到账地址。
在线合约工具:[StakingSharedPoolL2 | Address 0x4D53fba2Ee413283E902176316858AB1aB522563 | BscScan](https://testnet.bscscan.com/address/0x4D53fba2Ee413283E902176316858AB1aB522563#writeContract)
## 合约ABI
**ERC20**:https://gist.github.com/veox/8800debbf56e24718f9f483e1e40c35c
**StakingSharedPoolL2**:[StakingSharedPoolL2 | Address 0x4D53fba2Ee413283E902176316858AB1aB522563 | BscScan](https://testnet.bscscan.com/address/0x4D53fba2Ee413283E902176316858AB1aB522563#code)
## 计算规则
**Annual Percentage Rate (APR)**
1. 查询Total Staked并将单位转换为美元
2. 查询Today’s Rewards并将单位转换为美元
3. 用第二步计算的值除以第一步计算的值然后乘以365
**Total Rewards**
```js
let blocks = StakingSharedPoolL2.endBlock() - StakingSharedPoolL2.startBlock()
let tokenPerBlock = StakingSharedPoolL2.tokenPerBlock()
let allocPoint = StakingSharedPoolL2.pollInfo(pid).allocPoint;
return tokenPerBlock * blocks * (allocPoint / StakingSharedPoolL2.totalAllocPoint())
```
**Today's Rewards**
每个区块奖励数量乘以每天产生的区块数(币安链三秒产生一个区块)
```js
let tokenPerBlock = StakingSharedPoolL2.tokenPerBlock()
let allocPoint = StakingSharedPoolL2.pollInfo(pid).allocPoint;
return tokenPerBlock * (allocPoint / StakingSharedPoolL2.totalAllocPoint()) * (60 * 60 * 24 / 3)
```
**Total Staked**
1. 调用质押ERC20代币合约查询StakingSharedPoolL2合约地址的余额,比如查询SIE LP质押数量:
`let balance = ERC20(0x32a829bbc5b3ced5cf76108ce537e4f9be3bbdb9).balanceOf(0x90c8ed1d838253e24d41983d6bc55674a4a27370)`
2. 用质押合约的SIE LP余额除以SIE LP的总发行量,然后乘以SIE LP的SIE余额:
```
let totalSupply = ERC20(0x32a829bbc5b3ced5cf76108ce537e4f9be3bbdb9).totalSupply()
return (balance / totalSupply) * ERC20(0xe29d4e3ca2dc5e91729c508fce5a3e20ed2c34ea).balanceOf(0x32a829bbc5b3ced5cf76108ce537e4f9be3bbdb9)
```
**Staking Period**
`(StakingSharedPoolL2.endBlock - StakingSharedPoolL2.startBlock) * 3 / (60 * 60 * 24)`
**Your stake percentage**
`StakingSharedPoolL2.userInfo(pid, user).amount / StakingSharedPoolL2.poolInfo(pid).totalStaked`
**Ends in**
使用 RPC 接口 `eth_blockNumber` 获取当前区块高度。
`(StakingSharedPoolL2.endBlock - currentBloack) * 3 / (60 * 60 * 24)`
## 参考资料
[blockchain - web3 - 使用metamask 调用某个contract 的方法 - 申思维的技术站点-ruby/rails/titanium/敏捷方法论/测试驱动/自动化/全栈攻城狮/jquery/极客/直男 (siwei.me)](http://siwei.me/blog/posts/blockchain-web3-metamask-contract)