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.7.3

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';

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

Quick Start

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

const sdk = new BorrowSDK({
  apiKey: 'your-api-key',
  wallet: {
    address: 'bc1q...',
    signMessage: async (msg) => wallet.signMessage(msg),
    sendBitcoin: async (to, sats) => wallet.sendBitcoin(to, sats)
  }
});

const quotes = await sdk.getQuotes({
  collateralAmount: '0.1',
  loanAmount: '5000'
});
const workflowId = await sdk.executeBorrow(quotes[0]);

await sdk.trackWorkflow(workflowId, {
  onDepositReady: (info) => console.log(`Deposit ${info.amount} BTC to ${info.address}`),
  onComplete: () => console.log('Loan complete!')
}, 'borrow');

Features

  • Non-custodial: Your Bitcoin, your keys
  • Gasless: All EVM transactions are sponsored
  • Multi-chain: Arbitrum, Base, Ethereum, and BNB Chain 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)
  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!,
  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

For dashboards or account preloading, call setup() to initialize the smart account, create a session, and fetch history. Borrow execution can also prepare the required wallet/session state automatically.

The constructor is chainless. Account preload methods such as setup() use the active chain when available and otherwise default to Base for preload; borrow execution derives the chain from the selected quote.

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. Prepares the platform wallet address/signature automatically if needed
  3. Creates a repay transaction on the backend
  4. Starts a Temporal workflow that handles the entire process
  5. 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.

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

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

Wallet Connection

setup(): Promise<SetupResult>

Initializes the smart account, creates a session, and fetches history. This is useful for dashboard/account preload flows; executeBorrow() can prepare the required borrow session automatically.

const { userStatus, transactions } = await sdk.setup();
console.log('Smart Account:', userStatus.smartAccountAddress);
console.log('Transactions:', transactions.length);

Returns: Platform wallet, user status, active session, and transaction history.

Loan Operations

setup(): Promise<SetupResult>

Sets up the SDK for account-oriented flows and returns current history. It is optional for borrowing because executeBorrow() prepares the required borrow wallet/session if needed.

const { userStatus, transactions } = await sdk.setup();

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

Fetches loan quotes from available protocols.

const quotes = await sdk.getQuotes({
  collateralAmount: '0.01',
  loanAmount: '1000'
});

// 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...'
});

await sdk.trackWorkflow(workflowId, {
  onStatusUpdate: (status) => console.log(status),
  onComplete: () => console.log('Done!')
}, 'borrow');

Returns: Workflow ID string.

Repay Operations

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

Repay a loan (full or partial). The SDK prepares the platform wallet address/signature automatically if needed.

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. The SDK prepares the platform wallet address/signature automatically if needed.

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, ChainType } from '@satsterminal-sdk/borrow';

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

const quotes = await sdk.getQuotes({
  collateralAmount: '0.01',
  loanAmount: '1000'
});
const workflowId = await sdk.executeBorrow(quotes[0]);

await sdk.trackWorkflow(workflowId, {
  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: () => {
    console.log('✅ Loan completed!');
    console.log('Workflow ID:', workflowId);
  },
  onError: (error) => {
    console.error('❌ Error:', error);
  }
}, 'borrow');

Manual Loan Flow (Advanced)

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

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

// Step 3: Execute borrow with workflow tracking.
// executeBorrow() prepares the platform wallet/session automatically if needed.
const workflowId = await sdk.executeBorrow(selectedQuote);

await sdk.trackWorkflow(workflowId, {
  onStatusUpdate: (status) => {
    console.log(`[${status.step}/${status.totalSteps}] ${status.label}`);
  },
  onDepositReady: (info) => {
    console.log('Deposit to:', info.depositAddress);
  },
  onComplete: () => console.log('Done!')
}, 'borrow');

Withdraw USDC (Gasless)

// Withdraw borrowed USDC to your wallet - gas is sponsored.
// The SDK prepares platform wallet signing automatically if needed.
const transactionId = await sdk.withdrawToEVM({
  chain: ChainType.ARBITRUM,
  amount: '100',
  assetSymbol: 'USDC',
  destinationAddress: '0x...'
});

const status = await sdk.getWithdrawStatus(transactionId);
console.log(status.data.transactionDetails?.transactionHash);

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
  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() | Optional account preload: initialize wallet/session and fetch history | | getQuotes(params) | Get loan quotes | | executeBorrow(quote) | Execute borrow; prepares required wallet/session automatically | | repay(loanId, amount, options) | Repay a loan; prepares platform wallet signing automatically | | withdrawCollateral(loanId, amount, btcAddress) | Withdraw collateral to BTC; prepares platform wallet signing automatically | | withdrawToEVM(params) | Create a gasless platform-wallet transfer to EVM; returns a trackable withdrawal transaction ID | | withdrawToBitcoin(params) | Withdraw USDC to BTC; prepares platform wallet signing automatically | | 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 {
  const workflowId = await sdk.executeBorrow(selectedQuote);
  await sdk.trackWorkflow(workflowId, callbacks, 'borrow');
} catch (error) {
  if (error instanceof ApiError) {
    console.error('API Error:', error.statusCode, error.message);
  }
}

Documentation

Full documentation: docs.satsterminal.com

License

MIT