You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+16-59Lines changed: 16 additions & 59 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,7 @@
4
4
5
5
Maglev is an Automated Market Maker (AMM) that uses [Euler Vaults](https://docs.euler.finance/euler-vault-kit-white-paper/) to **mag**nify capital efficiency using **lev**erage. By borrowing assets as needed, Maglev AMMs can extend the range of their reserves and earn fees on trades several times larger than their actual liquidity.
6
6
7
-
To swappers, Maglev presents a conventional Uniswap2-style interface but internally it supports borrow and repaying, custom pricing curves, and other advanced functionality. Although invokeable by anyone, the primary swapper user-base is intended to be aggregators, intents solvers, and MEV bots.
7
+
To swappers, Maglev presents a hopefully familiar Uniswap2-style interface but internally it supports borrow and repaying, custom pricing curves, and other advanced functionality. Although useable by anyone, it is primarily intended to be invoked by sophisticated actors such as swap aggregators, intents solvers, and MEV bots. Similar to Uniswap, there is a careful separation between the critical core functionality for servicing swaps and the surrounding periphery functions for quoting, etc.
8
8
9
9
<!-- TOC FOLLOWS -->
10
10
<!-- START OF TOC -->
@@ -17,11 +17,7 @@ To swappers, Maglev presents a conventional Uniswap2-style interface but interna
@@ -38,30 +34,27 @@ The down-side is that while the AMM holds this leveraged position, it is paying
38
34
39
35
## Operation
40
36
41
-
Since the level of acceptable borrowing risk is not be the same for every user, pooled deposits are not supported. Each Maglev instance manages funds for a single entity (who of course may be jointly owned).
37
+
Since the level of acceptable borrowing risk is not necessarily the same for every user, pooled deposits are not supported. Each Maglev instance manages funds for a single entity (which of course may be jointly owned).
42
38
43
39
Maglev 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.
44
40
45
41
### Usage
46
42
47
-
The following are the high-level steps required to use Maglev:
43
+
The following are the high-level steps required to setup Maglev:
48
44
49
45
* Deposit funds into one or both of the vaults in proportion to the initial price
50
-
* Deploy the desired Maglev contract, choosing parameters such as the vaults, debt limits, and the desired `fee`
51
-
* Note that the Maglev contract must be created after the funds are deposited, because its constructor will read the current debts and balances to setup its reserves cache
46
+
* Deploy the desired Maglev contract, choosing parameters such as the vaults, initial price ratio, debt limits, and the swapping fee
47
+
* Note that the Maglev contract must be created *after* the funds are deposited, because its constructor will read the current debts and balances to setup its reserves cache
52
48
* Install the Maglev contract as an operator for your account
53
-
* Invoke the `activate()` function on the Maglev contract
54
-
* This function can be invoked by anyone, and it is harmless to re-invoke it
55
-
56
-
At this point, anyone can invoke `swap()` on the Maglev contract, and this will perform borrowing and transferring activity between the two vaults.
49
+
* Optional: Invoke the `activate()` function on the Maglev contract. Otherwise, Maglev will be activated when the first swap is performed (increasing its gas cost somewhat)
57
50
58
51
### Reconfiguration
59
52
60
53
All user-configurable parameters are stored in immutable variables, meaning they cannot be changed after the AMM is deployed. Instead, the holder should uninstall it from its EVC operator set, and a new Maglev instance should be created and installed in its place.
61
54
62
55
### Debt Limits
63
56
64
-
The initial deposits in the two vaults represent the initial investment, and are swapped back and forth in response to swapping activity. In order to prevent loss to arbitrage, the initial investment should be made in proportion to the price of the assets.
57
+
The initial deposits in the two vaults represent the initial investment, and are swapped back and forth in response to swapping activity. In order to prevent immediate losses to arbitrage, the initial investment should be made in proportion to the price of the assets.
65
58
66
59
In a conventional AMM such as Uniswap, the balances held by the contract are called *reserves*, and these represent a hard upper-bound on the amounts that can be swapped: In other words, no matter how much you are willing to pay, you can never receive more than the amount currently held in reserve.
67
60
@@ -71,68 +64,32 @@ For example, if the initial investment has a NAV of $1000, and the debt limit is
71
64
72
65
Each vault can have its own independent debt limit, which may be useful in case of vaults configured with asymmetric LTVs. A debt limit of 0 could be specified for one of the vaults if the holder only ever wants a borrow position in one of the assets. In the future we may add a debt minimum, allowing the holder to retain a position within a certain leverage range while continuing to profit off swapping activity.
73
66
74
-
Note that it depends on the [curve](#curves) if the maximum LTV can actually be achieved. A constant product curvewill only approach these reserve levels asymptotically, since each unit will get more and more expensive. With a constant sum curve, the LTV can be achieved precisely.
67
+
Note that the the maximum LTV cannot actually be achieved because of the design of the curve. Instead, it will only approach these reserve levels asymptotically, since each unit gets more and more expensive.
75
68
76
69
### Desynchronised Reserves
77
70
78
-
The Maglev contract tracks what it believes the reserves (amount available plus borrowable) to be by caching in storage. These reserves are updated on each swap. However, since the balance is not actually held by the Maglev contract (it is simply an operator), the actual underlying debts and balances may get out of sync. This can happen gradually as interest and fees are accrued, or suddenly if the holder moves funds or the position is liquidated.
71
+
The Maglev contract tracks what it believes the reserves (balance available plus borrowable) to be by caching in storage. These reserves are updated on each swap. However, since the balance is not actually held by the Maglev contract (it is simply an operator), the actual underlying debts and balances may get out of sync. This can happen gradually as interest and fees are accrued, or suddenly if the holder moves funds or the position is liquidated.
79
72
80
73
Normally this is not a problem, because swapping will still occur on the static curve (such actions do not change the offered prices). However, if there is a significant decrease in NAV then the desired LTVs may be exceeded (since the debt limit becomes higher relative to the NAV). If there is a significant increase in NAV then the AMM may become less capital efficient. To resynchronise, the Maglev instance should be uninstalled as an EVC operator, and a new one created and installed in its place.
81
74
82
75
### Fees
83
76
84
-
Maglev collects swap fees in the input token.
85
-
86
-
When quoting exact input swaps the effective input amount is decreased by the fee (rounding down) before consulting the curve. When quoting exact output swaps, the required input amount is increased by the fee (rounding up).
87
-
88
-
After depositing but prior to verifying the curve invariant, all input amounts are adjusted down (rounding down).
89
-
90
-
Since the full amount including fees is actually deposited (or repaid), fees have the effect of increasing the NAV of the position. However, they are not currently "fed back" into the reserves to be used by future swaps. If fees build up significantly, the Maglev instance should be [replaced](#desynchronised-reserves).
91
-
92
-
93
-
## Curves
77
+
Maglev collects swap fees in the input token. In the core, after depositing but prior to verifying the curve invariant, all input amounts are adjusted down (rounding down).
94
78
95
-
### Constant Sum
79
+
In the periphery, when quoting exact input swaps the effective input amount is decreased by the fee (rounding down) before consulting the curve. When quoting exact output swaps, the required input amount is increased by the fee (rounding up).
96
80
97
-
This "curve" simply adds the values of the two reserves together and ensures that after a swap this sum has not decreased. It is mostly suitable for assets that are pegged to the same value, such as stable-stable pairs.
81
+
Since the full amount including fees is actually deposited (or repaid), fees have the effect of increasing the NAV of the position. However, they are not currently "fed back" into the reserves to be used by future swaps. If fees build up significantly, and compounding of these proceeds is desired, the Maglev instance should be [replaced](#desynchronised-reserves) by an instance with higher debt limits.
98
82
99
-
This curve supports a price fraction so that the two tokens can have different relative values, which can be useful if the peg is other than 1:1, or if the tokens have differing decimals.
100
83
101
-
In this curve, the entire virtual reserves can be consumed, and since each marginal unit of the swap has the same price, there is no direct incentive for arbitrageurs to deleverage the position. However, for the same reason this does allow fixed-size fees for swaps of any supported size (fixed price impact).
84
+
## EulerSwap Curve
102
85
103
-
### Constant Product
86
+
Although the Maglev interface can support various types of curves, the current implementation only uses the *EulerSwap curve*. This is a new curve developed by Euler Labs, and can be thought of as a hybrid between constant sum and constant product. The curve is defined piecewise: A piece to the left of an "initial reserves" point, and a piece to the right.
104
87
105
-
This is the traditional Uniswap2 curve that preserves the product of the two reserves. The larger a swap, the higher the price impact and the more profitable it is to arbitrage a disbalanced pool back to the market price.
106
-
107
-
### EulerSwap Curve
108
-
109
-
This is a new curve developed by Euler. It can be thought of as a hybrid between constant sum and constant product. The curve is defined piecewise: A piece to the left of an "initial reserves" point, and a piece to the right.
110
-
111
-
Each piece has a `concentration` parameter that determines the trade-off between constant sum and constant product. The higher the concentration (closer to 1), the more it is similar to a constant sum, and the lower (closer to 0), a constant product. The curve is also parameterised by a `price` parameter which determines the slope at the initial reserves point. There are actually two price parameters which can be considered the numerator and denominator of the price fraction.
88
+
Each piece has a `concentration` parameter that determines the trade-off between constant sum and constant product. The higher the concentration (closer to 1), the more it resembles a constant sum, and the lower (closer to 0), a constant product. The curve is also parameterised by a `price` which determines the slope at the initial reserves point. There are actually two price parameters which can be considered the numerator and denominator of the price fraction.
112
89
113
90
With careful parameter selection, the EulerSwap curve supports optimal tradeoffs between capital efficiency and arbitrage incentives.
114
91
115
92
116
-
117
-
## Future directions
118
-
119
-
* Currently we have only been supporting stable-stable pairs
120
-
* What extra considerations would there be for floating pairs?
121
-
* Automatically re-invest fees. There are a few options:
122
-
* Don't do anything: Re-deploing probably isn't a huge deal
123
-
* Increase the reserves by the fee amount
124
-
* Increase the reserves by the extra amount of possible leverage supported by the new fee
125
-
* Apply fees to a super-concentrated middle section of the curve (needs R&D)
126
-
* Could current reserves be calculated dynamically based on balances/debts/debt limits?
127
-
* I guess you would lose a chunk of interest to arbitrage
128
-
* Donation attacks?
129
-
* What can we do to make this easily integrated with aggregators/MEV bots/etc?
130
-
* For sure we need events. What should be logged?
131
-
* How to handle a discovery/tracking of the different Maglev instances?
132
-
* Factory? Registry? Maybe a fake factory that reads the actually installed operators from a set of addresses?
! Better revert messages when a swap cannot be satisifed due to debt-limit/utilisation/etc
1
+
! Don't make quotes that would cause a swap to fail if supply/borrow caps exceeded
2
+
* Better revert messages when a swap fails due to maglev debt-limit/vault utilisation/etc
4
3
* currently it's an arithmetic underflow
5
-
! Don't make quotes that would cause a swap to fail due to supply or borrow caps
6
-
* ConstantSum: incorporate price multipliers in quote methods
7
-
* natspec
8
-
* permit2 instead of regular approval: measure gas savings
9
-
? a really small swap could fail because deposit() results in 0 shares, which EVK fails on. call convertToShares() first? Seems like overkill
10
-
? pause guardian
11
-
? how should aggregators find instances
12
-
? factory/registry contract
13
-
? fake registry contract that looks at the actually installed operators for a list of accounts
14
-
? transparent proxy so AMM address can stay constant
15
-
16
-
docs
17
-
low-level detail of how system works for auditors
18
-
how to add a curve
19
-
information for aggregators
20
-
how to maintain quotes off-chain, including tracking cash from VaultStatus logs of underlying vaults
21
-
note how EVK stores balance and debt in same storage slot
22
-
23
-
tests
24
-
prices/alternate decimals
25
-
especially quoting
26
-
when exchange rate in vaults != 1
27
-
uniswap callback, flash swaps
28
-
hitting reserve/utilisation limits
4
+
5
+
6
+
TESTING
7
+
8
+
* when exchange rate in vaults != 1
9
+
* uniswap callback, flash swaps
10
+
* hitting reserve/utilisation limits
11
+
* AssetsOutOfOrderOrEqual
12
+
13
+
14
+
MISC
15
+
16
+
? A really small swap could fail because deposit() results in 0 shares, which causes EVK to revert. Call convertToShares() first? Seems like overkill...
17
+
? permit2 instead of regular approval: measure gas savings
18
+
* Improve the efficiency of on-chain quoting
19
+
* Probably necessary for supporting non-zero slippage swaps
20
+
* Use unchecked math in verify() (needs careful boundary analysis)
21
+
* Closed-form quoting solutions
22
+
* "Range hints" for the binary search
23
+
24
+
25
+
IDEAS
26
+
27
+
* Currently we have only been supporting stable-stable pairs
28
+
* What extra considerations would there be for floating pairs?
29
+
* Automatically re-invest fees? There are a few options:
30
+
* Don't do anything: Re-deploing probably isn't a huge deal
31
+
* Increase the reserves by the fee amount
32
+
* Increase the reserves by the extra amount of possible leverage supported by the new fee
33
+
* Apply fees to a super-concentrated middle section of the curve (needs R&D)
34
+
* Could current reserves be calculated dynamically based on balances/debts/debt limits?
35
+
* I guess you would lose a chunk of interest to arbitrage
36
+
* Donation attacks?
37
+
* What can we do to make this easily integrated with aggregators/MEV bots/etc?
38
+
* How to handle a discovery/tracking of the different Maglev instances?
39
+
? Factory? Registry? Maybe a fake factory that reads the actually installed operators from a set of addresses?
40
+
? Transparent proxy so a Maglev address can stay constant
0 commit comments