npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@satsterminal-sdk/borrow

v1.6.21

Published

Borrowing module for SatsTerminal SDK

Readme

@satsterminal-sdk/borrow

Borrow stablecoins against your Bitcoin collateral. Gasless, non-custodial, powered by smart accounts.

Installation

npm install @satsterminal-sdk/borrow

Or use the aggregator if you also need swaps:

import { createClient } from 'satsterminal-sdk';
import { ChainType } from '@satsterminal-sdk/borrow';

const { borrow } = createClient({
  apiKey: process.env.API_KEY!,
  borrow: { chain: ChainType.BASE, wallet }
});

Quick Start

import { BorrowSDK, ChainType } from '@satsterminal-sdk/borrow';

const sdk = new BorrowSDK({
  apiKey: 'your-api-key',
  // baseUrl optional (defaults to https://api.satsterminal.com)
  chain: ChainType.ARBITRUM, // or ChainType.BASE
  wallet: {
    address: 'bc1q...',
    signMessage: async (msg) => wallet.signMessage(msg),
    sendBitcoin: async (to, sats) => wallet.sendBitcoin(to, sats)
  }
});

// Get a loan
const result = await sdk.getLoan({
  collateralBTC: 0.1,
  loanAmountUSD: 5000,
  onDepositReady: (info) => console.log(`Deposit ${info.amount} BTC to ${info.address}`),
  onComplete: () => console.log('Loan complete!')
});

Features

  • Non-custodial: Your Bitcoin, your keys
  • Gasless: All EVM transactions are sponsored
  • Multi-chain: Arbitrum, Base supported
  • Smart accounts: ERC-4337 account abstraction via ZeroDev

Usage

Get a Loan

interface BorrowSDKConfig {
  apiKey: string;                    // Required: Your API key
  baseUrl?: string;                  // Optional: API base URL (defaults to https://api.satsterminal.com)
  chain: ChainType;                  // Required: Chain to use
  wallet: WalletProvider;            // Required: Wallet provider
  rpcUrl?: string;                   // Optional: Custom RPC URL
  bundlerUrl?: string;               // Optional: Custom bundler URL
  storage?: StorageProvider;         // Optional: Custom storage (defaults to localStorage)
  workflowPollInterval?: number;     // Optional: Polling interval in ms (default: 2000)
  sessionValiditySeconds?: number;   // Optional: Session validity (default: 259200)
  autoTrackWorkflows?: boolean;      // Optional: Auto-track workflows (default: true)
  quoteSelector?: (quotes: Quote[]) => Quote; // Optional: Custom quote selector
  retryConfig?: RetryConfig;         // Optional: Retry configuration
  logger?: Logger;                   // Optional: Custom logger
}

Wallet Provider

The SDK requires a wallet provider that implements:

interface WalletProvider {
  address: string;                   // Bitcoin address
  publicKey?: string;                 // Optional: Public key
  signMessage: (message: string) => Promise<string>; // Sign messages
  sendBitcoin?: (toAddress: string, satoshis: number) => Promise<string>; // Send BTC
}

Example Configuration

const sdk = new BorrowSDK({
  apiKey: process.env.SATSTERMINAL_API_KEY!,
  chain: ChainType.ARBITRUM,
  wallet: {
    address: bitcoinAddress,
    signMessage: async (message) => {
      // Use sats-connect, Xverse, or UniSat wallet
      const response = await signMessage({ message });
      return response.signature;
    },
    sendBitcoin: async (to, amount) => {
      const response = await sendBtcTransaction({ 
        recipients: [{ address: to, amount }] 
      });
      return response.txid;
    }
  },
  autoTrackWorkflows: true,
  workflowPollInterval: 2000
});

Core Concepts

1. Setup

Before borrowing, you need to set up the SDK by calling setup(). This initializes the smart account and creates a session.

2. Quotes

Get loan quotes based on your collateral amount and desired loan amount. The SDK fetches quotes from multiple protocols.

3. Borrowing

Once you have a quote, you can execute the borrow operation. The SDK handles the entire workflow.

4. Repaying

Repay your loan partially or fully. You can also withdraw collateral if your loan health allows it.

5. Workflow Tracking

The SDK tracks asynchronous workflows and provides status updates via callbacks.

Repay Flow

The repay workflow is an asynchronous process that handles loan repayment and collateral withdrawal. Here's how it works:

Overview

When you call repay() or withdrawCollateral(), the SDK:

  1. Validates the amounts against the current loan state
  2. Creates a repay transaction on the backend
  3. Starts a Temporal workflow that handles the entire process
  4. Tracks the workflow and provides status updates

Workflow Stages

The repay workflow goes through the following stages:

1. INITIALIZING

  • The workflow is being set up
  • Validates amounts and prepares the transaction
  • User Action: None - wait for next stage

2. TRANSFERRING_TO_KERNEL (if repaying)

  • USDC is transferred from your wallet to the smart account (kernel wallet)
  • User Action: If insufficient balance, deposit USDC to the smart account address shown
  • Status: "Moving repay tokens to kernel wallet"

3. REPAYING_LOAN (if repaying)

  • The loan is repaid on the protocol (AAVE, Morpho, etc.)
  • USDC is used to pay down the debt
  • User Action: None - automatic
  • Status: "Executing loan repayment on protocol"

4. WITHDRAWING_COLLATERAL (if withdrawing)

  • Collateral (WBTC) is withdrawn from the protocol
  • User Action: None - automatic
  • Status: "Withdrawing collateral from protocol"

5. TRANSFERRING_TO_PLATFORM_WALLET (if withdrawing)

  • Withdrawn collateral is transferred to the platform wallet
  • User Action: None - automatic
  • Status: "Moving collateral to platform wallet"

6. BRIDGE Stages (if withdrawing)

If you're withdrawing collateral, it needs to be bridged from EVM (WBTC) to Bitcoin (BTC):

  • BRIDGE_INITIALIZING: Preparing the bridge
  • BRIDGE_QUOTE_READY: Bridge quote received
  • BRIDGE_SWAP_CREATED: Bridge swap order created
  • BRIDGE_EXECUTING_APPROVAL: Approving bridge contract
  • BRIDGE_APPROVAL_CONFIRMED: Approval confirmed
  • BRIDGE_EXECUTING_INITIATE: Initiating bridge
  • BRIDGE_INITIATE_CONFIRMED: Bridge initiated
  • BRIDGE_AWAITING_BRIDGE_COMPLETION: Waiting for bridge to complete
  • BRIDGE_COMPLETED: Bridge completed, BTC ready

7. COMPLETED

  • All operations completed successfully
  • If repaying: Loan debt reduced
  • If withdrawing: BTC sent to your withdrawal address

8. FAILED or CANCELLED

  • Workflow encountered an error or was cancelled
  • Check error details for resolution

Repay Flow Scenarios

Scenario 1: Repay Only (No Withdrawal)

INITIALIZING
  ↓
TRANSFERRING_TO_KERNEL (User deposits USDC)
  ↓
REPAYING_LOAN
  ↓
COMPLETED

Scenario 2: Withdraw Collateral Only (No Repay)

INITIALIZING
  ↓
WITHDRAWING_COLLATERAL
  ↓
TRANSFERRING_TO_PLATFORM_WALLET
  ↓
BRIDGE_INITIALIZING → ... → BRIDGE_COMPLETED
  ↓
COMPLETED

Scenario 3: Repay and Withdraw (Both)

INITIALIZING
  ↓
TRANSFERRING_TO_KERNEL (User deposits USDC)
  ↓
REPAYING_LOAN
  ↓
WITHDRAWING_COLLATERAL
  ↓
TRANSFERRING_TO_PLATFORM_WALLET
  ↓
BRIDGE_INITIALIZING → ... → BRIDGE_COMPLETED
  ↓
COMPLETED

Important Notes

  1. USDC Deposit Required: If repaying, you must deposit USDC to the smart account address before the workflow can proceed past TRANSFERRING_TO_KERNEL.

  2. Max Withdrawable: Before withdrawing, check getLoanCollateralInfo() to get the accurate maxWithdrawable amount (accounts for fees and health factor).

  3. Workflow Tracking: Use callbacks to track progress:

    await sdk.repay(loanId, amount, {
      trackWorkflow: true,
      callbacks: {
        onStatusUpdate: (status) => {
          console.log(`[${status.step}] ${status.label}`);
          console.log(status.description);
        },
        onComplete: () => console.log('Done!'),
        onError: (error) => console.error('Error:', error)
      }
    });
  4. Resuming Stuck Workflows: If a workflow gets stuck (e.g., waiting for USDC deposit), you can retry by calling repay() again with the same parameters, or use the "I've Deposited Funds" button in the UI.

  5. Partial Repays: You can repay any amount less than the total debt. The workflow will handle partial repayment correctly.

  6. Health Factor: The system ensures your loan remains healthy after operations. If a withdrawal would make the loan unhealthy, it will be rejected with an error message showing the maximum withdrawable amount.

API Reference

Initialization

new BorrowSDK(config: BorrowSDKConfig)

Creates a new SDK instance.

const sdk = new BorrowSDK({
  apiKey: 'your-api-key',
  chain: 'arbitrum',
  wallet: walletProvider
});

Wallet Connection

setup(): Promise<UserStatus>

Initializes the smart account and creates a session. Must be called before borrowing.

const userStatus = await sdk.setup();
console.log('Smart Account:', userStatus.smartAccountAddress);
console.log('Is Deployed:', userStatus.isDeployed);

Returns: UserStatus object with connection details.

Loan Operations

getLoan(options: GetLoanOptions): Promise<LoanResult>

High-level method that handles the entire loan process: setup, quoting, and borrowing.

const result = await sdk.getLoan({
  collateralBTC: 0.01,
  loanAmountUSD: 1000,
  ltv: 70,
  destinationAddress: '0x...', // Optional: Where to send the loan
  onStatusUpdate: (status) => {
    console.log('Status:', status.label, status.description);
  },
  onDepositReady: (info) => {
    console.log('Deposit to:', info.depositAddress);
    console.log('Amount:', info.amount, 'BTC');
  },
  onComplete: (result) => {
    console.log('Loan completed!', result);
  },
  onError: (error) => {
    console.error('Error:', error);
  }
});

Options:

  • collateralBTC: number - Amount of BTC to use as collateral
  • loanAmountUSD: number - Desired loan amount in USD
  • ltv?: number - Loan-to-value ratio (default: 70)
  • term?: number - Loan term in days (default: 30)
  • destinationAddress?: string - Address to receive the loan
  • quoteSelector?: (quotes: Quote[]) => Quote - Custom quote selection logic
  • onStatusUpdate?: (status: WorkflowStatus) => void - Status update callback
  • onDepositReady?: (info: DepositInfo) => void - Deposit ready callback
  • onComplete?: (result: any) => void - Completion callback
  • onError?: (error: string) => void - Error callback

Returns: LoanResult with workflow ID and tracker.

setup(): Promise<UserStatus>

Sets up the SDK for loan operations. Must be called before getQuotes() or executeBorrow().

const userStatus = await sdk.setup();

getQuotes(request: QuoteRequest): Promise<Quote[]>

Fetches loan quotes from available protocols.

const quotes = await sdk.getQuotes({
  collateralAmount: '0.01',
  loanAmount: '1000',
  ltv: 70,
  term: 30 // Optional: Loan term in days (default: 30)
});

// Select a quote (or use default selector)
const selectedQuote = quotes[0]; // Or use custom selector

Returns: Array of Quote objects from different protocols.

executeBorrow(quote: Quote, options?: BorrowOptions): Promise<string>

Executes a borrow transaction with the selected quote.

const workflowId = await sdk.executeBorrow(selectedQuote, {
  destinationAddress: '0x...',
  trackWorkflow: true,
  callbacks: {
    onStatusUpdate: (status) => console.log(status),
    onComplete: () => console.log('Done!')
  }
});

Returns: Workflow ID string.

Repay Operations

repay(originalBorrowId: string, repayAmount: string, options?: RepayOptions): Promise<string>

Repay a loan (full or partial).

const transactionId = await sdk.repay('loan-id', '500', {
  useCollateral: false, // Use collateral to repay?
  collateralToWithdraw: '0.001', // Optional: Withdraw collateral
  userBtcWithdrawAddress: 'bc1q...', // Required if withdrawing
  trackWorkflow: true,
  callbacks: {
    onStatusUpdate: (status) => console.log(status),
    onComplete: () => console.log('Repay complete!')
  }
});

Parameters:

  • originalBorrowId: string - The loan ID
  • repayAmount: string - Amount to repay in USDC (use '0' for collateral-only withdrawal)
  • options?: RepayOptions
    • useCollateral?: boolean - Use collateral for repayment
    • collateralToWithdraw?: string - Amount of collateral to withdraw
    • userBtcWithdrawAddress?: string - BTC address for withdrawal
    • trackWorkflow?: boolean - Track the workflow
    • callbacks?: WorkflowCallbacks - Workflow callbacks

Returns: Transaction ID string.

withdrawCollateral(originalBorrowId: string, collateralAmount: string, btcWithdrawAddress: string, options?: WithdrawOptions): Promise<string>

Withdraw collateral from a loan.

const transactionId = await sdk.withdrawCollateral(
  'loan-id',
  '0.001',
  'bc1q...',
  {
    trackWorkflow: true,
    callbacks: {
      onStatusUpdate: (status) => console.log(status),
      onComplete: () => console.log('Withdrawal complete!')
    }
  }
);

Returns: Transaction ID string.

getLoanCollateralInfo(loanId: string): Promise<LoanCollateralInfo | null>

Get loan collateral information including max withdrawable amount.

const collateralInfo = await sdk.getLoanCollateralInfo('loan-id');
if (collateralInfo) {
  console.log('Max Withdrawable:', collateralInfo.maxWithdrawable, 'BTC');
  console.log('Available Collateral:', collateralInfo.availableCollateral, 'BTC');
  console.log('Total Debt:', collateralInfo.totalDebt, 'USDC');
  console.log('Remaining Debt:', collateralInfo.remainingDebt, 'USDC');
}

Returns: LoanCollateralInfo object or null if not available.

Transaction History

getLoanHistory(options?: HistoryOptions): Promise<PaginatedResponse<UserTransaction>>

Get loan transaction history.

const history = await sdk.getLoanHistory({
  page: 1,
  limit: 20,
  status: 'active' // 'active' | 'pending' | 'all'
});

console.log(`Found ${history.transactions.length} transactions`);
console.log(`Total: ${history.pagination.totalTransactions}`);

Options:

  • page?: number - Page number (default: 1)
  • limit?: number - Items per page (default: 10)
  • status?: 'active' | 'pending' | 'all' - Filter by status (default: 'all')

Returns: Paginated response with transactions and pagination info.

getPendingLoans(): Promise<UserTransaction[]>

Get all pending loans (awaiting deposit).

const pendingLoans = await sdk.getPendingLoans();
console.log(`You have ${pendingLoans.length} pending loans`);

getRepayTransactions(loanId?: string): Promise<RepayTransaction[]>

Get repay transactions for a loan or all repay transactions.

// Get repay transactions for a specific loan
const repayTxs = await sdk.getRepayTransactions('loan-id');

// Get all repay transactions
const allRepayTxs = await sdk.getRepayTransactions();

getRepayStatus(transactionId: string): Promise<RepayTransactionStatusResponse>

Get status of a repay transaction.

const status = await sdk.getRepayStatus('transaction-id');
console.log('Status:', status.transactionDetails);
console.log('Workflow State:', status.transactionState);

Workflow Tracking

trackWorkflow(workflowId: string, callbacks: WorkflowCallbacks, workflowType?: 'borrow' | 'repay'): Promise<void>

Manually track a workflow.

await sdk.trackWorkflow('workflow-id', {
  onStatusUpdate: (status) => {
    console.log('Status:', status.label);
  },
  onComplete: (result) => {
    console.log('Workflow complete!', result);
  },
  onError: (error) => {
    console.error('Error:', error);
  }
}, 'borrow'); // or 'repay'

resumeLoan(workflowId: string, callbacks?: WorkflowCallbacks): Promise<void>

Resume tracking a loan workflow.

await sdk.resumeLoan('workflow-id', {
  onStatusUpdate: (status) => console.log(status),
  onComplete: () => console.log('Resumed and completed!')
});

Utility Methods

getStatus(workflowId: string): Promise<any>

Get workflow status.

const status = await sdk.getStatus('workflow-id');

clearSession(): void

Clear the current session.

sdk.clearSession();

Examples

Complete Loan Flow

import { BorrowSDK } from '@satsterminal-sdk/borrow';

const sdk = new BorrowSDK({
  apiKey: 'your-api-key',
  chain: 'arbitrum',
  wallet: walletProvider
});

// Get a loan with automatic workflow tracking
const result = await sdk.getLoan({
  collateralBTC: 0.01,
  loanAmountUSD: 1000,
  ltv: 70,
  onStatusUpdate: (status) => {
    console.log(`[${status.step}/${status.totalSteps}] ${status.label}`);
    console.log(status.description);
  },
  onDepositReady: (info) => {
    console.log('📥 Deposit Required:');
    console.log(`Address: ${info.depositAddress}`);
    console.log(`Amount: ${info.amount} BTC`);
    // User deposits BTC here
  },
  onComplete: (result) => {
    console.log('✅ Loan completed!');
    console.log('Workflow ID:', result.workflowId);
  },
  onError: (error) => {
    console.error('❌ Error:', error);
  }
});

// Stop tracking when done
result.stop();

Manual Loan Flow (Advanced)

// Step 1: Setup
await sdk.setup();

// Step 2: Get quotes
const quotes = await sdk.getQuotes({
  collateralAmount: '0.01',
  loanAmount: '1000',
  ltv: 70
});

// Step 3: Select best quote (or use default selector)
const selectedQuote = quotes[0];

// Step 4: Execute borrow with workflow tracking
const workflowId = await sdk.executeBorrow(selectedQuote, {
  trackWorkflow: true,
  callbacks: {
    onStatusUpdate: (status) => {
      console.log(`[${status.step}/${status.totalSteps}] ${status.label}`);
    },
    onDepositReady: (info) => {
      console.log('Deposit to:', info.depositAddress);
    },
    onComplete: () => console.log('Done!')
  }
});

Withdraw USDC (Gasless)

// Withdraw borrowed USDC to your wallet - gas is sponsored
const txHash = await sdk.withdrawToEVM({
  chain: ChainType.ARBITRUM,
  amount: '100',
  destinationAddress: '0x...'
});

Repay a Loan

await sdk.repay(loanId, '1000', {
  trackWorkflow: true,
  callbacks: {
    onComplete: () => console.log('Repaid!')
  }
});

Withdraw Collateral to Bitcoin

await sdk.withdrawCollateral(loanId, '0.01', 'bc1q...', {
  trackWorkflow: true
});

Check Positions

// Get wallet balances
const positions = await sdk.getWalletPositions();

// Get loan history
const history = await sdk.getLoanHistory({ status: 'active' });

// Get collateral info
const info = await sdk.getLoanCollateralInfo(loanId);
console.log('Max withdrawable:', info.maxWithdrawable);

Configuration

interface BorrowSDKConfig {
  apiKey: string;              // Required
  baseUrl: string;             // Required
  chain: ChainType;            // Required: ARBITRUM | BASE
  wallet: WalletProvider;      // Required
  workflowPollInterval?: number;     // Default: 2000ms
  sessionValiditySeconds?: number;   // Default: 259200 (3 days)
  autoTrackWorkflows?: boolean;      // Default: true
}

interface WalletProvider {
  address: string;
  signMessage: (message: string) => Promise<string>;
  sendBitcoin?: (toAddress: string, satoshis: number) => Promise<string>;
}

Wallet Integration

Works with any Bitcoin wallet that can sign messages:

// With sats-connect
import { signMessage, sendBtcTransaction } from 'sats-connect';

const wallet = {
  address: bitcoinAddress,
  signMessage: async (msg) => {
    const res = await signMessage({ message: msg });
    return res.signature;
  },
  sendBitcoin: async (to, amount) => {
    const res = await sendBtcTransaction({
      recipients: [{ address: to, amount }]
    });
    return res.txid;
  }
};

API Reference

| Method | Description | |--------|-------------| | setup() | Initialize SDK and create session | | getLoan(options) | Get a loan (handles full flow) | | getQuotes(params) | Get loan quotes | | executeBorrow(quote) | Execute borrow with quote | | repay(loanId, amount, options) | Repay a loan | | withdrawCollateral(loanId, amount, btcAddress) | Withdraw collateral to BTC | | withdrawToEVM(params) | Withdraw USDC to EVM (gasless) | | withdrawToBitcoin(params) | Withdraw USDC to BTC | | getLoanHistory(options) | Get transaction history | | getLoanCollateralInfo(loanId) | Get loan collateral details | | getWalletPositions() | Get wallet token balances |

Error Handling

import { BorrowSDKError, ApiError } from '@satsterminal-sdk/borrow';

try {
  await sdk.getLoan({ ... });
} catch (error) {
  if (error instanceof ApiError) {
    console.error('API Error:', error.statusCode, error.message);
  }
}

Documentation

Full documentation: docs.satsterminal.com

License

MIT