|
1 |
| -# Architecture |
| 1 | +# EulerSwap architecture |
2 | 2 |
|
3 |
| -## Operation |
| 3 | +# EulerSwap Architecture |
4 | 4 |
|
5 |
| -Since the level of acceptable borrowing risk may not be the same for every user, pooled deposits are not yet possible, and each EulerSwap instance manages funds for a single user (who of course may operate on behalf of pooled funds). |
| 5 | +## Overview |
6 | 6 |
|
7 |
| -EulerSwap is a contract designed to be used as an [EVC operator](https://evc.wtf/docs/whitepaper/#operators). This means that the user, known as the _holder_, does not give up control over their funds to a smart contract, but instead retains it in their wallet. The holder can be any compatible address, including standard multisig wallets or even an EOA. |
| 7 | +EulerSwap is an automated market maker (AMM) that integrates with Euler lending vaults to provide deeper liquidity for swaps. |
8 | 8 |
|
9 |
| -### Usage |
| 9 | +Unlike traditional AMMs that use shared liquidity pools, EulerSwap operates with independent swap accounts, where each account manages liquidity for a single user or entity. |
10 | 10 |
|
11 |
| -The following are the high-level steps required to use EulerSwap: |
| 11 | +Each EulerSwap instance is a lightweight smart contract that functions as an [EVC operator](https://evc.wtf/docs/whitepaper/#operators) while implementing a highly customizable AMM curve to determine swap output amounts. |
12 | 12 |
|
13 |
| -- Deposit funds into one or both of the vaults |
14 |
| -- Deploy the desired EulerSwap contract, choosing parameters such as the vaults and the desired `fee` |
15 |
| -- Calculate the desired [virtual reserves](#virtual-reserves) and set these values by invoking `setVirtualReserves()` |
16 |
| -- Install the EulerSwap contract as an operator for your account |
17 |
| -- Invoke the `configure()` function on the EulerSwap contract |
| 13 | +When a user initiates a swap, the swap account borrows the required output token using the input token as collateral. The swap account’s AMM curve governs the exchange rate, ensuring deep liquidity over short timeframes while maintaining a balance between collateral and debt over the long term. |
18 | 14 |
|
19 |
| -At this point, anyone can invoke `swap()` on the EulerSwap contract, and this will perform borrowing and transferring activity between the two vaults. |
| 15 | +## Code Structure |
20 | 16 |
|
21 |
| -### Debt Limits |
| 17 | +EulerSwap’s code is split into two main smart contracts: |
22 | 18 |
|
23 |
| -The initial deposits in the vaults represent the initial investment, and are swapped back and forth in response to swapping activity. In a conventional AMM such as Uniswap, these balance are called _reserves_. However, if swapping was constrained to these assets alone, then this would imply a hard limit on the size of swaps that can be serviced. To increase the effective funds, EulerSwap AMMs are configured with _virtual reserves_. These are typically larger than the size of the conventional reserves, which signifies that not only can all the assets be swapped from one vault to another, but even more assets can be borrowed on the EulerSwap's account. |
| 19 | +### EulerSwap core (`EulerSwap.sol`) |
24 | 20 |
|
25 |
| -Virtual reserves control the maximum debt that the EulerSwap contract will attempt to acquire on each of its two vaults. Each vault can be configured independently. |
| 21 | +- Handles collateralization via EVC and Euler lending vaults. |
| 22 | +- Implements AMM curve invariant checks through the `verify()` function. |
26 | 23 |
|
27 |
| -For example, if the initial investment has a NAV of $1000, and virtual reserves are configured at $5000 for each vault, then the maximum LTV loan that the AMM will support will be `5000/6000 = 0.8333`. In order to leave a safety buffer, it is recommended to select a maximum LTV that is below the borrowing LTV of the vault. |
| 24 | +### EulerSwap periphery (`EulerSwapPeriphery.sol`) |
28 | 25 |
|
29 |
| -Note that it depends on the [curve](#curves) if the maximum LTV can actually be achieved. A constant product will only approach these reserve levels asymptotically, since each unit will get more and more expensive. However, with constant sum, this LTV can be achieved directly. |
| 26 | +- Provides simplified functions for retrieving swap quotes from the AMM curve. |
| 27 | +- Acts as a convenience layer for external integrations. |
30 | 28 |
|
31 |
| -### Desynchronised Reserves |
| 29 | +## Operational flow |
32 | 30 |
|
33 |
| -The EulerSwap contract tracks what it believes the reserves to be by caching their values in storage. These reserves are updated on each swap. However, since the balance is not actually held by the EulerSwap contract (it is simply an operator), the actual underlying balances may get out of sync. This can happen gradually as interest is accrued, or suddenly if the holder moves funds or the position is liquidated. |
| 31 | +The following steps outline how a swap account is created and configured: |
34 | 32 |
|
35 |
| -When this occurs, the `syncVirtualReserves()` should be invoked. This determines the actual balances (and debts) of the holder, and adjusts them by the configured virtual reserve levels. |
| 33 | +1. Deposit initial liquidity into one or both of the vaults to enable swaps. |
| 34 | +2. Deploy the EulerSwap contract, specifying AMM curve parameters and the `fee`. |
| 35 | +3. Set the [virtual reserves](#virtual-reserves) by invoking `setVirtualReserves()`. |
| 36 | +4. Install the EulerSwap contract as an operator for the user's account. |
| 37 | +5. Invoke the `configure()` function on the EulerSwap contract. |
| 38 | + |
| 39 | +Once configured, the EulerSwap contract can process swaps. When a user invokes `swap()`, the contract facilitates borrowing and transfers between the underlying vaults as dictated by the AMM curve. |
| 40 | + |
| 41 | +### Virtual reserves |
| 42 | + |
| 43 | +The initial deposits in the vaults provide starting liquidity and facilitate swaps. In traditional AMMs like Uniswap, these balances are known as _reserves_. |
| 44 | +However, relying solely on these assets would impose a hard limit on swap size. To overcome this, EulerSwap introduces _virtual reserves_, allowing the AMM to extend its effective liquidity by borrowing against its real reserves. |
| 45 | + |
| 46 | +Virtual reserves control the maximum debt that the EulerSwap contract will attempt to acquire on each of its two vaults. Each vault can be configured independently. For example, if the initial investment has a NAV of \$1000, and virtual reserves are configured at \$5000 for each vault, then the maximum LTV loan that the AMM will support will be `5000/6000 = 0.8333`. In order to leave a safety buffer, it is recommended to select a maximum LTV that is below the borrowing LTV of the vault. Note that it depends on the [curve](#curves) if the maximum LTV can actually be achieved. A constant product curve will only approach these reserve levels asymptotically, since each unit will get more and more expensive. However, with a constant sum curve, the maximum LTV can be achieved directly. |
| 47 | + |
| 48 | +### Reserve synchronisation |
| 49 | + |
| 50 | +The EulerSwap contract tracks what it believes the reserves to be by caching their values in storage. These reserves are updated on each swap. However, since the balance is not actually held by the EulerSwap contract (it is simply an operator), the actual underlying balances may get out of sync. This can happen gradually as interest is accrued, or suddenly if the holder moves funds or the position is liquidated. When this occurs, the `syncVirtualReserves()` should be invoked. This determines the actual balances (and debts) of the holder and adjusts them by the configured virtual reserve levels. |
| 51 | + |
| 52 | +## Components |
| 53 | + |
| 54 | +### **1. Core contracts** |
| 55 | + |
| 56 | +#### **Maglev contract** |
| 57 | + |
| 58 | +The `Maglev` contract is the core of EulerSwap and is responsible for: |
| 59 | + |
| 60 | +- Managing liquidity reserves. |
| 61 | +- Executing token swaps based on the EulerSwap curve. |
| 62 | +- Enforcing collateralization through EVC. |
| 63 | +- Maintaining vault and asset associations. |
| 64 | + |
| 65 | +##### **Key features** |
| 66 | + |
| 67 | +- Implements a unique **swapping curve** that ensures efficient liquidity provision. |
| 68 | +- Handles **collateralized borrowing** via vaults. |
| 69 | +- Enforces a **fee multiplier** to apply swap fees. |
| 70 | +- Implements a **non-reentrant mechanism** to prevent recursive calls. |
| 71 | + |
| 72 | +##### **Key functions** |
| 73 | + |
| 74 | +- `activate()`: Initializes vault approvals and enables collateral. |
| 75 | +- `swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data)`: Performs asset swaps and enforces curve constraints. |
| 76 | +- `verify(uint256 newReserve0, uint256 newReserve1)`: Ensures reserves conform to the defined curve. |
| 77 | +- `f(uint256 xt, uint256 px, uint256 py, uint256 x0, uint256 y0, uint256 c)`: Defines the EulerSwap curve formula for swaps. |
| 78 | + |
| 79 | +### **2. Periphery contracts** |
| 80 | + |
| 81 | +#### **MaglevPeriphery contract** |
| 82 | + |
| 83 | +The `MaglevPeriphery` contract extends the functionality of the core Maglev contract by providing: |
| 84 | + |
| 85 | +- **Swap price quotations** before execution. |
| 86 | +- **Liquidity checks** to ensure solvency before transactions. |
| 87 | +- **Binary search mechanisms** for dynamic price calculation. |
| 88 | + |
| 89 | +##### **Key functions** |
| 90 | + |
| 91 | +- `quoteExactInput(address maglev, address tokenIn, address tokenOut, uint256 amountIn)`: Estimates the output amount for a given input. |
| 92 | +- `quoteExactOutput(address maglev, address tokenIn, address tokenOut, uint256 amountOut)`: Estimates the required input amount to receive a specified output. |
| 93 | +- `computeQuote(IMaglev maglev, address tokenIn, address tokenOut, uint256 amount, bool exactIn)`: A high-level function to compute swaps while enforcing fee multipliers. |
| 94 | +- `binarySearch(IMaglev maglev, uint112 reserve0, uint112 reserve1, uint256 amount, bool exactIn, bool asset0IsInput)`: Uses binary search to determine an optimal swap amount along the curve. |
| 95 | + |
| 96 | +### **3. Vault integration** |
| 97 | + |
| 98 | +EulerSwap integrates with **Ethereum Vault Connector (EVC)** to enable collateralized trading. Each liquidity vault manages asset balances, borrowing, and repayment, ensuring: |
| 99 | + |
| 100 | +- **Controlled debt exposure** |
| 101 | +- **Dynamic liquidity reserves** |
| 102 | +- **Secure vault interactions** |
| 103 | + |
| 104 | +### **4. Security mechanisms** |
| 105 | + |
| 106 | +- **Non-reentrant protection**: Ensures swaps do not trigger recursive calls. |
| 107 | +- **Collateral verification**: Uses EVC to verify and adjust collateral balances. |
| 108 | +- **Curve constraints enforcement**: Prevents swap execution that violates the defined curve invariant. |
| 109 | +- **Precision safeguards**: Fixed-point arithmetic (`1e18` scaling) ensures precision in calculations. |
| 110 | + |
| 111 | +## Summary |
| 112 | + |
| 113 | +EulerSwap’s architecture is designed for **efficient, secure, and collateral-backed trading** with a custom **swapping curve**. The system leverages: |
| 114 | + |
| 115 | +- **Maglev** as the core AMM contract. |
| 116 | +- **MaglevPeriphery** for auxiliary quoting and validations. |
| 117 | +- **Ethereum Vault Connector (EVC)** for collateralized vault management. |
| 118 | +- **Security-focused design** to prevent vulnerabilities in asset handling. |
| 119 | + |
| 120 | +This modular and scalable architecture ensures that EulerSwap provides robust DeFi trading functionality while maintaining security and efficiency. |
0 commit comments