Open-source attribution and settlement infrastructure for measurable Stellar DeFi campaigns.
Grindy.fun is the first reference implementation. The live product already operates campaign enrollment, scoring, leaderboards, analytics, and reward operations. This repository contains the reusable Stellar components that connect verifiable wallet activity to campaign attribution and transparent settlement.
- Live Stellar lab: stellar.grindy.fun
- Campaign #001: stellar.grindy.fun/campaigns/testnet-001
- Technical architecture: docs/technical-architecture.md
- License: MIT
Grindy Stellar Testnet Campaign #001 demonstrates the complete public readiness path:
Soroswap testnet swap
|
v
Soroswap adapter decodes XDR
|
v
NormalizedCampaignEvent
|
v
Eligibility and contribution
|
v
Final leaderboard and allocation manifest
|
v
CampaignEscrow finalization
|
v
RewardDistributor commitment and payout
| Proof | Result |
|---|---|
| Source activity | Public Soroswap transaction |
| Normalized contribution | 200 XLM eligible swap volume |
| Reward pool | 100 XLM |
| Final allocation | 70 XLM to one participant |
| Unused pool | 30 XLM returned atomically to the protocol owner |
| Settlement | Public batch payout |
| Participant claim proof | Participant-signed claim() transaction |
| Final status | Settled |
The Campaign #001 activity wallet was paid through the authenticated batch path because this repository does not control that participant key. The participant path was also exercised independently on testnet: a separate wallet committed its allocation and signed claim() itself against an isolated RewardDistributor deployment.
Protocol-funded reward custody and campaign lifecycle:
Created -> Funded -> Active -> Finalized -> Settled
|
v
Paused -> Active
|
v
Refunded
- Contract:
CDTZ7IWF...HJABCLP - Funding: 100 XLM transaction
- Finalization: allocation commitment
- Settlement: 70 XLM routed and 30 XLM returned
- Pause/refund proof: pause, refund
- Contract reference: contracts/campaign-escrow/README.md
Final allocation commitment, participant claims, verified batches, and duplicate-payment prevention:
- Contract:
CB4BMKLN...ZAXT37M - Allocation root:
27f185b31c6c785856541b5222efc76d4ea188a802b22b7a85a0c776709f11db - Commitment: public transaction
- Payout: public transaction
- Self-claim proof contract:
CDARFIGM...GVBBUPE - Participant-signed claim: public transaction
- Contract reference: contracts/reward-distributor/README.md
The original CampaignRewardVault remains in the repository as the earlier narrow deposit / withdraw testnet primitive. Campaign #001 uses the production-shaped escrow and distributor contracts above.
packages/campaign-event-schema defines the versioned public boundary between protocol-specific activity and campaign scoring.
{
"schemaVersion": "1.0",
"campaignId": "grindy-stellar-testnet-campaign-001",
"network": "testnet",
"wallet": "GDY2IB6RSKMLRFLAPPCLVRHPDAFYRL6V7SZDZP4QSHP3Y3XMGVDSYDN2",
"protocol": "soroswap",
"action": "swap",
"asset": "XLM",
"amount": "200",
"ledger": 4084752,
"transactionHash": "48dc831a8865641b1af97d817454afa0a1e4643f7fbc7bd058988ef42d4b3318",
"timestamp": "2026-08-11T10:39:53Z",
"eventId": "0017543876252295168-0000000004",
"idempotencyKey": "..."
}Amounts remain decimal strings, immutable ledger records receive deterministic event IDs, and campaign-specific idempotency keys prevent duplicate scoring across retries.
packages/adapter-sdk defines the interface from raw Stellar activity to a normalized contribution. adapters/soroswap is the first working implementation:
- decodes the public Soroswap Router event from Stellar XDR;
- validates contract, topics, campaign period, assets, pool, and wallet;
- preserves integer precision with decimal strings and
BigInt; - emits one deterministic normalized event;
- converts the eligible 200 XLM swap into a campaign scoring input.
The fixture is a real public testnet transaction, not synthetic activity. Protocol-specific scoring policy remains outside the adapter.
grindy-stellar-integration/
├── contracts/
│ ├── campaign-escrow/
│ ├── reward-distributor/
│ └── campaign-reward-vault/
├── packages/
│ ├── stellar-wallet-link/
│ ├── stellar-signature-verifier/
│ ├── campaign-event-schema/
│ └── adapter-sdk/
├── adapters/
│ └── soroswap/
├── examples/
│ ├── grindy-stellar-wallet-demo/
│ └── reward-vault-next/
└── docs/
├── technical-architecture.md
├── campaign-rails-roadmap.md
├── event-schema.md
├── settlement-manifest.md
├── security.md
└── setup.md
- Node.js 20+
- pnpm 10+
- Rust with the
wasm32v1-nonetarget - Stellar CLI for optimized contract builds
- Freighter for interactive testnet flows
pnpm install
pnpm check-types
pnpm test
pnpm build
pnpm contract:test
pnpm contract:buildpnpm vault:uiOpen http://localhost:3040 for wallet ownership and vault interaction. Campaign #001 is available at http://localhost:3040/campaigns/testnet-001.
| Area | Coverage |
|---|---|
| Wallet proof | Message construction, valid signature, invalid signature, wrong message |
| Event schema | Runtime validation, deterministic event IDs, idempotency |
| Adapter SDK | Eligibility guards and scoring-input boundary |
| Soroswap adapter | XDR decode, topic validation, precision, filtering, deterministic normalization |
| CampaignEscrow | Roles, funding, lifecycle, expiry, no participants, pool limit, settlement, refund |
| RewardDistributor | Allocation commitment, proof validation, duplicate claims, batches, balance limits, refunds |
| Public demos | TypeScript checks and production builds |
GitHub Actions reruns TypeScript builds/tests and all three Soroban contract test/WASM builds on pushes and pull requests.
- Grindy never requests or stores private keys or seed phrases.
- Wallet ownership signatures cannot move funds.
- Participant trading funds and DeFi positions never enter Grindy contracts.
- Only protocol-funded campaign rewards are escrowed.
- Campaign and distribution roles are explicit and authenticated.
- Allocation commitments are immutable after finalization.
- Claims are idempotent and duplicate payouts are rejected.
- Advanced settlement includes pause and protocol refund paths.
- Testnet contracts are public readiness software and have not received an external security audit.
See docs/security.md for the complete public security model.
This repository publishes reusable Stellar infrastructure:
- wallet ownership and signature modules;
- normalized campaign event schema;
- adapter interface and public protocol adapters;
- Soroban campaign settlement contracts;
- fixtures, tests, deployment evidence, and technical documentation.
The hosted Grindy product retains campaign operations, configurable scoring policy, partner analytics, anti-abuse review, administration, and private production infrastructure.
No secrets, production API keys, private deployment credentials, or private application code belong in this repository.
- Technical Architecture
- Campaign Rails Roadmap
- Campaign Event Schema
- Settlement Manifest
- Soroswap Adapter
- Security Model
- Local Setup
MIT.