Skip to content

Commit 8bfcf3d

Browse files
authored
Merge pull request #111 from euler-xyz/eulerswap2-updates
Eulerswap2 updates
2 parents d07c63e + 9287ae4 commit 8bfcf3d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+697
-691
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
- name: Install Foundry
2424
uses: foundry-rs/foundry-toolchain@v1
2525
with:
26-
version: nightly
26+
version: v1.3.6
2727

2828
- name: Show Forge version
2929
run: |

README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ forge doc --serve --port 4000
5050

5151
## Deployment Addresses
5252

53-
On networks where Uniswap v4 is deployed, EulerSwap is deployed using a factory variant that creates Uniswap v4 hook compatible instances. Elsewhere, the original 'OG' version of EulerSwap factory is deployed. The deployed addresses can be found in [Contract Addresses](https://docs.euler.finance/developers/contract-addresses) section of Euler docs. To check which version is deployed, call `poolManager` on the EulerSwap implementation contract (`eulerSwapV1Implementation`). If it returns zero-address then 'OG' version is deployed.
53+
Deployed addresses can be found in [Contract Addresses](https://docs.euler.finance/developers/contract-addresses) section of Euler docs.
5454

5555
## Getting Started
5656

@@ -80,11 +80,13 @@ Note that these limits are enforced by the quoting functions, which will revert
8080

8181
### Creating and Decomissioning Pools
8282

83-
The EulerSwap pools are created by the `EulerSwapFactory` contract, which emits a [PoolDeployed](https://github.com/euler-xyz/euler-swap/blob/1f73f5cb07f2e64e8c9815076749574b1b54e204/src/EulerSwapFactory.sol#L32) event and provides functions to list existing instances.
83+
EulerSwap pools are created by the `EulerSwapFactory` contract, which emits a `PoolDeployed` event and provides functions to list existing instances.
8484

85-
Pools can also be uninstalled by LPs, for example during rebalancing, in which case the factory emits a [PoolUninstalled](https://github.com/euler-xyz/euler-swap/blob/1f73f5cb07f2e64e8c9815076749574b1b54e204/src/EulerSwapFactory.sol#L34) event.
85+
Afterwards, pools can optionally be registered in the `EulerSwapRegistry` contract, which advertises them as ready for swapping. Doing so may require the posting of a small validity bond.
8686

87-
However, note that EulerSwap instances are installed on top of regular accounts within the Euler lending platform—they do not control these accounts. This means an LP can abandon an EulerSwap instance simply by withdrawing their position from the lending vaults. In such cases, the factory has no indication that the pool is no longer operational, but quoting functions or swap simulations will start reverting. If a pool continually fails to return quotes or reverts in simulation, it should likely be blacklisted.
87+
Note that EulerSwap instances are installed on top of regular accounts within the Euler lending platform. This means an LP can abandon an EulerSwap instance simply by withdrawing their position from the lending vaults. In such cases, the registry has no indication that the pool is no longer operational, but quoting functions or swap simulations will start reverting. If a pool is misconfigured and unable to fulfil swaps it is claiming via its `getLimits()` function, the bond may be forfeit and the misconfigured pool removed from the registry.
88+
89+
When a pool is decomissioned, it is recommended to remove from the registry in order to recover the validity bond.
8890

8991
## Safety
9092

docs/architecture.md

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,37 +15,42 @@ Swapping can be performed by invoking the EulerSwap instance, either through a U
1515
EulerSwap is split into the following main contracts:
1616

1717
* `EulerSwap`: Contract that is installed as an EVC operator by liquidity providers, and is also invoked by swappers in order to execute a swap.
18-
* `UniswapHook`: The functions required so that the EulerSwap instance can function as a Uniswap4 hook.
19-
* `EulerSwapFactory`: Factory contract for creating `EulerSwap` instances and for querying existing instances.
20-
* `EulerSwapPeriphery`: This is a wrapper contract for quoting and performing swaps, while handling approvals, slippage, etc.
18+
* `UniswapHook`: Internal contract implementing the functionality for EulerSwap instances to function as a Uniswap4 hook.
19+
* `EulerSwapManagement`: Internal contract that implements management functionality for EulerSwap instances to reduce code size. `EulerSwap` uses delegatecall to this contract.
20+
* `EulerSwapBase`: Internal base class used to share functionality between `EulerSwap` and `EulerSwapManagement`
21+
* `EulerSwapFactory`: Factory contract for creating `EulerSwap` instances.
22+
* `EulerSwapRegistry`: Registry contract for advertising `EulerSwap` instances that are available for swapping.
23+
* `EulerSwapPeriphery`: Wrapper contract for quoting and performing swaps, while handling approvals, slippage, etc.
24+
* `EulerSwapProtocolFeeConfig`: A contract queried to determine the protocol fee in effect for a given swap.
2125

2226
The above contracts depend on libraries:
2327

2428
* `CtxLib`: Allows access to the `EulerSwap` context: Structured storage and the instance parameters
2529
* `FundsLib`: Moving tokens: approvals and transfers in/out
2630
* `CurveLib`: Mathematical routines for calculating the EulerSwap curve
2731
* `QuoteLib`: Computing quotes. This involves invoking the logic from `CurveLib`, as well as taking into account other limitations such as vault utilisation, supply caps, etc.
32+
* `SwapLib`: Routines for actually performing swaps
2833

2934
And some utilities:
3035

3136
* `MetaProxyDeployer`: Deploys EIP-3448-style proxies.
32-
* `ProtocolFee`: The factory stores protocol fee parameters that will affect subsequently created `EulerSwap` instances. These can be changed by an owner.
3337

3438
## Operational flow
3539

3640
The following steps outline how an EulerSwap operator is created and configured:
3741

3842
1. Deposit initial liquidity into one or both of the underlying credit vaults to enable swaps.
39-
1. Choose the desired pool parameters (`IEulerSwap.Params` struct). The `protocolFee` and `protocolFeeRecipient` must be read from the factory.
43+
1. Choose the desired pool parameters (`IEulerSwap.StaticParams` and `IEulerSwap.DynamicParams` structs)
4044
1. [Mine](https://docs.uniswap.org/contracts/v4/guides/hooks/hook-deployment#hook-miner) a salt such that the predicted address of the `EulerSwap` instance will be deployed with the correct flags.
4145
1. Install the above address as an EVC operator, ensuring that any previous `EulerSwap` operators are uninstalled.
4246
1. Invoke `deployPool()` on the EulerSwap factory.
47+
1. Optional: Register the pool in the EulerSwapRegistry.
4348

4449
## Metaproxies
4550

4651
Each `EulerSwap` instance is a lightweight proxy, roughly modelled after [EIP-3448](https://eips.ethereum.org/EIPS/eip-3448). The only difference is that EIP-3448 appends the length of the metadata, whereas we don't, since it is a fixed size.
4752

48-
When an `EulerSwap` instance is created, the `IEulerSwap.Params` struct is ABI encoded and provided as the proxy metadata. This is provided to the implementation contract as trailing calldata via `delegatecall`. This allows the parameters to be accessed cheaply when servicing a swap, compared to if they had to be read from storage.
53+
When an `EulerSwap` instance is created, the `IEulerSwap.StaticParams` struct is ABI encoded and provided as the proxy metadata. This is provided to the implementation contract as trailing calldata via `delegatecall`. This allows the parameters to be accessed cheaply when servicing a swap, compared to if they had to be read from storage.
4954

5055
## Curve Parameters
5156

@@ -78,7 +83,7 @@ Note that there may be a race condition when removing one swap operator and inst
7883

7984
Swapping fees are charged by requiring the swapper to pay slightly more of the input token than is required by the curve parameters. This extra amount is simply directly deposited into the vaults on behalf of the EulerSwap account. This means that it has the effect of increasing the account's NAV, but does not change the shape of the curve itself. The curve is always static, per EulerSwap instance.
8085

81-
When an EulerSwap instance is created, a **protocol fee** parameter may be installed by the factory. This portion of the collected fees are routed to a protocol fee recipient. An administrator of the factory can change the the protocol fee and recipient for future created EulerSwap instances, although previously created instances will not be updated retroactively.
86+
When a swap is performed, the `EulerSwapProtocolFeeConfig` contract is queried to determine the protocol fee in effect. This proportion of the LP fees are instead sent to a protocol fee recipient chosen by the Euler DAO. This proportion cannot exceed 15%.
8287

8388

8489
## Reserve desynchronisation
@@ -103,7 +108,7 @@ Although the virtual reserves specify a hard limit for swaps, there may be other
103108
* The vaults have supply and/or borrow caps
104109
* The operator may have been uninstalled
105110

106-
There is a function `getLimits` that can take these into account. This function itself is an upper-bound and the values it returns may not be swappable either, in particular if the curve shape does not allow it. However, it makes a best effort and this function can be used to rapidly exclude pools that are definitely unable to service a given size swap.
111+
There is a function `getLimits` that can take these into account. This function is intended to return quotes that are swappable, but under some conditions may not be, if the pool is configured with larger reserves than the underlying Euler account's liquidity can handle. In these cases, the pool is eligible from being removed from the Registry.
107112

108113

109114
## Swapper Security

docs/interfaces.md

Lines changed: 0 additions & 113 deletions
This file was deleted.

foundry.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ out = "out"
44
libs = ["lib"]
55
solc = "0.8.27"
66
optimizer = true
7-
optimizer_runs = 1000000
7+
optimizer_runs = 2500
88
gas_reports = ["*"]
99
fs_permissions = [{ access = "read-write", path = "./"}]
1010

remappings.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,3 @@ ethereum-vault-connector/=lib/ethereum-vault-connector/src/
55
evk-test/=lib/euler-vault-kit/test/
66
permit2/=lib/euler-vault-kit/lib/permit2/
77
@uniswap/v4-core/=lib/v4-periphery/lib/v4-core/
8-
solmate/=lib/v4-periphery/lib/v4-core/lib/solmate/src

script/DeployProtocol.s.sol

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import {EulerSwapFactory} from "../src/EulerSwapFactory.sol";
66
import {EulerSwapRegistry} from "../src/EulerSwapRegistry.sol";
77
import {EulerSwapPeriphery} from "../src/EulerSwapPeriphery.sol";
88
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
9+
import {EulerSwapProtocolFeeConfig} from "../src/EulerSwapProtocolFeeConfig.sol";
910
import {EulerSwap} from "../src/EulerSwap.sol";
11+
import {EulerSwapManagement} from "../src/EulerSwapManagement.sol";
1012

1113
/// @title Script to deploy EulerSwapFactory & EulerSwapPeriphery.
1214
contract DeployProtocol is ScriptUtil {
@@ -21,16 +23,17 @@ contract DeployProtocol is ScriptUtil {
2123

2224
address evc = vm.parseJsonAddress(json, ".evc");
2325
address poolManager = vm.parseJsonAddress(json, ".poolManager");
24-
address evkFactory = vm.parseJsonAddress(json, ".evkFactory");
25-
address feeOwner = vm.parseJsonAddress(json, ".feeOwner");
26-
address feeRecipientSetter = vm.parseJsonAddress(json, ".feeRecipientSetter");
26+
address protocolFeeAdmin = vm.parseJsonAddress(json, ".protocolFeeAdmin");
2727
address validVaultPerspective = vm.parseJsonAddress(json, ".validVaultPerspective");
2828
address curator = vm.parseJsonAddress(json, ".curator");
2929

3030
vm.startBroadcast(deployerAddress);
3131

32-
address eulerSwapImpl = address(new EulerSwap(evc, poolManager));
33-
address eulerSwapFactory = address(new EulerSwapFactory(evc, eulerSwapImpl, feeOwner, feeRecipientSetter));
32+
address eulerSwapProtocolFeeConfig = address(new EulerSwapProtocolFeeConfig(evc, protocolFeeAdmin));
33+
address eulerSwapManagementImpl = address(new EulerSwapManagement(evc));
34+
address eulerSwapImpl =
35+
address(new EulerSwap(evc, eulerSwapProtocolFeeConfig, poolManager, eulerSwapManagementImpl));
36+
address eulerSwapFactory = address(new EulerSwapFactory(evc, eulerSwapImpl));
3437
new EulerSwapRegistry(evc, eulerSwapFactory, validVaultPerspective, curator);
3538
new EulerSwapPeriphery();
3639
vm.stopBroadcast();

script/README.md

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,17 @@ Before running the scripts, please make sure to fill the `.env` file following t
66

77
After filling the `.env` file, make sure to run: `source .env` in your terminal.
88

9-
## Deploy new pool
10-
- Fill the `DeployPool_input.json` file with the needed inputs.
11-
- The `eulerAccount` will be derived from the private key provided in `.env`. The account's position on Euler should be already set up.
12-
- Run `forge script ./script/DeployPool.s.sol --rpc-url network_name --broadcast --slow`, replacing `network_name` to match `_RPC_URL` environment variable (e.g. if running through `MAINNET_RPC_URL` replace `network_name` with `mainnet`)
13-
- The deployed pool address will be recorded in `./scripts/json/DeployPool_output.json` file
9+
## Deploy protocol
1410

15-
## Exact in swap
11+
- Fill the `DeployProtocol_input.json` file with the needed inputs.
12+
- Run `forge script ./script/DeployProtocol.s.sol --rpc-url network_name --broadcast --slow`, replacing `network_name` to match `_RPC_URL` environment variable (e.g. if running through `MAINNET_RPC_URL` replace `network_name` with `mainnet`)
1613

17-
- Fill the `SwapExactIn_input.json` file with the needed inputs.
18-
- Run `forge script ./script/SwapExactIn.s.sol --rpc-url network_name --broadcast --slow`, replacing `network_name` to match `_RPC_URL` environment variable (e.g. if running through `MAINNET_RPC_URL` replace `network_name` with `mainnet`)
14+
## Deployments
1915

20-
## Uninstall pool
16+
These are temporary deployments for testing. The official EulerSwap instances will be deployed by the EVK periphery infrastructure.
2117

22-
- Fill the `UninstallPool_input.json` file with the factory address.
23-
- Run `forge script ./script/UninstallPool.s.sol --rpc-url network_name --broadcast --slow`, replacing `network_name` to match `_RPC_URL` environment variable (e.g. if running through `MAINNET_RPC_URL` replace `network_name` with `mainnet`)
18+
### Base
2419

25-
## Deploy protocol
26-
27-
- Fill the `DeployProtocol_input.json` file with the needed inputs.
28-
- Run `forge script ./script/DeployProtocol.s.sol --rpc-url network_name --broadcast --slow`, replacing `network_name` to match `_RPC_URL` environment variable (e.g. if running through `MAINNET_RPC_URL` replace `network_name` with `mainnet`)
20+
EulerSwapFactory: 0xd7c9ec4925e5d95d341a169e8d7275e92b064b74
21+
EulerSwapRegistry: 0x93c4d4909fdc3b0651374f1160ec2aed4960d82c
22+
EulerSwapPeriphery: 0x18f0e5f802937447f49ea5e8faebb454c5c74c71

script/SwapExactIn.s.sol

Lines changed: 0 additions & 39 deletions
This file was deleted.

0 commit comments

Comments
 (0)