20230325cakeifo代碼實(shí)現(xiàn)示例及我的理解及注釋

// SPDX-License-Identifier: MIT

pragma solidity ^0.6.12;

import "@openzeppelin/contracts/access/Ownable.sol";

import "@openzeppelin/contracts/math/SafeMath.sol";

import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";

import "profile-nft-gamification/contracts/PancakeProfile.sol";

import "./interfaces/IIFOV2.sol";

import "pancake-cake-vault/contracts/IFOPool.sol";

import "pancake-cake-vault/contracts/test/CakeToken.sol";

import "pancake-cake-vault/contracts/test/SyrupBar.sol";

import "pancake-cake-vault/contracts/test/MasterChef.sol";

/**

* @title my cake ifo v3 implement

* @author lrqstudy

* @notice

*/

contract MyIFOInitializableV3 is IIFOV2,ReentrancyGuard,Ownerable {

? ? /**

? ? * 使用了openzeppelin中的safemath痴颊,將其方法用于uint256中轿钠,這個(gè)是之前的版本液肌,現(xiàn)在的新的solidity版本不需要

? ? */

? ? using SafeMath for uint256;

? ? using SafeERC20 for IERC20;

? ? // 定義了一個(gè)池子數(shù)的常量络断,公開的和私人的

? ? uint8 public constant NUMBER_POOLS = 2;

? ? // ifo工廠的地址

? ? address public immutable IFO_FACTORY;



? ? uint256 public MAX_BUFFER_BLOCKS;

? ? //用于參與本次ifo 的資金

? ? IERC20 public lpToken;

? ? //用于公開售賣的token地址

? ? IERC20 public offeringToken;

? ? //pancake平臺信息,只有注冊信息才可以參與ifo

? ? PancakeProfile public pancakeProfile;

? ? IFOPool public ifoPool;

? ? bool public isInitialized;

? ? //ifo 開始區(qū)塊號

? ? uint256 public startBlock;

? ? //ifo 結(jié)束區(qū)塊號

? ? uint256 public endBlock;

? ? //本次ifo的活動(dòng)id

? ? uint256 public campaignId;

? ? //參與達(dá)到要求后有多少積分

? ? uint256 public numberPoints;

? ? //最低積分要求

? ? uint256 public thresholdPoints;

? ? //總共要售賣的token數(shù)量

? ? uint256 public totalTokensOffered;

? ? PoolCharacteristics[NUMBER_POOLS] private _poolInformation;

? ? //定義了一個(gè)mapping結(jié)構(gòu)及老,key是地址豹悬,value是狀態(tài),描述用戶是否已經(jīng)領(lǐng)取積分

? ? mapping(address => bool) private _hasClaimedPoints;

? ? /**

? ? * @dev 定了一個(gè)潛逃的mapping結(jié)構(gòu)分瘦, 第一層key是用戶地址蘸泻,value是一個(gè) key為poolid, value為userinfo的結(jié)構(gòu)mapping結(jié)構(gòu)嘲玫,

? ? 用于記錄當(dāng)前用戶參與ifo的信息悦施,參與了幾個(gè)池子。

? ? */

? ? mapping(address => mapping(uint8 => UserInfo)) private _userInfo;

? ? //定義了一個(gè)mapping去团,key是用戶參與地址抡诞, value是用戶累計(jì)參與的金額。

? ? mapping(address => uint256) public userAccumulateDeposits;

? ? /**

? ? * 定義了一個(gè)池子的結(jié)構(gòu)

? ? * 包括了六個(gè)對象土陪, 募集目標(biāo)金額昼汗,共計(jì)提供多少token,每個(gè)用戶多少險(xiǎn)惡鬼雀,是否有參與費(fèi)用顷窒,總共的募集資金,總共產(chǎn)生多少費(fèi)用

? ? * @param amountLP

? ? * @param amountOfferingToken

? ? */

? ? struct PoolCharacteristics {

? ? ? ? uint256 raisingAmountPool;

? ? ? ? uint256 offeringAmountPool;

? ? ? ? uint256 limitPerUserInLP;

? ? ? ? bool hasTax;

? ? ? ? uint256 totalAmountPool;

? ? ? ? uint256 sumTaxesOverflow;

? ? }

? ? /**

? ? * 定義了一個(gè)userinfo的結(jié)構(gòu)取刃,存儲用戶參與了多少資金蹋肮,是否領(lǐng)取的狀態(tài)

? ? * @param amountLP

? ? * @param amountOfferingToken

? ? */

? ? struct UserInfo {

? ? ? ? uint256 amountPool;

? ? ? ? bool claimedPool;

? ? }

? ? event AdminWithdraw(uint256 amountLP, uint256 amountOfferingToken);

? ? event AdminTokenRecovery(address tokenAddress, uint256 amountTokens);

? ? event Deposit(address indexed user, uint256 amount, uint8 indexed pid);

? ? event Harvest(address indexed user, uint256 offeringAmount,uint256 excessAmount, uint8 indexed pid);

? ? event NewStartAndEndBlocks(uint256 startBlock,uint256 endBlock);

? ? event PointParametersSet(uint256 campaignId, uint256 numberPoints, uint256 thresholdPoints);

? ? event PoolParametersSet(uint256 offeringAmountPool, uint256 raisingAmountPool, uint8 pid);

? ? /**

? ? * 定義了一個(gè)修飾符,合約以及代理合約對象不能參與璧疗,只有普通的eta地址可以參與

? ? */

? ? modifier notContract() {

? ? ? ? require(!_isContract(msg.sender)," contract not allowed");

? ? ? ? require(msg.sender == tx.origin," proxy contract not allowed");

? ? ? ? _;

? ? }

? ? /**

? ? * 定義了一個(gè)構(gòu)造函數(shù)坯辩,指定IFO_Factory對象地址

? ? */

? ? constructor() public {

? ? ? ? IFO_FACTORY = msg.sender;

? ? }

? ? /**

? ? * 定義了一個(gè)初始化函數(shù),用于初始化設(shè)置當(dāng)前ifo事件

? ? * @param _lpToken? 用于參與的資金token地址

? ? * @param _offeringToken? 用于售賣的token地址

? ? * @param _pancakeProfileAddress pancakefile的合約地址

? ? * @param _startBlock 售賣開始的區(qū)塊編號

? ? * @param _endBlock? 售賣結(jié)束的區(qū)塊編號

? ? * @param _maxBufferBlocks 最大緩沖區(qū)塊數(shù)崩侠,用于控制ifo的冗余時(shí)間

? ? * @param _adminAddress? 管理員地址漆魔,用于提取當(dāng)前資金

? ? * @param _ifoPoolAddress? ifo池子地址,用于接收

? ? */

? ? function initialize(

? ? ? ? address _lpToken,

? ? ? ? address _offeringToken,

? ? ? ? address _pancakeProfileAddress,

? ? ? ? uint256 _startBlock,

? ? ? ? uint256 _endBlock,

? ? ? ? uint256 _maxBufferBlocks,

? ? ? ? address _adminAddress,

? ? ? ? address _ifoPoolAddress

? ? )? public? {

? ? ? ? require(!isInitialized,"operations: Already initialized");

? ? ? ? require(msg.sender == IFO_FACTORY, "Operation: only for Factory");

? ? ? ? //make this contract initialized

? ? ? ? isInitialized = true;

? ? ? ? lpToken = IERC20(_lpToken);

? ? ? ? offeringToken = IERC20(_offeringToken);

? ? ? ? /**

? ? ? ? * 這里無法理解却音,為什么 PancakeProfile創(chuàng)建了對象改抡,怎么就一個(gè)參數(shù)就可以呢?

? ? ? ? * PancakeProfile的構(gòu)造函數(shù)有四個(gè)參數(shù)系瓢。

? ? ? ? * @param _amount

? ? ? ? * @param _pid

? ? ? ? */

? ? ? ? pancakeProfile = PancakeProfile(_pancakeProfileAddress);


? ? ? ? ifoPool = IFOPool(_ifoPoolAddress);

? ? ? ? startBlock = _startBlock;

? ? ? ? endBlock = _endBlock;

? ? ? ? MAX_BUFFER_BLOCKS = _maxBufferBlocks;

? ? ? ? transferOwnership(_adminAddress);//這個(gè)將當(dāng)前合約轉(zhuǎn)移給管理員

? ? }

? ? /**

? ? * 用于處理用戶參與的請求函數(shù)

? ? * @param _amount 本次參與金額阿纤,

? ? * @param _pid 本次參與的池子編號

? ? */

? ? function depositPool(uint256 _amount,uint8 _pid) external override nonReentrant notContract {

? ? ? ? //用戶必須要注冊并獲得符合規(guī)定的pancake賬戶及頭像,從而參與ifo

? ? ? ? require(pancakeProfile.getUserStatus(msg.sender),"Deposit: Must have an active profile");

? ? ? ? //當(dāng)前只有兩個(gè)池子夷陋,如果池子id不小于2欠拾,說明參數(shù)有問題

? ? ? ? require(_pid < NUMBER_POOLS," Deposit: Non valid pool id");

? ? ? ? //必須是要先設(shè)定好融資額度胰锌,以及提供的token數(shù)量,用戶才能參與進(jìn)來藐窄。

? ? ? ? require(_poolInformation[_pid].offeringAmount > 0 && _poolInformation[_pid].raisingAmountPool>0,"Deposit: Pool not set");

? ? ? ? //只有到了開始的區(qū)塊號才能參與资昧,用戶不能參與

? ? ? ? require(block.number > startBlock,"Deposit: Too early");

? ? ? ? //過了結(jié)束參與的區(qū)塊號,不能參與

? ? ? ? require(block.number< endBlock,"Deposit: Too Late");

? ? ? ? //如果當(dāng)前ifo合約中的對應(yīng)的售賣余額荆忍,大于已經(jīng)提供的格带,那么說明設(shè)置的ifo 數(shù)據(jù)有問題。

? ? ? ? require(offeringToken.balanceOf(address(this))>= totalTokensOffered,"Deposit: Tokens not deposited properly");

? ? ? ? //用戶可以參與的額度刹枉,用于存入的總金額不得大于該額度

? ? ? ? uint256 ifoCredit = ifoPool.getUserCredit(msg.sender);

? ? ? ? require(userAccumulateDeposits[msg.sender].add(_amount)<= ifoCredit,"Not enough IFO credit left");

? ? ? ? //如果這些校驗(yàn)都通過了叽唱,那么將用于提供的cake數(shù)量調(diào)用轉(zhuǎn)賬函數(shù)轉(zhuǎn)到當(dāng)前合約地址中

? ? ? ? lpToken.safeTransferFrom(address(msg.sender),address(this),_amount);

? ? ? ? //將用戶成功參與到金額以及池子信息設(shè)置到mapping中,方便后續(xù)查看

? ? ? ? _userInfo[msg.sender][_pid].amountPool = _userInfo[msg.sender][_pid].amountPool.add(_amount);

? ? ? ? //如果每個(gè)用戶有參與限額嘶卧,那么用戶的參與金額不得大于這個(gè)限額

? ? ? ? if (_poolInformation[_pid].limitPerUserInLP > 0) {

? ? ? ? ? ? require(_userInfo[msg.sender][_pid].amountPool <= _poolInformation[_pid].limitPerUserInLPimi,"Deposit: new amount over user limt");

? ? ? ? }

? ? ? ? //將用戶本次參與的金額更新到總的參與池子信息中尔觉,方便后期查看

? ? ? ? _poolInformation[_pid].totalAmountPool = _poolInformation[_pid].totalAmountPool.add(_amount);

? ? ? ? //記錄用于累計(jì)參與到ifo金額數(shù)量。

? ? ? ? userAccumulateDeposits[msg.sender] = userAccumulateDeposits[msg.sender].add(_amount);

? ? ? ? //發(fā)出用戶參與ifo的事件芥吟。報(bào)告參與人侦铜,參與金額,參與項(xiàng)目id

? ? ? ? emit Deposit(msg.sender,_amount, _pid);

? ? }

? ? /**

? ? * 定義了用戶在參與結(jié)束后領(lǐng)取ifo的處理請求函數(shù)钟鸵。 ifo結(jié)束后钉稍,用戶點(diǎn)擊claim由當(dāng)前函數(shù)進(jìn)行處理。

? ? * @param _pid 項(xiàng)目id

? ? */

? ? function harvestPool(uint8 _pid) external override nonReentrant notContract{

? ? ? ? //必須結(jié)束ifo才能領(lǐng)取

? ? ? ? require(block.number > endBlock,"Harvest: Too early");

? ? ? ? //項(xiàng)目id必須是0 或者1

? ? ? ? require(_pid < NUMBER_POOLS,"Harvest:Non valid pool id");

? ? ? ? //只有參與過的人才可以領(lǐng)取

? ? ? ? require(_userInfo[msg.sender][_pid].amountPool>0,"Harvest: Did not participate ");

? ? ? ? //如果已經(jīng)領(lǐng)取了棺耍,則不能再次領(lǐng)取

? ? ? ? require(!_userInfo[msg.sender][_pid].claimedPool,"Harvest: already done");

? ? ? ? //調(diào)用領(lǐng)取參與積分的函數(shù)

? ? ? ? _claimPoints(msg.sender);

? ? ? ? //將用戶對應(yīng)的項(xiàng)目id的已經(jīng)領(lǐng)取狀態(tài)設(shè)置為true

? ? ? ? _userInfo[msg.sender][_pid].claimedPool = true;

? ? ? ? //計(jì)算用戶已經(jīng)參與的金額贡未,需要退還的金額,以及用戶參與的費(fèi)用

? ? ? ? (

? ? ? ? ? ? uint256 offeringTokenAmount,

? ? ? ? ? ? uint256 refundingTokenAmount,

? ? ? ? ? ? uint256 userTaxOverflow

? ? ? ? ) = _calculateOfferingAndRefundingAmountPool(msg.sender,_pid);

? ? ? ? if(userTaxOverflow > 0){

? ? ? ? ? ? _poolInformation[_pid].sumtaxedOverflow = _poolInformation[_pid].sumTaxesOverflow.add(userTaxOverflow);

? ? ? ? }

? ? ? ? //將用戶本次獲得的token數(shù)轉(zhuǎn)給當(dāng)前用戶

? ? ? ? if(offeringTokenAmount > 0) {

? ? ? ? ? ? //疑問: 這個(gè)是如何設(shè)置用戶的領(lǐng)取周期的 TODO

? ? ? ? ? ? offeringToken.safeTransfer(address(msg.sender),offeringTokenAmount);

? ? ? ? }

? ? ? ? //將用戶超額部分多cake退還給用戶

? ? ? ? if(refundingTokenAmount>0){

? ? ? ? ? ? lpToken.safeTransfer(address(msg.sender),refundingTokenAmount);

? ? ? ? }

? ? ? ? //調(diào)用通知事件蒙袍,告知領(lǐng)取人俊卤,提供的金額,以及退換的金額害幅。

? ? ? ? emit Harvest(msg.sender, offeringTokenAmount,refundingTokenAmount,_pid);

? ? }

? ? /**

? ? * 供ifo項(xiàng)目方領(lǐng)取募集資金以及剩余的出售token消恍,僅僅當(dāng)初設(shè)置為合約所有人地址才能調(diào)用

? ? * @param _lpAmount 領(lǐng)取募集資金額度

? ? * @param _offerAmount 領(lǐng)取剩余出售token數(shù)量

? ? */

? ? function finalWithdraw(uint256 _lpAmount,uint256 _offerAmount) external override onlyOwner {

? ? ? ? //領(lǐng)取數(shù)必須小于等于當(dāng)前合約中剩余的cake數(shù)

? ? ? ? require(_lpAmount <= lpToken.balanceOf(address(this)),"Operations: Not enough LP tokens");

? ? ? ? //領(lǐng)取的token數(shù)必須小于等于當(dāng)前合約剩余的token數(shù)

? ? ? ? require(_offerAmount <= offeringToken.balanceOf(this),"Operations Not enough offering tokens");

? ? ? ? if(_lpAmount > 0){

? ? ? ? ? ? //當(dāng)前合約中的cake轉(zhuǎn)給項(xiàng)目方

? ? ? ? ? ? lpToken.safeTransfer(address(msg.sender),_lpAmount);

? ? ? ? }

? ? ? ? if(_offerAmount >0){

? ? ? ? ? ? //將當(dāng)前合約中剩余的未出售token轉(zhuǎn)給項(xiàng)目方

? ? ? ? ? ? offeringToken.safeTransfer(address(msg.sender),_offerAmount);

? ? ? ? }

? ? ? ? //發(fā)送管理員領(lǐng)取事件

? ? ? ? emit AdminWithdraw(_lpAmount,_offerAmount);

? ? }

? ? /**

? ? * 給合約所有者恢復(fù)錯(cuò)誤轉(zhuǎn)入的token,且必須是除了cake和當(dāng)前待出售的合約以现。

? ? * @param _tokenAddress

? ? * @param _tokenAmount

? ? */

? ? function recoverWrongTokens(address _tokenAddress,uint256 _tokenAmount) external onlyOwner {

? ? ? ? //要轉(zhuǎn)移的token不能是cake

? ? ? ? require(_tokenAddress != address(lpToken), "can not be LP token");

? ? ? ? //要恢復(fù)的token也不能是項(xiàng)目方的出售token

? ? ? ? require(_tokenAddress != address(offeringToken),"recover: cannot be offering token");

? ? ? ? //將當(dāng)前合約對象強(qiáng)制轉(zhuǎn)換為ERC20對象狠怨,從而能調(diào)用erc20對象的safeTransfer方法,將當(dāng)前合約中的當(dāng)前token轉(zhuǎn)給項(xiàng)目方

? ? ? ? IERC20(_tokenAddress).safeTransfer(address(msg.sender),_tokenAmount);

? ? ? ? //發(fā)布管理員恢復(fù)誤操作token

? ? ? ? emit AdminTokenRecovery(_tokenAddress,_tokenAmount);

? ? }

? ? /**

? ? * 定義了一個(gè)設(shè)置啟動(dòng)參數(shù)的功能邑遏,給管理員調(diào)用

? ? * @param _offeringAmountPool 待出售token數(shù)量

? ? * @param _raisingAmountPool? 共計(jì)募集資金

? ? * @param _limitPerUserInLP? 每個(gè)參與人參與限額

? ? * @param _hasTax? 是否有費(fèi)用

? ? * @param _pid? 池子id

? ? */

? ? function setPool(

? ? ? ? uint256 _offeringAmountPool,

? ? ? ? uint256 _raisingAmountPool,

? ? ? ? uint256 _limitPerUserInLP,

? ? ? ? bool _hasTax,

? ? ? ? uint8 _pid

? ? ? ? ) external override onlyOwner {

? ? ? ? ? ? //只有開始的區(qū)塊之前才可以調(diào)用佣赖,在開始后不允許調(diào)用。

? ? ? ? ? ? require(block.number < startBlock," Operations: IFO has started");

? ? ? ? ? ? //池子id必須是指定的幾個(gè)记盒。

? ? ? ? ? ? require(_pid < NUMBER_POOLS," Operations: Pool does not exist");

? ? ? ? ? ? //將傳遞的參數(shù)賦值給poolInformation狀態(tài)變量

? ? ? ? ? ? _poolInformation[_pid].offeringAmountPool = _offeringAmountPool;

? ? ? ? ? ? _poolInformation[_pid].raisingAmountPool = _raisingAmountPool;

? ? ? ? ? ? _poolInformation[_pid].limitPerUserInLP = _limitPerUserInLP;

? ? ? ? ? ? _poolInformation[_pid].hasTax = _hasTax;

? ? ? ? ? ? uint256 tokensDistributedAcrossPools;

? ? ? ? ? ? for(uint8 i =0; i< NUMBER_POOLS;i++){

? ? ? ? ? ? ? ? // 統(tǒng)計(jì)兩個(gè)池子共提供的token數(shù)

? ? ? ? ? ? ? ? tokensDistributedAcrossPools = tokensDistributedAcrossPools.add(_poolInformation[i].offeringAmountPool);

? ? ? ? ? ? }

? ? ? ? ? ? totalTokensOffered = tokensDistributedAcrossPools;

? ? ? ? ? ? //發(fā)送池子參數(shù)設(shè)定的事件

? ? ? ? ? ? emit PoolParametersSet(_offeringAmountPool,_raisingAmountPool,_pid);

? ? }

? ? /**

? ? * 更新積分參數(shù)憎蛤,只能在區(qū)塊結(jié)束之前調(diào)用

? ? * @param _campaignId ifo活動(dòng)id

? ? * @param _numberPoints 積分?jǐn)?shù)

? ? * @param _thresholdPoints 積分門檻

? ? */

? ? function updatePointParameters(

? ? ? ? uint256 _campaignId,

? ? ? ? uint256 _numberPoints,

? ? ? ? uint256 _thresholdPoints

? ? ? ? ) external override onlyOwner {

? ? ? ? ? ? require(block.number < endBlock,"operation IFO has ended");

? ? ? ? ? ? numberPoints = _numberPoints;

? ? ? ? ? ? campaignId = _campaignId;

? ? ? ? ? ? thresholdPoints = _thresholdPoints;

? ? ? ? ? ? // 發(fā)布積分更新時(shí)間

? ? ? ? ? ? emit PointParametersSet(campaignId,numberPoints,thresholdPoints);

? ? }

? ? /**

? ? * 更新開始結(jié)束區(qū)塊號,從而重新設(shè)定開始結(jié)束時(shí)間纪吮。

? ? * @param _startBlock 新的開始區(qū)塊

? ? * @param _endBlock? 新的結(jié)束區(qū)塊

? ? */

? ? function updateStartAndEndBlocks(uint256 _startBlock,uint256 _endBlock) external onlyOwner {

? ? ? ? //新的結(jié)束區(qū)塊只能在當(dāng)前區(qū)塊延后 的MAX_BUFFER_BLOCKS 中

? ? ? ? require(_endBlock < (block.number + MAX_BUFFER_BLOCKS), "Operations: EndBlock too far");

? ? ? ? //當(dāng)前操作必須要在開始之前操作

? ? ? ? require(block.number < startBlock,"Operations: IFO has started");

? ? ? ? //新設(shè)置的結(jié)束區(qū)塊必須要大于開始區(qū)塊

? ? ? ? require(_startBlock < _endBlock, "Operations: New startBlock must be lower than new endBlock");

? ? ? ? //新設(shè)置的區(qū)塊必須要在當(dāng)前系統(tǒng)區(qū)塊之后俩檬。

? ? ? ? require(block.number < _startBlock,"Operations: New startblock must be higher than current block");

? ? ? ? startBlock = _startBlock;

? ? ? ? endBlock = _endBlock;

? ? ? ? //發(fā)布新開始結(jié)束時(shí)間區(qū)塊事件

? ? ? ? emit NewStartAndEndBlocks(_startBlock,_endBlock);

? ? }

? ? /**

? ? * 定義一個(gè)訪問ifo池子的方法栏豺。

? ? * @param _pid

? ? * @return

? ? * @return

? ? * @return

? ? * @return

? ? * @return

? ? * @return

? ? */

? ? function viewPoolInformation(uint256 _pid) external view override returns (

? ? ? ? uint256,

? ? ? ? uint256,

? ? ? ? uint256,

? ? ? ? bool,

? ? ? ? uint256,

? ? ? ? uint256

? ? ? ? ){

? ? ? ? ? ? return (

? ? ? ? ? ? ? ? _poolInformation[_pid].raisingAmountPool,

? ? ? ? ? ? ? ? _poolInformation[_pid].offeringAmountPool,

? ? ? ? ? ? ? ? _poolInformation[_pid].limitPerUserInLP,

? ? ? ? ? ? ? ? _poolInformation[_pid].hasTax,

? ? ? ? ? ? ? ? _poolInformation[_pid].totalAmountPool,

? ? ? ? ? ? ? ? _poolInformation[_pid].sumTaxesOverflow

? ? ? ? ? ? );

? ? }


? ? /**

? ? * 定義一個(gè)通過池子id獲得當(dāng)前池子溢出稅,如果沒有稅豆胸,則返回0,如果有稅巷疼,則返回計(jì)算稅的結(jié)果

? ? * @param _pid

? ? */

? ? function viewPoolTaxRateOverflow(uint256 _pid) external view override returns (uint256){

? ? ? ? if(!_poolInformation[_pid].hasTax){

? ? ? ? ? ? return 0;

? ? ? ? }

? ? ? ? return _calculateTaxOverflow(_poolInformation[_pid].totalAmountPool,_poolInformation[_pid].raisingAmountPool);

? ? }

? ? /**

? ? *

? ? * @param _user

? ? * @param _pids

? ? */

? ? function viewUserAllocationPools(address _user,uint8[] calldata _pids) external view override returns (uint256[] memory){

? ? ? ? uint256[] memory allocationPools = new uint256[](_pids.length);

? ? ? ? for(uint8 i=0; i< _pids.length;i++){

? ? ? ? ? ? allocationPools[i] = _getUserAllocationPool(_user,_pids[i]);

? ? ? ? }

? ? ? ? return allocationPools;

? ? }

? ? /**

? ? * 定義了一個(gè)訪問用戶數(shù)據(jù)的方法晚胡。 返回值有兩個(gè)數(shù)組。

? ? * 第一個(gè)是用戶參與每個(gè)池子對應(yīng)的金額數(shù)嚼沿,第二個(gè)數(shù)組是每個(gè)用戶是否領(lǐng)取了對應(yīng)的token

? ? * @param _user

? ? * @param _pids

? ? * @return

? ? * @return

? ? */

? ? function viewUserInfo(address _user, uint8[] calldata _pids) external view override returns(uint256[] memory, bool[] memory){

? ? ? ? uint256[] memory amountPools = new uint256[](_pids.length);

? ? ? ? bool[] memory statusPools = new bool[](_pids.length);

? ? ? ? for(uint8 i = 0; i< NUMBER_POOLS; i++){

? ? ? ? ? ? amountPools[i] = _userInfo[_user][i].amountPool;

? ? ? ? ? ? statusPools[i] = _userInfo[_user][i].claimedPool;

? ? ? ? }

? ? ? ? return (amountPools,statusPools);

? ? }

? ? /**

? ? * 獲取并返回用戶在每個(gè)池子中參與金額以及退款的金額數(shù)

? ? */

? ? function viewUserOfferingAndRefundingAmountsForPools(address _user,uint8[] calldata _pids) external

? ? view override returns (uint256[3][]memory){

? ? ? ? uint256[3][] memory amountPools = new uint256[3][](_pids.length);

? ? ? ? for(uint8 i =0; i<_pids.length;i++){

? ? ? ? ? ? uint256 userOfferingAmountPool;

? ? ? ? ? ? uint256 userRefundingAmountPool;

? ? ? ? ? ? uint256 userTaxAmountPool;

? ? ? ? ? ? if(_poolInformation[_pids[i]].raisingAmountPool > 0){

? ? ? ? ? ? ? ? (

? ? ? ? ? ? ? ? ? ? userOfferingAmount,

? ? ? ? ? ? ? ? ? ? userRefundingAmountPool,

? ? ? ? ? ? ? ? ? ? userTaxAmountPool

? ? ? ? ? ? ? ? ) = _calculateOfferingAndRefundingAmountsPool(_user,_pids[i]);

? ? ? ? ? ? }

? ? ? ? ? ? amountPools[i] = [userOfferingAmountPool,userRefundingAmountPool,userTaxAmountPool];

? ? ? ? }

? ? ? ? return amountPools;

? ? }

? ? /**

? ? * @notice It calculates the tax overflow given the raisingAmountPool and the totalAmountPool.

? ? * @dev 100,000,000,000 means 0.1 (10%) / 1 means 0.0000000000001 (0.0000001%) / 1,000,000,000,000 means 1 (100%)

? ? * @return It returns the tax percentage

? ? */

? ? function _calculateTaxOverflow(uint256 _totalAmountPool, uint256 _raisingAmountPool)

? ? ? ? internal

? ? ? ? pure

? ? ? ? returns (uint256)

? ? {

? ? ? ? uint256 ratioOverflow = _totalAmountPool.div(_raisingAmountPool);

? ? ? ? if (ratioOverflow >= 1500) {

? ? ? ? ? ? return 500000000; // 0.05%

? ? ? ? } else if (ratioOverflow >= 1000) {

? ? ? ? ? ? return 1000000000; // 0.1%

? ? ? ? } else if (ratioOverflow >= 500) {

? ? ? ? ? ? return 2000000000; // 0.2%

? ? ? ? } else if (ratioOverflow >= 250) {

? ? ? ? ? ? return 2500000000; // 0.25%

? ? ? ? } else if (ratioOverflow >= 100) {

? ? ? ? ? ? return 3000000000; // 0.3%

? ? ? ? } else if (ratioOverflow >= 50) {

? ? ? ? ? ? return 5000000000; // 0.5%

? ? ? ? } else {

? ? ? ? ? ? return 10000000000; // 1%

? ? ? ? }

? ? }

? ? /**

? ? * @notice It calculates the offering amount for a user and the number of LP tokens to transfer back.

? ? * @param _user: user address

? ? * @param _pid: pool id

? ? * @return {uint256, uint256, uint256} It returns the offering amount, the refunding amount (in LP tokens),

? ? * and the tax (if any, else 0)

? ? */

? ? function _calculateOfferingAndRefundingAmountsPool(address _user, uint8 _pid)

? ? ? ? internal

? ? ? ? view

? ? ? ? returns (

? ? ? ? ? ? uint256,

? ? ? ? ? ? uint256,

? ? ? ? ? ? uint256

? ? ? ? )

? ? {

? ? ? ? uint256 userOfferingAmount;

? ? ? ? uint256 userRefundingAmount;

? ? ? ? uint256 taxAmount;

? ? ? ? if (_poolInformation[_pid].totalAmountPool > _poolInformation[_pid].raisingAmountPool) {

? ? ? ? ? ? // Calculate allocation for the user

? ? ? ? ? ? uint256 allocation = _getUserAllocationPool(_user, _pid);

? ? ? ? ? ? // Calculate the offering amount for the user based on the offeringAmount for the pool

? ? ? ? ? ? userOfferingAmount = _poolInformation[_pid].offeringAmountPool.mul(allocation).div(1e12);

? ? ? ? ? ? // Calculate the payAmount

? ? ? ? ? ? uint256 payAmount = _poolInformation[_pid].raisingAmountPool.mul(allocation).div(1e12);

? ? ? ? ? ? // Calculate the pre-tax refunding amount

? ? ? ? ? ? userRefundingAmount = _userInfo[_user][_pid].amountPool.sub(payAmount);

? ? ? ? ? ? // Retrieve the tax rate

? ? ? ? ? ? if (_poolInformation[_pid].hasTax) {

? ? ? ? ? ? ? ? uint256 taxOverflow = _calculateTaxOverflow(

? ? ? ? ? ? ? ? ? ? _poolInformation[_pid].totalAmountPool,

? ? ? ? ? ? ? ? ? ? _poolInformation[_pid].raisingAmountPool

? ? ? ? ? ? ? ? );

? ? ? ? ? ? ? ? // Calculate the final taxAmount

? ? ? ? ? ? ? ? taxAmount = userRefundingAmount.mul(taxOverflow).div(1e12);

? ? ? ? ? ? ? ? // Adjust the refunding amount

? ? ? ? ? ? ? ? userRefundingAmount = userRefundingAmount.sub(taxAmount);

? ? ? ? ? ? }

? ? ? ? } else {

? ? ? ? ? ? userRefundingAmount = 0;

? ? ? ? ? ? taxAmount = 0;

? ? ? ? ? ? // _userInfo[_user] / (raisingAmount / offeringAmount)

? ? ? ? ? ? userOfferingAmount = _userInfo[_user][_pid].amountPool.mul(_poolInformation[_pid].offeringAmountPool).div(

? ? ? ? ? ? ? ? _poolInformation[_pid].raisingAmountPool

? ? ? ? ? ? );

? ? ? ? }

? ? ? ? return (userOfferingAmount, userRefundingAmount, taxAmount);

? ? }

? ? /**

? ? * 定義了一個(gè)供內(nèi)部調(diào)用的領(lǐng)取積分函數(shù)

? ? * @param _user

? ? */

? ? function _claimPoints(address _user) internal? {

? ? ? ? if(_hasClaimedPoints[_user]){

? ? ? ? ? ? return;//如果當(dāng)前用戶已經(jīng)領(lǐng)取積分估盘,那么不執(zhí)行后續(xù)命令? 疑問骡尽,為什么這里不報(bào)錯(cuò)呢遣妥,而僅僅是返回。

? ? ? ? }

? ? ? ? uint256 sumPools;

? ? ? ? for(uint8 i=0; i<NUMBER_POOLS;i++){

? ? ? ? ? ? sumPools = sumPools.add(_userInfo[msg.sender][i].amountPool);//統(tǒng)計(jì)用戶參與的總的金額數(shù)

? ? ? ? }

? ? ? ? //如果用戶參與的總金額數(shù)攀细,超過了限額箫踩,則滿足領(lǐng)取積分條件

? ? ? ? if(sumPools > thresholdPoints) {

? ? ? ? ? ? _hasClaimedPoints = true;//將已經(jīng)領(lǐng)取積分的狀態(tài)設(shè)置為true

? ? ? ? ? ? pancakeProfile.increaseUserPoints(msg.sender, numberPoints,campaignId);//調(diào)用pancakeProfile合約執(zhí)行給用戶增加積分的函數(shù)功能。

? ? ? ? }


? ? }

? ? /**

? ? * 獲取用戶參與量占當(dāng)前總量的比例

? ? * @param _user

? ? * @param _pid

? ? */

? ? function _getUserAllocationPool(address _user,uint8 _pid) internal view returns(uint256) {

? ? ? ? if(_poolInformation[_pid].totalAmountPool > 0) {

? ? ? ? ? ? return _userInfo[_user][_pid].amountPool.mul(1e18).div(_poolInformation[_pid]).totalAmountPool.mul(1e6);

? ? ? ? }

? ? ? ? return 0;

? ? }

? ? /**

? ? * 定義一個(gè)判斷是否是合約地址的內(nèi)部方法

? ? * @param _addr

? ? */

? ? function _isContract(address _addr) internal? view returns (bool){

? ? ? ? uint256 size;

? ? ? ? assembly {

? ? ? ? ? ? size := extcodesize(_addr)

? ? ? ? }

? ? ? ? return size >0;

? ? }

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末谭贪,一起剝皮案震驚了整個(gè)濱河市境钟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌俭识,老刑警劉巖慨削,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異套媚,居然都是意外死亡缚态,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門堤瘤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來玫芦,“玉大人,你說我怎么就攤上這事宙橱∫塘” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵师郑,是天一觀的道長环葵。 經(jīng)常有香客問我,道長宝冕,這世上最難降的妖魔是什么张遭? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮地梨,結(jié)果婚禮上菊卷,老公的妹妹穿的比我還像新娘缔恳。我一直安慰自己,他們只是感情好洁闰,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布歉甚。 她就那樣靜靜地躺著,像睡著了一般扑眉。 火紅的嫁衣襯著肌膚如雪纸泄。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天腰素,我揣著相機(jī)與錄音聘裁,去河邊找鬼。 笑死弓千,一個(gè)胖子當(dāng)著我的面吹牛衡便,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播洋访,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼镣陕,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了捌显?” 一聲冷哼從身側(cè)響起茁彭,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎扶歪,沒想到半個(gè)月后理肺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡善镰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年妹萨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片炫欺。...
    茶點(diǎn)故事閱讀 39,779評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡乎完,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出品洛,到底是詐尸還是另有隱情树姨,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布桥状,位于F島的核電站帽揪,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏辅斟。R本人自食惡果不足惜转晰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧查邢,春花似錦蔗崎、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至邓深,卻和暖如春他嫡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背庐完。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留徘熔,地道東北人门躯。 一個(gè)月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像酷师,于是被迫代替她去往敵國和親讶凉。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容