-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathVaultFactory.sol
90 lines (77 loc) · 3.09 KB
/
VaultFactory.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
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;
import {Create2ClonesWithImmutableArgs} from "clones-with-immutable-args/src/Create2ClonesWithImmutableArgs.sol";
import {IVaultFactory} from "./interfaces/IVaultFactory.sol";
import {Vault} from "./Vault.sol";
/// @title Vault Factory
/// @author Fractional Art
/// @notice Factory contract for deploying fractional vaults
contract VaultFactory is IVaultFactory {
/// @dev Use clones library for address types
using Create2ClonesWithImmutableArgs for address;
/// @notice Address of Vault proxy contract
address public implementation;
/// @dev Internal mapping to track the next seed to be used by an EOA
mapping(address => bytes32) internal nextSeeds;
/// @notice Initializes implementation contract
constructor() {
implementation = address(new Vault());
}
/// @notice Deploys new vault for sender
/// @return vault Address of deployed vault
function deploy() external returns (address payable vault) {
vault = deployFor(msg.sender);
}
/// @notice Gets pre-computed address of vault deployed by given account
/// @param _deployer Address of vault deployer
/// @return vault Address of next vault
function getNextAddress(address _deployer)
external
view
returns (address vault)
{
bytes32 salt = keccak256(abi.encode(_deployer, nextSeeds[_deployer]));
(uint256 creationPtr, uint256 creationSize) = implementation
.cloneCreationCode(abi.encodePacked());
bytes32 creationHash;
assembly {
creationHash := keccak256(creationPtr, creationSize)
}
bytes32 data = keccak256(
abi.encodePacked(bytes1(0xff), address(this), salt, creationHash)
);
vault = address(uint160(uint256(data)));
}
/// @notice Gets next seed value of given account
/// @param _deployer Address of vault deployer
/// @return Value of next seed
function getNextSeed(address _deployer) external view returns (bytes32) {
return nextSeeds[_deployer];
}
/// @notice Deploys new vault for given address
/// @param _owner Address of vault owner
/// @return vault Address of deployed vault
function deployFor(address _owner) public returns (address payable vault) {
bytes32 seed = nextSeeds[tx.origin];
// Prevent front-running the salt by hashing the concatenation of tx.origin and the user-provided seed.
bytes32 salt = keccak256(abi.encode(tx.origin, seed));
bytes memory data = abi.encodePacked();
vault = implementation.clone(salt, data);
Vault(vault).init();
// Transfer the ownership from this factory contract to the specified owner.
Vault(vault).transferOwnership(_owner);
// Increment the seed.
unchecked {
nextSeeds[tx.origin] = bytes32(uint256(seed) + 1);
}
// Log the vault via en event.
emit DeployVault(
tx.origin,
msg.sender,
_owner,
seed,
salt,
address(vault)
);
}
}