Skip to content

Commit 5d0f445

Browse files
committed
bump dependencies
1 parent 4b4da18 commit 5d0f445

File tree

3 files changed

+209
-16
lines changed

3 files changed

+209
-16
lines changed

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@
1010
"astro": "astro"
1111
},
1212
"dependencies": {
13-
"@astrojs/mdx": "^4.3.8",
14-
"@astrojs/netlify": "^6.6.0",
15-
"@astrojs/rss": "^4.0.13",
13+
"@astrojs/mdx": "^4.3.12",
14+
"@astrojs/netlify": "^6.6.3",
15+
"@astrojs/rss": "^4.0.14",
1616
"@astrojs/sitemap": "^3.6.0",
17-
"astro": "^5.15.1",
17+
"astro": "^5.16.2",
1818
"html-to-text": "^9.0.5",
1919
"markdown-it": "^14.1.0",
20-
"sharp": "^0.34.4"
20+
"sharp": "^0.34.5"
2121
},
2222
"devDependencies": {
2323
"@types/html-to-text": "^9.0.4",

src/content/blog/2025-10-17-circle-d2781b5070.md

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@ A practical use-case for this would be onchain stablecoin foreign exchange (FX),
1717

1818
In this blog post, we will go through the key steps needed to build a multi-currency wallet that can enable your end users to swap between USDC and EURC with [Circle Wallets](https://developers.circle.com/interactive-quickstarts/dev-controlled-wallets).
1919

20-
**Prerequisites**
20+
## Prerequisites
2121

2222
- Sign up for a [Circle Developer Account](https://console.circle.com/signup): To obtain the API key to make use of [Circle's Smart Contract Platform NodeJS SDK](https://www.npmjs.com/package/@circle-fin/smart-contract-platform) and [Circle's Developer Controlled Wallets NodeJS SDK](https://www.npmjs.com/package/@circle-fin/developer-controlled-wallets)
2323
- [Created a Developer Controlled Wallet](https://developers.circle.com/interactive-quickstarts/dev-controlled-wallets): For deploying smart contracts and executing contract functions.
2424
- Obtain testnet ETH, USDC and EURC: Fund the developer-controlled wallet to pay gas fees for transactions and test the token swaps
2525
- Get Sepolia ETH from the Google’s [Ethereum Sepolia Faucet](https://cloud.google.com/application/web3/faucet/ethereum/sepolia)
2626
- Get testnet USDC and EURC from Circle’s [Testnet Faucet](https://faucet.circle.com/)
2727

28-
**Building your multi-currency wallet experience**
28+
## Building your multi-currency wallet experience
2929

3030
The [developer-controlled wallets SDK](https://developers.circle.com/sdk-explorer/developer-controlled-wallets/Node.js/getting-started) allows you to retrieve the information to build out a smooth user-friendly experience for your end users. The SDK exposes methods that let you easily retrieve account information like the wallet address, transaction history and token balances.
3131

@@ -35,7 +35,7 @@ One thing that is particularly useful is the ability to have more fine-grained c
3535

3636
In our case, we only want the wallet to display USDC and EURC, and possibly ETH (for gas fees). We can add these 3 tokens into the monitored token list via the `createMonitoredTokens` method.
3737

38-
```javascript
38+
```js
3939
const response = await client.createMonitoredTokens({
4040
tokenIds: [
4141
"979869da-9115-5f7d-917d-12d434e56ae7", // ETH-SEPOLIA
@@ -47,30 +47,30 @@ const response = await client.createMonitoredTokens({
4747

4848
Once you’ve whitelisted your tokens of choice, your API calls for obtaining wallet balances, transactions and webhook callbacks will be monitored and only return the tokens on your list. However, if you do need to pull all tokens in your wallets, you can modify the scope to `MONITOR_ALL`.
4949

50-
```javascript
50+
```js
5151
const response = await client.updateMonitoredTokensScope({
5252
scope: "MONITOR_ALL",
5353
});
5454
```
5555

5656
You could also set the parameter `includeAll` to `true` when making API calls for listing balances or transactions to indicate you would like the full list for all tokens.
5757

58-
```javascript
58+
```js
5959
const response = await client.getWalletTokenBalance({
6060
id: WALLET_ID,
6161
includeAll: true,
6262
});
6363
```
6464

65-
**Making a swap**
65+
## Making a swap
6666

6767
We will focus on the server functions needed to make the swap in this blog post, but you can refer to REPLIT_LINK_OR_GITHUB_REPO for a simple framework-free sample application that demonstrates what the end-to-end flow might look like.
6868

6969
The developer-controlled wallets SDK makes it easier for your wallet to interact with smart contracts. The `createContractExecutionTransaction` method lets us create a transaction which executes a smart contract. We already have a simplified single-path swap contract [deployed onto Ethereum Sepolia](https://sepolia.etherscan.io/address/0x46c2f5022bae66db1adeaa89775044252820f3b4#code), if you want to see how it works.
7070

7171
To start using the SDK, you must initialise the client with your [API key](https://developers.circle.com/interactive-quickstarts/get-started#create-your-api-key) and [entity secret](https://developers.circle.com/interactive-quickstarts/dev-controlled-wallets#setup-your-entity-secret).
7272

73-
```javascript
73+
```js
7474
import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets";
7575

7676
const client = initiateDeveloperControlledWalletsClient({
@@ -81,7 +81,7 @@ const client = initiateDeveloperControlledWalletsClient({
8181

8282
There are two transactions involved in making a token swap. The first is to approve the transaction to the swap contract, and the next transaction executes the swap function.
8383

84-
```javascript
84+
```js
8585
// 1) Approve EURC to your swap contract
8686
const approveTxn = await client.createContractExecutionTransaction({
8787
walletId: WALLET_ID,
@@ -101,12 +101,10 @@ const swapTxn = await client.createContractExecutionTransaction({
101101
});
102102
```
103103

104-
**Wrapping up**
104+
## Wrapping up
105105

106106
This tutorial gives developers a starting point to build out  a multi-currency wallet and enable your end users to have the capability to swap between different stablecoins. We would also love to hear your feedback on what you thought about this tutorial, or if you encountered any issues while trying it out. You can join our Discord to share your thoughts and engage with other like-minded developers in our community.
107107

108-
109-
110108
<sup>1</sup> USDC and EURC  are issued by regulated affiliates of Circle. A list of Circle’s regulatory authorizations can be found [here](https://www.circle.com/legal/licenses).
111109

112110
Circle Wallets are provided by Circle Technology Services, LLC (“CTS”). CTS is a software provider and does not provide regulated financial or advisory services. You are solely responsible for services you provide to users, including obtaining any necessary licenses or approvals and otherwise complying with applicable laws. For additional details, please see the [Circle Developer Terms of Service](https://console.circle.com/legal/developer-terms).
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
---
2+
date: "2025-11-24T09:22:50+08:00"
3+
external_site: circle
4+
external_url: https://www.circle.com/blog/integrating-rainbowkit-with-bridge-kit-for-crosschain-usdc-transfers
5+
noindex: true
6+
tags:
7+
- circle
8+
- javascript
9+
title: "Integrating RainbowKit with Bridge Kit for crosschain USDC transfers"
10+
---
11+
12+
Given that browser-based wallets are among the most common types of crypto wallet, having a “Connect Wallet” button on an application is becoming an expectation among users. As the ecosystem expands, there are more competing wallets on the market, and it is not uncommon for someone to have multiple wallets installed and active at the same time.
13+
14+
Even though we have the [EIP-1193: Ethereum Provider JavaScript API](https://eips.ethereum.org/EIPS/eip-1193) that standardizes a Provider object and specifies its expected behaviors, the fragmented wallet ecosystem has made it quite challenging for application developers to connect to their users’ wallets. Thankfully, we have libraries like [wagmi](https://wagmi.sh/core/why) that help to abstract the wallet, provider and network logic into a more convenient developer experience.
15+
16+
In this tutorial, we will be integrating [RainbowKit](https://rainbowkit.com/), which is a React library built on top of wagmi and viem that allows us to add a wallet connection component to our bridging application, powered by [Bridge Kit](https://developers.circle.com/bridge-kit).
17+
18+
## Crosschain transfers with Bridge Kit
19+
20+
Bridge Kit is powered by [CCTP](https://www.circle.com/cross-chain-transfer-protocol) under the hood, and abstracts away a lot of the complexity of implementing CCTP, especially with the large number of bridge routes across numerous chains. An example of the key method call is as follows:
21+
22+
```ts
23+
// Transfer 10.00 USDC from Arc Testnet to Solana Devnet
24+
const result = await kit.bridge({
25+
from: { adapter: viemAdapter, chain: "Arc_Testnet" },
26+
to: { adapter: solanaAdapter, chain: "Solana_Devnet" },
27+
amount: "10.00",
28+
});
29+
```
30+
31+
Bridge Kit makes use of adapters to manage the blockchain-specific bridging operations for a particular network and is fully compatible with viem or ethers for EVM-compatible blockchains and Solana.
32+
33+
To retrieve a full list of supported chains, we can use the `getSupportedChains()` method, which returns an array of blockchain objects, each containing key information about the chain that can be used in our application’s UI.
34+
35+
```json
36+
{
37+
"type": "evm",
38+
"chain": "Arc_Testnet",
39+
"name": "Arc Testnet",
40+
"title": "ArcTestnet",
41+
"nativeCurrency": {
42+
"name": "Arc",
43+
"symbol": "Arc",
44+
"decimals": 18
45+
},
46+
"chainId": 5042002,
47+
"isTestnet": true,
48+
"explorerUrl": "https://testnet.arcscan.app/tx/{hash}",
49+
"rpcEndpoints": ["https://rpc.testnet.arc.network/"],
50+
"eurcAddress": "0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a",
51+
"usdcAddress": "0x3600000000000000000000000000000000000000",
52+
"cctp": {
53+
"domain": 26,
54+
"contracts": {
55+
"v2": {
56+
"type": "split",
57+
"tokenMessenger": "0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA",
58+
"messageTransmitter": "0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275",
59+
"confirmations": 1,
60+
"fastConfirmations": 1
61+
}
62+
}
63+
},
64+
"kitContracts": {
65+
"bridge": "0xC5567a5E3370d4DBfB0540025078e283e36A363d"
66+
}
67+
}
68+
```
69+
70+
In our React application, we make use of a custom hook just for the bridging functionality by initializing the SDK, then calling the bridge method on it, passing in the necessary parameters supplied from the user interface.
71+
72+
```ts
73+
import { BridgeKit } from "@circle-fin/bridge-kit";
74+
75+
const kit = new BridgeKit();
76+
const result = await kit.bridge({
77+
from: { adapter: params.fromAdapter, chain: params.fromChain as any },
78+
to: { adapter: params.toAdapter, chain: params.toChain as any },
79+
amount: params.amount,
80+
});
81+
```
82+
83+
## Adding the Connect Wallet button
84+
85+
Make sure to follow the instructions from [RainbowKit’s documentation](https://rainbowkit.com/docs/installation) to install and set up RainbowKit into the project. It has dependencies on wagmi, [viem](https://viem.sh/) and [TanStack Query](https://tanstack.com/query/latest). The application has to be wrapped in the necessary providers for the ConnectButton component to work.
86+
87+
```ts
88+
import { ConnectButton } from "@rainbow-me/rainbowkit";
89+
90+
export const App = () => {
91+
return <ConnectButton />;
92+
};
93+
```
94+
95+
The component comes with a button that triggers a modal which detects available wallets to connect to and connects the application to the wallet chosen by the user.
96+
97+
**Building the adapter object with wagmi**
98+
99+
Once the user’s wallet is connected to our application, wagmi allows us to pull the wallet connection information and extract the EIP-1193 provider so we can build an adapter object that Bridge Kit recognizes and will use for the transfer.
100+
101+
```ts
102+
import { useConnectorClient } from "wagmi";
103+
import { createAdapterFromProvider } from "@circle-fin/adapter-viem-v2";
104+
105+
// Get the connected wallet's provider from wagmi
106+
const { data: client } = useConnectorClient();
107+
const provider = client?.transport?.value?.provider;
108+
109+
// Use that provider to create a Circle adapter
110+
const adapter = await createAdapterFromProvider({ provider });
111+
return adapter;
112+
```
113+
114+
Depending on how the application is structured, this logic can be put in a separate custom hook or implemented as part of a component. If this adapter logic is implemented as a custom hook, we can use it in the relevant component when the bridge hook is called.
115+
116+
## Putting it all together
117+
118+
We would use state to capture the user’s inputs for their chosen source chain, destination chain and amount to transfer, and call the bridge hook with the adapter and user inputs.
119+
120+
```ts
121+
const { evmAdapter } = useEvmAdapter();
122+
const [sourceChain, setSourceChain] = useState<SupportedChain>("Arc_Testnet");
123+
const [destinationChain, setDestinationChain] = useState<SupportedChain>("");
124+
const [amount, setAmount] = useState<string>("0");
125+
126+
const { bridge, isLoading, error, clear } = useBridge();
127+
128+
const response = await bridge({
129+
fromChain: sourceChain,
130+
toChain: destinationChain,
131+
amount,
132+
fromAdapter: evmAdapter,
133+
toAdapter: evmAdapter,
134+
});
135+
```
136+
137+
The response object contains a lot of information about the entire CCTP transaction, including chain details, contract addresses and details of each step, which can be used to build out informative UIs for the end-user. The following is an abridged version of the response:
138+
139+
```json
140+
{
141+
"state": "success",
142+
"amount": "4000000",
143+
"token": "USDC",
144+
"source": {
145+
"address": "0xf6aa88ee4b7b10abbffbfa7d85bcffef7eab6fe4",
146+
"chain": {...}
147+
},
148+
"destination": {
149+
"address": "0xf6aa88ee4b7b10abbffbfa7d85bcffef7eab6fe4",
150+
"chain": {...}
151+
},
152+
"steps": [
153+
{
154+
"name": "approve",
155+
"state": "success",
156+
"txHash": "0x0efe59bf6b418484963d54a46d7cf7314cae906c3ced6d1ed4ab74aacddb062b",
157+
"data": {
158+
"txHash": "0x0efe59bf6b418484963d54a46d7cf7314cae906c3ced6d1ed4ab74aacddb062b",
159+
"status": "success",
160+
"cumulativeGasUsed": "222484",
161+
"gasUsed": "55684",
162+
"blockNumber": "8359932",
163+
"blockHash": "0xfb96409a5cf4f370196911c5b79daaf304b4744b7ab44362b0e92f75ad456727",
164+
"transactionIndex": 6,
165+
"effectiveGasPrice": "660000000000"
166+
},
167+
"explorerUrl": "https://testnet.arcscan.app/tx/0x0efe59bf6b418484963d54a46d7cf7314cae906c3ced6d1ed4ab74aacddb062b"
168+
},
169+
{
170+
"name": "burn",
171+
...
172+
},
173+
{
174+
"name": "fetchAttestation",
175+
...
176+
},
177+
{
178+
"name": "mint",
179+
...
180+
}
181+
],
182+
"config": {
183+
"transferSpeed": "FAST"
184+
},
185+
"provider": "CCTPV2BridgingProvider"
186+
}
187+
```
188+
189+
## Wrapping up
190+
191+
We have built a sample application that incorporates the key points covered in this tutorial to bridge USDC across all the [chains that support CCTP](https://developers.circle.com/cctp/cctp-supported-blockchains). Feel free to clone the [GitHub repo](https://github.com/circlefin/circle-bridge-kit-transfer) and play around with the application to see how it works.
192+
193+
![](https://cdn.prod.website-files.com/67116d0daddc92483c812ead/69207d431117c801e7a9accb_app-ui.png)
194+
195+
Combining RainbowKit for wallet connection and Bridge Kit for crosschain USDC transfers allows us to build a smoother user experience with fewer lines of code. Check out [Bridge Kit](https://developers.circle.com/bridge-kit) to start integrating crosschain transfers into your own application.

0 commit comments

Comments
 (0)