Skip to content

RiftCore00/whoznext

Repository files navigation

WhoZNext

License Rust Soroban CI

Automated Milestone & Issue Escrow Release – WhoZNext lets repository maintainers lock an asset budget against a GitHub Milestone. When issues tied to that milestone are closed and merged, the contract automatically releases micro-payouts to developers — no manual reconciliation, no end-of-month bottlenecks.

Built on Stellar Soroban and designed to integrate with WaveGuard for access control, WhoZNext keeps engineering momentum consistent during time-boxed sprints by automating financial closure alongside every PR merge.


Table of Contents


Project Purpose

WhoZNext is an automated milestone & issue escrow release system designed to solve the fundamental problem of predictable cash flow in time-boxed open-source development. It bridges the gap between engineering velocity and financial settlement, ensuring that contributor compensation keeps pace with sprint cycles.

Core Mission

In modern open-source projects, especially within the Stellar ecosystem, teams operate in intensive, time-boxed sprints (e.g., 1-week cycles). Traditional milestone payout systems create friction by:

  1. Decoupling financial settlement from engineering progress
  2. Creating administrative bottlenecks at arbitrary intervals
  3. Breaking development momentum with payment delays

WhoZNext addresses this by implementing a trustless, on-chain escrow system that automatically releases micro-payouts when engineering work is completed, eliminating manual reconciliation and end-of-month bottlenecks.

Why This Matters in the Stellar Ecosystem

During intensive development sprints, predictable cash flow is as critical as predictable code flow. WhoZNext ensures that financial settlement keeps pace with engineering velocity, removing the most common friction point in contributor retention and enabling sustainable open-source development.

Target Impact

  • For Contributors: Receive instant, on-chain payments the moment their PR is merged — no waiting for end-of-month processing.
  • For Maintainers: Automate financial closure alongside every PR merge, reducing administrative overhead and maintaining sprint momentum.
  • For the Ecosystem: Establish a reliable, trustless payment infrastructure that scales with open-source development velocity.

Technical Philosophy

WhoZNext is built on three core principles:

  1. Automation: Eliminate manual processes through smart contract automation
  2. Trustlessness: Use blockchain technology to remove counterparty risk
  3. Speed: Enable micro-payouts that settle in near real-time

This foundation enables a new paradigm where financial settlement is an automatic byproduct of engineering progress, not a separate administrative task.

Why It Matters in the Stellar Ecosystem

During intensive, time-boxed sprints (e.g., Drips Wave's 1-week cycles), predictable cash flow is as important as predictable code flow. WhoZNext ensures that financial settlement keeps pace with engineering velocity, removing the most common friction point in contributor retention.


Target Users

Role How They Use WhoZNext
Repository Maintainer Creates milestone pools, funds them with Stellar assets, and authorizes payouts as issues close.
Contributor Receives instant, on-chain payments the moment their PR is merged — no waiting for end-of-month processing.

Architecture Overview

┌─────────────────────────────────────────────────────┐
│                    WaveGuard                         │
│           (Access Registry / Maintainer ID)          │
└────────────┬─────────────────────────────┬──────────┘
             │                             │
             ▼                             ▼
┌──────────────────────────────────────────────────────┐
│                   WhoZNext                      │
│              Escrow Asset Vault                       │
│  ┌──────────────┐  ┌──────────────┐  ┌────────────┐ │
│  │ Milestone    │  │ Issue        │  │ Clawback   │ │
│  │ Pool Records │  │ Claim Logs   │  │ Mechanism  │ │
│  └──────────────┘  └──────────────┘  └────────────┘ │
└─────────────────────┬────────────────────────────────┘
                      │
                      ▼
┌──────────────────────────────────────────────────────┐
│            Stellar Asset Contract (SAC)               │
│              (Token Transfer Execution)                │
└──────────────────────────────────────────────────────┘
  1. Maintainer calls create_milestone_pool, funding the contract with a SAC token budget.
  2. Maintainer (or CI) calls release_issue_bounty with the issue ID, developer address, and amount. The contract verifies the maintainer's authority via WaveGuard.
  3. Contract atomically marks the issue as claimed and transfers the payout.
  4. Maintainer can claw back unclaimed funds after the milestone deadline via clawback_expired_funds.

Asset Escrow Lifecycle

Tokens move through four distinct phases from deposit to final settlement:

  1. Pool Creation — Deposit & Lock The maintainer calls create_milestone_pool, transferring total_funds from their wallet into the contract's asset vault. Tokens are locked on-chain and unavailable for withdrawal until the milestone concludes.

  2. Issue Payout — Transfer to Developer When an issue is closed and merged, the maintainer (or CI) calls release_issue_bounty. The contract deducts the specified amount from the pool balance and atomically transfers it to the developer address. The issue is marked completed = true.

  3. Duplicate Claim Protection — No Double-Spend Every claim is keyed by (repo_hash, issue_id). If release_issue_bounty is called again for the same pair, the contract reverts with BountyAlreadyClaimed before touching any tokens — the pool balance is unchanged.

  4. Clawback — Unclaimed Funds Returned After the milestone deadline, the maintainer calls clawback_expired_funds. Any remaining balance in the vault is transferred back to the maintainer, and the pool is cleared. No funds are ever stranded on-chain.


Smart Contract Design

Storage Strategy

Storage Tier Data Key Schema Rationale
Instance Milestone pool metadata (asset address, total budget, guard contract ref) DataKey::Pool (singleton) Persists for the contract's lifetime; cheap one-time bump.
Persistent Individual issue claim records DataKey::IssueClaim(repo_hash, issue_id)IssueClaim Security fix (CM-01): Temporary storage TTL expiry allowed replay attacks. Persistent storage ensures the duplicate-claim guard is durable for the contract's lifetime.

Authentication Design

Dual validation gates every payout:

  1. maintainer.require_auth() – The calling address must be an authorized maintainer registered in WaveGuard.
  2. Recipient match – The developer address in the call must match the contributor record associated with the issue.

Failed validation → BountyAlreadyClaimed or UnauthorizedMaintainer error (contract reverts).

Data Types (types.rs)

#[derive(Clone)]
#[contracttype]
pub struct IssueClaim {
    pub issue_id: u32,
    pub developer: Address,
    pub payment_amount: u128,
    pub completed: bool,
    pub maintainer: Address,
    pub claimed_at: u64,
}

Claim records are stored under a composite key of (repo_hash, issue_id), guaranteeing uniqueness across repositories. Each record includes the maintainer who authorized the payout and the claimed_at ledger timestamp for auditing.


Getting Started

Prerequisites

  • Rust 1.81+
  • Soroban CLI
  • A Stellar testnet/futurenet identity for deployment

Build

cd contracts/whoz_next
cargo build --release

Test

cargo test -- --nocapture

See Testing for details on the integration test suite.


Contract Methods

create_milestone_pool

Initializes a new milestone escrow pool. Transfers total_funds from the caller to the contract's asset vault, links to a WaveGuard registry identity, and sets the milestone deadline.

fn create_milestone_pool(
    env: Env,
    maintainer: Address,
    guard_contract: Address,
    asset: Address,
    total_funds: u128,
    expiry: u64,
) -> Result<(), Error>;

Parameters

Parameter Type Description
maintainer Address Stellar address of the pool creator. Must be registered in WaveGuard.
guard_contract Address Address of the deployed WaveGuard contract instance. Cannot be the same as the WhoZNext contract.
asset Address Stellar Asset Contract (SAC) token ID to use for payouts. Must be a trusted SAC instance.
total_funds u128 Total budget to lock for this milestone (in the smallest unit of asset, e.g. stroops). Must be > 0.
expiry u64 Unix timestamp (in seconds) after which unclaimed funds can be clawed back. Must be strictly in the future.

Auth

  • maintainer.require_auth() — the caller must sign the transaction.
  • WaveGuard is_maintainer check — the caller must be registered as an active maintainer in the WaveGuard registry.

Step-by-Step Guide

  1. Prerequisites:

    • Deploy a WaveGuard contract instance and register at least one maintainer address.
    • Deploy or identify a Stellar Asset Contract (SAC) for the token you want to use for payouts.
    • Ensure the maintainer address holds sufficient tokens (≥ total_funds) and has the deployer identity funded with XLM for transaction fees.
  2. Compute the expiry timestamp:

    # Example: 30 days from now (Unix seconds)
    date -d "+30 days" +%s
  3. Invoke the function:

    soroban contract invoke \
        --id <WHOZNEXT_CONTRACT_ID> \
        --source <MAINTAINER_KEY> \
        --network-passphrase "Test SDF Network ; September 2015" \
        --rpc-url https://soroban-testnet.stellar.org \
        -- \
        create_milestone_pool \
        --maintainer <MAINTAINER_ADDRESS> \
        --guard_contract <WAVEGUARD_ID> \
        --asset <SAC_TOKEN_ID> \
        --total_funds <AMOUNT> \
        --expiry <UNIX_TIMESTAMP>
  4. Verify the pool:

    soroban contract invoke \
        --id <WHOZNEXT_CONTRACT_ID> \
        --source <MAINTAINER_KEY> \
        --network-passphrase "Test SDF Network ; September 2015" \
        --rpc-url https://soroban-testnet.stellar.org \
        -- \
        milestone_info

Example

// Funds: 10,000 USDC (using 7-decimal places → 100_000_000_000 stroops)
// Expiry: Unix timestamp for 30 days from creation
client.create_milestone_pool(
    &maintainer,       // Pool creator / maintainer
    &guard_contract,   // Deployed WaveGuard address
    &usdc_token,       // USDC Stellar Asset Contract
    &100_000_000_000u128, // 10,000 USDC in smallest unit
    &1_700_000_000u64, // Expiry timestamp
);

Errors

Error Condition
UnauthorizedMaintainer Caller is not registered in WaveGuard.
InvalidGuard guard_contract equals the WhoZNext contract's own address.
InvalidAmount total_funds is zero.
InvalidExpiry expiry is zero.
ExpiryInPast expiry is ≤ current ledger timestamp.
PoolAlreadyExists A milestone pool has already been created (singleton contract).
TransferFailed Maintainer has insufficient token balance.

release_issue_bounty

Releases a micro-payout to a developer once their issue is closed and merged.

fn release_issue_bounty(
    e: Env,
    repo_hash: BytesN<32>,
    issue_id: u32,
    developer: Address,
    amount: u128,
) -> Result<(), Error>;
Parameter Description
repo_hash SHA-256 hash identifying the GitHub repository (linked to a milestone).
issue_id GitHub issue number (composite key with repo_hash prevents cross-repo collisions).
developer Stellar address receiving the payout.
amount Payout amount (must not exceed remaining pool balance).

Auth: maintainer.require_auth() + recipient address validation.

Safety: Once completed is set to true for a given (repo_hash, issue_id) pair, any subsequent call reverts with BountyAlreadyClaimed.


clawback_expired_funds

Returns unclaimed funds to the maintainer after a milestone deadline passes.

fn clawback_expired_funds(env: Env, maintainer: Address) -> Result<(), Error>;
Parameter Type Description
maintainer Address The original pool creator. Must match pool.maintainer exactly.

Auth: maintainer.require_auth(). Only callable after milestone expiry. WaveGuard is NOT checked — clawback uses direct address equality against pool.maintainer so that a compromised WaveGuard registry cannot block fund recovery.

Errors

Error Condition
PoolNotFound No milestone pool has been created.
PoolNotExpired Current ledger timestamp is before or at pool.expiry.
UnauthorizedCaller maintainer does not match pool.maintainer.
NoFundsToClawback Remaining balance is zero (fully claimed or already clawed back).

Helper / View Methods

(Implement as needed for front-end integration)

Method Returns Description
milestone_balance(e) u128 Current remaining balance in the milestone pool.
is_claimed(repo_hash, issue_id) bool Whether a specific issue has already been paid out.
milestone_info(repo_hash) MilestoneData Retrieve pool metadata for a given repo.

Integration with WaveGuard

WhoZNext depends on WaveGuard as its identity and access registry. It is used as the source of truth for who is an authorized maintainer.

Required WaveGuard Interface

WhoZNext makes a single cross-contract call:

/// Returns true if `address` is a registered, authorized maintainer.
fn is_maintainer(env: Env, address: Address) -> bool;

Where WaveGuard Is (and Is Not) Used

Operation Stellar require_auth WaveGuard is_maintainer
create_milestone_pool
release_issue_bounty
clawback_expired_funds ❌ (direct pool.maintainer address check)

clawback_expired_funds uses a direct address equality check against the original pool.maintainer (set at pool creation) rather than re-consulting WaveGuard. This design decision isolates the clawback path from a potential WaveGuard compromise — a rogue WaveGuard upgrade cannot reroute unclaimed funds.

Error Codes

If the WaveGuard check fails, the call reverts immediately with:

Situation Error Code
Caller not registered in WaveGuard UnauthorizedMaintainer (5)
Clawback caller ≠ original pool maintainer UnauthorizedCaller (6)
guard_contract address is zero/missing MissingGuardContract (11)

Setup Steps

  1. Deploy a WaveGuard instance and register maintainer addresses.
  2. Pass the WaveGuard contract address as guard_contract when calling create_milestone_pool.
  3. The guard_contract address is fixed at pool creation — it cannot be changed afterward. If the WaveGuard registry is ever compromised, a new pool must be created with a fresh guard address.
  4. WhoZNext handles all cross-contract calls internally; the integration is transparent to contributors.

Security & Vulnerability Protections

Duplicate Claim Prevention (Drain Attacks)

The contract uses a strict composite storage key combining repo_hash + issue_id. Claim records are stored in Persistent storage (security fix CM-01), ensuring the duplicate-claim guard survives for the contract's lifetime. Once completed is set to true, any subsequent release_issue_bounty for that exact (repo_hash, issue_id) pair immediately reverts with a BountyAlreadyClaimed error code — before any token transfer occurs.

Balance Overflow Protection

If a maintainer attempts to allocate more tokens than remain in the milestone pool, the contract detects the insufficient balance and gracefully reverts without locking up or losing any assets. Remaining funds stay accessible for future legitimate claims or clawback.

Access Control

Only WaveGuard-verified maintainer addresses can create pools, release bounties, or claw back funds. Contributor addresses are write-restricted — they can only receive payouts, not trigger them.

Testing Focus

The integration test suite covers:

  • Happy path: Create pool, fund, release bounty, verify recipient balance.
  • Duplicate claim: Attempt double-spend of the same issue ID → expect revert.
  • Over-allocation: Attempt payout exceeding pool balance → expect graceful revert with no asset loss.
  • Clawback: Claim expiry, return unclaimed funds to maintainer.
  • Unauthorized caller: Non-maintainer addresses rejected.

Testing

Quick Start

# Run all tests (unit + integration) with output
cargo test -- --nocapture

# Run only unit tests
cargo test --package whoz-next --lib -- --nocapture

# Run only integration tests
cargo test --package whoz-next --test '*' -- --nocapture

# Run a specific test by name
cargo test test_duplicate_claim_rejected -- --nocapture

Prerequisites for Integration Tests

Integration tests require the wasm32-unknown-unknown target:

rustup target add wasm32-unknown-unknown

Running with Docker

# Run all tests in a Docker container
docker compose -f docker/docker-compose.yml run --rm test

Test Suite Details

The test suite is organized into two categories:

Unit tests (contracts/whoz_next/src/test.rs):

  • Test individual function behavior and error paths
  • Validate input validation and authentication logic
  • Run quickly with no external dependencies

Integration tests (contracts/whoz_next/tests/*.rs):

  • Test cross-contract interactions with real Soroban environment
  • Deploy a mock SAC token and mock WaveGuard contract
  • Simulate the full milestone lifecycle

Integration Test Scenarios

  1. Happy path (full_lifecycle.rs): Create pool, fund, release bounty, verify recipient balance.
  2. Duplicate claim (duplicate_claim.rs): Attempt double-spend of the same issue ID → expect revert.
  3. Over-allocation (over_allocation.rs): Attempt payout exceeding pool balance → expect graceful revert with no asset loss.
  4. Clawback (clawback.rs): Claim expiry, return unclaimed funds to maintainer.
  5. Unauthorized access (unauthorized_access.rs): Non-maintainer addresses rejected.

Using the Test Script

# Run all tests via the convenience script
./scripts/test.sh

# Run a specific test
./scripts/test.sh test_duplicate_claim_rejected

# Run with environment overrides
RUST_LOG=debug ./scripts/test.sh

Project Structure

whoz-next/
├── contracts/
│   └── whoz_next/
│       ├── src/
│       │   ├── lib.rs          # Core ledger tracking and token distribution execution
│       │   └── types.rs        # Milestone allocations, error enums, and storage keys
│       └── Cargo.toml
├── tests/                       # Integration test suite
├── Cargo.toml                   # Workspace manifest
└── README.md

Key Files

File Purpose
contracts/whoz_next/src/lib.rs Core contract logic — pool creation, bounty release, clawback.
contracts/whoz_next/src/types.rs MilestoneAllocation, error enum (BountyAlreadyClaimed, InsufficientPoolBalance, UnauthorizedMaintainer), storage key definitions.
contracts/whoz_next/Cargo.toml Contract dependencies (soroban-sdk, waveguard-client, etc.).
tests/*.rs Integration tests with mock SAC token and full lifecycle coverage.

Contributing

Contributions are welcome! Please follow the standard workflow:

  1. Fork the repository.
  2. Create a feature branch (git checkout -b feat/my-feature).
  3. Commit your changes (git commit -am 'Add feature').
  4. Push to the branch (git push origin feat/my-feature).
  5. Open a Pull Request.

Ensure all tests pass and new code includes appropriate test coverage. For major changes, please open an issue first to discuss what you would like to change.


License

This project is licensed under the Apache License 2.0. See LICENSE for details.

About

Automated Milestone & Issue Escrow Release on Stellar Soroban — lock a token budget against a GitHub milestone, release micro-payouts when issues are merged.

Resources

License

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors