Skip to main content

Statechain Pass

Type: Off-chain transferable asset
Audience: Event platforms, access control systems, voucher issuers

Statechain Pass is a system for issuing and transferring off-chain ownership records — tickets, vouchers, door passes, or content licences — without touching the Minima chain for every transfer. Ownership is a chain of WOTS signatures; the current holder proves ownership by presenting the full chain. An agent-policy enforces approved recipients, expiry checks, and provenance auditing.


Packages used

PackageRole in Statechain Pass
@totemsdk/statechainCore off-chain ownership chain — create, transfer, verify
@totemsdk/agent-policyEnforces approved recipients, expiry, and provenance rules
@totemsdk/wots-leaseManages signing key lifecycle for each transfer
@totemsdk/chain-providerAnchors statechain roots on-chain for finality
@totemsdk/connectBrowser dApp bridge for customer wallet interactions
@totemsdk/realtimePushes transfer confirmations to issuer dashboard

Core integration path

1. Issue a pass

import { createStatechain } from '@totemsdk/statechain';
import { createSharedLeaseStrategy } from '@totemsdk/wots-lease';

const leaseStrategy = createSharedLeaseStrategy({ storage, storageKey: 'issuer-lease' });
const signer = await leaseStrategy.getSigner();

// Issue a new event ticket
const pass = await createStatechain({
assetId: `ticket:${eventId}:${seatNumber}`,
issuer: ISSUER_ADDRESS,
recipient: initialHolder,
metadata: {
event: 'Minima DevCon 2026',
seat: 'A12',
expiresAt: new Date('2026-06-01').getTime(),
},
signer,
});

console.log('Pass created:', pass.chainId);

2. Transfer to a new holder

import { transferStatechain } from '@totemsdk/statechain';

async function transferPass(pass: Statechain, newHolder: string) {
const proposal = {
id: crypto.randomUUID(),
intent: {
type: 'asset_transfer' as const,
assetId: pass.chainId,
from: pass.currentHolder,
to: newHolder,
expiresAt: pass.metadata.expiresAt,
},
requestedBy: { id: 'statechain-pass-app', type: 'app' as const },
createdAt: Date.now(),
};

const decision = await passPolicy.evaluate(proposal);
if (decision.outcome === 'rejected') throw new Error(decision.reason);
if (decision.outcome === 'requires_human') {
const ok = await confirm(decision.prompt);
if (!ok) return;
}

const transferSigner = await leaseStrategy.getSigner();
return transferStatechain(pass, { newHolder, signer: transferSigner });
}

3. Policy: approved recipients and expiry

import type { AgentPolicy, AgentProposal } from '@totemsdk/agent-policy';

const passPolicy: AgentPolicy = {
async evaluate(proposal: AgentProposal) {
const { intent } = proposal;
if (intent.type !== 'asset_transfer') {
return { outcome: 'rejected', reason: 'Only asset_transfer intents accepted' };
}

// Check expiry
if (intent.expiresAt && Date.now() > intent.expiresAt) {
return { outcome: 'rejected', reason: 'Pass has expired' };
}

// Check recipient allowlist (e.g. KYC'd wallets)
const isApproved = await recipientRegistry.isApproved(intent.to);
if (!isApproved) {
return {
outcome: 'requires_human',
prompt: `Recipient ${intent.to} is not on the approved list. Transfer anyway?`,
};
}

return {
outcome: 'approved',
receipt: buildReceipt(proposal, 'pass-policy-v1'),
};
},
};

4. Verify ownership at the gate

import { verifyStatechain } from '@totemsdk/statechain';
import { connect } from '@totemsdk/connect';

const { address } = await connect(location.origin);
const pass = await fetchPassFromWallet(address);

const valid = await verifyStatechain(pass, {
expectedIssuer: ISSUER_ADDRESS,
currentHolder: address,
checkExpiry: true,
});

if (valid) openGate();
else showError('Invalid or expired pass');

Future QVAC hook

Future QVAC hook

A QVAC agent can automate bulk pass issuance from a ticket manifest, monitor secondary-market transfer rates, auto-expire passes at event end, and trigger on-chain anchoring for audit compliance — all through the passPolicy boundary. The human operator only reviews flagged edge cases.