Skip to content

Comments

Feat: Create Backend API Endpoint for Fundraising Campaign Creation#13

Open
gelluisaac wants to merge 5 commits intoFundable-Protocol:devfrom
gelluisaac:feat
Open

Feat: Create Backend API Endpoint for Fundraising Campaign Creation#13
gelluisaac wants to merge 5 commits intoFundable-Protocol:devfrom
gelluisaac:feat

Conversation

@gelluisaac
Copy link

@gelluisaac gelluisaac commented Jul 24, 2025

This PR implements the backend API endpoint that interfaces with our Cairo smart contract's create_campaign function. The new endpoint handles campaign creation requests from the frontend and interacts with the StarkNet blockchain to deploy new fundraising campaigns.

Features Implemented
API Endpoint
Method: POST
Path: /api/v1/campaigns
Authentication: JWT token required
Rate Limiting: 5 campaigns per user per hour

Request/Response Schema
Request Body:
{
"campaign_ref": "string",
"target_amount": "string",
"donation_token": "string"
}

Success Response:
{
"success": true,
"data": {
"campaign_id": "string",
"campaign_ref": "string",
"target_amount": "string",
"donation_token": "string",
"transaction_hash": "string",
"created_at": "ISO 8601 timestamp"
}
}

Error Response:
{
"success": false,
"error": {
"code": "string",
"message": "string",
"details": {}
}
}

Acceptance Criteria Fulfilled
Core Functionality
API endpoint accepts valid campaign creation requests
Successfully interfaces with Cairo smart contract
Returns proper campaign ID from blockchain transaction
Implements all required validations
Handles all error scenarios gracefully
Includes comprehensive logging
Rate limiting implemented (5 campaigns per user per hour)

Summary by CodeRabbit

  • New Features

    • Introduced campaign creation API with input validation, authentication, and rate limiting (max 5 requests per user per hour).
    • Campaigns are now created on-chain via StarkNet and stored in the database with full audit logging.
    • Added blockchain utilities for verifying token contracts and checking wallet balances.
    • Added smart contract ABI for token distribution and related operations.
    • Added user authentication middleware for JWT token verification.
    • Added rate limiting middleware to control campaign creation frequency per user.
    • Added enhanced routing structure consolidating multiple API endpoints under versioned routes.
  • Chores

    • Updated dependencies to include support for Joi validation and StarkNet interactions.
  • Documentation

    • Added comprehensive type definitions for authentication, campaigns, and blockchain interactions.

@coderabbitai
Copy link

coderabbitai bot commented Jul 24, 2025

Walkthrough

This update introduces a comprehensive campaign creation feature, including blockchain integration with StarkNet, input validation, rate limiting, authentication, and database persistence. New middleware, utility modules, entity definitions, and TypeScript types are added. The routing structure is refactored to support campaign endpoints, and several supporting packages and ABI files are introduced.

Changes

File(s) Change Summary
package.json Added dependencies: joi and starknet.
src/components/v1/routes.v1.ts, src/index.ts Refactored router import and registration for campaign routes.
src/components/v1/campaigns/routes.v1.ts New router module aggregating platform, wallet, distribution, and campaign subroutes.
src/components/v1/campaigns/campaigns.routes.ts New Express router for /campaigns with authentication and rate limiting.
src/components/v1/campaigns/campaigns.controller.ts New controller for campaign creation: validates input, checks uniqueness, verifies blockchain, persists data.
src/components/v1/campaigns/campaign.entity.ts New TypeORM entity for campaign records.
src/components/v1/campaigns/campaignRequest.entity.ts New TypeORM entity for campaign request records (rate limiting).
src/components/v1/campaigns/campaigns.db.ts New DB helpers: uniqueness check, save campaign, track and count user requests for rate limiting.
src/components/v1/campaigns/campaigns.validation.ts New Joi schema and validation function for campaign input.
src/appMiddlewares/auth.middleware.ts New JWT authentication middleware and AuthUser interface.
src/appMiddlewares/rateLimit.middleware.ts New middleware enforcing per-user campaign creation rate limits.
src/utils/blockchainUtils.ts New utilities: get wallet balance, verify ERC20 token contracts on StarkNet.
src/utils/helper.ts New helpers: u256 conversion and StarkNet contract address validation.
src/utils/starknetService.ts New service: interacts with StarkNet to create campaigns on-chain with retry and error handling.
src/utils/distributor.abi.json Added full ABI for a distributor smart contract (token distribution, ownership, upgradeability, events, etc).
src/types/express/index.d.ts Augmented Express Request type to include optional user property.
src/types/auth.ts New AuthUser interface.
src/types/campaign/index.ts New campaign-related TypeScript interfaces: campaign data, U256, params, events, receipts, errors.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant API as Express API
    participant Auth as Auth Middleware
    participant Rate as Rate Limit Middleware
    participant Validator as Validator
    participant DB as Database
    participant Blockchain as StarkNet Service

    Client->>API: POST /campaigns (with JWT)
    API->>Auth: Authenticate JWT
    Auth-->>API: Attach req.user or 401 error
    API->>Rate: Check rate limit (user ID)
    Rate-->>API: Allow or 429 error
    API->>Validator: Validate input (Joi)
    Validator-->>API: Validation result
    API->>DB: Check campaign_ref uniqueness
    DB-->>API: Uniqueness result
    API->>Blockchain: Verify donation_token contract
    Blockchain-->>API: Verification result
    API->>Blockchain: Get user wallet balance
    Blockchain-->>API: Balance result
    API->>Blockchain: Create campaign on-chain
    Blockchain-->>API: Transaction receipt or error
    API->>DB: Save campaign metadata
    DB-->>API: Save result
    API->>DB: Log user campaign request
    DB-->>API: Log result
    API-->>Client: 201 Created (campaign details) or error
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Suggested reviewers

  • mubarak23

Poem

In the warren of code, a new path appears,
Campaigns are born with blockchain cheers!
With tokens and checks, and rate limits, too—
The rabbits ensure only five can get through.
From wallet to chain, and database deep,
This fluffy release is robust and neat!
🐇✨

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 0110857 and 869eb65.

📒 Files selected for processing (3)
  • src/components/v1/campaigns/campaign.entity.ts (1 hunks)
  • src/components/v1/campaigns/campaignRequest.entity.ts (1 hunks)
  • src/components/v1/distribution/distribution.controller.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/components/v1/distribution/distribution.controller.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/v1/campaigns/campaignRequest.entity.ts
  • src/components/v1/campaigns/campaign.entity.ts
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 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.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @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.

@gelluisaac gelluisaac marked this pull request as draft July 24, 2025 07: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: 18

🧹 Nitpick comments (3)
src/components/v1/routes.v1.ts (1)

5-5: Fix the typo in distributions import path.

There's a typo in the existing import: distrubtion.routes should be distribution.routes.

-import distributionRoutes from "./distribution/distrubtion.routes"
+import distributionRoutes from "./distribution/distribution.routes"
src/components/v1/campaigns.controller.ts (1)

75-75: Initialize variables with proper types

Variables should be initialized or properly typed to avoid potential issues.

-    let campaign_id, transaction_hash;
+    let campaign_id: string;
+    let transaction_hash: string;
src/utils/starknetService.ts (1)

11-11: Consider making RPC endpoint configurable

The hardcoded public RPC endpoint may have rate limits and reliability issues. Consider using an environment variable.

 const provider = new RpcProvider({
-  nodeUrl: 'https://starknet-mainnet.public.blastapi.io/rpc/v0_6', // Example public mainnet RPC endpoint
+  nodeUrl: process.env.STARKNET_RPC_URL || 'https://starknet-mainnet.public.blastapi.io/rpc/v0_6',
 });
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 6203e35 and 638c9de.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (10)
  • package.json (1 hunks)
  • src/components/v1/campaigns.controller.ts (1 hunks)
  • src/components/v1/campaigns.db.ts (1 hunks)
  • src/components/v1/campaigns.routes.ts (1 hunks)
  • src/components/v1/campaigns.validation.ts (1 hunks)
  • src/components/v1/routes.v1.ts (1 hunks)
  • src/types/express/index.d.ts (1 hunks)
  • src/utils/blockchainUtils.ts (1 hunks)
  • src/utils/helper.ts (1 hunks)
  • src/utils/starknetService.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/types/express/index.d.ts (4)
src/types/global.ts (2)
  • IRequest (79-89)
  • IToken (23-31)
src/components/v1/user/user.entity.ts (1)
  • UserEntity (6-36)
src/migrations/CreateCoreEntities.js (1)
  • up (6-94)
src/components/v1/wallet/wallet.entity.ts (1)
  • WalletEntity (8-55)
src/utils/blockchainUtils.ts (2)
src/components/v1/wallet/wallet.entity.ts (1)
  • WalletEntity (8-55)
src/migrations/CreateCoreEntities.js (1)
  • up (6-94)
🔇 Additional comments (7)
src/components/v1/routes.v1.ts (2)

6-6: LGTM: Campaign routes import follows established pattern.

The import statement is correctly structured and consistent with other route imports in the file.


13-13: LGTM: Campaign routes registration is properly implemented.

The route registration follows the same pattern as other routes and correctly maps campaigns to the /campaigns path prefix.

src/types/express/index.d.ts (1)

10-12: No Conflicts: Global Request Augmentation and IRequest Coexist Cleanly

The declaration in src/types/express/index.d.ts augments Express.Request with user: User, which lets untyped middleware (e.g. rate-limit’s keyGenerator) safely access req.user. Your existing IRequest in src/types/global.ts then extends that already-augmented Request with its own properties (decoded?, fingerprint?, Wallet?).

src/types/express/index.d.ts: merges user: User into every Express.Request
src/types/global.ts: exports IRequest extends Request to add session-specific fields
– Middleware/controllers correctly type req: IRequest and non-typed code still sees req.user

These two patterns layer without conflict. No changes needed here.

src/components/v1/campaigns.routes.ts (1)

24-24: Route path looks correct

The route path '/campaigns' is correct as it will be mounted under the version prefix in the main router, resulting in the full path '/api/v1/campaigns' as specified in the PR objectives.

src/components/v1/campaigns.validation.ts (1)

36-36: Contract address validation pattern is correct

The regex pattern correctly validates StarkNet contract addresses with 0x prefix and 64 hexadecimal characters.

src/components/v1/campaigns.controller.ts (1)

119-124: Audit log implementation looks good

The audit logging for campaign creation with relevant details is well-implemented and follows best practices.

src/utils/starknetService.ts (1)

35-39: Verify the contract method call parameters

The contract call should match the expected Cairo contract interface exactly.

Please verify that the create_campaign method in your Cairo contract expects these exact parameters in this order:

  1. campaign_ref (string)
  2. target_amount (U256 struct)
  3. donation_token (contract address)

Also ensure the method name matches exactly (case-sensitive).

@gelluisaac
Copy link
Author

gelluisaac commented Jul 24, 2025

@mubarak23 can i get the contract abi so i can push with the code rabbit review? with the contract address so i can test

@gelluisaac gelluisaac marked this pull request as ready for review July 25, 2025 12:28
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: 12

♻️ Duplicate comments (2)
src/types/express/index.d.ts (1)

1-12: User type consolidation still needed.

This implementation correctly extends the Express Request interface, but the previous review comment about consolidating multiple user types across the codebase remains valid.

src/utils/starknetService.ts (1)

120-124: Private key management still needs implementation

This placeholder must be replaced with secure key management before production deployment.

🧹 Nitpick comments (2)
src/components/v1/campaigns/campaigns.db.ts (2)

4-4: Fix import formatting and organization.

Missing space after comma in import statement, and imports should be organized at the top of the file.

-import { Campaign} from './campaign.entity'
+import { Campaign } from './campaign.entity';

14-15: Move imports to the top of the file.

Imports should be organized at the beginning of the file for better readability.

+import { CampaignData } from '../../../types/campaign';

// Check if campaign_ref is unique
export async function isCampaignRefUnique(campaign_ref: string): Promise<boolean> {
  // ... function body
}

// Save campaign metadata to DB
-import { CampaignData } from '../../../types/campaign';
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 638c9de and 114edac.

📒 Files selected for processing (16)
  • package.json (1 hunks)
  • src/appMiddlewares/auth.middleware.ts (1 hunks)
  • src/appMiddlewares/rateLimit.middleware.ts (1 hunks)
  • src/components/v1/campaigns/campaign.entity.ts (1 hunks)
  • src/components/v1/campaigns/campaigns.controller.ts (1 hunks)
  • src/components/v1/campaigns/campaigns.db.ts (1 hunks)
  • src/components/v1/campaigns/campaigns.routes.ts (1 hunks)
  • src/components/v1/campaigns/campaigns.validation.ts (1 hunks)
  • src/components/v1/campaigns/routes.v1.ts (1 hunks)
  • src/index.ts (1 hunks)
  • src/types/auth.ts (1 hunks)
  • src/types/campaign/index.ts (1 hunks)
  • src/types/express/index.d.ts (1 hunks)
  • src/utils/blockchainUtils.ts (1 hunks)
  • src/utils/distributor.abi.json (1 hunks)
  • src/utils/starknetService.ts (1 hunks)
✅ Files skipped from review due to trivial changes (6)
  • src/types/auth.ts
  • src/index.ts
  • src/components/v1/campaigns/routes.v1.ts
  • src/components/v1/campaigns/campaign.entity.ts
  • src/types/campaign/index.ts
  • src/utils/distributor.abi.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • package.json
🧰 Additional context used
🧬 Code Graph Analysis (5)
src/appMiddlewares/rateLimit.middleware.ts (1)
src/components/v1/campaigns/campaigns.db.ts (2)
  • getUserCampaignCountLastHour (57-62)
  • saveUserCampaignRequest (51-55)
src/types/express/index.d.ts (1)
src/appMiddlewares/auth.middleware.ts (1)
  • AuthUser (6-9)
src/utils/starknetService.ts (1)
src/types/campaign/index.ts (3)
  • CreateCampaignParams (16-21)
  • TransactionReceipt (28-31)
  • StarknetError (33-37)
src/appMiddlewares/auth.middleware.ts (1)
src/types/auth.ts (1)
  • AuthUser (2-6)
src/components/v1/campaigns/campaigns.db.ts (2)
dist/config/persistence/data-source.js (1)
  • AppDataSource (18-40)
src/types/campaign/index.ts (1)
  • CampaignData (1-9)
🔇 Additional comments (14)
src/components/v1/campaigns/campaigns.controller.ts (5)

12-24: Input validation implementation looks good!

The validation is properly structured with clear error responses and appropriate status codes.


26-38: Campaign reference uniqueness check is well implemented!

Proper use of 409 Conflict status for duplicate references with clear error messaging.


62-82: Excellent two-stage token validation!

Good practice to validate address format before making network calls to verify the contract on-chain.


84-119: Robust blockchain interaction with comprehensive error handling!

Excellent error mapping from contract-specific errors to appropriate HTTP status codes.


140-151: Proper success response structure!

Correct use of HTTP 201 status with comprehensive campaign data in the response.

src/components/v1/campaigns/campaigns.validation.ts (3)

4-15: Well-structured campaign reference validation!

Good use of trim, length validation, and regex to ensure no whitespace.


35-42: Correct StarkNet address validation!

The regex pattern accurately validates StarkNet contract address format.


16-34: Add error handling for BigInt conversion

The BigInt conversion could throw if the string is invalid, even with the pattern check.

     .custom((value, helpers) => {
+      try {
         if (BigInt(value) <= 0n) {
           return helpers.error('any.invalid');
         }
         // Optionally, check if value fits u256
         if (BigInt(value) > (2n ** 256n - 1n)) {
           return helpers.error('any.invalid');
         }
         return value;
+      } catch (error) {
+        return helpers.error('any.invalid');
+      }
     }, 'u256 validation')

Likely an incorrect or invalid review comment.

src/utils/starknetService.ts (4)

5-19: Great job addressing the previous review comments!

The CONTRACT_ADDRESS environment variable validation and ABI loading error handling have been properly implemented.


37-75: Excellent retry logic implementation!

Well-structured exponential backoff with jitter and selective retry based on error types.


102-117: Error mapping properly implemented!

Good coverage of common StarkNet error patterns with structured error responses.


90-99: I don’t see any custom parsing of raw StarkNet event data into named fields like campaign_id. The TransactionReceipt and CampaignEvent types assume data.campaign_id is already a string, but StarkNet’s raw receipts encode event data as hex‐felt arrays. You’ll need to surface where you deserialize those raw events into your CampaignEvent shape and ensure you convert any hex/felt values to human‐readable strings (e.g. via BigInt(hex).toString()). Otherwise, extractCampaignIdFromReceipt may return hex prefixed IDs or throw if the raw data isn’t pre‐converted.

Please:
• Locate the code that transforms StarkNet’s raw events array into your CampaignEvent.data object.
• Add explicit handling for hex/felt values (e.g. BigInt(hexValue).toString()).
• Update tests (or add new ones) to cover a hex‐encoded campaign_id case.

src/utils/blockchainUtils.ts (2)

30-47: Excellent implementation addressing previous concerns!

The function now properly queries the blockchain for balance with safe error handling that returns zero balance on failure.


50-59: Token verification properly implemented!

Good approach using the symbol method call to verify ERC20 contracts, addressing the previous security concern.

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 (1)
src/appMiddlewares/rateLimit.middleware.ts (1)

16-30: Race condition still exists despite previous feedback.

While the premature logging issue has been addressed, the race condition mentioned in previous reviews still exists. Multiple concurrent requests can pass the count check simultaneously before any database updates occur.

Consider implementing atomic operations or using Redis with INCR and EXPIRE for more reliable rate limiting:

// Alternative approach using database-level atomic operations
const count = await AppDataSource.transaction(async manager => {
  const repo = manager.getRepository(CampaignRequest);
  const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000);
  const currentCount = await repo.count({ 
    where: { user_id: userId, created_at: MoreThan(oneHourAgo) } 
  });
  
  if (currentCount >= 5) {
    throw new Error('RATE_LIMIT_EXCEEDED');
  }
  
  return currentCount;
});
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 114edac and e079792.

📒 Files selected for processing (6)
  • src/appMiddlewares/auth.middleware.ts (1 hunks)
  • src/appMiddlewares/rateLimit.middleware.ts (1 hunks)
  • src/components/v1/campaigns/campaignRequest.entity.ts (1 hunks)
  • src/components/v1/campaigns/campaigns.controller.ts (1 hunks)
  • src/components/v1/campaigns/campaigns.db.ts (1 hunks)
  • src/components/v1/campaigns/campaigns.routes.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/appMiddlewares/auth.middleware.ts
  • src/components/v1/campaigns/campaigns.routes.ts
  • src/components/v1/campaigns/campaigns.db.ts
  • src/components/v1/campaigns/campaigns.controller.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/appMiddlewares/rateLimit.middleware.ts (1)
src/components/v1/campaigns/campaigns.db.ts (1)
  • getUserCampaignCountLastHour (64-73)
🔇 Additional comments (2)
src/appMiddlewares/rateLimit.middleware.ts (2)

31-41: LGTM - Error handling is properly implemented.

The error handling correctly catches database failures and returns appropriate error responses with consistent structure.


6-15: LGTM - Authentication check is properly implemented.

The middleware correctly validates user authentication and returns appropriate 401 responses when authentication is missing.

@gelluisaac
Copy link
Author

@mubarak23 Pr is ready for review

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.

1 participant