Migration from V2 to V3

Find below important migration information for users of the Across API and the smart contracts (e.g. those who call the Across SpokePools directly to deposit or fill bridge transfers and those who track SpokePool events).

Introduction

Across V2 is migrating in-place to V3 and will support crosschain token swaps and a more streamlined contract interface. This guide is intended to help developers who integrate with Across to prepare their codebases for the upgrade. Please note that this page is a work in progress, and more sections will be added to help with different types of integrations.

Summary of Breaking Changes

  • Recipient contracts implementing handleAcrossMessage must now replace that with a handleAcrossV3Message call. Details.

  • Across V2 events including FundsDeposited will no longer be emitted. These will be replaced with V3 events. Details.

  • Relayers must now fill all deposits with a new function, fillV3Relay(). Details.

  • Depositors who wish to speed up their deposits must now use speedUpV3Deposit() instead of requestSpeedUpDeposit(). Details.

Across API migration guide

Overview

Across v3 redesigns how fees are handled when creating deposits. In a nutshell, the calculation of fees will be simplified and replaced byinputAmount/outputAmount arguments. This will impact the response data of the API and also how to call the deposit function of a SpokePool contract. Note that these changes won't be breaking short-term but are actionable mid- to long-term.

Non-breaking changes

For a seamless upgrade, there will be no breaking changes for the existing v2 interfaces.

Host

Both will be available, but eventually across.to/api will be sunset, please upgrade to app.across.to/api accordingly.

  • Updated from across.to/api to app.across.to/api

[Updated] relayFeePct will now include lpFeePct

In Across v2, the request GET /suggested-fees returned

It was then expected to call the method deposit of a SpokePool like

The lpFeePct was not required as an argument and automatically derived based on the quoteTimestamp. But if you wanted to show the total bridge fee to the user, then you would have to sum them up like

In Across v3, we need to pass the lpFeePct as part of the total fee when calling the deposit function. In order to be backwards-compatible, the API now returns for GET /suggested-fees

There are no changes to the interface and therefore no changes are required for how you call the deposit function or calculate the total bridge fee. If you want to show the correct fee breakdown though, some changes are needed (see here).

[Added] New v3 fees structure

If you want to show the correct detailed fee breakdown, you can use the newly added v3 properties of the GET /suggested-fees response data

Using the values of the new fees struct, you need to call the deposit function like

Breaking changes (mid- to long-term)

Even though there are no actionable changes short-term, some change will be actionable mid- to long-term.

[Deprecated] Flattened fees *Pct/*Total fields will be removed

As described here, the v3 fees have a different structure now. Eventually the redundant fields capitalFeePct, capitalFeeTotal, relayGasFeePct, relayGasFeeTotal and lpFeePct will be removed

Changes to Across Smart Contracts

Breaking Change: Across+ (Composable Bridging)

All users of Across+ (Composable Bridging) are required to upgrade their messaging implementations to use handleV3AcrossMessage().

Across v3 updates the callback interface for receiving messages in a recipient contract. The new function prototype is as follows:

The key differences to Across v2 are:

  • handleAcrossMessage() -> handleV3AcrossMessage

  • Function parameter `bool fillCompleted` has been removed.

For a smooth transition to Across v3, integrators are recommended to implement concurrent support for handleAcrossMessage() and handleV3AcrossMessage(). handleAcrossMessage() can be removed at a later date.

The motivation for updating the function prototype is that partial fills are no longer possible in Across v3, so messaging recipients no longer require special logic to account for them.

Events

If you depend on querying SpokePool events to track the status of bridge transfers, then this section is designed to support you.

Breaking Change: Deprecating Across V2 Events

In Across V2, a bridge consists of a FundsDeposited event (emitted by a deposit() call) on the origin chain and a FilledRelay event on the destination chain. They must match on all common parameters and the FilledRelay#realizedLpFeePct must be equal to the LP fee at the FundsDeposited#quoteTimestamp based on the computation rules described in the UMIP. Moreover, the FilledRelay#destinationToken also needs to match the FundsDeposited#originToken based on the matching rules described in the UMIP.

In Across V3, the deposit() call now emits a V3FundsDeposited event, which must match with a V3FilledRelay event as explained below. This means that FundsDeposited events (V2 events) will no longer be emitted.

Across V3 Events

Across V3 bridge transfers consist of a V3FundsDeposited event emitted on the origin chain and a FilledV3Relay event emitted on the destination chain.

V3FundsDeposited and FilledV3Relay must match on all common parameters except for outputToken. This can be set to 0x0 (the zero address) at deposit time to signal to relayers that they should use the "equivalent" token on the destinationChainId to fill the deposit, therefore if V3FundsDeposited#outputToken == 0x0 then FilledV3Relay#outputToken must be equal to the "equivalent" token on the destination chain. The Across UMIP should be updated to explain what it means to be "equivalent" but this essentially means the output and input token map to the same token on Ethereum, for example they could be the different USDC addresses on different L2s.

Note that the amount transferred to the recipient is relayExecutionInfo.updatedOutputAmount

Important changes for Relayers

This is an abridged summary of important breaking changes for Relayers to be aware of.

All deposits emitted in V3 contracts will be V3FundsDeposited events which can only be filled via SpokePool#filledV3Relay.

The important changes here are:

  • realizedLpFeePct The relayer no longer needs to set the realizedLpFeePct as a parameter when calling the fill function. LP fees will still be charged to relayers at refund time (i.e. they will receive the inputAmount minus the LP fees) and these fees will still be computed using the formula in the UMIP based on the deposit.quoteTimestamp. This is a nice quality of life improvement for relayers who will still need to compute the LP fee for a deposit but can use a much wider margin of error, as this fee will only be important for computing their profitability and they will not be at risk of sending an invalid fill if this fee is off by a small amount.

  • outputToken: See the section above about how outputToken must be set if FundsDeposited#outputToken == 0x0. This should be set to the "equivalent" token for the destination chain in this case.

  • No partial fills: it is not possible to send partial fills in V3.

  • Slow fills: Slow fills will be requested via a new function requestSlowFill. Slow fills can only be requested on deposits where the inputToken and outputToken are "equivalent". Slow fills will pay out the inputAmount * realizedLpFeePct, which will be set as the slow fill's updatedOutputAmount

Important changes for dApp Developers

The deposit interface will not change. The function will however emit a new event V3FundsDeposited as outlined in Across V3 Events. The fillDeadline will be set to MAX_UINT, meaning that the deposit will never expire and be refunded to the origin chain. The outputToken will be set to 0x0 to signal to depositors that the "equivalent" output token should be replaced at fill time. The exclusivityDeadline and exclusiveRelayer will be set to 0 and 0x0 respectively suggesting that there is no exclusivity period. Finally, the outputAmount will be equal to inputAmount * (1 - totalRelayFeePct). You can read more about setting this output amount value here.

To speed up a deposit, a new function will need to be used. Previously this was named speedUpDeposit and the new function to speed up a V3FundsDeposited event will be speedUpV3Deposit.

Last updated