Skip to content

Commit

Permalink
create SptFarm, the incentive mechanism for policyholders (#225)
Browse files Browse the repository at this point in the history
* create SptFarm, the incentive mechanism for policyholders

* test SptFarm

* feat/SptFarm: add deposit/withdraw multiple policy functions

* feat/SptFarm: deploy to all networks
  • Loading branch information
leonardishere authored Nov 1, 2021
1 parent 6d6df16 commit 39fe476
Show file tree
Hide file tree
Showing 12 changed files with 1,776 additions and 35 deletions.
2 changes: 1 addition & 1 deletion architecture_diagram.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion contracts/CpFarm.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import "./interface/ICpFarm.sol";
/**
* @title CpFarm
* @author solace.fi
* @notice Rewards [**Capital Providers**](/docs/user-guides/capital-provider/cp-role-guide) in [**SOLACE**](./SOLACE) for providing capital in the [`Vault`](./Vault).
* @notice Rewards [**Capital Providers**](/docs/user-guides/capital-provider/cp-role-guide) in [`Policy Manager`](./PolicyManager) for providing capital in the [`Vault`](./Vault).
*
* Over the course of `startTime` to `endTime`, the farm distributes `rewardPerSecond` [**SOLACE**](./SOLACE) to all farmers split relative to the amount of [**SCP**](./Vault) they have deposited.
*
Expand Down
537 changes: 537 additions & 0 deletions contracts/SptFarm.sol

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions contracts/interface/ICpFarm.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import "./IFarm.sol";
/**
* @title CpFarm
* @author solace.fi
* @notice Rewards [**Capital Providers**](/docs/user-guides/capital-provider/cp-role-guide) in [**SOLACE**](../SOLACE) for providing capital in the [`Vault`](../Vault).
* @notice Rewards [**Capital Providers**](/docs/user-guides/capital-provider/cp-role-guide) in [**Options**](../OptionFarming) for providing capital in the [`Vault`](../Vault).
*
* Over the course of `startTime` to `endTime`, the farm distributes `rewardPerSecond` [**SOLACE**](../SOLACE) to all farmers split relative to the amount of [**SCP**](../Vault) they have deposited.
* Over the course of `startTime` to `endTime`, the farm distributes `rewardPerSecond` [**Options**](../OptionFarming) to all farmers split relative to the amount of [**SCP**](../Vault) they have deposited.
*
* Users can become [**Capital Providers**](/docs/user-guides/capital-provider/cp-role-guide) by depositing **ETH** into the [`Vault`](../Vault), receiving [**SCP**](../Vault) in the process. [**Capital Providers**](/docs/user-guides/capital-provider/cp-role-guide) can then deposit their [**SCP**](../Vault) via [`depositCp()`](#depositcp) or [`depositCpSigned()`](#depositcpsigned). Alternatively users can bypass the [`Vault`](../Vault) and stake their **ETH** via [`depositEth()`](#depositeth).
*
Expand Down
137 changes: 137 additions & 0 deletions contracts/interface/ISptFarm.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.6;

import "./IPolicyManager.sol";
import "./IFarm.sol";


/**
* @title ISptFarm
* @author solace.fi
* @notice Rewards [**Policyholders**](/docs/protocol/policy-holder) in [**Options**](../OptionFarming) for staking their [**Policies**](./PolicyManager).
*
* Over the course of `startTime` to `endTime`, the farm distributes `rewardPerSecond` [**Options**](../OptionFarming) to all farmers split relative to the value of the policies they have deposited.
*
* Note that you should deposit your policies via [`depositPolicy()`](#depositpolicy) or [`depositPolicySigned()`](#depositpolicysigned). Raw `ERC721.transfer()` will not be recognized.
*/
interface ISptFarm is IFarm {

/***************************************
EVENTS
***************************************/

// Emitted when a policy is deposited onto the farm.
event PolicyDeposited(address indexed user, uint256 policyID);
// Emitted when a policy is withdrawn from the farm.
event PolicyWithdrawn(address indexed user, uint256 policyID);
/// @notice Emitted when rewardPerSecond is changed.
event RewardsSet(uint256 rewardPerSecond);
/// @notice Emitted when the end time is changed.
event FarmEndSet(uint256 endTime);

/***************************************
VIEW FUNCTIONS
***************************************/

/// @notice
function policyManager() external view returns (address policyManager_);

/// @notice Last time rewards were distributed or farm was updated.
function lastRewardTime() external view returns (uint256 timestamp);

/// @notice Accumulated rewards per share, times 1e12.
function accRewardPerShare() external view returns (uint256 acc);

/// @notice Value of policies a user deposited.
function userStaked(address user) external view returns (uint256 amount);

/// @notice Value of policies deposited by all farmers.
function valueStaked() external view returns (uint256 amount);

/// @notice Information about a deposited policy.
function policyInfo(uint256 policyID) external view returns (address depositor, uint256 value);

/**
* @notice Returns the count of [**policies**](./PolicyManager) that a user has deposited onto the farm.
* @param user The user to check count for.
* @return count The count of deposited [**policies**](./PolicyManager).
*/
function countDeposited(address user) external view returns (uint256 count);

/**
* @notice Returns the list of [**policies**](./PolicyManager) that a user has deposited onto the farm and their values.
* @param user The user to list deposited policies.
* @return policyIDs The list of deposited policies.
* @return policyValues The values of the policies.
*/
function listDeposited(address user) external view returns (uint256[] memory policyIDs, uint256[] memory policyValues);

/**
* @notice Returns the ID of a [**Policies**](./PolicyManager) that a user has deposited onto a farm and its value.
* @param user The user to get policyID for.
* @param index The farm-based index of the token.
* @return policyID The ID of the deposited [**policy**](./PolicyManager).
* @return policyValue The value of the [**policy**](./PolicyManager).
*/
function getDeposited(address user, uint256 index) external view returns (uint256 policyID, uint256 policyValue);

/***************************************
MUTATOR FUNCTIONS
***************************************/

/**
* @notice Deposit a [**policy**](./PolicyManager).
* User must `ERC721.approve()` or `ERC721.setApprovalForAll()` first.
* @param policyID The ID of the policy to deposit.
*/
function depositPolicy(uint256 policyID) external;

/**
* @notice Deposit a [**policy**](./PolicyManager) using permit.
* @param depositor The depositing user.
* @param policyID The ID of the policy to deposit.
* @param deadline Time the transaction must go through before.
* @param v secp256k1 signature
* @param r secp256k1 signature
* @param s secp256k1 signature
*/
function depositPolicySigned(address depositor, uint256 policyID, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;

/**
* @notice Deposit multiple [**policies**](./PolicyManager).
* User must `ERC721.approve()` or `ERC721.setApprovalForAll()` first.
* @param policyIDs The IDs of the policies to deposit.
*/
function depositPolicyMulti(uint256[] memory policyIDs) external;

/**
* @notice Deposit multiple [**policies**](./PolicyManager) using permit.
* @param depositors The depositing users.
* @param policyIDs The IDs of the policies to deposit.
* @param deadlines Times the transactions must go through before.
* @param vs secp256k1 signatures
* @param rs secp256k1 signatures
* @param ss secp256k1 signatures
*/
function depositPolicySignedMulti(address[] memory depositors, uint256[] memory policyIDs, uint256[] memory deadlines, uint8[] memory vs, bytes32[] memory rs, bytes32[] memory ss) external;

/**
* @notice Withdraw a [**policy**](./PolicyManager).
* Can only withdraw policies you deposited.
* @param policyID The ID of the policy to withdraw.
*/
function withdrawPolicy(uint256 policyID) external;

/**
* @notice Withdraw multiple [**policies**](./PolicyManager).
* Can only withdraw policies you deposited.
* @param policyIDs The IDs of the policies to withdraw.
*/
function withdrawPolicyMulti(uint256[] memory policyIDs) external;

/**
* @notice Burns expired policies.
* @param policyIDs The list of expired policies.
*/
function updateActivePolicies(uint256[] calldata policyIDs) external;
}
6 changes: 3 additions & 3 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import { config as dotenv_config } from "dotenv";
dotenv_config();
const USE_PROCESSED_FILES = process.env.USE_PROCESSED_FILES === "true";

const mainnet_fork = { url: process.env.MAINNET_URL || '', blockNumber: 13463370 };
const rinkeby_fork = { url: process.env.RINKEBY_URL || '', blockNumber: 9487521 };
const kovan_fork = { url: process.env.KOVAN_URL || '', blockNumber: 26927369 };
const mainnet_fork = { url: process.env.MAINNET_URL || '', blockNumber: 13529321 };
const rinkeby_fork = { url: process.env.RINKEBY_URL || '', blockNumber: 9565570 };
const kovan_fork = { url: process.env.KOVAN_URL || '', blockNumber: 28087080 };
const no_fork = { url: '', blockNumber: 0 };
const forking = (
process.env.FORK_NETWORK === "mainnet" ? mainnet_fork
Expand Down
38 changes: 32 additions & 6 deletions scripts/deploy-kovan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { create2Contract } from "./create2Contract";
import { logContractAddress } from "./utils";

import { import_artifacts, ArtifactImports } from "./../test/utilities/artifact_importer";
import { Deployer, Registry, Weth9, Vault, ClaimsEscrow, Treasury, PolicyManager, PolicyDescriptor, RiskManager, OptionsFarming, FarmController, CpFarm, Solace, AaveV2Product, WaaveProduct } from "../typechain";
import { Deployer, Registry, Weth9, Vault, ClaimsEscrow, Treasury, PolicyManager, PolicyDescriptor, RiskManager, OptionsFarming, FarmController, CpFarm, SptFarm, Solace, AaveV2Product, WaaveProduct } from "../typechain";

const DEPLOYER_CONTRACT_ADDRESS = "0x501aCe4732E4A80CC1bc5cd081BEe7f88ff694EF";
const REGISTRY_ADDRESS = "0x501aCEE3310d98881c827d4357C970F23a30AD29";
Expand All @@ -26,6 +26,7 @@ const RISK_MANAGER_ADDRESS = "0x501ACe9eE0AB4D2D4204Bcf3bE6eE13Fd6337804";
const OPTIONS_FARMING_ADDRESS = "0x501ACEB9772d1EfE5F8eA46FE5004fAd039e067A";
const FARM_CONTROLLER_ADDRESS = "0x501aCEDD1a697654d5F53514FF09eDECD3ca6D95";
const CP_FARM_ADDRESS = "0x501ACeb4D4C2CB7E4b07b53fbe644f3e51D25A3e";
const SPT_FARM_ADDRESS = "0x501acE7644A3482F7358BE05454278cF2c699581";
const SOLACE_ADDRESS = "0x501ACe4A8d42bA427B67d0CaD1AB11e25AeA65Ab";

const AAVE_PRODUCT_ADDRESS = "0x501ace153Ff22348076FdD236b774F6eb2d55EfB";
Expand All @@ -44,9 +45,13 @@ const minPeriod = 6450; // this is about 1 day
const maxPeriod = 2354250; // this is about 1 year from https://ycharts.com/indicators/ethereum_blocks_per_day
const price = 11044; // 2.60%/yr
// farm params
const startTime = 1634515200; // Oct 17, 2021
const endTime = 1666051200; // Oct 17, 2022
const solacePerSecond = BN.from("1157407407407407400"); // 100K per day
const solacePerSecond = BN.from("1157407407407407400"); // 100K per day across all farms
const cpFarmStartTime = 1634515200; // Oct 17, 2021
const cpFarmEndTime = 1666051200; // Oct 17, 2022
const cpFarmAllocPoints = 90000;
const sptFarmStartTime = 1635897600; // Nov 3, 2021
const sptFarmEndTime = 1667449200; // Nov 3, 2022
const sptFarmAllocPoints = 10000;

let artifacts: ArtifactImports;
let deployerContract: Deployer;
Expand All @@ -62,6 +67,7 @@ let riskManager: RiskManager;
let optionsFarming: OptionsFarming;
let farmController: FarmController;
let cpFarm: CpFarm;
let sptFarm: SptFarm;
let solace: Solace;

let aaveProduct: AaveV2Product;
Expand Down Expand Up @@ -97,6 +103,7 @@ async function main() {
await deployOptionsFarming();
await deployFarmController();
await deployCpFarm();
await deploySptFarm();
await deploySOLACE();
// products
await deployAaveV2Product();
Expand Down Expand Up @@ -309,19 +316,37 @@ async function deployCpFarm() {
cpFarm = (await ethers.getContractAt(artifacts.CpFarm.abi, CP_FARM_ADDRESS)) as CpFarm;
} else {
console.log("Deploying CpFarm");
var res = await create2Contract(deployer,artifacts.CpFarm,[signerAddress,registry.address,startTime,endTime], {}, "", deployerContract.address);
var res = await create2Contract(deployer,artifacts.CpFarm,[signerAddress,registry.address,cpFarmStartTime,cpFarmEndTime], {}, "", deployerContract.address);
cpFarm = (await ethers.getContractAt(artifacts.CpFarm.abi, res.address)) as CpFarm;
transactions.push({"description": "Deploy CpFarm", "to": deployerContract.address, "gasLimit": res.gasUsed});
console.log(`Deployed CpFarm to ${cpFarm.address}`);
}
if((await farmController.farmIndices(cpFarm.address)).eq(0) && await farmController.governance() == signerAddress) {
console.log("Registering CpFarm in FarmController");
let tx = await farmController.connect(deployer).registerFarm(cpFarm.address, 50);
let tx = await farmController.connect(deployer).registerFarm(cpFarm.address, cpFarmAllocPoints);
let receipt = await tx.wait();
transactions.push({"description": "Register CpFarm in FarmController", "to": farmController.address, "gasLimit": receipt.gasUsed.toString()});
}
}

async function deploySptFarm() {
if(!!SPT_FARM_ADDRESS) {
sptFarm = (await ethers.getContractAt(artifacts.SptFarm.abi, SPT_FARM_ADDRESS)) as SptFarm;
} else {
console.log("Deploying SptFarm");
var res = await create2Contract(deployer,artifacts.SptFarm,[signerAddress,registry.address,sptFarmStartTime,sptFarmEndTime], {}, "", deployerContract.address);
sptFarm = (await ethers.getContractAt(artifacts.SptFarm.abi, res.address)) as SptFarm;
transactions.push({"description": "Deploy SptFarm", "to": deployerContract.address, "gasLimit": res.gasUsed});
console.log(`Deployed SptFarm to ${sptFarm.address}`);
}
if((await farmController.farmIndices(sptFarm.address)).eq(0) && await farmController.governance() == signerAddress) {
console.log("Registering SptFarm in FarmController");
let tx = await farmController.connect(deployer).registerFarm(sptFarm.address, sptFarmAllocPoints);
let receipt = await tx.wait();
transactions.push({"description": "Register SptFarm in FarmController", "to": farmController.address, "gasLimit": receipt.gasUsed.toString()});
}
}

async function deploySOLACE() {
if(!!SOLACE_ADDRESS) {
solace = (await ethers.getContractAt(artifacts.SOLACE.abi, SOLACE_ADDRESS)) as Solace;
Expand Down Expand Up @@ -427,6 +452,7 @@ async function logAddresses() {
logContractAddress("OptionsFarming", optionsFarming.address);
logContractAddress("FarmController", farmController.address);
logContractAddress("CpFarm", cpFarm.address);
logContractAddress("SptFarm", sptFarm.address);
logContractAddress("SOLACE", solace.address);

logContractAddress("AaveV2Product", aaveProduct.address);
Expand Down
Loading

0 comments on commit 39fe476

Please sign in to comment.