Skip to content
Closed
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
7 changes: 6 additions & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ src = 'src'
test = 'tests'
out = 'out'
libs = ['lib']
fs_permissions = [{ access = "read", path = "tests/mocks/JsonBindings.sol" }]
fs_permissions = [
{ access = "read", path = "tests/mocks/JsonBindings.sol" },
{ access = "read", path = "./config" },
{ access = "read-write", path = "./output" },
{ access = "read-write", path = "./scripts/input" }
]
solc_version = "0.8.28"
evm_version = "cancun"
optimizer = true
Expand Down
43 changes: 43 additions & 0 deletions scripts/deploy/AaveV4DeployBatch.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2025 Aave Labs
pragma solidity ^0.8.0;

import {Script} from 'forge-std/Script.sol';

import {InputUtils} from 'src/deployments/utils/InputUtils.sol';
import {DeployUtils} from 'src/deployments/utils/DeployUtils.sol';
import {Logger} from 'src/deployments/utils/Logger.sol';

import {AaveV4DeployOrchestration} from 'src/deployments/orchestration/AaveV4DeployOrchestration.sol';

contract AaveV4DeployBatchScript is Script, DeployUtils, InputUtils {
string internal constant INPUT_PATH = 'scripts/deploy/input/AaveV4DeployInput.json';
string internal constant OUTPUT_PATH = 'output/reports/deployments/AaveV4DeployBatch.json';

constructor() {}

function run() external {
Logger logger = new Logger(OUTPUT_PATH);
FullDeployInputs memory inputs = loadFullDeployInputs(INPUT_PATH);

address deployer = msg.sender;

logger.log('Starting Aave V4 Batch Deployment');

vm.startBroadcast();
AaveV4DeployOrchestration.deployAaveV4(
logger,
deployer,
inputs.admin,
inputs.nativeWrapperAddress,
inputs.hubLabels,
inputs.spokeLabels,
inputs.setRoles
);
vm.stopBroadcast();

logger.log('Batch Deployment Completed');
logger.log('Saving Logs');
logger.save();
}
}
2 changes: 1 addition & 1 deletion snapshots/Spoke.Operations.ZeroRiskPremium.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"liquidationCall (receiveShares): partial": "299821",
"liquidationCall: full": "310468",
"liquidationCall: partial": "310186",
"permitReserve + repay (multicall)": "166029",
"permitReserve + repay (multicall)": "166017",
"permitReserve + supply (multicall)": "146862",
"permitReserve + supply + enable collateral (multicall)": "160573",
"repay: full": "126094",
Expand Down
2 changes: 1 addition & 1 deletion snapshots/Spoke.Operations.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"liquidationCall (receiveShares): partial": "333384",
"liquidationCall: full": "344031",
"liquidationCall: partial": "343749",
"permitReserve + repay (multicall)": "163273",
"permitReserve + repay (multicall)": "163264",
"permitReserve + supply (multicall)": "146862",
"permitReserve + supply + enable collateral (multicall)": "160573",
"repay: full": "120256",
Expand Down
19 changes: 19 additions & 0 deletions src/deployments/batches/AaveV4AccessBatch.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2025 Aave Labs
pragma solidity ^0.8.0;

import {BatchReports} from 'src/deployments/libraries/BatchReports.sol';
import {AaveV4AccessManagerEnumerableDeployProcedure} from 'src/deployments/procedures/deploy/AaveV4AccessManagerEnumerableDeployProcedure.sol';

contract AaveV4AccessBatch is AaveV4AccessManagerEnumerableDeployProcedure {
BatchReports.AccessBatchReport internal _report;

constructor(address admin_) {
address accessManagerAddress = _deployAccessManagerEnumerable(admin_);
_report = BatchReports.AccessBatchReport({accessManagerAddress: accessManagerAddress});
}

function getReport() external view returns (BatchReports.AccessBatchReport memory) {
return _report;
}
}
28 changes: 28 additions & 0 deletions src/deployments/batches/AaveV4ConfiguratorBatch.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2025 Aave Labs
pragma solidity ^0.8.0;

import {BatchReports} from 'src/deployments/libraries/BatchReports.sol';
import {AaveV4HubConfiguratorDeployProcedure} from 'src/deployments/procedures/deploy/AaveV4HubConfiguratorDeployProcedure.sol';
import {AaveV4SpokeConfiguratorDeployProcedure} from 'src/deployments/procedures/deploy/AaveV4SpokeConfiguratorDeployProcedure.sol';

contract AaveV4ConfiguratorBatch is
AaveV4HubConfiguratorDeployProcedure,
AaveV4SpokeConfiguratorDeployProcedure
{
BatchReports.ConfiguratorBatchReport internal _report;

constructor(address admin_) {
address hubConfiguratorAddress = _deployHubConfigurator(admin_);
address spokeConfiguratorAddress = _deploySpokeConfigurator(admin_);

_report = BatchReports.ConfiguratorBatchReport({
hubConfiguratorAddress: hubConfiguratorAddress,
spokeConfiguratorAddress: spokeConfiguratorAddress
});
}

function getReport() external view returns (BatchReports.ConfiguratorBatchReport memory) {
return _report;
}
}
28 changes: 28 additions & 0 deletions src/deployments/batches/AaveV4GatewaysBatch.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2025 Aave Labs
pragma solidity ^0.8.0;

import {BatchReports} from 'src/deployments/libraries/BatchReports.sol';
import {AaveV4NativeTokenGatewayDeployProcedure} from 'src/deployments/procedures/deploy/AaveV4NativeTokenGatewayDeployProcedure.sol';
import {AaveV4SignatureGatewayDeployProcedure} from 'src/deployments/procedures/deploy/AaveV4SignatureGatewayDeployProcedure.sol';

contract AaveV4GatewaysBatch is
AaveV4NativeTokenGatewayDeployProcedure,
AaveV4SignatureGatewayDeployProcedure
{
BatchReports.GatewaysBatchReport internal _report;

constructor(address admin_, address nativeWrapper_) {
address nativeGatewayAddress = _deployNativeTokenGateway(nativeWrapper_, admin_);
address signatureGatewayAddress = _deploySignatureGateway(admin_);

_report = BatchReports.GatewaysBatchReport({
nativeGatewayAddress: nativeGatewayAddress,
signatureGatewayAddress: signatureGatewayAddress
});
}

function getReport() external view returns (BatchReports.GatewaysBatchReport memory) {
return _report;
}
}
32 changes: 32 additions & 0 deletions src/deployments/batches/AaveV4HubBatch.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2025 Aave Labs
pragma solidity ^0.8.0;

import {BatchReports} from 'src/deployments/libraries/BatchReports.sol';
import {AaveV4HubDeployProcedure} from 'src/deployments/procedures/deploy/AaveV4HubDeployProcedure.sol';
import {AaveV4InterestRateStrategyDeployProcedure} from 'src/deployments/procedures/deploy/AaveV4InterestRateStrategyDeployProcedure.sol';
import {AaveV4TreasurySpokeDeployProcedure} from 'src/deployments/procedures/deploy/AaveV4TreasurySpokeDeployProcedure.sol';

contract AaveV4HubBatch is
AaveV4HubDeployProcedure,
AaveV4InterestRateStrategyDeployProcedure,
AaveV4TreasurySpokeDeployProcedure
{
BatchReports.HubBatchReport internal _report;

constructor(address admin_, address accessManagerAddress_) {
address hubAddress = _deployHub(accessManagerAddress_);
address irStrategyAddress = _deployInterestRateStrategy(hubAddress);
address treasurySpokeAddress = _deployTreasurySpoke(admin_, hubAddress);

_report = BatchReports.HubBatchReport({
hubAddress: hubAddress,
irStrategyAddress: irStrategyAddress,
treasurySpokeAddress: treasurySpokeAddress
});
}

function getReport() external view returns (BatchReports.HubBatchReport memory) {
return _report;
}
}
56 changes: 56 additions & 0 deletions src/deployments/batches/AaveV4SpokeInstanceBatch.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2025 Aave Labs
pragma solidity ^0.8.0;

import 'forge-std/Vm.sol';

import {BatchReports} from 'src/deployments/libraries/BatchReports.sol';
import {AaveV4SpokeInstanceDeployProcedure} from 'src/deployments/procedures/deploy/AaveV4SpokeInstanceDeployProcedure.sol';
import {AaveV4TransparentUpgradeableProxyDeployProcedure} from 'src/deployments/procedures/deploy/AaveV4TransparentUpgradeableProxyDeployProcedure.sol';
import {AaveV4AaveOracleDeployProcedure} from 'src/deployments/procedures/deploy/AaveV4AaveOracleDeployProcedure.sol';

contract AaveV4SpokeInstanceBatch is
AaveV4SpokeInstanceDeployProcedure,
AaveV4TransparentUpgradeableProxyDeployProcedure,
AaveV4AaveOracleDeployProcedure
{
BatchReports.SpokeInstanceBatchReport internal _report;

constructor(
Vm vm,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vm is always constant and can be inherited from a common contract like DeployUtils

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all procedures could inherit this common contract with vm and a bool public constant IS_TEST = true to skip on contract size check

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not plan to make them inherit, but to deploy those to execute the batch, so the idea was to pass the context there directly, but we can change the behavior.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

skip on contract size check

@DhairyaSethi where were you intending this part would be checked, was there anything else IS_TEST was meant to change in this file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Compiler will check those contract size since they are located in src/.

address deployer,
address admin_,
address accessManagerAddress_,
uint8 oracleDecimals_,
string memory oracleDescription_
) {
address predictedSpokeInstanceAddress = vm.computeCreateAddress(
deployer,
vm.getNonce(deployer) + 2
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why +2 here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we compute the address for the Spoke proxy, but between the moment we compute and the actual deployment, we have 2 other deployment to be executed (Oracle & Spoke Implementation), which means 2 txs to be broadcasted, and increasing the deployed nonce twice.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm weird I am hitting the SpokeInstance address mismatch error when running this script locally, were you getting the same?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when running the script, make sure to use a Foundry account and specify the sender so msg.sender and deployer matches during the whole script, using :
--account ${ACCOUNT} --sender ${SENDER}

Copy link
Contributor

@yan-man yan-man Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm we cant use vm cheatcodes in actual deployments, so dont think we can use this approach for predicting address

was there a reason you opted not to use create2 for computing predicted address like in v3?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can, the script which deploys the contracts one by one isn't deployed onchain. only the config part for payload & config engine

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The broadcast logic needs to be reworked to ensure only the actual contracts to deploy would be broadcasted onchain, and not the helper ones.

);

address aaveOracleAddress = _deployAaveOracle(
predictedSpokeInstanceAddress,
oracleDecimals_,
oracleDescription_
);
address spokeImplementationAddress = _deploySpokeInstance(aaveOracleAddress);
address spokeProxyAddress = _proxify(
spokeImplementationAddress,
admin_,
abi.encodeWithSignature('initialize(address)', accessManagerAddress_)
);

require(spokeProxyAddress == predictedSpokeInstanceAddress, 'SpokeInstance address mismatch');

_report = BatchReports.SpokeInstanceBatchReport({
aaveOracleAddress: aaveOracleAddress,
spokeImplementationAddress: spokeImplementationAddress,
spokeProxyAddress: spokeProxyAddress
});
}

function getReport() external view returns (BatchReports.SpokeInstanceBatchReport memory) {
return _report;
}
}
28 changes: 28 additions & 0 deletions src/deployments/batches/TestTokensBatch.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2025 Aave Labs
pragma solidity ^0.8.0;

import {BatchReports} from 'src/deployments/libraries/BatchReports.sol';
import {ConfigData} from 'src/deployments/libraries/ConfigData.sol';

import {WETHDeployProcedure} from 'src/deployments/procedures/deploy/WETHDeployProcedure.sol';
import {TestnetERC20DeployProcedure} from 'src/deployments/procedures/deploy/TestnetERC20DeployProcedure.sol';

contract TestTokensBatch is WETHDeployProcedure, TestnetERC20DeployProcedure {
BatchReports.TestTokensBatchReport internal _report;

constructor(ConfigData.TestTokenInput[] memory inputs_) {
_report.tokenAddresses = new address[](inputs_.length);
_report.wethAddress = _deployWETH();

for (uint256 i; i < inputs_.length; i++) {
ConfigData.TestTokenInput memory input = inputs_[i];
address tokenAddress = _deployTestnetERC20(input.name, input.symbol, input.decimals);
_report.tokenAddresses[i] = tokenAddress;
}
}

function getReport() external view returns (BatchReports.TestTokensBatchReport memory) {
return _report;
}
}
36 changes: 36 additions & 0 deletions src/deployments/libraries/BatchReports.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2025 Aave Labs
pragma solidity ^0.8.0;

library BatchReports {
struct AccessBatchReport {
address accessManagerAddress;
}

struct ConfiguratorBatchReport {
address hubConfiguratorAddress;
address spokeConfiguratorAddress;
}

struct SpokeInstanceBatchReport {
address spokeImplementationAddress;
address spokeProxyAddress;
address aaveOracleAddress;
}

struct HubBatchReport {
address hubAddress;
address irStrategyAddress;
address treasurySpokeAddress;
}

struct GatewaysBatchReport {
address signatureGatewayAddress;
address nativeGatewayAddress;
}

struct TestTokensBatchReport {
address wethAddress;
address[] tokenAddresses;
}
}
59 changes: 59 additions & 0 deletions src/deployments/libraries/ConfigData.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2025 Aave Labs
pragma solidity ^0.8.0;

import {IHub} from 'src/hub/interfaces/IHub.sol';
import {ISpoke} from 'src/spoke/interfaces/ISpoke.sol';

library ConfigData {
struct AddAssetParams {
address hub;
address underlying;
uint8 decimals;
address feeReceiver;
uint16 liquidityFee;
address irStrategy;
bytes irData;
}

struct UpdateAssetConfigParams {
address hub;
uint256 assetId;
IHub.AssetConfig config;
bytes irData;
}

struct AddSpokeParams {
address hub;
uint256 assetId;
address spoke;
IHub.SpokeConfig config;
}

struct AddSpokeToAssetsParams {
address hub;
address spoke;
uint256[] assetIds;
IHub.SpokeConfig[] configs;
}

struct UpdateLiquidationConfigParams {
address spoke;
ISpoke.LiquidationConfig config;
}

struct AddReserveParams {
address spoke;
address hub;
uint256 assetId;
address priceSource;
ISpoke.ReserveConfig config;
ISpoke.DynamicReserveConfig dynamicConfig;
}

struct TestTokenInput {
string name;
string symbol;
uint8 decimals;
}
}
Loading
Loading