@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.
- package/README.md +65 -0
- package/index.js +43 -0
- package/package.json +51 -0
- package/script/GenerateAlloc.s.sol +448 -0
- package/script/upgrades/DeployNewIPTokenStaking_V1_0_1.s.sol +42 -0
- package/script/utils/ChainIds.sol +12 -0
- package/script/utils/EIP1967Helper.sol +37 -0
- package/script/utils/InitializableHelper.sol +66 -0
- package/src/deploy/Create3.sol +62 -0
- package/src/interfaces/IIPTokenStaking.sol +303 -0
- package/src/interfaces/IUBIPool.sol +37 -0
- package/src/interfaces/IUpgradeEntrypoint.sol +33 -0
- package/src/libraries/Predeploys.sol +50 -0
- package/src/protocol/IPTokenStaking.sol +509 -0
- package/src/protocol/Secp256k1Verifier.sol +109 -0
- package/src/protocol/UBIPool.sol +98 -0
- package/src/protocol/UpgradeEntrypoint.sol +40 -0
- package/src/token/WIP.sol +90 -0
- package/test/data/ValidatorData.sol +122 -0
- package/test/deploy/Create3.t.sol +63 -0
- package/test/erc6551/Erc6551Registry.t.sol +33 -0
- package/test/secp256k/Secp256k1PubKeyVerifier.t.sol +50 -0
- package/test/stake/IPTokenStaking.t.sol +1022 -0
- package/test/timelock/Timelock.t.sol +136 -0
- package/test/token/WIP.t.sol +198 -0
- package/test/ubipool/UBIPool.t.sol +239 -0
- package/test/upgrade-entrypoint/UpgradeEntryPoint.t.sol +37 -0
- package/test/upgrades/PredeployUpgrades.t.sol +219 -0
- package/test/utils/Test.sol +170 -0
@@ -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
|
+
}
|