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
|
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;
import {LoveScript} from "../script/Love.s.sol";
import {Love} from "../src/Love.sol";
import {Test} from "forge-std/Test.sol";
/// @notice The token is meant to live at the same address on every EVM network,
/// so these tests pin the CREATE2 deployment path and the inputs the
/// address derives from.
contract LoveCreate2Test is Test {
bytes32 constant SALT = keccak256("LOVE");
LoveScript script;
function setUp() public {
script = new LoveScript();
// The canonical deterministic deployer, as it exists on live networks.
assertGt(CREATE2_FACTORY.code.length, 0, "create2 deployer missing");
}
function test_DeploysAtPredictedAddress() public {
address predicted = vm.computeCreate2Address(SALT, keccak256(type(Love).creationCode), CREATE2_FACTORY);
Love deployed = Love(_deploy(SALT));
assertEq(address(deployed), predicted);
assertEq(deployed.symbol(), "LOVE");
}
/// @dev What the deploy script prints must be what the chain gives back.
function test_ScriptPredictionMatchesDeployment() public {
assertEq(script.predict(SALT), _deploy(SALT));
}
function test_ScriptUsesKeccakOfLoveAsDefaultSalt() public view {
assertEq(script.DEFAULT_SALT(), SALT);
}
/// @dev Same salt, same code, same address — that is the whole point.
function test_PredictionIsChainAgnostic() public {
address onThisChain = script.predict(SALT);
vm.chainId(137);
assertEq(script.predict(SALT), onThisChain);
vm.chainId(42_161);
assertEq(script.predict(SALT), onThisChain);
}
function test_DifferentSaltsGiveDifferentAddresses() public view {
assertTrue(script.predict(SALT) != script.predict(keccak256("LOVE2")));
}
/// @dev Redeploying with the same salt must fail, not silently return the
/// existing token.
function test_RevertWhen_RedeployingWithSameSalt() public {
_deploy(SALT);
(bool ok,) = CREATE2_FACTORY.call(abi.encodePacked(SALT, type(Love).creationCode));
assertFalse(ok);
}
function testFuzz_PredictionMatchesDeployment(bytes32 salt) public {
assertEq(script.predict(salt), _deploy(salt));
}
function _deploy(bytes32 salt) internal returns (address deployed) {
(bool ok, bytes memory ret) = CREATE2_FACTORY.call(abi.encodePacked(salt, type(Love).creationCode));
require(ok, "create2 deployment failed");
// casting to 'bytes20' is safe because the deployer returns the 20-byte address, raw
// forge-lint: disable-next-line(unsafe-typecast)
deployed = address(bytes20(ret));
}
}
|