Skip to content

Latest commit

 

History

History
226 lines (174 loc) · 5.3 KB

File metadata and controls

226 lines (174 loc) · 5.3 KB

Shared Package

Common utilities and configuration shared across all apps in the AnySpend x402 monorepo.

Overview

This package provides reusable code to ensure consistency across the client, server, and agent applications. It prevents code duplication and serves as a single source of truth for shared logic.

Contents

Configuration

config/networks.ts

Network definitions for EVM-compatible chains supported by the demo.

import { EVM_NETWORKS } from '@shared/config/networks';

// Access network info
const baseNetwork = EVM_NETWORKS.base;
console.log(baseNetwork.name); // "Base"
console.log(baseNetwork.chainId); // 8453
console.log(baseNetwork.nativeCurrency.symbol); // "ETH"

Supported Networks:

  • Base (Mainnet & Sepolia)
  • Polygon (Mainnet & Amoy)
  • Arbitrum (Mainnet & Sepolia)

Network Object Structure:

{
  id: number;           // Chain ID
  name: string;         // Display name
  chainId: number;      // Chain ID (same as id)
  nativeCurrency: {
    name: string;
    symbol: string;
    decimals: number;
  };
  rpcUrls: {
    default: { http: string[] };
    public: { http: string[] };
  };
  blockExplorers: {
    default: {
      name: string;
      url: string;
    };
  };
  testnet?: boolean;
}

Utilities

utils/permitDetection.ts

Detection logic for EIP-2612 permit support on ERC20 tokens.

import { checkPermitSupport } from '@shared/utils/permitDetection';

// Check if a token supports gasless permits
const supportsPermit = await checkPermitSupport(
  tokenAddress,     // Token contract address
  rpcUrl,           // RPC endpoint
  chainId           // Chain ID
);

if (supportsPermit) {
  // Use permit-based approval (no gas required)
} else {
  // Fall back to standard approve()
}

How it works:

  1. Checks if contract implements permit() function (EIP-2612)
  2. Validates the function signature
  3. Returns boolean indicating support
  4. Includes commented EIP-3009 logic for future extensibility

Use Cases:

  • Client PaymentModal: Determine if permit UI should be shown
  • Agent payment flow: Select optimal approval method
  • Token compatibility checking

Usage in Apps

In TypeScript Code

All apps have path aliases configured:

// Instead of relative paths
import { EVM_NETWORKS } from '../../../shared/config/networks';
import { checkPermitSupport } from '../../../shared/utils/permitDetection';

// Use clean aliases
import { EVM_NETWORKS } from '@shared/config/networks';
import { checkPermitSupport } from '@shared/utils/permitDetection';

Path Alias Configuration

Each app's tsconfig.json includes:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@shared/*": ["../shared/*"]
    }
  }
}

For Vite (client app), also add to vite.config.ts:

{
  resolve: {
    alias: {
      '@shared': path.resolve(__dirname, '../shared')
    }
  }
}

Development

Adding New Shared Code

  1. Configuration: Add to config/ directory

    • Network configs
    • Token lists
    • Chain-specific constants
  2. Utilities: Add to utils/ directory

    • Pure functions (no side effects)
    • Reusable logic used across multiple apps
    • Type guards and validators
  3. Types: Consider adding a types/ directory for shared TypeScript types

Best Practices

Do:

  • Keep functions pure and side-effect free
  • Add comprehensive JSDoc comments
  • Export everything needed by consuming apps
  • Write self-contained, testable code
  • Use TypeScript for type safety

Don't:

  • Import app-specific dependencies
  • Add UI components (those belong in client app)
  • Include environment-specific logic
  • Create circular dependencies between apps

Type Safety

Since this is shared code, ensure strong typing:

// Good: Explicit types
export function checkPermitSupport(
  tokenAddress: `0x${string}`,
  rpcUrl: string,
  chainId: number
): Promise<boolean>

// Bad: Any types
export function checkPermitSupport(
  tokenAddress: any,
  rpcUrl: any,
  chainId: any
): Promise<any>

File Structure

apps/shared/
├── config/
│   └── networks.ts          # EVM network definitions
├── utils/
│   └── permitDetection.ts   # EIP-2612 permit detection
├── package.json             # Package configuration
└── README.md               # This file

Future Additions

Potential shared code to add:

  • Token Lists: Common token addresses per chain
  • Formatting Utilities: Amount formatting, address shortening
  • Validation Functions: Input validation, address checks
  • Constants: Common values used across apps
  • Type Definitions: Shared TypeScript interfaces
  • ABI Definitions: Common contract ABIs

Build Configuration

The shared package uses TypeScript with no build step. Files are imported directly using path aliases, and TypeScript compiles them as part of each consuming app's build process.

Note: Compiled .js, .d.ts, and .map files are gitignored to avoid committing build artifacts.

Testing

When adding utilities, consider adding unit tests:

# Future: Add testing framework
pnpm test:shared

Related