Developers · Solana

Solana onchain eligibility gate

A partner-owned program verifies a short-lived Abraxas authorization and consumes it once. Abraxas remains the policy layer. Your program remains the executor.

How it works

Private holder verification -> server verifies the current public receipt -> Abraxas signs a narrow Solana authorization (canonical message + dedicated Ed25519 key) -> the partner transaction includes the Ed25519 native verify instruction immediately before gate authorize -> the partner program CPI-consumes the PDA once. Server durable nonce (migration 101) and the onchain PDA are both required.

The reference gate is deployed on Solana devnet with the reviewed V2 ELF. GateConfig is not initialized or registered, so this is not an active eligibility integration. The consumer ID is a local fixture. No Mainnet deployment.

Canonical message

Prefix ABRAXAS_CHAIN_ELIGIBILITY_V2, then keccak of that prefix, schema version 2 as a big-endian u64, then network, partner, policy, action, and subject hashes, issued/expiry timestamps, nonce, attestation id, environment, signer key id, and opaque organization, actor, and institutional result-category commitments. Total 468 bytes. Legacy 372-byte V1 messages are rejected. The program requires an exact byte-for-byte match. It does not parse JSON and does not accept a browser allowed flag.

Accounts and PDA seeds

GateConfig PDA: ["gate_config", admin]
Authorization PDA: ["authorization", config, attestation_id]
Consumer authority PDA: ["consumer_authority"] (seeds::program = partner program)
Test result PDA (reference consumer): ["test_result", authorization]

Reference gate on devnet (unconfigured): 4hf3cY57ciPakr4omyTSbksAfW672iGrdo6fiDVQAD4K
Local-only consumer (not deployed): J2xccRtuG43drESLYznHhLhQkLTdfepcKYbiQ9BsJVaf

Stored on Authorization: hashed partner/policy/action binding, expiry, consumed/revoked, opaque attestation_ref.
Never stored: receipts, evidence, signatures, wallets beyond the required subject hash, provider payloads.

Local commands

cd solana/abraxas-eligibility-gate
cargo test --workspace
# Optional with a full Anchor toolchain:
# anchor build   # Anchor 0.30.1
# anchor test

The reviewed reference gate ELF was deployed to devnet at slot 502739924 and dumped back from chain with matching keccak and SHA-256 digests. Its transaction is 51Xhh2…CDFvSL. GateConfig has not been initialized, the partner consumer is not deployed, and the gate is not registered for issuance. No Mainnet claim.

Server example

import { AbraxasPartnerKit } from "@abraxas/partner-kit";

const kit = new AbraxasPartnerKit({
  partnerId: process.env.ABRAXAS_PARTNER_ID!,
  policyId: process.env.ABRAXAS_POLICY_ID!,
  policyVersion: 1,
  requirePolicyVersion: true,
  environment: "sandbox",
});

export async function issueSolanaOnchainGate(receiptId: string) {
  const res = await fetch(process.env.ABRAXAS_BASE_URL + "/api/v1/chain-attestations", {
    method: "POST",
    headers: {
      authorization: "Bearer " + process.env.ABRAXAS_SANDBOX_API_KEY,
      "content-type": "application/json",
    },
    body: JSON.stringify({
      receipt_id: receiptId,
      action_type: "partner_protocol_action",
      action_scope: "sandbox:partner_protocol",
      network_id: "solana_devnet",
      deployment_ref: process.env.ABRAXAS_GATE_DEPLOYMENT_REF,
      wallet_binding_mode: "required",
    }),
  });
  const issued = await res.json();
  if (!issued.allowed) return issued;
  // YOUR transaction: Ed25519 verify instruction immediately before gate authorize.
  // Then YOUR program consumes the PDA once. Abraxas does not submit the transaction.
  // A valid authorization is not a payment, transfer, trade, or token mint.
  return issued;
}

Related

Off-chain Solana adapter (no funds): /docs/solana. Chain attestation encoding: /docs/chain-verifiable-attestations. Signer rotation: /docs/chain-attestation-signer-lifecycle.