@travel-lockout/sdk
v0.1.1
Published
TypeScript SDK for Travel Lockout — offline pre-locked USDC payments on Base.
Maintainers
Readme
@travel-lockout/sdk
TypeScript SDK for Travel Lockout — offline, pre-locked USDC payments on Base.
Status: working V0, testnet only. Not audited. Built with viem.
A buyer pre-locks USDC in the on-chain contract, then authorizes a payment to a vendor offline (a signed note carried in a QR code). The vendor verifies it locally with no network, and settles on-chain later. See the repo root README and ARCHITECTURE.md for the full design and security reasoning.
Install
npm i @travel-lockout/sdkOr develop against this repo directly:
cd sdk && npm install && npm testWhat it does
| Function | Side | Purpose |
|---|---|---|
| createPayment(vendor, amount, nonce) | buyer | build a payment authorization |
| signPaymentWithKey(payment, domain, key) | buyer | sign it (EIP-712, offline) |
| signPaymentGuarded(...) | buyer | sign only within the lock's remaining budget |
| encodeToQR(...) / decodeFromQR(qr) | both | payment ⇄ scannable TL1: string |
| verifyLocally(decoded, commitment, opts) | vendor | offline accept/reject verdict |
| submitForSettlement({decoded, walletClient, publicClient}) | vendor | redeem on-chain |
| hashPayment / recoverPaymentSigner | both | low-level EIP-712 helpers |
Quick example
import {
createPayment, signPaymentWithKey, travelLockoutDomain,
encodeToQR, decodeFromQR, verifyLocally,
} from "@travel-lockout/sdk";
const domain = travelLockoutDomain({ chainId: 84532, verifyingContract: CONTRACT });
// Buyer (offline): sign a payment and show it as a QR.
const payment = createPayment(vendorAddr, 600000n /* 0.6 USDC */, 1n);
const signature = await signPaymentWithKey(payment, domain, buyerKey);
const qr = encodeToQR({ chainId: 84532, verifyingContract: CONTRACT, payment, signature });
// Vendor (offline): scan, decode, verify against a lock snapshot fetched earlier.
const decoded = decodeFromQR(qr);
const result = await verifyLocally(decoded, lockCommitment);
// -> { ok, signer, checks, reason?, residualRisk }The offline trust model (read this)
verifyLocally proves the note is authentic and consistent with the lock
the vendor last saw — it does NOT guarantee the lock still has the funds, because
the buyer's other notes may have drawn it down since the snapshot. It returns a
residualRisk note saying exactly that. The contract caps total payout at the
locked amount; signPaymentGuarded stops an honest buyer from accidentally
over-issuing. Fully-malicious over-issue can't be prevented offline — see
ARCHITECTURE.md §8.
Tests
npm test # unit + hermetic tests, fully offlineA gated live test redeems a real payment against the deployed contract on Base
Sepolia (needs a funded throwaway key + RPC in ../.env):
set -a; source ../.env; set +a
LIVE=1 npx vitest run test/live.demo.test.tsLicense
MIT.
