Handle errors
Validate input before you call a state-changing method. Catch SDK errors at the boundary where your app can show a user-facing message or retry.
Validate the LTV result
Check the loan-to-value (LTV) result before you create a loan:
const ltv = client.quote.calculateLtv(request, pools, prices);
if (ltv.validationErrors.length > 0) {
return {
ok: false,
message: ltv.validationErrors.map((error) => error.message).join(" "),
};
}
Handle SDK errors
Catch exported SDK errors before you handle unknown errors:
import {
LiquidiumError,
LiquidiumErrorCode,
SimpleLoanCreatedError,
} from "@liquidium/client";
try {
const loan = await client.simpleLoans.create(request);
return loan;
} catch (error) {
if (error instanceof SimpleLoanCreatedError) {
return client.simpleLoans.get({ loanId: error.loanId });
}
if (error instanceof LiquidiumError) {
if (error.code === LiquidiumErrorCode.REQUEST_TIMEOUT) {
// Show retry copy or use the app's retry path.
}
throw error;
}
throw error;
}
If your UI needs different messages for timeout, transport, validation, or protocol failures, use the exported LiquidiumErrorCode values.
SimpleLoanCreatedError means the remote loan was created but response hydration failed. Recover with the error's loanId or ref through client.simpleLoans.get(...). Do not call create(...) again because that can create a duplicate loan.
Wallet-executed deposit, borrow, and withdraw amounts below SDK minimums throw or return validation errors before state-changing calls. To show the minimum next to an amount input, use getMinimumDepositAmount(asset), getMinimumBorrowAmount(asset), or getMinimumWithdrawAmount(asset). Manual deposit-address flows do not accept an amount, so callers must apply the deposit minimum before broadcasting.
Decide when to retry
Use the error type and the operation type before you retry:
| Condition | Action |
|---|---|
Read-only request fails with NETWORK_ERROR, SERVICE_UNAVAILABLE, or REQUEST_TIMEOUT | Retry with your app's bounded backoff policy |
| State-changing request times out | Reload the related loan, activity, position, or history before you decide whether to submit another request |
Request fails with VALIDATION_ERROR or a protocol error | Correct the input or wait for the protocol state to change before you retry |
SimpleLoanCreatedError is thrown | Recover with client.simpleLoans.get(...); do not create another loan |
The SDK does not define an application retry interval. Do not automatically repeat a state-changing method because an error might have occurred after the remote operation succeeded.
Validate destinations
Lending outflow and Simple Loan destinations are validated against the selected asset and delivery chain:
| Asset path | Chain | Accepted destination family |
|---|---|---|
| BTC L1 | "BTC" | Bitcoin mainnet chain address |
| Native ETH | "ETH" | Ethereum address |
| ETH L1 USDC/USDT | "ETH" | Ethereum address |
| ICP native | "ICP" | IC principal, ICRC account, or ICP account identifier |
| ckBTC, ckETH, ckUSDC, ckUSDT | "ICP" | IC principal |
Lending uses chain and receiver. Simple Loans use borrow.chain, borrow.destination, refund.chain, and refund.destination. Prefer typed destination objects when the account family matters.
For lending, native ETH borrow and withdrawal destinations use a best-effort deployed-bytecode check. The SDK rejects a destination only when the check succeeds and confirms deployed bytecode. This includes smart contract wallets.
The SDK throws LiquidiumError with code LiquidiumErrorCode.INVALID_ADDRESS for malformed or reserved Ethereum addresses. It uses LiquidiumErrorCode.CONTRACT_DESTINATION_UNSUPPORTED when the best-effort check confirms that a native ETH lending destination has deployed bytecode. The Simple Loans API reports deployed-contract destination rejections as SDK API errors. Asset, chain, or destination-family mismatches use LiquidiumErrorCode.VALIDATION_ERROR. Catch these errors at the form boundary before retrying the flow.
When chain.id identifies Ethereum mainnet, lending queries the configured Ethereum Virtual Machine (EVM) client's getCode method. If the configured EVM client does not provide both chain.id and getCode, the SDK queries the Liquidium SDK API. RPC failures, API failures, and malformed responses do not block the outflow.
The SDK also validates the sender account for wallet-executed native ETH and ERC-20 supply as an EVM address. Deposit-address queries validate that the requested asset matches the selected ETH pool and reject malformed addresses returned by the deposit canister.