-
Notifications
You must be signed in to change notification settings - Fork 22
/
Aquifer.sol
107 lines (94 loc) · 3.75 KB
/
Aquifer.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {ReentrancyGuard} from "oz/security/ReentrancyGuard.sol";
import {IAquifer} from "src/interfaces/IAquifer.sol";
import {IWell} from "src/Well.sol";
import {LibClone} from "src/libraries/LibClone.sol";
/**
* @title Aquifer
* @author Brendan, Silo Chad, Brean
* @notice Aquifer is a permissionless Well registry and factory.
* @dev Aquifer deploys Wells by cloning a pre-deployed Well implementation.
*/
contract Aquifer is IAquifer, ReentrancyGuard {
using LibClone for address;
// A mapping of Well address to the Well implementation addresses
// Mapping gets set on Well deployment
mapping(address => address) public wellImplementation;
constructor() ReentrancyGuard() {}
/**
* @dev
* Use `salt == 0` to deploy a new Well with `create`
* Use `salt > 0` to deploy a new Well with `create2`
*/
function boreWell(
address implementation,
bytes calldata immutableData,
bytes calldata initFunctionCall,
bytes32 salt
) external nonReentrant returns (address well) {
if (immutableData.length > 0) {
if (salt != bytes32(0)) {
// Encode the salt with the `msg.sender` address to prevent frontrunning attack
salt = keccak256(abi.encode(msg.sender, salt));
well = implementation.cloneDeterministic(immutableData, salt);
} else {
well = implementation.clone(immutableData);
}
} else {
if (salt != bytes32(0)) {
// Encode the salt with the `msg.sender` address to prevent frontrunning attack
salt = keccak256(abi.encode(msg.sender, salt));
well = implementation.cloneDeterministic(salt);
} else {
well = implementation.clone();
}
}
if (initFunctionCall.length > 0) {
(bool success, bytes memory returnData) = well.call(initFunctionCall);
if (!success) {
// Next 5 lines are based on https://ethereum.stackexchange.com/a/83577
if (returnData.length < 68) revert InitFailed("");
assembly {
returnData := add(returnData, 0x04)
}
revert InitFailed(abi.decode(returnData, (string)));
}
}
if (!IWell(well).isInitialized()) {
revert WellNotInitialized();
}
// The Aquifer address MUST be set, either (a) via immutable data during cloning,
// or (b) as a storage variable during an init function call. In either case,
// the address MUST match the address of the Aquifer that performed deployment.
if (IWell(well).aquifer() != address(this)) {
revert InvalidConfig();
}
// Save implementation
wellImplementation[well] = implementation;
emit BoreWell(
well,
implementation,
IWell(well).tokens(),
IWell(well).wellFunction(),
IWell(well).pumps(),
IWell(well).wellData()
);
}
function predictWellAddress(
address implementation,
bytes calldata immutableData,
bytes32 salt
) external view returns (address well) {
// Aquifer doesn't support using a salt of 0 to deploy a Well at a deterministic address.
if (salt == bytes32(0)) {
revert InvalidSalt();
}
salt = keccak256(abi.encode(msg.sender, salt));
if (immutableData.length > 0) {
well = implementation.predictDeterministicAddress(immutableData, salt, address(this));
} else {
well = implementation.predictDeterministicAddress(salt, address(this));
}
}
}