-
Notifications
You must be signed in to change notification settings - Fork 24
/
Copy pathClonable.sol
111 lines (98 loc) · 3.79 KB
/
Clonable.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
108
109
110
111
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.9.0;
import "./Initializable.sol";
abstract contract Clonable
is
Initializable
{
address immutable internal _SELF = address(this);
event Cloned(address indexed by, address indexed self, address indexed clone);
modifier onlyDelegateCalls virtual {
require(address(this) != _SELF, "Clonable: not a delegate call");
_;
}
modifier wasInitialized {
require(initialized(), "Clonable: not initialized");
_;
}
/// @notice Tells whether this contract is a clone of `self()`
function cloned()
public view
returns (bool)
{
return (
address(this) != self()
);
}
/// @notice Tells whether this instance has been initialized.
function initialized() virtual public view returns (bool);
/// @notice Contract address to which clones will be re-directed.
function self() virtual public view returns (address) {
return _SELF;
}
/// Deploys and returns the address of a minimal proxy clone that replicates contract
/// behaviour while using its own EVM storage.
/// @dev This function should always provide a new address, no matter how many times
/// @dev is actually called from the same `msg.sender`.
/// @dev See https://eips.ethereum.org/EIPS/eip-1167.
/// @dev See https://blog.openzeppelin.com/deep-dive-into-the-minimal-proxy-contract/.
function _clone()
internal
returns (address _instance)
{
bytes memory ptr = _cloneBytecodePtr();
assembly {
// CREATE new instance:
_instance := create(0, ptr, 0x37)
}
require(_instance != address(0), "Clonable: CREATE failed");
emit Cloned(msg.sender, self(), _instance);
}
/// @notice Returns minimal proxy's deploy bytecode.
function _cloneBytecode()
virtual internal view
returns (bytes memory)
{
return abi.encodePacked(
hex"3d602d80600a3d3981f3363d3d373d3d3d363d73",
bytes20(self()),
hex"5af43d82803e903d91602b57fd5bf3"
);
}
/// @notice Returns mem pointer to minimal proxy's deploy bytecode.
function _cloneBytecodePtr()
virtual internal view
returns (bytes memory ptr)
{
address _base = self();
assembly {
// ptr to free mem:
ptr := mload(0x40)
// begin minimal proxy construction bytecode:
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
// make minimal proxy delegate all calls to `self()`:
mstore(add(ptr, 0x14), shl(0x60, _base))
// end minimal proxy construction bytecode:
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
}
}
/// Deploys and returns the address of a minimal proxy clone that replicates contract
/// behaviour while using its own EVM storage.
/// @dev This function uses the CREATE2 opcode and a `_salt` to deterministically deploy
/// @dev the clone. Using the same `_salt` multiple times will revert, since
/// @dev no contract can be deployed more than once at the same address.
/// @dev See https://eips.ethereum.org/EIPS/eip-1167.
/// @dev See https://blog.openzeppelin.com/deep-dive-into-the-minimal-proxy-contract/.
function _cloneDeterministic(bytes32 _salt)
virtual internal
returns (address _instance)
{
bytes memory ptr = _cloneBytecodePtr();
assembly {
// CREATE2 new instance:
_instance := create2(0, ptr, 0x37, _salt)
}
require(_instance != address(0), "Clonable: CREATE2 failed");
emit Cloned(msg.sender, self(), _instance);
}
}