PoP SDK - React
This is a library that allows you to easily integrate PoP into your React application.
Installation
npm install @anima-protocol/personhood-sdk-react
# or
yarn add @anima-protocol/personhood-sdk-react
Usage
Use the Personhood component
import '@anima-protocol/personhood-sdk-react/style.css'
import { Personhood } from '@anima-protocol/personhood-sdk-react'
const App = () => {
const sign = async (message) => {
// Sign the message
return signature
}
const onFinish = ({ info, state }) => {
// Do something when the user has finished the PoP flow
}
return (
<Personhood
onFinish={onFinish}
sessionId="01234567-8901-2345-6789-012345678901"
signCallback={sign}
walletAddress="0x..."
/>
)
}
The onFinish
callback will be called when the user has finished the PoP flow or if the session is already validated.
Its parameters follows the ones sent from the Personhood API session
object.
Examples
Rainbow Kit
The PoP SDK integrates seamlessly with every wallets that implements the personal sign method. Here is an example of how to use it with Rainbow Kit.
// src/index.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import {
connectorsForWallets,
darkTheme,
DisclaimerComponent,
RainbowKitProvider,
} from '@rainbow-me/rainbowkit'
import { configureChains, createClient, WagmiConfig } from 'wagmi'
import {
metaMaskWallet,
ledgerWallet,
braveWallet,
walletConnectWallet,
coinbaseWallet,
injectedWallet,
} from '@rainbow-me/rainbowkit/wallets'
import { mainnet, polygon } from 'wagmi/chains'
import { publicProvider } from 'wagmi/providers/public'
import '@rainbow-me/rainbowkit/styles.css'
export const { chains, provider, webSocketProvider } = configureChains(
[mainnet, polygon],
[publicProvider()]
)
const connectors = connectorsForWallets([
{
groupName: 'Recommended',
wallets: [
metaMaskWallet({ chains }),
ledgerWallet({ chains }),
braveWallet({ chains }),
],
},
{
groupName: 'Others',
wallets: [
walletConnectWallet({ chains }),
coinbaseWallet({ appName: 'Anima dApp', chains }),
injectedWallet({ chains }),
],
},
])
export const wagmiClient = createClient({
autoConnect: true,
connectors,
provider,
webSocketProvider,
})
const Disclaimer: DisclaimerComponent = () => (
<p>
By connecting your wallet, you agree to the{' '}
<a href="https://terms.anima.io" target="_blank" rel="noreferrer">
Terms of Service
</a>
</p>
)
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
root.render(
<React.StrictMode>
<WagmiConfig client={wagmiClient}>
<RainbowKitProvider
chains={chains}
theme={darkTheme({ borderRadius: 'small' })}
appInfo={{
appName: 'Fairdrop dApp',
disclaimer: Disclaimer,
}}
>
<App />
</RainbowKitProvider>
</WagmiConfig>
</React.StrictMode>
)
// src/App.tsx
import '@anima-protocol/personhood-sdk-react/style.css'
import { Personhood } from '@anima-protocol/personhood-sdk-react'
import { ConnectButton } from '@rainbow-me/rainbowkit'
import { useCallback } from 'react'
import { useAccount, useSignMessage } from 'wagmi'
const App = () => {
const { signMessageAsync } = useSignMessage()
const { address } = useAccount()
const sign = useCallback(
(payload: string) => signMessageAsync({ message: payload }),
[signMessageAsync]
)
const shared = useCallback((e: { info: string }) => {
console.log('shared', e.info)
}, [])
return (
<div
style={{
flex: 1,
display: 'flex',
height: '100vh',
backgroundColor: '#333',
position: 'relative',
alignItems: 'center',
justifyContent: 'center',
}}
>
<div style={{ position: 'absolute', right: '8px', top: '8px' }}>
<ConnectButton />
</div>
<Personhood
onFinish={shared}
sessionId="01234567-8901-2345-6789-012345678901"
signCallback={sign}
walletAddress={address}
/>
</div>
)
}
export default App
Wagmi (standalone or with Web3modal)
// src/App.tsx
import '@anima-protocol/personhood-sdk-react/style.css'
import { Personhood } from '@anima-protocol/personhood-sdk-react'
import { useSignMessage, useAccount } from 'wagmi'
export default function Example(): JSX.Element {
const { address } = useAccount()
const { signMessageAsync } = useSignMessage()
const sign = useCallback(
(payload: string) => signMessageAsync({ message: payload }),
[signMessageAsync]
)
const shared = useCallback((e: { info: string }) => {
console.log('shared', e.info)
}, [])
return (
<div>
{address && (
<Personhood
onFinish={shared}
sessionId="01234567-8901-2345-6789-012345678901"
signCallback={sign}
walletAddress={address}
/>
)}
</div>
)
}
export default App;
Ether.js
// src/App.tsx
import '@anima-protocol/personhood-sdk-react/style.css'
import { Personhood } from '@anima-protocol/personhood-sdk-react'
import { ethers, JsonRpcSigner } from 'ethers'
import { useEffect, useState } from 'react'
export default function Example(): JSX.Element {
const [signer, setSigner] = useState<JsonRpcSigner | null>(null)
const [address, setAddress] = useState<string | null>(null)
async function connectWallet() {
let signer = null
let provider = null
// Connect to the MetaMask EIP-1193 object. This is a standard
// protocol that allows Ethers access to make all read-only
// requests through MetaMask.
provider = new ethers.BrowserProvider(window.ethereum)
// // It also provides an opportunity to request access to write
// // operations, which will be performed by the private key
// // that MetaMask manages for the user.
signer = await provider.getSigner()
setSigner(signer)
}
useEffect(() => {
if (signer) {
signer.getAddress().then((address: string) => {
setAddress(address)
})
}
}, [signer, setAddress])
const sign = useCallback(
(payload: string) => signer.signMessage(payload),
[signer]
)
const shared = useCallback((e: { info: string }) => {
console.log('shared', e.info)
}, [])
return (
<div>
<button onClick={connectWallet}>Connect Wallet</button>
{address && signer && (
<Personhood
onFinish={shared}
sessionId="01234567-8901-2345-6789-012345678901"
signCallback={sign}
walletAddress={address}
/>
)}
</div>
)
}
Startknet Wallet (ArgentX or Braavos)
// src/App.tsx
import '@anima-protocol/personhood-sdk-react/style.css'
import { Personhood } from '@anima-protocol/personhood-sdk-react'
import { useState, useCallback } from 'react'
export default function Example(): JSX.Element {
const [address, setAddress] = useState<string | null>(null);
const [provider, setProvider] = useState<any>(null);
async function connectWallet() {
const provider = window.starknet;
await provider.enable();
setAddress(provider.selectedAddress);
setProvider(provider);
}
const sign = useCallback(
(payload: object) => provider.account.signMessage(payload),
[provider]
)
const shared = useCallback((e: { info: string }) => {
console.log('shared', e.info)
}, [])
return (
<div>
<button onClick={connectWallet}>Connect Wallet</button>
{address && provider && (
<Personhood
sessionId="01234567-8901-2345-6789-012345678901"
onFinish={shared}
signCallback={sign}
walletAddress={address}
starknetChainId={provider.chainId}
chainType="STARKNET"
/>
)}
</div>
);
}
Cosmos Wallet (Keplr)
// src/App.tsx
import '@anima-protocol/personhood-sdk-react/style.css'
import { Personhood } from '@anima-protocol/personhood-sdk-react'
import { useState } from 'react'
export default function Example(): JSX.Element {
const [keplr, setKeplr] = useState<any>((window as any).keplr);
const shared = useCallback((e: { info: string }) => {
console.log('shared', e.info)
}, [])
return (
<div>
<button onClick={connectWallet}>Connect Wallet</button>
{address && provider && (
<Personhood
sessionId="01234567-8901-2345-6789-012345678901"
onFinish={shared}
cosmosConfig={keplr}
walletAddress={address}
chainType="COSMOS"
/>
)}
</div>
);
}
Cosmos Wallet (Leap)
// src/App.tsx
import '@anima-protocol/personhood-sdk-react/style.css'
import { Personhood } from '@anima-protocol/personhood-sdk-react'
import { useState } from 'react'
export default function Example(): JSX.Element {
const [leap, setLeap] = useState<any>((window as any).leap);
const shared = useCallback((e: { info: string }) => {
console.log('shared', e.info)
}, [])
return (
<div>
<button onClick={connectWallet}>Connect Wallet</button>
{address && provider && (
<Personhood
sessionId="01234567-8901-2345-6789-012345678901"
onFinish={shared}
cosmosConfig={leap}
walletAddress={address}
chainType="COSMOS"
/>
)}
</div>
);
}