Across

Across troubleshooting is diagnosing Fill Deadline Expiry and Refund Timing

Across troubleshooting is the process of separating an unfilled crosschain intent from its later automatic refund. Once the fillDeadline passes without any fill, the deposit moves to expired; it doesn't instantly become refunded. Across keeps the input tokens in the origin SpokePool, includes the expired deposit in bundle settlement, and returns the tokens to the configured refund address. Track both the deposit status and origin-chain refund transaction before treating the transfer as complete.

Expired Is Eligibility, Not Receipt

An Across deposit marked expired has crossed its fill deadline, yet its origin-chain refund still awaits bundle processing and execution.

The common mistake is reading expired as proof of payment. Across exposes four main lifecycle labels for this path, and each label answers a narrower question about the deposit:

V3 relay logic permits one complete fill and no partial fills, so an ordinary expired intent doesn't leave a partly delivered balance to reconcile. Confirm the origin transaction, record originChainId and depositId, and then inspect the status response for depositRefundTxnRef. A sound Across troubleshooting record therefore separates three timestamps: deposit confirmation, deadline expiry, and refund execution. Only the third identifies receipt, while the second merely admits the deposit into the settlement path.

What Does an Expired Transfer Cost?

An expired Across transfer returns the escrowed input tokens automatically, while the confirmed origin transaction's network gas remains spent afterward.

The quoted bridge fee belongs to a successful fill: inputAmount minus outputAmount. It covers relayer capital, destination gas, and liquidity-provider pricing. Expiry changes the path because nobody delivered output tokens. The automatic refund doesn't ask the wallet to sign a claim transaction; settlement execution handles that step. Still, the origin-chain deposit transaction remains final, so its gas charge won't reappear in the wallet.

Worked example: treat the route, token amount, timestamps, and wallet balances as hypothetical inputs: 250 USDC moves from Arbitrum, chain ID 42161, to Base, chain ID 8453; the deposit confirms at 12:00 UTC with a 17:00 UTC fillDeadline, and the post-deposit origin balance is 40 USDC. Five hours equal 18 000 seconds, which sits inside a 21 600-second buffer. If no fill occurs by 17:00 and the pure USDC bridge refunds 250 USDC, the origin balance becomes 290 USDC. The earlier gas payment doesn't return.

For a same-token bridge, reconcile the refund against inputAmount, not the quoted destination outputAmount. A Swap API route that includes swaps can name a separate refundToken, so read that token's address, chain ID, and decimals from the quote. This distinction prevents a correct return from looking short merely because the original delivery quote included relayer and LP fees.

The Two Deadlines Control Different Decisions

Across uses fillDeadline to close filling and exclusivityDeadline to end one relayer's priority, so confusing them produces false expiry diagnoses.

The fillDeadline is a Unix timestamp evaluated against destination-chain time. Relay data stores it in a uint32, a 32-bit unsigned field. Contract logic rejects a fill only after current time exceeds the deadline; equality remains on the permitted side. A one-second clock boundary therefore separates a fillable relay from an expired relay.

Ethereum and Optimism SpokePool deployments configure fillDeadlineBuffer at 21 600 seconds, or 6 hours, beyond the origin deposit timestamp. Those deployments also configure a 3 600-second, or 1-hour, depositQuoteTimeBuffer. Integrators should pass the API-returned deadline unchanged because stale local arithmetic can create InvalidFillDeadline or InvalidQuoteTimestamp reverts.

The same material is presented Across setup. The exclusivity clock doesn't shorten the fill window. A zero exclusivity parameter means open relaying from the start. The current SpokePool logic interprets a positive value of at most 31 536 000 seconds as an offset; larger values act as absolute timestamps. After exclusivity ends, another relayer still has the remaining fill window. Refund eligibility begins only after fillDeadline, not after the 1-year interpretation threshold.

Why Is the Refund Still Pending?

An Across refund remains pending because expiry only makes the deposit eligible; Dataworker bundling, optimistic verification, message transport, and execution follow (examined Across walkthrough ).

At that point, Across proposes settlement bundles to the HubPool about every 1.5 hours at minimum, before the optimistic challenge period begins. That cadence determines when the Dataworker can include an expired deposit; it doesn't cover verification, transport, or execution.

Before the Bundle

The pre-bundle interval determines when the expired deposit enters a Merkle root. It doesn't deliver tokens by itself.

Expiry Detection

The status indexer polls relevant events on a 10-second cadence and reports an average 1-to-15-second indexing delay. Query with one depositTxnRef, or use the two-field pair of originChainId and depositId. Polling faster than the indexer won't accelerate settlement; it only repeats the same state.

Bundle Inclusion

The Across Dataworker includes the expired deposit in the next settlement bundle and proposes the resulting roots on Ethereum. UMA's Optimistic Oracle then supplies the challenge window. The 1.5-hour proposal rhythm is the first timing anchor, not a complete refund estimate, because expiry can occur at any point inside that interval.

After the Bundle

After the challenge window closes, Across finalizes the bundle and transports the refund root to the relevant SpokePool through the chain's settlement path, including canonical bridges where applicable. On-chain execution then transfers the escrowed tokens and changes the API state to refunded. A dispute, transport delay, or unexecuted root extends the wait, which is why several hours remains the proper expectation even though bundles target a 90-minute rhythm.

Where Will the Refunded Tokens Arrive?

Later in the process, Across sends an expired transfer to refundAddress, which defaults to the depositor, and refundOnOrigin defaults to true in the Swap API.

The recipient on the destination chain doesn't determine the refund destination. For an origin refund, inspect the same chain that accepted the deposit and watch the configured refund address. An EVM address occupies 20 bytes and displays as 0x plus 40 hexadecimal digits, yet identical text doesn't prove identical contract control across chains. A smart-contract wallet deployed on Base may not exist at that address on Arbitrum, so the selected address must be controllable on the actual refund chain during settlement.

Token units matter during reconciliation. USDC uses 6 decimals, making 1 USDC equal to 1 000 000 base units, while WETH uses 18 decimals. Read the quote's refundToken rather than searching only for the intended destination asset. A returned input token can otherwise appear absent when the wallet interface hides an unlisted ERC-20 balance.

HyperCore withdrawals form a specific edge case. Their status query uses origin chain ID 1337, but refunds land on HyperEVM, whose chain ID is 999. The quote exposes that location through refundToken.chainId. Standard EVM routes such as Ethereum, chain ID 1, and Arbitrum, chain ID 42161, follow their configured origin-refund setting.

Current Events Prevent Legacy Tracking Errors

Where that applies, Across monitoring should follow FundsDeposited and FilledRelay, because older V3 event names and narrower identifiers cause missing or mismatched records.

The non-EVM and prefill migration took effect on January 23, 2025, and renamed four SpokePool events. V3FundsDeposited became FundsDeposited, while FilledV3Relay became FilledRelay; the speed-up and slow-fill events changed in the same release. Replacement events encode addresses as bytes32 and widen depositId from uint32 to uint256. A parser that still expects 32-bit identifiers can truncate newer records before refund tracking starts.

The API avoids most event-version branching. Supply one transaction reference through depositTxnRef, or supply exactly two linked values: originChainId and depositId. The transaction-reference name also covers non-EVM identifiers such as a Solana signature, whereas depositTxHash reflects older EVM-only wording. If direct indexing remains necessary, viem should decode both legacy and replacement events across the relevant block range. That final record joins the origin deposit, destination fill state, and origin depositRefundTxnRef.

Move Money Across Chains text over glowing lines and colorful icons

Across troubleshooting: quick answers

Does speeding up an Across deposit extend its fill deadline?

Speeding up an Across deposit doesn't extend its fill deadline. The signed update changes the output amount, recipient, and message associated with the relay, giving relayers a revised economic offer or destination instruction. The original fillDeadline remains part of the relay identity. If that timestamp passes before a valid fill, the deposit enters the expiry and refund path despite the earlier speed-up request.

Can a slow fill still complete after the deadline?

A slow fill can't be requested once the fill deadline has passed. The SpokePool also blocks a slow-fill request during an active exclusivity window, because the nominated relayer still owns that interval. Before expiry, a valid request enters a settlement bundle, and anyone can execute the proven leaf only while fillDeadline remains valid. Once the deadline passes, follow the expired-deposit refund state instead of submitting another slow-fill request. That sequence preserves the relay's single-fill accounting on-chain.

Why does the status endpoint say a confirmed deposit is missing?

A confirmed deposit can remain absent briefly while the Across indexer ingests origin-chain events. The tracking service polls on a 10-second cadence and describes a typical 1-to-15-second indexing delay. Retry with the exact deposit transaction reference, or pair the correct originChainId with depositId. If the call still fails, confirm that the receipt contains the expected Across deposit event rather than only an ERC-20 approval.

Will an automatic refund reset the ERC-20 allowance?

An automatic Across refund doesn't change the ERC-20 allowance granted before the deposit. Allowance belongs to the token contract's separate state, while refund settlement transfers escrowed tokens back to the configured address. A completed refund therefore restores the token balance without reversing approval history. Read the token's allowance for the actual spender if you need its current value; the refunded status only confirms the return transfer, not an approval update. The spender and allowance amount must be checked independently afterward on-chain.

Why doesn't an expired Across testnet deposit refund automatically?

Across testnet doesn't run the same automatic settlement path as mainnet. Testnet relayer settlement is absent, so an unfilled test deposit won't progress through the normal bundle-based refund lifecycle. Treat that environment as an integration check for quote construction, deposit events, fill logic, and status handling. A testnet expiry therefore doesn't demonstrate the mainnet refund delay or prove that the production refund monitor is broken.

When is support information necessary for an expired Across transfer?

Support information becomes useful after the deposit is expired, several hours have passed, and no refund transaction appears. Prepare the depositTxnRef, originChainId, depositId, input token address, refund address, and visible status. For a deposit-address flow, also retain the generated deposit address and the funding transaction reference. Those identifiers distinguish a standard expired intent from a late deposit-address transfer or a transfer sent with an unexpected token or chain. Include any depositRefundTxnRef already returned, even if the wallet display lags.

Updated on