Skip to content

HUBS-224 crowdsale with individual locking staking periods #170

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

elmariachi111
Copy link
Contributor

@elmariachi111 elmariachi111 commented Dec 12, 2024

Stefan

  • new staked locking contract
    • slcs stores individual vesting durations
    • added timelocked contract trust. This is not great but it works at this point
    • replaces inline locked token contract with a verifiable implementation
  • updates subgraphs to support legacy & new contracts
    • introduced a second sl contract (sepolia / ethereum)
    • deploys the plain locking contract
    • reuses network indexer definitions

Summary by CodeRabbit

Release Notes

  • New Features

    • Added support for Timelocked Token implementation in Crowd Sale contracts.
    • Introduced enhanced staking and vesting duration controls for sales.
    • Implemented new locking contract creation mechanism.
    • Added a new LockingCrowdSale contract with improved functionality.
  • Improvements

    • Updated contract addresses for various network deployments, including new LockingCrowdSale entries.
    • Enhanced event handling for crowd sale processes.
    • Refined subgraph indexing capabilities.
    • Improved clarity in deployment documentation, including new sections on timelocked tokens.
  • Bug Fixes

    • Improved contract initialization and parameter validation.
    • Updated error handling for sale durations and contract interactions.
  • Infrastructure

    • Updated deployment scripts for new contract versions.
    • Modified local setup and testing procedures.
  • Documentation

    • Updated README with latest contract addresses and deployment instructions.

adds condition to faile when duration < 7 days (enfoced by token vesting contract)
replaces bakedin locking contract with an external deployment for verifiability

Signed-off-by: Stefan Adolf <stefan@molecule.to>
adds staking duration parameters to all staking tests
drops old V23 sale rollout script

Signed-off-by: Stefan Adolf <stefan@molecule.to>
Copy link

coderabbitai bot commented Dec 12, 2024

Walkthrough

This pull request introduces significant enhancements to the crowd sale and token locking mechanisms across multiple contracts and configurations. The primary focus is on integrating a new TimelockedToken implementation into the existing crowd sale infrastructure. Key changes include updating contract addresses, modifying deployment scripts, and adding new functionality for token vesting and staking durations. The changes span across smart contracts, deployment scripts, subgraph configurations, and test suites, ensuring a comprehensive update to the token sale ecosystem.

Changes

File/Path Change Summary
.env.example Updated environment variable addresses for various contracts
README.md Updated contract addresses, added new entries for Locking Crowdsale and Timelocked Token Implementation
script/DeployTokenizer.s.sol Added TimelockedToken import and integration into deployment process
script/dev/CrowdSale.s.sol Updated StakedLockingCrowdSale initialization to include TimelockedToken
script/dev/SignTermsMessage.s.sol Changed run function to public view
script/dev/Tokenizer.s.sol Modified logging for initialIpTokenImplementation
script/prod/RolloutV23Sale.sol Removed deprecated contract
setupLocal.sh Added show_help() function for usage instructions
src/crowdsale/LockingCrowdSale.sol Introduced TimelockedToken implementation, added trustLockingContract function
src/crowdsale/StakedLockingCrowdSale.sol Added salesStakeVestingDuration mapping, updated startSale function with new parameters
subgraph/abis/IPNFT.json Added isPoi function to IPNFT contract
subgraph/abis/LockingCrowdSale.json Created new ABI file for LockingCrowdSale contract
subgraph/abis/StakedLockingCrowdSale.json Updated ABI for StakedLockingCrowdSale with new constructor and functions
subgraph/makeAbis.sh Added functionality to extract ABI for LockingCrowdSale
subgraph/networks.json Updated contract addresses for Sepolia, Mainnet, and Foundry networks
subgraph/schema.graphql Added LOCKING_CROWDSALE enum value, new contract field for CrowdSale
subgraph/src/lockingCrowdSaleMapping.ts Enhanced event handling for locking crowd sale events
subgraph/src/stakedLockingCrowdSaleMapping.ts Updated event handling for StakedLockingCrowdSale
subgraph/src/crowdSaleMapping.ts Modified handleStarted function to link crowd sale instance with contract address
subgraph/subgraph.yaml Updated contract addresses and added LockingCrowdSale configuration
Test files Updated contract initialization with TimelockedToken, modified startSale function signatures

Sequence Diagram

sequenceDiagram
    participant Deploy as Deployment Script
    participant TimelockedToken
    participant LockingCrowdSale
    participant StakedLockingCrowdSale

    Deploy->>TimelockedToken: Create Implementation
    Deploy->>LockingCrowdSale: Initialize with TimelockedToken
    Deploy->>StakedLockingCrowdSale: Initialize with TimelockedToken
    StakedLockingCrowdSale->>StakedLockingCrowdSale: Set Stake Vesting Duration
    LockingCrowdSale->>LockingCrowdSale: Create/Trust Locking Contracts
Loading

Poem

🐰 Hopping through code with glee,
Timelocked tokens set us free!
Contracts dance with new delight,
Vesting schedules burning bright
A rabbit's blockchain jubilee! 🚀

Finishing Touches

  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Signed-off-by: Stefan Adolf <stefan@molecule.to>
@elmariachi111 elmariachi111 force-pushed the feature/hubs-224-crowdsale-with-individual-locking-staking-periods branch from def2bed to 8d83cfc Compare December 18, 2024 17:58
Signed-off-by: Stefan Adolf <stefan@molecule.to>
Signed-off-by: Stefan Adolf <stefan@molecule.to>
Signed-off-by: Stefan Adolf <stefan@molecule.to>
Signed-off-by: Stefan Adolf <stefan@molecule.to>
Signed-off-by: Stefan Adolf <stefan@molecule.to>
@elmariachi111 elmariachi111 marked this pull request as ready for review December 19, 2024 10:24
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (18)
subgraph/src/lockingCrowdSaleMapping.ts (3)

2-2: Consider renaming the imported BigInt.
Although this is a type from '@graphprotocol/graph-ts', it shadows the global 'BigInt' in TypeScript, which might lead to confusion. Renaming avoids collisions and clarifies the origin.

-import {
-  BigInt,
-  ...
-} from '@graphprotocol/graph-ts'
+import {
+  BigInt as GraphBigInt,
+  ...
+} from '@graphprotocol/graph-ts'
🧰 Tools
🪛 Biome (1.9.4)

[error] 2-2: Do not shadow the global "BigInt" property.

Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.

(lint/suspicious/noShadowRestrictedNames)


67-80: Ensure locked token uniqueness is correct and tested.
The code checks if the new locking token differs from the existing one and logs an error if they don't match. Check if any fallback or handle path is needed when a mismatch occurs, especially if an IP might inadvertently reference multiple locking tokens.


81-87: Optional: Distinguish the crowdSale.type assignment for future expansions.
Currently, "STAKED_LOCKING_CROWDSALE" is assigned. If there’s a possibility of different crowd sale subtypes, consider storing them in a more flexible, future-proof manner (e.g. an enum or additional fields).

src/crowdsale/LockingCrowdSale.sol (1)

65-70: Consider clarifying the fallback logic with a comment.
When the trustee returns no existing contract, a fresh TimelockedToken is created. A short comment explaining the fallback scenario can improve clarity for future maintainers.

src/crowdsale/StakedLockingCrowdSale.sol (1)

127-130: Large vesting durations.
You enforce a minimum of 7 days. Consider also an upper limit if business logic demands a max.

.env.example (2)

29-29: Standardize comment formatting

The comment style is inconsistent. Consider using a consistent format:

-#iptoken implementation=0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82
-#timelocked token implementation=0x0B306BF915C4d645ff596e518fAf3F9669b97016
+# IPToken implementation = 0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82
+# Timelocked token implementation = 0x0B306BF915C4d645ff596e518fAf3F9669b97016

Also applies to: 31-31

🧰 Tools
🪛 Gitleaks (8.21.2)

29-29: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


34-36: Consider grouping related addresses

Consider grouping the LOCKED_IPTS_ADDRESS with other IPT-related addresses for better organization and readability.

 USDC6_ADDRESS=0x3Aa5ebB10DC797CAC828524e59A333d0A371443c
 WETH_ADDRESS=0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44
 PLAIN_CROWDSALE_ADDRESS=0x09635F643e140090A9A8Dcd712eD6285858ceBef

-#these are generated when running the fixture scripts
-IPTS_ADDRESS=0x8dAF17A20c9DBA35f005b6324F493785D239719d
-LOCKED_IPTS_ADDRESS=0x24B3c7704709ed1491473F30393FFc93cFB0FC34
+# IPT-related addresses (generated when running the fixture scripts)
+IPTS_ADDRESS=0x8dAF17A20c9DBA35f005b6324F493785D239719d
+LOCKED_IPTS_ADDRESS=0x24B3c7704709ed1491473F30393FFc93cFB0FC34

Also applies to: 40-40

setupLocal.sh (2)

Line range hint 21-32: Consider adding validation for option combinations

The script might benefit from validating mutually exclusive options or requiring certain option combinations.

 while getopts "fx" opt; do
   case ${opt} in
     f)
       fixtures=true
       ;;
     x)
+      if [ "$fixtures" = false ]; then
+        echo "Error: -x requires -f option"
+        exit 1
+      fi
       extrafixtures=true
       ;;
     *)
       echo "Unknown option: $1"
       exit 1
       ;;
   esac
 done

Line range hint 66-73: Consider parameterizing the sleep duration

The hardcoded sleep duration of 15/16 seconds might need adjustment based on network conditions. Consider making it configurable.

+# Default sleep duration between operations (in seconds)
+SLEEP_DURATION=${SLEEP_DURATION:-15}
+
 if $extrafixtures; then
   echo "Running extra fixture scripts (crowdsales)."
 
   $FSC script/dev/CrowdSale.s.sol:FixtureCrowdSale 
-  echo "Waiting 15 seconds until claiming plain sale..."
-  sleep 16
+  echo "Waiting ${SLEEP_DURATION} seconds until claiming plain sale..."
+  sleep $((SLEEP_DURATION + 1))
script/DeployTokenizer.s.sol (2)

31-33: Improve comment clarity and consider adding events

The comment about contract verification could be more descriptive. Also, consider emitting events for important state changes.

-        //this allows the default TimelockedToken implementation to be verified on chain explorers
+        // Deploy TimelockedToken implementation first to enable contract verification on block explorers
         TimelockedToken timelockedTokenImplementation = new TimelockedToken();
+        emit TimelockedTokenImplementationDeployed(address(timelockedTokenImplementation));
         StakedLockingCrowdSale stakedLockingCrowdSale = new StakedLockingCrowdSale(timelockedTokenImplementation);
+        emit StakedLockingCrowdSaleDeployed(address(stakedLockingCrowdSale));

Don't forget to add the event declarations at the contract level:

event TimelockedTokenImplementationDeployed(address implementation);
event StakedLockingCrowdSaleDeployed(address crowdSale);

40-41: Consider standardizing the console log format

The console log format for the timelocked token implementation differs from other logs. Consider standardizing it:

-        console.log("timelocked token implementation=%s", address(timelockedTokenImplementation));
+        console.log("TIMELOCKED_TOKEN_IMPLEMENTATION_ADDRESS=%s", address(timelockedTokenImplementation));
script/prod/RolloutV25Sale.sol (2)

15-15: Document multisig addresses

The multisig addresses are hardcoded without clear documentation of their purpose and ownership. Consider adding comments explaining:

  • Who controls these multisigs
  • Why different addresses are used for mainnet vs other networks
  • Whether these have been verified as the correct addresses

Also applies to: 34-34


18-21: Consider emitting events for important state changes

Important contract deployments and ownership transfers should emit events for better traceability. Consider:

  1. Adding events to the contracts being deployed
  2. Using OpenZeppelin's Initializable to prevent double initialization

Example implementation:

event CrowdsaleDeployed(address indexed implementation, address indexed proxy, address indexed owner);

Also applies to: 40-43

test/CrowdSaleWithNonStandardERC20Test.t.sol (1)

87-87: Verify consistent vesting duration usage

The startSale function calls now include the vesting duration parameter. The values used are:

  • 60 days for standard sales
  • 7 days for the 2 decimals test case

Consider extracting these durations as constants to maintain consistency and make updates easier.

+    uint256 constant STANDARD_VESTING_DURATION = 60 days;
+    uint256 constant SHORT_VESTING_DURATION = 7 days;

Also applies to: 125-125, 183-183, 245-245, 310-310

test/CrowdSaleLockedStakedTest.t.sol (1)

459-461: Implement the pending test for locking contract reuse

The TODO comment indicates a missing test case for demonstrating how locking contracts are reused.

Would you like me to help implement this test case or create a GitHub issue to track this task?

subgraph/abis/LockingCrowdSale.json (1)

319-435: Consider adding validation for minimum sale duration

The startSale functions should consider adding validation for minimum sale duration to prevent flash sales that could be manipulated.

Consider adding a minimum duration check in the implementation to prevent potential market manipulation through extremely short sales.

README.md (2)

53-54: Consider improving the format of implementation addresses

The timelocked token implementation address and the deprecated crowdsale note could be better formatted for consistency with the rest of the document. Consider using the table format or a dedicated section for implementation addresses.

-timelocked token implementation=0xF8F79c1E02387b0Fc9DE0945cD9A2c06F127D851  
-~~new staked crowdsale (not used yet HUBS-224) 0x7eeb7113f90893fb95c6666e3930235850f2bc6A)~~
+| Contract | Address | Status |
+| -------- | ------- | ------ |
+| Timelocked Token Implementation | 0xF8F79c1E02387b0Fc9DE0945cD9A2c06F127D851 | Active |
+| Staked Crowdsale | 0x7eeb7113f90893fb95c6666e3930235850f2bc6A | Deprecated (HUBS-224) |
🧰 Tools
🪛 Gitleaks (8.21.2)

53-53: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


212-214: Fix typo in verification instructions

The word "crowdsale" is repeated in the instruction header.

-Verifying a the staked crowdsale crowdsale
+Verifying the staked crowdsale
🧰 Tools
🪛 LanguageTool

[grammar] ~212-~212: Two determiners in a row. Choose either “a” or “the”.
Context: ....sol:StakedLockingCrowdSale Verifying a the staked crowdsale crowdsaleforge verif...

(DT_DT)


[duplication] ~212-~212: Possible typo: you repeated a word
Context: ...ckingCrowdSale Verifying a the staked crowdsale crowdsaleforge verify-contract --chain-id=11155...

(ENGLISH_WORD_REPEAT_RULE)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 43f8c86 and a6b7a19.

📒 Files selected for processing (23)
  • .env.example (1 hunks)
  • README.md (2 hunks)
  • script/DeployTokenizer.s.sol (2 hunks)
  • script/dev/CrowdSale.s.sol (2 hunks)
  • script/dev/SignTermsMessage.s.sol (1 hunks)
  • script/dev/Tokenizer.s.sol (1 hunks)
  • script/prod/RolloutV23Sale.sol (0 hunks)
  • script/prod/RolloutV25Sale.sol (1 hunks)
  • setupLocal.sh (1 hunks)
  • src/crowdsale/LockingCrowdSale.sol (3 hunks)
  • src/crowdsale/StakedLockingCrowdSale.sol (7 hunks)
  • subgraph/abis/IPNFT.json (1 hunks)
  • subgraph/abis/LockingCrowdSale.json (1 hunks)
  • subgraph/abis/StakedLockingCrowdSale.json (5 hunks)
  • subgraph/makeAbis.sh (1 hunks)
  • subgraph/networks.json (3 hunks)
  • subgraph/schema.graphql (1 hunks)
  • subgraph/src/lockingCrowdSaleMapping.ts (1 hunks)
  • subgraph/subgraph.yaml (2 hunks)
  • test/CrowdSaleLockedStakedTest.t.sol (9 hunks)
  • test/CrowdSaleLockedTest.t.sol (1 hunks)
  • test/CrowdSalePermissioned.t.sol (2 hunks)
  • test/CrowdSaleWithNonStandardERC20Test.t.sol (6 hunks)
💤 Files with no reviewable changes (1)
  • script/prod/RolloutV23Sale.sol
✅ Files skipped from review due to trivial changes (1)
  • script/dev/Tokenizer.s.sol
🧰 Additional context used
🪛 Gitleaks (8.21.2)
README.md

53-53: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

.env.example

29-29: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


31-31: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🪛 LanguageTool
README.md

[grammar] ~212-~212: Two determiners in a row. Choose either “a” or “the”.
Context: ....sol:StakedLockingCrowdSale Verifying a the staked crowdsale crowdsaleforge verif...

(DT_DT)


[duplication] ~212-~212: Possible typo: you repeated a word
Context: ...ckingCrowdSale Verifying a the staked crowdsale crowdsaleforge verify-contract --chain-id=11155...

(ENGLISH_WORD_REPEAT_RULE)

🪛 Biome (1.9.4)
subgraph/src/lockingCrowdSaleMapping.ts

[error] 2-2: Do not shadow the global "BigInt" property.

Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.

(lint/suspicious/noShadowRestrictedNames)

🔇 Additional comments (34)
subgraph/src/lockingCrowdSaleMapping.ts (1)

32-87: Verify error handling when loading the CrowdSale/ IPT entities.
The logic already logs an error if the entity doesn't exist, then returns. Confirm that upstream code or tests ensure that the missing entities do not leave the subgraph in an unexpected state.

✅ Verification successful

Let me check the error handling patterns in these files to ensure consistency.


Error handling for CrowdSale/IPT entities is consistent and safe

The error handling patterns across the codebase are consistent and properly handle missing entities:

  • All CrowdSale.load() calls check for null and log appropriate errors before returning
  • All IPT.load() calls (except in common.ts which has a valid different use case) check for null, log errors, and return
  • The error handling in lockingCrowdSaleMapping.ts follows the same pattern as other files
  • Early returns prevent any further processing that could leave the subgraph in an inconsistent state
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Use ast-grep to locate entity loading in the subgraph code to ensure consistent error handling
ast-grep --pattern $'CrowdSale.load($_)' 
ast-grep --pattern $'IPT.load($_)' 

Length of output: 1608


Script:

#!/bin/bash
# Check error handling patterns in files that load CrowdSale and IPT entities
rg "CrowdSale.load|IPT.load" -A 5 subgraph/src/

Length of output: 6617

src/crowdsale/LockingCrowdSale.sol (6)

15-17: Contract naming clarity.
The interface name, ITrustedLockingContracts, accurately conveys that it provides externally trusted references to TimelockedToken instances. This is straightforward, good naming.


41-43: Constructor injection approach looks solid.
Injecting the TimelockedToken implementation address via the constructor is a robust approach that aligns well with proxy-based patterns.


50-52: Check the usage scope of trustLockingContractSource.
This function sets a trustee for locking contracts. For clarity and security, confirm that only the owner may call it and that calling it multiple times is safe.


Line range hint 84-88: Locking duration upper bound check is valid and conventional.
The revert condition for > 366 days is explicit and straightforward, preventing unreasonably long locks.


138-138: Clone usage is correct; confirm initialization is safe from reentrancy.
The code clones and initializes a TimelockedToken. Consider verifying that reentrancy cannot occur during initialization.


24-35: Consider verifying correctness of public variables.
The new public mappings and references allow external reading of lockingContracts. Confirm that read access to these mappings does not expose sensitive data or compromise security.

✅ Verification successful

Based on the search results, I can now generate the final response:

Public mappings for locking contracts are safely implemented
The lockingContracts mapping and lockingContractTrustee are used appropriately with proper access controls:

  • Locking contracts can only be created through createOrReturnTimelockContract() which enforces proper initialization
  • Writing to lockingContracts only happens in controlled contexts with owner-only access for trustee configuration
  • The mappings only expose read access to contract addresses, which is necessary for verification and integration
  • Test coverage confirms expected behavior for token locking, vesting and release mechanics
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Searching for usage of lockingContracts and lockingContractTrustee references to ensure no unintended writes or missed permission checks
rg lockingContracts -A 10
rg lockingContractTrustee -A 10

Length of output: 31917

src/crowdsale/StakedLockingCrowdSale.sol (4)

41-42: Mapping for staking durations is aligned with the new schema.
The new mapping 'salesStakeVestingDuration' is consistent with the broader locking logic.


57-58: Constructor chaining is appropriate.
Passing the _timelockedTokenImplementation to LockingCrowdSale ensures consistent TimelockedToken usage across both contracts.


88-90: Ensure lockingDuration and stakesVestingDuration validations remain consistent.
Both parameters have separate checks (e.g., stake vesting must be ≥ 7 days, while locking must be ≤ 366 days). Confirm that test cases cover boundary scenarios (e.g. exactly 7 days, exactly 366 days).

Also applies to: 98-99


Line range hint 196-222: Double-check vesting logic in the claim function.
Tokens are immediately transferred to the user if the sale is closed + vesting duration is exceeded. Otherwise, they’re locked in the vesting contract. This logic seems correct; ensure thorough tests for boundary conditions.

script/dev/SignTermsMessage.s.sol (1)

9-9: Marking 'run' as 'view' is sensible.
The function only logs a signature and does not mutate state. This change aligns with best practices for read-only logic.

setupLocal.sh (1)

12-18: LGTM! Well-documented help function

The help function clearly describes the available options and their purposes.

script/DeployTokenizer.s.sol (1)

14-14: Verify the initialization sequence

The TimelockedToken implementation is crucial for the StakedLockingCrowdSale. Let's verify that all contracts using this implementation are properly initialized.

Also applies to: 31-33

✅ Verification successful

Based on the shell script results, I can now generate the final response:

TimelockedToken initialization sequence verified and properly implemented

The TimelockedToken implementation is correctly initialized across the codebase:

  • All instances follow the same pattern: create TimelockedToken implementation first, then pass it to StakedLockingCrowdSale constructor
  • Proper initialization sequence is maintained in both test and deployment scripts
  • Integration with TokenVesting is handled correctly where required
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the initialization sequence and usage of TimelockedToken

# Check for TimelockedToken usage in other contracts
echo "Checking TimelockedToken usage:"
ast-grep --pattern 'contract $_ {
  $$$
  TimelockedToken $_ 
  $$$
}'

# Check for proper initialization patterns
echo "Checking initialization patterns:"
rg -A 5 "TimelockedToken.*new" 

Length of output: 4164

subgraph/schema.graphql (1)

123-123: LGTM! Schema change aligns with locking crowdsale implementation

The addition of LOCKING_CROWDSALE to the SaleType enum properly integrates with the existing schema structure, particularly with the TimelockedToken and LockedSchedule entities that handle token locking periods.

subgraph/networks.json (1)

19-22: Verify sepolia deployment

The sepolia address appears to be a real deployment. Let's verify its bytecode matches our contract.

subgraph/makeAbis.sh (1)

12-12: LGTM: ABI extraction for LockingCrowdSale

The addition of LockingCrowdSale ABI extraction aligns with the existing pattern and is correctly implemented.

test/CrowdSalePermissioned.t.sol (2)

69-70: LGTM: TimelockedToken integration

Proper initialization of TimelockedToken and its integration with StakedLockingCrowdSale.


107-107: Verify staking and locking durations

The test uses equal durations (60 days) for both staking and locking periods. Consider adding test cases with different durations to ensure the contract handles varying periods correctly.

script/dev/CrowdSale.s.sol (3)

38-40: LGTM: Deployment configuration

Proper initialization and deployment of TimelockedToken and StakedLockingCrowdSale contracts.


46-47: LGTM: Enhanced logging

Good addition of logging statements for contract addresses, which aids in deployment verification.


155-156: Consider standardizing durations across tests and fixtures

The fixture uses 7-day periods while the test uses 60-day periods. Consider standardizing these durations or documenting the reason for the difference.

subgraph/subgraph.yaml (2)

142-159: LGTM: Event handlers are properly configured

The LockingCrowdSale contract's event handlers are correctly configured to handle all relevant events including Started, Settled, Failed, Bid, LockingContractCreated, and various claim events.


127-127: Verify deployment address configuration

The LockingCrowdSale contract address appears to be using a placeholder value (0xbaadf00dbaadf00dbaadf00dbaadf00dbaadf00d). This needs to be updated with the actual deployed contract address.

test/CrowdSaleLockedTest.t.sol (1)

28-29: LGTM: Proper initialization of TimelockedToken

The TimelockedToken implementation is correctly instantiated and passed to the LockingCrowdSale constructor, following the new contract architecture.

test/CrowdSaleWithNonStandardERC20Test.t.sol (1)

53-54: LGTM: Consistent TimelockedToken implementation

The TimelockedToken setup matches the pattern used in other test files, maintaining consistency across the test suite.

subgraph/abis/IPNFT.json (1)

190-208: Document the purpose and behavior of isPoi function

The newly added isPoi function lacks documentation explaining its purpose and behavior. Since it's marked as pure, it suggests the result is deterministic based solely on the tokenId parameter, but the logic for this determination is unclear.

Let's check for any related documentation or usage:

test/CrowdSaleLockedStakedTest.t.sol (2)

58-60: LGTM: Proper initialization of TimelockedToken

The TimelockedToken implementation is correctly initialized and passed to the StakedLockingCrowdSale constructor.


400-404: LGTM: Proper validation of duration parameters

The test correctly verifies that the staking duration must be less than the vesting duration, ensuring the contract's invariants are maintained.

subgraph/abis/LockingCrowdSale.json (3)

1-12: LGTM: Constructor properly accepts TimelockedToken implementation

The constructor is well-defined with proper input validation through the contract type specification.


463-486: LGTM: Well-structured events with proper indexing

The events are well-designed with:

  • Proper indexing of key parameters for efficient filtering
  • Comprehensive event data for tracking important state changes
  • Clear separation of concerns between different event types

Also applies to: 487-517, 518-543, 544-556, 557-569, 570-588, 589-607, 608-632, 633-780


781-862: LGTM: Comprehensive error handling

The contract includes a complete set of custom errors that:

  • Provide specific error cases for better error handling
  • Include relevant error parameters where needed
  • Use descriptive names that clearly indicate the error condition
subgraph/abis/StakedLockingCrowdSale.json (2)

2-12: LGTM: Constructor properly initializes timelocked token implementation

The constructor correctly accepts and stores the timelocked token implementation address, which is essential for the contract's functionality.


322-340: Verify vesting duration constraints

The addition of salesStakeVestingDuration and stakesVestingDuration parameters requires validation:

  1. Ensure the vesting duration cannot be set to zero
  2. Verify the vesting duration cannot exceed reasonable limits
  3. Consider adding checks for the relationship between locking and vesting durations

Also applies to: 485-489

✅ Verification successful

Vesting duration constraints are properly implemented

The code shows that vesting duration constraints are properly handled:

  1. Zero duration check: if (stakesVestingDuration < 7 days) { revert InvalidDuration(); }
  2. Reasonable limits: Minimum of 7 days is enforced as required by TokenVesting contract
  3. Relationship with locking duration: The implementation correctly handles both durations independently:
    • Locking duration for auction tokens is handled by parent contract
    • Vesting duration for stakes is enforced to be at least 7 days
    • If vesting period has expired, tokens are transferred directly instead of being vested
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for duration validation checks
ast-grep --pattern 'function startSale($$$) {
  $$$
  require($duration > 0, $_)
  $$$
}'

# Look for maximum duration constraints
ast-grep --pattern 'function startSale($$$) {
  $$$
  require($duration <= $_maximum, $_)
  $$$
}'

Length of output: 192


Script:

#!/bin/bash
# Search for Solidity files containing StakedLockingCrowdSale contract
fd -e sol | xargs rg -l "contract StakedLockingCrowdSale"

# Search for duration validation patterns in Solidity files
rg -U "require\(.*duration.*[><=].*\)" --type sol

# Search for vesting duration setter or initialization
ast-grep --pattern 'function set$_VestingDuration($$$) {
  $$$
}'

# Look for constructor initialization of vesting duration
ast-grep --pattern 'constructor($$$) {
  $$$
  $_VestingDuration = $_
  $$$
}'

Length of output: 329


Script:

#!/bin/bash
# Let's examine the contract implementation
cat src/crowdsale/StakedLockingCrowdSale.sol

# Also search for any validation patterns with require
rg "require\(" src/crowdsale/StakedLockingCrowdSale.sol

Length of output: 10148

Signed-off-by: Stefan Adolf <stefan@molecule.to>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/crowdsale/LockingCrowdSale.sol (1)

30-34: Consider splitting the Started event for better gas efficiency.

The Started event contains many parameters which could increase gas costs when emitting. Consider splitting it into two events:

  • One for basic sale information
  • One for locking-specific information
-event Started(uint256 indexed saleId, address indexed issuer, Sale sale, TimelockedToken lockingToken, uint256 lockingDuration, uint16 feeBp);
+event SaleStarted(uint256 indexed saleId, address indexed issuer, Sale sale, uint16 feeBp);
+event LockingConfigured(uint256 indexed saleId, TimelockedToken lockingToken, uint256 lockingDuration);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a6b7a19 and ded1b66.

📒 Files selected for processing (1)
  • src/crowdsale/LockingCrowdSale.sol (4 hunks)
🔇 Additional comments (2)
src/crowdsale/LockingCrowdSale.sol (2)

Line range hint 4-16: LGTM! Imports are well-organized and appropriate.

The imports are properly scoped and include all necessary dependencies for the contract's functionality.


Line range hint 4-136: Verify reentrancy protection across token operations.

The contract handles token transfers and external calls. Let's verify the implementation of reentrancy guards.

✅ Verification successful

Let me gather more information about the base contract and its inheritance to verify reentrancy protection.


Based on the results, I can now generate the final response as we have sufficient information about the reentrancy protection:

Reentrancy protection is properly implemented.

The contract inherits from OpenZeppelin's ReentrancyGuard through its base CrowdSale contract, and critical functions that handle tokens are protected with the nonReentrant modifier:

  • settle() function is protected
  • claim() function is protected
  • Token operations in LockingCrowdSale are performed through internal functions called from these protected public functions
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for potential reentrancy vulnerabilities in token operations

# Check for nonReentrant modifiers in functions that handle tokens
echo "Checking for reentrancy protection in token handling functions..."
rg -A 2 "safeTransfer|forceApprove|lock" src/crowdsale/LockingCrowdSale.sol

# Check if the base CrowdSale contract implements reentrancy protection
echo "Checking base contract for reentrancy protection..."
ast-grep --pattern 'contract CrowdSale {
  $$$
  modifier nonReentrant() {
    $$$
  }
  $$$
}'

Length of output: 5353


Script:

#!/bin/bash
# Check CrowdSale.sol for ReentrancyGuard inheritance and usage
echo "Checking CrowdSale.sol imports and inheritance..."
rg -A 5 "contract CrowdSale" src/crowdsale/CrowdSale.sol

# Check for ReentrancyGuard usage in functions that handle tokens in CrowdSale
echo "Checking token handling functions in CrowdSale..."
rg -A 2 "nonReentrant|ReentrancyGuard" src/crowdsale/CrowdSale.sol

# Check implementation of _claimAuctionTokens in base contract
echo "Checking _claimAuctionTokens implementation..."
ast-grep --pattern 'function _claimAuctionTokens($$$) {
  $$$
}'

Length of output: 1519

subgraph mapping code reuse
configures an slcs2 contract 🤷
uses yaml refs to reuse slsc handlers

Signed-off-by: Stefan Adolf <stefan@molecule.to>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (3)
subgraph/subgraph.yaml (1)

214-215: Remove trailing spaces

Remove trailing spaces from line 215 to maintain consistent formatting.

-    mapping: *stakedLockingCrowdSaleMapping
-      
+    mapping: *stakedLockingCrowdSaleMapping
🧰 Tools
🪛 yamllint (1.35.1)

[error] 215-215: trailing spaces

(trailing-spaces)

subgraph/src/lockingCrowdSaleMapping.ts (1)

48-60: Ensure locked token uniqueness
This logic sets the locked token if unset and logs an error if the locked token is mismatched. Consider whether to escalate mismatches beyond a log error (e.g., ignoring subsequent updates or halting processing) for data integrity.

subgraph/src/stakedLockingCrowdSaleMapping.ts (1)

68-71: Potential fragility in parameter indexing
Accessing parameters by numeric index (like 7 for feeBp) can be error-prone if the event signature changes. Consider using a struct or referencing named fields if possible.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ded1b66 and 33cab65.

📒 Files selected for processing (6)
  • script/prod/RolloutV25Sale.sol (1 hunks)
  • src/crowdsale/LockingCrowdSale.sol (4 hunks)
  • subgraph/networks.json (3 hunks)
  • subgraph/src/lockingCrowdSaleMapping.ts (1 hunks)
  • subgraph/src/stakedLockingCrowdSaleMapping.ts (4 hunks)
  • subgraph/subgraph.yaml (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • script/prod/RolloutV25Sale.sol
🧰 Additional context used
🪛 Biome (1.9.4)
subgraph/src/lockingCrowdSaleMapping.ts

[error] 2-2: Do not shadow the global "BigInt" property.

Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.

(lint/suspicious/noShadowRestrictedNames)

🪛 yamllint (1.35.1)
subgraph/subgraph.yaml

[error] 181-181: trailing spaces

(trailing-spaces)


[error] 215-215: trailing spaces

(trailing-spaces)

🔇 Additional comments (23)
subgraph/networks.json (2)

53-56: Placeholder mainnet address still not updated

The placeholder address for LockingCrowdSale that was flagged in a previous review still needs to be addressed.


Line range hint 19-94: Verify start block numbers across networks

Please verify that the start block numbers are correct for the new contracts:

  • Sepolia: 7306191
  • Mainnet: 21431344
  • Foundry: 0

These should correspond to the actual block numbers where these contracts were deployed.

subgraph/subgraph.yaml (4)

143-159: LGTM: Event handlers configuration

The event handlers are well-structured and include all necessary events for the LockingCrowdSale functionality, including the new LockingContractCreated event.


90-90: Verify CrowdSale contract deployment address

Please ensure this address matches the deployed CrowdSale contract on the intended network.

✅ Verification successful

CrowdSale contract address is correctly configured for local development

The address 0x09635F643e140090A9A8Dcd712eD6285858ceBef is properly referenced in the foundry network configuration in networks.json, which is used for local development. This matches the address in the subgraph configuration.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify contract deployment and bytecode match
# Check if contract exists and has bytecode at the specified address
cast code 0x09635F643e140090A9A8Dcd712eD6285858ceBef --rpc-url http://localhost:8545

Length of output: 181


Script:

#!/bin/bash
# Let's verify if this address is referenced in other configuration files or deployment scripts
# This can help validate if the address is consistently used across the project

# Search for the address in all files
rg -i "0x09635F643e140090A9A8Dcd712eD6285858ceBef"

# Check for any deployment scripts or configuration files
fd -e js -e ts -e json "deploy|config" 

Length of output: 374


Script:

#!/bin/bash
# Let's check the networks.json file to understand the network context of this address
cat subgraph/networks.json

# Also check hardhat config for network configurations
cat hardhat.config.js

Length of output: 3360


166-166: Verify StakedLockingCrowdSale contract deployment address

Please ensure this address matches the deployed StakedLockingCrowdSale contract on the intended network.


Line range hint 4-215: Verify network and startBlock configurations

Please confirm that using:

  • network: "foundry"
  • startBlock: 0
    is intentional for all contracts. These settings will affect the subgraph's indexing behavior.
✅ Verification successful

Let me verify the configuration settings by checking the repository for any related configuration files or documentation.

The results will help us understand if these network settings are consistently used across the project and if they are documented somewhere.


Let me check the subgraph-specific documentation and configuration to understand if there's any guidance about the network and startBlock settings.


Let me correct the syntax and try again with proper glob patterns.


Let me check the setup script and environment configuration to understand how the network settings are managed.


Based on the gathered information from the repository, I can now provide a final response:

Network and startBlock configurations are correctly set for local development

The use of "foundry" network and startBlock 0 is intentional as this configuration is specifically for local development:

  • The README confirms this is a development setup using Foundry/Anvil as the local testnet
  • Separate configurations exist for production networks (Sepolia and Mainnet) as shown in the subgraph's README
  • StartBlock 0 is appropriate for local development where you want to index from the chain's beginning

For production deployments, the subgraph is prepared with different configurations using yarn prepare:local for local development and likely other prepare scripts for mainnet/testnet deployments.

🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Check for network configuration in other yaml files
fd -e yaml -e yml | xargs grep -l "network:\|foundry"

# Look for documentation about network configuration
fd "README.md" | xargs grep -i "network\|foundry"

# Check if there are different network configurations in different branches or environments
fd "subgraph.yaml" | xargs grep "network:"

Length of output: 3234


Script:

#!/bin/bash
# Check subgraph documentation
fd -t f -p "**/subgraph/**/README.md" | xargs cat

# Check for any environment-specific subgraph configurations
fd -t f -p "**/subgraph/**/*.example" | xargs cat

# Look for any deployment scripts that might contain network configuration
fd -t f -p "**/subgraph/**/deploy" -p "**/subgraph/**/*.sh" | xargs cat

Length of output: 892


Script:

#!/bin/bash
# Check subgraph documentation
cat subgraph/README.md 2>/dev/null

# Look for setup or deployment scripts
fd -t f "setup.sh|deploy.sh" subgraph/

# Check for any environment files
fd -t f ".env" subgraph/

# Look for any configuration related files
fd -t f "config|manifest" subgraph/

Length of output: 2798


Script:

#!/bin/bash
# Check setup script content
cat subgraph/setup.sh

# Check for environment example file
cat subgraph/.env.example 2>/dev/null

# Look for any prepare scripts that might handle network configuration
fd -t f "prepare" subgraph/ -x cat {}

Length of output: 1189

subgraph/src/lockingCrowdSaleMapping.ts (5)

2-2: False positive on BigInt overshadowing
This usage of "BigInt" from the Graph Protocol is typical and does not shadow the global BigInt in JavaScript.

🧰 Tools
🪛 Biome (1.9.4)

[error] 2-2: Do not shadow the global "BigInt" property.

Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.

(lint/suspicious/noShadowRestrictedNames)


31-39: Validate crowdSale entity existence
This block properly checks for a missing CrowdSale entity before proceeding. Good error handling to avoid null references.


62-68: Initialization of staked amount and type
Setting amountStaked to zero and assigning the crowdSale type to "LOCKING_CROWDSALE" is clear and consistent.


70-89: Combining plain and locking handleStarted
Invoking both plainHandleStarted and lockingHandleStarted ensures that the event logic for plain and locking sales is consistently applied. The approach looks good for reusability.


123-133: Dynamic data source creation for TimelockedToken
Creating a TimelockedToken template with a context is an established pattern in The Graph. The usage of makeERC20Token and makeTimelockedToken is organized and readable.

subgraph/src/stakedLockingCrowdSaleMapping.ts (6)

24-24: LockingStartedEvent import
Importing the LockingStartedEvent keeps the naming consistent with lockingCrowdSaleMapping. No issues found.


27-27: Reusing functions from lockingCrowdSaleMapping
Centralizing logic in lockingCrowdSaleMapping fosters maintainability, though you might ensure consistent naming to reduce confusion in future updates.


36-38: Helpful docstring
Documenting the legacy event scenario clarifies why fees are omitted. This prevents confusion for future maintainers.


78-96: Creating the LockingStartedEvent
Cloning and dispatching the event for locking logic is consistent with the approach in handleStarted. Just ensure the parameter indexes remain accurate when the underlying event changes.


140-151: Delegating claimed logic
handleClaimed simply reuses the generic logic, maintaining consistent behavior across different crowd sale types. Good separation of concerns.


153-157: Delegated handling of lockingContractCreated
Re-routing to lockedHandleLockingContractCreated centralizes the creation logic and avoids code duplication.

src/crowdsale/LockingCrowdSale.sol (6)

4-4: OpenZeppelin imports
Using IERC20 for address-based validations is standard. No immediate concerns.


Line range hint 16-29: Comprehensive contract documentation
The docstring accurately describes LockingCrowdSale’s purpose. This improves readability and eases onboarding for new contributors.


30-30: Public immutable variable
Exposing TIMELOCKED_TOKEN_IMPLEMENTATION as public is convenient for transparency. Ensure it’s not left uninitialized or zero in the constructor.


35-37: Add zero address check in the constructor
Validating that _timelockedTokenImplementation is nonzero prevents accidental deployments with invalid addresses.

 constructor(TimelockedToken _timelockedTokenImplementation) {
+    require(address(_timelockedTokenImplementation) != address(0), "Invalid implementation address");
     TIMELOCKED_TOKEN_IMPLEMENTATION = address(_timelockedTokenImplementation);
 }

44-52: Add critical validations to trustLockingContract
You may want to verify nonzero addresses, ensure no prior registrations, and optionally add an event to capture newly trusted locking contracts.

 function trustLockingContract(IERC20 token, TimelockedToken _timelockedToken) public onlyOwner {
+    require(address(token) != address(0), "Invalid token address");
+    require(address(_timelockedToken) != address(0), "Invalid TimelockedToken address");
+    require(address(lockingContracts[address(token)]) == address(0), "Locking contract already trusted");
     lockingContracts[address(token)] = _timelockedToken;
+    emit LockingContractTrusted(address(token), address(_timelockedToken));
 }

+event LockingContractTrusted(address indexed token, address indexed lockingContract);

133-133: Add error handling for the token initialization
Initialization can fail due to unexpected token behavior. Consider using try-catch for improved error diagnosis.

lockedTokenContract = TimelockedToken(Clones.clone(TIMELOCKED_TOKEN_IMPLEMENTATION));
-lockedTokenContract.initialize(auctionToken);
+try lockedTokenContract.initialize(auctionToken) {
+    emit LockingContractCreated(lockedTokenContract, auctionToken);
+} catch Error(string memory reason) {
+    revert(string.concat("Initialization failed: ", reason));
+} catch {
+    revert("Initialization failed");
+}

Signed-off-by: Stefan Adolf <stefan@molecule.to>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
README.md (1)

212-214: Fix documentation formatting

There are some minor issues in the verification instructions:

  1. Remove duplicate word "crowdsale"
  2. Fix article usage ("a the" → "the")
-Verifying a the staked crowdsale crowdsale
+Verifying the staked crowdsale
🧰 Tools
🪛 LanguageTool

[grammar] ~212-~212: Two determiners in a row. Choose either “a” or “the”.
Context: ....sol:StakedLockingCrowdSale Verifying a the staked crowdsale crowdsaleforge verif...

(DT_DT)


[duplication] ~212-~212: Possible typo: you repeated a word
Context: ...ckingCrowdSale Verifying a the staked crowdsale crowdsaleforge verify-contract --chain-id=11155...

(ENGLISH_WORD_REPEAT_RULE)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 33cab65 and c816611.

📒 Files selected for processing (2)
  • README.md (2 hunks)
  • script/prod/RolloutV25Sale.sol (1 hunks)
🧰 Additional context used
🪛 Markdownlint (0.37.0)
README.md

54-54: null
Bare URL used

(MD034, no-bare-urls)

🪛 Gitleaks (8.21.2)
README.md

52-52: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🪛 LanguageTool
README.md

[grammar] ~212-~212: Two determiners in a row. Choose either “a” or “the”.
Context: ....sol:StakedLockingCrowdSale Verifying a the staked crowdsale crowdsaleforge verif...

(DT_DT)


[duplication] ~212-~212: Possible typo: you repeated a word
Context: ...ckingCrowdSale Verifying a the staked crowdsale crowdsaleforge verify-contract --chain-id=11155...

(ENGLISH_WORD_REPEAT_RULE)

🔇 Additional comments (1)
README.md (1)

49-51: LGTM: Contract addresses documented

The new contract addresses for Locking Crowdsale and Staked Crowdsale are properly documented with verification links.

Signed-off-by: Stefan Adolf <stefan@molecule.to>
@elmariachi111 elmariachi111 force-pushed the feature/hubs-224-crowdsale-with-individual-locking-staking-periods branch from 3dcd036 to 48afc39 Compare December 23, 2024 17:07
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
subgraph/src/stakedLockingCrowdSaleMapping.ts (1)

66-93: Add type information to parameter comments.

The comments for parameters could be more descriptive, especially for complex types like struct Sale. Consider adding the full structure definition in the comments for better maintainability.

-      event.parameters[2], // struct  Sale
+      event.parameters[2], // struct Sale {
+                          //   address auctionToken;
+                          //   uint256 startTime;
+                          //   uint256 endTime;
+                          //   ... // complete the structure
+                          // }
subgraph/abis/LockingCrowdSale.json (4)

1-12: Consider improving parameter naming convention

The constructor parameter _timelockedTokenImplementation uses an underscore prefix. While this is common in Solidity, it's generally better to use consistent naming without underscore prefixes for parameters.

-        "name": "_timelockedTokenImplementation",
+        "name": "timelockedTokenImplementation",

626-772: Consider consolidating Started events

There are two Started events with different parameter sets. This could cause confusion for event listeners and make it harder to track sale starts consistently. Consider:

  1. Consolidating into a single event with optional parameters
  2. Using more distinct names to clarify the difference (e.g., StartedWithLocking and StartedWithoutLocking)

773-854: Enhance error messages with additional context

Consider adding parameters to the following errors to provide more context:

  • BadDecimals: Add expected and actual decimals
  • BadSaleDuration: Add minimum and maximum allowed durations
  • BadSalesAmount: Add minimum and maximum allowed amounts
  • BidTooLow: Add minimum required bid amount
  • FeesTooHigh: Add maximum allowed fee

281-292: Add maximum fee cap safeguard

The setCurrentFeesBp function allows the owner to set fees without an explicit maximum cap in the ABI. While there's a FeesTooHigh error, consider:

  1. Adding a constant for maximum allowed fees
  2. Documenting the fee limits in the ABI
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3dcd036 and 48afc39.

📒 Files selected for processing (7)
  • subgraph/abis/LockingCrowdSale.json (1 hunks)
  • subgraph/abis/StakedLockingCrowdSale.json (4 hunks)
  • subgraph/networks.json (3 hunks)
  • subgraph/package.json (1 hunks)
  • subgraph/schema.graphql (2 hunks)
  • subgraph/src/crowdSaleMapping.ts (1 hunks)
  • subgraph/src/stakedLockingCrowdSaleMapping.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • subgraph/src/crowdSaleMapping.ts
  • subgraph/schema.graphql
  • subgraph/networks.json
🔇 Additional comments (9)
subgraph/package.json (1)

11-11: Version bump aligns with new features.

The version change from 1.2.1 to 1.3.0-dev.1 appropriately reflects the addition of new features (TimelockedToken, StakedLockingCrowdSale) while indicating this is a development release for testing on Sepolia.

Let's verify the contract changes that justify this version bump:

✅ Verification successful

The shell script results confirm the presence of new contract implementations (StakedLockingCrowdSale.sol and LockingCrowdSale.sol) and their deployments in the networks configuration. Let me verify the subgraph schema changes to ensure they support these new contracts.


Let me check the subgraph mappings in a different way to verify the handlers for the new contracts.


Based on the shell script results, I can now generate the final response. The code shows:

  1. New contract implementations for StakedLockingCrowdSale and LockingCrowdSale
  2. Corresponding subgraph mappings (lockingCrowdSaleMapping.ts and stakedLockingCrowdSaleMapping.ts)
  3. Schema updates to support new crowdsale types (SaleType enum with LOCKING_CROWDSALE and STAKED_LOCKING_CROWDSALE)
  4. Deployed contract addresses in networks configuration

Version bump aligns with new features and implementation.

The version change from 1.2.1 to 1.3.0-dev.1 correctly reflects:

  • Minor version bump (1.3.0) for new features (LockingCrowdSale and StakedLockingCrowdSale)
  • Dev suffix (-dev.1) indicating development/testing phase on Sepolia
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the contract changes that justify the version bump

# Check for new contract implementations
echo "Checking for new contract implementations..."
rg -l "contract.*?(TimeLocked|StakedLocking|LockingCrowdSale)"

# Check for contract deployment configurations
echo "Checking deployment configurations..."
fd "networks.json|addresses.json" --exec cat {} 

Length of output: 3425


Script:

#!/bin/bash
# Check subgraph schema and mapping changes
echo "Checking subgraph schema..."
cat subgraph/schema.graphql

echo -e "\nChecking subgraph mappings for new handlers..."
rg -l "class.*(TimeLocked|StakedLocking|LockingCrowdSale)" subgraph/src/

Length of output: 5131


Script:

#!/bin/bash
# Check for mapping files and their content
echo "Listing mapping files..."
fd "\.ts$" subgraph/src/

echo -e "\nChecking mapping content for new handlers..."
fd "\.ts$" subgraph/src/ --exec cat {}

Length of output: 33724

subgraph/abis/StakedLockingCrowdSale.json (4)

2-25: LGTM: Constructor and implementation getter are well-defined

The constructor properly accepts the timelocked token implementation address, and the corresponding getter function follows the constant/immutable pattern naming convention.


309-327: LGTM: Vesting duration getter follows existing patterns

The salesStakeVestingDuration function maintains consistency with the existing salesLockingDuration pattern for duration management.


618-635: Security review needed for trustLockingContract

The trustLockingContract function introduces trust relationships that require careful security considerations:

  1. Access control mechanisms
  2. Trust revocation process
  3. Event emission for transparency
#!/bin/bash
# Description: Verify security controls around trustLockingContract

# Check for access control modifiers
ast-grep --pattern 'function trustLockingContract($$$) {
  $$$
}'

# Look for related events
rg "event.*Trust" --type sol

472-476: Verify the impact of the new stakesVestingDuration parameter

The addition of stakesVestingDuration parameter to startSale looks correct. However, we should verify that all existing calls to this function are updated accordingly.

✅ Verification successful

Based on the search results, I can now generate the final response. The code shows that there are three different startSale function signatures in the StakedLockingCrowdSale contract:

  1. A pure function that reverts with UnsupportedInitializer
  2. A function inherited from parent that takes Sale and lockingDuration
  3. The new implementation that takes additional parameters including stakesVestingDuration

Looking at the test files, all calls to startSale in CrowdSaleLockedStakedTest.t.sol and other test files have been updated to use the new signature with the required parameters. The deployment scripts and production rollout scripts also use the correct signature.

All existing calls to startSale have been properly updated to include the new stakesVestingDuration parameter

  • All test files use the correct function signature with required parameters
  • Deployment scripts (RolloutV25Sale.sol, DeployTokenizer.s.sol) use the updated signature
  • Production scripts are also updated to use the new parameter
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for startSale function calls to ensure they include the new parameter

# Search for startSale function calls
rg "startSale\(" -A 5 --type sol

# Search for test files that might need updates
fd -e sol -e js -e ts | rg -l "startSale"

Length of output: 104


Script:

#!/bin/bash
# Let's try a different approach to find startSale references

# Search for startSale function calls in all files
rg "startSale\(" -A 5

# Also search for test files containing startSale
rg -l "startSale"

# Look for contract deployments or interactions
rg "StakedLockingCrowdSale" -A 5

Length of output: 49775

subgraph/src/stakedLockingCrowdSaleMapping.ts (3)

Line range hint 3-32: LGTM: Import changes are well-structured and necessary.

The new imports support the enhanced functionality for handling both legacy and new contract events.


138-149: LGTM: Clean implementation of claim handling.

The function follows the established pattern and correctly delegates to the generic handler.


151-156: 🛠️ Refactor suggestion

Remove uncertain comment and add type safety checks.

The current implementation has two concerns:

  1. The comment "xing fingers that this works!" suggests uncertainty and should be replaced with proper documentation.
  2. The unchecked type casting could be unsafe if the event structures don't match exactly.

Consider adding type safety checks and proper documentation:

 export function handleLockingContractCreated(
   event: LockingContractCreatedEvent
 ): void {
-  //xing fingers that this works!
+  // Verify event structure before type casting
+  if (!event.parameters || event.parameters.length === 0) {
+    log.error('Invalid event parameters for LockingContractCreated', [])
+    return
+  }
   lockedHandleLockingContractCreated(changetype<LockedLockingContractCreatedEvent>(event))
 }

Let's verify the event structure compatibility:

subgraph/abis/LockingCrowdSale.json (1)

367-422: Verify the pure startSale function implementation

The second startSale overload is marked as pure but takes a Sale struct parameter. This seems incorrect as:

  1. The function likely needs to read or modify contract state
  2. Having two overloads with different state mutability could lead to confusion

Signed-off-by: Stefan Adolf <stefan@molecule.to>
Signed-off-by: Stefan Adolf <stefan@molecule.to>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
README.md (1)

106-111: LGTM with minor grammar improvements.

The documentation clearly explains the evolution of timelocked tokens and provides detailed verification instructions.

Consider these grammar improvements:

-Verifying a the staked crowdsale crowdsale
+Verifying the staked crowdsale

Also applies to: 218-220

🧰 Tools
🪛 LanguageTool

[uncategorized] ~108-~108: Possible missing comma found.
Context: ...ery elegant (and certainly not correct) solution we decided to "trust" external locking ...

(AI_HYDRA_LEO_MISSING_COMMA)


[typographical] ~108-~108: It appears that a comma is missing.
Context: ...another crowdsale instance. During this upgrade we decided to externalize the timelock ...

(DURING_THAT_TIME_COMMA)


[uncategorized] ~108-~108: Use a comma before ‘so’ if it connects two independent clauses (unless they are closely connected and short).
Context: ... externalize the timelock token template so upcoming instances can be verified on c...

(COMMA_COMPOUND_SENTENCE_2)

🪛 Markdownlint (0.37.0)

110-110: Expected: ---; Actual: ---
Horizontal rule style

(MD035, hr-style)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 48afc39 and 9a1c66e.

📒 Files selected for processing (5)
  • README.md (3 hunks)
  • script/prod/RolloutV25Sale.sol (1 hunks)
  • subgraph/networks.json (3 hunks)
  • subgraph/src/crowdSaleMapping.ts (1 hunks)
  • subgraph/subgraph.yaml (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • subgraph/src/crowdSaleMapping.ts
  • subgraph/networks.json
🧰 Additional context used
🪛 Markdownlint (0.37.0)
README.md

54-54: null
Bare URL used

(MD034, no-bare-urls)


110-110: Expected: ---; Actual: ---
Horizontal rule style

(MD035, hr-style)

🪛 Gitleaks (8.21.2)
README.md

52-52: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🪛 LanguageTool
README.md

[uncategorized] ~108-~108: Possible missing comma found.
Context: ...ery elegant (and certainly not correct) solution we decided to "trust" external locking ...

(AI_HYDRA_LEO_MISSING_COMMA)


[typographical] ~108-~108: It appears that a comma is missing.
Context: ...another crowdsale instance. During this upgrade we decided to externalize the timelock ...

(DURING_THAT_TIME_COMMA)


[uncategorized] ~108-~108: Use a comma before ‘so’ if it connects two independent clauses (unless they are closely connected and short).
Context: ... externalize the timelock token template so upcoming instances can be verified on c...

(COMMA_COMPOUND_SENTENCE_2)


[grammar] ~218-~218: Two determiners in a row. Choose either “a” or “the”.
Context: ....sol:StakedLockingCrowdSale Verifying a the staked crowdsale crowdsaleforge verif...

(DT_DT)


[duplication] ~218-~218: Possible typo: you repeated a word
Context: ...ckingCrowdSale Verifying a the staked crowdsale crowdsaleforge verify-contract --chain-id=11155...

(ENGLISH_WORD_REPEAT_RULE)

🪛 yamllint (1.35.1)
subgraph/subgraph.yaml

[error] 181-181: trailing spaces

(trailing-spaces)


[error] 216-216: trailing spaces

(trailing-spaces)

🔇 Additional comments (7)
script/prod/RolloutV25Sale.sol (3)

31-42: Critical: Implement ownership transfer

The ownership transfer to the multisig is commented out:

//lockingCrowdsale.transferOwnership(moleculeDevMultisig);

This is a security risk as the deployer will retain control.


45-64: ⚠️ Potential issue

Critical: Complete trust relationships and ownership setup

Multiple critical configurations are commented out or incomplete:

  1. Missing token address in trustLockingContract
  2. Ownership transfer is commented out
  3. Commented code at the bottom suggests incomplete setup

Apply this diff to implement the missing configurations:

 contract RolloutV25StakedSale is Script {
     function run() public {
         TokenVesting vesting = TokenVesting(0x8f80d1183CD983B01B0C9AC6777cC732Ec9800de);
         
         vm.startBroadcast();
         StakedLockingCrowdSale stakedLockingCrowdSale = new StakedLockingCrowdSale(timelockedTokenImplementation);
         vesting.grantRole(vesting.ROLE_CREATE_SCHEDULE(), address(stakedLockingCrowdSale));
-        //stakedLockingCrowdSale.trustLockingContract(IERC20());
+        stakedLockingCrowdSale.trustLockingContract(IERC20(moleculeDevMultisig));
         stakedLockingCrowdSale.trustVestingContract(vesting);
-        //stakedLockingCrowdSale.transferOwnership(moleculeDevMultisig);
+        stakedLockingCrowdSale.transferOwnership(moleculeDevMultisig);
         vm.stopBroadcast();
 
         console.log("STAKED_LOCKING_CROWDSALE_ADDRESS=%s", address(stakedLockingCrowdSale));
         console.log("timelocked token implementation=%s", address(timelockedTokenImplementation));
-        // vestedDaoToken.grantRole(vestedDaoToken.ROLE_CREATE_SCHEDULE(), address(stakedLockingCrowdSale));
-        // stakedLockingCrowdSale.trustVestingContract(vestedDaoToken);
     }
 }

Likely invalid or redundant comment.


15-18: Verify contract addresses before mainnet deployment

The hardcoded addresses are currently set for Sepolia testnet. Before deploying to mainnet:

  1. Update moleculeDevMultisig to the commented mainnet address (0xCfA0F84660fB33bFd07C369E5491Ab02C449f71B)
  2. Update timelockedTokenImplementation to the appropriate mainnet deployment
✅ Verification successful

Verify contract addresses before mainnet deployment

The review comment is accurate. The code follows the established pattern of using Sepolia addresses during development with clear documentation of mainnet addresses. The mainnet moleculeDevMultisig address (0xCfA0F84660fB33bFd07C369E5491Ab02C449f71B) is consistently used across the codebase in mainnet deployments, as evidenced in RolloutV23.sol and other mainnet configurations.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the contract addresses are valid and deployed

# Check if addresses are valid contracts
for addr in "0xF8F79c1E02387b0Fc9DE0945cD9A2c06F127D851" "0x9d5a6ae551f1117946FF6e0e86ef9A1B20C90Cb0"; do
  echo "Checking $addr..."
  # Get contract bytecode to verify it's a contract
  cast code $addr
done

# Search for any other occurrences of these addresses
echo -e "\nSearching for address usage..."
rg -A 3 "0xF8F79c1E02387b0Fc9DE0945cD9A2c06F127D851|0x9d5a6ae551f1117946FF6e0e86ef9A1B20C90Cb0"

Length of output: 2070


Script:

#!/bin/bash
# Search for deployment configurations and environment-specific addresses
echo "Searching for deployment configurations..."
fd -e json -e js -e ts -e yaml -e yml -e toml | xargs rg -l "address|0x"

echo -e "\nSearching for environment configurations..."
fd "config|env" | xargs rg -l "address|0x"

echo -e "\nSearching for other occurrences of the mainnet address..."
rg "0xCfA0F84660fB33bFd07C369E5491Ab02C449f71B"

Length of output: 1680


Script:

#!/bin/bash
echo "Checking environment configurations..."
cat subgraph/config/mainnet.js
cat subgraph/config/sepolia.js

echo -e "\nChecking RolloutV23.sol for context..."
cat script/prod/RolloutV23.sol

Length of output: 3597

subgraph/subgraph.yaml (3)

90-90: LGTM!

The CrowdSale contract address has been updated correctly.


Line range hint 166-216: LGTM! Well-structured configuration with forward compatibility.

The configuration properly handles:

  1. Both legacy and current Started events
  2. All required event handlers
  3. Provides a clear template for future crowdsale additions
🧰 Tools
🪛 yamllint (1.35.1)

[error] 216-216: trailing spaces

(trailing-spaces)


122-160: ⚠️ Potential issue

Update placeholder contract address

The address is currently set to a placeholder value (0xbaadf00dbaadf00dbaadf00dbaadf00dbaadf00d). This needs to be updated with the actual deployed contract address.

README.md (1)

49-54: LGTM! Well-documented contract updates.

The changes properly document:

  1. New Locking Crowdsale deployment
  2. Updated Staked Crowdsale address
  3. Timelocked token implementation
  4. Historical reference to previous deployment
🧰 Tools
🪛 Markdownlint (0.37.0)

54-54: null
Bare URL used

(MD034, no-bare-urls)

🪛 Gitleaks (8.21.2)

52-52: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

Signed-off-by: Stefan Adolf <stefan@molecule.to>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
script/prod/RolloutV25Sale.s.sol (3)

15-15: Parameterize hardcoded addresses for flexibility and maintainability

The script uses hardcoded addresses for timelockedTokenImplementation (line 15), moleculeDevMultisig (line 18), and vesting (line 48). Using hardcoded addresses can lead to issues when deploying to different networks or environments. Consider parameterizing these addresses, possibly through configuration files or environment variables, to enhance flexibility and ease of deployment across various environments.

Also applies to: 18-18, 48-48


53-53: Remove obsolete commented code for clarity

There are several lines of commented-out code that may no longer be necessary or relevant (lines 53, 60-62). Removing obsolete code improves readability and maintainability of the script.

Apply this diff to remove the unnecessary code:

-    //stakedLockingCrowdSale.trustLockingContract(IERC20());
-    // 0x7c36c64DA1c3a2065074caa9C48e7648FB733aAB
-    // vestedDaoToken.grantRole(vestedDaoToken.ROLE_CREATE_SCHEDULE(), address(stakedLockingCrowdSale));
-    // stakedLockingCrowdSale.trustVestingContract(vestedDaoToken);

Also applies to: 60-62


5-5: Redundant import of console.sol

console.sol is imported explicitly on line 5, but since Script.sol imported on line 4 already includes console.sol, the separate import may be redundant. Removing the redundant import helps reduce unnecessary code.

Apply this diff to remove the redundant import:

-    import "forge-std/console.sol";
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9a1c66e and 1fdc761.

📒 Files selected for processing (2)
  • script/prod/RolloutV25Sale.s.sol (1 hunks)
  • subgraph/package.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • subgraph/package.json
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Smart contract tests

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (3)
subgraph/networks.json (1)

79-82: ⚠️ Potential issue

Critical: Replace placeholder foundry address

The foundry address for LockingCrowdSale is using a placeholder value (0xbaadf00d...). While this is acceptable for testing, ensure it's updated with the actual deployed address.

src/crowdsale/LockingCrowdSale.sol (2)

34-36: 🛠️ Refactor suggestion

Add address validation in constructor.

The constructor should validate that the provided TimelockedToken implementation address is not zero to prevent potential deployment issues.

 constructor(TimelockedToken _timelockedTokenImplementation) {
+    require(address(_timelockedTokenImplementation) != address(0), "Invalid implementation address");
     TIMELOCKED_TOKEN_IMPLEMENTATION = address(_timelockedTokenImplementation);
 }

43-51: ⚠️ Potential issue

Add critical validations to trustLockingContract function.

The function lacks several important security checks:

  1. No validation of input addresses
  2. No check if a contract is already trusted
  3. No verification that the locking contract is compatible
  4. Missing event emission for tracking
+event LockingContractTrusted(address indexed token, address indexed lockingContract);

 function trustLockingContract(IERC20 token, TimelockedToken _timelockedToken) public onlyOwner {
+    require(address(token) != address(0), "Invalid token address");
+    require(address(_timelockedToken) != address(0), "Invalid locking contract address");
+    require(address(lockingContracts[address(token)]) == address(0), "Locking contract already exists");
+    
+    // Verify the locking contract is compatible
+    require(
+        _timelockedToken.UNDERLYING_TOKEN() == token,
+        "Incompatible locking contract"
+    );
+    
     lockingContracts[address(token)] = _timelockedToken;
+    emit LockingContractTrusted(address(token), address(_timelockedToken));
 }
🧹 Nitpick comments (2)
README.md (2)

110-113: Improve grammar in Timelocked Tokens section.

Consider these grammar improvements:

  1. Add "the" before "beginning of 2025"
  2. Add a comma after "During this upgrade"
  3. Add a comma before "so" in the last sentence
-originally the "timelocked token" was an inline concept of the slcs. Timelock contracts weren't reusable among cs impls. This changes as of beginning of 2025. As a rather simple but not very elegant (and certainly not correct) solution we decided to "trust" external locking contracts so you can reuse them among crowdsale instances.
+Originally the "timelocked token" was an inline concept of the slcs. Timelock contracts weren't reusable among cs impls. This changes as of the beginning of 2025. As a rather simple but not very elegant (and certainly not correct) solution, we decided to "trust" external locking contracts, so you can reuse them among crowdsale instances.
🧰 Tools
🪛 LanguageTool

[uncategorized] ~112-~112: Possible missing article found.
Context: ...able among cs impls. This changes as of beginning of 2025. As a rather simple but not ver...

(AI_HYDRA_LEO_MISSING_THE)


[typographical] ~112-~112: It appears that a comma is missing.
Context: ...another crowdsale instance. During this upgrade we decided to externalize the timelock ...

(DURING_THAT_TIME_COMMA)


[uncategorized] ~112-~112: Use a comma before ‘so’ if it connects two independent clauses (unless they are closely connected and short).
Context: ... externalize the timelock token template so upcoming instances can be verified on c...

(COMMA_COMPOUND_SENTENCE_2)


222-224: Fix typo in verification section.

Remove the duplicate word "crowdsale" and fix the article usage:

-Verifying a the staked crowdsale crowdsale
+Verifying the staked crowdsale
🧰 Tools
🪛 LanguageTool

[grammar] ~222-~222: Two determiners in a row. Choose either “a” or “the”.
Context: ....sol:StakedLockingCrowdSale Verifying a the staked crowdsale crowdsaleforge verif...

(DT_DT)


[duplication] ~222-~222: Possible typo: you repeated a word.
Context: ...ckingCrowdSale Verifying a the staked crowdsale crowdsaleforge verify-contract --chain-id=11155...

(ENGLISH_WORD_REPEAT_RULE)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1fdc761 and e9ef600.

📒 Files selected for processing (5)
  • README.md (4 hunks)
  • script/prod/RolloutV25Sale.s.sol (1 hunks)
  • src/crowdsale/LockingCrowdSale.sol (3 hunks)
  • subgraph/networks.json (3 hunks)
  • subgraph/package.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • subgraph/package.json
  • script/prod/RolloutV25Sale.s.sol
🧰 Additional context used
🪛 Gitleaks (8.21.2)
README.md

20-20: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


56-56: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🪛 Markdownlint (0.37.0)
README.md

58-58: null
Bare URL used

(MD034, no-bare-urls)


114-114: Expected: ---; Actual: ---
Horizontal rule style

(MD035, hr-style)

🪛 LanguageTool
README.md

[uncategorized] ~112-~112: Possible missing article found.
Context: ...able among cs impls. This changes as of beginning of 2025. As a rather simple but not ver...

(AI_HYDRA_LEO_MISSING_THE)


[typographical] ~112-~112: It appears that a comma is missing.
Context: ...another crowdsale instance. During this upgrade we decided to externalize the timelock ...

(DURING_THAT_TIME_COMMA)


[uncategorized] ~112-~112: Use a comma before ‘so’ if it connects two independent clauses (unless they are closely connected and short).
Context: ... externalize the timelock token template so upcoming instances can be verified on c...

(COMMA_COMPOUND_SENTENCE_2)


[grammar] ~222-~222: Two determiners in a row. Choose either “a” or “the”.
Context: ....sol:StakedLockingCrowdSale Verifying a the staked crowdsale crowdsaleforge verif...

(DT_DT)


[duplication] ~222-~222: Possible typo: you repeated a word.
Context: ...ckingCrowdSale Verifying a the staked crowdsale crowdsaleforge verify-contract --chain-id=11155...

(ENGLISH_WORD_REPEAT_RULE)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Smart contract tests
🔇 Additional comments (6)
subgraph/networks.json (2)

23-26: LGTM!

The Sepolia network configuration for LockingCrowdSale is properly defined with a valid address and start block.


53-56: LGTM!

The Mainnet network configuration for LockingCrowdSale is properly defined with a valid address and start block.

src/crowdsale/LockingCrowdSale.sol (2)

4-4: LGTM!

The import of IERC20 from OpenZeppelin is appropriate for token operations.


29-29: LGTM!

The immutable public variable follows proper naming conventions and visibility.

README.md (2)

17-17: LGTM!

The Mainnet Locking Crowdsale entry is properly documented with matching address and thirdweb badge.


53-54: LGTM!

The Sepolia contract entries are properly documented with matching addresses and thirdweb badges.

@elmariachi111 elmariachi111 force-pushed the feature/hubs-224-crowdsale-with-individual-locking-staking-periods branch from e9ef600 to 69591bb Compare January 9, 2025 16:02
Signed-off-by: Stefan Adolf <stefan@molecule.to>
@elmariachi111 elmariachi111 force-pushed the feature/hubs-224-crowdsale-with-individual-locking-staking-periods branch from 69591bb to 46fba8d Compare January 9, 2025 16:03
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
src/crowdsale/LockingCrowdSale.sol (3)

34-36: ⚠️ Potential issue

Add address validation in constructor.

The constructor should validate that the provided TimelockedToken implementation address is not zero to prevent potential deployment issues.

 constructor(TimelockedToken _timelockedTokenImplementation) {
+    require(address(_timelockedTokenImplementation) != address(0), "Invalid implementation address");
     TIMELOCKED_TOKEN_IMPLEMENTATION = address(_timelockedTokenImplementation);
 }

43-51: ⚠️ Potential issue

Add critical validations to trustLockingContract function.

The function lacks several important security checks:

  1. No validation of input addresses
  2. No check if a contract is already trusted
  3. No verification that the locking contract is compatible
  4. Missing event emission for tracking
 function trustLockingContract(IERC20 token, TimelockedToken _timelockedToken) public onlyOwner {
+    require(address(token) != address(0), "Invalid token address");
+    require(address(_timelockedToken) != address(0), "Invalid locking contract address");
+    require(address(lockingContracts[address(token)]) == address(0), "Locking contract already exists");
+    
+    // Verify the locking contract is compatible
+    require(
+        _timelockedToken.UNDERLYING_TOKEN() == token,
+        "Incompatible locking contract"
+    );
+    
     lockingContracts[address(token)] = _timelockedToken;
+    emit LockingContractTrusted(address(token), address(_timelockedToken));
 }

+event LockingContractTrusted(address indexed token, address indexed lockingContract);

132-135: ⚠️ Potential issue

Add error handling for external calls in _makeNewLockedTokenContract.

The initialization call could fail but there's no error handling. Consider adding try-catch to handle potential initialization failures gracefully.

 function _makeNewLockedTokenContract(IERC20Metadata auctionToken) private returns (TimelockedToken lockedTokenContract) {
     lockedTokenContract = TimelockedToken(Clones.clone(TIMELOCKED_TOKEN_IMPLEMENTATION));
-    lockedTokenContract.initialize(auctionToken);
+    try lockedTokenContract.initialize(auctionToken) {
+        emit LockingContractCreated(lockedTokenContract, auctionToken);
+    } catch Error(string memory reason) {
+        revert(string.concat("Initialization failed: ", reason));
+    } catch {
+        revert("Initialization failed");
+    }
-    emit LockingContractCreated(lockedTokenContract, auctionToken);
 }
🧹 Nitpick comments (1)
README.md (1)

112-112: Fix grammatical issues in documentation.

Several grammatical issues need to be addressed:

  1. Missing article: "as of the beginning of 2025"
  2. Missing comma: "solution, we decided"
  3. Missing comma: "upgrade, we decided"
  4. Missing comma before 'so'

Apply these corrections:

-originally the "timelocked token" was an inline concept of the slcs. Timelock contracts weren't reusable among cs impls. This changes as of beginning of 2025. As a rather simple but not very elegant (and certainly not correct) solution we decided to "trust" external locking contracts so upcoming instances can be verified on chain.
+Originally, the "timelocked token" was an inline concept of the SLCs. Timelock contracts weren't reusable among crowdsale implementations. This changes as of the beginning of 2025. As a rather simple but not very elegant (and certainly not correct) solution, we decided to "trust" external locking contracts, so upcoming instances can be verified on chain.
🧰 Tools
🪛 LanguageTool

[uncategorized] ~112-~112: You might be missing the article “the” here.
Context: ...able among cs impls. This changes as of beginning of 2025. As a rather simple but not ver...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)


[uncategorized] ~112-~112: A comma might be missing here.
Context: ...ery elegant (and certainly not correct) solution we decided to "trust" external locking ...

(AI_EN_LECTOR_MISSING_PUNCTUATION_COMMA)


[typographical] ~112-~112: It appears that a comma is missing.
Context: ...another crowdsale instance. During this upgrade we decided to externalize the timelock ...

(DURING_THAT_TIME_COMMA)


[uncategorized] ~112-~112: Use a comma before ‘so’ if it connects two independent clauses (unless they are closely connected and short).
Context: ... externalize the timelock token template so upcoming instances can be verified on c...

(COMMA_COMPOUND_SENTENCE_2)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e9ef600 and 46fba8d.

📒 Files selected for processing (5)
  • README.md (4 hunks)
  • script/prod/RolloutV25Sale.s.sol (1 hunks)
  • src/crowdsale/LockingCrowdSale.sol (3 hunks)
  • subgraph/networks.json (3 hunks)
  • subgraph/package.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • subgraph/package.json
  • script/prod/RolloutV25Sale.s.sol
  • subgraph/networks.json
🧰 Additional context used
🪛 Gitleaks (8.21.2)
README.md

20-20: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


56-56: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🪛 Markdownlint (0.37.0)
README.md

58-58: null
Bare URL used

(MD034, no-bare-urls)


114-114: Expected: ---; Actual: ---
Horizontal rule style

(MD035, hr-style)

🪛 LanguageTool
README.md

[uncategorized] ~112-~112: You might be missing the article “the” here.
Context: ...able among cs impls. This changes as of beginning of 2025. As a rather simple but not ver...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)


[uncategorized] ~112-~112: A comma might be missing here.
Context: ...ery elegant (and certainly not correct) solution we decided to "trust" external locking ...

(AI_EN_LECTOR_MISSING_PUNCTUATION_COMMA)


[typographical] ~112-~112: It appears that a comma is missing.
Context: ...another crowdsale instance. During this upgrade we decided to externalize the timelock ...

(DURING_THAT_TIME_COMMA)


[uncategorized] ~112-~112: Use a comma before ‘so’ if it connects two independent clauses (unless they are closely connected and short).
Context: ... externalize the timelock token template so upcoming instances can be verified on c...

(COMMA_COMPOUND_SENTENCE_2)

🔇 Additional comments (4)
src/crowdsale/LockingCrowdSale.sol (1)

4-4: LGTM! Import changes look good.

The addition of IERC20 import from OpenZeppelin is appropriate for the new functionality.

README.md (3)

17-20: Review duplicate crowdsale implementations.

There appear to be multiple crowdsale implementations deployed:

  • Locking Crowdsale
  • StakedLockingCrowdSale

This matches the past review comment about duplicate crowdsales. Consider documenting the differences between these implementations and their specific use cases to avoid confusion.

Let's verify the differences between these implementations:

#!/bin/bash
# Description: Compare the implementations of different crowdsale contracts
# Expected: Different contract interfaces and functionality

# Search for contract definitions
ast-grep --pattern 'contract LockingCrowdSale {
  $$$
}'

ast-grep --pattern 'contract StakedLockingCrowdSale {
  $$$
}'
🧰 Tools
🪛 Gitleaks (8.21.2)

20-20: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


110-113: Document technical debt and migration plan.

The Timelocked Tokens section acknowledges technical debt:

  • "not very elegant (and certainly not correct) solution"
  • External locking contracts are being "trusted"

Consider:

  1. Documenting the known limitations and risks
  2. Creating a roadmap for addressing these issues
  3. Adding validation checks for trusted contracts

Would you like me to help create a detailed technical specification for a more robust implementation?

🧰 Tools
🪛 LanguageTool

[uncategorized] ~112-~112: You might be missing the article “the” here.
Context: ...able among cs impls. This changes as of beginning of 2025. As a rather simple but not ver...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)


[uncategorized] ~112-~112: A comma might be missing here.
Context: ...ery elegant (and certainly not correct) solution we decided to "trust" external locking ...

(AI_EN_LECTOR_MISSING_PUNCTUATION_COMMA)


[typographical] ~112-~112: It appears that a comma is missing.
Context: ...another crowdsale instance. During this upgrade we decided to externalize the timelock ...

(DURING_THAT_TIME_COMMA)


[uncategorized] ~112-~112: Use a comma before ‘so’ if it connects two independent clauses (unless they are closely connected and short).
Context: ... externalize the timelock token template so upcoming instances can be verified on c...

(COMMA_COMPOUND_SENTENCE_2)


222-224: LGTM: Clear verification instructions added.

The new instructions for verifying the staked crowdsale contract are clear and include the necessary constructor arguments.

| StakedLockingCrowdSale | [0x35Bce29F52f51f547998717CD598068Afa2B29B7](https://etherscan.io/address/0x35Bce29F52f51f547998717CD598068Afa2B29B7#code) | <a href="https://thirdweb.com/ethereum/0x35Bce29F52f51f547998717CD598068Afa2B29B7?utm_source=contract_badge" target="_blank"><img width="200" height="45" src="https://badges.thirdweb.com/contract?address=0x35Bce29F52f51f547998717CD598068Afa2B29B7&theme=dark&chainId=1" alt="View contract" /></a> |

timelocked token implementation=0x625ed621d814645AA81C50c4f333D4a407576e8F
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Security: Remove exposed API keys.

The static analysis tool detected potential API keys in the documentation. While these appear to be example/placeholder values, it's best practice to use environment variables or configuration files for such sensitive information.

Replace the API keys with placeholders:

-timelocked token implementation=0x625ed621d814645AA81C50c4f333D4a407576e8F
+timelocked token implementation=${TIMELOCK_IMPLEMENTATION_ADDRESS}

Also applies to: 56-56

🧰 Tools
🪛 Gitleaks (8.21.2)

20-20: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

@elmariachi111 elmariachi111 merged commit 4589881 into main Jan 9, 2025
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants