Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ Snapshot files generated:
- `Spoke.Operations.json`: Gas for user-facing Spoke operations.
- `Spoke.Operations.ZeroRiskPremium.json`: Same scenarios as `Spoke.Operations.json` but with Collateral Risk set to 0, to show baseline gas excluding risk-premium computation.
- `Spoke.Getters.json`: Gas for getters across different combinations of supplies/borrows.
- `BabylonSpoke.Operations.json`: Same operations as `Spoke.Operations.json` on the BabylonSpoke, plus the manager-gated liquidations.
- `NativeTokenGateway.Operations.json`: Gas for native-asset (ETH) gateway flows.
- `SignatureGateway.Operations.json`: Gas for EIP-712 meta-transactions.

Expand Down
2 changes: 2 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ dynamic_test_linking = true
additional_compiler_profiles = [
{ name = "hub", optimizer = true, via_ir = true, optimizer_runs = 22_300 },
{ name = "spoke", optimizer = true, via_ir = true, optimizer_runs = 750 },
{ name = "babylon-spoke", optimizer = true, via_ir = true, optimizer_runs = 450 },
]

compilation_restrictions = [
{ paths = "src/hub/instances/HubInstance.sol", via_ir = true, optimizer_runs = 22_300 },
{ paths = "src/spoke/instances/SpokeInstance.sol", via_ir = true, optimizer_runs = 750 },
{ paths = "src/spoke/instances/BabylonSpokeInstance.sol", via_ir = true, optimizer_runs = 450 },
]

[bind_json]
Expand Down
3 changes: 2 additions & 1 deletion scripts/deploy/AaveV4DeployBatchBase.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ abstract contract AaveV4DeployBatchBaseScript is Script {
deployer,
inputs,
BytecodeHelper.getHubBytecode(),
BytecodeHelper.getSpokeBytecode()
BytecodeHelper.getSpokeBytecode(),
BytecodeHelper.getBabylonSpokeBytecode()
);
vm.stopBroadcast();
logger.writeJsonReportMarket(report);
Expand Down
2 changes: 2 additions & 0 deletions scripts/deploy/examples/AaveV4DeployAnvil.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ contract AaveV4DeployAnvil is AaveV4DeployBatchBaseScript {
hubLabels: hubLabels,
spokeLabels: spokeLabels,
spokeMaxReservesLimits: new uint16[](0),
babylonSpokeLabels: new string[](0),
babylonSpokeMaxReservesLimits: new uint16[](0),
salt: keccak256('anvil-test')
});
}
Expand Down
23 changes: 20 additions & 3 deletions scripts/utils/SpokeDeployUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,29 @@ library SpokeDeployUtils {
return Create2Utils.create2Deploy(salt, bytecode);
}

/// @notice Deploys BabylonLiquidationLogic via CREATE2.
/// @dev The CREATE2 factory must already be deployed on the target chain.
/// @param salt The CREATE2 salt for deterministic deployment.
/// @return The deployed library address.
function deployBabylonLiquidationLogic(bytes32 salt) internal returns (address) {
bytes memory bytecode = vm.getCode(
'src/spoke/libraries/BabylonLiquidationLogic.sol:BabylonLiquidationLogic'
);
return Create2Utils.create2Deploy(salt, bytecode);
}

/// @notice Returns the FOUNDRY_LIBRARIES-compatible string for library linking.
function getLibraryString(address liquidationLogic) internal pure returns (string memory) {
function getLibraryString(
address liquidationLogic,
address babylonLiquidationLogic
) internal pure returns (string memory) {
return
string(
abi.encodePacked(
'src/spoke/libraries/LiquidationLogic.sol:LiquidationLogic:',
vm.toString(liquidationLogic)
vm.toString(liquidationLogic),
',src/spoke/libraries/BabylonLiquidationLogic.sol:BabylonLiquidationLogic:',
vm.toString(babylonLiquidationLogic)
)
);
}
Expand All @@ -37,8 +53,9 @@ library SpokeDeployUtils {
/// @param salt The CREATE2 salt for deterministic deployment.
function _deployAndWriteLibrariesConfig(bytes32 salt) internal {
address liquidationLogic = deployLiquidationLogic(salt);
address babylonLiquidationLogic = deployBabylonLiquidationLogic(salt);

string memory librariesSolcString = getLibraryString(liquidationLogic);
string memory librariesSolcString = getLibraryString(liquidationLogic, babylonLiquidationLogic);

string memory sedCommand = string(
abi.encodePacked('echo FOUNDRY_LIBRARIES=', librariesSolcString, ' >> .env')
Expand Down
29 changes: 29 additions & 0 deletions snapshots/BabylonSpoke.Operations.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"borrow: first": "269707",
"borrow: second action, same reserve": "212573",
"liquidationCall (collateralCapEnforced): partial": "351737",
"liquidationCall (multiDebt): partial": "484706",
"liquidationCall (reportDeficit): full": "357973",
"liquidationCall: full": "293623",
"liquidationCall: partial": "346614",
"permitReserve + repay (multicall)": "166568",
"permitReserve + supply (multicall)": "151901",
"repay: full": "123453",
"repay: partial": "142811",
"setUserPositionManagersWithSig: disable": "46964",
"setUserPositionManagersWithSig: enable": "68852",
"supply + enable collateral (multicall)": "151263",
"supply: 0 borrows, collateral disabled": "127809",
"supply: 0 borrows, collateral enabled": "110709",
"supply: second action, same reserve": "110709",
"updateUserDynamicConfig: 1 collateral": "76439",
"updateUserRiskPremium: 1 borrow": "159056",
"updateUserRiskPremium: 2 borrows": "210722",
"usingAsCollateral: 0 borrows, disable": "41917",
"usingAsCollateral: 0 borrows, enable": "64373",
"withdraw: 0 borrows, full": "135226",
"withdraw: 0 borrows, partial": "140586",
"withdraw: 1 borrow, partial": "221676",
"withdraw: 2 borrows, partial": "270998",
"withdraw: non collateral": "111323"
}
2 changes: 1 addition & 1 deletion snapshots/Hub.Operations.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"remove: partial": "85702",
"reportDeficit": "116908",
"restore: full": "81488",
"restore: full - with transfer": "188919",
"restore: full - with transfer": "188918",
"restore: partial": "90198",
"restore: partial - with transfer": "148213",
"transferShares": "74540"
Expand Down
7 changes: 7 additions & 0 deletions src/config-engine/AaveV4ConfigEngine.sol
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ contract AaveV4ConfigEngine is IAaveV4ConfigEngine {
SpokeEngine.executeSpokeLiquidationConfigUpdates(updates);
}

/// @inheritdoc IAaveV4ConfigEngine
function executeBabylonLiquidationConfigUpdates(
BabylonLiquidationConfigUpdate[] calldata updates
) external {
SpokeEngine.executeBabylonLiquidationConfigUpdates(updates);
}

/// @inheritdoc IAaveV4ConfigEngine
function executeSpokeDynamicReserveConfigAdditions(
DynamicReserveConfigAddition[] calldata additions
Expand Down
22 changes: 22 additions & 0 deletions src/config-engine/AaveV4Payload.sol
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,17 @@ abstract contract AaveV4Payload {
}

/// @notice Returns the Spoke liquidation config updates to execute. Override to provide updates.
/// @notice Babylon liquidation config updates to execute.
/// @return An array of BabylonLiquidationConfigUpdate structs (empty by default).
function babylonLiquidationConfigUpdates()
public
view
virtual
returns (IAaveV4ConfigEngine.BabylonLiquidationConfigUpdate[] memory)
{
return new IAaveV4ConfigEngine.BabylonLiquidationConfigUpdate[](0);
}

/// @return An array of LiquidationConfigUpdate structs (empty by default).
function spokeLiquidationConfigUpdates()
public
Expand Down Expand Up @@ -348,6 +359,17 @@ abstract contract AaveV4Payload {
);
}

IAaveV4ConfigEngine.BabylonLiquidationConfigUpdate[]
memory babylonLiqConfigUpdates = babylonLiquidationConfigUpdates();
if (babylonLiqConfigUpdates.length > 0) {
_delegateCallEngine(
abi.encodeCall(
IAaveV4ConfigEngine.executeBabylonLiquidationConfigUpdates,
(babylonLiqConfigUpdates)
)
);
}

IAaveV4ConfigEngine.DynamicReserveConfigAddition[]
memory dynAdds = spokeDynamicReserveConfigAdditions();
if (dynAdds.length > 0) {
Expand Down
17 changes: 9 additions & 8 deletions src/config-engine/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,15 @@ The four groups, and the virtual functions in each, are listed below.

#### Spoke actions (`_executeSpokeActions`)

| Function | Struct | Purpose |
| -------------------------------------- | ------------------------------ | -------------------------------------------------------------------------------------- |
| `spokeReserveListings()` | `ReserveListing` | List a new reserve on a Spoke |
| `spokeReserveConfigUpdates()` | `ReserveConfigUpdate` | Update price source, collateral risk, paused, frozen, borrowable, receiveSharesEnabled |
| `spokeLiquidationConfigUpdates()` | `LiquidationConfigUpdate` | Update liquidation config |
| `spokeDynamicReserveConfigAdditions()` | `DynamicReserveConfigAddition` | Add a dynamic reserve config |
| `spokeDynamicReserveConfigUpdates()` | `DynamicReserveConfigUpdate` | Update a dynamic reserve config |
| `spokePositionManagerUpdates()` | `PositionManagerUpdate` | Activate/deactivate a PositionManager on a Spoke |
| Function | Struct | Purpose |
| -------------------------------------- | -------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `spokeReserveListings()` | `ReserveListing` | List a new reserve on a Spoke |
| `spokeReserveConfigUpdates()` | `ReserveConfigUpdate` | Update price source, collateral risk, paused, frozen, borrowable, receiveSharesEnabled |
| `spokeLiquidationConfigUpdates()` | `LiquidationConfigUpdate` | Update liquidation config |
| `babylonLiquidationConfigUpdates()` | `BabylonLiquidationConfigUpdate` | Update the liquidation manager and managed collateral reserve of a BabylonSpoke (calls the spoke directly) |
| `spokeDynamicReserveConfigAdditions()` | `DynamicReserveConfigAddition` | Add a dynamic reserve config |
| `spokeDynamicReserveConfigUpdates()` | `DynamicReserveConfigUpdate` | Update a dynamic reserve config |
| `spokePositionManagerUpdates()` | `PositionManagerUpdate` | Activate/deactivate a PositionManager on a Spoke |

#### AccessManager actions (`_executeAccessManagerActions`)

Expand Down
17 changes: 17 additions & 0 deletions src/config-engine/interfaces/IAaveV4ConfigEngine.sol
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,17 @@ interface IAaveV4ConfigEngine {
uint256 liquidationBonusFactor;
}

/// @notice Parameters for updating the Babylon liquidation config on a BabylonSpoke.
/// @dev The update is performed directly on the spoke, not through a SpokeConfigurator.
/// @dev spoke The address of the BabylonSpoke.
/// @dev liquidationManager The only address allowed to perform liquidations on the Spoke.
/// @dev managedCollateralReserveId The identifier of the only reserve usable as collateral.
struct BabylonLiquidationConfigUpdate {
address spoke;
address liquidationManager;
uint256 managedCollateralReserveId;
}

/// @notice Parameters for adding a dynamic reserve config on a Spoke.
/// @dev spokeConfigurator The SpokeConfigurator to use for this action.
/// @dev spoke The address of the Spoke.
Expand Down Expand Up @@ -392,6 +403,12 @@ interface IAaveV4ConfigEngine {
LiquidationConfigUpdate[] calldata updates
) external;

/// @notice Executes Babylon liquidation config updates on BabylonSpokes.
/// @param updates The Babylon liquidation config updates to execute.
function executeBabylonLiquidationConfigUpdates(
BabylonLiquidationConfigUpdate[] calldata updates
) external;

/// @notice Adds dynamic reserve configs on Spokes.
/// @param additions The dynamic reserve config additions to execute.
function executeSpokeDynamicReserveConfigAdditions(
Expand Down
15 changes: 15 additions & 0 deletions src/config-engine/libraries/SpokeEngine.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {SafeCast} from 'src/dependencies/openzeppelin/SafeCast.sol';
import {EngineFlags} from 'src/config-engine/libraries/EngineFlags.sol';
import {IHubBase} from 'src/hub/interfaces/IHubBase.sol';
import {ISpoke} from 'src/spoke/interfaces/ISpoke.sol';
import {IBabylonSpoke} from 'src/spoke/interfaces/IBabylonSpoke.sol';
import {IAaveV4ConfigEngine} from 'src/config-engine/interfaces/IAaveV4ConfigEngine.sol';

/// @title SpokeEngine
Expand Down Expand Up @@ -136,6 +137,20 @@ library SpokeEngine {
}
}

/// @notice Executes Babylon liquidation config updates on BabylonSpokes.
/// @param updates The Babylon liquidation config updates to execute.
function executeBabylonLiquidationConfigUpdates(
IAaveV4ConfigEngine.BabylonLiquidationConfigUpdate[] calldata updates
) external {
uint256 length = updates.length;
for (uint256 i; i < length; ++i) {
IBabylonSpoke(updates[i].spoke).updateBabylonLiquidationConfig(
updates[i].liquidationManager,
updates[i].managedCollateralReserveId
);
}
}

/// @notice Adds dynamic reserve configs on Spokes.
/// @param additions The dynamic reserve config additions to execute.
function executeSpokeDynamicReserveConfigAdditions(
Expand Down
10 changes: 7 additions & 3 deletions src/deployments/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,19 @@ The deploy script constructs a `FullDeployInputs` struct (see `src/deployments/u
make deploy-precompile
```

This deploys `LiquidationLogic` via CREATE2 and writes `FOUNDRY_LIBRARIES` to `.env` so Foundry can link `SpokeInstance` bytecode on the next compilation. See [LiquidationLogic Pre-deployment](#liquidationlogic-pre-deployment) for details.
This deploys `LiquidationLogic` and `BabylonLiquidationLogic` via CREATE2 and writes `FOUNDRY_LIBRARIES` to `.env` so Foundry can link the spoke instance bytecodes on the next compilation. See [LiquidationLogic Pre-deployment](#liquidationlogic-pre-deployment) for details.

### 3. Deploy Remaining Contracts

```bash
make deploy-contracts
```

This runs `AaveV4DeployOrchestration.deployAaveV4()`, which deploys batches in order: AccessManager → role labeling → Configurators → Configurator role setup → TreasurySpoke → Hubs → Spokes → Gateways → PositionManagers → role grants → DEFAULT_ADMIN transfer.
This runs `AaveV4DeployOrchestration.deployAaveV4()`, which deploys batches in order: AccessManager → role labeling → Configurators → Configurator role setup → TreasurySpoke → Hubs → Spokes → BabylonSpokes → Gateways → PositionManagers → role grants → DEFAULT_ADMIN transfer.

### BabylonSpoke

`BabylonSpoke` instances are deployed by the orchestration when `babylonSpokeLabels` is set, reusing the spoke deploy procedure. The spoke admin is granted the `BABYLON_SPOKE_CONFIGURATOR_ROLE`, which gates `updateBabylonLiquidationConfig` directly on the spoke.

### TokenizationSpoke

Expand All @@ -46,7 +50,7 @@ This requires a **two-step deploy** because Foundry needs to re-compile with the

**Step 1 — `LibraryPreCompile.s.sol`** (separate transaction):

1. `SpokeDeployUtils.deployLiquidationLogic()` deploys it via CREATE2 with `salt=0`
1. `SpokeDeployUtils` deploys `LiquidationLogic` and `BabylonLiquidationLogic` via CREATE2 with `salt=0`
2. Writes `FOUNDRY_LIBRARIES=src/spoke/libraries/LiquidationLogic.sol:LiquidationLogic:0x<address>` to `.env` via FFI
3. On re-run: if the library is already deployed (has code), skips. If `FOUNDRY_LIBRARIES` exists but the library isn't deployed (wrong chain/fork), deletes the stale entry and asks you to run again

Expand Down
61 changes: 61 additions & 0 deletions src/deployments/batches/AaveV4BabylonSpokeInstanceBatch.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// SPDX-License-Identifier: LicenseRef-BUSL
pragma solidity ^0.8.0;

import {BatchReports} from 'src/deployments/libraries/BatchReports.sol';
import {AaveV4AaveOracleDeployProcedure} from 'src/deployments/procedures/deploy/spoke/AaveV4AaveOracleDeployProcedure.sol';
import {AaveV4SpokeDeployProcedure} from 'src/deployments/procedures/deploy/spoke/AaveV4SpokeDeployProcedure.sol';
import {ISpoke} from 'src/spoke/interfaces/ISpoke.sol';
import {IAaveOracle} from 'src/spoke/interfaces/IAaveOracle.sol';

/// @title AaveV4BabylonSpokeInstanceBatch
/// @author Aave Labs
/// @notice Deploys a BabylonSpoke (proxy + implementation) and its AaveOracle, producing a batch report.
/// @dev Reuses the canonical Spoke deploy procedure: the BabylonSpoke instance has the identical
/// constructor and initializer.
contract AaveV4BabylonSpokeInstanceBatch is
AaveV4SpokeDeployProcedure,
AaveV4AaveOracleDeployProcedure
{
BatchReports.SpokeInstanceBatchReport internal _report;

/// @dev Constructor.
/// @param proxyAdminOwner_ The owner of the proxy admin.
/// @param authority_ The access-control authority for the BabylonSpoke.
/// @param babylonSpokeBytecode_ The creation bytecode of the BabylonSpoke implementation.
/// @param oracleDecimals_ The decimal precision for the AaveOracle.
/// @param maxUserReservesLimit_ The maximum number of reserves a user can interact with.
/// @param salt_ The CREATE2 salt for deterministic deployment.
constructor(
address proxyAdminOwner_,
address authority_,
bytes memory babylonSpokeBytecode_,
uint8 oracleDecimals_,
uint16 maxUserReservesLimit_,
bytes32 salt_
) {
address aaveOracle = _deployAaveOracle(oracleDecimals_);
(address spokeProxy, address spokeImplementation) = _deployUpgradeableSpokeInstance({
proxyAdminOwner: proxyAdminOwner_,
authority: authority_,
oracle: aaveOracle,
spokeBytecode: babylonSpokeBytecode_,
salt: salt_,
maxUserReservesLimit: maxUserReservesLimit_
});
IAaveOracle(aaveOracle).setSpoke(spokeProxy);

require(ISpoke(spokeProxy).ORACLE() == aaveOracle, 'spoke oracle mismatch');
require(IAaveOracle(aaveOracle).spoke() == spokeProxy, 'oracle spoke mismatch');

_report = BatchReports.SpokeInstanceBatchReport({
aaveOracle: aaveOracle,
spokeImplementation: spokeImplementation,
spokeProxy: spokeProxy
});
}

/// @notice Returns the batch deployment report.
function getReport() external view returns (BatchReports.SpokeInstanceBatchReport memory) {
return _report;
}
}
1 change: 1 addition & 0 deletions src/deployments/libraries/OrchestrationReports.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ library OrchestrationReports {
BatchReports.ConfiguratorBatchReport configuratorBatchReport;
BatchReports.TreasurySpokeBatchReport treasurySpokeBatchReport;
SpokeDeploymentReport[] spokeInstanceBatchReports;
SpokeDeploymentReport[] babylonSpokeInstanceBatchReports;
HubDeploymentReport[] hubInstanceBatchReports;
BatchReports.GatewaysBatchReport gatewaysBatchReport;
BatchReports.PositionManagerBatchReport positionManagerBatchReport;
Expand Down
Loading
Loading