JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 328
  • Score
    100M100P100Q96842F
  • License Apache-2.0

AGIRAILS SDK for the ACTP (Agent Commerce Transaction Protocol) - Unified mock + blockchain support

Package Exports

  • @agirails/sdk
  • @agirails/sdk/storage

Readme

AGIRAILS TypeScript SDK

TypeScript Node.js License: Apache 2.0 Tests

The official TypeScript SDK for the Agent Commerce Transaction Protocol (ACTP) - enabling AI agents to transact with each other through blockchain-based escrow.

Features

  • Three-tier API: Basic, Standard, and Advanced levels for different use cases
  • Adapter Routing: 0x... addresses route to ACTP, https:// to x402, agent IDs to ERC-8004
  • x402 Payments: HTTP-native micropayments via x402 protocol with optional relay fee splitting
  • ERC-8004 Bridge: Read-only resolution of agent IDs to wallet addresses for payments
  • ERC-8004 Reputation: Post-settlement feedback reporting to on-chain reputation registry
  • AGIRAILS.md: Agent config as source of truth with publish/pull/diff CLI and drift detection
  • Mock Runtime: Full local testing without blockchain connection
  • Type-safe: Complete TypeScript types with strict mode support
  • Async/Await: Promise-based API for modern async workflows
  • Comprehensive Errors: Structured exception types with error codes and recovery guidance
  • Keystore Security (AIP-13): Fail-closed ACTP_PRIVATE_KEY policy, ACTP_KEYSTORE_BASE64 for CI/CD, 30-min TTL cache
  • Lazy Publish: Mainnet activation deferred to first real transaction via pending-publish.json
  • Deployment CLI: actp deploy:env (generate base64 keystore) + actp deploy:check (scan for exposed secrets)
  • Security Built-in: EIP-712 signing, replay protection, safe nonce management
  • Configurable Confirmations: Block confirmation depth configurable per-network (default: 2)

Installation

npm install @agirails/sdk

Or with yarn:

yarn add @agirails/sdk

Quick Start

Testnet Quickstart (Base Sepolia)

Get started with real transactions on Base Sepolia testnet:

# Install CLI globally
npm install -g @agirails/sdk

# One-time setup: generates encrypted keystore at .actp/keystore.json
ACTP_KEY_PASSWORD=your-password actp init -m testnet

# Check your balance
ACTP_KEY_PASSWORD=your-password actp balance

# Make a payment
ACTP_KEY_PASSWORD=your-password actp pay 0xProviderAddress 100 --deadline 24h

# Watch transaction status
actp watch TX_ID

Alternative: Set ACTP_PRIVATE_KEY env var to use a raw private key instead of the keystore.

Basic API - Simple Payments

The simplest way to make a payment - just specify who, how much, and go:

import { ACTPClient } from '@agirails/sdk';

async function main() {
  // Create client in mock mode (no blockchain needed)
  const client = await ACTPClient.create({
    mode: 'mock',
    requesterAddress: '0x1111111111111111111111111111111111111111',
  });

  // Pay a provider
  const result = await client.basic.pay({
    to: '0xabcdefABCDEFabcdefABCDEFabcdefABCDEFabcd',
    amount: '100.00',  // $100 USDC
    deadline: '24h',   // Optional: expires in 24 hours
  });

  console.log('Transaction ID:', result.txId);
  console.log('State:', result.state);
}

main();

Standard API - Full Lifecycle Control

For applications that need explicit control over each transaction step:

import { ACTPClient } from '@agirails/sdk';
import { ethers } from 'ethers';

async function main() {
  // No wallet param needed — auto-detects .actp/keystore.json
  const client = await ACTPClient.create({
    mode: 'testnet',  // or 'mainnet' for production
    requesterAddress: '0x1111111111111111111111111111111111111111',
  });

  // Step 1: Create transaction (no funds locked yet)
  const txId = await client.standard.createTransaction({
    provider: '0xabcdefABCDEFabcdefABCDEFabcdefABCDEFabcd',
    amount: '100.50',
    deadline: '7d',
    disputeWindow: 172800,  // 2 days in seconds
  });
  console.log('Created transaction:', txId);

  // Step 2: Link escrow (locks funds, moves to COMMITTED)
  const escrowId = await client.standard.linkEscrow(txId);
  console.log('Escrow linked:', escrowId);

  // Step 3: Provider starts work (REQUIRED before DELIVERED!)
  await client.standard.transitionState(txId, 'IN_PROGRESS');

  // Step 4: Provider delivers with dispute window proof
  const abiCoder = ethers.AbiCoder.defaultAbiCoder();
  const disputeWindowProof = abiCoder.encode(['uint256'], [172800]); // 2 days
  await client.standard.transitionState(txId, 'DELIVERED', disputeWindowProof);

  // Step 5: Release funds to provider (after dispute window)
  await client.standard.releaseEscrow(txId);
  console.log('Payment complete!');
}

main();

Advanced API - Direct Runtime Access

For custom workflows and maximum flexibility:

import { ACTPClient } from '@agirails/sdk';

async function main() {
  const client = await ACTPClient.create({
    mode: 'mock',
    requesterAddress: '0x1111111111111111111111111111111111111111',
  });

  // Direct runtime access
  const runtime = client.advanced;

  // Create transaction with full control
  const txId = await runtime.createTransaction({
    requester: '0x...',
    provider: '0x...',
    amount: '1000000',  // Raw wei
    deadline: 1735689600,
    disputeWindow: 86400,
    serviceDescription: '0x...'
  });

  // Get transaction details
  const tx = await runtime.getTransaction(txId);
  console.log('State:', tx.state, 'Amount:', tx.amount);
}

main();

Transaction Lifecycle

ACTP transactions follow an 8-state lifecycle:

INITIATED → QUOTED → COMMITTED → IN_PROGRESS → DELIVERED → SETTLED
                ↘                      ↘              ↘
              CANCELLED              CANCELLED      DISPUTED → SETTLED
State Description
INITIATED Transaction created, no escrow linked
QUOTED Provider submitted price quote (optional)
COMMITTED Escrow linked, funds locked
IN_PROGRESS Provider actively working (optional)
DELIVERED Work delivered with proof
SETTLED Payment released (terminal)
DISPUTED Under dispute resolution
CANCELLED Cancelled before completion (terminal)

Configuration

Client Modes

// Mock mode - local testing, no blockchain
const client = await ACTPClient.create({
  mode: 'mock',
  requesterAddress: '0x1111111111111111111111111111111111111111',
  stateDirectory: '.actp'  // Optional: persist state to disk
});

// Testnet mode - Base Sepolia (auto-detects keystore or ACTP_PRIVATE_KEY)
const client = await ACTPClient.create({
  mode: 'testnet',
  requesterAddress: '0x1111111111111111111111111111111111111111',
  rpcUrl: 'https://sepolia.base.org'  // Optional: custom RPC
});

// Mainnet mode - Base (auto-detects keystore or ACTP_PRIVATE_KEY)
const client = await ACTPClient.create({
  mode: 'mainnet',
  requesterAddress: '0x1111111111111111111111111111111111111111',
});

Amount Formats

The SDK accepts amounts in multiple formats:

// All equivalent to $100.50 USDC
await client.basic.pay({ to: '0x...', amount: 100.50 });
await client.basic.pay({ to: '0x...', amount: '100.50' });
await client.basic.pay({ to: '0x...', amount: '$100.50' });
await client.basic.pay({ to: '0x...', amount: '100500000' });  // Wei

Deadline Formats

// Relative formats
deadline: '1h'   // 1 hour from now
deadline: '24h'  // 24 hours from now
deadline: '7d'   // 7 days from now

// Absolute timestamp
deadline: 1735689600  // Unix timestamp

// ISO date string
deadline: '2025-01-01T00:00:00Z'

Error Handling

The SDK provides structured exceptions with error codes:

import {
  ACTPError,
  TransactionNotFoundError,
  InvalidStateTransitionError,
  InsufficientBalanceError,
  ValidationError
} from '@agirails/sdk';

try {
  await client.basic.pay({ to: 'invalid', amount: 100 });
} catch (error) {
  if (error instanceof ValidationError) {
    console.log('Validation failed:', error.message);
    console.log('Error code:', error.code);
    console.log('Details:', error.details);
  } else if (error instanceof InsufficientBalanceError) {
    console.log(`Need ${error.required}, have ${error.available}`);
  } else if (error instanceof ACTPError) {
    console.log(`ACTP error [${error.code}]: ${error.message}`);
  }
}

Exception Hierarchy

ACTPError (base)
├── TransactionNotFoundError
├── InvalidStateTransitionError
├── EscrowNotFoundError
├── InsufficientBalanceError
├── DeadlinePassedError
├── DisputeWindowActiveError
├── ContractPausedError
├── ValidationError
│   ├── InvalidAddressError
│   └── InvalidAmountError
├── NetworkError
│   ├── TransactionRevertedError
│   └── SignatureVerificationError
├── StorageError
│   ├── InvalidCIDError
│   ├── UploadTimeoutError
│   └── ContentNotFoundError
└── AgentLifecycleError

CLI Reference

The SDK includes a full-featured CLI for interacting with ACTP:

Core Commands

# Payment operations
actp pay <provider> <amount> [--deadline TIME] [--service TEXT]
actp balance [ADDRESS]
actp mint --amount AMOUNT  # Mock mode only

# Transaction management
actp list [--state STATE] [--limit N]
actp status <tx_id>
actp cancel <tx_id>

# Time manipulation (mock mode only)
actp time advance <seconds>
actp time set <timestamp>
actp time now

Agent-First Features

# Watch transaction state changes (streams updates)
actp watch <tx_id> [--interval SECONDS] [--format json|text]

# Batch operations from file
actp batch <command_file> [--parallel N] [--continue-on-error]

# Dry-run simulation
actp simulate pay <provider> <amount>
actp simulate fee <amount>

AGIRAILS.md Config Management

# Publish agent config to on-chain registry
actp publish [--dry-run]

# Pull config from on-chain registry
actp pull [--network base-sepolia]

# Compare local config vs on-chain
actp diff [--network base-sepolia]

Deployment Security (AIP-13)

# Generate ACTP_KEYSTORE_BASE64 for CI/CD
actp deploy:env

# Scan repo for exposed secrets
actp deploy:check [--fix] [--quiet]

Configuration

# Initialize keystore (one-time setup)
ACTP_KEY_PASSWORD=your-password actp init -m testnet   # or mainnet
ACTP_KEY_PASSWORD=your-password actp init -m mainnet

# General config
actp config set <key> <value>
actp config get <key>
actp config list
actp config reset

# Available config keys:
#   network: base-sepolia | base-mainnet | mock
#   rpc-url: RPC endpoint URL
#   state-directory: Directory for mock state persistence

Output Formats

# Human-readable (default)
actp list

# JSON output for scripting
actp list --format json

# NDJSON streaming for watch
actp watch TX_ID --format ndjson

Testing

Run the test suite:

# Run all tests
npm test

# Run with verbose output
npm test -- --verbose

# Run specific test file
npm test -- src/__tests__/client.test.ts

# Run tests matching pattern
npm test -- --testNamePattern="pay"

# Run with coverage
npm run test:coverage

API Reference

ACTPClient

Method Description
ACTPClient.create(config) Factory method to create client
client.basic Access basic adapter
client.standard Access standard adapter
client.advanced Access runtime directly
client.getBalance() Get USDC balance
client.reset() Reset mock state

BasicAdapter

Method Description
pay(params) Create and fund transaction
checkStatus(txId) Get transaction status
getBalance() Get formatted balance

StandardAdapter

Method Description
createTransaction(params) Create transaction
linkEscrow(txId) Link escrow and lock funds
transitionState(txId, state, proof?) Transition to new state
releaseEscrow(txId) Release funds
getTransaction(txId) Get transaction details
getAllTransactions() List all transactions

Level 0 & Level 1 APIs

Level 0 - Low-level Primitives

import { ServiceDirectory, request, provide } from '@agirails/sdk';

// Register a provider for a service
const { serviceDirectory } = require('@agirails/sdk');
// serviceDirectory is an in-memory, per-process singleton
// Provider registers automatically when calling provide()

// Find providers for a service
const providers = serviceDirectory.findProviders('text-gen');
// Returns string[] of provider addresses

Level 1 - Agent Framework

import { Agent, AgentConfig } from '@agirails/sdk';

// Create an agent (auto-detects keystore, no wallet param needed)
const agent = new Agent({
  name: 'my-agent',
  network: 'testnet',
});

// Register services via agent.provide()
agent.provide('text-generation', async (job) => {
  return { result: `Processed: ${job.input}` };
});

await agent.start();

SDK Parity

This TypeScript SDK maintains full parity with the Python SDK:

Feature TypeScript SDK Python SDK
DeliveryProof Schema AIP-4 v1.1 (12 fields) AIP-4 v1.1 (12 fields)
Result Hashing keccak256 keccak256
JSON Canonicalization Insertion order Insertion order
EIP-712 Signing Full support Full support
Level0 API Full ACTP flow Full ACTP flow
Level1 Agent API Complete Complete
CLI Commands watch, batch, simulate, publish, pull, diff, deploy:* watch, batch, simulate, publish, pull, diff, deploy:*
Adapter Routing ACTP + x402 + ERC-8004 ACTP + x402 + ERC-8004
ERC-8004 Bridge Identity + Reputation Identity + Reputation
AGIRAILS.md Config publish/pull/diff/drift detection publish/pull/diff
Keystore AIP-13 Full (30-min TTL cache) Full (30-min TTL cache)
Lazy Publish pending-publish lifecycle pending-publish lifecycle
Nonce Tracking SecureNonce, ReceivedNonceTracker SecureNonce, ReceivedNonceTracker
Attestation Tracking UsedAttestationTracker UsedAttestationTracker

Shared Test Vectors: Both SDKs use the same JSON test fixtures to ensure identical behavior.

Networks

Network Chain ID Status
Base Sepolia 84532 ✅ Active (Testnet)
Base Mainnet 8453 ✅ Active

Fee Structure

  • Platform Fee: 1% of transaction amount
  • Minimum Fee: $0.05 USDC

Security

  • EIP-712 Signing: Typed structured data for secure message signing
  • Replay Protection: Nonce management prevents transaction replay
  • Non-custodial Escrow: 2-of-2 release pattern
  • EAS Integration: Ethereum Attestation Service for delivery proofs
  • ERC-8004 Reputation: On-chain settlement/dispute feedback after ACTP transactions
  • Input Validation: All user inputs validated before processing

Transaction Confirmations

All state-changing operations in ACTPKernel wait for block confirmations before events are emitted. The default is 2 confirmations (~4-6s on Base L2's ~2s blocks), configurable via BlockchainRuntimeConfig.confirmations. The SDK's EventMonitor receives already-confirmed events; no additional confirmation handling is needed at the application layer.

Decentralized Identifiers (DIDs)

AGIRAILS uses did:ethr DIDs based on the ERC-1056 standard for identity management.

DID Format

Every Ethereum address automatically IS a DID - no registration required:

did:ethr:84532:0x742d35cc6634c0532925a3b844bc9e7595f0beb
       ↑      ↑
   chainId  address

Basic Usage

import { DIDResolver } from '@agirails/sdk';

// Build DID from address (no registration needed!)
const did = DIDResolver.buildDID('0x742d35cc6634c0532925a3b844bc9e7595f0beb', 84532);
// → 'did:ethr:84532:0x742d35cc6634c0532925a3b844bc9e7595f0beb'

// Parse DID components
const parsed = DIDResolver.parseDID(did);
console.log(parsed.method);   // 'ethr'
console.log(parsed.chainId);  // 84532
console.log(parsed.address);  // '0x742d35cc6634c0532925a3b844bc9e7595f0beb'

// Validate DID format
const isValid = DIDResolver.isValidDID(did);  // true

Resolve DID to DID Document

import { DIDResolver } from '@agirails/sdk';

// Create resolver for Base Sepolia
const resolver = await DIDResolver.create({ network: 'base-sepolia' });

// Resolve DID to W3C DID Document
const result = await resolver.resolve('did:ethr:84532:0x742d35cc...');

if (result.didDocument) {
  console.log('Controller:', result.didDocument.controller);
  console.log('Verification Methods:', result.didDocument.verificationMethod);
  console.log('Service Endpoints:', result.didDocument.service);
}

Verify Signatures

import { DIDResolver } from '@agirails/sdk';

const resolver = await DIDResolver.create({ network: 'base-sepolia' });

// Verify a signature was made by a DID's controller (or authorized delegate)
const result = await resolver.verifySignature(
  'did:ethr:84532:0x742d35cc...',  // DID
  'Hello AGIRAILS',                 // Original message
  '0x1234...',                      // Signature
  { chainId: 84532 }                // Verification options
);

if (result.valid) {
  console.log('Signature valid!');
  console.log('Signer:', result.signer);
  console.log('Is delegate:', result.isDelegate);
}

Advanced: Manage Identity (Optional)

For advanced use cases, use DIDManager to manage delegates and attributes:

import { DIDManager } from '@agirails/sdk';

// Create manager with signer
const manager = new DIDManager(signer, { network: 'base-sepolia' });

// Add a signing delegate (valid for 24 hours)
await manager.addDelegate(
  'did:ethr:84532:0x742d35cc...',  // Your DID
  '0xDelegateAddress...',          // Delegate address
  'sigAuth',                        // Delegate type
  86400                             // Validity in seconds
);

// Rotate key ownership
await manager.changeOwner(
  'did:ethr:84532:0x742d35cc...',
  '0xNewOwnerAddress...'
);

// Add service endpoint attribute
await manager.setAttribute(
  'did:ethr:84532:0x742d35cc...',
  'did/svc/AgentService',
  'https://my-agent.example.com/api',
  86400
);

DID in ACTP Transactions

DIDs are used internally for:

  • Provider/Consumer Identity: Transaction parties identified by DIDs
  • Message Signing: EIP-712 messages reference DIDs
  • Delivery Proofs: Attestations link to provider DIDs
  • Reputation: Future reputation system will be DID-based

Environment Variables

# Wallet resolution (checked in order):
ACTP_PRIVATE_KEY=0x...       # Raw private key (fail-closed on mainnet — see AIP-13)
ACTP_KEYSTORE_BASE64=...     # Base64 keystore for CI/CD (use actp deploy:env to generate)
ACTP_KEY_PASSWORD=...        # Decrypts keystore (ACTP_KEYSTORE_BASE64 or .actp/keystore.json)

# Optional
BASE_SEPOLIA_RPC=...         # Custom RPC for Base Sepolia
BASE_MAINNET_RPC=...         # Custom RPC for Base Mainnet
CDP_API_KEY=...              # Coinbase Developer Platform API key
PIMLICO_API_KEY=...          # Pimlico bundler/paymaster API key
IPFS_GATEWAY=...             # Custom IPFS gateway URL

Requirements

  • Node.js 18+ (required for global fetch and AbortController)
  • TypeScript 5.0+ (for development)
  • Dependencies: ethers

Module Format

The SDK ships as CommonJS only. It works with require() and with bundlers (webpack, esbuild, Rollup) that support CJS. If you are using ESM (import syntax), Node.js will auto-interop with CJS modules — no additional configuration is needed.

License

Apache 2.0 License - see LICENSE for details.