> For the complete documentation index, see [llms.txt](https://crypto-excellence.gitbook.io/crypto-excellence-dao-documentation/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://crypto-excellence.gitbook.io/crypto-excellence-dao-documentation/platform-reference/core-features/smart-contracts/staking.sol.md).

# Staking.sol

The Staking smart contract is compiled with solidity v0.8.4 and uses the following libraries (and related dependencies):

* *Pausable.sol* from OpenZeppelin
* *IERC20.sol* from OpenZeppelin
* *SafeERC20.sol* from OpenZeppelin
* *Context.sol* from OpenZeppelin
* *UniswapV2Pair.sol* from UniswapV2
* *PRBMathUD60x18.sol* from PRBMath

The contract emits events for logging deposits and withdrawals.

#### computeCeShareFromLp

```solidity
/**
 * @dev Public View function to get ce share of LP deposit for a user.
 * This intializes a UniswapV2Pair on the LP token address (which will be on univ2)
 * It computes the CE share for an LP amount using the total supply of the LP token and then Reserve amounts for both tokens in the pair
 * It ensures an accurate compute by checking reserve token addresses in the pair
 * @param _pid the pool index
 * @param _amount the amount of LP token being deposited
 * @return amount of ce that corresponds to the lp deposit amount
 */
function computeCeShareFromLp(uint256 _pid, uint256 _amount) public view validatePoolByPid(_pid) returns (uint256) {
    PoolInfo storage pool = poolInfo[_pid];
    uint256 totalLpSupply = pool.lpToken.totalSupply();
    IUniswapV2Pair pair = IUniswapV2Pair(address(pool.lpToken));
    (uint112 res0, uint112 res1, ) = pair.getReserves();
    IERC20 token0 = IERC20(pair.token0());
    IERC20 token1 = IERC20(pair.token1());
    uint256 ceShare;
    if (address(token0) == address(CeToken)) {
        ceShare = _amount.mul(res0).div(totalLpSupply);
    } else if (address(token1) == address(CeToken)) {
        ceShare = _amount.mul(res1).div(totalLpSupply);
    } else {
        ceShare = 0;
    }
    return ceShare;
}
```

#### computeReward

```solidity
// coming soon
```

#### getApySecScaled

```solidity
// coming soon
```

#### getApyMonScaled

```solidity
// coming soon
```

#### addTimeLock

```solidity
/**
* @dev Time lock for adding lp pool. Can only be called by the owner.
* This will set the locktime for an lp pool to 48 hours after current block timestamp
* @param _lpToken the lp token for the pool
*/
function addTimeLock(IERC20 _lpToken) public onlyOwner {
   lockTime[address(_lpToken)] = block.timestamp + 172800;
}
```

#### add

```solidity
/**
 * @dev Add a new lp to the pool, reset the locktime for that pool. Can only be called by the owner.
 * XXX DO NOT add the same LP token more than once. Rewards will be messed up if you do.
 * require statements to revert state when conditions are not met
 * checks whether CeToken is in the _lpToken pair before being added as a pool
 * checks whether locktime was initiated for the lp pool
 * checks whether current block timestamp is greater than locktime for the lp pool
 * @param _allocPoint pool allocation points (unused in other methods)
 * @param _lpToken the lp token for the pool
 * @param _pegToken the peg token for the pool
 */
function add(uint256 _allocPoint, IERC20 _lpToken, IERC20 _pegToken) public onlyOwner {
    IUniswapV2Pair pair = IUniswapV2Pair(address(_lpToken));
    IERC20 token0 = IERC20(pair.token0());
    IERC20 token1 = IERC20(pair.token1());
    require(address(token0) == address(CeToken) || address(token1) == address(CeToken), "add: CeToken not found in pair");
    require(lockTime[address(_lpToken)] != 0, "add: timelock not initiated");
    require(block.timestamp > lockTime[address(_lpToken)], "add: timelock not complete");
    lockTime[address(_lpToken)] = 0;
    uint256 lastRewardTime = block.timestamp > startTime ? block.timestamp : startTime;
    totalAllocPoint = totalAllocPoint + _allocPoint;
    poolInfo.push(PoolInfo({
        lpToken: _lpToken,
        allocPoint: _allocPoint,
        lastRewardTime: lastRewardTime,
        accRewardPerShare: 0,
        pegToken: _pegToken
    }));
}
```

#### deposit

```solidity
/**
 * @dev Deposit LP tokens to staking contract for CE allocation and emits an event.
 * This will transfer any pending rewards to the user
 * This will transfer the LP token amount to the contract
 * This will transfer the peg token to the user based on CE share compute from LP token
 * This will also adjust user information to reflect latest deposit amounts, deposit time, and reset withdrawal request time
 * @param _pid the pool index
 * @param _amount the amount of LP tokens being deposited
 */
function deposit(uint256 _pid, uint256 _amount) public validatePoolByPid(_pid) {
    PoolInfo storage pool = poolInfo[_pid];
    UserInfo storage user = userInfo[_pid][msg.sender];
    if (user.amountCe > 0 && user.amount > 0) {
        uint256 rewardAmount = computeReward(_pid, address(msg.sender));
        safeCeTransfer(msg.sender, rewardAmount);
    }
    uint256 _amountCe = computeCeShareFromLp(_pid, _amount);
    pool.lpToken.safeTransferFrom(address(msg.sender), address(this), _amount);
    pool.pegToken.safeTransfer(address(msg.sender), _amountCe);
    user.amount = user.amount + _amount;
    user.amountCe = user.amountCe + _amountCe;
    user.depositTime = block.timestamp;
    user.withdrawRequest = 0;
    emit Deposit(msg.sender, _pid, _amount);
}
```

#### withdraw

```solidity
/**
 * @dev Withdraw LP tokens from staking contract and emits an event.
 * require statements to revert state when conditions are not met
 * checks whether user LP deposit is greater than or equal to withdrawal request amount
 * checks whether withdrawal cooldown was initiated
 * checks whether user withdrawal request occurs after deposit time
 * checks whether current block timestamp is greater than user withdrawal request timestamp plus 48h (enforcing the cooldown period)
 * This will transfer any pending rewards to the user
 * This will transfer the LP token amount to the user
 * This will transfer the peg token to the contract that is proportional to the LP token amount being withdrawn to the user
 * This will also adjust user information to reflect latest deposit amounts, and reset withdrawal request time
 * @param _pid the pool index
 * @param _amount the amount of LP tokens being withdrawn
 */
function withdraw(uint256 _pid, uint256 _amount) public validatePoolByPid(_pid) {
    PoolInfo storage pool = poolInfo[_pid];
    UserInfo storage user = userInfo[_pid][msg.sender];
    require(user.amount >= _amount, "withdraw: can't withdraw more than deposit");
    require(user.withdrawRequest != 0 && user.depositTime != 0, "withdraw: cooldown not initiated");
    require(user.withdrawRequest > user.depositTime, "withdraw: request before deposit");
    require(block.timestamp > (user.withdrawRequest + 172800), "withdraw: cooldown not complete");
    uint256 _amountCe = propCeShare(_pid, address(msg.sender), _amount);
    require(user.amountCe >= _amountCe, "withdraw: peg token exceeds deposit");
    uint256 rewardAmount = computeReward(_pid, address(msg.sender));
    safeCeTransfer(msg.sender, rewardAmount);
    user.amount = user.amount - _amount;
    user.amountCe = user.amountCe - _amountCe;
    user.withdrawRequest = 0;
    pool.pegToken.safeTransferFrom(address(msg.sender), address(this), _amountCe);
    pool.lpToken.safeTransfer(address(msg.sender), _amount);
    emit Withdraw(msg.sender, _pid, _amount);
}
```

#### withdrawCooldown

```solidity
/**
* @dev Withdraw cooldown period. Sets withdrawal request timestamp for msg sender.
* require statements to revert state when conditions are not met
* checks user LP amount deposited is greater than 0
* checks user CE share equivalent to LP amount deposited is greater than 0
* checks user withdrawal request time is currently 0 (no pending withdrawal requests)
* checks current block timestamp is greater than user deposit time
* @param _pid the pool index
*/
function withdrawCooldown(uint256 _pid) public validatePoolByPid(_pid) {
   UserInfo storage user = userInfo[_pid][msg.sender];
   require(user.amount > 0);
   require(user.amountCe > 0);
   require(user.withdrawRequest == 0);
   require(block.timestamp > user.depositTime);
   user.withdrawRequest = block.timestamp;
}
```

#### propCeShare

```solidity
/**
* @dev View function to get ce share corresponding to lp amount for withdrawals.
* @param _pid the pool index
* @param _user the address of user
* @param _amount the amount of LP token being withdrawn
* @return amount of ce that corresponds to the lp withdrawal amount
*/
function propCeShare(uint256 _pid, address _user, uint256 _amount) public view validatePoolByPid(_pid) returns (uint256) {
   UserInfo storage user = userInfo[_pid][_user];
   uint256 propCe = _amount.mul(user.amountCe).div(user.amount);
   return propCe;
}
```

#### pendingRewards

```solidity
/**
* @dev View function to get pending Rewards for a user.
* @param _pid the pool index
* @param _user the address of user
* @return the amount of pending ce rewards
*/
function pendingRewards(uint256 _pid, address _user) external view validatePoolByPid(_pid) returns (uint256) {
   uint256 rewardAmount = computeReward(_pid, _user);
   return rewardAmount;
}
```

#### deposited

```solidity
/**
* @dev View function to get deposited LP for a user.
* @param _pid the pool index
* @param _user the address of user
* @return the amount of LP tokens deposited
*/
function deposited(uint256 _pid, address _user) external view validatePoolByPid(_pid) returns (uint256) {
   UserInfo storage user = userInfo[_pid][_user];
   return user.amount;
}
```

#### depositedCe

```solidity
/**
* @dev View function to get the deposited CE share for a user.
* @param _pid the pool index
* @param _user the address of user
* @return the amount of CE share corresponding to deposited LP amount at the time of deposit(s)
*/
function depositedCe(uint256 _pid, address _user) external view validatePoolByPid(_pid) returns (uint256) {
   UserInfo storage user = userInfo[_pid][_user];
   return user.amountCe;
}
```

#### depositedTime

```solidity
/**
* @dev View function to get latest user deposit time
* @param _pid the pool index
* @param _user the address of user
* @return the most recent user deposit timestamp
*/
function depositedTime(uint256 _pid, address _user) external view validatePoolByPid(_pid) returns (uint256) {
   UserInfo storage user = userInfo[_pid][_user];
   return user.depositTime;
}
```

#### depositWithdrawRequest

```solidity
/**
* @dev View function to get latest user withdrawal request time
* @param _pid the pool index
* @param _user the address of user
* @return the latest user withdrawal request time, can be zero if it hasn't been requested
*/
function depositWithdrawRequest(uint256 _pid, address _user) external view validatePoolByPid(_pid) returns (uint256) {
   UserInfo storage user = userInfo[_pid][_user];
   return user.withdrawRequest;
}
```

#### validatePoolByPid

```solidity
/**
 * @dev Modifier that requires a pool with _pid to exist.
 */
modifier validatePoolByPid(uint256 _pid) {
    require (_pid < poolInfo.length , "Pool does not exist") ;
    _;
}
```

#### safeCeTransfer

```solidity
/**
 * @dev Safe internal transfer function, just in case if rounding error causes pool to not have enough rewards.
 * @param _to the recipient address
 * @param _amount the amount of rewards
 */
function safeCeTransfer(address _to, uint256 _amount) internal {
    uint256 ifBal = CeToken.balanceOf(address(this));
    if (_amount > ifBal) {
        CeToken.transfer(_to, ifBal);
        paidOut += ifBal;
    } else {
        CeToken.transfer(_to, _amount);
        paidOut += _amount;
    }
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://crypto-excellence.gitbook.io/crypto-excellence-dao-documentation/platform-reference/core-features/smart-contracts/staking.sol.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
