Skip to Content

Action Lifecycle

This section covers how prepared transactions flow from agent to chain in sdk-agent, and how sdk-agentkit handles execution automatically. The lifecycle differs between the two packages.


Lifecycle overview

Agent
Tool call
Validate
Prepared tx
App layer
Receive
Preview
Dispatch
Chain
Submit
Confirm
Tx hash

The agent never signs in sdk-agent: it produces a PreparedTx, the app layer dispatches it through the underlying SDK, and the chain returns a tx hash that flows back to the user, and, ideally, back to the agent as a tool message.


sdk-agent: prepared transactions, dispatched by your app

sdk-agent does not sign anything. Every prepare_* tool returns one of two shapes:

type PreparedTx = { valid: true; action: 'sdk_execute'; method: string; // dispatch key, e.g. "evm.btcbToLbtc" params: Record<string, unknown>; description: string; // human-readable summary }; type ValidationFailure = { valid: false; missing: string[]; // params the agent must still collect errors: string[]; note: string; // suggested next step for the LLM };

Your app layer (frontend, backend, wallet runner) is responsible for dispatching method against @lombard.finance/sdk and surfacing the resulting tx hash back to the user.


Method dispatch table

method@lombard.finance/sdk call
btc.generateLbtcDepositAddresschain.btc.stake({ assetOut: LBTC, destChain }).prepare(...).authorize().generateDepositAddress() (mints LBTC)
btc.generateBtcbDepositAddresschain.btc.deposit({ assetOut: BTCb, destChain }).prepare(...).authorizeFee().generateDepositAddress() (mints BTC.b)
evm.btcbToLbtcdepositToken({ tokenIn: BTCb, tokenOut: LBTC, ... })
evm.lbtcToBtcunstakeLBTC(...) (cross-chain LBTC → native BTC)
evm.lbtcToBtcbredeemToken({ tokenIn: LBTC, tokenOut: BTCb }) (same-chain LBTC → BTC.b)
evm.btcbToBtcredeemToken({ tokenIn: BTCb, btcAddress, ... })
evm.earnDepositdepositEarn({ token: LBTC, ... })
evm.earnWithdrawalBitcoin Earn withdrawal request
evm.cancelEarnWithdrawalCancel an active Bitcoin Earn withdrawal
evm.claimLbtcDepositclaimLBTC({ data, ... })
morpho.supplyCollateralMulti-tx batch: approval + supplyCollateral against the Morpho Blue market.
morpho.borrowMulti-tx batch: borrow loan asset against the supplied LBTC collateral.
morpho.repayMulti-tx batch: approval + repay of the borrowed loan asset.

Return-shape note

The BTC and Morpho prepare_* tools return shapes that differ from the EVM PreparedTx above.

BTC preps (prepare_btc_to_lbtc_deposit, prepare_btc_to_btcb_deposit) omit the valid: true discriminator and return { action, method, params, description }.

Morpho preps additionally wrap a transactions[] array (rather than a single params) and include a top-level marketId.

Branch on r.method rather than relying solely on r.valid when routing to the underlying SDK.


Minimal dispatch pattern

1

Stream the agent with Lombard tools

Wire lombardTools and LOMBARD_SYSTEM_PROMPT into your existing agent loop. onStepFinish fires on every tool result.

const result = streamText({ model: yourModel, system: LOMBARD_SYSTEM_PROMPT, tools: lombardTools, messages, onStepFinish: async ({ toolResults }) => { for (const { result: r } of toolResults) { if (r?.action !== 'sdk_execute') continue; // route on r.method } }, });
2

Branch on method and dispatch

Use the method dispatch table above to route each r.method to the matching @lombard.finance/sdk call.

if (r.method === 'evm.btcbToLbtc') { await depositToken({ ...r.params, tokenIn: Token.BTCb, tokenOut: Token.LBTC, account, chainId, provider, env, }); } else if (r.method === 'evm.lbtcToBtc') { await unstakeLBTC({ ...r.params, account, chainId, provider, env }); } else if (r.method === 'evm.earnDeposit') { await depositEarn({ ...r.params, token: Token.LBTC, account, chainId, provider, env }); } // ...handle the other methods from the table above
3

Preview before signing in the browser

In a browser app this dispatch usually lives in a TransactionPrompt-style component that previews description and only runs after explicit user confirmation.

Full reference implementation: apps/example-agent-chat in the SDK repo.


sdk-agentkit: automatic execution

The lifecycle is internal. lombardActionProvider handles approval checks, fee authorization, and the underlying SDK call inside each action. Your agent code gets back the transaction hash directly.


Status flows agents should poll

get_deposit_status (native BTC → LBTC or BTC.b)
sentconfirmednotarizedclaimable
get_redemption_status (LBTC unstake or BTC.b redemption)
queuedprocessingcompleted

For full lifecycle state machines, see Action Lifecycle in the SDK concepts.

Last updated on