Skip to content

dapinet/dapinet-sdk

Repository files navigation

@dapinet/sdk

TypeScript SDK for Dapinet UsagePayments V1.2 smart contract.

Installation

npm install @dapinet/sdk ethers

Features

  • ✅ Full TypeScript types for V1.2 contract
  • ✅ Request data encoding helpers (string, JSON, ABI, etc.)
  • ✅ EIP-712 signature helpers for settleWithSig
  • ✅ Gas estimation utilities
  • ✅ Zero dependencies (peer dependency on ethers v6)

Quick Start

1. Encode Request Data

import { encodeRequestData, apiIdToBytes32 } from '@dapinet/sdk';
import { ethers } from 'ethers';

// Simple string (e.g., city name for weather API)
const requestData = encodeRequestData('Paris');

// JSON object (e.g., complex API parameters)
const requestData = encodeRequestData({
  city: 'Paris',
  lang: 'fr',
  units: 'metric'
});

// ABI-encoded (e.g., typed parameters)
const requestData = encodeRequestData([
  ['string', 'string'], // types
  ['BTC', 'USD']        // values
], { format: 'abi' });

2. Send API Request

import { Contract, Wallet } from 'ethers';
import { encodeRequestData, apiIdToBytes32 } from '@dapinet/sdk';

const provider = new ethers.JsonRpcProvider('YOUR_RPC_URL');
const wallet = new Wallet('YOUR_PRIVATE_KEY', provider);
const contract = new Contract(CONTRACT_ADDRESS, ABI, wallet);

// Encode API ID
const apiId = apiIdToBytes32('weather-api');

// Encode request data
const requestData = encodeRequestData('Paris');

// Send request with payment
const tx = await contract.requestApiCall(apiId, requestData, {
  value: ethers.parseEther('0.0001') // API price
});

await tx.wait();
console.log('Request sent:', tx.hash);

3. Settle with Signature (Relayer Mode)

import { signSettle, combineSignature, createDeadline } from '@dapinet/sdk';
import { Contract, Wallet } from 'ethers';

// Operator signs the settlement
const operatorWallet = new Wallet('OPERATOR_PRIVATE_KEY');
const deadline = createDeadline(300); // 5 minutes from now

const signature = await signSettle(operatorWallet, {
  contractAddress: CONTRACT_ADDRESS,
  chainId: 421614, // Arbitrum Sepolia
  requestId: 1n,
  responseData: JSON.stringify({ temp: 10.2, city: 'Paris' }),
  nonce: 0n, // Get from contract: contract.operatorNonces(operatorAddress)
  deadline,
});

// Relayer (anyone) submits the settlement
const relayerWallet = new Wallet('RELAYER_PRIVATE_KEY', provider);
const contract = new Contract(CONTRACT_ADDRESS, ABI, relayerWallet);

const signatureBytes = combineSignature(signature);
const responseDataBytes = ethers.toUtf8Bytes(JSON.stringify({ temp: 10.2, city: 'Paris' }));

const tx = await contract.settleWithSig(
  signature.requestId,
  responseDataBytes,
  signature.deadline,
  signatureBytes
);

await tx.wait();
console.log('Settled with signature:', tx.hash);

API Reference

Encoding Functions

encodeRequestData(data, options?)

Encode request data for API calls.

Parameters:

  • data: Data to encode (string, object, array, or hex)
  • options: Optional encoding options
    • format: Encoding format ('string' | 'json' | 'abi' | 'abi-packed' | 'hex' | 'urlencoded')

Returns: Encoded bytes as hex string

Examples:

// Simple string
encodeRequestData('Paris') // -> 0x5061726973

// JSON object
encodeRequestData({ city: 'Paris', lang: 'fr' })

// ABI-encoded parameters
encodeRequestData([['string', 'uint256'], ['BTC', 1000]], { format: 'abi' })

// URL-encoded query string
encodeRequestData({ q: 'Paris', lang: 'fr' }, { format: 'urlencoded' })
// -> "q=Paris&lang=fr"

decodeRequestData(bytes, format?)

Decode request data from bytes.

Parameters:

  • bytes: Encoded bytes (hex string or Uint8Array)
  • format: Expected format (default: 'string')

Returns: Decoded data

EIP-712 Signature Functions

signSettle(wallet, params)

Create an EIP-712 signature for settleWithSig.

Parameters:

  • wallet: Ethers wallet or signer (operator)
  • params: Signature parameters
    • contractAddress: UsagePayments contract address
    • chainId: Chain ID (e.g., 421614 for Arbitrum Sepolia)
    • requestId: Request ID (bigint)
    • responseData: Response data (string, will be hashed)
    • nonce: Current nonce for operator (bigint)
    • deadline: Signature expiration timestamp (bigint)

Returns: Promise with { requestId, responseHash, nonce, deadline, v, r, s }

combineSignature(sig)

Combine v, r, s into a signature bytes.

Parameters:

  • sig: Signature components { v, r, s }

Returns: Signature as bytes (0x-prefixed hex string)

createDeadline(durationSeconds?)

Create a deadline timestamp.

Parameters:

  • durationSeconds: Duration in seconds (default: 300 = 5 minutes)

Returns: Deadline timestamp (bigint, seconds since epoch)

Utility Functions

apiIdToBytes32(apiId)

Convert API ID string to bytes32 hash.

Parameters:

  • apiId: API ID string (e.g., 'weather-api')

Returns: bytes32 hash (0x-prefixed hex string)

estimateRequestGas(requestDataSize)

Estimate gas for requestApiCall.

Parameters:

  • requestDataSize: Size of request data in bytes

Returns: Estimated gas (bigint)

formatEth(wei) / parseEth(eth)

Format wei to ETH string / Parse ETH string to wei.

Encoding Formats

1. Simple String

Best for: Simple parameters (city name, ticker symbol, etc.)

encodeRequestData('Paris')
encodeRequestData('BTC')

2. JSON

Best for: Complex structured data

encodeRequestData({ city: 'Paris', lang: 'fr', units: 'metric' })

3. ABI-Encoded

Best for: Type-safe encoding with Solidity types

// Multiple parameters with types
encodeRequestData([
  ['string', 'string', 'uint256'],  // types
  ['BTC', 'USD', 1000]              // values
], { format: 'abi' })

4. ABI-Packed

Best for: Gas-efficient encoding (no padding)

encodeRequestData([
  ['string', 'uint256'],
  ['BTC', 1000]
], { format: 'abi-packed' })

5. URL-Encoded

Best for: REST API query parameters

encodeRequestData({ q: 'Paris', lang: 'fr' }, { format: 'urlencoded' })
// Result: "q=Paris&lang=fr"

6. Hex

Best for: Pre-encoded binary data

encodeRequestData('0x1234abcd', { format: 'hex' })

Types

All TypeScript types are exported:

import {
  RequestedEvent,
  SettledEvent,
  ResponseEvent,
  SettledWithSigEvent,
  RequestStatus,
  Request,
  ApiInfo,
  RequestDataFormat,
  EncodeOptions,
  SettleSignature,
  DapinetConfig
} from '@dapinet/sdk';

Examples

Example 1: Weather API Request

import { ethers } from 'ethers';
import { encodeRequestData, apiIdToBytes32 } from '@dapinet/sdk';

const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);
const contract = new ethers.Contract(CONTRACT_ADDRESS, ABI, wallet);

async function requestWeather(city: string) {
  const apiId = apiIdToBytes32('weather-api');
  const requestData = encodeRequestData(city);

  const tx = await contract.requestApiCall(apiId, requestData, {
    value: ethers.parseEther('0.0001')
  });

  const receipt = await tx.wait();
  const event = receipt.logs.find(log => log.topics[0] === contract.interface.getEvent('Requested').topicHash);
  const requestId = event.topics[1];

  console.log(`Weather requested for ${city}, requestId: ${requestId}`);
  return requestId;
}

await requestWeather('Paris');

Example 2: Crypto Price API with Multiple Parameters

import { encodeRequestData, apiIdToBytes32 } from '@dapinet/sdk';

const apiId = apiIdToBytes32('crypto-price');

// JSON encoding for complex parameters
const requestData = encodeRequestData({
  symbols: ['BTC', 'ETH', 'SOL'],
  currency: 'USD',
  includeChange: true
});

const tx = await contract.requestApiCall(apiId, requestData, {
  value: ethers.parseEther('0.0005')
});

Example 3: Relayer Service for Gasless Settlements

import { signSettle, combineSignature, createDeadline } from '@dapinet/sdk';

// Operator service (off-chain)
class OperatorService {
  async createSettlement(requestId: bigint, responseData: string) {
    const nonce = await contract.operatorNonces(this.operatorAddress);
    const deadline = createDeadline(300); // 5 min

    const signature = await signSettle(this.operatorWallet, {
      contractAddress: CONTRACT_ADDRESS,
      chainId: 421614,
      requestId,
      responseData,
      nonce,
      deadline
    });

    // Send signature to relayer service
    await this.relayerApi.post('/settle', {
      requestId: signature.requestId.toString(),
      responseData,
      deadline: signature.deadline.toString(),
      signature: combineSignature(signature)
    });
  }
}

// Relayer service (pays gas)
class RelayerService {
  async settleBatch(settlements: Settlement[]) {
    for (const s of settlements) {
      const responseDataBytes = ethers.toUtf8Bytes(s.responseData);
      
      const tx = await this.contract.settleWithSig(
        s.requestId,
        responseDataBytes,
        s.deadline,
        s.signature
      );

      await tx.wait();
      console.log(`Settled request ${s.requestId}, tx: ${tx.hash}`);
    }
  }
}

Contract ABI

The full UsagePayments V1.2 ABI is available in the main contract repository:

/dapinet/contracts/out/UsagePaymentsV1_2.sol/UsagePaymentsV1_2.json

Support

License

Business Source License 1.1

Licensed under BSL 1.1 until 2029-01-01, then converts to MIT License.

  • Free for: Personal use, education, internal commercial use
  • ⚠️ Restricted: Cannot operate competing API marketplaces or networks
  • 🔓 Fully open: Converts to MIT License on 2029-01-01

See LICENSE for full terms.

About

Lightweight JavaScript/TypeScript library that allows developers to easily register APIs, send on-chain requests, and retrieve responses from decentralized operators — enabling any Web2 API to become a pay-per-call Web3 service in just a few lines of code.

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors