Skip to content

Latest commit

 

History

History
698 lines (537 loc) · 17.6 KB

File metadata and controls

698 lines (537 loc) · 17.6 KB

Kitties API Reference

The Kitties API provides a unified interface for interacting with the CryptoKitties smart contract from both browser and Node.js environments.

Table of Contents

Getting Started

API Documentation

Configuration & Setup

Development & Troubleshooting

Additional Resources


Installation

yarn add @repo/kitties-api

Quick Start

Browser Environment

import { KittiesAPI, configureBrowserProviders } from '@repo/kitties-api';

// Configure providers
const providers = await configureBrowserProviders(wallet, config, zkConfigProvider);

// Deploy new contract
const kittiesApi = await KittiesAPI.deploy(providers, {});

// Or connect to existing contract
const kittiesApi = await KittiesAPI.connect(providers, contractAddress);

Node.js Environment

import { KittiesAPI, configureProviders } from '@repo/kitties-api/node-api';

// Configure providers
const providers = await configureProviders(wallet, config, zkConfigProvider);

// Deploy or connect
const kittiesApi = await KittiesAPI.deploy(providers, {});

Core API

Contract Management

KittiesAPI.deploy(providers, options)

Deploy a new kitties contract.

Parameters:

  • providers: KittiesProviders - Configured Midnight providers

Returns: Promise<KittiesAPI>

const kittiesApi = await KittiesAPI.deploy(providers, {});

KittiesAPI.connect(providers, contractAddress)

Connect to an existing contract.

Parameters:

  • providers: KittiesProviders - Configured Midnight providers
  • contractAddress: ContractAddress | string - Contract address

Returns: Promise<KittiesAPI>

const kittiesApi = await KittiesAPI.connect(providers, "123...");

Kitty Operations

createKitty(): Promise<void>

Create a new kitty with random DNA.

await kittiesApi.createKitty();

getKitty(kittyId): Promise<KittyData>

Get kitty details by ID.

Parameters:

  • kittyId: bigint - Kitty ID

Returns: Promise<KittyData>

const kitty = await kittiesApi.getKitty(1n);
console.log(kitty.dna, kitty.gender, kitty.owner);

transferKitty(params): Promise<void>

Transfer kitty to another address.

Parameters:

  • params.to: { bytes: Uint8Array } - Recipient address
  • params.kittyId: bigint - Kitty ID
await kittiesApi.transferKitty({
  to: { bytes: recipientBytes },
  kittyId: 1n
});

getAllKittiesCount(): Promise<bigint>

Get total number of kitties created.

const count = await kittiesApi.getAllKittiesCount();

getUserKitties(owner): Promise<KittyData[]>

Get all kitties owned by an address.

Parameters:

  • owner: { bytes: Uint8Array } - Owner address
const kitties = await kittiesApi.getUserKitties(ownerAddress);

getMyKitties(from): Promise<KittyData[]>

Convenience method to get kitties for current wallet.

Parameters:

  • from: { bytes: Uint8Array } - Wallet address
const myKitties = await kittiesApi.getMyKitties(walletAddress);

Marketplace Operations

setPrice(params): Promise<void>

Set sale price for a kitty.

Parameters:

  • params.kittyId: bigint - Kitty ID
  • params.price: bigint - Sale price
await kittiesApi.setPrice({
  kittyId: 1n,
  price: 100n
});

createBuyOffer(params): Promise<void>

Make a purchase offer on a kitty.

Parameters:

  • params.kittyId: bigint - Kitty ID
  • params.bidPrice: bigint - Offered price
await kittiesApi.createBuyOffer({
  kittyId: 1n,
  bidPrice: 120n
});

approveOffer(params): Promise<void>

Accept a purchase offer (transfers ownership).

Parameters:

  • params.kittyId: bigint - Kitty ID
  • params.buyer: { bytes: Uint8Array } - Buyer address
await kittiesApi.approveOffer({
  kittyId: 1n,
  buyer: buyerAddress
});

getKittiesForSale(): Promise<KittyListingData[]>

Get all kitties currently for sale.

const forSale = await kittiesApi.getKittiesForSale();

getOffer(params): Promise<Offer>

Get offer details for a specific kitty and buyer.

Parameters:

  • params.kittyId: bigint - Kitty ID
  • params.buyer: { bytes: Uint8Array } - Buyer address
const offer = await kittiesApi.getOffer({
  kittyId: 1n,
  buyer: buyerAddress
});

Breeding System

breedKitty(params): Promise<void>

Breed two kitties to create offspring.

Parameters:

  • params.kittyId1: bigint - First parent ID
  • params.kittyId2: bigint - Second parent ID
await kittiesApi.breedKitty({
  kittyId1: 1n,
  kittyId2: 2n
});

NFT Standard Operations

The API exposes standard ERC-721 operations through the external NFT module:

balanceOf(owner): Promise<bigint>

Get number of tokens owned by an address.

const balance = await kittiesApi.balanceOf(ownerAddress);

ownerOf(tokenId): Promise<{ bytes: Uint8Array }>

Get owner of a specific token.

const owner = await kittiesApi.ownerOf(1n);

approve(params): Promise<void>

Approve another address to transfer a token.

Parameters:

  • params.to: { bytes: Uint8Array } - Approved address
  • params.tokenId: bigint - Token ID
await kittiesApi.approve({
  to: approvedAddress,
  tokenId: 1n
});

getApproved(tokenId): Promise<{ bytes: Uint8Array }>

Get approved address for a token.

const approved = await kittiesApi.getApproved(1n);

setApprovalForAll(params): Promise<void>

Set approval for all tokens.

Parameters:

  • params.operator: { bytes: Uint8Array } - Operator address
  • params.approved: boolean - Approval status
await kittiesApi.setApprovalForAll({
  operator: operatorAddress,
  approved: true
});

isApprovedForAll(params): Promise<boolean>

Check if operator is approved for all tokens.

Parameters:

  • params.owner: { bytes: Uint8Array } - Owner address
  • params.operator: { bytes: Uint8Array } - Operator address
const isApproved = await kittiesApi.isApprovedForAll({
  owner: ownerAddress,
  operator: operatorAddress
});

Static Utility Methods

KittiesAPI.createKitty(kittiesApi): Promise<TransactionResponse>

Static wrapper for creating kitties with transaction info.

KittiesAPI.getKittiesCount(providers, contractAddress): Promise<bigint | null>

Get kitty count without full API instance.

KittiesAPI.getContractAddress(kittiesApi): string

Get contract address from API instance.

Data Types

KittyData

interface KittyData {
  id: bigint;
  dna: bigint;
  gender: Gender;
  owner: { bytes: Uint8Array };
  price: bigint;
  forSale: boolean;
  generation: bigint;
}

KittyListingData

interface KittyListingData {
  id: bigint;
  kitty: KittyData;
}

Offer

interface Offer {
  kittyId: bigint;
  buyer: { bytes: Uint8Array };
  price: bigint;
}

TransactionResponse

interface TransactionResponse {
  txId?: string;
  txHash?: string;
  blockHeight?: bigint | number;
}

Provider Configuration

Browser Providers

import { configureBrowserProviders } from '@repo/kitties-api';

const providers = await configureBrowserProviders(
  wallet,
  config,
  zkConfigProvider
);

Node.js Providers

import { configureProviders } from '@repo/kitties-api/node-api';

const providers = await configureProviders(
  wallet,
  config,
  zkConfigProvider
);

Error Handling

The API throws descriptive errors for common issues:

try {
  await kittiesApi.createBuyOffer({ kittyId: 1n, bidPrice: 50n });
} catch (error) {
  if (error.message.includes('Kitty is not for sale')) {
    console.log('Cannot make offer on kitty not for sale');
  }
}

State Observation

The API provides an observable for real-time state updates:

kittiesApi.state$.subscribe(state => {
  console.log('Kitties count:', state.allKittiesCount);
  console.log('Kitties data:', state.kitties);
});

Testing

Integration Tests

cd packages/api/kitties
yarn test

Test Against Testnet

yarn test-against-testnet

Environment Differences

Browser vs Node.js

  • Browser: Uses wallet connector for transactions
  • Node.js: Direct wallet integration
  • Both: Same API surface, different provider setup

Configuration Files

Key Concepts Documented

🌐 Cross-Platform Compatibility

Problem: The kitties-api needs to work in both Node.js and browser environments with different capabilities.

Solutions Documented:

  • Environment abstraction layer (env.ts, env-node.ts, env-browser.ts)
  • Universal path resolution (path-resolver.ts)
  • Vite alias configuration for browser builds

🔧 Build System Integration

Configuration Points:

  • Vite Aliases: Route browser imports to browser-compatible implementations
  • TypeScript: Maintain type safety across environments
  • Module Systems: Handle both CommonJS and ESM contexts

Package Configuration & Dependencies

Package.json Export Structure

The Kitties API uses a sophisticated export structure to handle different environments and prevent dependency leaks:

{
  "exports": {
    ".": {
      "browser": {
        "types": "./dist/browser-index.d.ts",
        "import": "./dist/browser-index.js"
      },
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js"
    },
    "./node-api": {
      "types": "./dist/node/api.d.ts",
      "import": "./dist/node/api.js"
    },
    "./browser-api": {
      "types": "./dist/browser/api.d.ts",
      "import": "./dist/browser/api.js"
    },
    "./src/browser/env-browser.ts": "./src/browser/env-browser.ts"
  }
}

Key Benefits:

  • Environment Isolation: Browser and Node.js environments get different entry points
  • Dependency Control: Prevents Node.js-specific dependencies from leaking into browser builds
  • Type Safety: Separate type definitions for each environment
  • Direct Access: Allows importing specific modules when needed

Vite Configuration for Browser Builds

The project's web application demonstrates how to configure Vite for proper browser builds. See apps/web/vite.config.ts for the complete configuration:

Key Configuration Highlights:

// From apps/web/vite.config.ts
export default defineConfig({
  plugins: [
    react(),
    viteCommonjs({
      include: ['@repo/kitties-api/**'],  // Handle CommonJS in kitties-api
    }),
    wasm(),
  ],
  resolve: {
    alias: {
      ...stdLibBrowser,  // Node.js standard library polyfills
      
      // Environment Abstraction Layer Aliases
      // These ensure browser builds use browser-compatible implementations
      '@repo/kitties-api/src/env': '@repo/kitties-api/dist/browser/env-browser',
      '@repo/kitties-api/dist/env': '@repo/kitties-api/dist/browser/env-browser',
      '@repo/kitties-api/dist/env-node': '@repo/kitties-api/dist/browser/env-browser',
      './env-node.js': '@repo/kitties-api/dist/browser/env-browser',
      './env-node': '@repo/kitties-api/dist/browser/env-browser',
      '../node/env-node.js': '@repo/kitties-api/dist/browser/env-browser',
    },
  },
  optimizeDeps: {
    include: ['@repo/kitties-api'],
    exclude: ['@midnight-ntwrk/kitties-contract', 'node-fetch', 'fetch-blob'],
  },
  build: {
    rollupOptions: {
      external: [
        '@midnight-ntwrk/midnight-js-node-zk-config-provider',
        'fetch-blob',
        'node-domexception',
        'formdata-polyfill',
      ],
    },
  },
});

Critical Configuration Elements:

  1. Environment Abstraction Aliases: Multiple alias patterns ensure that any import path referring to Node.js environment code gets redirected to browser-compatible implementations.

  2. CommonJS Handling: The viteCommonjs plugin specifically includes the kitties-api package to handle mixed module formats.

  3. Standard Library Polyfills: Uses node-stdlib-browser to provide browser-compatible versions of Node.js built-ins.

  4. Dependency Optimization: Includes the API package for pre-bundling while excluding Node.js-specific dependencies.

  5. External Dependencies: Explicitly marks Node.js-only packages as external to prevent them from being bundled.

Environment Abstraction Layer

The API uses an environment abstraction layer to handle differences between browser and Node.js:

Structure:

src/
├── common/           # Shared code
├── browser/          # Browser-specific implementations
│   ├── env-browser.ts    # Browser environment stubs
│   └── api.ts           # Browser API layer
├── node/             # Node.js-specific implementations
│   ├── env-node.ts      # Node.js environment functions
│   └── api.ts           # Node.js API layer
└── env.ts            # Runtime environment detection

Key Features:

  • Runtime Detection: Automatically detects browser vs Node.js environment
  • Graceful Fallbacks: Browser stubs for Node.js-only functions
  • Type Safety: Consistent interfaces across environments
  • Dependency Isolation: Prevents platform-specific dependencies from cross-contaminating

Preventing Dependency Leaks

1. Environment-Specific Exports

// Browser builds import from browser-specific entry point
import { KittiesAPI } from '@repo/kitties-api/browser-api';

// Node.js builds import from node-specific entry point  
import { KittiesAPI } from '@repo/kitties-api/node-api';

2. Conditional Imports

// env.ts - Runtime environment detection
const isNode = typeof process !== 'undefined' && process.versions?.node;

if (isNode) {
  // Import Node.js-specific modules only in Node.js environment
  const { readFileSync } = await import('fs');
} else {
  // Use browser-compatible alternatives
  throw new Error('File operations not supported in browser');
}

3. Build-Time Exclusions

// package.json - Exclude Node.js dependencies from browser builds
{
  "browser": {
    "fs": false,
    "path": false,
    "crypto": false
  }
}

Resolution Path Best Practices

For Applications Using the API:

  1. Use Environment-Specific Imports

    // ✅ Good - Browser applications
    import { KittiesAPI } from '@repo/kitties-api/browser-api';
    
    // ✅ Good - Node.js applications
    import { KittiesAPI } from '@repo/kitties-api/node-api';
    
    // ❌ Avoid - May pull in wrong dependencies
    import { KittiesAPI } from '@repo/kitties-api';
  2. Configure Bundle Resolvers

    // webpack.config.js
    module.exports = {
      resolve: {
        alias: {
          '@repo/kitties-api$': '@repo/kitties-api/browser-api'
        },
        fallback: {
          "fs": false,
          "path": false
        }
      }
    };
  3. Handle Dynamic Imports

    // Use dynamic imports for optional Node.js functionality
    let nodeApi;
    try {
      nodeApi = await import('@repo/kitties-api/node-api');
    } catch (error) {
      // Fallback for browser environment
      console.log('Node.js API not available in browser');
    }

Debugging Configuration Issues

Common Issues and Solutions:

  1. "Module not found" errors in browser

    • Check Vite alias configuration
    • Ensure using browser-specific import paths
    • Verify nodePolyfills plugin configuration
  2. Node.js dependencies in browser bundle

    • Review export structure in package.json
    • Check for incorrect import paths
    • Add explicit exclusions in bundler config
  3. Type resolution errors

    • Ensure TypeScript can resolve environment-specific types
    • Check tsconfig.json path mappings
    • Verify dist/ folder structure after build

Debug Commands:

# Check resolved imports
yarn why @repo/kitties-api

# Analyze bundle composition
npx vite-bundle-analyzer

# Verify type resolution
tsc --noEmit --listFiles

Architecture Documentation

For detailed implementation information, see:

This documentation ensures the kitties-api remains maintainable and understandable as the project evolves.