This guide covers integration with the LOAN lending protocol on XPR Network.
LOAN is the native lending protocol on XPR Network enabling:
- Supply assets to earn interest - Deposit tokens, receive L-tokens (shares)
- Collateralized loans - Borrow against supplied collateral
- Variable interest rates - Supply/demand-based APY
- Liquidations - Automated health factor monitoring
- LOAN token rewards - Earn LOAN governance tokens on supply/borrow
- Governance - LOAN token holders govern protocol
| Contract | Description |
|---|---|
lending.loan |
Main lending/borrowing/redeem logic |
shares.loan |
L-token share receipts (LXPR, LUSDC, etc.) |
loan.token |
LOAN governance token |
oracles |
Price feeds for collateral |
⚠️ Important: The main contract islending.loan, NOTlending. Using the wrong contract will cause transactions to fail.
When you supply assets, you receive L-tokens representing your share of the pool:
| Supplied | L-Token Received | Precision | Token Contract |
|---|---|---|---|
| XPR | LXPR | 4 | shares.loan |
| XUSDC | LUSDC | 6 | shares.loan |
| XBTC | LBTC | 8 | shares.loan |
| XETH | LETH | 8 | shares.loan |
| XMD | LXMD | 6 | shares.loan |
| XUSDT | LUSDT | 6 | shares.loan |
| XMT (METAL) | LXMT | 8 | shares.loan |
| XRP | LXRP | 6 | shares.loan |
| DOGE | LDOGE | 6 | shares.loan |
| HBAR | LHBAR | 6 | shares.loan |
| ADA | LADA | 6 | shares.loan |
| XLM | LXLM | 6 | shares.loan |
| LTC | LLTC | 8 | shares.loan |
| SOL | LSOL | 6 | shares.loan |
L-token values increase over time as interest accrues, so you get back more than you deposited.
Health factor measures loan safety:
Health Factor = (Collateral Value × Liquidation Threshold) / Debt Value
| Health Factor | Status |
|---|---|
| > 1.5 | Safe |
| 1.0 - 1.5 | Warning |
| < 1.0 | Liquidatable |
Maximum borrowing power as percentage of collateral:
| Asset | Collateral Factor |
|---|---|
| XPR | 40% |
| XUSDC | 80% |
| XBTC | 70% |
| XETH | 70% |
| XMD | 90% |
| XMT (Metal) | 50% |
| XDOGE | 60% |
| XADA | 60% |
| XLTC | 60% |
| XSOL | 60% |
| XXLM | 60% |
| XXRP | 60% |
| XHBAR | 60% |
Before supplying, you must enter the markets for the assets you want to use:
# Enter XPR and XUSDC markets
proton action lending.loan entermarkets '{"payer":"myaccount","user":"myaccount","markets":["LXPR","LUSDC"]}' myaccountTransfer tokens to lending.loan with memo mint:
# Supply 40000 XPR
proton action eosio.token transfer '{"from":"myaccount","to":"lending.loan","quantity":"40000.0000 XPR","memo":"mint"}' myaccount
# Supply 100 XUSDC
proton action xtokens transfer '{"from":"myaccount","to":"lending.loan","quantity":"100.000000 XUSDC","memo":"mint"}' myaccountasync function supply(
session: any,
quantity: string,
tokenContract: string // 'eosio.token' for XPR, 'xtokens' for wrapped tokens
): Promise<any> {
return session.transact({
actions: [{
account: tokenContract,
name: 'transfer',
authorization: [session.auth],
data: {
from: session.auth.actor,
to: 'lending.loan',
quantity: quantity,
memo: 'mint'
}
}]
}, { broadcast: true });
}
// Example: Supply 1000 XUSDC
await supply(session, '1000.000000 XUSDC', 'xtokens');
// Example: Supply 10000 XPR
await supply(session, '10000.0000 XPR', 'eosio.token');Note: The
mintmemo triggers L-token minting. Your L-token shares appear in thelending.loansharestable scoped tolending.loan.
# Check your L-token shares
curl -s -X POST https://proton.eosusa.io/v1/chain/get_table_rows \
-H 'Content-Type: application/json' \
-d '{"code":"lending.loan","scope":"lending.loan","table":"shares","lower_bound":"myaccount","upper_bound":"myaccount","limit":1,"json":true}'Response format:
{
"rows": [{
"account": "myaccount",
"tokens": [
{
"key": {"sym": "4,LXPR", "contract": "shares.loan"},
"value": 390334875
},
{
"key": {"sym": "6,LUSDC", "contract": "shares.loan"},
"value": 71479562
}
]
}]
}The value field is the raw integer. Divide by 10^precision to get the human-readable amount:
- LXPR value
390334875with precision 4 =39033.4875 LXPR - LUSDC value
71479562with precision 6 =71.479562 LUSDC
To remove assets from your entered markets (e.g., when you no longer want them used as collateral):
# Exit XPR and XUSDC markets
proton action lending.loan exitmarkets '{"user":"myaccount","markets":["LXPR","LUSDC"]}' myaccountasync function exitMarkets(
session: any,
markets: string[] // e.g. ['LXPR', 'LUSDC']
): Promise<any> {
return session.transact({
actions: [{
account: 'lending.loan',
name: 'exitmarkets',
authorization: [session.auth],
data: {
user: session.auth.actor,
markets: markets
}
}]
}, { broadcast: true });
}Note: You cannot exit a market if you have outstanding borrows against that collateral.
The redeem action burns your L-tokens and returns the underlying asset plus accrued interest.
The action takes an extended_asset parameter:
# Redeem all LXPR shares back to XPR
proton action lending.loan redeem '{"redeemer":"myaccount","token":{"quantity":"39033.4875 LXPR","contract":"shares.loan"}}' myaccount
# Redeem all LUSDC shares back to XUSDC
proton action lending.loan redeem '{"redeemer":"myaccount","token":{"quantity":"71.479562 LUSDC","contract":"shares.loan"}}' myaccountasync function redeem(
session: any,
quantity: string, // e.g. "39033.4875 LXPR"
): Promise<any> {
return session.transact({
actions: [{
account: 'lending.loan',
name: 'redeem',
authorization: [session.auth],
data: {
redeemer: session.auth.actor,
token: {
quantity: quantity,
contract: 'shares.loan'
}
}
}]
}, { broadcast: true });
}
// Example: Redeem all LXPR
await redeem(session, '39033.4875 LXPR');
⚠️ Precision matters! LXPR uses precision 4 (e.g.,39033.4875), LUSDC uses precision 6 (e.g.,71.479562). Using wrong precision will fail.
The redeem action will:
- Burn your L-tokens via
shares.loanretireaction - Issue LOAN reward tokens
- Transfer the underlying asset back to you (e.g., XPR via
eosio.token)
async function borrow(
session: any,
quantity: string,
tokenContract: string // 'eosio.token' for XPR, 'xtokens' for wrapped tokens
): Promise<any> {
const position = await getUserPosition(session.auth.actor);
if (position && position.health_factor < 1.2) {
throw new Error('Health factor too low to borrow');
}
return session.transact({
actions: [{
account: 'lending.loan',
name: 'borrow',
authorization: [session.auth],
data: {
borrower: session.auth.actor,
underlying: {
quantity: quantity,
contract: tokenContract
},
use_stable_rate: false
}
}]
}, { broadcast: true });
}# Borrow 500 XPR against collateral
proton action lending.loan borrow '{"borrower":"myaccount","underlying":{"quantity":"500.0000 XPR","contract":"eosio.token"},"use_stable_rate":false}' myaccountTransfer tokens back with repay memo:
# Repay 500 XUSDC
proton action xtokens transfer '{"from":"myaccount","to":"lending.loan","quantity":"500.000000 XUSDC","memo":"repay"}' myaccount
# Repay 1000 XPR
proton action eosio.token transfer '{"from":"myaccount","to":"lending.loan","quantity":"1000.0000 XPR","memo":"repay"}' myaccountLOAN tokens are distributed as rewards for supplying and borrowing:
proton action lending.loan claimrewards '{"claimer":"myaccount","markets":["LXPR","LUSDC"]}' myaccountNote: Use the L-token symbol_code format (e.g.,
LXPRnot4,LXPR) for the markets parameter. You can only claim for markets you have active positions in.
async function getUserShares(account: string): Promise<any> {
const response = await fetch('https://proton.eosusa.io/v1/chain/get_table_rows', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
code: 'lending.loan',
scope: 'lending.loan',
table: 'shares',
lower_bound: account,
upper_bound: account,
limit: 1,
json: true
})
});
const { rows } = await response.json();
return rows[0] ?? null;
}async function getMarkets(): Promise<any[]> {
const response = await fetch('https://proton.eosusa.io/v1/chain/get_table_rows', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
code: 'lending.loan',
scope: 'lending.loan',
table: 'markets',
limit: 100,
json: true
})
});
const { rows } = await response.json();
return rows;
}async function getLiquidatableBorrows(): Promise<any[]> {
const response = await fetch('https://proton.eosusa.io/v1/chain/get_table_rows', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
code: 'lending.loan',
scope: 'lending.loan',
table: 'borrows',
limit: 1000,
json: true
})
});
const { rows } = await response.json();
return rows.filter((p: any) => p.health_factor < 1.0);
}# Liquidate an underwater position
proton action xtokens transfer '{"from":"myaccount","to":"lending.loan","quantity":"500.000000 XUSDC","memo":"liquidate:targetaccount:XPR"}' myaccount| Collateral | Liquidation Bonus |
|---|---|
| XPR | 10% |
| XUSDC | 5% |
| XBTC | 10% |
| XETH | 10% |
| Property | Value |
|---|---|
| Contract | loan.token |
| Symbol | LOAN |
| Precision | 4 |
| Max Supply | 100,000,000 LOAN |
Note: LOAN staking may not be active on mainnet. The
loan.stakingcontract does not appear to exist as of March 2026. Check on-chain before attempting staking operations.
# XPR price (feed index 3)
curl -s -X POST https://proton.eosusa.io/v1/chain/get_table_rows \
-H 'Content-Type: application/json' \
-d '{"code":"oracles","scope":"oracles","table":"data","lower_bound":3,"upper_bound":3,"limit":1,"json":true}'Known oracle feed indices:
| Index | Asset |
|---|---|
| 3 | XPR/USD |
| 4 | BTC/USD |
| 5 | USDC/USD |
| 6 | MTL/USD (XMT) |
| 7 | ETH/USD |
| 8 | DOGE/USD |
| 9 | USDT/USD |
| 16 | LTC/USD |
| 18 | XRP/USD |
| 19 | SOL/USD |
| 21 | HBAR/USD |
| 22 | ADA/USD |
| 23 | XLM/USD |
The LOAN protocol has a whitelist (updatewl action) that controls which accounts can interact. However, as of February 2026, the mint (supply) action appears to work for accounts not on the whitelist. The whitelist may only restrict certain operations like borrowing.
To check the whitelist:
curl -s -X POST https://proton.eosusa.io/v1/chain/get_table_rows \
-H 'Content-Type: application/json' \
-d '{"code":"lending.loan","scope":"lending.loan","table":"whitelist","limit":100,"json":true}'# Enter markets (required before first supply)
proton action lending.loan entermarkets '{"payer":"alice","user":"alice","markets":["LXPR","LUSDC"]}' alice
# Exit markets (remove collateral eligibility)
proton action lending.loan exitmarkets '{"user":"alice","markets":["LXPR","LUSDC"]}' alice
# Supply XPR (mint L-tokens)
proton action eosio.token transfer '{"from":"alice","to":"lending.loan","quantity":"1000.0000 XPR","memo":"mint"}' alice
# Supply XUSDC (mint L-tokens)
proton action xtokens transfer '{"from":"alice","to":"lending.loan","quantity":"100.000000 XUSDC","memo":"mint"}' alice
# Redeem LXPR back to XPR
proton action lending.loan redeem '{"redeemer":"alice","token":{"quantity":"975.1234 LXPR","contract":"shares.loan"}}' alice
# Redeem LUSDC back to XUSDC
proton action lending.loan redeem '{"redeemer":"alice","token":{"quantity":"71.479562 LUSDC","contract":"shares.loan"}}' alice
# Borrow
proton action lending.loan borrow '{"borrower":"alice","underlying":{"quantity":"500.0000 XPR","contract":"eosio.token"},"use_stable_rate":false}' alice
# Repay
proton action xtokens transfer '{"from":"alice","to":"lending.loan","quantity":"500.000000 XUSDC","memo":"repay"}' alice
# Claim LOAN rewards
proton action lending.loan claimrewards '{"claimer":"alice","markets":["LXPR","LUSDC"]}' alice
# Check shares
# Use RPC: code=lending.loan, scope=lending.loan, table=shares, lower_bound=alice, upper_bound=alice| Contract | Table | Scope | Description |
|---|---|---|---|
lending.loan |
shares |
lending.loan |
User L-token share balances |
lending.loan |
markets |
lending.loan |
Market stats, APYs, reserve ratios |
lending.loan |
borrows |
lending.loan |
User borrow positions, health factors |
lending.loan |
whitelist |
lending.loan |
Whitelisted accounts |
loan.token |
(standard token tables) | LOAN governance token | |
oracles |
data |
oracles |
Price feeds |
Use these endpoints for querying tables (in order of reliability):
https://proton.eosusa.io(recommended)https://proton.protonuk.iohttps://proton.cryptolions.io
- Contract is
lending.loan— notlending - Share tokens live on
shares.loan— not in your token balance - Memo
mintfor deposits, memorepayfor loan repayment - Redeem uses
extended_assetformat:{"quantity":"X LXPR","contract":"shares.loan"} - Precision must match exactly — LXPR=4, LUSDC=6, LBTC=8, etc.
- Enter markets first before supplying or borrowing
- LOAN rewards are issued during redeem and can also be claimed separately