Table of contents:
The OrangeKit package is built on top of RainbowKit, expanding its functionality to provide additional wallet connection options specifically tailored for Bitcoin wallets. With this package, developers can integrate Bitcoin wallet support alongside existing Ethereum-compatible (EVM) wallets, creating a more versatile connection experience for users.
One of the key features of this package is its ability to "masquerade" or simulate Bitcoin wallets as EVM wallets, allowing them to interact with Ethereum-based applications seamlessly. Under the hood, it manages a supporting provider, with it's underlying EVM account, that enables standard EVM operations (such as reading data and interacting with smart contracts) while keeping signing operations (such as authorizing transactions) routed to the Bitcoin wallet itself.
Additionally, the package directs transaction execution to a backing smart account, which handles the technical details on the EVM side. This setup enables users to use their Bitcoin wallet for both EVM-compatible transactions and Bitcoin-specific signing operations without needing to switch wallets or providers manually. Each OrangeKit Bitcoin wallet has an underlying smart account on an EVM chain that validates signatures from the Bitcoin wallet and issues EVM transactions.
In essence, this package allows for a more flexible and integrated multi-chain wallet experience by enabling Bitcoin wallets to operate within an EVM environment, making it easier for users to access both Bitcoin and EVM functionalities through a unified connection interface.
-
Wallet Management
The OrangeKit package provides a set of components that enable users to connect their Bitcoin wallets to your dApp. Beyond simple connection and disconnection, it also supports features like displaying balances, switching networks, and more.
-
Interoperability
The OrangeKit package provides integrations with the popular viem and wagmi libraries, making it easier to incorporate Bitcoin wallet support into applications that already utilize these libraries. By leveraging these integrations, developers can seamlessly manage wallet connections and streamline interactions across both Bitcoin and EVM ecosystems.
To quickly start a new project with OrangeKit integrated, you can use our sample dApp:
npm init @thesis/orange-template
# or
pnpm create @thesis/orange-template
# or
yarn create @thesis/orange-template
The sample dApp will be created on top of Vite + RainbowKit + Wagmi + OrangeKit.
You can also set everything up manually in you existing (or fresh) project. For manual setup please take a look at Step by step setup.
Note: Because RainbowKit is a React library, OrangeKit is also designed as a React library to ensure seamless integration.
Install OrangeKit library, RainbowKit and all of it's dependencies:
npm install @mezo-org/orangekit @rainbow-me/rainbowkit wagmi viem@2.x @tanstack/react-query
Note: We recommend reading through RainbowKit documentation first to fully understand the configuration process.
The configuration process is basically the same as in RainbowKit. We need to
create a wagmi config, which can be done using createDefaultConfig
from
RainbowKit.
import '@rainbow-me/rainbowkit/styles.css';
import { http } from "viem"
import { mainnet, sepolia } from "wagmi/chains"
import { getDefaultConfig } from "@rainbow-me/rainbowkit"
const rainbowKitConfig = {
appName,
transports: {
[mainnet.id]: http('https://mainnet.example.com'),
[sepolia.id]: http('https://sepolia.example.com'),
},
// If your dApp uses WalletConnect, then you have to provide the `projectId`
// here. OrangeKit itself does not require it.
projectId: "",
chains: [mainnet, sepolia],
multiInjectedProviderDiscovery: false,
}
const config = getDefaultConfig(rainbowKitConfig)
The key difference is that we need to add the bitcoin wallets we want to support
in our dApp. We can create a wallet by using specific function exported from
@mezo-org/orangekit
lib. As of now, the lib supports three wallets:
- Unisat - for this we will use
getUnisatWallet
function, - OKX - for this we will use
getOKXWallet
function, - Xverse - for this we will use
getXverseWallet
function.
Here's how to add them to wagmi config:
(...)
import { getDefaultConfig, WalletList } from "@rainbow-me/rainbowkit"
import {
getOKXWallet,
getUnisatWallet,
getXverseWallet,
} from "@mezo-org/orangekit"
(...)
const bitcoinWalletConfig = {
rpcUrl: <rpc_url>,
chainId: <evm_chain_id>,
relayApiKey: <gelato_relay_api_key>,
}
const unisatWallet = getUnisatWallet(bitcoinWalletConfig)
const okxWallet = getOKXWallet(bitcoinWalletConfig)
const xverseWallet = getXverseWallet(bitcoinWalletConfig)
export const orangeKitWallets: WalletList = [
{
groupName: "Orange Kit",
wallets: [unisatWallet, okxWallet, xverseWallet],
},
]
const config = getDefaultConfig({
...rainbowKitConfig,
wallets: orangeKitWallets,
})
As you might have notice in the previous section, our wallet initialization functions from OrangeKit requires some bitcoin wallet config passed:
const bitcoinWalletConfig = {
rpcUrl: <rpc_url>,
chainId: <evm_chain_id>,
relayApiKey: <gelato_relay_api_key>,
}
Here is a brief summary of what those values are:
- rpcUrl - the URL that connects your app to a blockchain network, allowing it to send and receive data,
- chainId - a unique identifier for each EVM blockchain network (like Ethereum, Mezo or Sepolia) so the app knows which network it's interacting with,
- relayApiKey - relayer api key needed to properly work with underlying EVM account.
We recommend to keep those values as environment variables.
Wrap your application with RainbowKitProvider
, WagmiProvider
, and
QueryClientProvider
just like you would normally do with RainbowKit lib:
import { RainbowKitProvider } from "@rainbow-me/rainbowkit"
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
import { WagmiProvider } from "wagmi"
import "@rainbow-me/rainbowkit/styles.css"
const queryClient = new QueryClient()
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
<RainbowKitProvider>
{/* Your App component */}
</RainbowKitProvider>
</QueryClientProvider>
</WagmiProvider>
</React.StrictMode>,
)
That's pretty much it when it comes to configuration! As stated earlier, we recommend to read through the RainbowKit documentation for better understanding.
To start adding functionalities, please see Connecting a wallet.
There are two ways to connect the OrangeKit wallet:
- through Wagmi,
- through RainbowKit,
We can connect to the specific wallet directly through wagmi
:
import {
useChainId,
useConnect,
} from "wagmi"
export const YourApp = () => {
const chainId = useChainId()
const { connectors, connect } = useConnect()
return (
<div>
{connectors.map((connector) => (
<button
type="button"
onClick={() => {
connect({ connector, chainId })
}}
key={connector.id}
>
{connector.name}
</button>
))}
</div>
)
};
This will render a button for each wallet that we've added to the rainbowKit config. This gives us more control over connector and how we want it to be displayed in our dApp.
We can also implement wallet connection through RainbowKit, where we import the
ConnectButton
component, which will handle the connection process under the
hood:
import { ConnectButton } from "@rainbow-me/rainbowkit"
export const YourApp = () => {
return <ConnectButton label="Connect wallet"/>;
};
For bitcoin account OrangeKit exports a helper hook - useBitcoinAccount()
-
which can be used to obtain address and balance of the connected bitcoin
account:
import { useBitcoinAccount } from "@mezo-org/orangekit"
const { btcAddress, btcBalance } = useBitcoinAccount()
useEffect(() => {
console.log("btcAddress: ", btcAddress)
console.log("btcBalance (in satoshi): ", btcBalance.total)
}, [btcAddress, btcBalance])
This hook returns the bitcoin balance in satoshis, in the following format:
{
confirmed: number,
unconfirmed: number,
total: number
}
To get an address and a balance of the underlying evm account, we can use
wagmi
hooks:
const { address } = useAccount()
const { data } = useBalance({ address })
useEffect(() => {
console.log("ethAddress: ", address)
console.log("ethBalance (in wei): ", data.value.toString())
}, [address, data])
The OrangeKit wallets supports message signing from wagmi
lib, so signing
functions the same way as it does in wagmi
:
import { useSignMessage } from 'wagmi'
function App() {
const { signMessage } = useSignMessage()
return (
<button onClick={() => signMessage({ message: 'hello world' })}>
Sign message
</button>
)
}
To send BTC transactions we can use a useSendBitcoin
hook from
@mezo-org/orangekit
:
import { useSendBitcoin } from "@mezo-org/orangekit"
const { sendBitcoin } = useSendBitcoin()
const onSendBitcoin = async () => {
const txHash = await sendBitcoin("<btc_address>", 1500)
console.log("txHash: ", txHash)
}
sendBitcoin
function takes two arguments:
- address for which we want to send bitoins to
- amount of bitcoins (in satoshis) that we want to send
Note: Make sure the gelato_relay_api_key
is passed to bitcoinWalletConfig
before testing this.
To send EVM transactions from the underlying EVM account, we can use a
useSendTransaction
hook from @mezo-org/orangekit
:
import { useSendTransaction } from "@mezo-org/orangekit"
const { sendTransaction } = useSendTransaction()
const onSendTransaction = async () => {
const result = await sendTransaction(
"<eth_address>",
100000n,
"0x00",
)
console.log(result?.hash)
}
sendTransaction
function takes three arguments:
- address for which we want to send eth to
- amount of eth (in wei) that we want to send
- additional data that we would like to send with the transaction