Skip to content

docs: Add comprehensive CONTRIBUTING.md for Base subscription protocol development#4

Open
Kubudak90 wants to merge 29 commits into
karinasvatk:mainfrom
Kubudak90:add-contributing-guide
Open

docs: Add comprehensive CONTRIBUTING.md for Base subscription protocol development#4
Kubudak90 wants to merge 29 commits into
karinasvatk:mainfrom
Kubudak90:add-contributing-guide

Conversation

@Kubudak90
Copy link
Copy Markdown

Summary

This PR adds a comprehensive CONTRIBUTING.md guide to help developers understand and contribute to SubBase's decentralized subscription infrastructure on Base L2.

What's Included

Development Environment

  • Prerequisites: Foundry, Node.js, Git
  • Installation instructions with dependencies
  • Environment configuration template
  • Quick start commands (build, test, format, lint)

Architecture Overview

  • Contract structure documentation
  • Subscription lifecycle explanation
  • UUPS upgrade pattern details
  • Key entities: Plans, Subscriptions, Charges, Automation

Contributing Guidelines

  • Types of contributions welcome
  • Development workflow (fork → branch → PR)
  • Solidity coding standards with examples
  • Conventional Commits format with examples
  • Type and scope definitions

Testing

  • Test structure documentation
  • Foundry test examples with best practices
  • Fuzz testing guidelines
  • Coverage requirements (90% line, 100% critical)

Security

  • Security checklist for PRs
  • Vulnerability disclosure process
  • Audit history table
  • Slither and static analysis guidelines

Deployment

  • Local testing with Anvil
  • Testnet deployment instructions
  • Mainnet deployment notes

Community

  • Communication channels
  • Contributor recognition
  • Code of Conduct reference
  • Resources and related projects

Why This Matters

SubBase is a production protocol on Base mainnet handling real USDC subscriptions. Contributors need clear guidance on:

  1. Foundry development workflow
  2. UUPS upgrade pattern safety
  3. Chainlink Automation integration
  4. Security best practices for financial contracts
  5. Testing standards for subscription logic

Checklist

  • Development environment setup
  • Architecture documentation
  • Coding standards with examples
  • Testing guidelines
  • Security checklist
  • Deployment instructions
  • Community guidelines

Related

This addresses the need for contributor documentation to help grow the SubBase developer community.


Note: This is my first contribution to SubBase. I'm impressed by the protocol's approach to decentralized subscriptions on Base and wanted to help make it easier for other developers to contribute. Happy to iterate on any feedback!

karinasvatk and others added 29 commits December 5, 2025 08:26
- Add PastDue and Suspended subscription statuses
- Add V2 storage variables for charge tracking
- Add failed attempts, last charge attempt, grace period tracking
- Add new errors and events for charge module
- Maintain storage layout compatibility with V1
- Implement charge() for processing subscription payments
- Implement batchCharge() for multiple subscriptions
- Add failed payment handling with grace periods
- Add automatic PastDue and Suspended status transitions
- Implement retry logic with configurable max attempts
- Add reactivate() for suspended subscriptions
- Add admin functions for grace period and retry configuration
- Emit events for charge success, failure, and status changes
- Implement checkUpkeep() for Chainlink Automation
- Implement performUpkeep() for automated charging
- Add batch processing with configurable limits
- Handle partial failures gracefully
- Support continuous automated billing cycles
- Inherit from SubBaseV1 and AutomationModule
- Add initializeV2() for V2-specific configuration
- Maintain UUPS upgradeability
- Add version() function returning 2
- Enable auto-charge billing engine
ChargeModule tests:
- testCharge_Success: Successful charge updates billing time
- testCharge_NotDueYet: Reverts when not due
- testCharge_InsufficientBalance: Marks PastDue on failure
- testCharge_UpdatesNextBillingTime: Verifies billing cycle
- testBatchCharge_MultipleSubscriptions: Batch processing
- testBatchCharge_PartialSuccess: Handles mixed results
- testGetChargeableSubscriptions: Returns due subscriptions
- testRetryCharge_Success: Successful retry reactivates
- testRetryCharge_MaxAttempts: Suspends after max retries
- testGracePeriod_Expiration: Grace period tracking
- testReactivate_PaysOutstanding: Pays and reactivates

AutomationModule tests:
- testCheckUpkeep_ReturnsReadySubscriptions: Chainlink integration
- testPerformUpkeep_ChargesAll: Automated batch charging
- testAutomationWorkflow_MultipleCycles: Multiple billing periods
- testPerformUpkeep_PartialSuccess: Handles failures gracefully
- Deploy SubBaseV2 implementation
- Upgrade proxy from V1 to V2
- Initialize V2 with grace period and max retries
- Support configurable parameters via environment variables
- Verify upgrade and configuration post-deployment
- Create universal deploy.yml with version selection (v1, v2, both)
- Create universal upgrade.yml for upgrading to any version
- Add configurable grace period and max retries for V2
- Remove old CI workflows: coverage, lint, slither, size-check
- Remove old deploy-v1.yml and upgrade-v1.yml
- Keep test.yml for running tests
- Remove duplicate error names (ChargeFailed, SubscriptionSuspended)
- Add onlyOwner modifier override in SubBaseV2
- Change _owner from private to internal in SubBaseV1 for inheritance
- Resolve modifier conflicts between SubBaseV1 and ChargeModule
- Add virtual to onlyOwner modifier in SubBaseV1
- Specify both contracts in override: SubBaseV1 and ChargeModule
- Replace removed SubscriptionSuspended() error with SubscriptionNotActive()
- Remove abstract onlyOwner modifier from ChargeModule
- Simplify override in SubBaseV2 to only override SubBaseV1
- Functions in ChargeModule will use onlyOwner from parent contract
- Add virtual onlyOwner modifier back to ChargeModule
- Override both SubBaseV1 and ChargeModule in SubBaseV2
- Use helper function for cleaner modifier implementation
- Replace virtual onlyOwner modifier in ChargeModule with virtual _checkOwner function
- Implement _checkOwner in SubBaseV2
- Eliminates modifier inheritance conflict between SubBaseV1 and ChargeModule
- ChargeModule admin functions now call _checkOwner() directly
Major Updates:
- ✨ New user-friendly README with Base infrastructure focus
- 📊 Add deployments.json with mainnet & testnet addresses
- 🧹 Remove old development files (ARCHITECTURE.md, contracts.json)
- 🗑️ Remove deprecated UpgradeV1.s.sol script

README Improvements:
- Professional badges and branding
- Quick start guides for creators and subscribers
- Comprehensive integration examples (Solidity + JS/TS)
- Chainlink Automation setup instructions
- Use cases, roadmap, and security info
- SEO-optimized for Base ecosystem indexing

Deployments:
- Base Mainnet: 0xfa34E4c68c77D54dD8B694c8395953465129E3c9 (V2)
- Base Sepolia: 0x8B182755Ae296e8f222Ac4E677B7Cc63dFDe7BA0 (V2)
- Grace Period: 7 days, Max Retries: 3
Add comprehensive test coverage for edge cases:
- Zero/minimal/maximal prices and billing periods
- Charging at exact billing time boundaries
- Multiple consecutive billing cycles
- Empty and long metadata strings
- Non-existent plan/subscription queries

These tests ensure the protocol handles extreme parameter values correctly.
Cover all possible subscription state transitions:
- Active → Cancelled (user cancel)
- Active → PastDue (first payment failure)
- PastDue → Active (successful retry)
- PastDue → Suspended (max retries reached)
- PastDue → Cancelled (user cancel while PastDue)
- Suspended → Active (reactivation)
- Suspended → Cancelled (user cancel while suspended)

Also test invalid transitions and authorization checks.
Includes full lifecycle test exercising all states.
Ensure critical security properties:
- Cannot charge same subscription twice in same billing period
- NextBillingTime advances correctly across cycles
- Batch charging handles duplicate IDs safely
- Failed attempts counter persists and resets correctly
- Cannot retry subscriptions in wrong states
- Max retry attempts enforced strictly

Closes potential double-billing vulnerability.
Test grace period mechanics thoroughly:
- Grace period set on first failure
- Exact expiration time boundaries
- Multiple failures during grace period
- Grace period cleared on success/reactivation
- Config updates and their effects
- Minimal and large grace periods
- Interaction with max retry attempts

Validates 7-day grace period default behavior.
Storage Layout Documentation:
- Document all 11 storage slots with clear comments
- Explain V1 and V2 storage additions
- Clarify __gap usage for future upgrades
- Add slot position tracking for upgrade safety

State Machine Specification (docs/STATE_MACHINES.md):
- Formal specification of Plan and Subscription lifecycles
- Document all state transitions with preconditions/postconditions
- Define charging mechanics and idempotency guarantees
- Cover grace period behavior and retry logic
- List all events and invariants
- Provide integration guidelines for dApp developers

This documentation enables integrators to understand protocol semantics
without reading Solidity code, and ensures future upgrades maintain
storage compatibility.
Add draft branch to test triggers and enable manual workflow dispatch.
This allows running comprehensive test suite (80+ tests) via GitHub Actions.
Replace SubBaseV2.ErrorName.selector with bytes4(keccak256("ErrorName()"))
for proper error handling. Add SubBaseErrors import to all new test files.
Replace SubBaseV2.ErrorName.selector with bytes4(keccak256("ErrorName()"))
for NotDueForCharge, SubscriptionNotActive, InvalidGracePeriod, and
InvalidMaxRetryAttempts errors.
Tests need to remove user balance to simulate insufficient funds.
Using transfer() with vm.prank() fails because staticcall consumes the prank.
burn() method allows tests to directly remove tokens without prank issues.
- Replace all usdc.transfer() calls with usdc.burn() to avoid vm.prank() consumption issues
- Fix subscription ID assertions in IdempotencyReplay tests (setUp creates ID=0, new subs start at ID=1)
- All three test files (GracePeriodEdgeCases, IdempotencyReplay, StateTransitions) now use burn() consistently

Resolves test failures where vm.prank() was consumed by balanceOf() staticcall.
Fixed three categories of test issues:

1. **transfer() → burn()**: Replaced all remaining usdc.transfer() calls with usdc.burn() in:
   - ChargeModule.t.sol (10 instances)
   - AutomationModule.t.sol (3 instances)

2. **nextBillingTime expectations**: Contract sets nextBillingTime = block.timestamp + period where
   block.timestamp is the warped value. Tests were expecting the old (pre-warp) timestamp.
   Fixed in:
   - ChargeModule.t.sol: testCharge_UpdatesNextBillingTime, testCharge_Success
   - IdempotencyReplay.t.sol: testIdempotency_CannotChargeImmediatelyAfterSuccessfulCharge,
     testIdempotency_NextBillingTimeUpdatedCorrectly
   - StateTransitions.t.sol: testTransition_SuspendedToActive
   - AutomationModule.t.sol: testPerformUpkeep_ChargesAll, testAutomationWorkflow_MultipleCycles

3. **Multiple billing cycles**: Fixed testAutomationWorkflow_MultipleCycles to use absolute timestamps
   instead of relative warps to ensure each cycle warps to the correct future time.

All 94 tests should now pass.
Fixed remaining 10 test failures by using hardcoded absolute timestamps
instead of dynamic calculations.

Key insight: contract sets nextBillingTime = block.timestamp + period
where block.timestamp is the CURRENT (warped) time, so:
- Initial: nextBillingTime = 1 + 2592000 = 2592001
- After first charge at 2592001: nextBillingTime = 2592001 + 2592000 = 5184001

Fixed tests:
- ChargeModule.t.sol: testCharge_Success, testCharge_UpdatesNextBillingTime,
  testCharge_InsufficientBalance (event order), testReactivate_PaysOutstanding
- IdempotencyReplay.t.sol: testIdempotency_CannotChargeImmediatelyAfterSuccessfulCharge,
  testIdempotency_NextBillingTimeUpdatedCorrectly (complete rewrite)
- StateTransitions.t.sol: testTransition_SuspendedToActive
- AutomationModule.t.sol: testPerformUpkeep_ChargesAll
- BoundaryConditions.t.sol: testSubscription_MultipleBillingCycles (rewrote loop),
  testSubscription_ShortBillingPeriod (fixed loop)

All 94 tests should now pass.
Resolved merge conflicts in:
- src/storage/SubBaseStorage.sol (kept detailed NatSpec documentation)
- test/AutomationModule.t.sol (kept updated test version)
- test/ChargeModule.t.sol (kept updated test version)

All 94 tests passing after merge.
Complete operational guide for Chainlink Automation covering:
- Chainlink Automation configuration and setup
- How checkUpkeep and performUpkeep work
- Charge logic and failure handling
- Monitoring (events, metrics, alerts)
- Emergency procedures (pause, manual charging)
- Gas optimization and troubleshooting
- Production deployment checklist

This guide provides operators with everything needed to
run and monitor SubBase automation in production.
- Add development environment setup for Foundry
- Document architecture: UUPS upgrade pattern, subscription lifecycle
- Include coding standards with Solidity style guide
- Add testing requirements with Foundry examples
- Document commit conventions following Conventional Commits
- Include security checklist and vulnerability disclosure
- Add deployment instructions for local/testnet/mainnet
- Document community guidelines and recognition

This guide helps developers contribute to SubBase's decentralized
subscription infrastructure on Base L2 with Chainlink Automation.

Refs: Project would benefit from contributor onboarding documentation
@Kubudak90 Kubudak90 requested a review from karinasvatk as a code owner April 2, 2026 17:12
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