Create a protected investing opportunity
Learn how to create a protected investment opportunity for another DeFi protocol.
After obtaining protection via a Cozy protection market, many users will want to deploy the newly borrowed funds to earn yield. That’s where Cozy Protected Investing comes in.
Cozy Protected Investing enables users to borrow, invest and track returns in one step, in one place. This guide details how you can create a Protected Investment opportunity for users on cozy.finance or on your DeFi app.
Deploy a protection market
Each Cozy Protected Investment opportunity requires a corresponding Protection Market. Please refer to the Create a protection market guide for details on developing and deploying trigger and protection market contracts.
Adding protected investment opportunities to the Cozy app
Deploy an invest/divest contract
Protection markets cover the borrow-side of an investment opportunity; however, you’ll also need to provide instructions for how the borrowed funds should be invested. For this, you’ll deploy an additional contract that is responsible for investing, divesting and managing any other assets related to the investment position (e.g. reward tokens or airdrops).
Please refer to Create an invest/divest contract guide for details on developing and deploying an invest/divest contract.
Data fetching
The Cozy app requires a few pieces of data to support an investment opportunity. The Cozy subgraph (covered in detail below) supplies much of this data, but the subgraph is limited to Cozy protocol-specific data (i.e. protection markets and positions in those markets). Data related to an investment opportunity on a separate DeFi protocol requires a separate data source.
That’s why it’s necessary to create an endpoint — on a per opportunity basis — which is responsible for investment performance data as well as data that facilitates invest/divest contract interaction. This endpoint — referred to as the opportunity's dataURI
— uniquely identifies that opportunity.
Assuming a dataURI
ending in /new-opty
, this data endpoint must handle the following query parameters:
No query params
/new-opty
- returns base data about the investment opportunity, like the rate of return, the remaining capacity to be deposited into the opportunity and whether the opportunity is disabled. Sample response:
Typical Fields | Description |
isDisabled | Boolean. Whether the investment opportunity is still accepting funds. All invest transactions will fail if this is true. |
investingCapacity | String. The amount of funds in human-readable units which the investment opportunity can accept. The invest transaction will fail in an attempt to deposit funds beyond this amount. Null if there is no maximum capacity for the opportunity. |
investRate | Number. The percentage return in decimal form associated with funds invested into this opportunity. The investRate minus the borrowRate equals the netReturnRate — or the overall APY — associated with this opportunity. |
Two Step Invest Fields | Description |
investFlow | String. Sometimes, an investment opportunity will have a non-standard flow. The Cozy app currently supports only one non-standard flow: the |
twoStepDeployTime | String. The time when funds in a |
Ethereum account
/new-opty?account=<ethereumAccount>
- returns all the data of the base new-opty
endpoint, but adds balance information for the passed in Ethereum account. Sample response:
Typical Response Fields | Description |
balanceUnderlying | String. The total value of the position in human-readable units of underlying from the borrow market for the investment opportunity |
balanceUsd | Number. The total value of the position in USD |
lastUpdatedBlockNumber | Number. The block number corresponding to the data in this response. Used for communicating the sync-status of the data currently being presented. (i.e. does the state of the invest position data match the data from the subgraph) |
receiptTokenBalances | Array. An array of the receipt tokens associated with this position |
rewardTokenBalances | Array. An array of the reward tokens associated with this position |
totalWithdrawableAmount | String. The number of receipt tokens as a raw, contract-friendly string that can be redeemed when divesting from the investment opportunity |
Two Step Invest Fields | Description |
pendingDepositsUnderlying | String. The amount of funds in human-readable units of underlying that have been deposited into the protocol but not yet deployed to earn yield |
scheduledWithdrawalReady | Boolean. Whether funds that were previously scheduled to be withdrawn are now ready to be withdrawn |
scheduledWithdrawalUnderlying | String. The amount of funds in human-readable units of underlying that were previously scheduled to be withdrawn but require additional time before they are ready to be withdrawn |
Token Info Fields | Description |
balance | String. Balance in human-readable units of this token for the investment account |
balanceUnderlying | String. The value of this token balance, in human-readable units of underlying from the borrow market for the investment opportunity |
balanceUsd | Number. The value of this token balance, in USD |
decimals | Number. The number of decimals to divide a raw balance by to produce its human-readable form |
token | Object. The standard details of an erc20 token |
When describing balance fields in this guide, we will always refer to their units as either raw or human-readable. Raw fields are the format used by smart contracts that have no decimal places. If you divide a raw value by Math.pow(10, decimals), you get the human-readable form.
Invest params
/new-opty?invest=[<marketContractAddress>, <investAmountInUnderlying>]
- returns the parameters which will be passed into the invest
method of the invest/divest contract deployed for this investment opportunity. Sample response:
Divest params
/new-opty?invest=[<marketContractAddress>, <divestAmountInUnderlying>, <eoaAddress>]
- returns the parameters which will be passed into the divest
method of the invest/divest contract deployed for this investment opportunity. Sample response
Surfacing
Cozy displays investment opportunities based on a set of market-lists
maintained in the cozy-invest-lists
repo. Inspired by Uniswap’s token-lists
standard, all Cozy market-lists
conform to a simple, JSON schema.
Once all the smart contracts related to your investment opportunity have been deployed, you can create a new protection market entry in the community
protection-market-list
in Cozy’s cozy-invest-lists
repo and submit a PR. Make sure to validate your entry to the schema using the validation framework found in the protection-market-list
schema.
Amongst other things, your list entry will include:
Invest/divest contract details: the contract addresses and signatures of the invest/divest contracts you deployed
Investment opportunity strategy: a description of the steps taken when borrowed funds are deployed
Sample protection-market-list
entry:
Selected Fields | Description |
platformId | Number. Cozy’s ID for the platform to which funds will be deposited; please consult the Cozy-Finance/platform-ids repo for the correct |
tokens#input | Object. Details on tokens that are deposited to enter into the opportunity |
tokens#receipt | Object. Details on tokens that are returned in receipt when an opportunity is entered; these tokens are exchanged again to exit the position. |
tokens#rewards | Object. Details on all the tokens which may be accrued as rewards while a position is active |
divest#address | String. Address of the invest/divest contract you deployed |
divest#signature | String. Signature of the divest function on the invest/divest contract you deployed |
invest#address | String. Address of the invest/divest contract you deployed |
invest#signature | String. Signature of the invest function on the invest/divest contract you deployed |
strategy | Array. Array of |
strategy#action | String. The action taking place in this leg of the investing strategy |
strategy#actionReceiver | String. The receiver of the action taking place (grammatically, the direct or indirect object) |
PR review
After submitting your new protection market list entry to the cozy-invest-lists
repo for PR, we’ll review your invest/divest contracts and test your dataURI
endpoint to ensure everything is working properly. Please ensure your invest/divest contracts are verified on Etherscan, so we can review the code.
Adding protected investment opportunities to your DeFi app
Hosting a protected investment opportunity on your site is easy and allows new users to engage with your project while staying protected.
Depositing collateral
To enter into a protected investing position, a user must first have supplied collateral to borrow against. This collateral must be supplied to a Cozy money market, a process is detailed in this guide.
Each market has a collateralFactor
which is applied to funds deposited into a money market that determines how much funds can be borrowed by that account (i.e. If $100 was supplied to a money market with a 0.75 collateral factor, that account can borrow $75).
If a user’s borrows exceed the total value of their collateral, they will be subject to liquidation.
Entering a protected investing position
In order to create a protected investing position, the flow is as simple as:
Borrow from the Cozy protection market you just deployed. See this guide on how to Buy protection programmatically. Note: a user must have already deposited collateral for the borrow to succeed!
Follow the same logic your app usually does for entering into a new position, for the amount that was borrowed.
Tracking an investing position
To track the performance of the investing position, you’ll need data on both the borrow-side and invest-side of the position (from the Cozy market side and other DeFi protocol side, respectively).
The Cozy Subgraph supplies all the data for borrow-side. For example, the user’s collateral balance, how much borrowing power they have and their protected borrow balance can all be found in the Cozy Subgraph.
The subgraph automatically indexes all Cozy protection markets and indexes all positions which are opened on those markets. In the subgraph, these are represented by Market
& AccountCToken
entities.
Please see discussion of these two entities below, but for additional information consult the comments in the Schema panel of the subgraph’s page.
Markets
The Market
entity holds a lot of critical information for presenting a Cozy protection market including:
Basic descriptive data: the name, symbol, underlying of the market and associated trigger contract address
Key numbers used by the protocol: borrow cap, exchange rate, borrow rate
Selected Market Fields | Description |
borrowCap | String. Total cumulative amount in human-readable units of underlying that can be borrowed from a market at one time |
borrowRate | String. The annualized interest rate in decimal form users must pay to borrow from a market |
exchangeRate | String. The exchange rate of underlying / receipt token in decimal form |
cash | String. The amount in human-readable underlying available to be borrowed on a market. Any borrow transactions greater than the available cash in the market will fail. |
collateralFactor | String. Factor applied to the supplied funds of a money market that determines how much funds can be borrowed by that account (i.e. If $100 was supplied to a money market with a 0.75 collateral factor, that account can borrow $75) |
AccountCTokens
The AccountCToken
entity represents a position opened by a user on a protection market. It includes data on:
Current balances of the position: the cToken balance and the stored borrow balance
Historical tabulations for this user in the market: total underlying borrowed, repaid, supplied or redeemed
Selected AccountCTokens Fields | Description |
cTokenBalance | String. The receipt token balance of this position in human-readable units |
enteredMarket | Boolean. Whether the user’s supplied funds should be used as collateral for other borrows (see guide on supplying collateral) |
storedBorrowBalance | String. Current borrow balance stored in the protocol contracts in human-readable units (excludes interest since last accrual block; see calculations below to get up-to-date borrowBalance) |
Key calculations
To calculate the borrow balance of a position in underlying:
To calculate the supply balance of a position in underlying:
Exiting a position
To close out a position, follow the opposite steps to opening it:
Follow the normal steps for closing a position in your protocol.
Repay the Cozy protection market using the funds just received from closing the position on your protocol. For details on repaying debt on Cozy, please consult the Repay Debt section of the Manage protection programmatically guide.
Last updated