This repository contains the source code for the GrowthDeFi smart contracts (Version 1) and related support code for testing and monitoring the contracts.
- /contracts/. This folder is where the smart contract source code resides.
- /docker/. This folder contains docker and/or docker-compose files that help setting up and running a ganache-cli service for testing and development.
- /migrations/. This folder hosts the relevant set of Truffle migration scripts used to publish the smart contracts to the blockchain.
- /stress-test/. This folder contains code to assist in stress testing the core contract functionality by performing a sequence of random operations.
- /telegram-bot/. This folder contains code to assist in monitoring the smart contract health/vitals in real time via Telegram notifications.
- /test/. This folder contains a set of relevant unit tests for Truffle written in Solidity.
The smart contracts are written in Solidity and the source code is organized in the following folder structure:
- /contracts/. This folder has the core functionality with the main contract hierarchy and supporting functionality. This is further described in detail below.
- /contracts/interop/. This folder contains the minimal interoperability interfaces to other services such as Aave, Compound, Curve, DyDx, etc.
- /contracts/modules/. This folder contains a set of libraries organized as modules each abstracting a specific functionality. These are compile-time libraries with internal functions, they do not serve the purpose of organizing the code into runtime (public) libraries. As Solidity libraries usually work, the code is assumed to execute in the context of the caller contract.
- /contracts/network/. In this folder we have a simple and helpful library to declare static properties such as the current network (mainnet, ropsten, etc), well-known useful contract addresses for each supported network, as well as some global definitions that are handy for debugging during development.
The /contracts/ folder contains basically 12 groups of files as presented below. Their actual functionality is described in the next section.
- Interface files, such as GToken.sol, GCToken.sol, and GExchange.sol that describe the available public interface to the smart contracts. GToken.sol is the general interface for the GrowthDeFi V1 tokens (refered to as gTokens) and GCToken.sol is an extension of that interface to decribe the GrowthDeFi V1 tokens based on Compound cTokens (and refered to as gcTokens). GExchange.sol is a simple interface for an external contract specialized in token conversion; which allows for the replacement and customization of the conversion service provider used by gTokens at any given point in time. Other interface files present in the project are GPooler.sol, GMining.sol, and GVoting.sol, which serve to support modular and public extensions of gTokens for managing a liquidity pool, performing liquidity and profit mining, and implement a vote mechanism for governance, respectivelly.
- Abstract contract files that provide the basis implementation of shared functionality for their respective interface. These are basically GTokenBase.sol for gTokens, and GCTokenBase.sol for gcTokens. Note that gTokens extend the ERC-20 specification and we use the OpenZeppelin library as basis for their implementation. Besides the ERC-20 related functionality we also make use of OpenZeppelin's Ownable to guard admin-only public functions and ReentrancyGuard to conservatively guard all publicly exposed functions against reentrancy.
- Concrete contract files that derive from the abstract contract files by filling in the specific details purposedly left open. These provide the final/leaf contracts in the gTokens hierarchy. The list comprises gTokens Type 0 (a.k.a. PMTs) GTokenType0.sol; gcTokens implemented in two flavors: Type 1 gcTokens GCTokenType1.sol, and Type 2 gcTokens GCTokenType2.sol. A special gToken Type 3 GTokenType3.sol provides the foundation for governance by implementing a 1-level delegation voting token.
- Component contracts as (public) libraries that provide core functionality implementation. Besides properly encapsulating the functionality they also allow working around the contract size limitations of the EVM. These are GLiquidityPoolManager.sol for liquidity pool management/handling; GPortfolioReserveManager.sol for multi token exposure allowing a distribution of the reserve to a list of gTokens in a amind-defined percentual allocation (used by Type 0 gTokens); GCLeveragedReserveManager.sol for leveraged reserve management/handling where flash loans are used to maintain the desired leverage level over lending/borrowing of the reserve of cTokens (used by Type 1 gcTokens); GCDelegatedReserveManager.sol for delegated reserve management/handling where borrowing is employed to mint other gTokens that are used to maintain and grow the cToken reserve (used by Type 2 gcTokens);
- A single entrypoint file GTokens.sol that succinctly declares all the available gTokens.
- A set of public libraries to abstract the available modules. The G.sol library that compiles and serves as entrypoint to most the relevant functions available under the /modules/ folder. The GC.sol, similarly, do the same for the Compound lending market abstractions, respectively. These libraries exists mostly to work around the EVM limitation of contract sizes, but it also provide a concise standardized and neat reference to library code.
- Two handy pure calculation libraries that hoist gToken and gcToken minting/burning formulas, GFormulae and GCFormulae respectively. These provide a set of pure (in the Solidity sense) functions.
- A contract that helps abstract FlashLoans callbacks GFlashBorrower.sol for both Aave and DyDx. This class is used by Type 1 tokens to perform flash loans and efficiently maintain the desired leverage level.
- Two, and possibly more, exchange implementations deriving from GExchange.sol to handle token conversion, such as GUniswapV2Exchange.sol, GSushiswapExchange.sol. Possibly more providers or more sophisticated routing maybe be added on the future.
- A ETH bridge contract GEtherBridge.sol to facilitate the integration with the Ethereum native asset. This is handy as gTokens are designed to work with ERC-20 tokens and uses WETH.
- A token registry contract GTokenRegistry.sol to facilitate the registration and automatic integration of new gTokens via thegraph.com.
- A Gnosis Safe module contract GDAOModule.sol to implement the protocol governance by extending a Gnosis Safe multisig (which is expected to have privileged access to the gTokens admin functionality) allowing for the decentralized update of its signers according to the votes delegated by stkGRO holders.
- The reference implementation of the GRO token is available on GrowthToken.sol.
This repository implements the first batch of tokens for the GrowthDeFi platform. These tokens, so called gTokens, are organized in the following hierarchy:
- gToken
- gToken (Type 0)
- gDAI
- gUSDC
- gETH
- gWBTC
- gcToken
- gcToken (Type 1)
- gcDAI
- gcUSDC
- gcToken (Type 2)
- gcETH
- gcWBTC
- gcToken (Type 1)
- gToken (Type 3)
- stkGRO
- gToken (Type 0)
As one may deduct, gTokens are typically named after their reserve token.
gTokens based on other platforms will be added to the hierarchy in the future.
A gToken is a token that maintains a reserve, in another token, and provides its supply. The price of a gToken unit can be derived by the ratio between the reserve and the supply.
To mint and burn gTokens one must deposit and withdrawal the underlying reserve token to and from the associated gToken smart contract. Anyone can perform these operations as long as they provide the required underlying asset amount.
For each of these operations there is a 1% fee deducted from the gToken amount involved in the operation. The fee is based on the nominal price of gTokens calculated just before the actual operation takes place.
The fee collected is split twofold: 1) half is immediatelly burned, which is equivalent to redistributing the underlying associated reserve among all gToken holds; 2) the other half is provided to a liquidity pool.
Every gToken contract is associated to a Balancer liquidity pool comprised of 50% of GRO and 50% of the given gToken. This liquidity pool is available publicly for external use and arbitrage and is set up with a trade fee of 10%.
Associated with the liquidity pool there is also some priviledged (admin) functionality to:
- Allocate the pool and associate with the gToken contract
- Burn 0.5% (or the actual burning rate) once per week
- Set the burning rate, which is initially 0.5%
- Migrate the pool funds (GRO and gToken balances) to an external address with a 7 day grace period
Note that after the liquidity pool is migrated for the first time, the gToken contract collects a 2% fee on deposits and does not collect any fee for withdrawals.
Relevant implementation files:
The gToken Type 0 family implements Portfolio Management Tokens (PMTs). These are tokens for which deposits and withdrawals of the reserve token is invested in a basket of related gTokens up to 5 different ones. The distribution is percentual and part of it can be maintained in the reserve token itself to accomodate liquidity and save on gas for small and frequent operations. For every asset supported by the GrowthDeFi platform there is a gToken Type 0 correspondent. The PMTs are the entry points to the platform.
The default configuration for a gToken Type 0, as of this writting, is to allocate 90% of the reserve assets to its correspondent gcToken and leave 10% of the reserve liquid (for instance, the gDAI PMT is composed of 10% liquid DAI and 90% gcDAI).
In order to save on gas, a PMT operation will at most trigger one operation of any of the underlying gTokens. Therefore the move into the target distribution of assets according to the portfolio settings is incremental, as operations happen. The target percentual configuration can be changed anytime by the contract onwer, but it may take half a dozen large operations to get the reserve into the desired distribution.
The strategy for choosing which gToken is chosen to perform the underlying operation is basically its percentual deviation from the configured target. Furthermore we provide margin parameters to avoid having to rebalance the portfolio at every given operation.
Relevant implementation files:
gcTokens are cTokens based on their Compound counterpart. For instance gcDAI has as reserve token cDAI.
The gcTokens Type 1 are stable-coin based. They maintain a reserve using their Compound counterpart which provides yield based on the associated underlying asset (DAI in case of cDAI) and also allows for the collection of COMP tokens.
The COMP collected is converted to DAI, and used to mint cDAI, as soon as a minimal amount is reached. The conversion is performed using the associated exchange contract and is limited to a maximal amount. Both the min/max amounts and the exchange contract can be modified by the gcToken contract owner.
The gcToken Type 1 contract incorporates the ability to deposit/withdraw balances directly in DAI handling internally the details of minting cDAI and redeeming DAI from cDAI.
The main functionality of the gcToken Type 1 contract is leveraging. The contract incorporates a logic to mint cDAI and use it to borrow DAI. The new DAI is then used again to mint more cDAI which in turn is used to borrow more DAI. This cycle is repeaded until we reach the point where the difference between the total amount of DAI used to mint cDAI and the total of DAI borrowed is closed to the actual amount of DAI carried by the reserve.
For example, if we have $100 worth of DAI in the reserve, assuming 75% DAI collateralization ratio from Compound, after 1-cycle, we would have borrowed $75 worth of DAI and minted $175 worth of cDAI. If we repeat that process, at each cycle, we get closer and closer to borrowing $300 worth of DAI and minting $400 worth of cDAI. The reserve becomes the actual difference between these two amounts and the leverage is maximal.
The proccess of cycling into and out off leverage could be done via loops using just the liquidity available in the gToken contract. However, we have optimized the process to avoid loops using a flash loan. We borrow the required amount of assets to perform the operation and then return it in a single shot.
Note that the actual reserve collateralization ratio used by the gcToken Type 1 contract can be provided by the contract owner and is relative to the maximal collateralization ratio allowed by Compound. In order to switch off leveraging one must set this collateralization ratio to 0%.
As a final note, leveraging is used to potentialize gains on the Compound platform. Due to liquidity mining lending and borrowing from itself may, at times, result in higher yields.
Relevant implementation files:
- GCToken.sol
- GCFormulae.sol
- GCTokenBase.sol
- GMining.sol
- GCTokenType1.sol
- GFlashBorrower.sol
- GCLeveragedReserveManager.sol
The gToken Type 2 family is tailored to non-stable coins. Funds deposited into a gcToken Type 2 contract are used to mint the associated Compound cToken and used as collateral to borrow DAI, which in turn is used to mint gDAI.
As with gcTokens Type 1, we collect COMP from liquidity mining, convert it, and use it to mint more of the underlying cToken. Similarly, we monitor the profit on the gDAI minted and, when it reaches a minimum level, we redeem the profit from gDAI, convert it, and use it to mint more of the underlying cToken.
As with gcToken Type 1, the actual reserve collateralization ratio used by the gcToken Type 2 contract can be provided by the contract owner and is relative to the maximal collateralization ratio allowed by Compound. In order to switch off leveraging one must set this collateralization ratio to 0%.
Relevant implementation files:
- GCToken.sol
- GCFormulae.sol
- GCTokenBase.sol
- GMining.sol
- GCTokenType2.sol
- GCDelegatedReserveManager.sol
The gTokens Type 3 implement the basic gToken interface for deposits/withdrawals and provides a balance/vote delegation mechanism that will serve as basis for the system governance.
Differently from the other gTokens, gTokens Type 3 do not have a locked liquidity pool to collect fees. Instead the fees collected are immediately burned. The fee gets burned not only in shares, but also in terms of the underlying reserve asset. And the fees for gTokens Type 3 are set at the much higher rate of 10%. The final characteristic that differentiates them from other gTokens is that ERC-20 transfers are prohibted. These tokens can be minted and burned, but not moved around.
As governace tokens, gTokens Type 3 provide a voting delegation mechanism. Each holder can appoint a candidate for vote delegation. Each candidate collects the reserve balance of those who appointed him in votes. So the contract offers two additional functions: 1) a function for setting your candidate and therefore delegating your balance in votes; 2) a function for reading the number of votes of a given candidate. Voting is organized in intervals of 24 hours, therefore candidate and vote changes in the current interval are only reflected on the next interval. With this additional functionality we can build a list of most voted candidates just by requiring that users suggest themselves to be part of the list and, if they indeed have the votes for that, they will be included on the list.
The single token contract that belongs to the gTokens Type 3 class is stkGRO, which is a version of the GRO token tailored for governance.
Relevant implementation files:
configuring the repository:
$ npm i
Compiling the smart contracts:
$ npm run build
Deploying the smart contracts (locally):
$ ./start-mainnet-fork.sh & npm run deploy
Running the unit tests:
$ ./start-mainnet-fork.sh & npm run test
Running the stress test:
$ ./start-mainnet-fork.sh & npm run stress-test