Skip to content

Commit 3b918f5

Browse files
authored
Hooks v extension benchmark (#85)
* Update important interfaces naming away from Hooks to Extension + Callbacks * rename fn -> function * cleanup redundancy in names * WIP no bitmasks * update interfaces: replace bitmask with bytes4[] * abstract CoreContract inherits ICoreContract * ERC20CoreContract inherits ERC20Core * Benchmark for ERC20CoreContract
1 parent a365f28 commit 3b918f5

File tree

3 files changed

+325
-14
lines changed

3 files changed

+325
-14
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.0;
3+
4+
import {Test} from "forge-std/Test.sol";
5+
6+
import {EIP1967Proxy} from "test/utils/EIP1967Proxy.sol";
7+
8+
import {IExtensionContract} from "src/interface/IExtensionContract.sol";
9+
import {CoreContract, ICoreContract} from "src/core/CoreContract.sol";
10+
11+
import {
12+
MockExtensionERC20,
13+
MockExtensionWithOneCallbackERC20,
14+
MockExtensionWithFourCallbacksERC20
15+
} from "test/mocks/MockExtension.sol";
16+
17+
import {ERC20CoreContract} from "src/core/token/ERC20CoreContract.sol";
18+
19+
contract ERC20CoreContractBenchmarkTest is Test {
20+
/*//////////////////////////////////////////////////////////////
21+
SETUP
22+
//////////////////////////////////////////////////////////////*/
23+
24+
// Participants
25+
address public platformAdmin = address(0x123);
26+
address public platformUser = address(0x456);
27+
address public claimer = 0xDDdDddDdDdddDDddDDddDDDDdDdDDdDDdDDDDDDd;
28+
29+
// Target test contracts
30+
ERC20CoreContract public erc20;
31+
address public hookProxyAddress;
32+
33+
function setUp() public {
34+
// Setup: minting on ERC-20 contract.
35+
36+
// Platform contracts: gas incurred by platform.
37+
vm.startPrank(platformAdmin);
38+
39+
hookProxyAddress = address(
40+
new EIP1967Proxy(
41+
address(new MockExtensionERC20()),
42+
abi.encodeWithSelector(
43+
MockExtensionERC20.initialize.selector,
44+
platformAdmin // upgradeAdmin
45+
)
46+
)
47+
);
48+
49+
vm.stopPrank();
50+
51+
// Developer contract: gas incurred by developer.
52+
vm.startPrank(platformUser);
53+
54+
address[] memory extensionsToInstall = new address[](0);
55+
56+
erc20 = new ERC20CoreContract(
57+
"Token",
58+
"TKN",
59+
"ipfs://QmPVMvePSWfYXTa8haCbFavYx4GM4kBPzvdgBw7PTGUByp/0",
60+
platformUser, // core contract owner,
61+
extensionsToInstall,
62+
address(0),
63+
bytes("")
64+
);
65+
66+
vm.stopPrank();
67+
68+
vm.label(address(erc20), "ERC20CoreContract");
69+
vm.label(hookProxyAddress, "MockExtensionERC20");
70+
vm.label(platformAdmin, "Admin");
71+
vm.label(platformUser, "Developer");
72+
vm.label(claimer, "Claimer");
73+
}
74+
75+
/*//////////////////////////////////////////////////////////////
76+
DEPLOY END-USER CONTRACT
77+
//////////////////////////////////////////////////////////////*/
78+
79+
function test_deployEndUserContract() public {
80+
// Deploy a minimal proxy to the ERC20CoreContract implementation contract.
81+
82+
vm.pauseGasMetering();
83+
84+
address[] memory extensionsToInstall = new address[](1);
85+
extensionsToInstall[0] = hookProxyAddress;
86+
87+
vm.resumeGasMetering();
88+
89+
ERC20CoreContract core = new ERC20CoreContract(
90+
"Token",
91+
"TKN",
92+
"ipfs://QmPVMvePSWfYXTa8haCbFavYx4GM4kBPzvdgBw7PTGUByp/0",
93+
platformUser, // core contract owner,
94+
extensionsToInstall,
95+
address(0),
96+
bytes("")
97+
);
98+
}
99+
100+
/*//////////////////////////////////////////////////////////////
101+
MINT 1 TOKEN AND 10 TOKENS
102+
//////////////////////////////////////////////////////////////*/
103+
104+
function test_mintOneToken() public {
105+
vm.pauseGasMetering();
106+
107+
vm.prank(platformUser);
108+
erc20.installExtension(hookProxyAddress, 0, "");
109+
110+
// Check pre-mint state
111+
address claimerAddress = claimer;
112+
uint256 quantity = 1 ether;
113+
ERC20CoreContract core = erc20;
114+
115+
vm.prank(claimer);
116+
117+
vm.resumeGasMetering();
118+
119+
// Claim token
120+
core.mint(claimerAddress, quantity, "");
121+
}
122+
123+
function test_mintTenTokens() public {
124+
vm.pauseGasMetering();
125+
126+
vm.prank(platformUser);
127+
erc20.installExtension(hookProxyAddress, 0, "");
128+
129+
// Check pre-mint state
130+
address claimerAddress = claimer;
131+
uint256 quantity = 10 ether;
132+
ERC20CoreContract core = erc20;
133+
134+
vm.prank(claimer);
135+
136+
vm.resumeGasMetering();
137+
138+
// Claim token
139+
core.mint(claimerAddress, quantity, "");
140+
}
141+
142+
/*//////////////////////////////////////////////////////////////
143+
TRANSFER 1 TOKEN
144+
//////////////////////////////////////////////////////////////*/
145+
146+
function test_transferOneToken() public {
147+
vm.pauseGasMetering();
148+
149+
vm.prank(platformUser);
150+
erc20.installExtension(hookProxyAddress, 0, "");
151+
152+
// Check pre-mint state
153+
address claimerAddress = claimer;
154+
uint256 quantity = 10 ether;
155+
ERC20CoreContract core = erc20;
156+
core.mint(claimerAddress, quantity, "");
157+
158+
address to = address(0x121212);
159+
vm.prank(claimer);
160+
161+
vm.resumeGasMetering();
162+
163+
// Transfer token
164+
core.transfer(to, 1);
165+
}
166+
167+
/*//////////////////////////////////////////////////////////////
168+
PERFORM A BEACON UPGRADE
169+
//////////////////////////////////////////////////////////////*/
170+
171+
function test_beaconUpgrade() public {
172+
vm.pauseGasMetering();
173+
174+
address newImpl = address(new MockExtensionERC20());
175+
address proxyAdmin = platformAdmin;
176+
MockExtensionERC20 proxy = MockExtensionERC20(payable(hookProxyAddress));
177+
178+
vm.prank(proxyAdmin);
179+
180+
vm.resumeGasMetering();
181+
182+
// Perform upgrade
183+
proxy.upgradeToAndCall(address(newImpl), bytes(""));
184+
}
185+
186+
/*//////////////////////////////////////////////////////////////
187+
ADD NEW FUNCTIONALITY AND UPDATE FUNCTIONALITY
188+
//////////////////////////////////////////////////////////////*/
189+
190+
function test_installOneHook() public {
191+
vm.pauseGasMetering();
192+
193+
address mockHook = address(new MockExtensionWithOneCallbackERC20());
194+
ERC20CoreContract hookConsumer = erc20;
195+
196+
vm.prank(platformUser);
197+
198+
vm.resumeGasMetering();
199+
200+
hookConsumer.installExtension(mockHook, 0, "");
201+
}
202+
203+
function test_installFourHooks() public {
204+
vm.pauseGasMetering();
205+
206+
address mockHook = address(new MockExtensionWithFourCallbacksERC20());
207+
ERC20CoreContract hookConsumer = erc20;
208+
209+
vm.prank(platformUser);
210+
211+
vm.resumeGasMetering();
212+
213+
hookConsumer.installExtension(mockHook, 0, "");
214+
}
215+
216+
function test_uninstallOneHook() public {
217+
vm.pauseGasMetering();
218+
219+
ERC20CoreContract hookConsumer = erc20;
220+
221+
vm.prank(platformUser);
222+
hookConsumer.installExtension(hookProxyAddress, 0, "");
223+
224+
vm.prank(platformUser);
225+
226+
vm.resumeGasMetering();
227+
228+
hookConsumer.uninstallExtension(hookProxyAddress, 0, "");
229+
}
230+
231+
function test_uninstallFourHooks() public {
232+
vm.pauseGasMetering();
233+
234+
address mockHook = address(new MockExtensionWithFourCallbacksERC20());
235+
ERC20CoreContract hookConsumer = erc20;
236+
237+
vm.prank(platformUser);
238+
hookConsumer.installExtension(mockHook, 0, "");
239+
240+
vm.prank(platformUser);
241+
242+
vm.resumeGasMetering();
243+
244+
hookConsumer.uninstallExtension(mockHook, 0, "");
245+
}
246+
}

core/test/benchmark/ERC20CoreBenchmark.t.sol

+13-14
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,6 @@ contract ERC20CoreBenchmarkTest is Test, HookFlagsDirectory {
6060
hooksToInstallOnInit
6161
);
6262

63-
// Developer installs `MockHookERC20` hook
64-
erc20.installHook(IHookInstaller.InstallHookParams(hookProxyAddress, 0, bytes("")));
65-
6663
vm.stopPrank();
6764

6865
vm.label(address(erc20), "ERC20Core");
@@ -103,6 +100,9 @@ contract ERC20CoreBenchmarkTest is Test, HookFlagsDirectory {
103100
function test_mintOneToken() public {
104101
vm.pauseGasMetering();
105102

103+
vm.prank(platformUser);
104+
erc20.installHook(IHookInstaller.InstallHookParams(hookProxyAddress, 0, bytes("")));
105+
106106
// Check pre-mint state
107107
address claimerAddress = claimer;
108108
uint256 quantity = 1 ether;
@@ -119,6 +119,9 @@ contract ERC20CoreBenchmarkTest is Test, HookFlagsDirectory {
119119
function test_mintTenTokens() public {
120120
vm.pauseGasMetering();
121121

122+
vm.prank(platformUser);
123+
erc20.installHook(IHookInstaller.InstallHookParams(hookProxyAddress, 0, bytes("")));
124+
122125
// Check pre-mint state
123126
address claimerAddress = claimer;
124127
uint256 quantity = 10 ether;
@@ -139,6 +142,9 @@ contract ERC20CoreBenchmarkTest is Test, HookFlagsDirectory {
139142
function test_transferOneToken() public {
140143
vm.pauseGasMetering();
141144

145+
vm.prank(platformUser);
146+
erc20.installHook(IHookInstaller.InstallHookParams(hookProxyAddress, 0, bytes("")));
147+
142148
// Check pre-mint state
143149
address claimerAddress = claimer;
144150
uint256 quantity = 10 ether;
@@ -183,9 +189,6 @@ contract ERC20CoreBenchmarkTest is Test, HookFlagsDirectory {
183189
IHook mockHook = IHook(address(new MockOneHookImplERC20()));
184190
ERC20Core hookConsumer = erc20;
185191

186-
vm.prank(platformUser);
187-
hookConsumer.uninstallHook(hookProxyAddress);
188-
189192
vm.prank(platformUser);
190193

191194
vm.resumeGasMetering();
@@ -199,9 +202,6 @@ contract ERC20CoreBenchmarkTest is Test, HookFlagsDirectory {
199202
IHook mockHook = IHook(address(new MockFourHookImplERC20()));
200203
ERC20Core hookConsumer = erc20;
201204

202-
vm.prank(platformUser);
203-
hookConsumer.uninstallHook(hookProxyAddress);
204-
205205
vm.prank(platformUser);
206206

207207
vm.resumeGasMetering();
@@ -212,14 +212,16 @@ contract ERC20CoreBenchmarkTest is Test, HookFlagsDirectory {
212212
function test_uninstallOneHook() public {
213213
vm.pauseGasMetering();
214214

215-
IHook mockHook = IHook(address(new MockOneHookImplERC20()));
216215
ERC20Core hookConsumer = erc20;
217216

217+
vm.prank(platformUser);
218+
erc20.installHook(IHookInstaller.InstallHookParams(hookProxyAddress, 0, bytes("")));
219+
218220
vm.prank(platformUser);
219221

220222
vm.resumeGasMetering();
221223

222-
hookConsumer.uninstallHook(address(mockHook));
224+
hookConsumer.uninstallHook(hookProxyAddress);
223225
}
224226

225227
function test_uninstallFourHooks() public {
@@ -228,9 +230,6 @@ contract ERC20CoreBenchmarkTest is Test, HookFlagsDirectory {
228230
IHook mockHook = IHook(address(new MockFourHookImplERC20()));
229231
ERC20Core hookConsumer = erc20;
230232

231-
vm.prank(platformUser);
232-
hookConsumer.uninstallHook(hookProxyAddress);
233-
234233
vm.prank(platformUser);
235234
hookConsumer.installHook(IHookInstaller.InstallHookParams(address(mockHook), 0, ""));
236235

0 commit comments

Comments
 (0)