Skip to content

Commit 32b289f

Browse files
authored
feat: add endorsement and governance changes (#67)
1 parent b1fee18 commit 32b289f

File tree

87 files changed

+13808
-3727
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+13808
-3727
lines changed

packages/contracts/.gitignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,9 @@ artifacts
1515
docs
1616

1717
# GalaxyMember metadata
18-
metadata/galaxyMember/metadata.zip
18+
metadata/galaxyMember/metadata.zip
19+
# Local upgrade worklog (not deployed yet)
20+
.upgrade-worklog.md
21+
22+
# Endorsement migration output
23+
scripts/endorsement-migration/data/

packages/contracts/CLAUDE.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
Instructions specific to `packages/contracts` directory.
44

5+
## Important Notes
6+
7+
If you figure new rules out, or important things to remember for next time you will work on smart contracts changes, told to you by the devs, please add them to the file.
8+
59
## Domain Knowledge
610

711
### VeBetterDAO Overview
@@ -181,6 +185,28 @@ const v6 = await upgradeProxy("GalaxyMemberV5", "GalaxyMember", await v5.getAddr
181185
expect(await v6.existingData()).to.equal(expectedValue)
182186
```
183187

188+
### CRITICAL: Upgrade Test Version Mismatch Pattern
189+
190+
When working with upgrade tests, watch for this common bug:
191+
192+
```typescript
193+
// Comment says V4 → V5
194+
// Upgrade X2EarnAppsV4 to X2EarnAppsV5
195+
const x2EarnAppsV5 = (await upgradeProxy("X2EarnAppsV4", "X2EarnApps", ...)) as X2EarnApps
196+
// ^^^^^^^^^^^ WRONG!
197+
```
198+
199+
**Problem**: The test was written when V5 was the latest version. `"X2EarnApps"` referred to V5 back then. Now that we're at V8, `"X2EarnApps"` refers to V8, so this test incorrectly upgrades from V4 → V8, skipping V5/V6/V7.
200+
201+
**Fix**: Always use explicit version names for intermediate upgrades:
202+
203+
```typescript
204+
// Correct: explicit version
205+
const x2EarnAppsV5 = (await upgradeProxy("X2EarnAppsV4", "X2EarnAppsV5", ...)) as X2EarnAppsV5
206+
```
207+
208+
**Rule**: Only use `"ContractName"` (without version suffix) when upgrading TO the latest version. For intermediate versions, always use `"ContractNameVN"`.
209+
184210
### Library Redeployment
185211

186212
**Always redeploy all libraries when upgrading.** Libraries are redeployed fresh with each contract upgrade - there's no library versioning or reuse.
@@ -258,6 +284,26 @@ NEXT_PUBLIC_APP_ENV=local npx hardhat test --network hardhat test/YourTest.test.
258284
- `{contract}/v{N}-compatibility.test.ts` - Backward compatibility tests
259285
- `{contract}/{feature}.test.ts` - Feature-specific tests
260286

287+
### CI Unit Test Shards
288+
289+
Unit tests run in parallel via shards in `.github/workflows/unit-tests.yml`. Each shard has a `label` and runs tests matched by `grep` on that label. Test describe blocks use `@shard15x` (or similar) in their name to match.
290+
291+
**When adding a new test shard** (e.g. for a new feature or coverage-focused suite):
292+
293+
1. Add `@shard15x` (or next available) to the describe block name in the test file
294+
2. **Add the shard to `.github/workflows/unit-tests.yml`** in the `strategy.matrix` - otherwise CI will not run it
295+
296+
Example matrix entry:
297+
298+
```yaml
299+
- shard: shard15f
300+
label: X-Apps - V8 Upgrade
301+
- shard: shard15g
302+
label: X-Apps - EndorsementUtils Coverage
303+
```
304+
305+
Shard assignments are documented in `packages/contracts/test/README.md`.
306+
261307
### Helper Functions
262308

263309
Import from `./helpers`:

packages/contracts/CONTRACTS_CHANGELOG.md

Lines changed: 184 additions & 41 deletions
Large diffs are not rendered by default.

packages/contracts/README.md

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,18 @@ Our contracts are upgradeable and versioned. See the [contracts changelog](/pack
3030
## Testnet contract addresses
3131

3232
```
33-
"B3TR": "0xbf64cf86894Ee0877C4e7d03936e35Ee8D8b864F",
34-
"B3TRGovernor": "0xDF5E114D391CAC840529802fe8D01f6bdeBE41eC",
35-
"Emissions": "0x148d21032F4a7b4aeF236E2E9C0c5bF62d10f8EB",
36-
"GalaxyMember": "0xCf73039913e05aa1838d5869E72290d2b454C1E8",
37-
"TimeLock": "0x30ee94F303643902a68aD8A7A6456cA69d763192",
38-
"Treasury": "0x039893EBe092A2D22B08E2b029735D211bfF7F50",
39-
"VOT3": "0xa704c45971995467696EE9544Da77DD42Bc9706E",
40-
"VoterRewards": "0x2E47fc4aabB3403037fB5E1f38995E7a91Ce8Ed2",
41-
"X2EarnApps": "0xcB23Eb1bBD5c07553795b9538b1061D0f4ABA153",
42-
"X2EarnRewardsPool": "0x5F8f86B8D0Fa93cdaE20936d150175dF0205fB38",
43-
"XAllocationPool": "0x9B9CA9D0C41Add1d204f90BA0E9a6844f1843A84",
44-
"XAllocationVoting": "0x5859ff910d8b0c127364c98E24233b0af7443c1c",
45-
"B3TRFaucet": "0x5e9c1F0f52aC6b5004122059053b00017EAfB561",
46-
"RelayerRewardsPool": "0x92b5a7484970d9b2ad981e8135ff14e6f996dc04"
33+
"B3TR": "0x95761346d18244bb91664181bf91193376197088",
34+
"B3TRGovernor": "0xc30b4d0837f7e3706749655d8bde0c0f265dd81b",
35+
"Emissions": "0x66898f98409db20ed6a1bf0021334b7897eb0688",
36+
"GalaxyMember": "0x38a59fa7fd7039884465a0ff285b8c4b6fe394ca",
37+
"TimeLock": "0x835509222aa67c333a1cbf29bd341e014aba86c9",
38+
"Treasury": "0x3d531a80c05099c71b02585031f86a2988e0caca",
39+
"VOT3": "0x6e8b4a88d37897fc11f6ba12c805695f1c41f40e",
40+
"VoterRewards": "0x851ef91801899a4e7e4a3174a9300b3e20c957e8",
41+
"X2EarnApps": "0x0b54a094b877a25bdc95b4431eaa1e2206b1ddfe",
42+
"X2EarnRewardsPool": "0x2d2a2207c68a46fc79325d7718e639d1047b0d8b",
43+
"XAllocationPool": "0x6f7b4bc19b4dc99005b473b9c45ce2815bbe7533",
44+
"XAllocationVoting": "0x8800592c463f0b21ae08732559ee8e146db1d7b2"
4745
```
4846

4947
Notice: _VeBetter Passport contract deployed only on mainnet._

packages/contracts/contracts/B3TRGovernor.sol

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,14 @@ import { IGalaxyMember } from "./interfaces/IGalaxyMember.sol";
8181
* - Difference from V4: Updated all libraries to use new version of IVoterRewards that supports GM Upgrades.
8282
* ------------------ VERSION 6 ------------------
8383
* - Updated all libraries to use new version of IVoterRewards that supports GM Rewards Pool.
84-
------------------ VERSION 7 ------------------
84+
* ------------------ VERSION 7 ------------------
8585
* - Added proposal type concept, STANDARD (0n) for existing proposals and GRANT (1n) for new grants proposals.
8686
* - Added deposit threshold cap based on proposal type.
87+
* ------------------ VERSION 8 ------------------
88+
* - No changes from V7 (placeholder for future reference).
89+
* ------------------ VERSION 9 ------------------
90+
* - Added reason parameter to cancel function for providing cancellation rationale.
91+
* - Added ProposalCanceledWithReason event.
8792
*/
8893
contract B3TRGovernor is
8994
IB3TRGovernor,
@@ -537,7 +542,7 @@ contract B3TRGovernor is
537542
* @return string The version of the governor
538543
*/
539544
function version() external pure returns (string memory) {
540-
return "8";
545+
return "9";
541546
}
542547

543548
/**
@@ -814,13 +819,15 @@ contract B3TRGovernor is
814819
* @param values The list of values to send
815820
* @param calldatas The list of call data
816821
* @param descriptionHash The hash of the description
822+
* @param reason The reason for canceling the proposal
817823
* @return uint256 The proposal id
818824
*/
819825
function cancel(
820826
address[] memory targets,
821827
uint256[] memory values,
822828
bytes[] memory calldatas,
823-
bytes32 descriptionHash
829+
bytes32 descriptionHash,
830+
string memory reason
824831
) external returns (uint256) {
825832
GovernorStorageTypes.GovernorStorage storage $ = getGovernorStorage();
826833
return
@@ -831,7 +838,8 @@ contract B3TRGovernor is
831838
targets,
832839
values,
833840
calldatas,
834-
descriptionHash
841+
descriptionHash,
842+
reason
835843
);
836844
}
837845

packages/contracts/contracts/XAllocationPool.sol

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ import { IX2EarnRewardsPool } from "./interfaces/IX2EarnRewardsPool.sol";
6060
* - Track the unallocated funds for each round
6161
* - Added admin function to manually set the unallocated funds for a given round
6262
* - Added a getter to see if all apps have claimed their rewards for a given round
63+
* - Fix allocations with zero votes
6364
*/
6465
contract XAllocationPool is IXAllocationPool, AccessControlUpgradeable, ReentrancyGuardUpgradeable, UUPSUpgradeable {
6566
using Checkpoints for Checkpoints.Trace208; // Checkpoints library for managing the voting mechanism used in the XAllocationVoting contract
@@ -268,10 +269,8 @@ contract XAllocationPool is IXAllocationPool, AccessControlUpgradeable, Reentran
268269
uint256 x2EarnRewardsPoolAmount
269270
) = claimableAmount(roundId, appId);
270271

271-
require(amountToClaim > 0, "XAllocationPool: no rewards available for this app");
272-
273272
$.claimedRewards[appId][roundId] = true;
274-
273+
275274
//check that contract has enough funds to pay the reward
276275
require(
277276
$.b3tr.balanceOf(address(this)) >= (teamAllocationsAmount + x2EarnRewardsPoolAmount + unallocatedAmount),

packages/contracts/contracts/X2EarnApps.sol renamed to packages/contracts/contracts/deprecated/V7/X2EarnAppsV7.sol

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,19 @@
2323

2424
pragma solidity 0.8.20;
2525

26-
import { X2EarnAppsUpgradeable } from "./x-2-earn-apps/X2EarnAppsUpgradeable.sol";
27-
import { AdministrationUpgradeable } from "./x-2-earn-apps/modules/AdministrationUpgradeable.sol";
28-
import { AppsStorageUpgradeable } from "./x-2-earn-apps/modules/AppsStorageUpgradeable.sol";
29-
import { ContractSettingsUpgradeable } from "./x-2-earn-apps/modules/ContractSettingsUpgradeable.sol";
30-
import { VoteEligibilityUpgradeable } from "./x-2-earn-apps/modules//VoteEligibilityUpgradeable.sol";
31-
import { EndorsementUpgradeable } from "./x-2-earn-apps/modules/EndorsementUpgradeable.sol";
32-
import { EndorsementUtils } from "./x-2-earn-apps/libraries/EndorsementUtils.sol";
26+
import { X2EarnAppsUpgradeableV7 } from "./x-2-earn-apps/X2EarnAppsUpgradeableV7.sol";
27+
import { AdministrationUpgradeableV7 } from "./x-2-earn-apps/modules/AdministrationUpgradeableV7.sol";
28+
import { AppsStorageUpgradeableV7 } from "./x-2-earn-apps/modules/AppsStorageUpgradeableV7.sol";
29+
import { ContractSettingsUpgradeableV7 } from "./x-2-earn-apps/modules/ContractSettingsUpgradeableV7.sol";
30+
import { VoteEligibilityUpgradeableV7 } from "./x-2-earn-apps/modules/VoteEligibilityUpgradeableV7.sol";
31+
import { EndorsementUpgradeableV7 } from "./x-2-earn-apps/modules/EndorsementUpgradeableV7.sol";
32+
import { EndorsementUtilsV7 } from "./x-2-earn-apps/libraries/EndorsementUtilsV7.sol";
3333
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
3434
import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
35-
import { IXAllocationVotingGovernor } from "./interfaces/IXAllocationVotingGovernor.sol";
35+
import { IXAllocationVotingGovernor } from "../../interfaces/IXAllocationVotingGovernor.sol";
3636

3737
/**
38-
* @title X2EarnApps
38+
* @title X2EarnAppsV7
3939
* @notice This contract handles the x-2-earn applications of the VeBetterDAO ecosystem. The contract allows the insert, management and
4040
* eligibility of apps for the B3TR allocation rounds.
4141
* @dev The contract is using AccessControl to handle the admin and upgrader roles.
@@ -60,20 +60,20 @@ import { IXAllocationVotingGovernor } from "./interfaces/IXAllocationVotingGover
6060
*
6161
* -------------------- Version 6 --------------------
6262
* - Upon StarGate launch, we updated the NodeManagement contract to V3. This impacted mostly
63-
* EndorsementUtils library.
64-
* EndorsementUpgradeable module.
63+
* EndorsementUtilsV7 library.
64+
* EndorsementUpgradeableV7 module.
6565
*
6666
* -------------------- Version 7 --------------------
6767
* - Integrated Stargate NFT contract for node management and endorsement verification.
6868
* - Updated endorsement system to use Stargate NFT for node ownership and token management.
6969
*/
70-
contract X2EarnApps is
71-
X2EarnAppsUpgradeable,
72-
AdministrationUpgradeable,
73-
ContractSettingsUpgradeable,
74-
VoteEligibilityUpgradeable,
75-
AppsStorageUpgradeable,
76-
EndorsementUpgradeable,
70+
contract X2EarnAppsV7 is
71+
X2EarnAppsUpgradeableV7,
72+
AdministrationUpgradeableV7,
73+
ContractSettingsUpgradeableV7,
74+
VoteEligibilityUpgradeableV7,
75+
AppsStorageUpgradeableV7,
76+
EndorsementUpgradeableV7,
7777
AccessControlUpgradeable,
7878
UUPSUpgradeable
7979
{
@@ -94,7 +94,7 @@ contract X2EarnApps is
9494
* @dev This function is called only once during the contract deployment
9595
*/
9696
function initializeV7(address _stargateNft) external onlyRole(UPGRADER_ROLE) reinitializer(7) {
97-
require(_stargateNft != address(0), "X2EarnApps: Invalid Stargate NFT contract address");
97+
require(_stargateNft != address(0), "X2EarnAppsV7: Invalid Stargate NFT contract address");
9898
__Endorsement_init_v7(_stargateNft);
9999
}
100100

@@ -302,7 +302,7 @@ contract X2EarnApps is
302302
* @dev See {IX2EarnApps-updateNodeEndorsementScores}.
303303
*/
304304
function updateNodeEndorsementScores(
305-
EndorsementUtils.NodeStrengthScores calldata _nodeStrengthScores
305+
EndorsementUtilsV7.NodeStrengthScores calldata _nodeStrengthScores
306306
) external onlyRole(GOVERNANCE_ROLE) {
307307
_updateNodeEndorsementScores(_nodeStrengthScores);
308308
}

0 commit comments

Comments
 (0)