For the complete documentation index, see llms.txt. This page is also available as Markdown.

Swift

Swift Package for integrating Colibri Stateless Client into iOS and macOS applications. These bindings provide a native Swift API for secure, verified blockchain interactions without trusting centralized infrastructure.

Overview

The Colibri Swift Bindings enable you to verify Ethereum RPC calls with cryptographic proofs, directly in Swift applications. This provides Web3 functionality without dependency on centralized RPC providers.

Core Features

  • 🔐 Cryptographic Verification - All RPC responses are validated with Merkle proofs

  • 📱 iOS + macOS Support - Native Swift Package for all Apple platforms

  • 🗄️ Flexible Storage System - Customizable storage implementations for different use cases

  • ⚡ Performance - Optimized C libraries with Swift interface

  • 🧪 Comprehensive Testing - Complete integration tests with mock data

Architecture

┌─────────────────────────────────────────────────────────────────┐
│                    Swift Application Layer                      │
├─────────────────────────────────────────────────────────────────┤
│                     Colibri.swift API                           │
│  • Colibri class (main interface)                               │
│  • RequestHandler protocol                                      │
│  • ColibriStorage protocol                                      │
│  • Error handling & type conversion                             │
├─────────────────────────────────────────────────────────────────┤
│                  Swift-C Bridge Layer                           │
│  • swift_storage_bridge.c                                       │
│  • Function pointer callbacks                                   │
│  • Memory management                                            │
├─────────────────────────────────────────────────────────────────┤
│                   Core C Libraries                              │
│  • Prover (proof generation)                                   │
│  • Verifier (proof verification)                                │
│  • Storage plugin system                                        │
│  • Cryptographic libraries (blst, ed25519)                      │
└─────────────────────────────────────────────────────────────────┘

Quick Start

iOS Integration

For iOS applications, use the pre-built XCFramework:

iOS Example App

The CI-Pipeline contains a minimalistic Example and TestApp for iOS, which is used to test the integration. You can look at the code as an example on how to use certain features.

The code can be found in the bindings/swift/test_ios_app.

macOS Development

For macOS development with local static libraries:

Development Workflow

Local macOS Build

What happens during build:

  1. Compile C Libraries - All core libraries (Prover, Verifier, Crypto)

  2. Swift Storage Bridge - C-Swift interop for storage system

  3. Generate Integration Tests - Automatic generation of test functions from test/data

  4. Prepare Package - Swift Package with all dependencies

iOS XCFramework Build

XCFramework Structure:

Test System

Unit Tests

  • Initialization Tests - Colibri setup and configuration

  • Method Support Tests - RPC method availability

  • Storage Tests - Custom storage implementations

  • Error Handling Tests - Error handling and edge cases

Integration Tests

  • 23 automatically generated tests from test/data/*/test.json

  • Mock HTTP Requests - Offline tests with real blockchain data

  • Sequential Execution - Storage is global, tests run sequentially

  • Result Verification - Structural and string-based comparison

iOS Test App

The iOS test app serves as:

  • CI Integration Test - Verifies package integration in CI

  • Developer Example - Reference implementation for iOS developers

  • API Demonstration - Shows all important Colibri APIs

API Reference

Colibri Class

Prover Mode

Controls how proofs are built and verified. Set via proverMode:

  • .local -- Proofs are built entirely on the client. Requires access to a Beacon API and execution layer RPC. Fully trustless, but slower and needs more infrastructure.

  • .remote -- Proofs are fetched from a remote Colibri prover server. Fastest option but relies on the prover server for proof generation. The verifier still cryptographically checks every proof.

  • .hybrid -- The consensus-layer proof (BlockHeaderProof) comes from the Colibri server, while execution-layer data (account proofs, storage, etc.) is fetched directly from the RPC provider. Best balance of performance and scalability -- the Colibri server only serves lightweight, cacheable header proofs while the heavy RPC load goes to your existing provider.

  • .proxy -- Like remote, but the client sends its own RPC and Beacon API URLs to the prover server. The server uses these endpoints instead of its own. Useful when the client has access to private or premium RPC providers.

  • .lightClient -- Like hybrid, with additional background polling of block headers to keep the cache warm. Call startLightClient() / stopLightClient() to control polling (default interval: 12s). By default only the compact eth_getBlockHeader is fetched; pass fullBlock: true to fetch the full block (useful when many eth_getTransactionByHash / eth_getTransactionReceipt calls follow).

Default: .remote when prover URLs are configured, .local otherwise.

Privacy (PAP)

PAP (Pragmatic Adaptive Privacy) reduces intent leakage towards RPC/prover by using cached data when available and verifying afterwards.

  • privacyModePrivacyMode.none (default) or PrivacyMode.basic. With .basic, the verifier sets the PAP flag so that method-type and verification can use cached storage for optimistic execution (e.g. for eth_call); method type may depend on params.

This feature is still experimental!

Weak Subjectivity Period check

Whenever a sync crosses the Weak Subjectivity Period (WSP) -- typically ~2 to 4 months on Ethereum mainnet -- the verifier anchors the highest finalized header against an external checkpointz / Beacon API endpoint. The check applies to all three sync paths: verifier-driven Light Client updates, prover-supplied LCSyncData, and prover-supplied ZKSyncData. For ZKSyncData the verifier prefers configured witness signatures (checkpointWitnessKeys + matching signatures from the prover) and only falls back to checkpointz when no witness anchor is available.

  • skipWspCheck (Bool, default false) -- sets VERIFY_FLAG_SKIP_WSP_CHECK (bit 1 << 7) and disables the round-trip. SECURITY: only safe with an alternative trust anchor; raises the risk of long-range attacks across periods older than the WSP. See the threat model -- long range attacks for details.

Freshness window for latest proofs

Proofs that target the latest block tag remain cryptographically valid forever -- without a freshness window, a months-old proof could still be replayed as "current". The Swift binding therefore reads the wallclock and forwards now - maxLatestAgeSeconds to the verifier, which rejects proofs whose block timestamp is older with "proof for latest too old".

The gate covers the following RPC methods:

  • EVM: eth_call, eth_estimateGas, colibri_simulateTransaction

  • Account: eth_getBalance, eth_getCode, eth_getStorageAt, eth_getTransactionCount, eth_getProof

  • Block / header: eth_getBlockByNumber, eth_getBlockHeader, eth_blobBaseFee, eth_maxPriorityFeePerGas

  • Implicit-latest: eth_blockNumber

eth_getLogs is not covered yet (tracked in issue #128). Account methods rely on a slim timestamp leaf inside the state proof which is only emitted by prover version ≥ 1.1.27; against older provers the verifier fails closed ("cannot verify freshness of latest block without block context").

  • maxLatestAgeSeconds (UInt64, default 60 ≈ 5 Ethereum slots) -- upper bound on the accepted age. Set to 0 to disable the check (e.g. when using legacy proof formats that do not embed a block context).

Caveat: the gate fires only on "latest" (not "safe"/"finalized"). If the host wallclock is behind maxLatestAgeSeconds (devices without configured time, sandboxed simulators), the lower bound clamps to 0 and the check is silently disabled. Make sure your runtime has a synced clock or set maxLatestAgeSeconds = 0 explicitly to acknowledge this state.

PAP mode: the freshness check also applies to PAP, where the call proof arrives via colibri_proofCall (same proof structure as a direct eth_call). This requires a prover that embeds the block context (≥ 1.1.15); against an older PAP proof without a block timestamp the check fails closed ("cannot verify freshness of latest block without block context"). Set maxLatestAgeSeconds = 0 to opt out.

Privacy-preserving eth_call (oblivious + PAP + hybrid)

For full storage privacy on eth_call, use hybrid prover mode, PAP, and oblivious nodes (obliviousNodes defaults to []).

  • .hybrid: block proof only from prover; storage from RPC/oblivious node, verified locally.

  • .basic (PAP): avoids eth_createAccessList on the prover; only eth_getProof RPCs are sent externally.

  • Oblivious: TEE RPC for eth_getProof; sets OBLIVIOUS + PAP flags when non-empty. See Oblivious Labs for TEE/ORAM background.

Storage System

Error Handling

Verified EVM reverts (ColibriError.revert)

When an eth_call (or similar EVM execution) is verified successfully but the EVM itself executed a REVERT, the binding throws ColibriError.revert(data:). This is a fully verified outcome -- not a transport or proof failure -- and matches the Geth-style RPC error { code: 3, message: "execution reverted", data: "0x..." }.

The associated value is the raw revert return data as a 0x-prefixed hex string. Callers typically ABI-decode this against the contract's error definitions (custom errors, Error(string), etc.). This is the mechanism that lets dApp libraries decode OffchainLookup (EIP-3668 / CCIP-Read) for example for the ENS off-chain resolver.

Storage Implementations

Default File Storage

UserDefaults Storage (iOS)

Core Data Storage

Chain Configurations

Supported Chains

Multi-Chain Setup

Performance Optimization

Storage Performance

Memory Management

Testing

Mock Request Handler

Test Utils

CI/CD Integration

GitHub Actions

The Swift bindings are fully integrated into the CI/CD pipeline:

Automatic Distribution

On every release, a distribution package is automatically created:

  1. iOS XCFramework for Device + Simulator

  2. Swift Package with binaryTarget

  3. Upload to separate distribution repository

  4. Release on GitHub with versioning

Troubleshooting

Common Issues

"No such module 'Colibri'"

iOS Simulator Crashes

RPC Calls Fail

Storage Permissions

Debug Tips

Storage Debug

Network Debug

Platform Specifics

iOS Considerations

  • App Transport Security: HTTPS required for all prover URLs

  • Background Tasks: RPC calls in background apps may be terminated

  • Memory Limits: Adjust storage cache size to iOS memory limits

  • Network Reachability: Offline capabilities through local proof generation

macOS Considerations

  • Sandboxing: Configure file system access for storage

  • Code Signing: All C libraries must be signed

  • Rosetta: Intel Mac compatibility through Universal Binaries

Further Information

Last updated