USDC deposit amount for a vault on Polygon, and let Trails figure out how to route funds from the user’s current chain and token into that final deposit.
This walkthrough assumes:
- your app owns the full mobile or web UI
- Sequence Embedded Wallet is your authentication and signing layer
- Trails is your routing and settlement layer
- your backend decides which vault or lending market to target
- the user may fund the deposit from a different supported token or chain
This guide focuses on a practical v1 implementation:
- one destination market or vault
USDCas the destination deposit assetPolygonas the destination chain- a user-initiated deposit flow
- Create your Builder project and collect keys
- Install dependencies
- Initialize Sequence Embedded Wallet
- Read the user’s balances
- Define and encode the destination deposit call
- Quote and commit the Trails intent
- Fund the intent from the embedded wallet
- Execute the intent and wait for the receipt
1. Create your Builder project and collect keys
First, create or open a Sequence Builder project and configure Embedded Wallet for your app. You will need:- a
PROJECT_ACCESS_KEY - a
WAAS_CONFIG_KEY - a
TRAILS_API_KEY
2. Install dependencies
Install the Sequence WaaS SDK, Trails API SDK, andviem for calldata encoding.
Keep your
TRAILS_API_KEY on the backend. Your client should call your backend for quote, commit, execute, and receipt polling.3. Initialize Sequence Embedded Wallet
Initialize the Sequence WaaS SDK and authenticate the user.[lib/sequence.ts]
- social
idToken - guest wallet
4. Read the user’s balances
Before you can construct a useful deposit quote, you need to know which token and chain the user will fund from. Use the Sequence indexer to fetch the user’s balances:[server/getBalances.ts]
- show the user supported balances
- let them choose a source token and chain
- pass
originChainId,originTokenAddress, and the desired deposit amount into your quote request
5. Define and encode the destination deposit call
For a white-labeled flow, your backend should decide which target contract is valid for deposits. For example, you might support a single ERC-4626 vault and store:chainIdvaultAddressdepositTokenAddress- protocol display name
- ABI fragment required for deposit
viem:
[server/encodeVaultDeposit.ts]
earn docs use the pool’s supply(asset, amount, onBehalfOf, referralCode) method.
This walkthrough uses a fixed destination amount. The user chooses how much
USDC should arrive at the destination vault on Polygon, and Trails computes how much source liquidity is required.Even with that simplified setup, Trails is still doing the important work in this architecture:- expressing the deposit as an intent
- routing user funds from the origin chain and token to the final destination
- executing the destination contract call
- returning a receipt model your app can track
6. Quote and commit the Trails intent
Once you know the owner address, source token, amount, and target vault call, your backend can request a Trails quote.[server/trails.ts]
- a vault on
Polygon USDCas the destination token- an exact amount of
USDCto deposit
- how much source liquidity is required
- whether a swap is needed
- whether a bridge is needed
- how to settle the final contract call on the destination chain
7. Fund the intent from the embedded wallet
Trails returns adepositTransaction on the quoted intent. That is the transaction your user must fund from their embedded wallet.
Read the funding information from the intent:
sendERC20:
[client/fundIntent.ts]
depositTransactionHash.
This is the point where the Trails-powered flow becomes visible to the user: they can fund a deposit from the origin asset returned by the quote, while your app still guarantees the final deposit lands in the target
Polygon vault as USDC.8. Execute the intent and wait for the receipt
Once the funding transaction has been submitted, execute the Trails intent on your backend:[server/executeIntent.ts]
- show pending and completed states
- link to the origin and destination transactions
- reconcile deposits in your backend
- surface support information if execution fails
Suggested API shape
If you want this to feel like a product-level yield API inside your app, create a thin backend layer on top of Sequence and Trails. Recommended endpoints:POST /yield/quotePOST /yield/commitPOST /yield/executeGET /yield/receipt/:intentIdGET /yield/opportunitiesGET /yield/positions
- supported vault metadata
- calldata encoding
- Trails API access
- receipt monitoring
- APY and earnings data
- route construction
- bridge and swap orchestration
- destination execution
- completion tracking
Testnet path
Before wiring a production vault, it is useful to validate the full intent lifecycle on testnet. The safest way to do that is:- query Trails for supported chains
- filter for testnets
- fetch supported tokens for the selected testnet
- swap the production addresses in this guide for testnet addresses
[server/getTestnetChains.ts]
[server/getTestnetTokens.ts]
- a testnet
originChainId - a supported testnet source token
- a testnet destination token
- a testnet vault or lending market address
supply(...) and withdraw(...) methods.
For Morpho, do not assume there is a public official testnet vault you can target. Morpho vaults are permissionless and you can deploy your own ERC-4626-style test vault, but the public Morpho vault documentation and addresses pages do not provide a general official testnet vault catalog in the same way you might expect for mainnet integrations.
Keep the integration model exactly the same on testnet:
- quote the Trails intent
- fund the returned deposit transaction
- execute the intent
- wait for the receipt
- an Aave V3 testnet market with published addresses
- your own test ERC-4626 vault
Withdrawals
For a first release, keep withdrawals as a two-stage flow:- call the vault’s
withdraw(...)orredeem(...)method directly from the user’s Sequence wallet - if needed, create a second Trails intent to move the withdrawn funds into another token or chain
supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode)withdraw(address asset, uint256 amount, address to)
- deposit with a Trails destination call to
supply(...) - withdraw directly with the user’s wallet by calling
withdraw(...)
Positions and earnings backend design
Once deposits are live, your backend needs to answer product questions such as:- how much has the user deposited
- what is their current position value
- what is the current APY
- how much has the user earned
1. Execution history
Use Trails for transaction lifecycle data:GetIntentGetIntentReceiptWaitIntentReceiptGetIntentHistory
- which deposits were initiated
- whether they completed
- which chains and tokens were involved
- the final execution receipts
2. Live position state
Use protocol reads or protocol data services for current position state:- ERC-4626 share balances and conversion helpers
- Aave aToken balances and reserve data
- protocol APIs or subgraphs where available
- current underlying balance
- current share balance
- realized and unrealized earnings
- current APY or rate inputs
protocolvaultAddressdepositAssetshareTokendestinationChainIdlatestPrincipallatestPositionValuelatestApylastSyncedAt
- reads completed Trails intents for the wallet
- groups them by supported vault
- fetches live protocol state
- computes current value and earnings
- caches the result for your app
APY and earnings
Trails gives you the routing and execution layer. For a white-labeled app, you should plan to own the APY and earnings layer yourself. Typical sources are:- protocol contract reads
- protocol APIs or subgraphs
- your own indexer or cache
- current APY display
- earnings summaries
- in-app badges like “earning”
- which opportunities are available in your product