Using IdentityKit (for React)
IdentityKit makes it easy to add wallet connections to React dApps. It supports OISY and others.
Install:
npm install @nfid/identitykit
# or yarn add @nfid/identitykit
# or pnpm add @nfid/identitykit
**Setup:**
Wrap your main React app component with `IdentityKitProvider`. Tell it which wallets to show. _Very important: set `authType` correctly for OISY._
```jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App'; // Your main App component
// Import IdentityKit styles and components
import '@nfid/identitykit/react/styles.css';
import { IdentityKitProvider, IdentityKitAuthType, OISY } from '@nfid/identitykit/react';
// You can add other wallets too!
import { PlugWallet, NFIDWallet, InternetIdentity } from '@nfid/identitykit/react';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<IdentityKitProvider
// IMPORTANT FOR OISY: Use ACCOUNTS mode!
// Because OISY needs approval for each action (no delegation support currently).
authType={IdentityKitAuthType.ACCOUNTS}
// List the wallets you want to support. We include OISY here.
signers={[OISY, PlugWallet, NFIDWallet, InternetIdentity]}
// Optional: canister IDs your app talks to (can improve user experience)
// targets={["your_backend_canister_id"]}
// Optional: your dApp's name, shown in wallet prompts
// appName="My Awesome dApp"
// Optional: your dApp's logo, shown in wallet prompts
// appLogo="https://example.com/logo.png"
>
<App />
</IdentityKitProvider>
</React.StrictMode>
);
```
**Why `IdentityKitAuthType.ACCOUNTS`?** This tells IdentityKit to use an interaction mode based on ICRC-27 (getting accounts) and ICRC-49 (requesting calls), where the wallet (OISY) will prompt for approval for each transaction. This is the _only_ mode OISY currently supports because it does not implement delegation features (like ICRC-34). **You must use this mode for OISY compatibility with IdentityKit.**
**Add the Button:**
Put the `<ConnectWallet />` component in your UI (e.g., header).
```jsx
import { ConnectWallet } from '@nfid/identitykit/react';
function Navbar() {
return (
<nav style={{ display: 'flex', justifyContent: 'space-between', padding: '1rem' }}>
<h1>My dApp</h1>
<ConnectWallet /> {/* This button does the magic! */}
</nav>
);
}
```
This button shows "Connect Wallet". When clicked, it opens a modal listing the configured wallets (including OISY). If the user picks OISY, IdentityKit handles opening the OISY interface, managing the connection handshake, and updating the button state to "Connected" (or showing the user's principal).
**Using the Connection:**
IdentityKit provides React hooks to get user information and make canister calls.
```jsx
import React from 'react';
import { useIdentityKit, useAgent } from '@nfid/identitykit/react';
import { Actor } from '@dfinity/agent';
import { Principal } from '@dfinity/principal';
// Assume you have ICP Ledger IDL factory (e.g., from @dfinity/nns-ledger)
import { idlFactory as ledgerIdlFactory } from '@dfinity/nns-ledger'; // Or your own ICRC-1 IDL
import { AccountIdentifier } from '@dfinity/ledger-icp'; // Helper for ICP ledger accounts
const ICP_LEDGER_CANISTER_ID = 'ryjl3-tyaaa-aaaaa-aaaba-cai'; // ICP Ledger on mainnet
function UserDashboard() {
// Get state and functions from IdentityKit
const { principal, accounts, isConnected, disconnect } = useIdentityKit();
// Get the special agent that talks to the connected wallet
const agent = useAgent(); // This agent is configured to use the wallet for signing
const handleTransfer = async () => {
if (!isConnected || !agent || !accounts || accounts.length === 0) {
alert('Connect wallet first!');
return;
}
// Example: Send to a known principal. In a real app, this would be dynamic.
const recipientPrincipal = Principal.fromText('uzr34-vyaaa-aaaaq-aaaea-cai'); // Example recipient (replace with actual)
const recipientAccount = AccountIdentifier.fromPrincipal({ principal: recipientPrincipal });
const amount = 1_000_000n; // 0.01 ICP in e8s (use BigInt 'n')
try {
// Create actor using the agent from IdentityKit
// This agent will route calls through the connected wallet (OISY)
const ledgerActor = Actor.createActor(ledgerIdlFactory, {
agent,
canisterId: Principal.fromText(ICP_LEDGER_CANISTER_ID),
});
const transferArgs = {
to: recipientAccount.toUint8Array(),
fee: { e8s: 10_000n }, // Standard ICP transfer fee
memo: 0n,
from_subaccount: [], // Use default subaccount (empty array)
created_at_time: [], // Optional: timestamp
amount: { e8s: amount },
};
// Call transfer -> This will trigger OISY popup for approval!
console.log('Requesting transfer via OISY...');
const blockIndex = await ledgerActor.transfer(transferArgs);
console.log(`Transfer OK! Block index: ${blockIndex}`);
alert(`Transfer successful! Block index: ${blockIndex}`);
} catch (error) {
console.error('Transfer failed:', error);
alert(`Transfer failed: ${error.message || error}`);
}
};
if (!isConnected) {
return <p>Please connect your wallet using the button above.</p>;
}
return (
<div>
<h2>Welcome!</h2>
<p>Connected Principal: {principal?.toText()}</p>
{accounts && accounts.length > 0 && <p>Your Account ID (from OISY): {accounts.address}</p>}
<button onClick={handleTransfer}>Send 0.01 ICP (Test)</button>
<button onClick={disconnect}>Disconnect</button>
</div>
);
}
export default UserDashboard;
```
When ledgerActor.transfer()
is called, the agent
obtained from useAgent()
is configured by IdentityKit to send the call request to OISY (or whichever wallet is connected). OISY then displays an approval popup to the user (because we are in ACCOUNTS
mode, requiring explicit consent for such actions). If the user approves, OISY signs and dispatches the transaction, and the result is returned to your dApp.
IdentityKit Summary:
Easiest for React developers, especially if multiple wallet support is desired. Handles UI components and state management for connections. Crucially, remember to use `IdentityKitAuthType.ACCOUNTS` for OISY due to its current lack of delegation support.
Last updated