Skip to main content

Create and track Simple Loans

Use Simple Loans for a checkout-style borrow flow. The SDK creates a generated Liquidium profile, returns transfer targets, and lets your app restore the loan from a short reference.

Simple Loan flow

The following table shows the flow and your app's responsibility at each step:

StepSDK callYour app does
Load market dataclient.market.listPools() and client.market.getAssetPrices()Show supported collateral and borrow assets
Validate amountsclient.quote.calculateLtv(...)Block too-small borrow amounts, an invalid loan-to-value (LTV) ratio, or frozen-pool input before creation
Create loanclient.simpleLoans.create(...)Store loan.ref and show the selected quote from loan.initialDeposit.targets[chain]
Track loanclient.simpleLoans.get({ ref }), client.simpleLoans.find(...), and client.activities.list({ shortRef: ref })Reload state and monitor deposits, borrows, and repayments
Repay loanRead loan.repayment.targets[chain]If the selected quote exists and its amount > 0n, ask the user to send it to quote.target.address

Create a loan

Use the following fields in a client.simpleLoans.create(...) request:

FieldDescription
collateralCollateral poolId, asset, and intended credited amount in base units
borrowBorrow poolId, asset, amount, delivery chain, and destination
refundRefund chain and destination for returned collateral
ltvMaxBpsMaximum LTV in basis points, where 6_000n is 60%
depositWindowSecondsHow long the user has to send collateral

borrow.destination and refund.destination can be strings or typed account objects such as { type: "ChainAddress", address: "bc1q..." }, { type: "IcPrincipal", address: "aaaaa-aa" }, or { type: "IcrcAccount", address: "aaaaa-aa" }. The SDK validates that each destination family matches its selected asset and chain before creation.

Native ETH Simple Loans do not support borrow destinations with deployed contract bytecode. The same restriction applies to the refund destination when the collateral is native ETH. You do not need an Ethereum client for these checks.

Collateral minimums

The SDK rejects Simple Loan collateral below the configured deposit minimum before creating the loan:

AssetMinimum collateral amount
BTC5_100n sats
ETH5_000_000_000_000_000n wei (0.005 ETH)
ICP10_000n e8s
USDC1_000_000n base units
USDT1_000_000n base units

If your UI displays or pre-checks the same minimum, use getMinimumDepositAmount(asset).

Borrow minimums

The SDK enforces these minimum borrow amounts before creation:

AssetMinimum borrow amount
BTC5_100n sats
ETH5_000_000_000_000_000n wei (0.005 ETH)
USDC1_000_000n base units
USDT1_000_000n base units

If your UI displays or pre-checks the same minimum, use getMinimumBorrowAmount(asset).

ETH transfer rails

ETH pools expose native ETH targets under targets[Chain.ETH] and ckETH ICRC targets under targets[Chain.ICP]. Both routes use 18 decimals and amounts in wei. Native ETH transfers send value directly to the generated Ethereum address. ckETH transfers use the returned ICRC account.

Native ETH quotes use a 0.00025 ETH inflow-fee fallback when the live estimate fails or is non-positive. Repayment quotes expose inflowFeeEstimateAvailable: false when this fallback is used.

Restore a loan

Use the user-facing reference for refreshes, status pages, and support links:

const loan = await client.simpleLoans.get({ ref: savedReference });

Use the numeric loan ID when your backend stores it:

const loan = await client.simpleLoans.get({ loanId });

Use find(...) when the user might paste a short reference, numeric loan ID string, address, or transaction ID:

const results = await client.simpleLoans.find(addressOrTxidOrRef);

When its argument is a string, find(...) queries the SDK API search index and returns lightweight matches without hydrating every loan. It supports short references, numeric canister loan ID strings, generated deposit or repayment addresses, borrow or refund destination addresses, and indexed transaction IDs. After the user selects a match, use get({ ref }) or get({ loanId }).

Response fields

Most UIs need these fields after create(...) or get(...):

FieldDescription
loan.refShort reference to save and show the user
loan.statusShared LiquidiumStatus with operation, state, confirmations, and requiredConfirmations
loan.terms.ltvMaxBpsMaximum LTV selected at creation
loan.terms.depositWindowSecondsDeposit timeout selected at creation
loan.collateral.decimalsDecimal scale for collateral display
loan.borrow.decimalsDecimal scale for borrow, debt, and repayment display
loan.initialDeposit.collateralAmountIntended credited collateral target used for LTV
loan.initialDeposit.decimalsDecimal scale for initial deposit amounts
loan.initialDeposit.targets[chain]Fee-inclusive amount, inflow fee, and target for an available collateral transfer rail
loan.repayment.debtAmountCurrent debt before transfer fees
loan.repayment.targets[chain]Fee-inclusive repayment amount, fee metadata, and target for an available repayment rail

Target maps are partial. A missing chain entry means that transfer rail is unavailable, not that no debt exists. Check loan.repayment.debtAmount > 0n or the selected quote's amount > 0n before prompting for repayment.

client.simpleLoans.find(...) returns lightweight indexed fields, including loanId, ref, profileId, createdAt, collateral, and borrow. To load the full loan fields for a selected match, use client.simpleLoans.get(...). If you need active or completed flow activity, use client.activities.list(...) separately.

Diagnostic data

Diagnostic warmed-profile queries support both authorization types. client.simpleLoans.listWarmedProfiles() returns authorization.type as "EthSignature" for legacy profiles or "IcpCaller" for native IC caller profiles. "EthSignature" is deprecated for profile creation but remains supported for compatibility. Event queries can also return deprecated "ProfileWarmed" events or native "IcpProfileWarmed" events.

For loan.status, activity status, confirmation fields, and top-up handling, see the status system.