Skip to content
Closed
Show file tree
Hide file tree
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
8 changes: 8 additions & 0 deletions docs/walletkit/features/experimental/chain-abstraction.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import androidLogo from '../../../../static/assets/home/androidLogo.png'
import iosLogo from '../../../../static/assets/home/iosLogo.png'
import rnLogo from '../../../../static/assets/home/rnLogo.png'
import Table from '../../../components/Table'
import webLogo from '../../../../static/assets/home/webLogo.png'

# Chain Abstraction

Expand Down Expand Up @@ -64,6 +65,13 @@ The user does not have any USDC on Base, but their wallet seamlessly allows them
description: 'Get started with WalletKit in React Native.',
icon: rnLogo,
href: '../../react-native/experimental/chain-abstraction'
},
{
name: 'Web',
type: 'web',
description: 'Get started with WalletKit in Web.',
icon: webLogo,
href: '../../web/experimental/chain-abstraction'
}
]}
/>
Expand Down
176 changes: 46 additions & 130 deletions docs/walletkit/react-native/experimental/chain-abstraction.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ Apps need to pass `gas` as null when sending a transaction to allow proper gas e

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 complete
4. Once the bridging transactions are completed, execute the initial transaction
2. If not, use the `prepareDetailed` method to generate necessary bridging transactions
3. Sign routing and initial transaction hashes, prepared by the prepare method
4. Use `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

![Chain Abstraction Flow](/assets/chain-abstraction-flow.png)
![Chain Abstraction Flow](/assets/chain-abstraction-sequence.png)

## Methods

Expand All @@ -38,149 +38,65 @@ Following are the methods from WalletKit that you will use in implementing chain
This method checks if a transaction requires additional bridging transactions beforehand.

```typescript
public prepare(params: {
transaction: ChainAbstractionTypes.Transaction;
}): Promise<ChainAbstractionTypes.CanFulfilResponse>;
public abstract prepareDetailed(params: {
transaction: ChainAbstractionTypes.PartialTransaction;
}): ChainAbstractionTypes.PrepareDetailedResponse;
```

### Status
### Execute

Helper method used to check the fulfilment status of a bridging operation.
Helper method used to broadcast the bridging and initial transactions and wait for them to be completed.

```typescript
public abstract status(params: {
fulfilmentId: string;
}): Promise<ChainAbstractionTypes.FulfilmentStatusResponse>;
public abstract execute(params: {
orchestrationId: ChainAbstractionTypes.OrchestrationId;
bridgeSignedTransactions: ChainAbstractionTypes.SignedTransaction[];
initialSignedTransaction: ChainAbstractionTypes.SignedTransaction;
}): ChainAbstractionTypes.ExecuteResult;
```

### 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 `status` method to check the status of the fulfillment operation.

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 the JsonRpcError to the dapp and display the error to the user.
When sending a transaction, first check if chain abstraction is needed using the `prepareDetailed` method.
If it is needed, you must sign all the fulfillment transactions and use the `execute` method.
Here's a complete example:

```typescript
walletkit.on("session_request", async (event) => {
const {
id,
topic,
params: { request, chainId },
} = event;

if (request.method === "eth_sendTransaction") {
const originalTransaction = request.params[0];
// Check if chain abstraction is needed
const result = await walletKit.chainAbstraction.prepareDetailed({
transaction: {
from: transaction.from as `0x${string}`,
to: transaction.to as `0x${string}`,
// @ts-ignore - cater for both input or data
input: transaction.input || (transaction.data as `0x${string}`),
chainId: chainId,
},
});

// Handle the prepare result
if ('success' in result) {
if ('notRequired' in result.success) {
// No bridging required, proceed with normal transaction
console.log('no routing required');
} else if ('available' in result.success) {
const available = result.success.available;

// Check if bridging transactions are required
const prepareResponse = await wallet.prepare({
transaction: {
...originalTransaction,
chainId,
},
// Sign all bridge transactions and initial transaction
const bridgeTxs = available.route.map(tx => tx.transactionHashToSign);
const signedBridgeTxs = bridgeTxs.map(tx => wallet.signAny(tx));
const signedInitialTx = wallet.signAny(available.initial.transactionHashToSign);

// Execute the chain abstraction
const result = await walletKit.chainAbstraction.execute({
bridgeSignedTransactions: signedBridgeTxs,
initialSignedTransaction: signedInitialTx,
orchestrationId: available.routeResponse.orchestrationId,
});

if (prepareResponse.status === "error") {
// Display error to user and respond to dapp
await wallet.respondSessionRequest({
topic,
response: formatJsonRpcResult(id, prepareResponse.reason),
});
return;
}

if (prepareResponse.status === "available") {
const { transactions, funding, fulfilmentId, checkIn } = prepareResponse.data;

// Display bridging information to user
// Once approved, execute bridging transactions
for (const transaction of transactions) {
const signedTransaction = await wallet.signTransaction(transaction);
await wallet.sendTransaction(signedTransaction);
}
// await for the completed fulfilment status
await statusResult = await wallet.status({
fulfilmentId
});

// Proceed with original transaction
const signedTransaction = await wallet.signTransaction(originalTransaction);
const result = await wallet.sendTransaction(signedTransaction);

await wallet.respondSessionRequest({
topic,
response: formatJsonRpcResult(id, result)
});
} else {
// No bridging required, process transaction normally
const signedTransaction = await wallet.signTransaction(originalTransaction);
const result = await wallet.sendTransaction(signedTransaction);

await wallet.respondSessionRequest({
topic,
response: formatJsonRpcResult(id, result)
});
}
}
});
```

## Types

Following are the types that are used in the chain abstraction methods.

```typescript
namespace ChainAbstractionTypes {
type FundingFrom = {
tokenContract: string;
amount: string;
chainId: string;
symbol: string;
};

type Transaction = {
from: string;
to: string;
value: string;
chainId: string;
gas?: string;
gasPrice?: string;
data?: string;
nonce?: string;
maxFeePerGas?: string;
maxPriorityFeePerGas?: string;
};

type CanFulfilResponse =
| {
status: "not_required";
}
| {
status: "available";
data: {
fulfilmentId: string;
checkIn: number;
transactions: Transaction[];
funding: FundingFrom[];
};
}
| {
status: "error";
reason: string; // reason can be insufficientFunds | insufficientGasFunds | noRoutesAvailable
};

type FulfilmentStatusResponse = {
createdAt: number;
} & (
| {
status: "completed";
}
| { status: "pending"; checkIn: number }
);
}
```

For example, check out implementation of chain abstraction in [sample wallet](https://github.com/reown-com/react-native-examples/pull/185) with React Native CLI.
For example, check out implementation of chain abstraction in [sample wallet](https://github.com/reown-com/react-native-examples/tree/main/wallets/rn_cli_wallet) with React Native CLI.

## Testing

Expand Down
108 changes: 108 additions & 0 deletions docs/walletkit/web/experimental/chain-abstraction.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Chain Abstraction

:::note
💡 Chain Abstraction is currently in experimental phase.
:::

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 when 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 `prepareDetailed` method to generate necessary bridging transactions
3. Sign routing and initial transaction hashes, prepared by the prepare method
4. Use `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

![Chain Abstraction Flow](/assets/chain-abstraction-sequence.png)

## Methods

:::note
Make sure you are using canary version of `@reown/walletkit`.
:::

Following are the methods from WalletKit that you will use in implementing chain abstraction.

### Prepare

This method checks if a transaction requires additional bridging transactions beforehand.

```typescript
public abstract prepareDetailed(params: {
transaction: ChainAbstractionTypes.PartialTransaction;
}): ChainAbstractionTypes.PrepareDetailedResponse;
```

### Execute

Helper method used to broadcast the bridging and initial transactions and wait for them to be completed.

```typescript
public abstract execute(params: {
orchestrationId: ChainAbstractionTypes.OrchestrationId;
bridgeSignedTransactions: ChainAbstractionTypes.SignedTransaction[];
initialSignedTransaction: ChainAbstractionTypes.SignedTransaction;
}): ChainAbstractionTypes.ExecuteResult;
```

### Usage

When sending a transaction, first check if chain abstraction is needed using the `prepareDetailed` method.
If it is needed, you must sign all the fulfillment transactions and use the `execute` method.
Here's a complete example:

```typescript
// Check if chain abstraction is needed
const result = await walletKit.chainAbstraction.prepareDetailed({
transaction: {
from: transaction.from as `0x${string}`,
to: transaction.to as `0x${string}`,
// @ts-ignore - cater for both input or data
input: transaction.input || (transaction.data as `0x${string}`),
chainId: chainId,
},
});

// Handle the prepare result
if ('success' in result) {
if ('notRequired' in result.success) {
// No bridging required, proceed with normal transaction
console.log('no routing required');
} else if ('available' in result.success) {
const available = result.success.available;

// Sign all bridge transactions and initial transaction
const bridgeTxs = available.route.map(tx => tx.transactionHashToSign);
const signedBridgeTxs = bridgeTxs.map(tx => wallet.signAny(tx));
const signedInitialTx = wallet.signAny(available.initial.transactionHashToSign);

// Execute the chain abstraction
const result = await walletKit.chainAbstraction.execute({
bridgeSignedTransactions: signedBridgeTxs,
initialSignedTransaction: signedInitialTx,
orchestrationId: available.routeResponse.orchestrationId,
});
}
}
```

For example, check out implementation of chain abstraction in [sample wallet](https://github.com/reown-com/web-examples/tree/main/advanced/wallets/react-wallet-v2) built with React.

## Testing

To test Chain Abstraction, you can use the [AppKit laboratory](https://appkit-lab.reown.com/library/wagmi/) and try sending [USDC/USDT](../../../walletkit/features/experimental/chain-abstraction.mdx#what-are-the-supported-tokens-and-networks) with any chain abstraction supported wallet.
You can also use this [sample wallet](https://react-wallet.walletconnect.com) for testing.

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