diff --git a/script/deploy/BurnerRouter.s.sol b/script/deploy/BurnerRouter.s.sol new file mode 100644 index 0000000..91cb2e0 --- /dev/null +++ b/script/deploy/BurnerRouter.s.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.25; + +import {Script, console2} from "forge-std/Script.sol"; + +import {IBurnerRouterFactory} from "../../src/interfaces/router/IBurnerRouterFactory.sol"; +import {IBurnerRouter} from "../../src/interfaces/router/IBurnerRouter.sol"; + +contract BurnerRouterScript is Script { + function run( + address burnerRouterFactory, + address owner, + address collateral, + uint48 delay, + address globalReceiver, + IBurnerRouter.NetworkReceiver[] calldata networkReceivers, + IBurnerRouter.OperatorNetworkReceiver[] calldata operatorNetworkReceivers + ) public { + vm.startBroadcast(); + + address burnerRouter = IBurnerRouterFactory(burnerRouterFactory).create( + IBurnerRouter.InitParams({ + owner: owner, + collateral: collateral, + delay: delay, + globalReceiver: globalReceiver, + networkReceivers: networkReceivers, + operatorNetworkReceivers: operatorNetworkReceivers + }) + ); + + console2.log("Burner Router: ", burnerRouter); + + vm.stopBroadcast(); + } +} diff --git a/script/deploy/BurnerRouterFactory.s.sol b/script/deploy/BurnerRouterFactory.s.sol new file mode 100644 index 0000000..14922a1 --- /dev/null +++ b/script/deploy/BurnerRouterFactory.s.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.25; + +import {Script, console2} from "forge-std/Script.sol"; + +import {BurnerRouterFactory} from "../../src/contracts/router/BurnerRouterFactory.sol"; +import {BurnerRouter} from "../../src/contracts/router/BurnerRouter.sol"; + +contract BurnerRouterFactoryScript is Script { + function run() public { + vm.startBroadcast(); + + address burnerRouterImplementation = address(new BurnerRouter()); + address burnerRouterFactory = address(new BurnerRouterFactory(burnerRouterImplementation)); + + console2.log("Burner Router Factory: ", burnerRouterFactory); + + vm.stopBroadcast(); + } +} diff --git a/script/deploy/Burners.s.sol b/script/deploy/Burners.s.sol new file mode 100644 index 0000000..7113dc4 --- /dev/null +++ b/script/deploy/Burners.s.sol @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.25; + +import {Script, console2} from "forge-std/Script.sol"; + +import {BurnerRouterFactory} from "../../src/contracts/router/BurnerRouterFactory.sol"; +import {BurnerRouter} from "../../src/contracts/router/BurnerRouter.sol"; + +import {wstETH_Burner} from "../../src/contracts/burners/wstETH_Burner.sol"; +import {rETH_Burner} from "../../src/contracts/burners/rETH_Burner.sol"; +import {mETH_Burner} from "../../src/contracts/burners/mETH_Burner.sol"; +import {swETH_Burner} from "../../src/contracts/burners/swETH_Burner.sol"; +import {sfrxETH_Burner} from "../../src/contracts/burners/sfrxETH_Burner.sol"; +import {ETHx_Burner} from "../../src/contracts/burners/ETHx_Burner.sol"; + +contract BurnersScript is Script { + function run() public { + vm.startBroadcast(); + + address burnerRouterFactory; + { + address burnerRouterImplementation = address(new BurnerRouter()); + burnerRouterFactory = address(new BurnerRouterFactory(burnerRouterImplementation)); + } + + bool deploy_wstETH_Burner = block.chainid == 1 || block.chainid == 17_000 || block.chainid == 11_155_111; + address wstETH_BurnerAddress; + if (deploy_wstETH_Burner) { + address collateral; + address lidoWithdrawalQueue; + if (block.chainid == 1) { + // mainnet + collateral = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0; + lidoWithdrawalQueue = 0x889edC2eDab5f40e902b864aD4d7AdE8E412F9B1; + } else if (block.chainid == 17_000) { + // holesky + collateral = 0x8d09a4502Cc8Cf1547aD300E066060D043f6982D; + lidoWithdrawalQueue = 0xc7cc160b58F8Bb0baC94b80847E2CF2800565C50; + } else if (block.chainid == 11_155_111) { + // sepolia + collateral = 0xB82381A3fBD3FaFA77B3a7bE693342618240067b; + lidoWithdrawalQueue = 0x1583C7b3f4C3B008720E6BcE5726336b0aB25fdd; + } + + wstETH_BurnerAddress = address(new wstETH_Burner(collateral, lidoWithdrawalQueue)); + } + + bool deploy_rETH_Burner = block.chainid == 1 || block.chainid == 17_000; + address rETH_BurnerAddress; + if (deploy_rETH_Burner) { + address collateral; + if (block.chainid == 1) { + // mainnet + collateral = 0xae78736Cd615f374D3085123A210448E74Fc6393; + } else if (block.chainid == 17_000) { + // holesky + collateral = 0x7322c24752f79c05FFD1E2a6FCB97020C1C264F1; + } + + rETH_BurnerAddress = address(new rETH_Burner(collateral)); + } + + bool deploy_mETH_Burner = block.chainid == 1 || block.chainid == 17_000 || block.chainid == 11_155_111; + address mETH_BurnerAddress; + if (deploy_mETH_Burner) { + address collateral; + if (block.chainid == 1) { + // mainnet + collateral = 0xd5F7838F5C461fefF7FE49ea5ebaF7728bB0ADfa; + } else if (block.chainid == 17_000) { + // holesky + collateral = 0xe3C063B1BEe9de02eb28352b55D49D85514C67FF; + } else if (block.chainid == 11_155_111) { + // sepolia + collateral = 0x072d71b257ECa6B60b5333626F6a55ea1B0c451c; + } + + mETH_BurnerAddress = address(new mETH_Burner(collateral)); + } + + bool deploy_swETH_Burner = block.chainid == 1; + address swETH_BurnerAddress; + if (deploy_swETH_Burner) { + address collateral; + address swEXIT; + if (block.chainid == 1) { + // mainnet + collateral = 0xf951E335afb289353dc249e82926178EaC7DEd78; + swEXIT = 0x48C11b86807627AF70a34662D4865cF854251663; + } + + swETH_BurnerAddress = address(new swETH_Burner(collateral, swEXIT)); + } + + bool deploy_sfrxETH_Burner = block.chainid == 1; + address sfrxETH_BurnerAddress; + if (deploy_sfrxETH_Burner) { + address collateral; + address fraxEtherRedemptionQueue; + if (block.chainid == 1) { + // mainnet + collateral = 0xac3E018457B222d93114458476f3E3416Abbe38F; + fraxEtherRedemptionQueue = 0x82bA8da44Cd5261762e629dd5c605b17715727bd; + } + + sfrxETH_BurnerAddress = address(new sfrxETH_Burner(collateral, fraxEtherRedemptionQueue)); + } + + bool deploy_ETHx_Burner = block.chainid == 1 || block.chainid == 17_000; + address ETHx_BurnerAddress; + if (deploy_ETHx_Burner) { + address collateral; + address staderConfig; + if (block.chainid == 1) { + // mainnet + collateral = 0xA35b1B31Ce002FBF2058D22F30f95D405200A15b; + staderConfig = 0x4ABEF2263d5A5ED582FC9A9789a41D85b68d69DB; + } else if (block.chainid == 17_000) { + // holesky + collateral = 0xB4F5fc289a778B80392b86fa70A7111E5bE0F859; + staderConfig = 0x50FD3384783EE49011E7b57d7A3430a762b3f3F2; + } + + ETHx_BurnerAddress = address(new ETHx_Burner(collateral, staderConfig)); + } + + console2.log("Burner Router Factory: ", burnerRouterFactory); + if (deploy_wstETH_Burner) { + console2.log("wstETH_Burner: ", wstETH_BurnerAddress); + } + if (deploy_rETH_Burner) { + console2.log("rETH_Burner: ", rETH_BurnerAddress); + } + if (deploy_mETH_Burner) { + console2.log("mETH_Burner: ", mETH_BurnerAddress); + } + if (deploy_swETH_Burner) { + console2.log("swETH_Burner: ", swETH_BurnerAddress); + } + if (deploy_sfrxETH_Burner) { + console2.log("sfrxETH_Burner: ", sfrxETH_BurnerAddress); + } + if (deploy_ETHx_Burner) { + console2.log("ETHx_Burner: ", ETHx_BurnerAddress); + } + + vm.stopBroadcast(); + } +} diff --git a/script/deploy/ETHx_Burner.s.sol b/script/deploy/ETHx_Burner.s.sol new file mode 100644 index 0000000..f3456a1 --- /dev/null +++ b/script/deploy/ETHx_Burner.s.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.25; + +import {Script, console2} from "forge-std/Script.sol"; + +import {ETHx_Burner} from "../../src/contracts/burners/ETHx_Burner.sol"; + +contract ETHx_BurnerScript is Script { + function run() public { + vm.startBroadcast(); + + address collateral; + address staderConfig; + if (block.chainid == 1) { + // mainnet + collateral = 0xA35b1B31Ce002FBF2058D22F30f95D405200A15b; + staderConfig = 0x4ABEF2263d5A5ED582FC9A9789a41D85b68d69DB; + } else if (block.chainid == 17_000) { + // holesky + collateral = 0xB4F5fc289a778B80392b86fa70A7111E5bE0F859; + staderConfig = 0x50FD3384783EE49011E7b57d7A3430a762b3f3F2; + } else { + revert(); + } + + address ETHx_BurnerAddress = address(new ETHx_Burner(collateral, staderConfig)); + + console2.log("ETHx_Burner: ", ETHx_BurnerAddress); + + vm.stopBroadcast(); + } +} diff --git a/script/deploy/mETH_Burner.s.sol b/script/deploy/mETH_Burner.s.sol new file mode 100644 index 0000000..376bb1d --- /dev/null +++ b/script/deploy/mETH_Burner.s.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.25; + +import {Script, console2} from "forge-std/Script.sol"; + +import {mETH_Burner} from "../../src/contracts/burners/mETH_Burner.sol"; + +contract mETH_BurnerScript is Script { + function run() public { + vm.startBroadcast(); + + address collateral; + if (block.chainid == 1) { + // mainnet + collateral = 0xd5F7838F5C461fefF7FE49ea5ebaF7728bB0ADfa; + } else if (block.chainid == 17_000) { + // holesky + collateral = 0xe3C063B1BEe9de02eb28352b55D49D85514C67FF; + } else if (block.chainid == 11_155_111) { + // sepolia + collateral = 0x072d71b257ECa6B60b5333626F6a55ea1B0c451c; + } else { + revert(); + } + + address mETH_BurnerAddress = address(new mETH_Burner(collateral)); + + console2.log("mETH_Burner: ", mETH_BurnerAddress); + + vm.stopBroadcast(); + } +} diff --git a/script/deploy/rETH_Burner.s.sol b/script/deploy/rETH_Burner.s.sol new file mode 100644 index 0000000..2fe1195 --- /dev/null +++ b/script/deploy/rETH_Burner.s.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.25; + +import {Script, console2} from "forge-std/Script.sol"; + +import {rETH_Burner} from "../../src/contracts/burners/rETH_Burner.sol"; + +contract rETH_BurnerScript is Script { + function run() public { + vm.startBroadcast(); + + address collateral; + if (block.chainid == 1) { + // mainnet + collateral = 0xae78736Cd615f374D3085123A210448E74Fc6393; + } else if (block.chainid == 17_000) { + // holesky + collateral = 0x7322c24752f79c05FFD1E2a6FCB97020C1C264F1; + } else { + revert(); + } + + address rETH_BurnerAddress = address(new rETH_Burner(collateral)); + + console2.log("rETH_Burner: ", rETH_BurnerAddress); + + vm.stopBroadcast(); + } +} diff --git a/script/deploy/sfrxETH_Burner.s.sol b/script/deploy/sfrxETH_Burner.s.sol new file mode 100644 index 0000000..03fb43b --- /dev/null +++ b/script/deploy/sfrxETH_Burner.s.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.25; + +import {Script, console2} from "forge-std/Script.sol"; + +import {sfrxETH_Burner} from "../../src/contracts/burners/sfrxETH_Burner.sol"; + +contract sfrxETH_BurnerScript is Script { + function run() public { + vm.startBroadcast(); + + address collateral; + address fraxEtherRedemptionQueue; + if (block.chainid == 1) { + // mainnet + collateral = 0xac3E018457B222d93114458476f3E3416Abbe38F; + fraxEtherRedemptionQueue = 0x82bA8da44Cd5261762e629dd5c605b17715727bd; + } else { + revert(); + } + + address sfrxETH_BurnerAddress = address(new sfrxETH_Burner(collateral, fraxEtherRedemptionQueue)); + + console2.log("sfrxETH_Burner: ", sfrxETH_BurnerAddress); + + vm.stopBroadcast(); + } +} diff --git a/script/deploy/swETH_Burner.s.sol b/script/deploy/swETH_Burner.s.sol new file mode 100644 index 0000000..7dd74e8 --- /dev/null +++ b/script/deploy/swETH_Burner.s.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.25; + +import {Script, console2} from "forge-std/Script.sol"; + +import {swETH_Burner} from "../../src/contracts/burners/swETH_Burner.sol"; + +contract swETH_BurnerScript is Script { + function run() public { + vm.startBroadcast(); + + address collateral; + address swEXIT; + if (block.chainid == 1) { + // mainnet + collateral = 0xf951E335afb289353dc249e82926178EaC7DEd78; + swEXIT = 0x48C11b86807627AF70a34662D4865cF854251663; + } else { + revert(); + } + + address swETH_BurnerAddress = address(new swETH_Burner(collateral, swEXIT)); + + console2.log("swETH_Burner: ", swETH_BurnerAddress); + + vm.stopBroadcast(); + } +} diff --git a/script/deploy/wstETH_Burner.s.sol b/script/deploy/wstETH_Burner.s.sol new file mode 100644 index 0000000..3e0e085 --- /dev/null +++ b/script/deploy/wstETH_Burner.s.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.25; + +import {Script, console2} from "forge-std/Script.sol"; + +import {wstETH_Burner} from "../../src/contracts/burners/wstETH_Burner.sol"; + +contract wstETH_BurnerScript is Script { + function run() public { + vm.startBroadcast(); + + address collateral; + address lidoWithdrawalQueue; + if (block.chainid == 1) { + // mainnet + collateral = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0; + lidoWithdrawalQueue = 0x889edC2eDab5f40e902b864aD4d7AdE8E412F9B1; + } else if (block.chainid == 17_000) { + // holesky + collateral = 0x8d09a4502Cc8Cf1547aD300E066060D043f6982D; + lidoWithdrawalQueue = 0xc7cc160b58F8Bb0baC94b80847E2CF2800565C50; + } else if (block.chainid == 11_155_111) { + // sepolia + collateral = 0xB82381A3fBD3FaFA77B3a7bE693342618240067b; + lidoWithdrawalQueue = 0x1583C7b3f4C3B008720E6BcE5726336b0aB25fdd; + } else { + revert(); + } + + address wstETH_BurnerAddress = address(new wstETH_Burner(collateral, lidoWithdrawalQueue)); + + console2.log("wstETH_Burner: ", wstETH_BurnerAddress); + + vm.stopBroadcast(); + } +} diff --git a/specs/BurnerRouter.md b/specs/BurnerRouter.md new file mode 100644 index 0000000..7e5f924 --- /dev/null +++ b/specs/BurnerRouter.md @@ -0,0 +1,43 @@ +## Burner Router + +[See the code here](../src/contracts/router/) + +The Burner Router allows redirecting the slashed collateral tokens to different addresses, which may be represented by Burners, Treasury contracts, LP lockers, etc. + +### Full Flow + +1. Setup + + - Before the Vault's creation, deploy a new Burner Router via `BurnerRouterFactory` with the same collateral address as the Vault will use + - Deploy the Vault inputting the received `BurnerRouter` address and `IBaseSlasher.BaseParams.isBurnerHook` set to `true` + +2. Slashing + + - The router is called via `onSlash()` function + - It determines the needed address for redirection and saves the redirection amount for it + +3. Trigger transfer + + - Transfers a given account's whole balance from the router to this account + +### Deploy + +```shell +source .env +``` + +#### Deploy factory + +Deployment script: [click](../script/deploy/BurnerRouterFactory.s.sol) + +```shell +forge script script/deploy/BurnerRouterFactory.s.sol:BurnerRouterFactoryScript --broadcast --rpc-url=$ETH_RPC_URL +``` + +#### Deploy entity + +Deployment script: [click](../script/deploy/BurnerRouter.s.sol) + +```shell +forge script script/deploy/BurnerRouter.s.sol:BurnerRouterScript 0x0000000000000000000000000000000000000000 0x0000000000000000000000000000000000000000 0x0000000000000000000000000000000000000000 0 0x0000000000000000000000000000000000000000 [\(0x0000000000000000000000000000000000000000,0x0000000000000000000000000000000000000000\),\(0x0000000000000000000000000000000000000000,0x0000000000000000000000000000000000000000\)] [\(0x0000000000000000000000000000000000000000,0x0000000000000000000000000000000000000000,0x0000000000000000000000000000000000000000\),\(0x0000000000000000000000000000000000000000,0x0000000000000000000000000000000000000000,0x0000000000000000000000000000000000000000\)] --sig "run(address,address,address,uint48,address,(address,address)[],(address,address,address)[])" --broadcast --rpc-url=$ETH_RPC_URL +``` diff --git a/specs/Burners.md b/specs/Burners.md index 13bd724..8c4e924 100644 --- a/specs/Burners.md +++ b/specs/Burners.md @@ -8,28 +8,6 @@ Symbiotic achieves this by separating the ability to slash assets from the under For example, if asset is ETH LST it can be used as a collateral if it's possible to create `Burner` contract that withdraw ETH from beaconchain and burn it, if asset is native e.g. governance token it also can be used as collateral since burner might be implemented as "black-hole" contract or address. -## Burner Router - -[See the code here](../src/contracts/router/) - -The Burner Router allows redirecting the slashed collateral tokens to different addresses, which may be represented by Burners, Treasury contracts, LP lockers, etc. - -### Full Flow - -1. Setup - - - Before the Vault's creation, deploy a new Burner Router via `BurnerRouterFactory` with the same collateral address as the Vault will use - - Deploy the Vault inputting the received `BurnerRouter` address and `IBaseSlasher.BaseParams.isBurnerHook` set to `true` - -2. Slashing - - - The router is called via `onSlash()` function - - It determines the needed address for redirection and saves the redirection amount for it - -3. Trigger transfer - - - Transfers a given account's whole balance from the router to this account - ## Default Burners We've implemented default Burners for the assets restaked at Symbiotic, which need "unwrapping" (and allow it in a permissionless way): @@ -51,6 +29,14 @@ An asset transfered to the [Burner](../src/contracts/burners/wstETH_Burner.sol) - Claim withdrawal request by its ID - Burn ETH by `selfdestruct()` +#### Deploy entity + +Deployment script: [click](../script/deploy/wstETH_Burner.s.sol) + +```shell +forge script script/deploy/wstETH_Burner.s.sol:wstETH_BurnerScript --broadcast --rpc-url=$ETH_RPC_URL +``` + ### rETH Burner An asset transfered to the [Burner](../src/contracts/burners/rETH_Burner.sol) - rETH @@ -62,6 +48,14 @@ An asset transfered to the [Burner](../src/contracts/burners/rETH_Burner.sol) - - Unwrap rETH into ETH via rETH contract - Burn ETH by `selfdestruct()` +#### Deploy entity + +Deployment script: [click](../script/deploy/rETH_Burner.s.sol) + +```shell +forge script script/deploy/rETH_Burner.s.sol:rETH_BurnerScript --broadcast --rpc-url=$ETH_RPC_URL +``` + ### mETH Burner An asset transfered to the [Burner](../src/contracts/burners/mETH_Burner.sol) - mETH @@ -77,6 +71,14 @@ An asset transfered to the [Burner](../src/contracts/burners/mETH_Burner.sol) - - Claim withdrawal request by its ID - Burn ETH by `selfdestruct()` +#### Deploy entity + +Deployment script: [click](../script/deploy/mETH_Burner.s.sol) + +```shell +forge script script/deploy/mETH_Burner.s.sol:mETH_BurnerScript --broadcast --rpc-url=$ETH_RPC_URL +``` + ### swETH Burner An asset transfered to the [Burner](../src/contracts/burners/swETH_Burner.sol) - swETH @@ -93,6 +95,14 @@ An asset transfered to the [Burner](../src/contracts/burners/swETH_Burner.sol) - - Claim withdrawal request by its ID - Burn ETH by `selfdestruct()` +#### Deploy entity + +Deployment script: [click](../script/deploy/swETH_Burner.s.sol) + +```shell +forge script script/deploy/swETH_Burner.s.sol:swETH_BurnerScript --broadcast --rpc-url=$ETH_RPC_URL +``` + ### sfrxETH Burner An asset transfered to the [Burner](../src/contracts/burners/sfrxETH_Burner.sol) - sfrxETH @@ -108,6 +118,14 @@ An asset transfered to the [Burner](../src/contracts/burners/sfrxETH_Burner.sol) - Claim withdrawal request by its ID - Burn ETH by `selfdestruct()` +#### Deploy entity + +Deployment script: [click](../script/deploy/sfrxETH_Burner.s.sol) + +```shell +forge script script/deploy/sfrxETH_Burner.s.sol:sfrxETH_BurnerScript --broadcast --rpc-url=$ETH_RPC_URL +``` + ### ETHx Burner An asset transfered to the [Burner](../src/contracts/burners/ETHx_Burner.sol) - ETHx @@ -123,3 +141,11 @@ An asset transfered to the [Burner](../src/contracts/burners/ETHx_Burner.sol) - - Claim withdrawal request by its ID - Burn ETH by `selfdestruct()` + +#### Deploy entity + +Deployment script: [click](../script/deploy/ETHx_Burner.s.sol) + +```shell +forge script script/deploy/ETHx_Burner.s.sol:ETHx_BurnerScript --broadcast --rpc-url=$ETH_RPC_URL +```