@piplabs/story-contracts 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of @piplabs/story-contracts might be problematic. Click here for more details.

@@ -0,0 +1,98 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity 0.8.23;
3
+
4
+ import { Ownable2StepUpgradeable } from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
5
+ import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
6
+ import { MulticallUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/MulticallUpgradeable.sol";
7
+ import { Secp256k1Verifier } from "./Secp256k1Verifier.sol";
8
+ import { IUBIPool } from "../interfaces/IUBIPool.sol";
9
+
10
+ /// @title UBIPool
11
+ /// @notice Contract for distributing UBI to validators
12
+ /// UBI comes from a percentage of the protocol's emmission during a defined period
13
+ /// This % is minted to the UBIPool contract and can be claimed by validators
14
+ /// Each validator can claim their UBI for a given month
15
+ /// Distributions will be made public monthly by Story for community scrutiny,
16
+ /// and if correct, will be distributed to validators via this contract
17
+ contract UBIPool is
18
+ IUBIPool,
19
+ Ownable2StepUpgradeable,
20
+ ReentrancyGuardUpgradeable,
21
+ Secp256k1Verifier,
22
+ MulticallUpgradeable
23
+ {
24
+ /// @notice The maximum UBI percentage
25
+ uint32 public immutable MAX_UBI_PERCENTAGE;
26
+
27
+ /// @notice The current distribution id, incremented for each new distribution
28
+ uint256 public currentDistributionId;
29
+
30
+ /// @notice The amount of UBI for each validator for a given distribution
31
+ mapping(uint256 distributionId => mapping(bytes validatorCmpPubkey => uint256 amount)) public validatorUBIAmounts;
32
+
33
+ /// @notice The total amount of pending tokens to claim.
34
+ /// Added when a distribution is set, and subtracted when a validator claims their UBI.
35
+ uint256 public totalPendingClaims;
36
+
37
+ constructor(uint32 maxUBIPercentage) {
38
+ MAX_UBI_PERCENTAGE = maxUBIPercentage;
39
+ _disableInitializers();
40
+ }
41
+
42
+ /// @notice Initializes the contract.
43
+ /// @param owner The owner of the contract
44
+ function initialize(address owner) public initializer {
45
+ require(owner != address(0), "UBIPool: owner cannot be zero address");
46
+ __Ownable_init(owner);
47
+ }
48
+
49
+ /// @notice Sets the UBI percentage distribution in CL
50
+ /// @param percentage The percentage of the UBI
51
+ function setUBIPercentage(uint32 percentage) external onlyOwner {
52
+ require(percentage <= MAX_UBI_PERCENTAGE, "UBIPool: percentage too high");
53
+ emit UBIPercentageSet(percentage);
54
+ }
55
+
56
+ /// @notice Sets the UBI distribution for a given month
57
+ /// @param totalUBI The total amount of UBI
58
+ /// @param validatorCmpPubKeys The validator compressed public keys
59
+ /// @param amounts The amounts of UBI for each validator
60
+ /// @return distributionId The distribution id
61
+ function setUBIDistribution(
62
+ uint256 totalUBI,
63
+ bytes[] calldata validatorCmpPubKeys,
64
+ uint256[] calldata amounts
65
+ ) external onlyOwner returns (uint256) {
66
+ require(validatorCmpPubKeys.length > 0, "UBIPool: validatorCmpPubKeys cannot be empty");
67
+ require(validatorCmpPubKeys.length == amounts.length, "UBIPool: length mismatch");
68
+ require(totalUBI + totalPendingClaims <= address(this).balance, "UBIPool: not enough balance");
69
+ totalPendingClaims += totalUBI;
70
+ uint256 accAmount;
71
+ currentDistributionId++;
72
+ for (uint256 i = 0; i < amounts.length; i++) {
73
+ require(amounts[i] > 0, "UBIPool: amounts cannot be zero");
74
+ _verifyCmpPubkey(validatorCmpPubKeys[i]);
75
+ validatorUBIAmounts[currentDistributionId][validatorCmpPubKeys[i]] = amounts[i];
76
+ accAmount += amounts[i];
77
+ }
78
+ require(accAmount == totalUBI, "UBIPool: total amount mismatch");
79
+ emit UBIDistributionSet(currentDistributionId, totalUBI, validatorCmpPubKeys, amounts);
80
+ return currentDistributionId;
81
+ }
82
+
83
+ /// @notice Claims the UBI for a given month for a validator
84
+ /// @dev The validator address must be the one who is set to receive the UBI
85
+ /// @param distributionId The distribution id
86
+ /// @param validatorCmpPubkey The validator compressed public key
87
+ function claimUBI(
88
+ uint256 distributionId,
89
+ bytes calldata validatorCmpPubkey
90
+ ) external nonReentrant verifyCmpPubkeyWithExpectedAddress(validatorCmpPubkey, msg.sender) {
91
+ uint256 amount = validatorUBIAmounts[distributionId][validatorCmpPubkey];
92
+ require(amount > 0, "UBIPool: no UBI to claim");
93
+ validatorUBIAmounts[distributionId][validatorCmpPubkey] = 0;
94
+ (bool success, ) = msg.sender.call{ value: amount }("");
95
+ require(success, "UBIPool: failed to send UBI");
96
+ totalPendingClaims -= amount;
97
+ }
98
+ }
@@ -0,0 +1,40 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity 0.8.23;
3
+
4
+ import { Ownable2StepUpgradeable } from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
5
+
6
+ import { IUpgradeEntrypoint } from "../interfaces/IUpgradeEntrypoint.sol";
7
+
8
+ /**
9
+ * @title UpgradeEntrypoint
10
+ * @notice Entrypoint contract for submitting x/upgrade module actions.
11
+ */
12
+ contract UpgradeEntrypoint is IUpgradeEntrypoint, Ownable2StepUpgradeable {
13
+ constructor() {
14
+ _disableInitializers();
15
+ }
16
+
17
+ /// @notice Initializes the contract.
18
+ function initialize(address owner) public initializer {
19
+ require(owner != address(0), "UpgradeEntrypoint: owner cannot be zero address");
20
+ __Ownable_init(owner);
21
+ }
22
+
23
+ /// @notice Submits an upgrade plan.
24
+ /// @param name Sets the name for the upgrade. This name will be used by the upgraded version of the software to
25
+ /// apply any special "on-upgrade" commands during the first BeginBlock method after the upgrade is applied. It is
26
+ /// also used to detect whether a software version can handle a given upgrade. If no upgrade handler with this name
27
+ /// has been set in the software, it will be assumed that the software is out-of-date when the upgrade Time or
28
+ /// Height is reached and the software will exit.
29
+ /// @param height The height at which the upgrade must be performed.
30
+ /// @param info Any application specific upgrade info to be included on-chain such as a git commit that validators
31
+ /// could automatically upgrade to.
32
+ function planUpgrade(string calldata name, int64 height, string calldata info) external onlyOwner {
33
+ emit SoftwareUpgrade({ name: name, height: height, info: info });
34
+ }
35
+
36
+ /// @notice Cancels an upgrade plan if there is one planned. Otherwise, it does nothing.
37
+ function cancelUpgrade() external onlyOwner {
38
+ emit CancelUpgrade();
39
+ }
40
+ }
@@ -0,0 +1,90 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity 0.8.23;
3
+
4
+ import { ERC20 } from "solady/src/tokens/ERC20.sol";
5
+ /// @notice Wrapped IP implementation.
6
+ /// @author Inspired by WETH9 (https://github.com/dapphub/ds-weth/blob/master/src/weth9.sol)
7
+ contract WIP is ERC20 {
8
+ /// @notice emitted when IP is deposited in exchange for WIP
9
+ event Deposit(address indexed from, uint amount);
10
+ /// @notice emitted when WIP is withdrawn in exchange for IP
11
+ event Withdrawal(address indexed to, uint amount);
12
+ /// @notice emitted when a transfer of IP fails
13
+ error IPTransferFailed();
14
+ /// @notice emitted when an invalid transfer recipient is detected
15
+ error ERC20InvalidReceiver(address receiver);
16
+ /// @notice emitted when an invalid transfer spender is detected
17
+ error ERC20InvalidSpender(address spender);
18
+
19
+ /// @notice triggered when IP is deposited in exchange for WIP
20
+ receive() external payable {
21
+ deposit();
22
+ }
23
+
24
+ /// @notice deposits IP in exchange for WIP
25
+ /// @dev the amount of IP deposited is equal to the amount of WIP minted
26
+ function deposit() public payable {
27
+ _mint(msg.sender, msg.value);
28
+ emit Deposit(msg.sender, msg.value);
29
+ }
30
+
31
+ /// @notice withdraws WIP in exchange for IP
32
+ /// @dev the amount of IP minted is equal to the amount of WIP burned
33
+ /// @param value the amount of WIP to burn and withdraw
34
+ function withdraw(uint value) external {
35
+ _burn(msg.sender, value);
36
+ (bool success, ) = msg.sender.call{ value: value }("");
37
+ if (!success) {
38
+ revert IPTransferFailed();
39
+ }
40
+ emit Withdrawal(msg.sender, value);
41
+ }
42
+
43
+ /// @notice returns the name of the token
44
+ function name() public pure override returns (string memory) {
45
+ return "Wrapped IP";
46
+ }
47
+
48
+ /// @notice returns the symbol of the token
49
+ function symbol() public pure override returns (string memory) {
50
+ return "WIP";
51
+ }
52
+
53
+ /// @notice approves `spender` to spend `amount` of WIP
54
+ function approve(address spender, uint256 amount) public override returns (bool) {
55
+ if (spender == msg.sender) {
56
+ revert ERC20InvalidSpender(msg.sender);
57
+ }
58
+
59
+ return super.approve(spender, amount);
60
+ }
61
+
62
+ /// @notice transfers `amount` of WIP to a recipient `to`
63
+ function transfer(address to, uint256 amount) public override returns (bool) {
64
+ if (to == address(0)) {
65
+ revert ERC20InvalidReceiver(address(0));
66
+ }
67
+ if (to == address(this)) {
68
+ revert ERC20InvalidReceiver(address(this));
69
+ }
70
+
71
+ return super.transfer(to, amount);
72
+ }
73
+
74
+ /// @notice transfers `amount` of WIP from `from` to a recipient `to`
75
+ function transferFrom(address from, address to, uint256 amount) public override returns (bool) {
76
+ if (to == address(0)) {
77
+ revert ERC20InvalidReceiver(address(0));
78
+ }
79
+ if (to == address(this)) {
80
+ revert ERC20InvalidReceiver(address(this));
81
+ }
82
+
83
+ return super.transferFrom(from, to, amount);
84
+ }
85
+
86
+ /// @dev Sets Permit2 contract's allowance to infinity.
87
+ function _givePermit2InfiniteAllowance() internal pure override returns (bool) {
88
+ return true;
89
+ }
90
+ }
@@ -0,0 +1,122 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity 0.8.23;
3
+
4
+ /* solhint-disable max-line-length */
5
+
6
+ contract ValidatorData {
7
+ struct ValidatorInfo {
8
+ bytes uncompressedHex;
9
+ bytes compressedHex;
10
+ address evmAddress;
11
+ }
12
+
13
+ ValidatorInfo[] validators;
14
+
15
+ constructor() {
16
+ validators.push(
17
+ ValidatorInfo({
18
+ uncompressedHex: hex"0481513466154dfc0e702d8325d7a45284bc395f60b813230da299fab640c1eb085a6e35cb30d41af355e4701f455447a675c497f98d38e783ba3f91bf75595a8f", // pragma: allowlist secret
19
+ compressedHex: hex"0381513466154dfc0e702d8325d7a45284bc395f60b813230da299fab640c1eb08", // pragma: allowlist secret
20
+ evmAddress: 0xb5cb887155446f69b5e4D11C30755108AC87e9cD
21
+ })
22
+ );
23
+ validators.push(
24
+ ValidatorInfo({
25
+ uncompressedHex: hex"04dd68a0a4923a1b9321d39f01425f7b631066514cb2e5e1b5ed91e5c327d30c534b55b55f63ca2ba7335f8086b955d93c25225986d8d8992675ce526fe720ecf1", // pragma: allowlist secret
26
+ compressedHex: hex"03dd68a0a4923a1b9321d39f01425f7b631066514cb2e5e1b5ed91e5c327d30c53", // pragma: allowlist secret
27
+ evmAddress: 0xf89D606F67a267E9dbCc813c8169988aB8aAeB5E
28
+ })
29
+ );
30
+ validators.push(
31
+ ValidatorInfo({
32
+ uncompressedHex: hex"04b95e0ff2299de8215fda840dcf37c9398296b0000773a7cf96e6814b979806acce72cb5239fd06f3d86c5ed409b3b5844182ceabb696835a9f9f2a9392ed2add", // pragma: allowlist secret
33
+ compressedHex: hex"03b95e0ff2299de8215fda840dcf37c9398296b0000773a7cf96e6814b979806ac", // pragma: allowlist secret
34
+ evmAddress: 0x7D42B46Cc15bC492C928950acD34E3A474305B8c
35
+ })
36
+ );
37
+ validators.push(
38
+ ValidatorInfo({
39
+ uncompressedHex: hex"04a5e10cd81da0bfe7644673fb349dea42d6b058b126a6dc81526561cc9d1680aae5b7adfaccba3c3c48d2b2ed637e6bc4eaca65da45b4ac57278c16daccf2dbbe", // pragma: allowlist secret
40
+ compressedHex: hex"02a5e10cd81da0bfe7644673fb349dea42d6b058b126a6dc81526561cc9d1680aa", // pragma: allowlist secret
41
+ evmAddress: 0xED0A0fb9d98a8C1d4D6E4A47241B79eEE982A42c
42
+ })
43
+ );
44
+ validators.push(
45
+ ValidatorInfo({
46
+ uncompressedHex: hex"04e40b0d98016dd26fdb19f446bc04739b3728f9e35ebf75b13584d745c9f360bc9adf8910018442f12fda19a323e321c6f7f68e68d13e27fb39edf667255a3efc", // pragma: allowlist secret
47
+ compressedHex: hex"02e40b0d98016dd26fdb19f446bc04739b3728f9e35ebf75b13584d745c9f360bc", // pragma: allowlist secret
48
+ evmAddress: 0x47F4fdC22191BB622a9Ea2645E684e12715D2512
49
+ })
50
+ );
51
+ validators.push(
52
+ ValidatorInfo({
53
+ uncompressedHex: hex"048400994469b03d92a8c81949125c799a6d3ef26e4c16e200aec20a3f9fdd6a00ac491c3192fe316d71d866ed102c59c4fc0073f06226202e34e88ccec9bb8f9d", // pragma: allowlist secret
54
+ compressedHex: hex"038400994469b03d92a8c81949125c799a6d3ef26e4c16e200aec20a3f9fdd6a00", // pragma: allowlist secret
55
+ evmAddress: 0x9f6f533a1620f5c66539dF2dF3a2Ff3E93a36830
56
+ })
57
+ );
58
+ validators.push(
59
+ ValidatorInfo({
60
+ uncompressedHex: hex"049d511cb4290718656a8eab48475d6127fc33acfc3e6f0415f5c4642d7766db554faef7531f593eff2c1c0eeb29881c094055a91a158526484a95c2f08e598d83", // pragma: allowlist secret
61
+ compressedHex: hex"039d511cb4290718656a8eab48475d6127fc33acfc3e6f0415f5c4642d7766db55", // pragma: allowlist secret
62
+ evmAddress: 0x54DA9dC7A141E86f6D5b8bb3Bd770f8d6F606DA7
63
+ })
64
+ );
65
+ validators.push(
66
+ ValidatorInfo({
67
+ uncompressedHex: hex"046d6057a9982310f0d907edc08079912e09ca4dc843c80b26c1107262f11e1580b81db4439e93324309271730135a885d90b01e3a134da12bed39868cb4e9f94a", // pragma: allowlist secret
68
+ compressedHex: hex"026d6057a9982310f0d907edc08079912e09ca4dc843c80b26c1107262f11e1580", // pragma: allowlist secret
69
+ evmAddress: 0x53b9e8B9C04a6f6d4ae7BdAC759dE986083e7F0f
70
+ })
71
+ );
72
+ validators.push(
73
+ ValidatorInfo({
74
+ uncompressedHex: hex"04bfaa0a7de99fcca7702e00abff8bc9be4191bdd3b91d6900c4076c4bfdeb21f65793df6d75f88a7f5db5af53384c23c8f65d1406e251df74e72b18913ef48594", // pragma: allowlist secret
75
+ compressedHex: hex"02bfaa0a7de99fcca7702e00abff8bc9be4191bdd3b91d6900c4076c4bfdeb21f6", // pragma: allowlist secret
76
+ evmAddress: 0x82512864E8FECD296D228804F916601e925c97a3
77
+ })
78
+ );
79
+ validators.push(
80
+ ValidatorInfo({
81
+ uncompressedHex: hex"04761e5750ce3dd0cdca272572746151200a6216413f3a59681751d04ad4aeb46f78251d54d47dba45624d484d9c002ad007fa62180159bf0dfed6460a5a649765", // pragma: allowlist secret
82
+ compressedHex: hex"03761e5750ce3dd0cdca272572746151200a6216413f3a59681751d04ad4aeb46f", // pragma: allowlist secret
83
+ evmAddress: 0x89B59cDb363602006dA41f2e22DB180c08f08a8c
84
+ })
85
+ );
86
+ validators.push(
87
+ ValidatorInfo({
88
+ uncompressedHex: hex"048f9ea6b774a6bb7b776f0d8a10a12d611118de57ed308bb14291668a4815f716976758014910c6e3f518aba17e11d7ee9cca8b91898ae991478557a08791d50f", // pragma: allowlist secret
89
+ compressedHex: hex"038f9ea6b774a6bb7b776f0d8a10a12d611118de57ed308bb14291668a4815f716", // pragma: allowlist secret
90
+ evmAddress: 0xedfe6037703C34cfF2caA52Dc36aD008cF494a8B
91
+ })
92
+ );
93
+ validators.push(
94
+ ValidatorInfo({
95
+ uncompressedHex: hex"04c4c09d9163b8a9fe1e64b94e203a632933ed5eecd8bd148c51d665fd75ff2d4afe8b1b2e58b5e5dacfc16b9ad233b9c7c172b35c7925b2ce58e21f9614e7ee06", // pragma: allowlist secret
96
+ compressedHex: hex"02c4c09d9163b8a9fe1e64b94e203a632933ed5eecd8bd148c51d665fd75ff2d4a", // pragma: allowlist secret
97
+ evmAddress: 0xa9C9cb27A16a2adE746fC88D92AE9Bac210d1D87
98
+ })
99
+ );
100
+ validators.push(
101
+ ValidatorInfo({
102
+ uncompressedHex: hex"0479c448c6da7a8d5ee2eaa30318d4f5f9e7bde1d804d966d306cbc88e0e85bc0020a6f288651f51abf5caa47e7934de9f0e6dee0888ecb2624c054c4aef5079bf", // pragma: allowlist secret
103
+ compressedHex: hex"0379c448c6da7a8d5ee2eaa30318d4f5f9e7bde1d804d966d306cbc88e0e85bc00", // pragma: allowlist secret
104
+ evmAddress: 0x3AcB94A61A9AC3024e1302b8910f4fA1e647866C
105
+ })
106
+ );
107
+ validators.push(
108
+ ValidatorInfo({
109
+ uncompressedHex: hex"0472ec9c47ae07959c59c92b83b03bd1cf393973a4ff9cafedb77e62be405c26d011d660c5caf70e06dbd4f015449ae3518fb99df1c11dc21ebedadc0170c3940f", // pragma: allowlist secret
110
+ compressedHex: hex"0372ec9c47ae07959c59c92b83b03bd1cf393973a4ff9cafedb77e62be405c26d0", // pragma: allowlist secret
111
+ evmAddress: 0x6c18582A638d0DFc4f7da3a4ED9f73FD10EFD5bd
112
+ })
113
+ );
114
+ validators.push(
115
+ ValidatorInfo({
116
+ uncompressedHex: hex"04ce0f23517b664591d061a3a3b5af80c3c887abbbbe54f47e3946f3f6405910a62a7b1ee97a6ea45c66aae8263ece2ded5c54ca7a598b6df6b219259a570d4e05", // pragma: allowlist secret
117
+ compressedHex: hex"03ce0f23517b664591d061a3a3b5af80c3c887abbbbe54f47e3946f3f6405910a6", // pragma: allowlist secret
118
+ evmAddress: 0xA6AB5320cC27c4643F946247D2f044946DECF050
119
+ })
120
+ );
121
+ }
122
+ }
@@ -0,0 +1,63 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity 0.8.23;
3
+ /* solhint-disable no-console */
4
+ /* solhint-disable max-line-length */
5
+ /// NOTE: pragma allowlist-secret must be inline (same line as the pubkey hex string) to avoid false positive
6
+ /// flag "Hex High Entropy String" in CI run detect-secrets
7
+
8
+ import { Test } from "../utils/Test.sol";
9
+
10
+ import { Create3 } from "../../src/deploy/Create3.sol";
11
+
12
+ contract Create3Test is Test {
13
+ function testCreate3_deploy() public {
14
+ // deploy and getDeployed should return same address when deployed by the same deployer and with same salt.
15
+ bytes32 salt = 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef;
16
+ bytes memory creationCode = type(Create3).creationCode;
17
+ address deployed = create3.deploy(salt, creationCode);
18
+ address expected = create3.getDeployed(address(this), salt);
19
+ assertEq(deployed, expected);
20
+
21
+ // Network shall generate the same address for the same deployer and salt.
22
+ vm.expectRevert("DEPLOYMENT_FAILED");
23
+ deployed = create3.deploy(salt, creationCode);
24
+
25
+ // Network shall generate different addresses for different deployers.
26
+ address otherAddr = address(0xf398C12A45Bc409b6C652E25bb0a3e702492A4ab);
27
+ vm.prank(otherAddr);
28
+ deployed = create3.deploy(salt, creationCode);
29
+ expected = create3.getDeployed(otherAddr, salt);
30
+ assertEq(deployed, expected);
31
+
32
+ // Network shall generate different addresses for different salts.
33
+ bytes32 otherSalt = 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890fedcba;
34
+ deployed = create3.deploy(otherSalt, creationCode);
35
+ expected = create3.getDeployed(address(this), otherSalt);
36
+ assertEq(deployed, expected);
37
+ }
38
+
39
+ function testCreate3_deploy_onlySalt() public {
40
+ // deployDeterministic and predictDeterministicAddress return same address when deployed by the same salt.
41
+ bytes32 salt = 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef;
42
+ bytes memory creationCode = type(Create3).creationCode;
43
+ address deployed = create3.deployDeterministic(creationCode, salt);
44
+ address expected = create3.predictDeterministicAddress(salt);
45
+ assertEq(deployed, expected);
46
+
47
+ // Network shall generate the same address for the same salt.
48
+ vm.expectRevert("DEPLOYMENT_FAILED");
49
+ deployed = create3.deployDeterministic(creationCode, salt);
50
+
51
+ // Network shall generate same addresses for different deployers.
52
+ address otherAddr = address(0xf398C12A45Bc409b6C652E25bb0a3e702492A4ab);
53
+ vm.prank(otherAddr);
54
+ vm.expectRevert("DEPLOYMENT_FAILED");
55
+ deployed = create3.deployDeterministic(creationCode, salt);
56
+
57
+ // Network shall generate different addresses for different salts.
58
+ bytes32 otherSalt = 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890fedcba;
59
+ deployed = create3.deployDeterministic(creationCode, otherSalt);
60
+ expected = create3.predictDeterministicAddress(otherSalt);
61
+ assertEq(deployed, expected);
62
+ }
63
+ }
@@ -0,0 +1,33 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity 0.8.23;
3
+
4
+ import { Test } from "../utils/Test.sol";
5
+ /* solhint-disable no-console */
6
+ /* solhint-disable max-line-length */
7
+ /// NOTE: pragma allowlist-secret must be inline (same line as the pubkey hex string) to avoid false positive
8
+ /// flag "Hex High Entropy String" in CI run detect-secrets
9
+
10
+ contract ERC6551RegistryTest is Test {
11
+ function test_erc6551Registry() public {
12
+ address account = erc6551Registry.createAccount(
13
+ address(this),
14
+ 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef,
15
+ block.chainid,
16
+ address(this),
17
+ 1
18
+ );
19
+
20
+ assertNotEq(account, address(0));
21
+
22
+ assertEq(
23
+ account,
24
+ erc6551Registry.account(
25
+ address(this),
26
+ 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef,
27
+ block.chainid,
28
+ address(this),
29
+ 1
30
+ )
31
+ );
32
+ }
33
+ }
@@ -0,0 +1,50 @@
1
+ // SPDX-License-Identifier: GPL-3.0-only
2
+ pragma solidity 0.8.23;
3
+ /* solhint-disable no-console */
4
+ /* solhint-disable max-line-length */
5
+ /* solhint-disable function-state-mutability */
6
+ /// NOTE: pragma allowlist-secret must be inline (same line as the pubkey hex string) to avoid false positive
7
+ /// flag "Hex High Entropy String" in CI run detect-secrets
8
+
9
+ import { Test } from "forge-std/Test.sol";
10
+
11
+ import { Secp256k1Verifier } from "../../src/protocol/Secp256k1Verifier.sol";
12
+
13
+ contract Secp256k1VerifierHarness is Secp256k1Verifier {
14
+ function uncompressPublicKey(bytes memory compressedKey) public pure returns (bytes memory) {
15
+ return _uncompressPublicKey(compressedKey);
16
+ }
17
+ }
18
+
19
+ contract Secp256k1VerifierTest is Test {
20
+ Secp256k1VerifierHarness public verifier;
21
+
22
+ function setUp() public {
23
+ verifier = new Secp256k1VerifierHarness();
24
+ }
25
+
26
+ function testCompressPublicKey_validKey() public view {
27
+ // prefix: 04
28
+ bytes
29
+ memory uncmpPubkey = hex"04ed58a9319aba87f60fe08e87bc31658dda6bfd7931686790a2ff803846d4e59c215b515f2acba1de2979c9b1376e088d4e48b20331a876ae4ed2c4f6bafc4016"; // pragma: allowlist-secret
30
+ // prefix: 03
31
+ bytes memory cmpPubkey = hex"02ed58a9319aba87f60fe08e87bc31658dda6bfd7931686790a2ff803846d4e59c"; // pragma: allowlist-secret
32
+
33
+ bytes memory anotherCmpPubkey = hex"037ff1214f5af4b652bc6c352ecb1296791cf754a426b49a7c4a263124f7497e98"; // pragma: allowlist-secret
34
+
35
+ vm.assertEq(verifier.uncompressPublicKey(cmpPubkey), uncmpPubkey);
36
+ vm.assertNotEq(verifier.uncompressPublicKey(cmpPubkey), verifier.uncompressPublicKey(anotherCmpPubkey));
37
+ }
38
+
39
+ function testCompressPublicKey_deriveAddress() public pure {
40
+ // prefix 04 sliced from `04e38d15ae6cc5d41cce27a2307903cb12a406cbf463fe5fef215bdf8aa988ced195e9327ac89cd362eaa0397f8d7f007c02b2a75642f174e455d339e4a1efe47b` // pragma: allowlist-secret
41
+ bytes
42
+ memory uncmpPubkeySliced = hex"e38d15ae6cc5d41cce27a2307903cb12a406cbf463fe5fef215bdf8aa988ced195e9327ac89cd362eaa0397f8d7f007c02b2a75642f174e455d339e4a1efe47b"; // pragma: allowlist-secret
43
+
44
+ address expectedAddr = 0xf398C12A45Bc409b6C652E25bb0a3e702492A4ab;
45
+ address derivedAddr = address(uint160(uint256(keccak256(uncmpPubkeySliced))));
46
+
47
+ vm.assertEq(uncmpPubkeySliced.length, 64);
48
+ vm.assertEq(derivedAddr, expectedAddr);
49
+ }
50
+ }