PancakeSwap Worker
Table of content
Background
Once user want to open position / manage position at PancakeSwap farming, a vault contract will call a contract that deployed with this worker contract
PancakeSwap is an AMM DEX that allows traders to convert one asset to another asset without order book. Users can provide liquidity to the market by providing a pair of asset with 1:1 value. For example, if current price of BNB = 500 USDT, liquidity provider need to provide 1 BNB and 500 USDT to the liquidity pool so that other can exchange directly with the pool instead of another trader.
To provide incentive to liquidity provider, AMM DEX traditionally grant a third token as a reward to compensate the opportunity cost of trading. This is where the yield farming come in to play. Alpaca finance provide a platform that allow liquidity provider to provide a liquidity with margin. Meaning they can provide a liquidity more than they currently have.
In this implementation of worker at PancakeSwap, the responsibility of PancakeSwap worker is to manage the LP token on behalf of users. This also included the borrowed capital as well.
Abstract
- PancakeSwap is a fork of UniSwap V2 and use constant x*y = k curve AMM as their engine.
- Each worker that get deployed will have a different set of base token and farm token. Read more about base token and farm token at Worker Contract
- Worker keep track of each position portion relative to total amount of LP that this worker hold on behalf of user by
- LP share : Represent a portion of LP token with respect to the overall LP token that this worker hold
- LP Balance : Actual amount of LP token that will be used to deposit to / withdraw from PancakeSwap MasterChef contract
- ** Note. PancakeSwap MasterChef contract work similarly like Alpaca's FairLaunch contract. FairLaunch Contract
Attributes
PancakeSwap Worker Attribute
Name | Type | Public | Description |
---|---|---|---|
masterChef | IPcancakeMasterChef | PancakeSwap Masterchef address | |
factory | IPancakeFactory | PancakeSwap Factory address | |
router | IPancakeRouter02 | PancakeSwap Router address | |
lpToken | IPancakePair | PancakeSwap LP address | |
wNative | address | Address of wrap native token | |
baseToken | address | Address of base token | |
farmingToken | address | Address of farm token | |
cake | address | Address of CAKE token | |
operator | address | Vault address | |
pid | uint256 | PancakeSwap Masterchef Pool ID | |
shares | mappinguint256 | mapping of position's share amount | |
okStrats | addressboolmapping | List of whitelisted strategy contracts | |
totalShare | uint256 | Total of share that issued to positions | |
addStrat | IStrategy | Address of strategy contract that will do adding liquidity to underlying LP | |
liqStrat | IStrategy | Address of strategy contract that will do the remove liquidity from underlying LP | |
reinvestBountyBps | uint256 | Basis point that will allocate portion of reward back to caller | |
maxReinvestBountyBps | uint256 | Maximum that reinvest bounty basis point canbe | |
okReinveestors | mapping | List of whitelisted reinvestor address | |
fee | uint256 | Trading fee at PancakeSwap | |
feeDenom | uint256 | Denominator of the fee used | |
reinvestThreshold | uint256 | A threshold that will not trigger reinvest operation | |
reinvestPath | addressarray | A path that used in reinvesting back to LP | |
treasuryAccount | address | Address that will the contract will keep the platform revenue | |
treashuryBountyBps | uint256 | Basis point that allocated for platform revenue | |
benificialVault | address | A Vault address that will benefit from reinvesting | |
benificialValutBountyBps | uint256 | Basis point that allocated the reward back to the vault | |
buybackAmount | uint256 | Temporary state variable used to handle transferring base token to beneficial vault address |
Modifier
onlyEOAorWhitelisted
/// @dev Require that the caller must be an EOA account to avoid flash loans.
modifier onlyEOA() {
require(msg.sender == tx.origin, "PancakeswapV2Worker02::onlyEOA:: not eoa");
_;
}
Logic
- the caller must be an external own account.
- Otherwise, revert transaction.
onlyOperator
/// @dev Require that the caller must be the operator.
modifier onlyOperator() {
require(msg.sender == operator, "PancakeswapV2Worker02::onlyOperator:: not operator");
_;
}
Logic
- the caller address must be the same as configured
- Otherwise, revert transaction.
onlyReinvestor
//// @dev Require that the caller must be ok reinvestor.
modifier onlyReinvestor() {
require(okReinvestors[msg.sender], "PancakeswapV2Worker02::onlyReinvestor:: not reinvestor");
_;
Logic
- the caller address must be the same as configured
- Otherwise, revert transaction.
Functions
Functions
Name | Type | Description | Documented |
---|---|---|---|
initialize | External | Initialize the contract once deployed | |
shareToBalance | PublicView | Get share amount from balance | |
balanceToShare | PublicView | Get balance from share amount | |
reinvest | External | Compound reward back to position | |
_reinvest | Internal | ||
work | External | Operate on positions | |
getMktSellAmount | PublicView | Check market if a token was to be sold | |
health | ExternalView | Check market value of position | |
liquidate | External | Liquidate position | |
_rewardToBeneficialVault | Internal | ||
_buyback | Internal | ||
actualBaseTokenBalance | InternalView | Get balance of base token that this contract is holding | |
_addShare | Internal | ||
_removeShare | Internal | ||
getPath | ExternalView | ||
getReversePath | ExternalView | ||
getRewardPath | ExternalView | ||
getReinvestPath | ExternalView | ||
setReinvestConfig | ExternalOwner | ||
setMaxReinvestBountyBps | ExternalOwner | ||
setStrategyOk | ExternalOwner | ||
setReinvestorOk | ExternalOwner | ||
setRewardPath | ExternalOwner | ||
setCriticalStrategies | ExternalView | ||
setTreasuryConfig | ExternalOwner | ||
setBeneficialVaultConfig | ExternalOwner |
initialize
Use case
- Deploy worker to be allow users to work on a specific base token / farm token pair
function Params
Name | Type | Description |
---|---|---|
_operator | address | Contract address that bound to this contract. Normally will be a vault contract |
_baseToken | address | ERC20 address of the token that will be considered as base token |
_masterChef | IPancakeMasterChef | PancakeSwap's Master Chef contract that will be used during working |
_router | IPancakeRouter | PancakeSwap's Router contract that will be used during working |
_pid | uint256 | Pool ID that associated with PancakeSwap's Master Chef that will accept the LP token and yield Cake token |
_addStrat | IStrategy | a contract address that will be used for adding liquidity to PancakeSwap liquidity pool |
_liqStrat | IStrategy | a contract address that will be used to break the LP token at PancakeSwap |
_reinvestBountyBps | uint256 | Basis Point that used to calculate an incentive for reinvesting the position |
_treasureyAccount | address | Address that will keep the revenue from working related |
_reinvestPath | addressarray | An array of address that associated with swapping a token to reinvest in the LP position |
_reinvestThreshold | uint256 | Threshold to triggered reinvestment if pending cake reward reached |
Untitled |
Logic
- Set corresponding state variable
- Check validity of configuration
shareToBalance
Use case
- Check the LP balance that belongs to the user
function Params
Name | Type | Description |
---|---|---|
share | uint256 | Amount of share to convert to value |
Logic
- When there's no share, 1 share = 1 balance
- Get total balance from PancakeSwap MasterChef contract
- Calculate balance by total balance * ( share / total share in this contract )
balanceToShare
Use case
- Convert token amount to share amount respectively to this contract's total share
function Params
Name | Type | Description |
---|---|---|
balance | uint256 | Total amount to calculate to share amount |
Logic
- When there's no share, 1 share = 1 balance
- Get total balance as a denominator from PancakeSwap MasterChef contract
- calculate share by total share * (balance / total balance)
reinvest
Use case
- Allow whitelisted bot to claim CAKE reward, convert to LP token, compound back to the positions
- ** There will be fee for doing so that will go to reinvest bot. This will be our platform revenue.
function Params
Name | Type | Description |
---|---|---|
Untitled |
Logic
- Call _reinvest() internal function passing the caller address as a treasury account
- call _buyback() internal function
_reinvest
Use case
- Called from reinvest function
- Triggered at the beginning of work function where positions are being adjust
function Params
Name | Type | Description |
---|---|---|
_treasuryAccount | address | Address that will get some cut out of the reward from LP position |
_treasuryBountyBps | uint256 | Basis point that will deduct from the reward |
_callerBalance | uint256 | amount to be exclude from sending to treasury account |
_reinvestThreshold | uint256 | Threshold to skip if CAKE reward of the LP position is low |
Logic
- Claim all the CAKE reward first
- Check CAKE balance in this contract
- If CAKE is below reinvest threshold, exit this function
- calculate bounty for calling this reinvest function by _treasuryBountyBps * total CAKE reward
- Cut some amount our of bounty to beneficial vault ( Vault's contract )
- Transfer remaining bounty reward to treasury account
- Convert all non-bounty reward to base token
- Transfer base token to configure strategy contract that will do the converting BaseToken to LP token
- Execute the strategy, expected the strategy will transfer the LP back
- Deposit all LP token to PancakeSwap's MasterChef contract
work
Use case
- Called by a vault contract to do one of the following
- Open position
- Add collateral
- Close position
- Partially close the position
function Params
Name | Type | Description |
---|---|---|
id | uint256 | Position ID to work on |
user | address | The original user that is interacting with the operator. |
debt | uint256 | The amount of user debt to help the strategy make decisions |
data | bytescalldata | The encoded data, consisting of strategy address and calldata |
Logic
- trigger _reinvest internal function if configured
- Get the share amount of this position and convert it back to LP token
- Execute a strategy contract that passed via data variable
- add the LP token back to PancakeSwap's MasterChef contract. If the action is to close the position this will eventually be skipped
- Return any remaining BaseToken back to the caller. Typically the vault contract.
getMktSellAmount
Use case
- Check the position value as a base token amount if the position to be convert all to the base token
- Called from health function
function Params
Name | Type | Description |
---|---|---|
aIn | uint256 | The amount of asset to market sell |
rIn | uint256 | The amount of asset in reserve for input |
rOut | uint256 | The amount of asset in reserve for output |
Logic
- If aIn = 0, return 0
- calculate using x*y = k formula
- return the calculation with trading fee in consideration
health
Use case
- Check the position's health
- Use to check validity of liquidation of the position
- Display the health in Alpaca frontend interface
function Params
Name | Type | Description |
---|---|---|
id | uint256 | Position ID to check it's health |
Logic
- Calculate the LP of this position
- Get the pool's total supply of BaseToken and FarmingToken
- Calculate the token amounts if to convert the position's LP tokens to the underlying assets
- call getMktSellAmount function supplying farm token as an input
- return the sum of base token from step 3 and step 4
liquidate
Use case
- Once the position is underwater, meaning the debt of the position almost equal to the collateral, the position will be eligible for liquidation
- LP token will be convert to base token, return the debt to a vault contract and remaining back to position owner
function Params
Name | Type | Description |
---|---|---|
id | uint256 | The position ID to perform liquidation |
Logic
- Convert the position back to LP tokens
- Transfer the LP token to configured liquidation strategy contract
- Return all available BaseToken back to the caller, typically a vault contract
_rewardToBeneficialVault
Use case
- Called from _reinvest function
- use to transfer part of the CAKE reward to the vault that associated with this position
function Params
Name | Type | Description |
---|---|---|
_pid | uint256 | The target Pool ID that user will withdraw staked token neglecting the Alpaca reward |
Logic
- read base token from the vault of interest contract
- swap reward token to beneficialVaultToken
- if beneficialvault token not equal to baseToken regardless of a caller balance, can directly transfer to beneficial vault
- otherwise, need to keep it as a buybackAmount,
** since beneficial vault is the same as the calling vault, it will think of this reward as a `back` amount to pay debt/ sending back to a position owner
_buyback
Use case
- If the base token of the worker is not the same with the vault token, this will be skipped
Logic
- Transfer the token to beneficial vault contract
actualBaseTokenBalance
Use case
- Since buybackAmount variable has been created to collect a buyback balance when during the reinvest within the work method, thus the actualBaseTokenBalance exists to differentiate an actual base token balance balance without taking buy back amount into account
Logic
- Return token amount excluding the amount to buyback
_addShare
Use case
- Internal function to stake all outstanding LP tokens to the given position ID
- Used at the end of when there's an operation to the positions
function Params
Name | Type | Description |
---|---|---|
id | uint256 | Position ID to add share |
Logic
- Get the total amount of LP hold by this contract
- If there's none, exit
- deposit all LP token to PancakeSwap's MasterChef contract
- Calculate the share of this position
- Update the total share value
_removeShare
Use case
- At the beginning of ever work operation on positions, it will call this function to recalculate everything
- If position to be liquidate, this will be called as well
function Params
Name | Type | Description |
---|---|---|
id | uint256 | Position ID of interest |
Logic
- Calculate the LP balance from the share of the position
- Withdraw amount of LP from step 1 from PancakeSwap MasterChef contract
- Subtract the position share from total share of this contract
getPath
Use case
- Check the path that the worker is working on
Logic
- Return array of address where first element is the base token address and farm token as the second element
getReversedPath
Use case
- Check the path that the worker is working on but in reverse direction
Logic
- Return array of address where first element is the farm token address and base token as the second element
getRewardPath
Use case
- Check the configured path of reward
Logic
- Return the reward path vairable
getReinvestPath
Use case
- Internal function to get reinvest path. Return route through WBNB if reinvestPath not set
- Used in _reinvest function where swapping reward token to base token happened
Logic
- If the configured path has more than one element, return the configured one
- If the base token is a wrap Native token, return an array of reward as a first element and wNative token as the second element
- If the base token is an ERC20 token, return an array of reward as a first element and wNative token as the second element, and base token as a last element
setReinvestConfig
Use case
- Config parameters for the reinvest operation
function Params
Name | Type | Description |
---|---|---|
_reinvestBountyBps | uint256 | Basis point to cut from reward from farming that will go to reinvester |
_reinvestThreshold | uint256 | Threshold that will skip the reinvest if not met |
_reinvestPath | addressarray | Path used in converting CAKE reward to base token |
Logic
- Set state variables according to the function input
setMaxReinvestBountyBps
Use case
- Additional configuration to reinvest scenario
function Params
Name | Type | Description |
---|---|---|
_maxReinvestBountyBps | uint256 | Maximum basis point that will cut from farming reward token |
Logic
- Set the state variable from the function input
- Basis point can't exceed 3000 (30%)
setStrategyOk
Use case
- Whitelist the contract list of strategies that this worker can call
- This is to prevent malicious strategy contract injection
function Params
Name | Type | Description |
---|---|---|
strats | addressarray | List of addresses that implement strategy interface |
isOk | bool | True if whitelist, false if to blacklist |
Logic
- Loop through all address
- Set the flag to whitelist/blacklist according to isOk flag
setReinvestorOk
Use case
- Whitelist the list of reinvest address allowed to do reinvest operation
- This is to prevent malicious reinvestor that can manipulate the price of underlying LP pair then liquidate
function Params
Name | Type | Description |
---|---|---|
reinvestors | addressarray | List of addresses |
isOk | bool | True if whitelist, false if to blacklist |
Logic
- Loop through all address
- Set the flag to whitelist/blacklist according to isOk flag
setRewardPath
Use case
- Set path for converting CAKE token to base token
function Params
Name | Type | Description |
---|---|---|
_rewardPath | addressarray | List of token address |
Logic
- Last element of the array must be the base token
- Set the state variable from the function input
setCriticalStrategies
Use case
- Set the strategy contract addresses that is a mandatory to operate a worker contract
- Add base token strategy
- Open position
- Reinvest
- Add collateral
- Liquidate strategy
- Close position
- Liquidate position
- Add base token strategy
function Params
Name | Type | Description |
---|---|---|
_addStrat | IStrategy | Strategy address use for adding liquidity to underly DEX LP pair |
_liqStrat | IStrategy | Strategy address use for removing liquidity to underly DEX LP pair |
Logic
- Set state variables according to the function input
setTreasuryConfig
Use case
- Set treasury configurations
function Params
Name | Type | Description |
---|---|---|
_treasuryAccount | address | The treasury address to update |
_treasuryBountyBps | uint256 | The treasury bounty to update |
Logic
- Set state variables according to the function input
setBeneficialVaultConfig
Use case
- Set beneficial vault related data including beneficialVaultBountyBps, beneficialVaultAddress, and rewardPath
function Params
Name | Type | Description |
---|---|---|
_beneficialVaultBountyBps | uint256 | The bounty basis point value to update |
_beneficialVault | IVault | Address of contract that implement vault contract |
_rewardPath | addressarray | List of token address |
Logic
- Set state variables according to the function input