Skip to content

Commit 7096e9c

Browse files
authored
Core contracts using ICoreContract (#87)
* Fix getInstalledExtensions * Canon ERC20Core is ICoreContract
1 parent 3b918f5 commit 7096e9c

9 files changed

+146
-1163
lines changed

core/src/core/CoreContract.sol

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ abstract contract CoreContract is ICoreContract {
7979
returns (InstalledExtension[] memory _installedExtensions)
8080
{
8181
uint256 totalInstalled = extensionImplementation_.length;
82+
_installedExtensions = new InstalledExtension[](totalInstalled);
8283

8384
for (uint256 i = 0; i < totalInstalled; i++) {
8485
address implementation = extensionImplementation_[i];

core/src/core/token/ERC20Core.sol

+46-77
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,14 @@ import {Ownable} from "@solady/auth/Ownable.sol";
55
import {Multicallable} from "@solady/utils/Multicallable.sol";
66
import {ERC20} from "@solady/tokens/ERC20.sol";
77

8-
import {HookFlagsDirectory} from "../../hook/HookFlagsDirectory.sol";
9-
import {HookInstaller} from "../HookInstaller.sol";
8+
import {CoreContract} from "../CoreContract.sol";
109

11-
import {IERC20HookInstaller} from "../../interface/IERC20HookInstaller.sol";
1210
import {BeforeMintHookERC20} from "../../hook/BeforeMintHookERC20.sol";
1311
import {BeforeApproveHookERC20} from "../../hook/BeforeApproveHookERC20.sol";
1412
import {BeforeTransferHookERC20} from "../../hook/BeforeTransferHookERC20.sol";
1513
import {BeforeBurnHookERC20} from "../../hook/BeforeBurnHookERC20.sol";
1614

17-
contract ERC20Core is ERC20, HookInstaller, Ownable, Multicallable, IERC20HookInstaller, HookFlagsDirectory {
15+
contract ERC20Core is ERC20, CoreContract, Ownable, Multicallable {
1816
/*//////////////////////////////////////////////////////////////
1917
STORAGE
2018
//////////////////////////////////////////////////////////////*/
@@ -33,16 +31,10 @@ contract ERC20Core is ERC20, HookInstaller, Ownable, Multicallable, IERC20HookIn
3331
//////////////////////////////////////////////////////////////*/
3432

3533
/// @notice Emitted when the on initialize call fails.
36-
error ERC20CoreOnInitializeCallFailed();
37-
38-
/// @notice Emitted when a hook initialization call fails.
39-
error ERC20CoreHookInitializeCallFailed();
34+
error ERC20CoreInitCallFailed();
4035

4136
/// @notice Emitted when a hook call fails.
42-
error ERC20CoreHookCallFailed();
43-
44-
/// @notice Emitted when insufficient value is sent in the constructor.
45-
error ERC20CoreInsufficientValueInConstructor();
37+
error ERC20CoreCallbackFailed();
4638

4739
/// @notice Emitted on an attempt to mint tokens when no beforeMint hook is installed.
4840
error ERC20CoreMintDisabled();
@@ -58,23 +50,14 @@ contract ERC20Core is ERC20, HookInstaller, Ownable, Multicallable, IERC20HookIn
5850
CONSTRUCTOR
5951
//////////////////////////////////////////////////////////////*/
6052

61-
/**
62-
* @notice Initializes the ERC20 token.
63-
*
64-
* @param _name The name of the token.
65-
* @param _symbol The symbol of the token.
66-
* @param _contractURI The contract URI of the token.
67-
* @param _owner The owner of the contract.
68-
* @param _onInitializeCall Any external call to make on contract initialization.
69-
* @param _hooksToInstall Any hooks to install and initialize on contract initialization.
70-
*/
7153
constructor(
7254
string memory _name,
7355
string memory _symbol,
7456
string memory _contractURI,
7557
address _owner,
76-
OnInitializeParams memory _onInitializeCall,
77-
InstallHookParams[] memory _hooksToInstall
58+
address[] memory _extensionsToInstall,
59+
address _initCallTarget,
60+
bytes memory _initCalldata
7861
) payable {
7962
// Set contract metadata
8063
name_ = _name;
@@ -84,26 +67,15 @@ contract ERC20Core is ERC20, HookInstaller, Ownable, Multicallable, IERC20HookIn
8467
// Set contract owner
8568
_setOwner(_owner);
8669

87-
// Track native token value sent to the constructor
88-
uint256 constructorValue = msg.value;
89-
90-
// Initialize the core token
91-
if (_onInitializeCall.target != address(0)) {
92-
if (constructorValue < _onInitializeCall.value) revert ERC20CoreInsufficientValueInConstructor();
93-
constructorValue -= _onInitializeCall.value;
94-
95-
(bool success, bytes memory returndata) =
96-
_onInitializeCall.target.call{value: _onInitializeCall.value}(_onInitializeCall.data);
97-
98-
if (!success) _revert(returndata, ERC20CoreOnInitializeCallFailed.selector);
70+
// External call upon core core contract initialization.
71+
if (_initCallTarget != address(0) && _initCalldata.length > 0) {
72+
(bool success, bytes memory returndata) = _initCallTarget.call{value: msg.value}(_initCalldata);
73+
if (!success) _revert(returndata, ERC20CoreInitCallFailed.selector);
9974
}
10075

10176
// Install and initialize hooks
102-
for (uint256 i = 0; i < _hooksToInstall.length; i++) {
103-
if (constructorValue < _hooksToInstall[i].initValue) revert ERC20CoreInsufficientValueInConstructor();
104-
constructorValue -= _hooksToInstall[i].initValue;
105-
106-
_installHook(_hooksToInstall[i]);
77+
for (uint256 i = 0; i < _extensionsToInstall.length; i++) {
78+
_installExtension(_extensionsToInstall[i]);
10779
}
10880
}
10981

@@ -129,14 +101,18 @@ contract ERC20Core is ERC20, HookInstaller, Ownable, Multicallable, IERC20HookIn
129101
return contractURI_;
130102
}
131103

132-
/// @notice Returns all of the contract's hooks and their implementations.
133-
function getAllHooks() external view returns (ERC20Hooks memory hooks) {
134-
hooks = ERC20Hooks({
135-
beforeMint: getHookImplementation(BEFORE_MINT_ERC20_FLAG),
136-
beforeTransfer: getHookImplementation(BEFORE_TRANSFER_ERC20_FLAG),
137-
beforeBurn: getHookImplementation(BEFORE_BURN_ERC20_FLAG),
138-
beforeApprove: getHookImplementation(BEFORE_APPROVE_ERC20_FLAG)
139-
});
104+
function getSupportedCallbackFunctions()
105+
public
106+
pure
107+
override
108+
returns (bytes4[] memory supportedCallbackFunctions)
109+
{
110+
supportedCallbackFunctions = new bytes4[](4);
111+
112+
supportedCallbackFunctions[0] = BeforeMintHookERC20.beforeMintERC20.selector;
113+
supportedCallbackFunctions[1] = BeforeTransferHookERC20.beforeTransferERC20.selector;
114+
supportedCallbackFunctions[2] = BeforeBurnHookERC20.beforeBurnERC20.selector;
115+
supportedCallbackFunctions[3] = BeforeApproveHookERC20.beforeApproveERC20.selector;
140116
}
141117

142118
/*//////////////////////////////////////////////////////////////
@@ -223,19 +199,12 @@ contract ERC20Core is ERC20, HookInstaller, Ownable, Multicallable, IERC20HookIn
223199
INTERNAL FUNCTIONS
224200
//////////////////////////////////////////////////////////////*/
225201

226-
/// @dev Returns whether the caller can update hooks.
227-
function _canUpdateHooks(address _caller) internal view override returns (bool) {
228-
return _caller == owner();
229-
}
230-
231-
/// @dev Returns whether the caller can write to hooks.
232-
function _isAuthorizedToCallHookFallbackFunction(address _caller) internal view override returns (bool) {
233-
return _caller == owner();
202+
function _isAuthorizedToInstallExtensions(address _target) internal view override returns (bool) {
203+
return _target == owner();
234204
}
235205

236-
/// @dev Should return the supported hook flags.
237-
function _supportedHookFlags() internal view virtual override returns (uint256) {
238-
return BEFORE_MINT_ERC20_FLAG | BEFORE_TRANSFER_ERC20_FLAG | BEFORE_BURN_ERC20_FLAG | BEFORE_APPROVE_ERC20_FLAG;
206+
function _isAuthorizedToCallExtensionFunctions(address _target) internal view override returns (bool) {
207+
return _target == owner();
239208
}
240209

241210
/// @dev Sets contract URI
@@ -245,19 +214,19 @@ contract ERC20Core is ERC20, HookInstaller, Ownable, Multicallable, IERC20HookIn
245214
}
246215

247216
/*//////////////////////////////////////////////////////////////
248-
HOOKS INTERNAL FUNCTIONS
217+
CALLBACK INTERNAL FUNCTIONS
249218
//////////////////////////////////////////////////////////////*/
250219

251220
/// @dev Calls the beforeMint hook.
252221
function _beforeMint(address _to, uint256 _amount, bytes calldata _data) internal virtual {
253-
address hook = getHookImplementation(BEFORE_MINT_ERC20_FLAG);
222+
address extension = getCallbackFunctionImplementation(BeforeMintHookERC20.beforeMintERC20.selector);
254223

255-
if (hook != address(0)) {
256-
(bool success, bytes memory returndata) = hook.call{value: msg.value}(
224+
if (extension != address(0)) {
225+
(bool success, bytes memory returndata) = extension.call{value: msg.value}(
257226
abi.encodeWithSelector(BeforeMintHookERC20.beforeMintERC20.selector, _to, _amount, _data)
258227
);
259228

260-
if (!success) _revert(returndata, ERC20CoreHookCallFailed.selector);
229+
if (!success) _revert(returndata, ERC20CoreCallbackFailed.selector);
261230
} else {
262231
// Revert if beforeMint hook is not installed to disable un-permissioned minting.
263232
revert ERC20CoreMintDisabled();
@@ -266,37 +235,37 @@ contract ERC20Core is ERC20, HookInstaller, Ownable, Multicallable, IERC20HookIn
266235

267236
/// @dev Calls the beforeTransfer hook, if installed.
268237
function _beforeTransfer(address _from, address _to, uint256 _amount) internal virtual {
269-
address hook = getHookImplementation(BEFORE_TRANSFER_ERC20_FLAG);
238+
address extension = getCallbackFunctionImplementation(BeforeTransferHookERC20.beforeTransferERC20.selector);
270239

271-
if (hook != address(0)) {
272-
(bool success, bytes memory returndata) = hook.call(
240+
if (extension != address(0)) {
241+
(bool success, bytes memory returndata) = extension.call(
273242
abi.encodeWithSelector(BeforeTransferHookERC20.beforeTransferERC20.selector, _from, _to, _amount)
274243
);
275-
if (!success) _revert(returndata, ERC20CoreHookCallFailed.selector);
244+
if (!success) _revert(returndata, ERC20CoreCallbackFailed.selector);
276245
}
277246
}
278247

279248
/// @dev Calls the beforeBurn hook, if installed.
280249
function _beforeBurn(address _from, uint256 _amount, bytes calldata _data) internal virtual {
281-
address hook = getHookImplementation(BEFORE_BURN_ERC20_FLAG);
250+
address extension = getCallbackFunctionImplementation(BeforeBurnHookERC20.beforeBurnERC20.selector);
282251

283-
if (hook != address(0)) {
284-
(bool success, bytes memory returndata) = hook.call{value: msg.value}(
252+
if (extension != address(0)) {
253+
(bool success, bytes memory returndata) = extension.call{value: msg.value}(
285254
abi.encodeWithSelector(BeforeBurnHookERC20.beforeBurnERC20.selector, _from, _amount, _data)
286255
);
287-
if (!success) _revert(returndata, ERC20CoreHookCallFailed.selector);
256+
if (!success) _revert(returndata, ERC20CoreCallbackFailed.selector);
288257
}
289258
}
290259

291260
/// @dev Calls the beforeApprove hook, if installed.
292261
function _beforeApprove(address _from, address _to, uint256 _amount) internal virtual {
293-
address hook = getHookImplementation(BEFORE_APPROVE_ERC20_FLAG);
262+
address extension = getCallbackFunctionImplementation(BeforeApproveHookERC20.beforeApproveERC20.selector);
294263

295-
if (hook != address(0)) {
296-
(bool success, bytes memory returndata) = hook.call(
264+
if (extension != address(0)) {
265+
(bool success, bytes memory returndata) = extension.call(
297266
abi.encodeWithSelector(BeforeApproveHookERC20.beforeApproveERC20.selector, _from, _to, _amount)
298267
);
299-
if (!success) _revert(returndata, ERC20CoreHookCallFailed.selector);
268+
if (!success) _revert(returndata, ERC20CoreCallbackFailed.selector);
300269
}
301270
}
302271
}

0 commit comments

Comments
 (0)