Skip to content

Commit 9f0fcbd

Browse files
Merge bb24acb into 497d18d
2 parents 497d18d + bb24acb commit 9f0fcbd

File tree

5 files changed

+344
-227
lines changed

5 files changed

+344
-227
lines changed

remappings.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
ds-test/=lib/solmate/lib/ds-test/src/
44
erc4626-tests/=lib/erc4626-tests/
55
forge-std/=lib/forge-std/src/
6-
solmate/=lib/solmate/src/
6+
@solmate/=lib/solmate/src/
77
@openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/
88
@openzeppelin-v5/=lib/openzeppelin-contracts-v5.3.0/contracts
99
@openzeppelin/=lib/openzeppelin-contracts/contracts
1010
@pcaversaccio/createx/=lib/createx/src/
11+
@solady/=lib/createx/lib/solady/src/

script/DeployFactory.s.sol

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -73,23 +73,11 @@ contract DeployFactory is Script {
7373

7474
vm.startBroadcast();
7575

76-
77-
/////// Deploy Renounced ProxyAdmin
78-
79-
console.log("Deploying vault's renounced proxy admin");
80-
81-
address renouncedProxyAdmin = address(new ProxyAdmin());
82-
83-
console.log("Renounced proxy admin deployed at: ", renouncedProxyAdmin);
84-
85-
ProxyAdmin(renouncedProxyAdmin).renounceOwnership();
86-
87-
8876
/////// Deploy aTokenVaultFactory Implementation (pass Renounced ProxyAdmin as argument)
8977

9078
console.log("Deploying aTokenVaultFactory implementation...");
9179

92-
ATokenVaultFactory factoryImplementation = new ATokenVaultFactory({proxyAdmin: renouncedProxyAdmin});
80+
ATokenVaultFactory factoryImplementation = new ATokenVaultFactory();
9381

9482
console.log("aTokenVaultFactory implementation deployed at: ", address(factoryImplementation));
9583

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.10;
4+
5+
import "forge-std/Script.sol";
6+
import {ATokenVaultFactory} from "../src/ATokenVaultFactory.sol";
7+
8+
/**
9+
* @title DeployFactoryImplementation
10+
* @author Aave Labs
11+
* @notice Script to deploy the aTokenVaultFactory contract implementation
12+
* @dev Run the script with the following command first:
13+
*
14+
* forge script script/DeployFactoryImplementation.s.sol:DeployFactoryImplementation -vvvv --rpc-url {$RPC_URL} --account ${ACCOUNT} --slow
15+
*
16+
* If succeeds, then add the --broadcast flag in order to send the transaction to the network.
17+
*/
18+
contract DeployFactoryImplementation is Script {
19+
20+
function run() external {
21+
22+
console.log("BlockNumber: ", block.number);
23+
24+
console.log("ChainId: ", block.chainid);
25+
26+
vm.startBroadcast();
27+
28+
console.log("Deploying aTokenVaultFactory implementation...");
29+
30+
ATokenVaultFactory factoryImplementation = new ATokenVaultFactory();
31+
32+
console.log("aTokenVaultFactory implementation deployed at: ", address(factoryImplementation));
33+
34+
vm.stopBroadcast();
35+
}
36+
}

src/ATokenVaultFactory.sol

Lines changed: 104 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,26 @@ pragma solidity ^0.8.10;
55

66
import {IERC20} from "@openzeppelin/interfaces/IERC20.sol";
77
import {IPoolAddressesProvider} from "@aave-v3-core/interfaces/IPoolAddressesProvider.sol";
8-
import {TransparentUpgradeableProxy} from "@openzeppelin/proxy/transparent/TransparentUpgradeableProxy.sol";
9-
import {ATokenVault} from "./ATokenVault.sol";
108
import {SafeERC20} from "@openzeppelin/token/ERC20/utils/SafeERC20.sol";
11-
import {ProxyAdmin} from "@openzeppelin/proxy/transparent/ProxyAdmin.sol";
9+
import {ATokenVaultRevenueSplitterOwner} from "./ATokenVaultRevenueSplitterOwner.sol";
10+
import {ImmutableATokenVault} from "./ImmutableATokenVault.sol";
11+
import {SSTORE2} from "@solmate/utils/SSTORE2.sol";
12+
import {Create2} from "@openzeppelin/utils/Create2.sol";
13+
import {LibZip} from "@solady/utils/LibZip.sol";
1214

1315
/**
14-
* @title ATokenVaultImplDeploymentLib
15-
* @author Aave Labs
16-
* @notice Library that handles the deployment of the ATokenVault implementation contract
17-
* @dev This library is a helper to avoid holding the ATokenVault bytecode in the factory contract avoiding exceeding
18-
* the contract size limit.
16+
* @dev Struct containing constructor parameters for vault deployment
1917
*/
20-
library ATokenVaultImplDeploymentLib {
21-
function deployVaultImpl(
22-
address underlying,
23-
uint16 referralCode,
24-
IPoolAddressesProvider poolAddressesProvider
25-
) external returns (address vault) {
26-
return address(new ATokenVault(
27-
underlying,
28-
referralCode,
29-
poolAddressesProvider
30-
));
31-
}
18+
struct VaultParams {
19+
address underlying;
20+
uint16 referralCode;
21+
IPoolAddressesProvider poolAddressesProvider;
22+
address owner;
23+
uint256 initialFee;
24+
string shareName;
25+
string shareSymbol;
26+
uint256 initialLockDeposit;
27+
ATokenVaultRevenueSplitterOwner.Recipient[] revenueRecipients;
3228
}
3329

3430
/**
@@ -39,75 +35,48 @@ library ATokenVaultImplDeploymentLib {
3935
contract ATokenVaultFactory {
4036
using SafeERC20 for IERC20;
4137

42-
/*//////////////////////////////////////////////////////////////
43-
EVENTS
44-
//////////////////////////////////////////////////////////////*/
45-
4638
/**
4739
* @dev Emitted when a new vault is deployed
48-
* @param vault The address of the deployed vault proxy
49-
* @param implementation The address of the vault implementation
40+
* @param vault The address of the deployed vault
5041
* @param underlying The underlying asset address
5142
* @param deployer The address that deployed the vault
5243
* @param params The parameters used to deploy the vault
5344
*/
5445
event VaultDeployed(
5546
address indexed vault,
56-
address indexed implementation,
5747
address indexed underlying,
5848
address deployer,
5949
VaultParams params
6050
);
6151

62-
/*//////////////////////////////////////////////////////////////
63-
CONSTANTS
64-
//////////////////////////////////////////////////////////////*/
65-
66-
/// @notice Proxy admin address for all deployed vaults, with renounced ownership.
67-
/// @dev Future version will deploy a plain immutable vault without proxy.
68-
address internal immutable RENOUNCED_PROXY_ADMIN;
69-
70-
/*//////////////////////////////////////////////////////////////
71-
STRUCTS
72-
//////////////////////////////////////////////////////////////*/
73-
7452
/**
75-
* @dev Struct containing constructor parameters for vault deployment
53+
* @dev Emitted when a new revenue splitter owner is deployed
54+
* @param revenueSplitterOwner The address of the deployed revenue splitter owner
55+
* @param vault The address of the vault to split the revenue from
56+
* @param owner The address of the owner of the revenue splitter, effective owner of the vault
57+
* @param revenueRecipients The recipients of the revenue
7658
*/
77-
struct VaultParams {
78-
address underlying;
79-
uint16 referralCode;
80-
IPoolAddressesProvider poolAddressesProvider;
81-
address owner;
82-
uint256 initialFee;
83-
string shareName;
84-
string shareSymbol;
85-
uint256 initialLockDeposit;
86-
}
59+
event RevenueSplitterOwnerDeployed(
60+
address indexed revenueSplitterOwner,
61+
address indexed vault,
62+
address indexed owner,
63+
ATokenVaultRevenueSplitterOwner.Recipient[] revenueRecipients
64+
);
8765

88-
/*//////////////////////////////////////////////////////////////
89-
CONSTRUCTOR
90-
//////////////////////////////////////////////////////////////*/
66+
address immutable public VAULT_CREATION_CODE_SSTORE2_POINTER;
9167

92-
/**
93-
* @dev Constructor
94-
* @param proxyAdmin The address that will be the admin of all deployed proxies. Must have renounced ownership.
95-
*/
96-
constructor(address proxyAdmin) {
97-
RENOUNCED_PROXY_ADMIN = proxyAdmin;
98-
require(ProxyAdmin(proxyAdmin).owner() == address(0), "PROXY_ADMIN_OWNERSHIP_NOT_RENOUNCED");
99-
}
68+
uint256 internal _nextSaltNonce;
10069

101-
/*//////////////////////////////////////////////////////////////
102-
EXTERNAL FUNCTIONS
103-
//////////////////////////////////////////////////////////////*/
70+
constructor() {
71+
VAULT_CREATION_CODE_SSTORE2_POINTER = SSTORE2.write(LibZip.flzCompress(type(ImmutableATokenVault).creationCode));
72+
}
10473

10574
/**
106-
* @notice Deploy a new ATokenVault with the given parameters
75+
* @notice Deploys a new ATokenVault with the given parameters
10776
* @param params All parameters needed for vault deployment and initialization
10877
* @return vault The address of the deployed vault proxy
10978
*/
110-
function deployVault(VaultParams memory params) public returns (address vault) {
79+
function deployVault(VaultParams memory params) public returns (address) {
11180
require(params.underlying != address(0), "ZERO_ADDRESS_NOT_VALID");
11281
require(address(params.poolAddressesProvider) != address(0), "ZERO_ADDRESS_NOT_VALID");
11382
require(params.owner != address(0), "ZERO_ADDRESS_NOT_VALID");
@@ -121,34 +90,84 @@ contract ATokenVaultFactory {
12190
params.initialLockDeposit
12291
);
12392

124-
address implementation = ATokenVaultImplDeploymentLib.deployVaultImpl(
125-
params.underlying,
126-
params.referralCode,
127-
params.poolAddressesProvider
93+
bytes32 salt = bytes32(_nextSaltNonce++);
94+
95+
bytes memory vaultInitCode = abi.encodePacked(
96+
LibZip.flzDecompress(SSTORE2.read(VAULT_CREATION_CODE_SSTORE2_POINTER)),
97+
abi.encode(
98+
params.underlying,
99+
params.referralCode,
100+
params.poolAddressesProvider,
101+
address(this),
102+
params.initialFee,
103+
params.shareName,
104+
params.shareSymbol,
105+
params.initialLockDeposit
106+
)
128107
);
129108

130-
vault = address(new TransparentUpgradeableProxy(
131-
implementation,
132-
RENOUNCED_PROXY_ADMIN,
133-
""
134-
));
109+
address vaultAddress = _computeVaultAddress(vaultInitCode, salt);
135110

136-
IERC20(params.underlying).safeApprove(vault, params.initialLockDeposit);
111+
IERC20(params.underlying).safeApprove(vaultAddress, params.initialLockDeposit);
137112

138-
ATokenVault(vault).initialize(
139-
params.owner,
140-
params.initialFee,
141-
params.shareName,
142-
params.shareSymbol,
143-
params.initialLockDeposit
144-
);
113+
_deployVault(vaultInitCode, salt);
114+
115+
address owner = params.owner;
116+
if (params.revenueRecipients.length > 0) {
117+
owner = _deployRevenueSplitterOwner(vaultAddress, params.owner, params.revenueRecipients);
118+
}
119+
ImmutableATokenVault(vaultAddress).transferOwnership(owner);
145120

146121
emit VaultDeployed(
147-
vault,
148-
implementation,
122+
vaultAddress,
149123
params.underlying,
150124
msg.sender,
151125
params
152126
);
127+
128+
return vaultAddress;
129+
}
130+
131+
/**
132+
* @notice Deploys a new ATokenVaultRevenueSplitterOwner with the given parameters
133+
* @param vaultAddress The address of the vault to split the revenue from
134+
* @param owner The address of the owner of the revenue splitter, effective owner of the vault
135+
* @param revenueRecipients The recipients of the revenue
136+
* @return revenueSplitter The address of the deployed revenue splitter
137+
*/
138+
function deployRevenueSplitterOwner(
139+
address vaultAddress,
140+
address owner,
141+
ATokenVaultRevenueSplitterOwner.Recipient[] memory revenueRecipients
142+
) external returns (address) {
143+
return _deployRevenueSplitterOwner(vaultAddress, owner, revenueRecipients);
144+
}
145+
146+
function _deployRevenueSplitterOwner(
147+
address vaultAddress,
148+
address owner,
149+
ATokenVaultRevenueSplitterOwner.Recipient[] memory revenueRecipients
150+
) internal returns (address) {
151+
address revenueSplitter = address(new ATokenVaultRevenueSplitterOwner(vaultAddress, owner, revenueRecipients));
152+
emit RevenueSplitterOwnerDeployed(revenueSplitter, vaultAddress, owner, revenueRecipients);
153+
return revenueSplitter;
154+
}
155+
156+
function _computeVaultAddress(bytes memory vaultInitCode, bytes32 salt) internal view returns (address) {
157+
return Create2.computeAddress(salt, keccak256(vaultInitCode));
158+
}
159+
160+
function _deployVault(bytes memory vaultInitCode, bytes32 salt) internal returns (address) {
161+
address vaultAddress;
162+
assembly {
163+
vaultAddress := create2(0, add(vaultInitCode, 32), mload(vaultInitCode), salt)
164+
// If the deployment fails, revert bubbling up the error
165+
if iszero(vaultAddress) {
166+
let returnDataSize := returndatasize()
167+
returndatacopy(0, 0, returnDataSize)
168+
revert(0, returnDataSize)
169+
}
170+
}
171+
return vaultAddress;
153172
}
154173
}

0 commit comments

Comments
 (0)