Skip to content

Repository files navigation

Cascade Splits

Non-custodial payment splitting protocol for Solana. Automatically distribute incoming payments to multiple recipients based on pre-configured percentages.

License: Apache-2.0SolananpmPyPIVerified Build

Program ID:SPL1T3rERcu6P6dyBiG7K8LUr21CssZqDAszwANzNMB

Overview

Cascade Splits enables trustless payment distribution on Solana:

  • Non-custodial: Funds held in PDA-owned vaults, no private keys
  • Automatic: Split funds instantly on execution
  • Permissionless: Anyone can trigger distributions
  • Self-healing: Missing recipient ATAs handled gracefully with automatic recovery

How It Works

Payment → Vault (PDA) → execute_split() → Recipients
  1. Authority creates a split config with recipients and percentages
  2. Protocol creates a vault (ATA owned by PDA) to receive payments
  3. Payments sent to vault
  4. Anyone calls execute_split() to distribute funds

Features

  • 1-20 recipients per split configuration
  • 1% protocol fee (transparent, on-chain enforced)
  • SPL Token & Token-2022 support, including sRFC-37 frozen accounts
  • Multiple configs per authority/mint via unique identifiers
  • Idempotent execution - safe to retry
  • Self-healing - unclaimed funds auto-deliver when ATAs created
  • Zero-copy accounts - optimized for high-throughput micropayments

Quick Start

Installation

# Clone repository
git clone https://github.com/cascade-protocol/splits.git
cd splits
# Install dependencies
pnpm install
# Build program
anchor build

Run Tests

# Mollusk unit tests (fast)
cargo test -p cascade-splits
# Anchor integration tests
anchor test

Run Benchmarks

cargo bench -p cascade-splits

Costs

Rent (Refundable)

Creating a split config requires rent-exempt deposits that are fully refundable when closing:

AccountSizeRent
SplitConfig1,832 bytes0.0136 SOL
Vault ATA165 bytes0.0020 SOL
Total~0.0157 SOL

At $150/SOL ≈ $2.35 (refunded on close_split_config)

Compute Units

InstructionCUsNotes
execute_split (1 recipient)~28,505Minimal case
execute_split (5 recipients)~68,573Typical case
execute_split (10 recipients)~109,000High activity
create_split_config36,590 - 40,024Includes vault ATA creation
update_split_config7,424 - 14,032Varies by recipient count
close_split_config~10,168Includes vault ATA closure
initialize_protocol~8,998One-time setup

Scaling: ~8K CU per recipient (6K Token CPI + 2K overhead). Even 10-recipient splits use only 8% of Solana's 1.4M CU budget.

For comparison: typical DEX swaps use 100,000-400,000+ CUs.

See docs/benchmarks/compute_units.md for full benchmark history and additional scenarios (unclaimed flows, protocol admin ops).

Usage Example

Execute a Split (Facilitators)

import{createSolanaRpc}from"@solana/kit";import{executeSplit,isCascadeSplit}from"@cascade-fyi/splits-sdk";constrpc=createSolanaRpc("https://api.mainnet-beta.solana.com");// Check if destination is a split vaultif(awaitisCascadeSplit(rpc,vault)){constresult=awaitexecuteSplit(rpc,vault,executor);if(result.ok){// Build and send transaction using your preferred methodconsttx=buildTransaction([result.instruction],signer);awaitsendTransaction(tx);}else{console.log(`Cannot execute: ${result.reason}`);}}

Note: The core module returns instructions — transaction building is your responsibility, enabling compatibility with any @solana/kit version. For high-level convenience with WebSocket confirmation, use executeAndConfirmSplit from @cascade-fyi/splits-sdk.

Create a Split (Merchants)

import{createSplitsClient}from"@cascade-fyi/splits-sdk";import{createSolanaRpc,createSolanaRpcSubscriptions,createKeyPairSignerFromBytes}from"@solana/kit";constrpc=createSolanaRpc("https://api.mainnet-beta.solana.com");constrpcSubscriptions=createSolanaRpcSubscriptions("wss://api.mainnet-beta.solana.com");constsigner=awaitcreateKeyPairSignerFromBytes(secretKey);constsplits=createSplitsClient({ rpc, rpcSubscriptions, signer });constresult=awaitsplits.ensureSplit({recipients: [{address: "Agent111111111111111111111111111111111111111",share: 90},{address: "Marketplace1111111111111111111111111111111",share: 10},],});// result.vault is your payment address (use as x402 payTo)

See SDK documentation for complete API reference.

Architecture

Account Structure

ProtocolConfig (global singleton)

  • Authority and fee wallet configuration
  • Seeds: [b"protocol_config"]

SplitConfig (per-split)

  • Recipients, percentages, vault address
  • Seeds: [b"split_config", authority, mint, unique_id]
  • Zero-copy for optimal compute (1,832 bytes fixed)

Instructions

InstructionAuthorizationDescription
initialize_protocolDeployerOne-time protocol setup
update_protocol_configProtocol authorityUpdate fee wallet
create_split_configAnyoneCreate new split
execute_splitAnyoneDistribute vault funds
update_split_configConfig authorityUpdate recipients
close_split_configConfig authorityDelete config, reclaim rent

Self-Healing Unclaimed Recovery

If a recipient's ATA is missing during execution:

  1. Their share is recorded as "unclaimed" and stays in vault
  2. Funds are protected from re-splitting
  3. On next execute_split, system attempts to clear unclaimed
  4. Once recipient creates ATA, funds auto-deliver

No separate claim instruction needed - single interface for all operations.

x402 Integration

Cascade Splits integrates seamlessly with x402 payment facilitators:

import{isCascadeSplit,executeSplit}from"@cascade-fyi/splits-sdk";// In your facilitator's settle handler:if(awaitisCascadeSplit(rpc,paymentDestination)){// It's a split vault - execute distribution after paymentconstresult=awaitexecuteSplit(rpc,paymentDestination,executor);if(result.ok){// Build and send using your kit versionawaitsendTransaction([result.instruction],signer);}}

Use the splitConfig address (PDA) as your payTo destination — facilitators derive the vault ATA automatically. This makes payTo token-agnostic: same address works for USDC, USDT, or any supported token. The SDK caches detection results for high-volume efficiency.

See specification for complete integration guide.

Development

Project Structure

├── programs/cascade-splits/
│ ├── src/
│ │ ├── instructions/ # Instruction handlers
│ │ ├── state.rs # Account structures
│ │ ├── errors.rs # Error codes
│ │ └── events.rs # Event definitions
│ ├── tests/ # Mollusk unit tests
│ └── benches/ # Compute unit benchmarks
├── packages/splits-sdk/ # TypeScript SDK (Solana)
├── packages/splits-sdk-evm/ # TypeScript SDK (EVM)
├── apps/dashboard/ # Dashboard app
├── apps/docs/ # Documentation site
└── docs/
└── specification.md # Full specification

Dependencies

  • Anchor 0.32.1
  • Solana SDK 2.2
  • Mollusk SVM 0.5.1 (testing)
  • @solana/kit ^5.0.0 (SDK)

Building

# Build program
anchor build
# Build SDK
pnpm build

Documentation

Security

Implemented Protections

  • Non-custodial (PDA-owned vaults)
  • Overflow/underflow checks (all math uses checked_*)
  • Duplicate recipient validation
  • Bounded account size (max 20 recipients)
  • Protocol fee enforcement (cannot be bypassed)
  • ATA validation on creation

Audits

Coming soon

License

Apache License 2.0 - see LICENSE file.

Links


Built by Cascade Labs

About

Non-custodial payment splitting protocol for Solana

Topics

Resources

Contributing

Security policy

Stars

7 stars

Watchers

2 watching

Forks

Releases

Contributors

Languages