Skip to main content

Overview

This agent skill monitors a user’s credit position and takes autonomous action to keep it healthy:
  • Repays debt before the billing cycle ends to avoid the 15% overdue APR
  • Tops up collateral if the health factor drops below a safe threshold
  • Alerts on critical health factor levels

API Endpoints Used

EndpointPurpose
GET /credit/accounts/{account}/infoCheck health factor, debt, due date
GET /credit/accounts/{account}/repayBuild repayment calldata
GET /credit/accounts/{account}/lockBuild collateral top-up calldata

How It Works

1

Poll Position Health

The agent periodically checks the user’s credit position:
curl -X GET https://api.sprinter.tech/credit/accounts/0xUSER/info
{
  "data": {
    "USDC": {
      "totalCollateralValue": "5000.00",
      "principal": "2000.00",
      "interest": "12.50",
      "healthFactor": "1.85",
      "dueDate": "2025-04-01T00:00:00Z"
    }
  }
}
The agent extracts three signals: healthFactor, principal + interest (total debt), and dueDate.
2

Evaluate & Decide

The agent applies rules to decide what action to take:
ConditionAction
dueDate is within 3 days and debt > 0Auto-repay full balance
healthFactor < 1.3Lock additional collateral
healthFactor < 1.1Lock collateral + alert user
healthFactor >= 1.3 and no upcoming due dateNo action
3

Execute

When the due date is approaching, the agent repays the full outstanding balance:
curl -X GET 'https://api.sprinter.tech/credit/accounts/0xUSER/repay?amount=2012500000'
The amount is principal + interest in USDC lowest denomination (6 decimals). $2,012.50 = 2012500000.Returns { calls: ContractCall[] } — execute via the delegated signer.

Implementation

const SPRINTER_API = "https://api.sprinter.tech";
const POLL_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes
const HEALTH_FACTOR_THRESHOLD = 1.3;
const REPAY_DAYS_BEFORE_DUE = 3;

interface CreditInfo {
  data: {
    USDC: {
      totalCollateralValue: string;
      principal: string;
      interest: string;
      healthFactor: string;
      dueDate: string | null;
    };
  };
}

interface ContractCall {
  to: string;
  data: string;
  value: string;
}

async function getCreditInfo(account: string): Promise<CreditInfo> {
  const res = await fetch(`${SPRINTER_API}/credit/accounts/${account}/info`);
  if (!res.ok) throw new Error(`Credit info failed: ${res.status}`);
  return res.json();
}

async function buildRepayCalls(account: string, amount: string): Promise<ContractCall[]> {
  const res = await fetch(
    `${SPRINTER_API}/credit/accounts/${account}/repay?amount=${amount}`,
  );
  if (!res.ok) throw new Error(`Repay calldata failed: ${res.status}`);
  const data = await res.json();
  return data.calls;
}

async function buildLockCalls(
  account: string,
  amount: string,
  asset: string
): Promise<ContractCall[]> {
  const res = await fetch(
    `${SPRINTER_API}/credit/accounts/${account}/lock?amount=${amount}&asset=${asset}`,
  );
  if (!res.ok) throw new Error(`Lock calldata failed: ${res.status}`);
  const data = await res.json();
  return data.calls;
}

async function executeCalls(calls: ContractCall[], signer: any): Promise<string> {
  let lastTxHash = "";
  for (const call of calls) {
    const tx = await signer.sendTransaction({
      to: call.to,
      data: call.data,
      value: call.value || "0",
    });
    const receipt = await tx.wait();
    if (!receipt || receipt.status !== 1) throw new Error(`Tx reverted: ${tx.hash}`);
    lastTxHash = tx.hash;
  }
  return lastTxHash;
}

/** Convert dollar amount to USDC lowest denomination (6 decimals) */
function dollarsToUsdcUnits(dollars: number): string {
  return Math.ceil(dollars * 1_000_000).toString();
}

function daysUntil(dateStr: string): number {
  return (new Date(dateStr).getTime() - Date.now()) / (1000 * 60 * 60 * 24);
}

async function monitorAndAct(account: string, signer: any, collateralAsset: string) {
  const info = await getCreditInfo(account);
  const { principal, interest, healthFactor, dueDate } = info.data.USDC;

  const debt = parseFloat(principal) + parseFloat(interest);
  const hf = parseFloat(healthFactor);

  // Auto-repay if due date is approaching
  if (dueDate && daysUntil(dueDate) <= REPAY_DAYS_BEFORE_DUE && debt > 0) {
    console.log(`Due date approaching — repaying $${debt.toFixed(2)}`);
    const calls = await buildRepayCalls(account, dollarsToUsdcUnits(debt));
    const txHash = await executeCalls(calls, signer);
    console.log(`Repayment executed: ${txHash}`);
    return;
  }

  // Top up collateral if health factor is low
  if (hf < HEALTH_FACTOR_THRESHOLD && debt > 0) {
    console.log(`Health factor ${hf.toFixed(2)} below threshold — locking more collateral`);
    const calls = await buildLockCalls(account, "1000000000000000000", collateralAsset);
    const txHash = await executeCalls(calls, signer);
    console.log(`Collateral locked: ${txHash}`);
    return;
  }

  console.log(`Position healthy — HF: ${hf.toFixed(2)}, debt: $${debt.toFixed(2)}`);
}

// Run the monitor loop
setInterval(() => {
  monitorAndAct("0xUSER_ADDRESS", signer, "0xCOLLATERAL_TOKEN").catch(console.error);
}, POLL_INTERVAL_MS);

Configuration

Poll Interval

Default: every 5 minutes. Increase for lower API usage, decrease if positions are volatile. For most users, 5–15 minutes is sufficient.
Default: 1.3. The agent tops up collateral when health factor drops below this. See Risk Management for liquidation thresholds — positions below 1.0 are liquidatable.
Default: 3 days before due date. Repaying early avoids the 15% overdue APR that kicks in after the billing cycle ends.

Credit Engine

Health factor, LTVs, and liquidation mechanics.

Risk Management

Collateral tiers and concentration limits.

Credit API Reference

Full account info endpoint with interactive playground.