Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update chain-abstraction.mdx #285

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 38 additions & 74 deletions docs/walletkit/ios/experimental/chain-abstraction.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ Apps need to pass `gas` as null, while sending a transaction to allow proper gas
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
3. Sign routing and initial transaction hashes, prepared by the prepare method
4. 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

Expand All @@ -30,106 +30,70 @@ Following are the methods from WalletKit that you will use in implementing chain

### Prepare

This method is used to check if chain abstraction is needed. If it is, it will return a response with the necessary transactions.
This method is used to check if chain abstraction is needed. If it is, it will return a response with the necessary transactions and it's hashes to be signed.
If it is not, it will return a response with the original transaction.

```swift
@available(*, message: "This method is experimental. Use with caution.")
public func prepare(transaction: InitialTransaction) async throws -> PrepareResponse {
public func prepare(chainId: String, from: FfiAddress, call: Call, localCurrency: Currency) async throws -> PrepareDetailedResponse {
}
```

### Wait For Success With Timeout

This method is used to wait for all transactions to complete successfully. It will return a response with the transaction hash and receipt if the operation completed successfully.
If the operation did not complete successfully, it will throw an error.

This method is used to execute the fulfillment operations, including transactions broadcasting.
```swift
@available(*, message: "This method is experimental. Use with caution.")
public func waitForSuccessWithTimeout(orchestrationId: String, checkIn: UInt64, timeout: UInt64 = 180) async throws -> StatusResponseCompleted {
}
```

### Estimate Fees

This method is used to estimate fees on a specific chain.

```swift
@available(*, message: "This method is experimental. Use with caution.")
public func estimateFees(chainId: String) async throws -> Eip1559Estimation {
}
```

### Get UI Fields

Get UI fields that you can use to display like estimated fees in user's local currency for specific chain.

```swift
@available(*, message: "This method is experimental. Use with caution.")
public func getUIFields(chainId: String) async throws -> UIFields {
}
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. If it is needed, you need to sign all the fulfillment transactions and broadcast them in parallel.
After that, you need to call the `waitForSuccessWithTimeout` method to check the status of the fulfillment operation.
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 hashes and invoke the `execute` method.

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, you need to send a JsonRpcError to the dapp and display the error to the user.

```swift
guard request.method == "eth_sendTransaction" else {
return
}

let tx = try request.params.get([Tx].self)[0]

let transaction = InitialTransaction(
chainId: request.chainId.absoluteString
from: tx.from,
to: tx.to,
value: "0",
input: tx.data,
let routeResponseSuccess = try await WalletKit.instance.ChainAbstraction.prepare(
chainId: selectedNetwork.chainId.absoluteString,
from: myAccount.address,
call: call,
localCurrency: .usd
)

let routeResponseSuccess = try await WalletKit.instance.prepare(transaction: transaction)

switch routeResponseSuccess {
case .success(let routeResponseSuccess):
switch routeResponseSuccess {
case .available(let routeResponseAvailable):
// sign and broadcast routing transactions and then the initial transaction
case .notRequired(let routeResponseNotRequired):
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):
// error has occurred, respond with an error to a dapp

}
```

After broadcasting the transactions, use the `waitForSuccessWithTimeout` method to monitor their completion. Once all transactions are successful, you can proceed with broadcasting the initial transaction.

```swift
let orchestrationId = routeResponseAvailable.orchestrationId
print("📋 Orchestration ID: \(orchestrationId)")

print("🔄 Starting status checking...")

let completed = try await WalletKit.instance.waitForSuccessWithTimeout(orchestrationId: orchestrationId, checkIn: 5, timeout: 180)
print("✅ Routing Transactions completed successfully!")
print("📊 Completion details: \(completed)")
case .error(let routeResponseError):
// Show an error

}

print("🚀 Initiating initial transaction...")
try await sendInitialTransaction(initialTransaction: routeResponseAvailable.initialTransaction)
```

For example, check out implementation of chain abstraction in [sample wallet](https://github.com/reown-com/reown-swift/blob/develop/Example/WalletApp/PresentationLayer/Wallet/CATransactionModal/CATransactionPresenter.swift) with Swift.

## 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://testflight.apple.com/join/09bTAryp) for testing.
Best way to test Chain Abstraction is to use [sample wallet](https://testflight.apple.com/join/09bTAryp)

You can also use the [AppKit laboratory](https://appkit-lab.reown.com/library/wagmi/) and try sending USDC with any chain abstraction-supported wallet.

<video controls width="100%" height="100%" style={{ borderRadius: '10px' }}>
<source src="/assets/chain-abstraction-demo.mp4" type="video/mp4" />
</video>
</video>