Presto
Built on top of the Covenants Aggregator, and integrable with all Covenant functions, Presto optimizes and automates tasks that require multiple swap, transfer and add liquidity operations, making everything simpler, faster and cheaper for users.
This section is dedicated to the general-purpose Presto contract, which can be customized for specific use cases, as demonstrated by our Presto verticalizations for the Covenant WUSD, Farming and Index Token protocols. See their respective sections to learn more.
How Presto Works
The building block of each Presto contract is the PrestoOperation
struct, which contains all of the requisite data for an operation.
Its inputs are as follows:
inputTokenAddress
-> theaddress
of the input token (i.e. the initial token) forswap
andtransfer
operations; foraddLiquidity
operations, theaddress
of the liquidity pool (LP) token.inputTokenAmount
-> theamount
of the input (or LP) token to be used in the operation.ammPlugin
-> theaddress
of the Automated Market Maker (AMM) forswap
andaddLiquidity
operations; fortransfer
operations this field is not populated.liquidityPoolAddresses
-> array containing the LPaddresses
to be used for aswap
operation (not populated fortransfer
oraddLiquidity
operations).swapPath
-> array containing the sequential path of tokens (ending with the output token) used in a swap operation. So for example if you have an operation that swaps BUIDL to ETH and then to USDC, theswapPath
array will contain ETH in the first position and USDC in the second one.This field is left blank for non-swap operations.enterInEth
-> a boolean value that represents if the input token is ETH (true
) or not (false
); i.e, if the input token is ETH,enterInETH
istrue
; if not,enterInETH
isfalse
.exitInEth
-> a boolean value that represents if the output token is ETH (true
) or not (false
); i.e, if the output token is ETH,exitInETH
istrue
; if not,exitInETH
isfalse
.receivers
-> array containing the receiveraddresses
of the operation. Receiveraddresses
can be defined forswap
,transfer
andaddLiquidity
operations.receiversPercentages
-> array containing the relative percentage for eachaddress
receiver. The length of this array must be equal toreceivers array length -1
; since the last receiver's percentage is equal to the outstanding percentage, it is calculated as that automatically.
Execute Presto Operations
To perform Presto operations as defined by their structs, the execute
function is used, input with an array of one or more PrestoOperation
structs; multiple can be executed at once.
The execute
function first has to transfer the inputTokenAmount
from the msg.sender
(i.e. the Presto user) to the Presto contract, which it does by calling the _transferToMe
method.
But before _transferToMe
can transfer the inputTokenAmount
, it must first internally call the _collectTokens
method in order to calculate the amount to be transferred.
For addLiquidity
operations, the _collectTokens
method internally calls _byLiquidityPoolAmount
, (an API of the AMM Aggregator) and uses it to calculate the amount of LP tokens.
Then it internally calls the _collectTokenData
method, passing as input the addresses and amounts of paired tokens of the LP token.
For transfer
and swap
operations, the _collectTokens
method also internally calls the _collectTokenData
method, but passes as input the address
and amount of the input token.
The _collectTokenData
function uses this input to create an indexed position for the inputTokenAddress
; or, if one has already been created for another operation in the contract, retrieves and adds to it the amount of input token for this one, represented by _tokenAmounts[position]
. This is so that if you want to perform multiple operations (by passing multiple PrestoOperation
structs in the contract) with the same input token, the contract will only have to perform the token transfer once via _safeTransferFrom
.
With all parameters calculated, the_transferToMe
method can, at last, carry out the execute
function's original task, by internally calling the _safeTransferFrom
method, which transfers the right amount of tokens from the msg.sender
to the contract.
And now the execute
function can perform each operation.
1) Transfer
For a transfer
operation, execute
calls the _transferTo
method. This calculates:
1) the amount of the input token to be sent to the Covenants DFO wallet, as a mandatory fee
2) the amounts of it to be sent to the receivers as specified in the receivers
and receiversPercentages
arrays
It then transfers these amounts accordingly.
2) Add Liquidity
For addLiquidity
operations, execute
calls the _addLiquidity
method. This uses the AMM Aggregator to build the liquidityPoolData
to be called by the addLiquidity
function (one of the AMM Aggregator on-chain API).
The addLiquidity
function then sends the obtained output LP tokens to the receivers as specified in the receivers
andreceiversPercentages
arrays.
3) Swap
For swap operations, execute
calls the _swap
method. This first defines the output token of the operation.
and then uses the AMM Aggregator to build the swapData
to be called by the swap
function.
If necessary (i.e. if the input token isn't ETH), if then also internally calls the_safeApprove
method on the input token.
and then calculates the amount of output token to be obtained from the swap operation, which it then performs.
and then finally sends that amount to the receivers as specified in the receivers
and receiversPercentages
arrays.
Flush and Clear
After performing all of a contract's operations, the execute
function finally calls the _flushAndClear
method.
This takes care of two things.
1) It checks if any residual tokens remain in the contract, and if so sends them back to the msg.sender
.
Example
During the execution of an operation, market conditions change in such a way that not all tokens are sent to receivers. Let's say that in a swap
3 ETH is swapped for 5.1 BUIDL, and that the total balance is now 5.1 BUIDL—even though an LPAmount
was set that corresponds to 5 BUIDL in the PrestoOperation
. This discrepancy means that 0.1 BUIDL remains in the contract. The _flushAndClear
method allows themsg.sender
to retrieve these residual tokens so that none remain in the contract.
2) It deletes the storage
, _tokenAmounts
and _tokenToTransfer
parameters (which were used to efficiently manage transfer operations between the user and the contract) from the contract.
Last updated
Was this helpful?