# Error calling staking function on Binance smartchain and pancakeswap

**URL:** <https://forum.openzeppelin.com/t/error-calling-staking-function-on-binance-smartchain-and-pancakeswap/5331>\
**Category:** Support\
**Created:** [January 8, 2021, 11:24am UTC](https://forum.openzeppelin.com/t/error-calling-staking-function-on-binance-smartchain-and-pancakeswap/5331 "2021-01-08T11:24:16Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Prabhakaran](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/prabhakaran/32/3288_2.png) [@Prabhakaran](https://forum.openzeppelin.com/u/Prabhakaran)\
**Post date:** [January 8, 2021, 11:24am UTC](https://forum.openzeppelin.com/t/error-calling-staking-function-on-binance-smartchain-and-pancakeswap/5331/1 "2021-01-08T11:24:16Z")

</div>

Hi,I am trying to create staking contract on binance mainnet for that i followed these steps  
1)created pair token from pancakeswap  
2)created(deployed) staking contract by giving masterchef and my token address and pair address(LP token)  
But when i try to call stake function in remix editor by giving some amount i got some gas estimation error.  
may be i missed some steps before calling staking function ,can anyone suggest me steps to create staking contract on binance

---

<div class="post-metadata">

**Author:** ![Skyge](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/skyge/32/343_2.png) [@Skyge](https://forum.openzeppelin.com/u/Skyge)\
**Post date:** [January 8, 2021, 4:20pm UTC](https://forum.openzeppelin.com/t/error-calling-staking-function-on-binance-smartchain-and-pancakeswap/5331/2 "2021-01-08T16:20:24Z")

</div>

Sorry I am not similar with the BSC-Chain, but do you call `approve` before you call `stake`, that is

```auto
LPToken.approve(stakingContract, approvalAmount);

```

and if possible, please paste your code.

---

<div class="post-metadata">

**Author:** ![Prabhakaran](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/prabhakaran/32/3288_2.png) [@Prabhakaran](https://forum.openzeppelin.com/u/Prabhakaran)\
**Post date:** [January 8, 2021, 5:41pm UTC](https://forum.openzeppelin.com/t/error-calling-staking-function-on-binance-smartchain-and-pancakeswap/5331/3 "2021-01-08T17:41:27Z")

</div>

Thanks @Skyge I tried that too before calling stake function but still i am getting that issue.

---

<div class="post-metadata">

**Author:** ![Skyge](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/skyge/32/343_2.png) [@Skyge](https://forum.openzeppelin.com/u/Skyge)\
**Post date:** [January 10, 2021, 3:44pm UTC](https://forum.openzeppelin.com/t/error-calling-staking-function-on-binance-smartchain-and-pancakeswap/5331/4 "2021-01-10T15:44:37Z")

</div>

emmmm, could you please share your code?

---

<div class="post-metadata">

**Author:** ![Prabhakaran](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/prabhakaran/32/3288_2.png) [@Prabhakaran](https://forum.openzeppelin.com/u/Prabhakaran)\
**Post date:** [January 11, 2021, 5:54am UTC](https://forum.openzeppelin.com/t/error-calling-staking-function-on-binance-smartchain-and-pancakeswap/5331/5 "2021-01-11T05:54:26Z")

</div>

Hi @Skyge here is my staking contract

```
 pragma solidity >=0.5.17;
    pragma experimental ABIEncoderV2;

    /**
     * @title Ownable
     * @dev The Ownable contract has an owner address, and provides basic authorization control
     * functions, this simplifies the implementation of "user permissions".
     */
    contract Ownable {
      address private _owner;

      event OwnershipRenounced(address indexed previousOwner);

      event OwnershipTransferred(
        address indexed previousOwner,
        address indexed newOwner
      );

      /**
       * @dev The Ownable constructor sets the original `owner` of the contract to the sender
       * account.
       */
      constructor() public {
        _owner = msg.sender;
      }

      /**
       * @return the address of the owner.
       */
      function owner() public view returns(address) {
        return _owner;
      }

      /**
       * @dev Throws if called by any account other than the owner.
       */
      modifier onlyOwner() {
        require(isOwner());
        _;
      }

      /**
       * @return true if `msg.sender` is the owner of the contract.
       */
      function isOwner() public view returns(bool) {
        return msg.sender == _owner;
      }

      /**
       * @dev Allows the current owner to relinquish control of the contract.
       * @notice Renouncing to ownership will leave the contract without an owner.
       * It will not be possible to call the functions with the `onlyOwner`
       * modifier anymore.
       */
      function renounceOwnership() public onlyOwner {
        emit OwnershipRenounced(_owner);
        _owner = address(0);
      }

      /**
       * @dev Allows the current owner to transfer control of the contract to a newOwner.
       * @param newOwner The address to transfer ownership to.
       */
      function transferOwnership(address newOwner) public onlyOwner {
        _transferOwnership(newOwner);
      }

      /**
       * @dev Transfers control of the contract to a newOwner.
       * @param newOwner The address to transfer ownership to.
       */
      function _transferOwnership(address newOwner) internal {
        require(newOwner != address(0));
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
      }
    }

    /**
     * @title SafeMath
     * @dev Math operations with safety checks that revert on error
     */
    library SafeMath {

      /**
      * @dev Multiplies two numbers, reverts on overflow.
      */
      function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
        if (a == 0) {
          return 0;
        }

        uint256 c = a * b;
        require(c / a == b);

        return c;
      }

      /**
      * @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
      */
      function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0); // Solidity only automatically asserts when dividing by 0
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
      }

      /**
      * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
      */
      function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a);
        uint256 c = a - b;

        return c;
      }

      /**
      * @dev Adds two numbers, reverts on overflow.
      */
      function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a);

        return c;
      }

      /**
      * @dev Divides two numbers and returns the remainder (unsigned integer modulo),
      * reverts when dividing by zero.
      */
      function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0);
        return a % b;
      }
    }

    interface IBEP20 {
      function totalSupply() external view returns (uint256);

      function balanceOf(address who) external view returns (uint256);

      function allowance(address owner, address spender)
        external view returns (uint256);

      function transfer(address to, uint256 value) external returns (bool);

      function approve(address spender, uint256 value)
        external returns (bool);

      function transferFrom(address from, address to, uint256 value)
        external returns (bool);
    }

    /**
     * @title A simple holder of tokens.
     * This is a simple contract to hold tokens. It's useful in the case where a separate contract
     * needs to hold multiple distinct pools of the same token.
     */
    contract TokenPool is Ownable {
        IBEP20 public token;

        constructor(IBEP20 _token) public {
            token = _token;
        }

        function balance() public view returns (uint256) {
            return token.balanceOf(address(this));
        }

        function transfer(address to, uint256 value) external onlyOwner returns (bool) {
            return token.transfer(to, value);
        }

        function rescueFunds(address tokenToRescue, address to, uint256 amount) external onlyOwner returns (bool) {
            require(address(token) != tokenToRescue, 'TokenPool: Cannot claim token held by the contract');

            return IBEP20(tokenToRescue).transfer(to, amount);
        }
    }

    // MasterChef public interface

    interface IMasterChef {

        // View function to see pending CAKEs on frontend.
        function pendingCake(uint256 _pid, address _user) external view returns (uint256);

        // Update reward variables of the given pool to be up-to-date.
        function updatePool(uint256 _pid) external;

        // Deposit LP tokens to MasterChef for CAKE allocation.
        function deposit(uint256 _pid, uint256 _amount) external;

        // Withdraw LP tokens from MasterChef.
        function withdraw(uint256 _pid, uint256 _amount) external;

        // Stake CAKE tokens to MasterChef
        function enterStaking(uint256 _amount) external;

        // Withdraw CAKE tokens from STAKING.
        function leaveStaking(uint256 _amount) external;

        // Withdraw without caring about rewards. EMERGENCY ONLY.
        function emergencyWithdraw(uint256 _pid) external;
        
       struct UserInfo {
            uint256 amount; // How many LP tokens the user has provided.
            uint256 rewardDebt;    
       }
       
        // User info view
        function userInfo(uint256 _pid, address _user) external view returns (UserInfo memory);
    }

    contract PrabhStaking is Ownable {
        using SafeMath for uint256;

        event Staked(address indexed user, uint256 amount, uint256 total, bytes data);
        event Unstaked(address indexed user, uint256 amount, uint256 total, bytes data);
        event TokensClaimed(address indexed user, uint256 amount);
        event TokensLocked(uint256 amount, uint256 durationSec, uint256 total);
        // amount: Unlocked tokens, total: Total locked tokens
        event TokensUnlocked(uint256 amount, uint256 total);

        TokenPool private _unlockedPool;
        TokenPool private _lockedPool;
        
        IBEP20 public stakingToken = IBEP20(0xf730d0aa2fDF7b03FB08218EBC6B03522D87C32a); // DITTO-BNB LP
        
        // Pancakeswap constants

        IMasterChef private pcsMasterChef = IMasterChef(0x73feaa1eE314F8c655E354234017bE2193C9E24E);
        IBEP20 private cake = IBEP20(0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82);
        uint256 PrabhStaking_PID =52;

        //
        // Time-bonus params
        //
        uint256 public constant BONUS_DECIMALS = 2;
        uint256 public startBonus = 0;
        uint256 public bonusPeriodSec = 0;

        //
        // Global accounting state
        //
        uint256 public totalLockedShares = 0;
        uint256 public totalStakingShares = 0;
        uint256 private _totalStakingShareSeconds = 0;
        uint256 private _lastAccountingTimestampSec = now;
        uint256 private _maxUnlockSchedules = 0;
        uint256 private _initialSharesPerToken = 0;

        //
        // User accounting state
        //
        // Represents a single stake for a user. A user may have multiple.
        struct Stake {
            uint256 stakingShares;
            uint256 timestampSec;
        }

        // Caches aggregated values from the User->Stake[] map to save computation.
        // If lastAccountingTimestampSec is 0, there's no entry for that user.
        struct UserTotals {
            uint256 stakingShares;
            uint256 stakingShareSeconds;
            uint256 lastAccountingTimestampSec;
        }

        // Aggregated staking values per user
        mapping(address => UserTotals) public userTotals;

        // The collection of stakes for each user. Ordered by timestamp, earliest to latest.
        mapping(address => Stake[]) private _userStakes;

        //
        // Locked/Unlocked Accounting state
        //
        struct UnlockSchedule {
            uint256 initialLockedShares;
            uint256 unlockedShares;
            uint256 lastUnlockTimestampSec;
            uint256 endAtSec;
            uint256 durationSec;
        }

        UnlockSchedule[] public unlockSchedules;

        /**
         * @param maxUnlockSchedules Max number of unlock stages, to guard against hitting gas limit.
         * @param startBonus_ Starting time bonus, BONUS_DECIMALS fixed point.
         * e.g. 25% means user gets 25% of max distribution tokens.
         * @param bonusPeriodSec_ Length of time for bonus to increase linearly to max.
         * @param initialSharesPerToken Number of shares to mint per staking token on first stake.
         */
        constructor(uint256 maxUnlockSchedules, uint256 startBonus_, uint256 bonusPeriodSec_, uint256 initialSharesPerToken) public {
            // The start bonus must be some fraction of the max. (i.e. <= 100%)
            require(startBonus_ <= 10**BONUS_DECIMALS, 'PrabhStaking: start bonus too high');
            // If no period is desired, instead set startBonus = 100%
            // and bonusPeriod to a small value like 1sec.
            require(bonusPeriodSec_ != 0, 'DittoStaking: bonus period is zero');
            require(initialSharesPerToken > 0, 'PrabhStaking: initialSharesPerToken is zero');

            IBEP20 distributionToken = IBEP20(0x8352A0a849cD181Cc7Ef61F972b7B8E5d677b66D); // DITTO
            
            _unlockedPool = new TokenPool(distributionToken);
            _lockedPool = new TokenPool(distributionToken);
            startBonus = startBonus_;
            bonusPeriodSec = bonusPeriodSec_;
            _maxUnlockSchedules = maxUnlockSchedules;
            _initialSharesPerToken = initialSharesPerToken;
            
            // MasterChef: Unlimited approval
            
            stakingToken.approve(address(pcsMasterChef), uint256(-1));
        }

        /**
         * @return The token users receive as they unstake.
         */
        function getDistributionToken() public view returns (IBEP20) {
            assert(_unlockedPool.token() == _lockedPool.token());
            return _unlockedPool.token();
        }

        /**
         * @dev Transfers amount of deposit tokens from the user.
         * @param amount Number of deposit tokens to stake.
        
         */
        function stake(uint256 amount) external {
            _stakeFor(msg.sender, msg.sender, amount);
        }

        /**
         * @dev Transfers amount of deposit tokens from the caller on behalf of user.
         * @param user User address who gains credit for this stake operation.
         * @param amount Number of deposit tokens to stake.
        
         */
        function stakeFor(address user, uint256 amount ) external onlyOwner {
            _stakeFor(msg.sender, user, amount);
        }

        /**
         * @dev Private implementation of staking methods.
         * @param staker User address who deposits tokens to stake.
         * @param beneficiary User address who gains credit for this stake operation.
         * @param amount Number of deposit tokens to stake.
         */
        function _stakeFor(address staker, address beneficiary, uint256 amount) private {
            require(amount > 0, 'DittoStaking: stake amount is zero');
            require(beneficiary != address(0), 'DittoStaking: beneficiary is zero address');
            require(totalStakingShares == 0 || totalStaked() > 0,
                    'DittoStaking: Invalid state. Staking shares exist, but no staking tokens do');

            uint256 mintedStakingShares = (totalStakingShares > 0)
                ? totalStakingShares.mul(amount).div(totalStaked())
                : amount.mul(_initialSharesPerToken);
            require(mintedStakingShares > 0, 'DittoStaking: Stake amount is too small');
            
            updateAccounting();
            
            // 1. User Accounting
            UserTotals storage totals = userTotals[beneficiary];
            
            totals.stakingShares = totals.stakingShares.add(mintedStakingShares);
            totals.lastAccountingTimestampSec = now;

            Stake memory newStake = Stake(mintedStakingShares, now);
            _userStakes[beneficiary].push(newStake);
            // 2. Global Accounting
            totalStakingShares = totalStakingShares.add(mintedStakingShares);
            // Already set in updateAccounting()
            // _lastAccountingTimestampSec = now;

            // interactions
            require(stakingToken.transferFrom(staker, address(this), amount),
                'DittoStaking: transfer into staking pool failed');
                
            pcsMasterChef.deposit(PrabhStaking_PID, amount);

            emit Staked(beneficiary, amount, totalStakedFor(beneficiary), "");
        }

        /**
         * @dev Unstakes a certain amount of previously deposited tokens. User also receives their
         * alotted number of distribution tokens.
         * @param amount Number of deposit tokens to unstake / withdraw.
         
         */
        function unstake(uint256 amount) external {
            _unstake(amount);
        }

        /**
         * @param amount Number of deposit tokens to unstake / withdraw.
         * @return The total number of distribution tokens that would be rewarded.
         */
        function unstakeQuery(uint256 amount) public returns (uint256) {
            return _unstake(amount);
        }

        /**
         * @dev Unstakes a certain amount of previously deposited tokens. User also receives their
         * alotted number of distribution tokens.
         * @param amount Number of deposit tokens to unstake / withdraw.
         * @return The total number of distribution tokens rewarded.
         */
        function _unstake(uint256 amount) private returns (uint256) {
            updateAccounting();

            // checks
            require(amount > 0, 'PrabhStaking: unstake amount is zero');
            require(totalStakedFor(msg.sender) >= amount,
                'DittoStaking: unstake amount is greater than total user stakes');
            uint256 stakingSharesToBurn = totalStakingShares.mul(amount).div(totalStaked());
            require(stakingSharesToBurn > 0, 'DittoStaking: Unable to unstake amount this small');
        
            // 1. User Accounting
            UserTotals storage totals = userTotals[msg.sender];
            Stake[] storage accountStakes = _userStakes[msg.sender];

            // Redeem from most recent stake and go backwards in time.
            uint256 stakingShareSecondsToBurn = 0;
            uint256 sharesLeftToBurn = stakingSharesToBurn;
            uint256 rewardAmount = 0;
            uint256 cakeRewardAmount = 0;
            
            // Withdraw the requested shares from MasterChef
            pcsMasterChef.withdraw(DITTO_BNB_PID, amount);
            uint256 cakeBalance = cake.balanceOf(address(this));
            
            while (sharesLeftToBurn > 0) {
                Stake storage lastStake = accountStakes[accountStakes.length - 1];
                uint256 stakeTimeSec = now.sub(lastStake.timestampSec);
                uint256 newStakingShareSecondsToBurn = 0;
                if (lastStake.stakingShares <= sharesLeftToBurn) {
                    // fully redeem a past stake
                    newStakingShareSecondsToBurn = lastStake.stakingShares.mul(stakeTimeSec);
                    rewardAmount = computeNewReward(rewardAmount, newStakingShareSecondsToBurn, stakeTimeSec);
                    stakingShareSecondsToBurn = stakingShareSecondsToBurn.add(newStakingShareSecondsToBurn);
                    sharesLeftToBurn = sharesLeftToBurn.sub(lastStake.stakingShares);
                    accountStakes.length--;
                } else {
                    // partially redeem a past stake
                    newStakingShareSecondsToBurn = sharesLeftToBurn.mul(stakeTimeSec);
                    rewardAmount = computeNewReward(rewardAmount, newStakingShareSecondsToBurn, stakeTimeSec);
                    stakingShareSecondsToBurn = stakingShareSecondsToBurn.add(newStakingShareSecondsToBurn);
                    lastStake.stakingShares = lastStake.stakingShares.sub(sharesLeftToBurn);
                    sharesLeftToBurn = 0;
                }
            }
            
            // Calculate proportionate CAKE reward amount
            cakeRewardAmount = cakeBalance.mul(stakingShareSecondsToBurn).div(_totalStakingShareSeconds);
            
            totals.stakingShareSeconds = totals.stakingShareSeconds.sub(stakingShareSecondsToBurn);
            totals.stakingShares = totals.stakingShares.sub(stakingSharesToBurn);
            // Already set in updateAccounting
            // totals.lastAccountingTimestampSec = now;

            // 2. Global Accounting
            _totalStakingShareSeconds = _totalStakingShareSeconds.sub(stakingShareSecondsToBurn);
            totalStakingShares = totalStakingShares.sub(stakingSharesToBurn);
            // Already set in updateAccounting
            // _lastAccountingTimestampSec = now;
            
            // interactions
            require(stakingToken.transfer(msg.sender, amount),
                'PrabhStaking: transfer out of staking pool failed');
            
            require(_unlockedPool.transfer(msg.sender, rewardAmount),
                'PrabhStaking: transfer out of unlocked pool failed');
            require(cake.transfer(msg.sender, cakeRewardAmount),
                'PrabhStaking: transfer of CAKE rewards failed');

            emit Unstaked(msg.sender, amount, totalStakedFor(msg.sender), "");
            emit TokensClaimed(msg.sender, rewardAmount);

            require(totalStakingShares == 0 || totalStaked() > 0,
                    "PrabhStaking: Error unstaking. Staking shares exist, but no staking tokens do");
            return rewardAmount;
        }

        /**
         * @dev Applies an additional time-bonus to a distribution amount. This is necessary to
         * encourage long-term deposits instead of constant unstake/restakes.
         * The bonus-multiplier is the result of a linear function that starts at startBonus and
         * ends at 100% over bonusPeriodSec, then stays at 100% thereafter.
         * @param currentRewardTokens The current number of distribution tokens already alotted for this
         * unstake op. Any bonuses are already applied.
         * @param stakingShareSeconds The stakingShare-seconds that are being burned for new
         * distribution tokens.
         * @param stakeTimeSec Length of time for which the tokens were staked. Needed to calculate
         * the time-bonus.
         * @return Updated amount of distribution tokens to award, with any bonus included on the
         * newly added tokens.
         */
        function computeNewReward(uint256 currentRewardTokens,
                                    uint256 stakingShareSeconds,
                                    uint256 stakeTimeSec) private view returns (uint256) {

            uint256 newRewardTokens =
                totalUnlocked()
                .mul(stakingShareSeconds)
                .div(_totalStakingShareSeconds);

            if (stakeTimeSec >= bonusPeriodSec) {
                return currentRewardTokens.add(newRewardTokens);
            }

            uint256 oneHundredPct = 10**BONUS_DECIMALS;
            uint256 bonusedReward =
                startBonus
                .add(oneHundredPct.sub(startBonus).mul(stakeTimeSec).div(bonusPeriodSec))
                .mul(newRewardTokens)
                .div(oneHundredPct);
            return currentRewardTokens.add(bonusedReward);
        }

        /**
         * @param addr The user to look up staking information for.
         * @return The number of staking tokens deposited for addr.
         */
        function totalStakedFor(address addr) public view returns (uint256) {
            return totalStakingShares > 0 ?
                totalStaked().mul(userTotals[addr].stakingShares).div(totalStakingShares) : 0;
        }

        /**
         * @return The total number of deposit tokens staked globally, by all users.
         */
        function totalStaked() public view returns (uint256) {
            IMasterChef.UserInfo memory userInfo = pcsMasterChef.userInfo(PrabhStaking_PID, address(this));
            
            return userInfo.amount;
        }

        /**
         * @dev A globally callable function to update the accounting state of the system.
         * Global state and state for the caller are updated.
         * @return [0] balance of the locked pool
         * @return [1] balance of the unlocked pool
         * @return [2] caller's staking share seconds
         * @return [3] global staking share seconds
         * @return [4] Rewards caller has accumulated, optimistically assumes max time-bonus.
         * @return [5] block timestamp
         */
        function updateAccounting() public returns (
            uint256, uint256, uint256, uint256, uint256, uint256) {

            unlockTokens();

            // Global accounting
            uint256 newStakingShareSeconds =
                now
                .sub(_lastAccountingTimestampSec)
                .mul(totalStakingShares);
            _totalStakingShareSeconds = _totalStakingShareSeconds.add(newStakingShareSeconds);
            _lastAccountingTimestampSec = now;

            // User Accounting
            UserTotals storage totals = userTotals[msg.sender];
            uint256 newUserStakingShareSeconds =
                now
                .sub(totals.lastAccountingTimestampSec)
                .mul(totals.stakingShares);
            totals.stakingShareSeconds =
                totals.stakingShareSeconds
                .add(newUserStakingShareSeconds);
            totals.lastAccountingTimestampSec = now;

            uint256 totalUserRewards = (_totalStakingShareSeconds > 0)
                ? totalUnlocked().mul(totals.stakingShareSeconds).div(_totalStakingShareSeconds)
                : 0;

            return (
                totalLocked(),
                totalUnlocked(),
                totals.stakingShareSeconds,
                _totalStakingShareSeconds,
                totalUserRewards,
                now
            );
        }

        /**
         * @return Total number of locked distribution tokens.
         */
        function totalLocked() public view returns (uint256) {
            return _lockedPool.balance();
        }

        /**
         * @return Total number of unlocked distribution tokens.
         */
        function totalUnlocked() public view returns (uint256) {
            return _unlockedPool.balance();
        }

        /**
         * @return Number of unlock schedules.
         */
        function unlockScheduleCount() public view returns (uint256) {
            return unlockSchedules.length;
        }

        /**
         * @dev This funcion allows the contract owner to add more locked distribution tokens, along
         * with the associated "unlock schedule". These locked tokens immediately begin unlocking
         * linearly over the duraction of durationSec timeframe.
         * @param amount Number of distribution tokens to lock. These are transferred from the caller.
         * @param durationSec Length of time to linear unlock the tokens.
         */
        function lockTokens(uint256 amount, uint256 durationSec) external onlyOwner {
            require(unlockSchedules.length < _maxUnlockSchedules,
                'PrabhStaking: reached maximum unlock schedules');

            // Update lockedTokens amount before using it in computations after.
            updateAccounting();

            uint256 lockedTokens = totalLocked();
            uint256 mintedLockedShares = (lockedTokens > 0)
                ? totalLockedShares.mul(amount).div(lockedTokens)
                : amount.mul(_initialSharesPerToken);

            UnlockSchedule memory schedule;
            schedule.initialLockedShares = mintedLockedShares;
            schedule.lastUnlockTimestampSec = now;
            schedule.endAtSec = now.add(durationSec);
            schedule.durationSec = durationSec;
            unlockSchedules.push(schedule);

            totalLockedShares = totalLockedShares.add(mintedLockedShares);

            require(_lockedPool.token().transferFrom(msg.sender, address(_lockedPool), amount),
                'PrabhStaking: transfer into locked pool failed');
            emit TokensLocked(amount, durationSec, totalLocked());
        }

        /**
         * @dev Moves distribution tokens from the locked pool to the unlocked pool, according to the
         * previously defined unlock schedules. Publicly callable.
         * @return Number of newly unlocked distribution tokens.
         */
        function unlockTokens() public returns (uint256) {
            uint256 unlockedTokens = 0;
            uint256 lockedTokens = totalLocked();

            if (totalLockedShares == 0) {
                unlockedTokens = lockedTokens;
            } else {
                uint256 unlockedShares = 0;
                for (uint256 s = 0; s < unlockSchedules.length; s++) {
                    unlockedShares = unlockedShares.add(unlockScheduleShares(s));
                }
                unlockedTokens = unlockedShares.mul(lockedTokens).div(totalLockedShares);
                totalLockedShares = totalLockedShares.sub(unlockedShares);
            }

            if (unlockedTokens > 0) {
                require(_lockedPool.transfer(address(_unlockedPool), unlockedTokens),
                    'PrabhStaking: transfer out of locked pool failed');
                emit TokensUnlocked(unlockedTokens, totalLocked());
            }

            return unlockedTokens;
        }

        /**
         * @dev Returns the number of unlockable shares from a given schedule. The returned value
         * depends on the time since the last unlock. This function updates schedule accounting,
         * but does not actually transfer any tokens.
         * @param s Index of the unlock schedule.
         * @return The number of unlocked shares.
         */
        function unlockScheduleShares(uint256 s) private returns (uint256) {
            UnlockSchedule storage schedule = unlockSchedules[s];

            if(schedule.unlockedShares >= schedule.initialLockedShares) {
                return 0;
            }

            uint256 sharesToUnlock = 0;
            // Special case to handle any leftover dust from integer division
            if (now >= schedule.endAtSec) {
                sharesToUnlock = (schedule.initialLockedShares.sub(schedule.unlockedShares));
                schedule.lastUnlockTimestampSec = schedule.endAtSec;
            } else {
                sharesToUnlock = now.sub(schedule.lastUnlockTimestampSec)
                    .mul(schedule.initialLockedShares)
                    .div(schedule.durationSec);
                schedule.lastUnlockTimestampSec = now;
            }

            schedule.unlockedShares = schedule.unlockedShares.add(sharesToUnlock);
            return sharesToUnlock;
        }

        function pendingCakeByUser(address _user) public view returns (uint256) {
            uint256 pendingCake = pcsMasterChef.pendingCake(PrabhStaking_BNB_PID, address(this));
            uint256 cakeBalance = cake.balanceOf(address(this));
            uint256 totalCakeRewardsAvailable = pendingCake.add(cakeBalance);
     
            if(_totalStakingShareSeconds == 0) {
                return 0;
            }
            
            uint256 newStakingShareSeconds =
                now
                .sub(_lastAccountingTimestampSec)
                .mul(totalStakingShares);
            
            uint256 totalStakingShareSeconds = _totalStakingShareSeconds.add(newStakingShareSeconds);
                
            UserTotals storage totals = userTotals[_user];
            
            uint256 newUserStakingShareSeconds =
                now
                .sub(totals.lastAccountingTimestampSec)
                .mul(totals.stakingShares);
                
            uint256 totalUserStakingShareSeconds =
                totals.stakingShareSeconds
                .add(newUserStakingShareSeconds);
            
            // Calculate CAKE reward amount

            return totalCakeRewardsAvailable.mul(totalUserStakingShareSeconds).div(totalStakingShareSeconds);
        }

        /**
         * @dev Lets the owner rescue funds air-dropped to this contract.
         * @param tokenToRescue Address of the token to be rescued.
         * @param to Address to which the rescued funds are to be sent.
         * @param amount Amount of tokens to be rescued.
         * @return Transfer success.
         */
        function rescueFunds(address tokenToRescue, address to, uint256 amount)
            public onlyOwner returns (bool) {

            return IBEP20(tokenToRescue).transfer(to, amount);
        }
    }
```

---

<div class="post-metadata">

**Author:** ![Skyge](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/skyge/32/343_2.png) [@Skyge](https://forum.openzeppelin.com/u/Skyge)\
**Post date:** [January 11, 2021, 4:48pm UTC](https://forum.openzeppelin.com/t/error-calling-staking-function-on-binance-smartchain-and-pancakeswap/5331/6 "2021-01-11T16:48:19Z")

</div>

So, it seems like the user should call the function named `stake` to stake, it looks fine, so could you please paste the failed transaction hash and what is net are you testing on the BSC-Chain?

---

<div class="post-metadata">

**Author:** ![Prabhakaran](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/prabhakaran/32/3288_2.png) [@Prabhakaran](https://forum.openzeppelin.com/u/Prabhakaran)\
**Post date:** [January 11, 2021, 6:11pm UTC](https://forum.openzeppelin.com/t/error-calling-staking-function-on-binance-smartchain-and-pancakeswap/5331/7 "2021-01-11T18:11:16Z")

</div>

Here is the transaction hash,and i am using binance mainnet

> **[Binance Transaction Hash (Txhash) Details | BscScan](https://bscscan.com/tx/0x7d4c870e5ad1d9baf225fbb013122ae39ceafe136cd8146e03975a42fca23096)**
>
> Binance (BNB) detailed transaction info for txhash 0x7d4c870e5ad1d9baf225fbb013122ae39ceafe136cd8146e03975a42fca23096. The transaction status, block confirmation, gas fee, BNB, and token transfer are shown.

---

<div class="post-metadata">

**Author:** ![Skyge](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/skyge/32/343_2.png) [@Skyge](https://forum.openzeppelin.com/u/Skyge)\
**Post date:** [January 12, 2021, 2:06am UTC](https://forum.openzeppelin.com/t/error-calling-staking-function-on-binance-smartchain-and-pancakeswap/5331/8 "2021-01-12T02:06:01Z")

</div>

A little complex, I need more time to debug.

---

<div class="post-metadata">

**Author:** ![Skyge](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/skyge/32/343_2.png) [@Skyge](https://forum.openzeppelin.com/u/Skyge)\
**Post date:** [January 12, 2021, 3:30pm UTC](https://forum.openzeppelin.com/t/error-calling-staking-function-on-binance-smartchain-and-pancakeswap/5331/9 "2021-01-12T15:30:44Z")

</div>

It seems like the problem is at this line:

```auto
pcsMasterChef.deposit(PrabhStaking_PID, amount);

```

You set the variable as `uint256 PrabhStaking_PID =52;`, so when I check `MasterChef.poolInfo(52)`, it shows like below:

 ![image](https://us1.discourse-cdn.com/flex022/uploads/zeppelin/original/2X/e/ea19a3a3e0ad7ed44a8a53083f3f4a67cd4a235b.png)

So the `LP token` is `0x3aB77e40340AB084c3e23Be8e5A6f7afed9D41DC` rather than

```bash
IBEP20 public stakingToken = IBEP20(0xf730d0aa2fDF7b03FB08218EBC6B03522D87C32a); 

```

in your contract. So maybe that’s the problem.

---

<div class="post-metadata">

**Author:** ![Prabhakaran](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/prabhakaran/32/3288_2.png) [@Prabhakaran](https://forum.openzeppelin.com/u/Prabhakaran)\
**Post date:** [January 12, 2021, 4:24pm UTC](https://forum.openzeppelin.com/t/error-calling-staking-function-on-binance-smartchain-and-pancakeswap/5331/10 "2021-01-12T16:24:05Z")

</div>

when i deploy my contract the overall poolnfo length is 51 in Masterchef thats why i give 52 as PID and deployed the staking contract.

I checked it in masterchef as you done but i doesn't shows any details for my PID.

> 0xf730d0aa2fdf7b03fb08218ebc6b03522d87c32a

this is my pair address(LP token) i got from pancakeswap .

I don't know why my PID and LPtoken is not added in Masterchef pool.Is there any steps done to added our LPtoken in masterchef contract.

---

<div class="post-metadata">

**Author:** ![Skyge](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/skyge/32/343_2.png) [@Skyge](https://forum.openzeppelin.com/u/Skyge)\
**Post date:** [January 13, 2021, 12:49am UTC](https://forum.openzeppelin.com/t/error-calling-staking-function-on-binance-smartchain-and-pancakeswap/5331/11 "2021-01-13T00:49:29Z")

</div>

I think only owner can add a new LP token pool.

---

<div class="post-metadata">

**Author:** ![Prabhakaran](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/prabhakaran/32/3288_2.png) [@Prabhakaran](https://forum.openzeppelin.com/u/Prabhakaran)\
**Post date:** [January 13, 2021, 2:28am UTC](https://forum.openzeppelin.com/t/error-calling-staking-function-on-binance-smartchain-and-pancakeswap/5331/12 "2021-01-13T02:28:30Z")

</div>

so i have deploy new masterchef contract instead of using common masterchef contract right?

---

<div class="post-metadata">

**Author:** ![Martina](https://avatars.discourse-cdn.com/v4/letter/m/85f322/32.png) [@Martina](https://forum.openzeppelin.com/u/Martina)\
**Post date:** [January 18, 2021, 3:05am UTC](https://forum.openzeppelin.com/t/error-calling-staking-function-on-binance-smartchain-and-pancakeswap/5331/13 "2021-01-18T03:05:12Z")

</div>

For that we want to deploy masterchef as separate contract ? and How Lp token can be added in masterchef contract? Can you help me to solve this problem.

---

<div class="post-metadata">

**Author:** ![Skyge](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/skyge/32/343_2.png) [@Skyge](https://forum.openzeppelin.com/u/Skyge)\
**Post date:** [January 18, 2021, 3:11am UTC](https://forum.openzeppelin.com/t/error-calling-staking-function-on-binance-smartchain-and-pancakeswap/5331/14 "2021-01-18T03:11:55Z")

</div>

If you want to use the current using contracts, I think, you have got to connect to the contract owner to add your LP token, of course, you can also deploy a new `masterchef contract`, so you are the contract owner and you can add what you want.

---

<div class="post-metadata">

**Author:** ![Skyge](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/skyge/32/343_2.png) [@Skyge](https://forum.openzeppelin.com/u/Skyge)\
**Post date:** [January 18, 2021, 3:14am UTC](https://forum.openzeppelin.com/t/error-calling-staking-function-on-binance-smartchain-and-pancakeswap/5331/15 "2021-01-18T03:14:11Z")

</div>

Emmm, you mean that you want to deploy the `masterchef contract`, right?

---

<div class="post-metadata">

**Author:** ![Martina](https://avatars.discourse-cdn.com/v4/letter/m/85f322/32.png) [@Martina](https://forum.openzeppelin.com/u/Martina)\
**Post date:** [January 18, 2021, 3:23am UTC](https://forum.openzeppelin.com/t/error-calling-staking-function-on-binance-smartchain-and-pancakeswap/5331/16 "2021-01-18T03:23:56Z")

</div>

Yes,If we deploy new master chef contract and how we can add our LP token to that contract,it will add automatically or we have to add it?

---

<div class="post-metadata">

**Author:** ![Skyge](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/skyge/32/343_2.png) [@Skyge](https://forum.openzeppelin.com/u/Skyge)\
**Post date:** [January 18, 2021, 3:32am UTC](https://forum.openzeppelin.com/t/error-calling-staking-function-on-binance-smartchain-and-pancakeswap/5331/17 "2021-01-18T03:32:22Z")

</div>

Call this function:

```auto
function add(uint256 _allocPoint, IBEP20 _lpToken, bool _withUpdate) public

```

by the owner account

---

<div class="post-metadata">

**Author:** ![Martina](https://avatars.discourse-cdn.com/v4/letter/m/85f322/32.png) [@Martina](https://forum.openzeppelin.com/u/Martina)\
**Post date:** [January 18, 2021, 4:03am UTC](https://forum.openzeppelin.com/t/error-calling-staking-function-on-binance-smartchain-and-pancakeswap/5331/18 "2021-01-18T04:03:46Z")

</div>

Thankyou @Skyge . I try and update it soon.

---

<div class="post-metadata">

**Author:** ![Martina](https://avatars.discourse-cdn.com/v4/letter/m/85f322/32.png) [@Martina](https://forum.openzeppelin.com/u/Martina)\
**Post date:** [January 18, 2021, 10:34am UTC](https://forum.openzeppelin.com/t/error-calling-staking-function-on-binance-smartchain-and-pancakeswap/5331/19 "2021-01-18T10:34:09Z")

</div>

Hi @Skyge ,now “function add(uint256 \_allocPoint, IBEP20 \_lpToken, bool \_withUpdate) public” this will work after this i call stake function its now working but when i call unstake function it will produce gas etimation error.can you help me.

---

<div class="post-metadata">

**Author:** ![Prabhakaran](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/prabhakaran/32/3288_2.png) [@Prabhakaran](https://forum.openzeppelin.com/u/Prabhakaran)\
**Post date:** [January 18, 2021, 10:38am UTC](https://forum.openzeppelin.com/t/error-calling-staking-function-on-binance-smartchain-and-pancakeswap/5331/20 "2021-01-18T10:38:13Z")

</div>

Thanks @Skyge as per your advice i deployed masterchef contract and added LP token to masterchef pool and stake function also working now but after stake function i call unstake function it doesnt work it shows gas estimation error,although i send transaction and i cheked it in binancescan it show error like this

> Fail with error 'Ownable: caller is not the owner'

Tnxhash:  
0xda243f37bf4328fbefed50ed57b3855b2fffbe06cbe77e405f38f19b15de5523

 ![2021-01-18 (3)](https://us1.discourse-cdn.com/flex022/uploads/zeppelin/original/2X/f/f9b7cd1d7565b8be0669c3c9e76731a39e5e4385.png)

[Next page](https://forum.openzeppelin.com/t/error-calling-staking-function-on-binance-smartchain-and-pancakeswap/5331.md?page=2)
