Skip to content

Latest commit

Β 

History

History
552 lines (419 loc) Β· 14.4 KB

File metadata and controls

552 lines (419 loc) Β· 14.4 KB

πŸ’° Galaxy DeFi Protocols

Integration layer for Stellar DeFi protocols

License: MIT TypeScript Stellar

πŸ“‹ Overview

@galaxy/core-defi-protocols provides a unified interface for interacting with DeFi protocols on the Stellar blockchain. It abstracts protocol-specific implementations behind a common interface, making it easy to integrate multiple protocols with consistent patterns.

Supported Protocols

  • Blend Protocol - Lending and borrowing
  • Soroswap - Decentralized exchange
  • Aquarius - Liquidity pools

🎯 Features

  • βœ… Unified Interface - Common interface (IDefiProtocol) for all protocols
  • βœ… Type Safety - Full TypeScript support with comprehensive types
  • βœ… Factory Pattern - Easy protocol instantiation with factory service
  • βœ… Validation - Built-in input validation for addresses, amounts, and assets
  • βœ… Error Handling - Consistent error handling across all protocols
  • βœ… Extensible - Easy to add new protocol implementations
  • βœ… Security - Never stores private keys, validates all inputs
  • βœ… Testing - 90%+ test coverage

πŸ“¦ Installation

npm install @galaxy/core-defi-protocols

πŸš€ Quick Start

Basic Usage

import {
  getProtocolFactory,
  ProtocolConfig,
  TESTNET_CONFIG
} from '@galaxy/core-defi-protocols';

// 1. Create protocol configuration
const config: ProtocolConfig = {
  protocolId: 'blend',
  name: 'Blend Protocol',
  network: TESTNET_CONFIG,
  contractAddresses: {
    pool: 'CBLEND_POOL_CONTRACT_ADDRESS'
  },
  metadata: {}
};

// 2. Get protocol instance from factory
const factory = getProtocolFactory();
const blend = factory.createProtocol(config);

// 3. Initialize protocol
await blend.initialize();

// 4. Supply assets to earn interest
const result = await blend.supply(
  'GBRPYHIL2CI3FNQ4BXLFMNDLFJUNPU2HY3ZMFSHONUCEOASW7QC7OX2H',
  'SXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
  {
    code: 'USDC',
    issuer: 'GAUSDC_ISSUER_ADDRESS',
    type: 'credit_alphanum4'
  },
  '1000.00'
);

console.log('Transaction hash:', result.hash);

// 5. Check position health
const position = await blend.getPosition(walletAddress);
console.log('Health Factor:', position.healthFactor);
console.log('Collateral Value:', position.collateralValue);
console.log('Debt Value:', position.debtValue);

πŸ“š Core Concepts

IDefiProtocol Interface

All protocols implement the IDefiProtocol interface, which defines:

  • Lending Operations: supply(), borrow(), repay(), withdraw()
  • Position Management: getPosition(), getHealthFactor()
  • Protocol Info: getSupplyAPY(), getBorrowAPY(), getStats()
  • DEX Operations (optional): swap(), addLiquidity(), removeLiquidity()

BaseProtocol Abstract Class

The BaseProtocol abstract class provides common functionality:

  • Network connection management
  • Input validation (addresses, amounts, assets)
  • Configuration validation
  • Error handling utilities
  • Transaction result building

Protocol Factory

The ProtocolFactory uses the singleton pattern to manage protocol registration and instantiation:

import { ProtocolFactory } from '@galaxy/core-defi-protocols';

const factory = ProtocolFactory.getInstance();

// Register a custom protocol
factory.register('my-protocol', MyProtocolClass);

// Create protocol instance
const protocol = factory.createProtocol(config);

πŸ”§ API Reference

Types

Asset

interface Asset {
  code: string;                                    // e.g., 'USDC', 'XLM'
  issuer?: string;                                 // Required for non-native assets
  type: 'native' | 'credit_alphanum4' | 'credit_alphanum12';
}

Position

interface Position {
  address: string;
  supplied: PositionBalance[];                     // Supplied assets
  borrowed: PositionBalance[];                     // Borrowed assets
  healthFactor: string;                            // >1.0 is healthy
  collateralValue: string;                         // Total collateral in USD
  debtValue: string;                               // Total debt in USD
}

TransactionResult

interface TransactionResult {
  hash: string;                                    // Transaction hash
  status: 'success' | 'failed' | 'pending';
  ledger: number;                                  // Ledger number
  createdAt: Date;
  metadata: Record<string, unknown>;
}

Operation Types (Discriminated Unions)

import {
  OperationType,
  SupplyOperation,
  SwapOperation,
  isSupplyOperation,
  isSwapOperation
} from '@galaxy/core-defi-protocols';

// All operation types: SupplyOperation, WithdrawOperation, BorrowOperation,
// RepayOperation, SwapOperation, AddLiquidityOperation, RemoveLiquidityOperation

const supplyOp: SupplyOperation = {
  type: OperationType.SUPPLY,
  timestamp: new Date(),
  walletAddress: 'GBRPY...OX2H',
  asset: { code: 'USDC', issuer: 'GAUS...', type: 'credit_alphanum4' },
  amount: '1000.0000000'
};

// Use type guards to narrow types
if (isSupplyOperation(op)) {
  console.log(`Supplying ${op.amount} of ${op.asset.code}`);
}

Error Classes

import {
  ProtocolError,
  InsufficientBalanceError,
  SlippageExceededError,
  isProtocolError,
  wrapError
} from '@galaxy/core-defi-protocols';

// Available error classes:
// - ProtocolError (base) - ProtocolInitError - InsufficientBalanceError
// - InvalidOperationError - ContractError - SlippageExceededError - HealthFactorError

try {
  await protocol.supply(wallet, privateKey, asset, amount);
} catch (error) {
  if (isProtocolError(error)) {
    console.error(`[${error.code}] ${error.message}`);
    if (error instanceof InsufficientBalanceError) {
      console.log(`Need ${error.required}, have ${error.available}`);
    }
  } else {
    const wrapped = wrapError(error, 'blend');
    console.error(wrapped.toJSON());
  }
}

Main Methods

DexAggregatorService

DexAggregatorService compares Soroswap and SDEX quotes and can evaluate explicit split execution across both venues.

import { DexAggregatorService } from '@galaxy-kj/core-defi-protocols';

const aggregator = new DexAggregatorService({
  protocolId: 'soroswap',
  name: 'Soroswap',
  network: TESTNET_CONFIG,
  contractAddresses: {
    router: 'CA_ROUTER',
    factory: 'CA_FACTORY',
  },
  metadata: {},
});

const bestQuote = await aggregator.getBestQuote(
  { code: 'XLM', type: 'native' },
  { code: 'USDC', issuer: 'GAUS...', type: 'credit_alphanum4' },
  '100'
);

const splitQuote = await aggregator.getSplitQuote(
  { code: 'XLM', type: 'native' },
  { code: 'USDC', issuer: 'GAUS...', type: 'credit_alphanum4' },
  '100',
  [60, 40]
);

initialize()

Initialize protocol connection and validate configuration.

await protocol.initialize();

supply(walletAddress, privateKey, asset, amount)

Supply assets to the protocol to earn interest.

const result = await protocol.supply(
  'GBRPY...OX2H',
  'SXXXX...XXXX',
  { code: 'USDC', issuer: 'GAUS...', type: 'credit_alphanum4' },
  '1000.00'
);

borrow(walletAddress, privateKey, asset, amount)

Borrow assets from the protocol against supplied collateral.

const result = await protocol.borrow(
  'GBRPY...OX2H',
  'SXXXX...XXXX',
  { code: 'XLM', type: 'native' },
  '500.00'
);

getPosition(address)

Get user's current position in the protocol.

const position = await protocol.getPosition('GBRPY...OX2H');
console.log('Health Factor:', position.healthFactor);

getHealthFactor(address)

Get detailed health factor information for a position.

const health = await protocol.getHealthFactor('GBRPY...OX2H');
console.log('Is Healthy:', health.isHealthy);
console.log('Liquidation Threshold:', health.liquidationThreshold);

πŸ”„ Soroswap Protocol (DEX)

Soroswap is a Uniswap V2-style decentralized exchange on Stellar. It supports token swaps and liquidity pool management.

Quick Start

import {
  SoroswapProtocol,
  SOROSWAP_TESTNET_CONFIG,
  calculateSoroswapPoolAnalytics,
  getSoroswapConfig
} from '@galaxy/core-defi-protocols';

// Initialize Soroswap
const soroswap = new SoroswapProtocol(SOROSWAP_TESTNET_CONFIG);
await soroswap.initialize();

// Get protocol stats
const stats = await soroswap.getStats();
console.log('TVL:', stats.tvl);

// Get pair information
const pairInfo = await soroswap.getPairInfo(tokenAAddress, tokenBAddress);
console.log('Reserves:', pairInfo.reserve0, pairInfo.reserve1);

// Get all registered pairs
const pairs = await soroswap.getAllPairs();

// Get analytics with external price / volume inputs
const analytics = await soroswap.getPoolAnalytics(pairAddress, {
  token0PriceUsd: 0.11,
  token1PriceUsd: 1,
  volume24hUsd: 25000,
  lpPosition: {
    lpTokenAmount: '5000000',
    initialPriceRatio: 9,
  },
});

console.log('Pool TVL:', analytics.tvlUsd);
console.log('24h fees:', analytics.fees24hUsd);
console.log('Fee APR:', analytics.feeApr);
console.log('Impermanent loss %:', analytics.lpPosition?.impermanentLossPct);

// Or derive analytics locally from a raw pool snapshot
const localAnalytics = calculateSoroswapPoolAnalytics({
  poolAddress: analytics.poolAddress,
  token0: analytics.token0,
  token1: analytics.token1,
  reserve0: analytics.reserve0,
  reserve1: analytics.reserve1,
  totalSupply: analytics.totalSupply,
  options: {
    token0PriceUsd: 0.11,
    token1PriceUsd: 1,
    volume24hUsd: 25000,
  },
});

Factory Usage

import { getProtocolFactory, SOROSWAP_TESTNET_CONFIG } from '@galaxy/core-defi-protocols';

// Soroswap auto-registers with the factory on import
const factory = getProtocolFactory();
const soroswap = factory.createProtocol(SOROSWAP_TESTNET_CONFIG);
await soroswap.initialize();

DEX Operations

The Soroswap integration currently includes:

  • swap() β€” Token swaps via the router contract
  • getSwapQuote() β€” Quote outputs and price impact
  • addLiquidity() β€” Add liquidity to pools
  • removeLiquidity() β€” Remove liquidity from pools
  • getLiquidityPool() β€” Read on-chain pool balances
  • getPoolAnalytics() β€” Derive TVL, fee APR, volume-based revenue, and LP impermanent loss estimates

Contract Addresses

Network Router Factory
Testnet CCJUD55AG...ZE7BRD CDP3HMUH6...RJTBY
Mainnet CAG5LRYQ5...AJDDH CA4HEQTL2...7AW2

πŸ› οΈ Development

Adding a New Protocol

  1. Create Protocol Class
// src/protocols/my-protocol/my-protocol.ts
import { BaseProtocol } from '../base-protocol';
import { ProtocolType } from '../../types/defi-types';

export class MyProtocol extends BaseProtocol {
  protected getProtocolType(): ProtocolType {
    return ProtocolType.LENDING;
  }

  protected async setupProtocol(): Promise<void> {
    // Initialize protocol-specific connections
  }

  // Implement required abstract methods
  public async supply(...) { /* ... */ }
  public async borrow(...) { /* ... */ }
  // ... other methods
}
  1. Register Protocol
import { getProtocolFactory } from '@galaxy/core-defi-protocols';
import { MyProtocol } from './protocols/my-protocol/my-protocol';

const factory = getProtocolFactory();
factory.register('my-protocol', MyProtocol);
  1. Write Tests
// __tests__/protocols/my-protocol.test.ts
describe('MyProtocol', () => {
  it('should supply assets', async () => {
    const protocol = new MyProtocol(config);
    await protocol.initialize();
    const result = await protocol.supply(...);
    expect(result.status).toBe('success');
  });
});

Running Tests

# Run all tests
npm test

# Run tests in watch mode
npm run test:watch

# Run tests with coverage
npm run test:coverage

Building

# Build the package
npm run build

# Build in watch mode (for development)
npm run dev

πŸ”’ Security

Best Practices

  1. Unsigned Transaction Workflow - Protocol methods can return unsigned XDRs when a privateKey is not provided (empty string). This allows for secure client-side signing (e.g., via Freighter or Hawkeye).
  2. Never Store Private Keys - Private keys are only used to sign transactions and are never stored.
  3. Validate All Inputs - Use built-in validation utilities for addresses, amounts, and assets.
  4. Check Health Factors - Always check position health before risky operations
  5. Use Slippage Protection - Set appropriate slippage tolerance for swaps
  6. Test on Testnet First - Always test your integration on testnet before mainnet

Input Validation

import {
  validateAddress,
  validateAmount,
  validateAsset,
  validateSlippage
} from '@galaxy/core-defi-protocols';

// Validate Stellar address
validateAddress('GBRPY...OX2H');

// Validate amount
validateAmount('1000.50', 'Deposit Amount');

// Validate asset
validateAsset({
  code: 'USDC',
  issuer: 'GAUS...XXXX',
  type: 'credit_alphanum4'
});

// Validate slippage (0-1, e.g., 0.01 for 1%)
validateSlippage('0.01');

πŸ§ͺ Testing

The package includes comprehensive tests with 90%+ coverage:

  • Unit Tests - All utilities and services
  • Integration Tests - Protocol implementations
  • Validation Tests - Input validation
npm test                 # Run all tests
npm run test:coverage    # Generate coverage report

πŸ“– Examples

See the docs/examples/defi-protocols/ directory for complete examples:

  • 01-basic-setup.ts - Basic protocol setup and initialization
  • 02-lending-operations.ts - Supply, borrow, repay, withdraw
  • 03-custom-protocol.ts - Implementing a custom protocol
  • 04-operations.ts - Using different operation types and error handling

🀝 Contributing

  1. Follow the project's TypeScript style guide
  2. Write comprehensive tests (aim for 90%+ coverage)
  3. Update documentation for new features
  4. Add examples for new protocols

πŸ“„ License

MIT Β© Galaxy DevKit Team

πŸ”— Links


Built with ❀️ for the Stellar ecosystem