Skip to main content
The vault destinations walkthrough covers the primary recipe: a predetermined destination-token amount funding a native-value call. This page covers what varies from it.
Read deposit into vault destinations first. Every example here assumes that six-step flow and changes only the posthook. The full hooks.postHook field reference is there too.
Jump to your case:

Source token approvals

Source token approvals and destination call funding are two different mechanisms. Do not conflate them. Source token approval is a wallet action on the source chain. For an ERC-20 source asset, the route response can include route.execution.approvals[], each entry carrying the tokenAddress, spender, and amount to approve before the route transaction can succeed. The spender is a provider contract, never a Trustware one. sendRouteTransaction handles these on EVM routes: it reads the current allowance, approves the exact amount when one is missing, waits for confirmation, then requests the route signature. It never grants an unlimited allowance. If the allowance read fails, it approves anyway rather than sending a transaction it knows would revert. Two consequences for your UI:
  • The user can see more than one wallet prompt. Tell them an approval may come first, then the deposit itself.
  • Each approval must confirm on chain before the route signature is requested, so the call can stay pending for a minute or more.
If you sign yourself, through the REST API or a custom signer, implement the same sequence: read route.execution.approvals[], grant each allowance, wait for confirmation, then send route.execution.transaction. Every field is optional, so skip any entry missing a spender, tokenAddress, or non-zero amount. Destination call funding is toApprovalAddress, covered next. It is not a wallet prompt.

ERC-20 destination calls

If your destination function pulls tokens with transferFrom instead of taking native value, set toApprovalAddress to the address allowed to pull fundToken. That is normally the contract performing the transferFrom, usually the vault itself.
depositFor is illustrative. Substitute your own pull-based deposit function and ABI. Note there is no value field. The call is funded with an ERC-20, so nothing native is attached. How the allowance is granted depends on the provider that resolves the route. Some prepend an ERC-20 approve() ahead of your call, patching the approval amount alongside your call’s amount when fullAmount is set. Others hand it to their own execution engine. You set the same field either way.
Do not set toApprovalAddress for native-value destination calls. Native assets need no allowance, and the API rejects a request that pairs toApprovalAddress with a native fundToken.

Amount patching

In this mode, the amount argument in your calldata is patched for you.
How it is patched is provider dependent. Some providers patch it at execution time with the amount received. For others, Trustware patches it before building the route, with a quoted toAmountMin, or toAmount when no minimum is quoted.
Set fullAmount: true and use amountInputPos to say which ABI argument holds the amount.
amountInputPos is the zero-based index of the ABI argument to patch. In depositFor(address recipient, address token, uint256 amount) the amount is the third argument, so it is 2. Index 0 is valid, so do not treat a falsy index as unset. The argument must be a static type such as uint256. Patching a dynamic argument such as bytes corrupts the encoding. Do not send fundAmount in this mode. buildRoute rejects the request before it is sent if fullAmount is true and amountInputPos is missing.

Fallback behavior

toFallbackAddress names an address that receives the funds if the destination call fails.
toFallbackAddress is provider dependent. It is forwarded to the provider that resolves the route and implemented there. Not every provider offers an equivalent, so never treat fallback as a guarantee or build a recovery flow that assumes it applies.
There is no destination-call status field, so the route status alone will not tell you whether a fallback ran. Read your destination contract, and the fallback address balance to distinguish the two outcomes.

Deposit-address routes

Trustware.buildDepositAddress() accepts the same hooks.postHook shape as buildRoute. Use it when the source funds arrive by plain payment to an address rather than from a wallet you can prompt.
Deposit-address routing is provider dependent, and so are deposit-address routes with a posthook. This path needs a provider that supports both, so it is not available on every route.
Client-side posthook validation is identical on both calls. buildDepositAddress() takes the same request body as buildRoute() and returns a deposit address instead of a signable transaction.

Call other destination contracts

Nothing about hooks.postHook is vault specific. It executes an arbitrary encoded call, so the same pattern covers staking contracts, margin accounts, lending pools, and anything else you control. Only the ABI and the function you encode change. Two questions decide which sections apply to you:
  • Does your function accept native value or pull an ERC-20? Native value uses value. An ERC-20 pull uses toApprovalAddress and no value.
  • Do you know the amount in advance? If yes, use a predetermined fundAmount. If not, use amount patching.

Errors and failure handling

buildRoute and buildDepositAddress reject a structurally incomplete posthook before sending. These four are thrown as a plain Error with no code, so instanceof TrustwareError and error.code branching do not apply. To run the same checks before building a route, for example in form validation, call assertValidPostHook({ postHook }). It throws the same errors and requires @trustware/sdk 1.1.11 or later. fullAmount and amountInputPos are provider dependent, as covered in amount patching. These checks only confirm completeness. The API is authoritative for what the client cannot check: calldata correctness, destination compatibility, and provider eligibility. A rejected posthook returns 400 with a message describing the problem. Two more plain Error cases come from the approval step inside sendRouteTransaction: Approval transaction reverted and Timed out waiting for approval confirmation. Treat both as recoverable and let the user retry.
Everything else follows the normal error handling patterns.

Deposit into vault destinations

The six-step walkthrough, the hooks.postHook field reference, and the complete example.

Headless core

The full Trustware namespace API, including buildRoute, sendRouteTransaction, and pollStatus.

POST /route

The REST request and response schema, including hooks.postHook and route.execution.approvals.

Error handling

Posthook validation errors, approval failures, and the imperative try/catch pattern.