Integration layer for Stellar DeFi protocols
@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.
- Blend Protocol - Lending and borrowing
- Soroswap - Decentralized exchange
- Aquarius - Liquidity pools
- β
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
npm install @galaxy/core-defi-protocolsimport {
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);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()
The BaseProtocol abstract class provides common functionality:
- Network connection management
- Input validation (addresses, amounts, assets)
- Configuration validation
- Error handling utilities
- Transaction result building
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);interface Asset {
code: string; // e.g., 'USDC', 'XLM'
issuer?: string; // Required for non-native assets
type: 'native' | 'credit_alphanum4' | 'credit_alphanum12';
}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
}interface TransactionResult {
hash: string; // Transaction hash
status: 'success' | 'failed' | 'pending';
ledger: number; // Ledger number
createdAt: Date;
metadata: Record<string, unknown>;
}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}`);
}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());
}
}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 protocol connection and validate configuration.
await protocol.initialize();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 assets from the protocol against supplied collateral.
const result = await protocol.borrow(
'GBRPY...OX2H',
'SXXXX...XXXX',
{ code: 'XLM', type: 'native' },
'500.00'
);Get user's current position in the protocol.
const position = await protocol.getPosition('GBRPY...OX2H');
console.log('Health Factor:', position.healthFactor);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 is a Uniswap V2-style decentralized exchange on Stellar. It supports token swaps and liquidity pool management.
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,
},
});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();The Soroswap integration currently includes:
swap()β Token swaps via the router contractgetSwapQuote()β Quote outputs and price impactaddLiquidity()β Add liquidity to poolsremoveLiquidity()β Remove liquidity from poolsgetLiquidityPool()β Read on-chain pool balancesgetPoolAnalytics()β Derive TVL, fee APR, volume-based revenue, and LP impermanent loss estimates
| Network | Router | Factory |
|---|---|---|
| Testnet | CCJUD55AG...ZE7BRD |
CDP3HMUH6...RJTBY |
| Mainnet | CAG5LRYQ5...AJDDH |
CA4HEQTL2...7AW2 |
- 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
}- 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);- 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');
});
});# Run all tests
npm test
# Run tests in watch mode
npm run test:watch
# Run tests with coverage
npm run test:coverage# Build the package
npm run build
# Build in watch mode (for development)
npm run dev- Unsigned Transaction Workflow - Protocol methods can return unsigned XDRs when a
privateKeyis not provided (empty string). This allows for secure client-side signing (e.g., via Freighter or Hawkeye). - Never Store Private Keys - Private keys are only used to sign transactions and are never stored.
- Validate All Inputs - Use built-in validation utilities for addresses, amounts, and assets.
- Check Health Factors - Always check position health before risky operations
- Use Slippage Protection - Set appropriate slippage tolerance for swaps
- Test on Testnet First - Always test your integration on testnet before mainnet
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');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 reportSee the docs/examples/defi-protocols/ directory for complete examples:
01-basic-setup.ts- Basic protocol setup and initialization02-lending-operations.ts- Supply, borrow, repay, withdraw03-custom-protocol.ts- Implementing a custom protocol04-operations.ts- Using different operation types and error handling
- Follow the project's TypeScript style guide
- Write comprehensive tests (aim for 90%+ coverage)
- Update documentation for new features
- Add examples for new protocols
MIT Β© Galaxy DevKit Team
Built with β€οΈ for the Stellar ecosystem