Chain Abstraction
Chain Abstraction in WalletKit enables users with stablecoins on any network to spend them on-the-fly on a different network. Our Chain Abstraction solution provides a toolkit for wallet developers to integrate this complex functionality using WalletKit.
For example, when an app requests a 100 USDC payment on Base network but the user only has USDC on Arbitrum, WalletKit offers methods to detect this mismatch, generate necessary transactions, track the cross-chain transfer, and complete the original transaction after bridging finishes.
How It Works
Apps need to pass gas
as null, while sending a transaction to allow proper gas estimation by the wallet. Refer to this guide for more details.
When sending a transaction, you need to:
- Check if the required chain has enough funds to complete the transaction
- If not, use the
prepare
method to generate necessary bridging transactions - Sign routing and initial transaction hashes, prepared by the prepare method
- Invoke
execute
method to broadcast routing and initial transactions and wait for it to be completed
The following sequence diagram illustrates the complete flow of a chain abstraction operation, from the initial dapp request to the final transaction confirmation
Methods
Following are the methods from WalletKit that you will use in implementing chain abstraction.
💡 Chain abstraction is currently in the experimental phase
Prepare
This method is used to check if chain abstraction is needed. If it is, it will return a response with the necessary transactions. If it is not, it will return a response with the original transaction.
@available(*, message: "This method is experimental. Use with caution.")
public func prepare(transaction: InitialTransaction) async throws -> PrepareResponse {
}
Execute
This method is used to execute the chain abstraction operation. The method will handle broadcasting all transactions in the correct order and monitor the cross-chain transfer process. It returns an ExecuteDetails
object with the transaction status and results.
@available(*, message: "This method is experimental. Use with caution.")
public func execute(uiFields: UiFields, routeTxnSigs: [FfiPrimitiveSignature], initialTxnSig: FfiPrimitiveSignature) async throws -> ExecuteDetails {
}
Usage
When sending a transaction, first check if chain abstraction is needed using the prepare
method. Call the execute
method to broadcast the routing and initial transactions and wait for it to be completed.
If the operation is successful, you need to broadcast the initial transaction and await the transaction hash and receipt. If the operation is not successful, send a JsonRpcError to the dapp and display the error to the user.
let routeResponseSuccess = try await WalletKit.instance.ChainAbstraction.prepare(
chainId: selectedNetwork.chainId.absoluteString,
from: myAccount.address,
call: call,
localCurrency: .usd
)
switch routeResponseSuccess {
case .success(let routeResponse):
switch routeResponse {
case .available(let UiFileds):
// If the route is available, present a CA transaction flow
for txnDetails in uiFields.route {
let hash = txnDetails.transactionHashToSign
let sig = try! signer.signHash(hash)
routeTxnSigs.append(sig)
}
// sign initial transaction hash
let initialTxHash = uiFields.initial.transactionHashToSign
let initialTxnSig = try! signer.signHash(initialTxHash)
let executeDetails = try await WalletKit.instance.ChainAbstraction.execute(uiFields: uiFields, routeTxnSigs: routeTxnSigs, initialTxnSig: initialTxnSig)
case .notRequired:
// user does not need to move funds from other chains, sign and broadcast original transaction
}
case .error(let routeResponseError):
// Show an error
}
For example, check out implementation of chain abstraction in sample wallet with Swift.
Testing
Best way to test Chain Abstraction is to use sample wallet. You can also use the AppKit laboratory and try sending USDC with any chain abstraction-supported wallet.