Atomic Sale
Sell Pending Liquidation
Sell an open router record to the sale recipient at its standing bid and settle it in one transaction
POST
/
lending-external-securities-v2
/
api
/
liquidations
/
liquidation
/
{liquidationId}
/
sell
curl -X POST "https://api.trusset.org/lending-external-securities-v2/api/liquidations/liquidation/14/sell" \
-H "X-API-Key: trusset_your_key_here" \
-H "Content-Type: application/json" \
-d '{"marketId": "cmuvtwr29002ds2mft47ye2yl"}'
const url = 'https://api.trusset.org/lending-external-securities-v2/api/liquidations/liquidation/14/sell';
const headers = { 'X-API-Key': 'trusset_your_key_here', 'Content-Type': 'application/json' };
const res = await fetch(url, { method: 'POST', headers, body: JSON.stringify({ marketId }) });
const { success, data, error } = await res.json();
if (!success) throw new Error(`${error.code}: ${error.message}`);
const tx = await operatorWallet.sendTransaction(data.transaction);
await tx.wait();
const confirmed = await fetch(url, {
method: 'POST',
headers,
body: JSON.stringify({ ...data.confirmWith.body, txHash: tx.hash })
});
const { data: sale } = await confirmed.json();
{
"success": true,
"data": {
"success": true,
"liquidationId": "14",
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x067a3feea46649adad8e31c33b3a4d8774b8d8cf",
"data": "0x...",
"chainId": 11155111,
"value": "0"
},
"functionName": "sellPending",
"description": "Sell the collateral of liquidation 14 to the sale recipient at its standing bid and settle the record in the same transaction",
"requiredRole": "OPERATOR_ROLE",
"signer": "0x1234f9a07c6b53d81e2a4f70c9b385d6014a7e52",
"routerAddress": "0x067a3feea46649adad8e31c33b3a4d8774b8d8cf",
"buyer": "0x5a72e0b41d3f8c62079ae4b1d38f0c95261ba473",
"expectedPayment": { "amount": "21560.0", "raw": "21560000000" },
"collateralAmount": "220.0",
"collateralAmountRaw": "220000000000000000000",
"price": { "amount": "100.0", "raw": "100000000" },
"priceFactor": { "priceFactorBps": 9800, "priceFactorE18": "980000000000000000" },
"settlementAsset": {
"address": "0x98ad0ca091552e23c564b41c74282e5343d03e8a",
"symbol": "USDC",
"decimals": 6
},
"confirmWith": {
"endpoint": "POST /lending-external-securities-v2/api/liquidations/liquidation/14/sell",
"field": "txHash",
"body": { "txHash": null, "marketId": "cmuvtwr29002ds2mft47ye2yl" }
}
}
}
{
"success": false,
"error": {
"code": "ATOMIC_BUYER_UNAVAILABLE",
"message": "The sale recipient 0x5a72e0b41d3f8c62079ae4b1d38f0c95261ba473 allows the router to take 5000.0 USDC, short of the 21560.0 USDC this sale costs, so the payment fails. It raises its allowance to the router.",
"txHash": null,
"details": {
"reasonCode": "ALLOWANCE_SHORT",
"saleRecipient": "0x5a72e0b41d3f8c62079ae4b1d38f0c95261ba473",
"expectedPayment": { "amount": "21560.0", "raw": "21560000000" }
}
}
}
Builds the router’s
The confirmed response:
The sale is written to the audit log as
Confirming with
sellPending call. It sells all the collateral of an open liquidation record to the sale recipient at its standing bid, and settles the record in the same transaction. Send the hash back to record the sale. It is the atomic sale for a record that is already on the router: one seized in two-step mode, or the remainder of an expired auction. A holder of the router’s OPERATOR_ROLE signs.
The sale is priced at the oracle price times the bid. The payment goes through the market’s settlement waterfall like any settlement. It repays the pool, draws on the insurance fund for a shortfall, and returns any surplus to the borrower. The record is recorded as SETTLED with realization: ATOMIC and the sale recipient as buyer.
When a sale is refused
The atomic sale is offered only on a market priced from a live market price (MARKET) whose lender of record declared EXCHANGE_SALE as its realization mode. Any other market is refused with 409 ATOMIC_SALE_UNAVAILABLE, details.reasonCode PRICE_SOURCE_NOT_MARKET or REALIZATION_PATH_NOT_EXCHANGE_SALE, and settles the two-step way through Withdraw Collateral for Sale and Settle Liquidation. When the price source, or the realization path a MARKET market declared, cannot be read, the call answers 503 MARKET_STATE_UNAVAILABLE.
The router sells only a whole record. Once any of its collateral left the router for sale, the record is refused with 409 COLLATERAL_ALREADY_OUT_FOR_SALE and settles the two-step way.
Before calldata is returned, the API checks that the sale recipient can buy this record. It needs a bid at or above the market’s floor that stays live for at least another 60 seconds, a fresh price, enough allowance and balance for the payment, room under the router’s sale rate limit, and a delivery the collateral token admits. The record’s borrower cannot be the sale recipient. A sale it cannot pay is refused with 409 ATOMIC_BUYER_UNAVAILABLE, details.reasonCode naming the gap and details.expectedPayment the amount. The transaction is then simulated from the signer, and a revert the router would raise is named the same way, with details.revert naming the contract error.
Path Parameters
string
required
Liquidation ID on the market’s router.
Body Parameters
string
The market whose liquidation you mean, as its record ID. Every market runs its own router and IDs restart at
1 on each. Supply it when the same ID exists on several of your markets, or the call is refused with AMBIGUOUS_LIQUIDATION_ID. Also accepted as a query parameter.string
The router operator that will sign. Omit it to check your instance’s primary verified wallet. A wallet without
OPERATOR_ROLE is refused with ROUTER_OPERATOR_ROLE_MISSING, and the error carries the calldata that grants it. Also accepted as a query parameter.string
Hash of the mined
sellPending transaction. Send it to confirm; the sale is read from the router’s AtomicSaleExecuted event and the market’s settlement. Omit it to receive the calldata.Response Fields
The calldata response:object
Show child attributes
Show child attributes
string
The router record.
string
SIGN_TRANSACTION.object
The
sellPending call on the router, { to, data, chainId, value }.string
sellPending.string
What the transaction does.
string
OPERATOR_ROLE.string
The wallet that holds it.
string
The router, lowercased.
string
The sale recipient that buys, lowercased.
object
{ amount, raw }: what the buyer pays at the current price and bid.string
The collateral sold, in collateral units.
collateralAmountRaw carries it in base units.object
{ amount, raw }: the oracle price the sale is priced at.object
{ priceFactorBps, priceFactorE18 }: the standing bid.object
{ address, symbol, decimals }.object
{ endpoint, field, body }: this route, txHash as the field, and a body carrying the record’s marketId.object
Show child attributes
Show child attributes
string
The router record.
string
The market’s record ID.
string
SETTLED.string
ATOMIC.string
What the market received, in borrow asset units.
string
The sale recipient that bought, lowercased.
string
What the buyer paid.
string
The oracle price the sale used.
string
The bid as a decimal factor, for example
0.98.string
The collateral sold, in collateral units.
object
{ returned, escrowed }: surplus paid to the borrower, or escrowed for it when the transfer failed.object
{ seizureCovered, settlementCovered, reimbursed }: what the insurance fund paid in and was paid back.object
The market’s settlement of the record:
marketLiquidationId, routerLiquidationId, proceedsReceived, routerProceeds, shortfall, debtApplied, writeOffRecovered, reserve ({ requested, covered, uncovered } or null) and reserveReimbursed.string
ISO 8601 block time of the sale.
string
The verified transaction.
string
The wallet that sent it.
LENDING_PENDING_SOLD_ATOMICALLY.
curl -X POST "https://api.trusset.org/lending-external-securities-v2/api/liquidations/liquidation/14/sell" \
-H "X-API-Key: trusset_your_key_here" \
-H "Content-Type: application/json" \
-d '{"marketId": "cmuvtwr29002ds2mft47ye2yl"}'
const url = 'https://api.trusset.org/lending-external-securities-v2/api/liquidations/liquidation/14/sell';
const headers = { 'X-API-Key': 'trusset_your_key_here', 'Content-Type': 'application/json' };
const res = await fetch(url, { method: 'POST', headers, body: JSON.stringify({ marketId }) });
const { success, data, error } = await res.json();
if (!success) throw new Error(`${error.code}: ${error.message}`);
const tx = await operatorWallet.sendTransaction(data.transaction);
await tx.wait();
const confirmed = await fetch(url, {
method: 'POST',
headers,
body: JSON.stringify({ ...data.confirmWith.body, txHash: tx.hash })
});
const { data: sale } = await confirmed.json();
{
"success": true,
"data": {
"success": true,
"liquidationId": "14",
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x067a3feea46649adad8e31c33b3a4d8774b8d8cf",
"data": "0x...",
"chainId": 11155111,
"value": "0"
},
"functionName": "sellPending",
"description": "Sell the collateral of liquidation 14 to the sale recipient at its standing bid and settle the record in the same transaction",
"requiredRole": "OPERATOR_ROLE",
"signer": "0x1234f9a07c6b53d81e2a4f70c9b385d6014a7e52",
"routerAddress": "0x067a3feea46649adad8e31c33b3a4d8774b8d8cf",
"buyer": "0x5a72e0b41d3f8c62079ae4b1d38f0c95261ba473",
"expectedPayment": { "amount": "21560.0", "raw": "21560000000" },
"collateralAmount": "220.0",
"collateralAmountRaw": "220000000000000000000",
"price": { "amount": "100.0", "raw": "100000000" },
"priceFactor": { "priceFactorBps": 9800, "priceFactorE18": "980000000000000000" },
"settlementAsset": {
"address": "0x98ad0ca091552e23c564b41c74282e5343d03e8a",
"symbol": "USDC",
"decimals": 6
},
"confirmWith": {
"endpoint": "POST /lending-external-securities-v2/api/liquidations/liquidation/14/sell",
"field": "txHash",
"body": { "txHash": null, "marketId": "cmuvtwr29002ds2mft47ye2yl" }
}
}
}
{
"success": false,
"error": {
"code": "ATOMIC_BUYER_UNAVAILABLE",
"message": "The sale recipient 0x5a72e0b41d3f8c62079ae4b1d38f0c95261ba473 allows the router to take 5000.0 USDC, short of the 21560.0 USDC this sale costs, so the payment fails. It raises its allowance to the router.",
"txHash": null,
"details": {
"reasonCode": "ALLOWANCE_SHORT",
"saleRecipient": "0x5a72e0b41d3f8c62079ae4b1d38f0c95261ba473",
"expectedPayment": { "amount": "21560.0", "raw": "21560000000" }
}
}
}
Error Codes
| Code | HTTP | Cause |
|---|---|---|
VALIDATION_ERROR | 400 | marketId is longer than 100 characters, or an address or hash is malformed |
AMBIGUOUS_LIQUIDATION_ID | 400 | This ID exists on more than one of your markets. The error carries candidates; resend with marketId |
ALREADY_SETTLED | 400 | The record is already settled or written off, here or on the router |
ROUTER_OPERATOR_ROLE_MISSING | 400 | The signer lacks OPERATOR_ROLE on the router. The error carries grant calldata. When the simulated sale is what the router refuses for the role, the same code answers 403 |
WALLET_NOT_CONFIGURED | 400 | No signerAddress was sent and your instance has no verified wallet |
TX_NOT_VERIFIED | 400 | The confirmed transaction sells a different liquidation, or carries no atomic sale of this one |
SELL_PENDING_FAILED | 400 | The sale could not be prepared or recorded and no more specific code applied |
LIQUIDATION_NOT_FOUND | 404 | No liquidation with that ID on your instance, or the router has none |
MARKET_NOT_FOUND | 404 | marketId names no market on your instance, or the market the record settles into could not be identified |
ATOMIC_SALE_UNAVAILABLE | 409 | The market is not MARKET-priced, or its realization mode is not EXCHANGE_SALE. details carries priceSource, realizationMode and reasonCode. Settle the two-step way |
ATOMIC_UNSUPPORTED | 409 | The router’s implementation predates the atomic sale. details carries routerAddress and routerUpgrade |
ATOMIC_BUYER_UNAVAILABLE | 409 | The sale recipient cannot buy this record. details carries reasonCode (NO_BID, BID_EXPIRED, SELF_PURCHASE, BID_BELOW_FLOOR, PRICE_STALE, RATE_LIMITED, ALLOWANCE_SHORT, BALANCE_SHORT or DELIVERY_REFUSED), saleRecipient and expectedPayment. When the simulation raised it, details carries revert and reasonCode instead |
COLLATERAL_ALREADY_OUT_FOR_SALE | 409 | Part or all of the record’s collateral already left the router for sale. Report the sale and settle the two-step way |
SALE_RECIPIENT_NOT_SET | 409 | The router has no sale recipient, so there is no buyer |
LIQUIDATION_ON_VENUE | 409 | The record’s Dutch auction is still open, so the router holds none of its collateral |
TX_WOULD_REVERT | 409 | The simulated sale reverts for a reason no other code covers. details.revert names it |
MARKET_STATE_UNAVAILABLE | 503 | The market’s price source, its declared realization path or its oracle could not be read. Nothing was signed. Retry shortly |
ROUTER_UNREADABLE | 503 | The router, the bid, the price or the buyer’s funds could not be read, or the sale could not be simulated. Retry shortly |
ROUTER_UNRESOLVED | 503 | The market’s liquidation router could not be read. Retry shortly |
ROLE_UNVERIFIABLE | 503 | The signer’s role on the router could not be read. Retry shortly |
txHash can also return any transaction verification error.⌘I
curl -X POST "https://api.trusset.org/lending-external-securities-v2/api/liquidations/liquidation/14/sell" \
-H "X-API-Key: trusset_your_key_here" \
-H "Content-Type: application/json" \
-d '{"marketId": "cmuvtwr29002ds2mft47ye2yl"}'
const url = 'https://api.trusset.org/lending-external-securities-v2/api/liquidations/liquidation/14/sell';
const headers = { 'X-API-Key': 'trusset_your_key_here', 'Content-Type': 'application/json' };
const res = await fetch(url, { method: 'POST', headers, body: JSON.stringify({ marketId }) });
const { success, data, error } = await res.json();
if (!success) throw new Error(`${error.code}: ${error.message}`);
const tx = await operatorWallet.sendTransaction(data.transaction);
await tx.wait();
const confirmed = await fetch(url, {
method: 'POST',
headers,
body: JSON.stringify({ ...data.confirmWith.body, txHash: tx.hash })
});
const { data: sale } = await confirmed.json();
{
"success": true,
"data": {
"success": true,
"liquidationId": "14",
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x067a3feea46649adad8e31c33b3a4d8774b8d8cf",
"data": "0x...",
"chainId": 11155111,
"value": "0"
},
"functionName": "sellPending",
"description": "Sell the collateral of liquidation 14 to the sale recipient at its standing bid and settle the record in the same transaction",
"requiredRole": "OPERATOR_ROLE",
"signer": "0x1234f9a07c6b53d81e2a4f70c9b385d6014a7e52",
"routerAddress": "0x067a3feea46649adad8e31c33b3a4d8774b8d8cf",
"buyer": "0x5a72e0b41d3f8c62079ae4b1d38f0c95261ba473",
"expectedPayment": { "amount": "21560.0", "raw": "21560000000" },
"collateralAmount": "220.0",
"collateralAmountRaw": "220000000000000000000",
"price": { "amount": "100.0", "raw": "100000000" },
"priceFactor": { "priceFactorBps": 9800, "priceFactorE18": "980000000000000000" },
"settlementAsset": {
"address": "0x98ad0ca091552e23c564b41c74282e5343d03e8a",
"symbol": "USDC",
"decimals": 6
},
"confirmWith": {
"endpoint": "POST /lending-external-securities-v2/api/liquidations/liquidation/14/sell",
"field": "txHash",
"body": { "txHash": null, "marketId": "cmuvtwr29002ds2mft47ye2yl" }
}
}
}
{
"success": false,
"error": {
"code": "ATOMIC_BUYER_UNAVAILABLE",
"message": "The sale recipient 0x5a72e0b41d3f8c62079ae4b1d38f0c95261ba473 allows the router to take 5000.0 USDC, short of the 21560.0 USDC this sale costs, so the payment fails. It raises its allowance to the router.",
"txHash": null,
"details": {
"reasonCode": "ALLOWANCE_SHORT",
"saleRecipient": "0x5a72e0b41d3f8c62079ae4b1d38f0c95261ba473",
"expectedPayment": { "amount": "21560.0", "raw": "21560000000" }
}
}
}
