OutLayer Documentation

Example Projects

Production-ready examples demonstrating different WASI patterns and use cases. All examples are open-source and ready to deploy.

random-arkWASI P1Beginner#

Generate cryptographically secure random numbers inside TEE (Trusted Execution Environment) using WASI's random_get interface.

Use Cases:

  • Fair lottery systems requiring verifiable randomness
  • Gaming applications needing unpredictable outcomes
  • Cryptographic key generation
  • Random sampling for statistical analysis

Key Features:

  • Uses getrandom crate for secure randomness
  • TEE environment ensures entropy source cannot be manipulated
  • Simple JSON input/output interface
  • Perfect starter example for WASI development

Input Format:

{
  "count": 5,
  "min": 1,
  "max": 100
}

Request 5 random numbers between 1 and 100

Output Format:

{
  "numbers": [42, 17, 93, 8, 55]
}

How It Works

  1. WASM calls random_get WASI function
  2. Worker runtime requests entropy from TEE hardware
  3. Random bytes are generated using CPU's secure random number generator
  4. Numbers are scaled to requested range (min-max)
  5. Result returned as JSON

Technical Details:

  • WASI Version: Preview 1 (wasm32-wasip1)
  • Language: Rust with getrandom crate
  • Entry Point: main() reads stdin, writes stdout
  • Dependencies: serde_json for JSON parsing
  • Build: cargo build --target wasm32-wasip1 --release
  • Size: ~200KB compiled WASM

echo-arkWASI P1Beginner#

Simple echo service that accepts JSON input and returns it with a timestamp. Demonstrates basic WASI I/O and data processing.

Use Cases:

  • Testing WASI input/output pipeline
  • Verifying data serialization/deserialization
  • Template for building more complex data processing tasks
  • Learning WASI development fundamentals

Key Features:

  • JSON input validation
  • Timestamp generation using WASI clock interface
  • Error handling and structured responses
  • Minimal dependencies - great learning example

Input Format:

{
  "message": "Hello, OutLayer!",
  "metadata": {
    "user_id": "alice.near"
  }
}

Output Format:

{
  "echo": {
    "message": "Hello, OutLayer!",
    "metadata": {
      "user_id": "alice.near"
    }
  },
  "timestamp": "2025-01-15T12:34:56Z",
  "processed_by": "echo-ark v1.0"
}

How It Works

  1. WASM reads JSON from stdin
  2. Deserializes input using serde_json
  3. Generates timestamp using WASI clock_time_get
  4. Constructs response object with original data + metadata
  5. Serializes and writes to stdout

Technical Details:

  • WASI Version: Preview 1 (wasm32-wasip1)
  • Language: Rust
  • Entry Point: main()
  • Dependencies: serde, serde_json, chrono
  • Build: cargo build --target wasm32-wasip1 --release
  • Size: ~180KB compiled WASM

ai-arkWASI P2SecretsIntermediate#

Integrate OpenAI GPT models into your NEAR smart contracts. Send prompts from on-chain and receive AI-generated responses securely.

Use Cases:

  • AI-powered smart contract decision making
  • Natural language processing for on-chain data
  • Content generation triggered by blockchain events
  • Intelligent chatbots with verifiable responses

Key Features:

  • HTTP client using reqwest with WASI sockets
  • Encrypted API key storage using OutLayer secrets
  • Support for GPT-4, GPT-3.5-turbo models
  • Configurable temperature, max tokens, system prompts

Input Format:

{
  "prompt": "Explain NEAR Protocol in one sentence",
  "model": "gpt-4",
  "temperature": 0.7,
  "max_tokens": 100
}

Output Format:

{
  "response": "NEAR Protocol is a scalable, developer-friendly blockchain platform...",
  "model": "gpt-4",
  "tokens_used": 28,
  "finish_reason": "stop"
}

How It Works

  1. WASM reads OPENAI_API_KEY from encrypted secrets (env var)
  2. Constructs HTTP POST request to OpenAI API
  3. Sends request via WASI HTTP interface
  4. Receives and parses JSON response
  5. Extracts AI-generated text and metadata
  6. Returns structured result to NEAR contract

Technical Details:

  • WASI Version: Preview 2 (component model)
  • Language: Rust
  • HTTP Client: reqwest with wasi-preview2 feature
  • Secrets: Required (OPENAI_API_KEY)
  • Network: Required (outbound HTTPS to api.openai.com)
  • Build: cargo component build --release
  • Size: ~2.5MB compiled WASM

Setting Up Secrets

  1. Navigate to Secrets Management
  2. Create new secret with key OPENAI_API_KEY and your OpenAI API key as value
  3. Set repo to your GitHub project (e.g., github.com/alice/ai-ark)
  4. Choose access condition (e.g., AllowAll for testing, Whitelist for production)
  5. Worker will automatically decrypt and inject into WASM environment

Important Security Notes

  • ✅ API keys stored encrypted on-chain, decrypted only in TEE
  • ✅ Keys never exposed to worker logs or external parties
  • ⚠️ Monitor OpenAI API usage to prevent unexpected costs
  • ⚠️ Set token limits to control response sizes

weather-arkWASI P2SecretsIntermediate#

Fetch real-world weather data from OpenWeatherMap API and bring it on-chain. Perfect for parametric insurance, prediction markets, and climate-dependent DeFi.

Use Cases:

  • Weather-based parametric insurance (crop insurance, travel insurance)
  • Prediction markets requiring real-world weather data
  • Climate data for carbon credit verification
  • Event cancellation triggers based on weather conditions

Key Features:

  • Fetches temperature, humidity, pressure, wind speed
  • Supports city name or coordinates lookup
  • Returns structured weather data with timestamps
  • Encrypted API key via OutLayer secrets (OPENWEATHER_API_KEY)

Input Format (by city):

{
  "city": "London",
  "country_code": "UK"
}

Input Format (by coordinates):

{
  "lat": 51.5074,
  "lon": -0.1278
}

Output Format:

{
  "location": "London, UK",
  "temperature_celsius": 12.5,
  "humidity_percent": 76,
  "pressure_hpa": 1013,
  "wind_speed_mps": 3.2,
  "description": "partly cloudy",
  "timestamp": "2025-01-15T12:34:56Z"
}

How It Works

  1. WASM reads OPENWEATHER_API_KEY from encrypted secrets
  2. Constructs HTTP request to OpenWeatherMap API
  3. Sends GET request via WASI HTTP interface
  4. Parses JSON response with serde
  5. Converts units (Kelvin → Celsius, etc.)
  6. Returns normalized weather data to NEAR contract

Technical Details:

  • WASI Version: Preview 2 (component model)
  • Language: Rust
  • HTTP Client: reqwest with WASI sockets
  • Secrets: Required (OPENWEATHER_API_KEY)
  • Network: Required (outbound HTTPS to api.openweathermap.org)
  • API: OpenWeatherMap Current Weather API
  • Build: cargo component build --release
  • Size: ~2.2MB compiled WASM

Setting Up Secrets

  1. Get free API key from OpenWeatherMap
  2. Navigate to Secrets Management
  3. Create secret: key = OPENWEATHER_API_KEY, value = your API key
  4. Set repo to your GitHub project
  5. Choose access condition (AllowAll for public data, Whitelist for production)

Important Security Notes

  • ✅ Free tier: 60 calls/minute, 1M calls/month
  • ⚠️ Monitor API usage to stay within limits
  • ✅ API keys encrypted and only decrypted in TEE
  • ⚠️ Weather data typically updates every 10 minutes - avoid excessive calls

oracle-arkWASI P2Advanced#

Multi-source price oracle with aggregation and validation. Production-ready decentralized oracle for cryptocurrency and commodity prices.

Key Features:

  • Multiple API sources: CoinGecko, CoinMarketCap, TwelveData
  • Price aggregation methods: average, median, weighted
  • Deviation validation and error handling
  • Batch requests for multiple tokens (up to 10)
  • API key management via encrypted secrets
  • Comprehensive error reporting per source

Supported Assets:

  • Cryptocurrencies: Bitcoin, Ethereum, NEAR, SOL, etc.
  • Commodities: Gold (XAU/USD), Oil (BRENT/USD)
  • Forex: EUR/USD, GBP/USD, etc.

Input Example (Multi-token):

{
  "tokens": [
    {
      "token_id": "bitcoin",
      "sources": [
        {"name": "coingecko", "token_id": null},
        {"name": "coinmarketcap", "token_id": "BTC"}
      ],
      "aggregation_method": "median",
      "min_sources_num": 2
    }
  ],
  "max_price_deviation_percent": 5.0
}

Output Example:

{
  "tokens": [
    {
      "token": "bitcoin",
      "data": {
        "price": 110836.0,
        "timestamp": 1729447200,
        "sources": ["coingecko", "coinmarketcap"]
      },
      "message": null
    }
  ]
}

How to Use:

# 1. Get API keys (optional but recommended):
# - CoinMarketCap: https://coinmarketcap.com/api/
# - TwelveData: https://twelvedata.com/apikey
# - CoinGecko: Free tier (no key needed) or Pro

# 2. Store API keys as encrypted secrets via Dashboard
# Open https://outlayer.fastnear.com/secrets:
# - Secrets JSON: {"CMC_API_KEY":"...", "TWELVE_DATA_KEY":"..."}

# 3. Clone and build
git clone https://github.com/zavodil/oracle-ark.git
cd oracle-ark
cargo build --target wasm32-wasip2 --release

# 4. Request price data
near call outlayer.testnet request_execution '{
  "source": {
    "GitHub": {
      "repo": "https://github.com/YOUR_USERNAME/oracle-ark",
      "commit": "main",
      "build_target": "wasm32-wasip2"
    }
  },
  "secrets_ref": {
    "profile": "production",
    "account_id": "your-account.testnet"
  },
  "resource_limits": {
    "max_instructions": 100000000,
    "max_memory_mb": 128,
    "max_execution_seconds": 60
  },
  "input_data": "{\"tokens\":[{\"token_id\":\"bitcoin\",\"sources\":[{\"name\":\"coingecko\"},{\"name\":\"coinmarketcap\",\"token_id\":\"BTC\"}],\"aggregation_method\":\"median\",\"min_sources_num\":2}],\"max_price_deviation_percent\":5.0}"
}' --accountId your-account.testnet --deposit 0.1 --gas 300000000000000

# Result will contain median price from multiple sources

Technical Details:

  • WASI Version: Preview 2 (component model)
  • Language: Rust
  • HTTP Client: reqwest with WASI sockets
  • Secrets: Optional (API keys for higher rate limits)
  • Network: Required (outbound HTTPS to multiple APIs)
  • Build: cargo component build --release
  • Size: ~3.5MB compiled WASM

Ethereum API OracleWASI P2Advanced#

Query Ethereum blockchain data via JSON-RPC (balances, smart contracts, transactions). Similar to the previous oracle example but configured for Ethereum node providers like Alchemy. Bridge NEAR with Ethereum data for cross-chain applications.

Key Features:

  • Ethereum JSON-RPC API integration (eth_getBalance, eth_call, etc.)
  • Support for Alchemy, Infura, and other Ethereum node providers
  • Custom request structure with JSON path extraction
  • Cross-chain data oracle for NEAR ↔ Ethereum bridges
  • Encrypted API key storage (Alchemy secrets profile)
  • Production-ready on testnet and mainnet

Input Example (Check ETH Balance):

{
  "requests": [
    {
      "id": "alchemy",
      "sources": [
        {
          "name": "custom",
          "custom": {
            "url": "https://eth-mainnet.g.alchemy.com/v2",
            "method": "POST",
            "body": {
              "method": "eth_getBalance",
              "params": ["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "latest"],
              "id": 1,
              "jsonrpc": "2.0"
            },
            "json_path": "result",
            "value_type": "string"
          }
        }
      ]
    }
  ],
  "max_price_deviation_percent": 10.0
}

Output Example:

{
  "results": [
    {
      "id": "alchemy",
      "value": "0x1bc16d674ec80000",
      "sources_used": 1
    }
  ]
}

Quick Start (Testnet):

# Using pre-configured Alchemy secrets on testnet
near contract call-function as-transaction outlayer.testnet request_execution \
  json-args '{
    "source": {
      "GitHub": {
        "repo": "https://github.com/zavodil/oracle-ark",
        "commit": "main",
        "build_target": "wasm32-wasip2"
      }
    },
    "secrets_ref": {
      "profile": "alchemy",
      "account_id": "zavodil2.testnet"
    },
    "resource_limits": {
      "max_instructions": 100000000,
      "max_memory_mb": 128,
      "max_execution_seconds": 60
    },
    "input_data": "{\"requests\":[{\"id\":\"alchemy\",\"sources\":[{\"name\":\"custom\",\"custom\":{\"url\":\"https://eth-mainnet.g.alchemy.com/v2\",\"method\":\"POST\",\"body\":{\"method\":\"eth_getBalance\",\"params\":[\"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\",\"latest\"],\"id\":1,\"jsonrpc\":\"2.0\"},\"json_path\":\"result\",\"value_type\":\"string\"}}]}],\"max_price_deviation_percent\":10.0}"
  }' \
  prepaid-gas '300.0 Tgas' \
  attached-deposit '0.1 NEAR' \
  sign-as your-account.testnet \
  network-config testnet \
  sign-with-keychain send

Use Cases:

  • Cross-Chain Bridges: Verify Ethereum transactions on NEAR
  • DeFi Integration: Monitor Ethereum token balances from NEAR contracts
  • Multi-Chain Wallets: Display ETH balances in NEAR apps
  • Smart Contract State: Read Ethereum contract data (ERC20, NFTs)
  • Block Explorer: Query Ethereum transaction history

Notes:

  • Same codebase as oracle-ark, different secrets configuration
  • Requires Alchemy API key (free tier: 300M compute units/month)
  • Supports any Ethereum JSON-RPC method (eth_call, eth_getTransactionReceipt, etc.)
  • Pre-configured secrets available on testnet: zavodil2.testnet
  • Mainnet secrets: zavodil.near

Technical Details:

  • WASI Version: Preview 2 (component model)
  • Language: Rust
  • HTTP Client: reqwest with WASI sockets
  • Secrets: Required (ALCHEMY_API_KEY)
  • Network: Required (outbound HTTPS to Alchemy/Infura)
  • Build: cargo component build --release
  • Size: ~3.5MB compiled WASM

botfather-arkWASI P2Host FunctionsAdvanced#

Account factory pattern for NEAR - create and manage multiple NEAR accounts with AI-generated names using hierarchical key derivation. Demonstrates advanced host function usage with call() and transfer(), providing access to private NEAR RPC endpoints (powered by Fastnear).

Use Cases:

  • Account Factory: Generate multiple NEAR accounts programmatically
  • Batch Operations: Execute contract calls on multiple accounts simultaneously (e.g., buy tokens, delegate to staking pool)
  • Onboarding Platform: Create named accounts for users via Telegram bots or web apps
  • Sub-Account Management: Manage hierarchical account structures with deterministic key derivation

Key Features:

  • AI-powered account name generation (GPT integration)
  • Deterministic key derivation from master seed using SHA-256
  • Account discovery via Fastnear API
  • Batch contract calls with template variables ({{account_id}})
  • Fund distribution across multiple accounts
  • Uses near:rpc/[email protected] host functions: call(), transfer()

Actions:

1. Create Accounts:

{
  "action": "create_accounts",
  "prompt": "space exploration theme",
  "count": 3,
  "deposit_per_account": "1000000000000000000000000"
}

Creates accounts like mars-rover.testnet, moon-base.testnet

2. Fund Accounts:

{
  "action": "fund_accounts",
  "total_amount": "30000000000000000000000000",
  "indices": []
}

Empty indices = fund all accounts equally (30 NEAR ÷ 3 accounts = 10 NEAR each)

3. Batch Contract Calls:

{
  "action": "batch_call",
  "contract_id": "token.near",
  "method_name": "transfer",
  "args": {"receiver_id": "{{account_id}}", "amount": "1000"},
  "deposit": "1",
  "gas": "30000000000000",
  "indices": [0, 2]
}

Execute on accounts at indices 0 and 2. Use {{account_id}} placeholder for dynamic account ID

4. List Accounts:

{
  "action": "list_accounts"
}

Returns all created accounts with balances and public keys

Output Example:

{
  "success": true,
  "accounts": [
    {
      "index": 0,
      "account_id": "mars_rover.testnet",
      "public_key": "ed25519:...",
      "balance": "1000000000000000000000000",
      "balance_near": "1.0000"
    }
  ],
  "transactions": [
    {
      "account_id": "mars_rover.testnet",
      "tx_hash": "Abc123...",
      "success": true
    }
  ]
}

How It Works

  1. Key Derivation in TEE: Derivation key (PROTECTED_MASTER_KEY) is generated inside TEE (nobody ever sees it). Derived keys are created using SHA-256: SHA256(derivation_key + sender_id + index) - each derived key controls one account
  2. Account Discovery: Queries Fastnear API to find existing accounts by derived public keys (stateless operation)
  3. AI Name Generation: Calls OpenAI API to generate creative account names based on theme prompt
  4. Account Creation: Uses NEAR RPC call() host function to create accounts via create_account action
  5. Batch Execution: Iterates through account indices and executes operations using call() or transfer()

Setting Up Secrets

⚠️ This example is not available in Playground because it requires creating a secret with NEAR_SENDER_PRIVATE_KEY - your NEAR account's private key (with NEAR tokens) to pay for account creation and funding.

To use this example, create a secret in the Secrets page with the following configuration:

Manual Secrets:
{
  "NEAR_SENDER_PRIVATE_KEY": "ed25519:your_private_key",
  "OPENAI_API_KEY": "sk-...",
  "OPENAI_ENDPOINT": "https://api.openai.com/v1/chat/completions",
  "OPENAI_MODEL": "gpt-3.5-turbo"
}
Generated Secret (created in TEE):
  • Click "Generate Secret" button
  • Secret name: PROTECTED_MASTER_KEY
  • Type: ED25519 (generates ed25519 key pair in TEE)
  • This key is created inside TEE and never exposed - used to derive all account keys
Access Control:

Set 👥 Whitelist with your account ID (the one that will manage created accounts)

Technical Details:

  • WASI Version: Preview 2 (component model)
  • Language: Rust
  • WIT Interface: near:rpc/[email protected] (call, transfer, view)
  • Secrets: Required (NEAR_SENDER_PRIVATE_KEY, OPENAI_API_KEY, PROTECTED_MASTER_KEY)
  • Network: Required (Fastnear API, OpenAI API, NEAR RPC via host functions)

Important Security Notes

  • WASM provides signer: User's NEAR private key is passed via secrets (not worker's key)
  • Keys created in TEE: Derivation key (PROTECTED_MASTER_KEY) is generated inside TEE and never leaves it. Derived keys are created using deterministic SHA-256 derivation from derivation key.
  • Accounts managed only in TEE: All derived accounts are controlled exclusively by keys that exist only inside TEE - nobody can export or see the private keys
  • Deterministic keys: Same derivation key + sender + index always generates same account key
  • Derivation key isolation: Each NEAR_SENDER_ID has isolated account space
  • ⚠️ Store derivation key safely: Loss of derivation key = loss of access to all derived accounts

intents-arkWASI P2Advanced#

DEX token swaps via NEAR Intents protocol. User's FT transfer transaction pauses, WASI performs swap off-chain, then resolves by sending swapped tokens back - all within single transaction.

Key Features:

  • FT transfer pauses during off-chain swap execution
  • NEAR Intents API integration (quote → publish → settle)
  • NEP-413 message signing with ed25519
  • Automatic token withdrawal to user upon completion
  • Private key management via encrypted secrets
  • Storage deposit handling for fungible tokens

Transaction Flow:

  1. User calls ft_transfer_call to swap contract
  2. Contract receives tokens and calls OutLayer
  3. Transaction pauses - contract enters yield state
  4. WASI worker performs swap via NEAR Intents API
  5. Worker withdraws swapped tokens to user
  6. Transaction resumes - contract completes with callback

How to Use:

# 1. Create operator account on NEAR mainnet
near create-account operator.near --useFaucet

# 2. Store operator private key as encrypted secret
# Open https://outlayer.fastnear.com/secrets:
# - Secrets JSON: {"OPERATOR_PRIVATE_KEY":"ed25519:..."}

# 3. Clone and deploy swap contract
git clone https://github.com/zavodil/intents-ark.git
cd intents-ark/contract
cargo near build
near deploy swap-contract.near res/swap_contract.wasm

# 4. Initialize contract
near call swap-contract.near new '{
  "operator_account_id": "operator.near"
}' --accountId swap-contract.near

# 5. User swaps 1 WNEAR for USDC
near call wrap.near ft_transfer_call '{
  "receiver_id": "swap-contract.near",
  "amount": "1000000000000000000000000",
  "msg": "{\"Swap\":{\"token_out\":\"usdc.token\",\"min_amount_out\":\"900000\"}}"
}' --accountId user.near --depositYocto 1 --gas 300000000000000

# Transaction will:
# - Pause after receiving WNEAR
# - Execute swap off-chain via NEAR Intents
# - Resume and send swapped USDC to user

Note: NEAR Intents works on mainnet only. For testnet testing, use mock swap implementation.

Technical Details:

  • WASI Version: Preview 2 (component model)
  • Language: Rust
  • HTTP Client: reqwest for NEAR Intents API
  • Secrets: Required (OPERATOR_PRIVATE_KEY)
  • Network: Required (NEAR Intents API, mainnet only)
  • Signing: NEP-413 message signing with ed25519
  • Build: cargo component build --release
  • Size: ~3.8MB compiled WASM

private-dao-arkWASI P1Advanced#

Anonymous, verifiable DAO voting with cryptographic privacy. Heavy cryptography (ECIES encryption, HKDF key derivation, merkle tree proofs) executed off-chain in TEE. Each user's vote is encrypted on-chain, tallying happens in secure enclave, only aggregate counts are revealed.

🔐 Privacy Guarantees:

  • Individual votes remain secret - only aggregate counts revealed
  • DAO members can send encrypted noise instead of real votes to hide voting activity from observers
  • Merkle proofs allow voters to verify their vote was counted without revealing how they voted

Key Features:

  • ECIES encryption for private votes (secp256k1)
  • HKDF-SHA256 deterministic key derivation from single master secret
  • Merkle tree construction for vote inclusion proofs
  • Dummy messages: Send encrypted noise to hide whether you voted (indistinguishable from real votes on-chain)
  • Vote changes: Vote multiple times, timestamp-based deduplication (latest vote wins)
  • TEE attestation for execution integrity
  • Full-stack React frontend with NEAR Wallet integration

Architecture:

1. Generate master secret:
   OutLayer → TEE generates random master secret (stored encrypted)

2. User joins DAO:
   Contract → OutLayer → TEE derives pubkey from master secret

3. User votes:
   Frontend encrypts vote with pubkey → Contract stores encrypted vote

4. Finalize proposal:
   Contract → OutLayer → TEE decrypts votes + tallies + builds merkle tree
   Returns aggregate counts + merkle proofs (individual votes never exposed)

5. Verify vote:
   User computes vote hash → Verifies merkle proof against root

Privacy Features:
- Individual votes never revealed (only aggregate counts)
- Dummy messages: Send encrypted noise to hide voting activity
- Vote changes: Vote multiple times, only latest counts (timestamped)
- Merkle proofs: Verify inclusion without revealing vote content

Cost: Heavy cryptography off-chain = ~$0.001 per vote

Cryptographic Components:

HKDF Key Derivation
// Single master secret → unique key per user
let info = format!("user:{}:{}", dao_account, user_account);
let user_privkey = hkdf_sha256(&master_secret, info.as_bytes());
let user_pubkey = secp256k1::derive_public_key(&user_privkey);
ECIES Encryption (Frontend)
import { encrypt } from 'eciesjs';

const vote = "yes";  // or "no"
const pubkeyHex = await contract.get_user_pubkey({ user });
const encrypted = encrypt(pubkeyHex, Buffer.from(vote));
await contract.cast_vote({ proposal_id, encrypted_vote: encrypted.toString('hex') });
Vote Hash Computation (Critical!)
// Must preserve u64 precision - use BigInt!
const timestamp = result.receipts_outcome[0].outcome.status.SuccessValue;
const timestampStr = atob(timestamp).trim();  // Keep as string
const timestampBigInt = BigInt(timestampStr);

// Convert to 8-byte little-endian
const buffer = new ArrayBuffer(8);
new DataView(buffer).setBigUint64(0, timestampBigInt, true);

// SHA256(user + timestamp_le + encrypted)
const combined = concat(
  textEncoder.encode(accountId),
  new Uint8Array(buffer),
  textEncoder.encode(encrypted)
);
const voteHash = hex(await crypto.subtle.digest('SHA-256', combined));
Merkle Proof Verification
// Try all possible paths (2^depth combinations)
async function verifyProof(voteHash, proofPath, merkleRoot) {
  async function tryPaths(hash, remaining) {
    if (!remaining.length) return hash === merkleRoot;

    const [sibling, ...rest] = remaining;

    // Try both orderings
    if (await tryPaths(await sha256(hash + sibling), rest)) return true;
    if (await tryPaths(await sha256(sibling + hash), rest)) return true;

    return false;
  }
  return await tryPaths(voteHash, proofPath);
}

How to Deploy:

# 1. Generate DAO master secret in TEE
# (Alternatively: generate locally and store encrypted)
openssl rand -hex 32 > dao_master_secret.txt

# 2. Store master secret via Dashboard (encrypted in keystore)
# Open https://outlayer.fastnear.com/secrets:
# - Repo: github.com/YOUR_USERNAME/private-dao-ark
# - Profile: production
# - Secrets JSON: {"DAO_MASTER_SECRET":"<paste hex from file>"}
# - Access: AllowAll (or Whitelist for DAO admin only)

# 3. Clone and build WASI module
git clone https://github.com/zavodil/private-dao-ark.git
cd private-dao-ark
cargo build --target wasm32-wasip1 --release
git push origin main

# 4. Deploy DAO contract
cd dao-contract
cargo near build
near deploy privatedao.testnet \
  use-file res/private_dao_contract.wasm \
  with-init-call new \
  json-args '{
    "owner_id":"owner.testnet",
    "name":"My Private DAO",
    "outlayer_contract":"outlayer.testnet",
    "wasi_repo":"https://github.com/YOUR_USERNAME/private-dao-ark",
    "wasi_commit":"main",
    "secrets_profile":"production",
    "secrets_owner":"your.testnet",
    "membership_mode":"Public"
  }' \
  prepaid-gas '100.0 Tgas' \
  attached-deposit '0 NEAR'

# 5. Deploy frontend
cd ../dao-frontend
npm install
cat > .env <<EOF
REACT_APP_CONTRACT_ID=privatedao.testnet
REACT_APP_NEAR_NETWORK=testnet
EOF
npm run build
# Deploy build/ to Vercel/Netlify/Cloudflare Pages

# 6. Users can now:
# - Join DAO (get encrypted pubkey derived from master secret)
# - Create proposals with quorum requirements
# - Vote privately (votes encrypted with their pubkey)
# - Finalize proposals (OutLayer decrypts in TEE and tallies)
# - Verify their vote was counted (merkle proof verification)

Use Cases:

  • Anonymous Governance: Board elections where individual votes should remain secret
  • Whistleblower Protection: Report issues without revealing identity
  • Salary Decisions: Vote on compensation without peer pressure
  • Grant Allocation: Fund projects while preventing vote buying
  • Conflict Resolution: Vote on sensitive matters privately

Technical Highlights:

💰 Cost Efficiency

Heavy cryptography off-chain: ~$0.001/vote
ECIES + HKDF + Merkle trees feasible with OutLayer

🔒 Privacy Model

Encrypted votes on-chain
Dummy messages hide voting activity
Vote changes allowed (latest wins)
Decryption in secure enclave

✅ Verifiability

Merkle proofs: Voters verify inclusion
TEE attestation: Verify execution integrity

⚡ Scalability

Master secret in TEE → unlimited users
No storage overhead for keys

Important Security Notes

  • Master secret must be highly secured (hardware wallet, multi-sig, etc.)
  • TEE attestation uses Intel TDX via Phala Network
  • Frontend must correctly compute vote hash (BigInt for u64 precision!)
  • Vote hash saved by user is CRITICAL for later verification

Technical Details:

  • WASI Version: Preview 1 (wasm32-wasip1)
  • Language: Rust
  • Cryptography: ECIES (secp256k1), HKDF-SHA256, Merkle trees
  • Secrets: Required (DAO_MASTER_SECRET)
  • Frontend: React with NEAR Wallet integration
  • Build: cargo build --target wasm32-wasip1 --release
  • Size: ~1.2MB compiled WASM

captcha-arkWASI P2Full Stack#

Token sale with mandatory CAPTCHA verification. Transaction won't complete until user solves CAPTCHA. WASI worker receives session ID from backend and waits for verification signal. Example implementation demonstrating async human verification pattern.

Key Features:

  • Transaction blocking until CAPTCHA solved
  • WASI worker requests CAPTCHA challenge from backend
  • Backend sends CAPTCHA to user via WebSocket
  • Worker waits for verification signal (long-polling)
  • hCaptcha integration for human verification
  • React frontend with NEAR Wallet Selector
  • Node.js backend with Express + WebSocket server

Architecture:

User Browser → Token Sale Contract → OutLayer → WASI Worker
      ↑                                              ↓
      └────── Launchpad Backend (WebSocket) ←────────┘

Flow:
1. User clicks "Buy Tokens" with session_id
2. Contract calls OutLayer, transaction pauses
3. WASI worker → backend: "I received payment from session_id X.
   Verify this is a real user, not a bot. Send CAPTCHA and notify
   me when user completes it."
4. Backend sends CAPTCHA to user's browser via WebSocket
5. User solves CAPTCHA in modal
6. Backend verifies solution and marks session as verified
7. Worker receives "verified" signal, returns success to contract
8. Transaction resumes - user receives tokens

Components:

  • WASI Worker: Rust WASM that verifies CAPTCHA (wasm32-wasip2)
  • Smart Contract: Token sale logic with OutLayer integration
  • Backend: Node.js Express server with WebSocket support
  • Frontend: React app with hCaptcha widget

How to Use:

# 1. Get hCaptcha account (free at hcaptcha.com)
# - Create site and get Site Key + Secret Key

# 2. Clone repository
git clone https://github.com/zavodil/captcha-ark.git
cd captcha-ark

# 3. Setup backend
cd launchpad-backend
npm install
cat > .env <<EOF
PORT=3181
HCAPTCHA_SITE_KEY=your_site_key
HCAPTCHA_SECRET=your_secret_key
WORKER_API_KEY=$(openssl rand -hex 32)
EOF
npm start

# 4. Setup frontend
cd ../launchpad-app
npm install
cat > .env <<EOF
REACT_APP_CONTRACT_ID=tokensale.testnet
REACT_APP_NEAR_NETWORK=testnet
REACT_APP_HCAPTCHA_SITE_KEY=your_site_key
EOF
npm run build
# Deploy build/ to your web server

# 5. Build WASI worker
cd ../captcha-ark
cargo build --target wasm32-wasip2 --release
git push origin main

# 6. Deploy token sale contract
cd ../token-sale-contract
cargo near build
near deploy tokensale.testnet \
  use-file res/token_sale_contract.wasm \
  with-init-call new \
  json-args '{"owner":"owner.testnet","total_supply":"10000","launchpad_url":"https://api.yourdomain.com"}' \
  prepaid-gas '100.0 Tgas' \
  attached-deposit '0 NEAR'

# 7. Users can now buy tokens - CAPTCHA required!
# Visit https://launchpad.yourdomain.com and click "Buy Tokens"

Production Setup: Requires SSL certificates for both frontend and backend domains. See CONFIGURATION.md for complete deployment guide.

Important Security Notes

  • Backend must implement worker authentication to prevent spam attacks
  • Unauthorized requests to create CAPTCHA challenges should be rejected
  • Use HTTPS for both frontend and backend in production
  • Implement rate limiting on CAPTCHA challenge creation

Technical Details:

  • WASI Version: Preview 2 (component model)
  • Language: Rust (WASM), TypeScript (Frontend/Backend)
  • HTTP Client: reqwest for backend communication
  • Backend: Node.js + Express + WebSocket
  • Frontend: React with NEAR Wallet Selector
  • CAPTCHA: hCaptcha integration
  • Build: cargo component build --release
  • Size: ~2.8MB compiled WASM