-
Notifications
You must be signed in to change notification settings - Fork 52
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #199 from reown-com/chain-abstraction
added chain abstraction docs
- Loading branch information
Showing
9 changed files
with
726 additions
and
9 deletions.
There are no files selected for viewing
276 changes: 276 additions & 0 deletions
276
docs/walletkit/android/experimental/chain-abstraction.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,276 @@ | ||
# 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 | ||
|
||
:::note | ||
Apps need to pass `gas` as null, while sending a transaction to allow proper gas estimation by the wallet. Refer to this [guide](../../../appkit/next/experimental/chain-abstraction.mdx) for more details. | ||
::: | ||
|
||
When sending a transaction, you need to: | ||
1. Check if the required chain has enough funds to complete the transaction | ||
2. If not, use the `prepare` method to generate necessary bridging transactions | ||
3. Check the status of the bridging transactions and wait for them to be completed | ||
4. Once the bridging transactions are completed, execute the initial transaction | ||
|
||
The following sequence diagram illustrates the complete flow of a chain abstraction operation, from the initial dapp request to the final transaction confirmation | ||
|
||
![Chain Abstraction Flow](/assets/chain-abstraction-flow.png) | ||
|
||
## Methods | ||
|
||
The following methods from WalletKit are used in implementing chain abstraction. | ||
|
||
:::note | ||
Chain abstraction is currently in an experimental phase and requires the `@ChainAbstractionExperimentalApi` annotation. | ||
::: | ||
|
||
### Prepare | ||
|
||
This method is used to check if chain abstraction is needed. If it is, it will return a `PrepareSuccess.Available` object with the necessary transactions and funding information. | ||
If it is not, it will return a `PrepareSuccess.NotRequired` object with the original transaction. | ||
|
||
```kotlin | ||
@ChainAbstractionExperimentalApi | ||
fun prepare( | ||
initialTransaction: Wallet.Model.InitialTransaction, | ||
onSuccess: (Wallet.Model.PrepareSuccess) -> Unit, | ||
onError: (Wallet.Model.PrepareError) -> Unit | ||
) | ||
``` | ||
|
||
### Status | ||
|
||
This method is used to check the status of the fulfillment operation. It will return a `Status.Completed` object if the operation completed successfully or a `Status.Error` object if it encountered an error. | ||
|
||
```kotlin | ||
@ChainAbstractionExperimentalApi | ||
fun status( | ||
fulfilmentId: String, | ||
checkIn: Long, | ||
onSuccess: (Wallet.Model.Status.Completed) -> Unit, | ||
onError: (Wallet.Model.Status.Error) -> Unit | ||
) | ||
``` | ||
|
||
### Estimate Fees | ||
|
||
This method is used to estimate the fees for the fulfillment operation. | ||
|
||
```kotlin | ||
@Throws(Exception::class) | ||
@ChainAbstractionExperimentalApi | ||
fun estimateFees(chainId: String): Wallet.Model.EstimatedFees | ||
``` | ||
|
||
### Get ERC20 Balance | ||
|
||
This method is used to get the balance of an ERC20 token on a specific chain. | ||
|
||
```kotlin | ||
@Throws(Exception::class) | ||
@ChainAbstractionExperimentalApi | ||
fun getERC20Balance(chainId: String, tokenAddress: String, ownerAddress: String): String | ||
``` | ||
|
||
### Get Fulfilment Details | ||
|
||
This method is used to get the details of the fulfillment operation. | ||
|
||
```kotlin | ||
@ChainAbstractionExperimentalApi | ||
fun getTransactionsDetails( | ||
available: Wallet.Model.PrepareSuccess.Available, | ||
onSuccess: (Wallet.Model.TransactionsDetails) -> Unit, | ||
onError: (Wallet.Model.Error) -> Unit | ||
) | ||
``` | ||
|
||
### Usage | ||
|
||
When sending a transaction, first check if chain abstraction is needed using the `prepare` method. If it is needed, you must sign all the fulfillment transactions and broadcast them in parallel. | ||
After that, you need to call the `status` method to check the status of the fulfillment operation. | ||
|
||
If the operation is successful, broadcast the initial transaction and await the transaction hash and receipt. | ||
If the operation is unsuccessful, send the JsonRpcError to the dapp and display the error to the user. | ||
|
||
```kotlin | ||
val initialTransaction = Wallet.Model.Transaction(...) | ||
|
||
WalletKit.prepare( | ||
initialTransaction, | ||
onSuccess = { prepareSuccess -> | ||
when (prepareSuccess) { | ||
is Wallet.Model.PrepareSuccess.Available -> { | ||
//Sign all the fulfilment transactions | ||
//Broadcast the fulfilment transactions in parallel | ||
//Await for the transaction hashes and receipts | ||
|
||
//Call the status | ||
WalletKit.status(fulfilmentId, checkIn, | ||
onSuccess = { | ||
//Successfull filfilment operation | ||
//Broadcast the inittial transaction | ||
//Await for the tx hash ande receipt | ||
//Send the response to the Dapp | ||
}, | ||
onError = { | ||
//Status error - wallet should send the JsonRpcError to a dapp for given request and display error to the user | ||
} | ||
) | ||
} | ||
|
||
is Wallet.Model.PrepareSuccess.NotRequired -> { | ||
//Chain abstraction is not required, handle transaction as usual | ||
} | ||
} | ||
}, | ||
onError = { prepareError -> | ||
// One of the possible errors: NoRoutesAvailable, InsufficientFunds, InsufficientGasFunds - wallet should send the JsonRpcError to a dapp for given request and display error to the user | ||
} | ||
) | ||
``` | ||
|
||
For example, check out implementation of chain abstraction in [sample wallet](https://github.com/WalletConnect/WalletConnectKotlinV2/tree/master/sample/wallet) with Kotlin. | ||
|
||
## Testing | ||
|
||
To test Chain Abstraction, you can use the [AppKit laboratory](https://appkit-lab.reown.com/library/wagmi/) and try sending USDC with any chain abstraction supported wallet. | ||
You can also use this [sample wallet](https://appdistribution.firebase.dev/i/076a3bc9669d3bee) for testing. | ||
|
||
<video controls width="100%" height="100%" style={{ borderRadius: '10px' }}> | ||
<source src="/assets/chain-abstraction-demo.mp4" type="video/mp4" /> | ||
</video> | ||
|
||
## Types | ||
|
||
Following are the types that are used in the chain abstraction methods. | ||
|
||
```kotlin | ||
data class Transaction( | ||
var from: String, | ||
var to: String, | ||
var value: String, | ||
var gasLimit: String, | ||
var input: String, | ||
var nonce: String, | ||
var chainId: String | ||
) | ||
|
||
data class InitialTransaction( | ||
var from: String, | ||
var to: String, | ||
var value: String, | ||
var input: String, | ||
var chainId: String | ||
) | ||
|
||
data class FeeEstimatedTransaction( | ||
var from: String, | ||
var to: String, | ||
var value: String, | ||
var gasLimit: String, | ||
var input: String, | ||
var nonce: String, | ||
var maxFeePerGas: String, | ||
var maxPriorityFeePerGas: String, | ||
var chainId: String | ||
) | ||
|
||
sealed class PrepareSuccess { | ||
data class Available( | ||
val fulfilmentId: String, | ||
val checkIn: Long, | ||
val transactions: List<Transaction>, | ||
val initialTransaction: Transaction, | ||
val initialTransactionMetadata: InitialTransactionMetadata, | ||
val funding: List<FundingMetadata> | ||
) : PrepareSuccess() | ||
|
||
data class NotRequired(val initialTransaction: Transaction) : PrepareSuccess() | ||
} | ||
|
||
data class InitialTransactionMetadata( | ||
var symbol: String, | ||
var amount: String, | ||
var decimals: Int, | ||
var tokenContract: String, | ||
var transferTo: String | ||
) | ||
|
||
data class FundingMetadata( | ||
var chainId: String, | ||
var tokenContract: String, | ||
var symbol: String, | ||
var amount: String, | ||
var bridgingFee: String, | ||
var decimals: Int | ||
) | ||
|
||
sealed class PrepareError : Model() { | ||
data object NoRoutesAvailable : PrepareError() | ||
data object InsufficientFunds : PrepareError() | ||
data object InsufficientGasFunds : PrepareError() | ||
data class Unknown(val message: String) : PrepareError() | ||
} | ||
|
||
sealed class Status : Model() { | ||
data class Completed(val createdAt: Long) : Status() | ||
data class Error(val reason: String) : Status() | ||
} | ||
|
||
data class TransactionsDetails( | ||
var fulfilmentDetails: List<TransactionDetails>, | ||
var initialDetails: TransactionDetails, | ||
var bridgeFees: List<TransactionFee>, | ||
var localBridgeTotal: Amount, | ||
var localFulfilmentTotal: Amount, | ||
var localTotal: Amount | ||
) | ||
|
||
data class TransactionDetails( | ||
var transaction: FeeEstimatedTransaction, | ||
var transactionFee: TransactionFee | ||
) | ||
|
||
data class TransactionFee( | ||
var fee: Amount, | ||
var localFee: Amount | ||
) | ||
|
||
data class Amount( | ||
var symbol: String, | ||
var amount: String, | ||
var unit: String, | ||
var formatted: String, | ||
var formattedAlt: String | ||
) | ||
``` | ||
|
||
## ProGuard rules | ||
|
||
If you encounter issues with minification, add the below rules to your application: | ||
|
||
``` | ||
-keepattributes *Annotation* | ||
-keep class com.sun.jna.** { *; } | ||
-keepclassmembers class com.sun.jna.** { | ||
native <methods>; | ||
*; | ||
} | ||
-keep class uniffi.** { *; } | ||
# Preserve all public and protected fields and methods | ||
-keepclassmembers class ** { | ||
public *; | ||
protected *; | ||
} | ||
-dontwarn uniffi.** | ||
-dontwarn com.sun.jna.** | ||
``` |
82 changes: 82 additions & 0 deletions
82
docs/walletkit/features/experimental/chain-abstraction.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import Wrapper from '../../../components/Home/Wrapper' | ||
import androidLogo from '../../../../static/assets/home/androidLogo.png' | ||
import iosLogo from '../../../../static/assets/home/iosLogo.png' | ||
import rnLogo from '../../../../static/assets/home/rnLogo.png' | ||
|
||
# Chain Abstraction | ||
|
||
Chain Abstraction allows users to spend stablecoins across different networks seamlessly. | ||
This solution provides wallet developers with a toolkit to integrate cross-chain functionality using WalletKit. | ||
|
||
:::note | ||
💡 Support for Chain Abstraction is currently in experimental phase. | ||
::: | ||
|
||
## How it works | ||
|
||
When an application sends a `wallet_sendTransaction` request for an ERC-20 transfer (such as USDC), | ||
the wallet checks for available tokens across all supported networks. If the user has sufficient funds on any supported network, | ||
they can complete the transaction instantly, regardless of which network holds their tokens. | ||
|
||
For example, consider a scenario where an app requests a transfer of 225 USDC on the Base Network. | ||
Even if the user doesn't have USDC on Base, their wallet can automatically source the funds from other networks, | ||
making the experience seamless for both the user and the application. | ||
|
||
:::note | ||
💡 Make sure you have enough gas fees in other networks from which bridging will happen. | ||
For example, in given scenario, you need to have enough gas fees on OP Mainnet and Arbitrum. | ||
::: | ||
|
||
The diagram below shows an example scenario where a user is interacting with an app and is asked to transfer 225 USDC to the app on Base Network. | ||
The user does not have any USDC on Base, but their wallet seamlessly allows them to source the funds from other networks. | ||
|
||
![Chain Abstraction Example](/assets/chain_abstraction_demo.png) | ||
|
||
## Get Started | ||
|
||
<Wrapper | ||
type="large" | ||
fit={false} | ||
items={[ | ||
{ | ||
name: 'Android', | ||
type: 'android', | ||
description: 'Get started with WalletKit in Android.', | ||
icon: androidLogo, | ||
href: '../../android/experimental/chain-abstraction' | ||
}, | ||
{ | ||
name: 'iOS', | ||
type: 'ios', | ||
description: 'Get started with WalletKit in iOS.', | ||
icon: iosLogo, | ||
href: '../../ios/experimental/chain-abstraction', | ||
isWhite: true | ||
}, | ||
{ | ||
name: 'React Native', | ||
type: 'react-native', | ||
description: 'Get started with WalletKit in React Native.', | ||
icon: rnLogo, | ||
href: '../../react-native/experimental/chain-abstraction' | ||
} | ||
]} | ||
/> | ||
|
||
## FAQ | ||
|
||
### What are the available networks for Chain Abstraction? | ||
|
||
Chain Abstraction is available on the following networks: | ||
|
||
- Base | ||
- Arbitrum | ||
- OP Mainnet | ||
|
||
### What are the supported tokens for Chain Abstraction? | ||
|
||
Currently, Chain Abstraction supports USDC but we are working on adding support for more tokens. | ||
|
||
### What are the limitations? | ||
|
||
We currently support 1:1 transfers i.e. sourcing funds from one address to another. Make sure that you're transferring minimum 0.55 USDC and have enough gas to pay bridging fees. |
Oops, something went wrong.