Model-Based Farming Manager

Contract NameGithubDeployed Contract AddressContract ImplementedInitialization Data

ModelBasedFarmingManager

Coming soon

Coming soon

IModelBasedFarmingManager, LazyInitCapableElement

_flushKey, executorRewardPercentage, infoModels, _rebalancePercentages, firstRebalanceBlock, _rebalanceInterval and

LazyInitCapableElement init data

Model-Based Farming Manager Initialization

The ModelBasedFarmingManager must be initialized by the farming contract itself; specifically, via the init function of the farming contract:

function init(address extension, bytes memory extensionInitData, address rewardTokenAddress, bytes memory farmingSetupInfosBytes) public returns(bytes memory extensionReturnCall)
  • address extension -> The address of the Model-Based Farming Manager contract must be passed as address extension.

  • bytes extensionInitData -> The initialization data of the Model-Based Farming Manager must be passed as bytes extensionInitData. Look below for more information on Model-Based Farming Manager initialization data.

  • address rewardTokenAddress -> address of the Farming contract reward token. There can be only one reward token per Farming contract.

  • bytes farmingSetupInfosBytes -> ABI-encoded data of the contract's farmingSetupInfos structs used to create Farming setups. Look here for more info.

Following the creation of the farming contract and initialization of the Farming Manager, the organization must, through a proposal, link the Farming Manager to itself as an active component (to learn more, see here).

Model-Based Farming Manager initialization data

The initialization data of the Model-Based Farming Manager contract must be passed as extensionInitData when initializing the Farming contract.

In particular the Model-Based Farming Manager init data are:

function _lazyInit(bytes memory lazyInitData) internal override returns(bytes memory) {
    uint256 firstRebalanceBlock;
    uint256 _rebalanceInterval;

    FarmingSetupInfo[] memory infoModels;
    (_flushKey, executorRewardPercentage, infoModels, _rebalancePercentages, firstRebalanceBlock, _rebalanceInterval) = abi.decode(lazyInitData, (bytes32, uint256, FarmingSetupInfo[], uint256[], uint256, uint256));

    for(uint256 i = 0; i < infoModels.length; i++) {
        _models.push(infoModels[i]);
    }

    if((rebalanceInterval = _rebalanceInterval) > 0) {
        if(firstRebalanceBlock != 0 && _rebalanceInterval < firstRebalanceBlock) {
            lastRebalanceBlock = firstRebalanceBlock - _rebalanceInterval;
        }
    }
    _rewardTokenAddress = IFarmMainRegular(_farmingContract = msg.sender)._rewardTokenAddress();
    _setModels(_models, _rebalancePercentages);
    return "";
}
  • bytes32 _flushKey -> it's the Organization Component key where unissued Farming tokens are sent. If it's passed as bytes32(0) the Organization Treasury Manager is automatically taken.

  • uint256 executorRewardPercentage -> this is the percentage of the reward token that the rebalanceRewardsPerBlock function caller--AKA, the msg.sender--will receive as a reward.

  • FarmingSetupInfo[] infoModels -> it represents the FarmingSetupInfo struct(s) from which the farming setups will be created.

  • uint256[] _rebalancePercentages -> it represents the percentage of reward tokens split between the various farming setups. This array's length must be equal to infoModels.length-1 . For example, if you have 2 models and you want to split the token amount 60% in the first one and 40% on the second one, you have to pass only 60%. The other percentage is automatically calculated as 100-60

  • uint256 firstRebalanceBlock -> this is the first block at which the rebalanceRewardsPerBlock function can be called.

  • uint256 _rebalanceInterval -> this is how many blocks must pass between each execution of rebalanceRewardsPerBlock.

ModelBasedFarmingManager is a LazyInitCapableElement, and so the initialization data must follow this pattern. In particular, the host of the Model-Based Farming Manager must be the address of the Organization to which it will be linked as an active component. The host address parameter must be initialized together with the above parameters.

How does the creation of farming setups work?

The Farming setups can be created at the initialization of the Farming contract.

InfoModels, or models, are created in the initialization data of the model-based Farming Manager. Each time the rebalanceRewardsPerBlock function is called, according to the defined block interval, many new Farming setups are created as there are models defined.

For each model waits, an amount of reward tokens equal to (balance of the Model-Based Farming Manager * its specific _rebalancePercentages) / the duration of the setup defined within the specific model.

If, for example, there is only one model, at each rebalanceRewardsPerBlock only one new Farming setup will be created with a total reward per block equal to the entire balance of the Model-Based Farming Manager.

If, for example, there are:

  • model 1 with _rebalancePercentages equal to 40%.

  • model 2 with _rebalancePercentages equal to 60%.

At each rebalanceRewardsPerBlock two new Farming setups will be created with:

  • reward per block setup 1 = 40% of the balance of the Model-Based Farming Manager at the time of rebalanceRewardsPerBlock.

  • reward for block setup 2 = 60% of the balance of the Model-Based Farming Manager at the time of rebalanceRewardsPerBlock.

Example: how to create and initialize a Farming contract linked to a Model-Based Farming Manager

The following example shows how to correctly pass the Farming contract and Model-Based Farming Manager contract init data.

The example uses

var modelTypes = [
    "uint256", //uint256 blockDuration; duration of setup
    "uint256", //uint256 startBlock; optional start block used for the delayed activation of the first setup
    "uint256", //uint256 originalRewardPerBlock
    "uint256", //uint256 minStakeable; minimum amount of staking tokens
    "uint256", //uint256 renewTimes; if the setup is renewable or if it's one time
    "address", //address liquidityPoolTokenAddress; address of the liquidity pool token
    "address", //address mainTokenAddress
    "bool",    //bool involvingETH; if the setup involves ETH or not.
    "uint256", //uint256 setupsCount; number of setups created by this info
    "uint256", //uint256 lastSetupIndex; index of last setup
    "int24",   //int24 tickLower; tickLower of the UniswapV3 pool
    "int24"    //int24 tickUpper; tickUpper of the UniswapV3 pool 
];

var models = [[
    10000,
    0,
    0,
    300,
    0,
    yourLPAddress,
    yourRewardTokenAddress,
    true,
    0,
    0,
    -145000,
    39200
]]

var initData = abi.encode(["bytes32", "uint256", `tuple(${modelTypes.join(',')})[]`, "uint256[]", "uint256", "uint256"],
[
    utilities.voidBytes32,
    yourExecutorRewardPercentage,
    models,
    [],
    0,
    yourBlockInterval
])

// Model-Based Farming Manager host address
initData = web3.eth.abi.encodeParameters(["address", "bytes"], [yourHostAddress, initData])

var deployData = modelBasedFarmingManager.methods.lazyInit(initData).encodeABI()

var lazyInitData = web3.eth.abi.encodeParameters(["address", "bytes", "address", "bytes"], [
    modelBasedFarmingManager.options.address,
    deployData,
    yourRewardTokenAddress,
    "0x"
])

await blockchainCall(factory.methods.deploy, lazyInitData, {from : yourWallet})

return modelBasedFarmingManager.options.address;
}

Farming Contract Interaction

The Model-Based Farming Manager provides the following interaction functions with the Farming contract.

transferTo

function transferTo(uint256 amount) external;l

This function, which can be called only by the farming contract itself, is used to send the required amount of reward tokens from the Model-Based Farming Manager to the farming contract; this must be done before the contract's setups can be or at the moment they are activated (see here to learn more).

backToYou

function backToYou(uint256 amount) external payable;

This function, which can be called only by the farming contract itself, is used to send back any unissued reward tokens from a farming contract after all its setups have ended back to the Model-Based Farming Manager (see here to learn more).

rebalanceRewardsPerBlock

function rebalanceRewardsPerBlock(address executorRewardReceiver) external;

The function creates a new Farming setup for each model set in the Model-Based Farming Manager contract splitting the reward token balance according to the _rebalancePercentages set.

The function can be called every time the set interval in blocks is reached (_rebalanceInterval).

Anyone can call it, and whoever does receives a reward (which serves as an economic incentive).

As input, it takes the address of the executorReward receiver address, which is msg.sender unless the caller specifies otherwise.

The executorReward is calculated as (the reward token amount to be split x executorReward percentage).

The percentage amounts to be sent to each receiver are then calculated.

flushBackToTreasury

function flushBackToTreasury(address[] calldata tokenAddresses) external;

This function, which can be called only by all authorized subjects and Components linked to the Organization, is used to send tokens from the Model-Based Farming Manager contract to the flusher Component set (_flushKey).

It can be used to send to the flusher unissued reward tokens sent to the Model-Based Farming Manager by the backToYou function.

setFarmingSetups

function setFarmingSetups(FarmingSetupConfiguration[] memory farmingSetups) external;l

This function, which can be called by all authorized subjects and Components linked to the Organization, is used to add new Farming setups and modify existing setups of the Farming contract. See here to learn more.

setTreasury

function setTreasury(address) external override authorizedOnly {
    revert("Impossibru!");
}

The Farming Manager address is automatically set as the Farming contract treasury, and cannot be changed. See here to learn more.

Last updated