This document is intended for developers who wish to programmatically route crypto assets from other protocols to and from Vesper pools and strategies. It is a companion to the Vesper Contracts API Reference, which documents API end points for Vesper pools and Vesper strategies.
The discussion that follows assumes that you've read Vesper's Modular Pool Architecture, which explains pool and strategy architecture in abstract terms. Below, we will go into more concrete detail to explain how this architecture is implemented in Vesper's smart contracts.
Vesper smart contracts, written in the Solidity programming language, are organized in the Vesper code repository in directories described in the next sections. The Vesper Contracts API Reference only documents contracts that reside in the Pool directory, along with a few key contracts in the Strategy directory, since those are the only ones that other (that is, external to Vesper) protocols would interact with. The types of Vesper smart contracts which exist in the repository but are not included in the Reference are described briefly below.
Interfaces are pure abstract contracts that contain external functions that contain only declarations — that is, no statements. Implementations of other contracts inherit from them. The Interfaces directory includes Vesper interfaces from which pools and strategies are derived. Examples include IVesperPool.sol, IStrategy.sol, and IEarnDrip.sol.
This directory includes all the contracts that are instantiated when a Vesper pool is deployed. Each of these contracts is described in the Vesper API Reference.
This directory includes all the strategy contracts employed by Vesper pools to generate yield. The contracts in this directory include both general purpose contracts like Strategy.sol and VesperStrategy.sol that are inherited by all strategy contracts, and contracts that implement specific strategies on specific platforms — for example the aave subdirectory includes the contracts AaveCore.sol, AaveLeverageStrategy.sol, AaveStrategy.sol, and so forth. In addition, there are subdirectories in the aave directory for each of the supported target blockchains — Ethereum mainnet, Polygon and Avalanche.
This directory includes interfaces and contracts that are used to implement various tests.
This directory includes contracts that are used to upgrade pools and their related contracts.
This directory that contains contracts used to do things like interfacing with external exchanges.
Contracts including Errors.sol, the abstract contracts FlashLoanHelper.sol, Governable.sol and Pausable.sol are implemented by all pools to provide common functionality.
We have seen that Vesper pools are engineered for upgrading. Not only can pool logic be changed to fix any errors or to improve performance, but also the strategies used by pools can be changed or modified at any time. This is accomplished using proxies, as explained below.
Note that although OpenZeppelin offers contracts to implement proxies, Vesper uses its own implementation of this concept not OpenZeppelin's.
The idea behind proxies is separating the logic parts of a pool from its state. Consider the illustration below. Imagine that we were going to implement a Vesper Grow pool for the 'Cool' token. The vCool pool would be created as an instance of Strategy.sol. When deployed, it would create two new contracts: the Logic Layer Contract, or llc, which contains the pool's logic, and the Storage Layer Contract, or SLC, which contains the pool's state. Thereafter, the storage layer contract effectively is the pool, from the point of view of other contracts that interact with it. In other words, if you were writing a contract on a protocol external to Vesper and wanted to invoke, say, the withdraw method of the vCool contract, you would access it at address A1, not A0.
Note that in the illustration below, the arrows from the vCool pool only point in one direction. This indicates that the pool contract spawns the SLC and LLC, but those contracts, once created, have no interaction with the pool contract.
The storage layer contract, in turn, contains a pointer to the address of the logic layer contract. The logic layer actually contains the code that implements the function that was invoked.
Proxied pools separate a pool's state from its logic
Given this architecture, the process of upgrading a pool is simply a matter of deploying a new LLC, and then changing pointer in the SLC to point to the new LLC instead of the original one.
The Address of the pool is the address of the storage layer contract