Reference@t402/tezos

@t402/tezos

Tezos blockchain implementation for T402 payments using FA2 (TZIP-12) tokens.

Installation

pnpm add @t402/tezos

Overview

The @t402/tezos package enables T402 payments on Tezos using the FA2 token standard (TZIP-12). It uses the exact-direct scheme — the client executes the transfer entrypoint directly on the FA2 contract.

Key features:

  • FA2 standard (TZIP-12) — multi-asset token contracts
  • Token IDs — FA2 contracts can hold multiple token types
  • TzKT indexer — transaction verification via indexer API

Network IDs

NetworkCAIP-2 IDRPC Endpoint
Mainnettezos:NetXdQprcVkpaWUhttps://mainnet.api.tez.ie
Ghostnet (Testnet)tezos:NetXnHfVqm9iesphttps://ghostnet.tezos.marigold.dev

Tezos CAIP-2 identifiers use the network’s genesis block hash prefix.

Client Usage

import { ExactDirectTezosClient } from '@t402/tezos/exact-direct/client'
 
const client = new ExactDirectTezosClient({
  address: 'tz1YourAddress...',
  signAndSendOperation: async (params) => {
    // Use your Tezos wallet (Temple, Kukai, etc.)
    const result = await wallet.sendOperation(params)
    return result.opHash
  }
})
 
const payload = await client.createPaymentPayload(2, requirements)

Server Usage

import { ExactDirectTezosServer } from '@t402/tezos/exact-direct/server'
 
const server = new ExactDirectTezosServer({
  rpcUrl: 'https://mainnet.api.tez.ie'
})
 
const enhanced = await server.enhancePaymentRequirements(baseRequirements)

Facilitator Usage

import { ExactDirectTezosFacilitator } from '@t402/tezos/exact-direct/facilitator'
 
const facilitator = new ExactDirectTezosFacilitator({
  rpcUrl: 'https://mainnet.api.tez.ie',
  indexerUrl: 'https://api.tzkt.io' // TzKT indexer for verification
})
 
const result = await facilitator.verify(payload, requirements)
const settled = await facilitator.settle(payload, requirements)

PaymentRequirements

const requirements = {
  scheme: 'exact-direct',
  network: 'tezos:NetXdQprcVkpaWU',
  amount: '1000000', // 1 USDT (6 decimals)
  asset: 'KT1XnTn74bUtxHfDtBmm2bGZAQfhPbvKWR8o', // FA2 contract
  payTo: 'tz1MerchantAddress...',
  maxTimeoutSeconds: 300,
  extra: {
    tokenId: 0 // Token ID within the FA2 contract
  }
}

Payment Flow

  1. Client calls the FA2 transfer entrypoint on the token contract
  2. Operation is injected into the Tezos network
  3. Client returns the opHash (operation hash) as proof
  4. Facilitator verifies via TzKT indexer or RPC
  5. Operation is confirmed after 1+ block confirmations

Token Addresses

TokenNetworkFA2 ContractToken IDDecimals
USDtMainnetKT1XnTn74bUtxHfDtBmm2bGZAQfhPbvKWR8o06
⚠️

FA2 contracts can hold multiple tokens. Always specify the tokenId in the extra field of PaymentRequirements. USDT on Tezos uses token ID 0.

Payload Structure

interface ExactDirectTezosPayload {
  opHash: string;           // operation hash (o prefix, base58)
  from: string;             // sender address (tz1/tz2/tz3 prefix)
  to: string;               // recipient address
  amount: string;           // amount in smallest units
  contractAddress: string;  // FA2 contract address (KT1 prefix)
  tokenId: number;          // token ID within contract
}

FA2 Transfer Entrypoint

The FA2 transfer entrypoint accepts:

transfer: list(
  pair(
    address,  // from
    list(pair(address, pair(nat, nat)))  // [(to, (token_id, amount))]
  )
)

Address Formats

PrefixType
tz1Ed25519 implicit account
tz2Secp256k1 implicit account
tz3P-256 implicit account
KT1Originated contract

Error Codes

CodeDescription
invalid_payload_structureMissing opHash, from, to, or amount
network_mismatchOperation network doesn’t match
amount_mismatchTransferred amount less than required
recipient_mismatchTransfer recipient doesn’t match payTo
contract_mismatchFA2 contract doesn’t match asset
token_id_mismatchToken ID doesn’t match requirements
operation_not_foundOperation hash not found
operation_failedOperation exists but failed

Example: Full Integration

import { t402Client } from '@t402/fetch'
import { registerExactDirectTezosClient } from '@t402/tezos/exact-direct/client'
 
const client = new t402Client()
registerExactDirectTezosClient(client, {
  address: wallet.address,
  signAndSendOperation: wallet.sendOperation
})
 
const response = await client.fetch('https://api.example.com/premium')

Go SDK

import "github.com/t402-io/t402/sdks/go/mechanisms/tezos"
 
// Client
client := tezos.NewExactDirectTezosScheme(signer, &tezos.Config{})
payload, err := client.CreatePaymentPayload(ctx, requirements)
 
// Facilitator
facilitator := tezos.NewExactDirectTezosFacilitator(rpcURL, indexerURL)
result, err := facilitator.Verify(ctx, payload, requirements)