Liquidity
Add Liquidity
Deposit the borrow asset into the pool directly and receive LP shares
POST
/
lending-external-securities-v2
/
api
/
positions
/
{marketId}
/
add-liquidity
curl -X POST "https://api.trusset.org/lending-external-securities-v2/api/positions/{marketId}/add-liquidity" \
-H "X-API-Key: trusset_your_key_here" \
-H "Content-Type: application/json" \
-d '{"amount": "250000", "provider": "0x2b6ed29a95753c3ad948348e3e7b1a251080ffb9"}'
const url = `https://api.trusset.org/lending-external-securities-v2/api/positions/${marketId}/add-liquidity`;
const headers = {
'X-API-Key': 'trusset_your_key_here',
'Content-Type': 'application/json'
};
const res = await fetch(url, {
method: 'POST',
headers,
body: JSON.stringify({ amount: '250000', provider: await operatorWallet.getAddress() })
});
const { data } = await res.json();
const hashes: string[] = [];
for (const step of data.steps) {
const tx = await operatorWallet.sendTransaction(step.transaction);
await tx.wait();
hashes.push(tx.hash);
}
await fetch(url, {
method: 'POST',
headers,
body: JSON.stringify({ amount: '250000', txHash: hashes[data.confirmStepIndex] })
});
{
"success": true,
"data": {
"action": "SIGN_TRANSACTIONS",
"steps": [
{
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x98ad0ca091552e23c564b41c74282e5343d03e8a",
"data": "0x...",
"value": "0",
"chainId": 11155111
},
"functionName": "approve",
"description": "Approve the market to pull USDC"
},
{
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x70a0e25c7b768b87e658348b3b577678a173e038",
"data": "0x...",
"value": "0",
"chainId": 11155111
},
"functionName": "addLiquidity"
}
],
"confirmStepIndex": 1,
"confirmWith": {
"endpoint": "POST /lending-external-securities-v2/api/positions/cmssh7p1k0001cghxq2m4v8rz/add-liquidity",
"field": "txHash"
}
}
}
{
"success": true,
"data": {
"txHash": "0x9f2c41d8b7e05a3164c2870fbd935e1a4c7802db6135ea9048f7c21b5d3ea41b",
"amount": "250000.0"
}
}
{
"success": false,
"error": {
"code": "LIQUIDITY_VAULT_ONLY",
"message": "This market takes deposits only from its operator wallet (0x2b6ed29a95753c3ad948348e3e7b1a251080ffb9) and from the vaults its admin registered, so a deposit from 0x5ad87a0621175206b72d10e4b8577b192e7f40ab would revert. Deposit through one of the operator's connected vaults instead."
}
}
{
"success": false,
"error": {
"code": "BELOW_MIN_DEPOSIT",
"message": "The first deposit into a market must be at least 1000.0 USDC (1000000000 of its smallest unit at 6 decimals)."
}
}
Deposits the market’s borrow asset into the lending pool directly. The depositor receives LP shares at the current share price, and those shares accrue value as borrowers pay interest.
Two transactions are required: an ERC-20 approval for exactly the amount, then the deposit. Both come back as ordered steps.
A deposit that reached the market through another contract, such as a multisig wallet, confirms from the market’s
Who can deposit directly
On current markets only two kinds of address can calladdLiquidity: the market’s operator wallet and the vaults the market admin registered. The operator wallet starts as the wallet that took the lender-of-record role and moves only through Rotate Operator Wallet. Read it as operatorWallet on Get Market Metrics, where vaultOnlyLiquidity: true marks a market under this rule.
Every other liquidity provider funds the market through one of the operator’s vaults, with Deposit or Deposit to Vault. The vault checks the depositor against its own register and the provider register of each market it funds. A direct deposit from any other wallet reverts on-chain, so the API refuses it first with LIQUIDITY_VAULT_ONLY.
No liquidity can be added to a MARKET-priced market until its borrower register qualifies as a professional gate: at least one verification profile admits wallets to it, and every profile that does, on any instance of the market’s network and environment, is limited to professional clients and has its admissions signed by its own instance. Until then a deposit is refused with 409 PROFESSIONAL_BORROWER_GATE_REQUIRED, also from the operator wallet. The check runs after the depositor checks, and the market contract does not apply it. See Professional borrowers.
A market still running an implementation from before this rule answers with its own gate instead. LIQUIDITY_OPERATOR_ONLY means it takes liquidity only from its lender of record and the providers it admitted. IDENTITY_REGISTRY_REQUIRED means it is open to third parties but has no provider register yet. IDENTITY_NOT_VERIFIED means the wallet is not verified on the register the market checks, and ELIGIBILITY_REMOVAL_PENDING that its admission to that register is waiting for removal.
Path Parameters
string
required
Body Parameters
string
Amount to deposit as a positive decimal string, for example
"250000". Denominated in the market’s borrow asset and parsed at its decimals. Required when building calldata. The confirm call needs only txHash: the recorded amount comes from the mined transaction, and an amount sent alongside is validated but not used.string
Wallet that will sign the deposit. Required when building calldata on a current market: without it the deposit cannot be checked against the operator wallet and the registered vaults, and the call returns
PROVIDER_REQUIRED. On a market running an earlier implementation it is optional, and supplying it runs that market’s own gate before a transaction is offered. When supplied, the API also checks that the wallet holds amount of the borrow asset, and refuses with INSUFFICIENT_BALANCE when it holds less. Not needed on the confirm call, where the provider is taken from the mined transaction.string
Hash of the transaction you broadcast for this operation. Send it to confirm the transaction and record the result. Omit it to receive the calldata.
Response Fields
object
Show child attributes
Show child attributes
string
SIGN_TRANSACTIONS when txHash is omitted.array
Ordered transactions to broadcast. Returned when
txHash is omitted. The first approves the market to pull exactly amount of the borrow asset, the second calls addLiquidity.integer
Index of the step to confirm with. Always
1.object
{ endpoint, field }: this route, with txHash as the field. Returned when txHash is omitted.string
Deposit transaction hash. Returned when confirming with
txHash.string
Amount actually deposited, read from the
LiquidityAdded event rather than from the request. Returned when confirming with txHash.First-deposit minimum
The first deposit into an empty pool must be at least 1,000 whole units of the borrow asset, for example 1,000 USDC. Current markets expose the figure asminInitialDeposit(). A market first deployed before per-asset scaling existed applies 1,000,000,000 smallest units, which is 1,000 of a 6-decimal asset.
The same floor applies to the deposit that recapitalises a pool whose value bad debt has fully consumed. It is a dust floor on the first share issue. Later deposits have no minimum beyond the token’s own precision.
The minimum is checked when the calldata is built, not when you confirm. Broadcasting an undersized first deposit reverts on-chain rather than returning
BELOW_MIN_DEPOSIT. totalShares on Get Market Metrics reads 0.0 on an empty pool.Depositors receive shares at the current share price, which already includes accrued interest. Depositing does not dilute existing providers.
curl -X POST "https://api.trusset.org/lending-external-securities-v2/api/positions/{marketId}/add-liquidity" \
-H "X-API-Key: trusset_your_key_here" \
-H "Content-Type: application/json" \
-d '{"amount": "250000", "provider": "0x2b6ed29a95753c3ad948348e3e7b1a251080ffb9"}'
const url = `https://api.trusset.org/lending-external-securities-v2/api/positions/${marketId}/add-liquidity`;
const headers = {
'X-API-Key': 'trusset_your_key_here',
'Content-Type': 'application/json'
};
const res = await fetch(url, {
method: 'POST',
headers,
body: JSON.stringify({ amount: '250000', provider: await operatorWallet.getAddress() })
});
const { data } = await res.json();
const hashes: string[] = [];
for (const step of data.steps) {
const tx = await operatorWallet.sendTransaction(step.transaction);
await tx.wait();
hashes.push(tx.hash);
}
await fetch(url, {
method: 'POST',
headers,
body: JSON.stringify({ amount: '250000', txHash: hashes[data.confirmStepIndex] })
});
{
"success": true,
"data": {
"action": "SIGN_TRANSACTIONS",
"steps": [
{
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x98ad0ca091552e23c564b41c74282e5343d03e8a",
"data": "0x...",
"value": "0",
"chainId": 11155111
},
"functionName": "approve",
"description": "Approve the market to pull USDC"
},
{
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x70a0e25c7b768b87e658348b3b577678a173e038",
"data": "0x...",
"value": "0",
"chainId": 11155111
},
"functionName": "addLiquidity"
}
],
"confirmStepIndex": 1,
"confirmWith": {
"endpoint": "POST /lending-external-securities-v2/api/positions/cmssh7p1k0001cghxq2m4v8rz/add-liquidity",
"field": "txHash"
}
}
}
{
"success": true,
"data": {
"txHash": "0x9f2c41d8b7e05a3164c2870fbd935e1a4c7802db6135ea9048f7c21b5d3ea41b",
"amount": "250000.0"
}
}
{
"success": false,
"error": {
"code": "LIQUIDITY_VAULT_ONLY",
"message": "This market takes deposits only from its operator wallet (0x2b6ed29a95753c3ad948348e3e7b1a251080ffb9) and from the vaults its admin registered, so a deposit from 0x5ad87a0621175206b72d10e4b8577b192e7f40ab would revert. Deposit through one of the operator's connected vaults instead."
}
}
{
"success": false,
"error": {
"code": "BELOW_MIN_DEPOSIT",
"message": "The first deposit into a market must be at least 1000.0 USDC (1000000000 of its smallest unit at 6 decimals)."
}
}
Error Codes
| Code | HTTP | Cause |
|---|---|---|
NO_MARKET_ADDRESS | 400 | The market has no on-chain address recorded |
MISSING_MARKET_ID | 400 | marketId is longer than 100 characters |
VALIDATION_ERROR | 400 | amount is missing without txHash, is not a positive decimal string or carries more decimal places than the borrow asset supports, or provider or txHash is malformed |
BELOW_MIN_DEPOSIT | 400 | This is the first deposit into an empty or fully consumed pool and it is under the floor |
MARKET_PAUSED | 400 | The market is paused. Its admin must unpause it |
PROVIDER_REQUIRED | 400 | provider was omitted on a market that takes direct deposits only from its operator wallet and registered vaults |
INSUFFICIENT_BALANCE | 400 | provider holds less of the borrow asset than amount, so the deposit would revert after the approval. details carries payer, balance and required. Skipped when the balance cannot be read |
IDENTITY_NOT_VERIFIED | 400 | Earlier implementations only. provider is not verified on the register the market checks. On the single-register implementation details carries register, requiredProfile and accessList, and the message names the verification profile or whitelist behind the register when there is one |
IDENTITY_GATE_RETIRED | 409 | Earlier implementations only. Returned instead of IDENTITY_NOT_VERIFIED when the register that refuses provider is the previous Trusset ID Register, which takes no new identities. details carries register, gate, retired: true and currentRegistry. gate is identity on the single-register implementation, where the admin first moves the market on with Upgrade Market, and provider on a market that reads its provider register itself. The admin then installs the current register with Set Identity Gates |
LIQUIDITY_VAULT_ONLY | 403 | provider is neither the operator wallet nor a registered vault. Deposit through one of the operator’s vaults |
LIQUIDITY_OPERATOR_ONLY | 403 | Earlier implementations only. The market takes liquidity only from its lender of record and the providers it admitted |
MARKET_NOT_FOUND | 404 | No market with this ID on your instance |
MARKET_PENDING_CURATOR | 409 | The market has no lender of record yet. See Lender of record |
IDENTITY_REGISTRY_REQUIRED | 409 | Earlier implementations only. The pool is open to third parties but carries no provider register yet |
ELIGIBILITY_REMOVAL_PENDING | 409 | Earlier implementations only. provider is verified on the register the market checks, but its admission is waiting for removal, so no new liquidity is prepared for it. details carries register and wallet |
PROFESSIONAL_BORROWER_GATE_REQUIRED | 409 | The market is MARKET-priced and its borrower register does not qualify as a professional gate. details.field is borrowerRegistry |
MARKET_STATE_UNAVAILABLE | 503 | The market could not be read to check the first-deposit minimum, whether it is paused, who may deposit, or its price source and borrower register. Retry shortly |
STATE_UNAVAILABLE | 503 | The verification profiles behind a MARKET market’s borrower register, or the pending removals on the register that checks provider, could not be read. Retry shortly |
LiquidityAdded event in the receipt. Confirming with txHash can also return any transaction verification error.⌘I
curl -X POST "https://api.trusset.org/lending-external-securities-v2/api/positions/{marketId}/add-liquidity" \
-H "X-API-Key: trusset_your_key_here" \
-H "Content-Type: application/json" \
-d '{"amount": "250000", "provider": "0x2b6ed29a95753c3ad948348e3e7b1a251080ffb9"}'
const url = `https://api.trusset.org/lending-external-securities-v2/api/positions/${marketId}/add-liquidity`;
const headers = {
'X-API-Key': 'trusset_your_key_here',
'Content-Type': 'application/json'
};
const res = await fetch(url, {
method: 'POST',
headers,
body: JSON.stringify({ amount: '250000', provider: await operatorWallet.getAddress() })
});
const { data } = await res.json();
const hashes: string[] = [];
for (const step of data.steps) {
const tx = await operatorWallet.sendTransaction(step.transaction);
await tx.wait();
hashes.push(tx.hash);
}
await fetch(url, {
method: 'POST',
headers,
body: JSON.stringify({ amount: '250000', txHash: hashes[data.confirmStepIndex] })
});
{
"success": true,
"data": {
"action": "SIGN_TRANSACTIONS",
"steps": [
{
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x98ad0ca091552e23c564b41c74282e5343d03e8a",
"data": "0x...",
"value": "0",
"chainId": 11155111
},
"functionName": "approve",
"description": "Approve the market to pull USDC"
},
{
"action": "SIGN_TRANSACTION",
"transaction": {
"to": "0x70a0e25c7b768b87e658348b3b577678a173e038",
"data": "0x...",
"value": "0",
"chainId": 11155111
},
"functionName": "addLiquidity"
}
],
"confirmStepIndex": 1,
"confirmWith": {
"endpoint": "POST /lending-external-securities-v2/api/positions/cmssh7p1k0001cghxq2m4v8rz/add-liquidity",
"field": "txHash"
}
}
}
{
"success": true,
"data": {
"txHash": "0x9f2c41d8b7e05a3164c2870fbd935e1a4c7802db6135ea9048f7c21b5d3ea41b",
"amount": "250000.0"
}
}
{
"success": false,
"error": {
"code": "LIQUIDITY_VAULT_ONLY",
"message": "This market takes deposits only from its operator wallet (0x2b6ed29a95753c3ad948348e3e7b1a251080ffb9) and from the vaults its admin registered, so a deposit from 0x5ad87a0621175206b72d10e4b8577b192e7f40ab would revert. Deposit through one of the operator's connected vaults instead."
}
}
{
"success": false,
"error": {
"code": "BELOW_MIN_DEPOSIT",
"message": "The first deposit into a market must be at least 1000.0 USDC (1000000000 of its smallest unit at 6 decimals)."
}
}
