Error calling staking function on Binance smartchain and pancakeswap

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

2 Likes

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

LPToken.approve(stakingContract, approvalAmount);

and if possible, please paste your code.

1 Like

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

1 Like

emmmm, could you please share your code?

1 Like

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);
        }
    }
1 Like

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?

2 Likes

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

1 Like

A little complex, I need more time to debug.

2 Likes

It seems like the problem is at this line:

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:

So the LP token is 0x3aB77e40340AB084c3e23Be8e5A6f7afed9D41DC rather than

IBEP20 public stakingToken = IBEP20(0xf730d0aa2fDF7b03FB08218EBC6B03522D87C32a); 

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

1 Like

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.

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

1 Like

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

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.

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.

1 Like

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

1 Like

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?

1 Like

Call this function:

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

by the owner account

1 Like

Thankyou @Skyge . I try and update it soon.

1 Like

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.

1 Like

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

1 Like