Skip to content

Commit 57e5845

Browse files
Merge branch 'master' into hook-target-firewall
2 parents ea581b6 + e242c52 commit 57e5845

File tree

51 files changed

+2365
-452
lines changed

Some content is hidden

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

51 files changed

+2365
-452
lines changed
692 KB
Binary file not shown.
311 KB
Binary file not shown.
249 KB
Binary file not shown.

docs/swaps.md

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,16 @@ Finally a `multicall` function allows chaining all of the above to execute compl
4545
The swaps can be performed in one of 3 modes:
4646
- exact input
4747

48-
In this mode, all of the provided input token is expected to be swapped for an unknown amount of the output token. The proceeds are expected to be sent to a vault, to be skimmed by the user, or back to the swapper contract. The latter option is useful when performing complex, multi-stage swaps, where the output token is accumulated in the swapper before being consumed at the end of the operation. Note that the available handlers (1Inch and Uniswap Auto Router) execute a payload encoded off-chain, so a lot of the parameters passed to the `swap` funtion will be ignored and only the amount of input token encoded in the payload will be swapped, even if the swapper holds more.
48+
In this mode, all of the provided input token is expected to be swapped for an unknown amount of the output token. The proceeds are expected to be sent to a vault, to be skimmed by the user, or back to the swapper contract. The latter option is useful when performing complex, multi-stage swaps, where the output token is accumulated in the swapper before being consumed at the end of the operation. Note that the available handler (`GenericHandler`) executes a payload encoded off-chain, so a lot of the parameters passed to the `swap` funtion will be ignored and only the amount of input token encoded in the payload will be swapped, even if the swapper holds more.
4949

5050
- exact output
5151

5252
In this mode, the swapper is expected to purchase a specified amount of the output token in exchange for an unknown amount of the input token. The input token amount provided to the swapper acts as an implicit slippage limit. Currently available handlers (Uniswap V2 and V3) will check the current balance of the output token held by the swapper and adjust the amount of token to buy to only purchase the remainder. This feature can be used to construct multi-stage swaps. For instance, in the first stage, most of the token is bought through a dex aggregator, which presumably offers better price, but doesn't provide exact output swaps. The proceeds are directed to the swapper contract. In the second stage another `swap` call is executed, and the remainder is bought directly in Uniswap, where exact output trades are supported.
5353

5454
In exact output trades, the remaining, unused input token amount is automatically redeposited for the account specified in `SwapParams.accountIn` in a vault specified in `SwapParams.vaultIn`.
5555

56+
Note that the generic handler can also be invoked in exact output mode. The swap will be executed as per the request encoded off-chain, but swapper will attempt to return unused input token balance if any.
57+
5658
- target debt (swap and repay)
5759

5860
In this mode, the swapper will check how much debt a provided account has (including current interest accrued), compare it with a target debt the user requests, and the amount already held by the swapper contract, and by exact output trade will buy exactly the amount required to repay the debt (down to the target amount). In most cases the target amount will be zero, which means the mode can be used to close debt positions without leaving any dust.
@@ -63,18 +65,20 @@ The swaps can be performed in one of 3 modes:
6365

6466
Finally, and similarly to exact output, any unused input will be redeposited for the `accountIn`.
6567

68+
Note that the generic handler can also be invoked in target debt mode. In such a case there will be no on-chain modification to the swap payload, but swapper will attempt a repay and return of the unused input as per swap params.
69+
6670

6771
### Handlers
6872

6973
The swapper contract executes trades using external providers like 1Inch or Uniswap. Internal handler modules take care of interfacing with the provider. They are enumerated by a `bytes32` encoded string. The available handlers are listed as constants in `Swapper.sol`.
7074

71-
- 1Inch handler
75+
- Generic handler
7276

73-
Only supports `exact input` mode. Executes a payload returned by [1Inch API](https://portal.1inch.dev/documentation/swap/introduction) on the aggregator contract.
77+
Executes arbitrary call on arbitrary target address. Presumably they are calls to swap providers. For example a payload returned by [1Inch API](https://portal.1inch.dev/documentation/swap/introduction) on the aggregator contract or payloads created with [Uniswap's Auto Router](https://github.com/Uniswap/smart-order-router) on [SwapRouter02](https://etherscan.io/address/0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45)
7478

75-
- Uniswap Auto Router handler
79+
Generic handler accepts all 3 swapping modes, although for most swap providers only exact input is natively available. Although the off-chain data will not be modified to match the actual on-chain conditions during execution, swapper will carry out post processing according to the swap mode: returning unused input token in exact output mode or repaying debt in target debt mode. See F5 in [Common flows](#common-flows-in-evk) for one possible use case.
7680

77-
Supports `exact input` and `exact output` modes. Executes payloads created with [Uniswap's Auto Router](https://github.com/Uniswap/smart-order-router) on [SwapRouter02](https://etherscan.io/address/0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45). Payload is simply executed in both modes, so in exact output, the handler will not try to update the amount bought with balance already present in the swapper, as the other uniswap handlers.
81+
The data passed to the handler in `SwapParams.data` should be an abi encoded tuple: target contract address and call data
7882

7983
- Uniswap V2 handler
8084

@@ -98,15 +102,15 @@ F1. Swap exact amount of deposits from one EVault (A) to another (B)
98102
- fetch a swap payload from either 1Inch api or Uniswap Auto Router, setting B as the receiver
99103
- create EVC batch call with the following items:
100104
- `A.withdraw` the required input token amount to the swapper contract
101-
- `Swapper.swap` - `exact input` on the selected handler
105+
- `Swapper.swap` - `exact input` on the generic handler
102106
- `SwapVerifier.verifyAmountMinAndSkim` Check a minimum required amount was bought for the input, according to slippage settings and claim it for the user.
103107

104108
F2. Swap deposits from one EVault (A) to exact amount of another (B)
105109
- find an exact input payload on 1Inch or Uniswap Auto Router such that most of the required output amount is bought. E.g., binary search input amount that yields 98% of the required output amount. The receiver encoded in the payload must be the swapper contract.
106110
- create EVC batch with the following items:
107111
- `A.withdraw` to the swapper contract. The amount must cover all of the estimated swap costs with some extra, to account for slippage
108112
- `swapper.multicall` with the following items:
109-
- `Swapper.swap` - `exact input` with the off-chain payload
113+
- `Swapper.swap` - `exact input` on the generic handler with the off-chain payload
110114
- `Swapper.swap` - `exact output` on one of the supportin handlers (Uni V2/V3) with the user specified `amountOut`. The receiver can be either the swapper contract or B vault.
111115
- `Swapper.sweep` the output token, into the B vault
112116
- `SwapVerifier.verifyAmountMinAndSkim` check a minimum required amount was bought and claim the funds for the user. Because exact output swaps are not guaranteed to be exact always, a small slippage could be allowed.
@@ -127,9 +131,8 @@ F4. Sell deposits from one vault (A) to repay debt in another (B)
127131
F5. Sell deposit from one vault (A) to repay debt in another (B) when exact output is unavailable
128132

129133
For some token pairs, the exact output swap might not be available at all, or the price impact might be too big due to poor liquidity in Uniswap. In such cases to repay the full debt:
130-
- find an exact input payload on 1Inch or Uniswap Auto Router, to buy slightly **more** of the output token than is necessary to repay the debt, taking into account slippage on exchanges and interest accrual between the payload generation and transaction execution. E.g., binary search input amount that yields 102% of the current debt. Set the receiver to the liability vault.
134+
- find an exact input payload on 1Inch or Uniswap Auto Router, to buy slightly **more** of the output token than is necessary to repay the debt, taking into account slippage on exchanges and interest accrual between the payload generation and transaction execution. E.g., binary search input amount that yields 102% of the current debt (2% slippage limit). Set the receiver to the liability vault.
131135
- create EVC batch with the following items:
132136
- `A.withdraw` the required input token amount to the swapper contract
133-
- `Swapper.swap` - `exact input` on the selected handler
134-
- `SwapVerifier.verifyAmountMinAndSkim` check that the minimum required amount was bought and claim it for the user
135-
- `B.repayWithShares` setting the amount to max uint256. Debt should be removed to zero, with the remainder of the output token deposited in B vault for the borrower.
137+
- `Swapper.swap` - `target debt` on the generic handler. The `amountOut` should be set to the amount of debt the user requested to have after the operation. Set to zero, to repay full debt.
138+
- `SwapVerifier.verifyDebtMax` check that the user's debt matches the expectations

foundry.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ quote_style = "double"
2222
number_underscore = "preserve"
2323
override_spacing = true
2424
wrap_comments = true
25+
ignore = [
26+
"script/production/mainnet/DeployCBBTC.s.sol"
27+
]
2528

2629
[profile.default.fuzz]
2730
max_test_rejects = 1_000_000

remappings.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ euler-price-oracle/=lib/euler-price-oracle/src/
77
euler-price-oracle-test/=lib/euler-price-oracle/test/
88
fee-flow/=lib/fee-flow/src/
99
reward-streams/=lib/reward-streams/src/
10-
@openzeppelin/contracts/utils/math/=lib/euler-price-oracle/lib/openzeppelin-contracts/contracts/utils/math/
10+
@openzeppelin/contracts/=lib/euler-price-oracle/lib/openzeppelin-contracts/contracts/
1111
solady/=lib/euler-price-oracle/lib/solady/src/

script/00_ERC20.s.sol

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
3+
pragma solidity ^0.8.0;
4+
5+
import {ScriptUtils, ERC20Mintable} from "./utils/ScriptUtils.s.sol";
6+
import {RewardToken} from "../src/ERC20/deployed/RewardToken.sol";
7+
8+
contract MockERC20Deployer is ScriptUtils {
9+
function run() public broadcast returns (address mockERC20) {
10+
string memory inputScriptFileName = "00_MockERC20_input.json";
11+
string memory outputScriptFileName = "00_MockERC20_output.json";
12+
string memory json = getInputConfig(inputScriptFileName);
13+
string memory name = abi.decode(vm.parseJson(json, ".name"), (string));
14+
string memory symbol = abi.decode(vm.parseJson(json, ".symbol"), (string));
15+
uint8 decimals = abi.decode(vm.parseJson(json, ".decimals"), (uint8));
16+
17+
mockERC20 = execute(name, symbol, decimals);
18+
19+
string memory object;
20+
object = vm.serializeAddress("mock", "mockERC20", mockERC20);
21+
vm.writeJson(object, string.concat(vm.projectRoot(), "/script/", outputScriptFileName));
22+
}
23+
24+
function deploy(string memory name, string memory symbol, uint8 decimals)
25+
public
26+
broadcast
27+
returns (address mockERC20)
28+
{
29+
mockERC20 = execute(name, symbol, decimals);
30+
}
31+
32+
function execute(string memory name, string memory symbol, uint8 decimals) public returns (address mockERC20) {
33+
mockERC20 = address(new ERC20Mintable(getDeployer(), name, symbol, decimals));
34+
}
35+
}
36+
37+
contract RewardTokenDeployer is ScriptUtils {
38+
function run() public broadcast returns (address rewardToken) {
39+
string memory inputScriptFileName = "00_RewardToken_input.json";
40+
string memory outputScriptFileName = "00_RewardToken_output.json";
41+
string memory json = getInputConfig(inputScriptFileName);
42+
address evc = abi.decode(vm.parseJson(json, ".evc"), (address));
43+
address owner = abi.decode(vm.parseJson(json, ".owner"), (address));
44+
address receiver = abi.decode(vm.parseJson(json, ".receiver"), (address));
45+
address underlying = abi.decode(vm.parseJson(json, ".underlying"), (address));
46+
string memory name = abi.decode(vm.parseJson(json, ".name"), (string));
47+
string memory symbol = abi.decode(vm.parseJson(json, ".symbol"), (string));
48+
49+
rewardToken = execute(evc, owner, receiver, underlying, name, symbol);
50+
51+
string memory object;
52+
object = vm.serializeAddress("rewardToken", "rewardToken", rewardToken);
53+
vm.writeJson(object, string.concat(vm.projectRoot(), "/script/", outputScriptFileName));
54+
}
55+
56+
function deploy(
57+
address evc,
58+
address owner,
59+
address receiver,
60+
address underlying,
61+
string memory name,
62+
string memory symbol
63+
) public broadcast returns (address rewardToken) {
64+
rewardToken = execute(evc, owner, receiver, underlying, name, symbol);
65+
}
66+
67+
function execute(
68+
address evc,
69+
address owner,
70+
address receiver,
71+
address underlying,
72+
string memory name,
73+
string memory symbol
74+
) public returns (address rewardToken) {
75+
rewardToken = address(new RewardToken(evc, owner, receiver, underlying, name, symbol));
76+
}
77+
}

script/00_MockERC20.s.sol

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

0 commit comments

Comments
 (0)