Skip to content

Latest commit

 

History

History
300 lines (230 loc) · 7.34 KB

File metadata and controls

300 lines (230 loc) · 7.34 KB

Grainlify Contracts SDK

TypeScript SDK for interacting with Grainlify Soroban smart contracts on the Stellar network.

Documentation

Detailed documentation for the SDK is available in the docs/ directory:

Installation

npm install @grainlify/contracts-sdk

Features

  • Type-safe contract interactions
  • Comprehensive error handling with typed errors
  • Network error detection and reporting
  • Input validation
  • Support for ProgramEscrow and BountyEscrow lifecycle, claim, refund, batch, and query functions

Usage

Bounty Escrow

See sdk/examples/bounty-lock-release.ts for a full walkthrough of the bounty lifecycle.

import { BountyEscrowClient } from '@grainlify/contracts-sdk';
import { Keypair } from '@stellar/stellar-sdk';

const client = new BountyEscrowClient({
  contractId: 'YOUR_CONTRACT_ID',
  rpcUrl: 'https://soroban-testnet.stellar.org',
  networkPassphrase: 'Test SDF Network ; September 2015'
});

const sourceKeypair = Keypair.fromSecret('YOUR_SECRET_KEY');

await client.lockFunds(
  'GDEPOSITOR...',
  1n, // Bounty ID
  10000000n, // Amount
  Math.floor(Date.now() / 1000) + 86400, // Deadline
  sourceKeypair
);

The bounty client wraps the core contract lifecycle:

  • lockFunds, releaseFunds, partialRelease, refund
  • approveRefund, setClaimWindow, authorizeClaim, claim, cancelPendingClaim
  • batchLockFunds, batchReleaseFunds
  • getEscrowInfo, getPendingClaim, getRefundHistory, getRefundEligibility
  • queryEscrowsByStatus, queryEscrowsByAmount, queryEscrowsByDeadline, queryEscrowsByDepositor, queryEscrows, queryExpiringBounties
  • getAggregateStats, getEscrowCount, getEscrowIdsByStatus, getFeeConfig, getPauseFlags

State-changing methods require a signing Keypair; read/query methods do not.

await client.setClaimWindow(3600, sourceKeypair);
await client.authorizeClaim(1n, 'GRECIPIENT...', sourceKeypair);
const claim = await client.getPendingClaim(1n);
const recipientKeypair = Keypair.fromSecret('RECIPIENT_SECRET_KEY');
await client.claim(claim.bounty_id, recipientKeypair);

await client.approveRefund(2n, 5000000n, 'GDEPOSITOR...', 'Partial', sourceKeypair);
const eligibility = await client.getRefundEligibility(2n);

Program Escrow

Initialize the Client

import { ProgramEscrowClient } from '@grainlify/contracts-sdk';

const client = new ProgramEscrowClient({
  contractId: 'YOUR_CONTRACT_ID',
  rpcUrl: 'https://soroban-testnet.stellar.org',
  networkPassphrase: 'Test SDF Network ; September 2015'
});

Initialize a Program

import { Keypair } from '@stellar/stellar-sdk';

const sourceKeypair = Keypair.fromSecret('YOUR_SECRET_KEY');

try {
  const programData = await client.initProgram(
    'my-program-id',
    'GAUTHORIZED_PAYOUT_KEY...',
    'GTOKEN_ADDRESS...',
    sourceKeypair
  );
  console.log('Program initialized:', programData);
} catch (error) {
  if (error instanceof ValidationError) {
    console.error('Invalid input:', error.message);
  } else if (error instanceof ContractError) {
    console.error('Contract error:', error.code, error.message);
  } else if (error instanceof NetworkError) {
    console.error('Network error:', error.statusCode, error.message);
  }
}

Lock Funds

try {
  const programData = await client.lockProgramFunds(
    10000000n, // Amount in stroops
    sourceKeypair
  );
  console.log('Funds locked. Remaining balance:', programData.remaining_balance);
} catch (error) {
  // Handle errors
}

Execute Batch Payout

const recipients = [
  'GRECIPIENT1...',
  'GRECIPIENT2...',
  'GRECIPIENT3...'
];

const amounts = [
  1000000n,
  2000000n,
  1500000n
];

try {
  const programData = await client.batchPayout(
    recipients,
    amounts,
    sourceKeypair
  );
  console.log('Batch payout completed');
} catch (error) {
  // Handle errors
}

Get Program Info

try {
  const programData = await client.getProgramInfo();
  console.log('Program ID:', programData.program_id);
  console.log('Total funds:', programData.total_funds);
  console.log('Remaining balance:', programData.remaining_balance);
} catch (error) {
  // Handle errors
}

Error Handling

The SDK provides three main error types:

ValidationError

Thrown when input parameters are invalid before making a contract call.

import { ValidationError } from '@grainlify/contracts-sdk';

try {
  await client.lockProgramFunds(0n, keypair); // Invalid: amount must be > 0
} catch (error) {
  if (error instanceof ValidationError) {
    console.error('Field:', error.field);
    console.error('Message:', error.message);
  }
}

ContractError

Thrown when the smart contract returns an error.

import { ContractError, ContractErrorCode } from '@grainlify/contracts-sdk';

try {
  await client.singlePayout(recipient, amount, keypair);
} catch (error) {
  if (error instanceof ContractError) {
    switch (error.code) {
      case ContractErrorCode.NOT_INITIALIZED:
        console.error('Program not initialized');
        break;
      case ContractErrorCode.UNAUTHORIZED:
        console.error('Unauthorized access');
        break;
      case ContractErrorCode.INSUFFICIENT_BALANCE:
        console.error('Insufficient balance');
        break;
      // ... handle other cases
    }
  }
}

NetworkError

Thrown when there are network or transport issues.

import { NetworkError } from '@grainlify/contracts-sdk';

try {
  await client.getProgramInfo();
} catch (error) {
  if (error instanceof NetworkError) {
    console.error('Status code:', error.statusCode);
    console.error('Cause:', error.cause);
    // Implement retry logic
  }
}

Contract Error Codes

  • NOT_INITIALIZED - Program not initialized
  • UNAUTHORIZED - Caller does not have permission
  • INSUFFICIENT_BALANCE - Insufficient balance for operation
  • INVALID_AMOUNT - Amount must be greater than zero
  • ALREADY_INITIALIZED - Program already initialized
  • EMPTY_BATCH - Cannot process empty batch
  • LENGTH_MISMATCH - Recipients and amounts arrays must match
  • OVERFLOW - Payout amount overflow
  • GOVERNANCE_VERSION_TOO_LOW - Linked governance contract version is below the program escrow minimum
  • BOUNTY_AMOUNT_BELOW_MINIMUM - Bounty amount is below the configured policy minimum
  • BOUNTY_AMOUNT_ABOVE_MAXIMUM - Bounty amount is above the configured policy maximum
  • BOUNTY_CIRCUIT_BREAKER_OPEN - Bounty escrow circuit breaker is open
  • BOUNTY_GOVERNANCE_VERSION_TOO_LOW - Linked governance contract version is below the bounty escrow minimum

Testing

Run the test suite:

npm test

Run tests with coverage:

npm run test:coverage

Error Handling Tests

The SDK includes comprehensive error handling tests covering:

  • Input validation errors
  • Contract error parsing and mapping
  • Network and transport errors
  • HTTP status code handling
  • Error type hierarchy and properties
  • Error recovery scenarios

See src/__tests__/error-handling.test.ts and src/__tests__/network-errors.test.ts for detailed test cases.

Development

Build the SDK:

npm run build

Regenerate the SDK API reference:

npm run docs

Watch mode for tests:

npm run test:watch

License

MIT