LST / LRT mint · withdraw-request · claim · cancel
GET/v1/actions/vaults/lst
Build calldata for LST / LRT (and Lagoon) actions — mint, withdraw-request, claim, and cancel — via the unified LST dispatchers. The protocol is resolved from the calldata-sdk registry by (chainId, shareToken), or forced with kind= (required for Lagoon — kind=lagoon&mode=sync|async — and any unregistered vault).
Deposits also work through the unified /v1/actions/vaults/deposit — pass the LST share token as
vaultand it routes here automatically (no need to know it's an LST). This endpoint stays as the explicit LST route and is the home for the exit-side actions (request-withdraw/claim/cancel), which the generic deposit endpoint does not cover.
How an integrator knows what to pay with (acceptedInputs)
LSTs are not uniform ERC-4626 vaults — each protocol accepts a different set of pay assets (native ETH, an unwrapped sibling like stETH/eETH, or specific ERC-20s) and some paths require extra slippage/intermediate options. Rather than hard-coding this, fetch the vault data first and let it drive the request:
GET /v1/data/vaults?chainId=…&providers=lst→ each LST carries aproviderMetablock:isMintable—false⇒ no on-chain mint (e.g. cbETH); don't call this endpoint.mintContract— the deposit target.exchangeRate/convertToShares— to compute expected output and aminOut.acceptedInputs[]— the machine-readable accept-set (see below).
- Pick the
acceptedInputsentry whoseassetmatches what the user holds. - Call this endpoint with
action=deposit,payAsset=<that asset>, and the entry'sneeds[]supplied as query params.
acceptedInputs[] entry shape
| field | meaning |
|---|---|
asset | "native" (pay with the chain coin → pass payAsset=0x000…000) or a lowercased ERC-20 address to pass as payAsset. |
symbol | optional UI hint (e.g. stETH). |
mode | direct (single call) · wrap (approve + wrap a base LST the user already holds) · submit-wrap (native → base → wrapped; needs the realised base amount). |
needs | option keys the caller must pass for this path (e.g. ["minMETHAmount"], ["eEthAmount"], ["stEthAmount"]). Absent ⇒ none. |
Example — wstETH advertises three paths:
"acceptedInputs": [
{ "asset": "native", "mode": "direct" },
{ "asset": "0xae7ab9…", "symbol": "stETH", "mode": "wrap" },
{ "asset": "native", "mode": "submit-wrap", "needs": ["stEthAmount"] }
]
- Pay with ETH →
payAsset=0x000…000(one-stepreceive()). - Pay with stETH you already hold →
payAsset=0xae7ab9…(approve + wrap).
Multi-step results
wrap / submit-wrap paths produce multiple ordered transactions. The response's actions.transactions[] is the sequence to execute in order, and actions.permissions[] carries any ERC-20 approvals to run first. Single-step mints return one transaction and (for native) no permissions. Always iterate transactions[]; never assume a single tx.
Slippage / required options
Paths whose needs includes a min-out (minMETHAmount, minRSETHAmountExpected, …) require the caller to compute the floor from the data's exchangeRate and pass it. Native one-step mints (stETH, ETHx, ezETH, ynETH, pufETH, wstETH-receive) need nothing beyond amount.
Actions
deposit— mint.amountrequired;payAsset(default native); path options peracceptedInputs[].needs.request-withdraw— start an exit (queue/cooldown).amountrequired;inputAsset?,outputAsset?,owner?.claim— settle a matured exit. Pass therequestId/v1/data/vaults/withdrawals returned, verbatim (id,requestIdsCSV andtokenIdare accepted as the same handle). The route maps it onto the protocol's own argument. You can also pass that argument by name:unlockIndex(BENQI, Sceptre, Kintsu),idx(Stader MaticX, Lista),index(Renzo, wBETH),withdrawalIdx(Puffer),unstakeRequestId(Mantle),burnId(Valantis),recordId(dualCORE),tokenIds(ether.fi),withdrawIds(Beets),indexes(asBNB cancel), and so on. BENQI sAVAX with no id buildsredeem(), which claims every request inside its 2-day window. Several BENQI ids run highest-first, because the contract swap-and-pops.cancel— cancel a pending request (same identifier params).
Plain-text reference — GET /v1/actions/vaults/lst
Parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
chainId | query | string | yes | Chain ID See the ChainId schema for the full set of supported chains. |
action | query | deposit, request-withdraw, claim, cancel | no | Operation to build. |
shareToken | query | string | yes | LST share-token address (the token the user wants to mint / exit). |
operator | query | string | yes | User wallet executing the action (payer). receiver defaults to it. |
receiver | query | string | no | Recipient of the minted shares / claimed assets. Defaults to operator. |
amount | query | string | no | Required for deposit and request-withdraw. Wei, in the payAsset decimals. |
payAsset | query | string | no | deposit: what the user pays. Zero address (or 0xEEEE…) = native; otherwise an ERC-20 from the LST's acceptedInputs[].asset. Defaults to native. |
kind | query | string | no | Protocol override — required for Lagoon (lagoon) and any vault not in the static registry. Otherwise resolved from (chainId, shareToken). |
mode | query | sync, async | no | Lagoon deposit mode. |
minOut | query | integer | no | Generic slippage floor (wei) where the protocol path accepts one. For protocol-specific names see the LST acceptedInputs[].needs. |
referral | query | string | no | Optional referral address (protocols that support it). |
stEthAmount | query | integer | no | wstETH submit-wrap path: the realised stETH amount (read stETH.balanceOf after the submit leg). |
eEthAmount | query | integer | no | weETH submit-wrap path: the realised eETH amount (read after the deposit leg). |
vault | query | string | no | StakeWise per-vault target (and other per-vault protocols). |
poolId | query | string | no | Solv pool selector. |
validatorGroup | query | string | no | StakedCelo (stCELO) deposit: validator group to vote for — a changeStrategy(group) step is prepended (account-wide). Auto-selected when omitted and the caller is on the (reverting) default strategy; zero address forces the default. |
rewardVault | query | string | no | BeraPaw reward-vault target. |
stakingToken | query | string | no | Bearn staking-token target. |
inputAsset | query | string | no | request-withdraw: asset being burned, when the protocol needs it disambiguated. |
outputAsset | query | string | no | request-withdraw / claim: desired exit asset, when the protocol supports a choice. |
owner | query | string | no | request-withdraw: position owner, when not operator. |
requestIds | query | string | no | claim/cancel: CSV of withdrawal-request ids. |
hints | query | string | no | claim/cancel: CSV of finalization hints (Lido). |
amounts | query | string | no | claim/cancel: CSV of per-request amounts. |
tokenId | query | integer | no | claim/cancel: NFT request id. |
id | query | integer | no | claim/cancel: numeric request id. |
requestId | query | string | no | claim/cancel: the requestId from /v1/data/vaults/withdrawals, passed back verbatim (an integer, or a composite like <asset>:<nonce> for Kelp and <validator>:<nonce> for TruFin). Mapped onto the protocol's own argument. |
unlockIndex | query | integer | no | claim/cancel: BENQI / Sceptre / Kintsu unlock index (the position in the user's request list). |
idx | query | integer | no | claim: Stader MaticX / Lista request position. |
index | query | integer | no | claim: Renzo / wBETH request position. |
withdrawIds | query | string | no | claim: CSV of Beets global withdraw ids (SonicStaking.userWithdraws(user, i)). |
tokenIds | query | string | no | claim: CSV of ether.fi withdraw NFT ids. |
indexes | query | string | no | cancel: CSV of asBNB queued-mint indexes. |
shares | query | integer | no | claim: share amount (7540/4626 savings). |
assets | query | integer | no | claim: asset amount. |
controller | query | string | no | claim: 7540 controller, when not receiver. |
user | query | string | no | claim/cancel: position user, when not operator. |
recipient | query | string | no | claim: payout recipient, when supported. |
Response 200
| Field | Type | Description |
|---|---|---|
success | True | |
data | object | Informational data (quotes, simulation results, etc.) |
actions | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). |
actions.transactions | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. |
actions.transactions[].chainType | evm | Which VM executes this step. ABSENT means evm, which is the only value any endpoint returns today — every EVM response is unchanged. A non-EVM chain would return a different shape (a serialized, PERISHABLE transaction rather than to/data/value) carrying its own chainType, so a client that wants to stay forward-compatible should branch on this field rather than assume to is present. |
actions.transactions[].to | string | Target contract address |
actions.transactions[].data | string | Encoded calldata |
actions.transactions[].value | string | ETH value to send with the transaction |
actions.transactions[].description | string | Human-readable label. For alternatives, this is the aggregator name (e.g. "Paraswap"). For transactions, describes the setup action (e.g. "Switch e-mode to 1"). |
actions.alternatives | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's description is the aggregator name. The client should pick one to execute. Present on loop action endpoints. |
actions.alternatives[].chainType | evm | Which VM executes this step. ABSENT means evm, which is the only value any endpoint returns today — every EVM response is unchanged. A non-EVM chain would return a different shape (a serialized, PERISHABLE transaction rather than to/data/value) carrying its own chainType, so a client that wants to stay forward-compatible should branch on this field rather than assume to is present. |
actions.alternatives[].to | string | Target contract address |
actions.alternatives[].data | string | Encoded calldata |
actions.alternatives[].value | string | ETH value to send with the transaction |
actions.alternatives[].description | string | Human-readable label. For alternatives, this is the aggregator name (e.g. "Paraswap"). For transactions, describes the setup action (e.g. "Switch e-mode to 1"). |
actions.permissions | object[] | Approval/delegation transactions that must execute before both transactions and alternatives. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. |
actions.permissions[].to | string | Target contract address |
actions.permissions[].data | string | Encoded calldata |
actions.permissions[].value | string | ETH value |
actions.permissions[].description | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") |
actions.permissions[].spender | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's approvalTarget — several bridges can share one spender, so do not match by description. |
actions.permissions[].type | ERC20, Lender | What kind of grant this is. A signatures[] offer names the type it replaces via its replaces field. |
actions.signatures | object[] | EIP-712 payloads the user can sign INSTEAD of sending the corresponding permissions entry. Only present when the caller opted in with permit=auto|required and a permit path exists. Sign with eth_signTypedData_v4, then POST the same endpoint with {permits: [{permitId, signature}]} (plus builds where the response issued buildIds) — the permit executes inside the main transaction. |
actions.signatures[].permitId | string | Opaque, self-describing handle for this permit. Round-trip it verbatim: POST {permits: [{permitId, signature}]} back to the same endpoint. |
actions.signatures[].kind | erc2612, dai, permit2, aaveCredit, morphoAuth, cometAuth | Permit flavour |
actions.signatures[].typedData | object | Ready for eth_signTypedData_v4 (domain, types incl. EIP712Domain, primaryType, message). All numeric fields are decimal strings. |
actions.signatures[].replaces | string | Which permissions entry this signature replaces (ERC20 | Lender) |
actions.signatures[].spender | string | Who the signature authorises. Match against the permission / quote (approvalTarget) it replaces — on multi-spender responses (x-chain) only routes whose approvalTarget equals this spender are covered by the signature. |
actions.signatures[].description | string | Human-readable label for this entry. |
actions.signatures[].unscoped | boolean | True when the grant is NOT amount-scoped (full position control until revoked) — surface this to the user. |
actions.signatures[].deadline | string | Unix seconds after which the signature is worthless (default: 30 minutes). |
actions.signs | object[] | Messages that MUST be signed before anything can be sent (unlike signatures, which are optional permit offers). When non-empty, transactions and alternatives are EMPTY: sign typedData with eth_signTypedData_v4 (or, for format: personal_sign, message with personal_sign), then call submit with the signature under submit.signatureField, and execute what that answers. permissions may still be present and can be sent before or after signing. Produced by Inverse FiRM loops (/loop/leverage, /loop/close), Morpho Midnight make, Term order-sign and the Lista leg of /rewards/claim. |
actions.signs[].purpose | authorize-action, publish-order, authenticate | authorize-action: the signature authorises an on-chain action and submit answers its transaction (Inverse ALE loops). publish-order: the signature makes an off-chain order and submit publishes it (Midnight make, Term order-sign). authenticate: the signature is a LOGIN to a third-party API that serves the data the transaction needs (Lista reward proofs); it authorises nothing on-chain. |
actions.signs[].format | eip712, personal_sign | eip712: sign typedData with eth_signTypedData_v4. personal_sign: sign the UTF-8 message with personal_sign. |
actions.signs[].typedData | object | format: eip712 only. Ready for eth_signTypedData_v4. All numeric fields are decimal strings. |
actions.signs[].message | string | format: personal_sign only. The exact text to sign; send it back verbatim (it is part of submit.params). |
actions.signs[].signer | string | The address that must sign. The server recovers the signer and refuses any other. |
actions.signs[].deadline | string | Unix seconds after which the signature is worthless. |
actions.signs[].spender | string | Who the signature authorises. |
actions.signs[].description | string | Human-readable label for this entry. |
Example response
{
"success": true,
"data": {},
"actions": {
"transactions": [
{
"chainType": "evm",
"to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
"data": "0x617ba037000000000000000000000000c02aaa39b2",
"value": "0",
"description": "string"
}
],
"alternatives": [
{
"chainType": "evm",
"to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
"data": "0x617ba037000000000000000000000000c02aaa39b2",
"value": "0",
"description": "string"
}
],
"permissions": [
{
"to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"data": "0x617ba037000000000000000000000000c02aaa39b2",
"value": "0",
"description": "string",
"spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"type": "ERC20"
}
],
"signatures": [
{
"permitId": "string",
"kind": "erc2612",
"typedData": {},
"replaces": "string",
"spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"description": "string",
"unscoped": true,
"deadline": "string"
}
],
"signs": [
{
"purpose": "authorize-action",
"format": "eip712",
"typedData": {},
"message": "string",
"signer": "string",
"deadline": "string",
"spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"description": "string",
"submit": {
"method": "GET",
"endpoint": "string",
"params": {},
"body": {},
"signatureField": "string"
}
}
],
"permitSkipped": [
{
"replaces": "string",
"reason": "string"
}
]
}
}
Request
Responses
- 200
- 400
- 429
- 500
- 502
Ordered transactions[] (execute in sequence) + ERC-20 permissions[] (execute first). Single-step mints return one transaction.
Validation error
Rate limited. Unauthenticated callers share a per-IP budget; send an x-api-key header to lift it. Retry with exponential backoff.
Unexpected server error. Safe to retry with backoff.
An upstream data source or protocol origin failed (error.code is ORIGIN_FAILED). error.details carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400.