API
Initializationβ
To setup the client you need to configure it with your projectId
which you can obtain from WalletConnect Cloud.
Furthremore you may need to configure the domain
and isLimited
parameters:
domain
defaults towindow.location.host
and must be set to the domain setup in Cloud Setup. For exampleapp.example.com
. Do not add the scheme (https://
).allApps
determines if your app has access to all of the user's subscriptions, or only the ones that the app is hosted on. By setting it totrue
, it enables settingdomain
to a value other thanwindow.location.host
. SettingallApps: true
can be useful during development to allow your localhost-deployed app to access the subscriptions for the domain you setup. Note that most apps do not need to set this in production environments, as they only need access to their own subscriptions. When enabled, the user has to sign a SIWE message granting your app more permissions, and this requires additional consideration from the user. Read here for more details.
- React
- JavaScript
initWeb3inboxClient({ projectId, domain, allApps, logLevel })
Referencesβ
- projectId: Your WalletConnect project ID
- domain (Optional): Your app's domain. Defaults to
window.location.host
. - allApps (Optional): Set to
true
to request access to all of the user's notification subscriptions for all apps, instead of onlydomain
. Defaults tofalse
. - logLevel (Optional): Increase verbosity of console logging. Defaults to
error
. Can be set toerror
,info
, ordebug
.
const client = await Web3InboxClient.init({ projectId, domain, allApps })
Referencesβ
- projectId: Your WalletConnect project ID
- domain (Optional): Your app's domain. Defaults to
window.location.host
. - allApps (Optional): Set to
false
to request access to all of the user's notification subscriptions for all apps, instead of onlydomain
. Defaults totrue
.
Managing Accountβ
Setting account for web3inboxβ
- React
- JavaScript
const {
data: account,
isRegistered,
identityKey,
setAccount,
error,
isLoading
} = useW3iAccount('eip155:1:0x9A...')
Referencesβ
- data: CAIP-10 account currently active in Web3Inbox
- setAccount: Change actively managed account in Web3Inbox. Does not need to be used as you can set the account directly in the params.
- isRegistered: A boolean of whether or not the account currently set is registered
- identityKey: Currently set account's identity key
- error: A string, representing possible error of setting an account.
- isLoading: A boolean, representing if an account is being set
await client.setAccount('eip155:1:0x9AfEaC202C837df470b5A145e0EfD6a574B21029')
const account = client.getAccount() // eip155:1:0x9AfEaC202C837df470b5A145e0EfD6a574B21029
client.watchAccount(account => {
console.log({ account }) // eip155:1:0x9AfEaC202C837df470b5A145e0EfD6a574B21029
})
Referencesβ
- account: CAIP-10 account currently active in Web3Inbox
- setAccount: Change actively managed account in Web3Inbox
- watchAccount: Watcher ticks whenever the account updates
Registering an accountβ
- React
- JavaScript
- 1 Click Auth
Note: EIP-1271 signatures coming from smart wallets are supported in version 1.1.0
and above.
import { useSignMessage } from '@wagmi'
const { signMessageAsync } = useSignMessage()
const { isRegistered } = useW3iAccount('eip155:1:0x9A...')
const { prepareRegistration } = usePrepareRegistration()
const { register, isLoading: isRegistering } = useRegister()
const handleRegistration = async () => {
try {
const { message, registerParams } = await prepareRegistration()
const signature = await signMessageAsync({ message: message })
await register({ registerParams, signature })
} catch (registerIdentityError: any) {
console.error(registerIdentityError)
}
}
Referencesβ
- isRegistered: A boolean of whether or not the account currently set is registered
- prepareRegistration: Prepare registration params
- register: Register using a signature and register params
- isLoading: A boolean, representing if an account is being registered
Some suggested methods of signing the message:
@wagmi/core
signMessage
method- The
useSignMessage
hook in@wagmi
- Ethers.js
Wallet.signMessage
method
With 1 Click Auth, you can avoid the secondary signature request needed for typical register
call. Instead, you can use a SIWE config like the one below for [Web3Modal SIWE](TODO LINK HERE WHEN ITS OUT OF ALPHA)
let registerParams: Awaited<ReturnType<Web3InboxClient['prepareRegistrationViaRecaps']>> | null =
null
export const getMessageParams = async (client: Web3InboxClient | null) => {
if (!client) {
throw new Error('Client not ready yet')
}
registerParams = await client.prepareRegistrationViaRecaps({
domain: window.location.hostname,
allApps: true
})
const { cacaoPayload } = registerParams
return {
chains: wagmiConfig.chains.map(chain => chain.id),
domain: cacaoPayload.domain,
statement: cacaoPayload.statement ?? undefined,
uri: cacaoPayload.uri,
resources: cacaoPayload.resources
}
}
export const createMessage = ({ address, ...args }: SIWECreateMessageArgs) => {
if (!registerParams) {
throw new Error("Can't create message if registerParams is undefined")
}
registerParams = {
...registerParams,
cacaoPayload: {
...registerParams?.cacaoPayload,
...args
}
}
const message = formatMessage(registerParams.cacaoPayload, address)
// statement is generated in format message and not part of original payload.
const statement = message.split('\n')[3]
registerParams.cacaoPayload.statement = statement
return message
}
export const getNonce = async () => {
return registerParams?.cacaoPayload.nonce ?? 'FAILED_NONCE'
}
export const getSession = async (client: Web3InboxClient | null) => {
const { address, chainId } = getAccount({ ...wagmiConfig })
await waitFor(async () => !!client)
const account = `eip155:${chainId}:${address}`
const identityKey = await client?.getAccountIsRegistered(account)
const invalidSession = !(address && chainId && identityKey)
if (invalidSession) throw new Error('Failed to get account')
return {
address,
chainId
}
}
const verifySiweMessage = async (params: SIWEVerifyMessageArgs, client: Web3InboxClient | null) => {
if (!client) {
throw new Error('Failed to verify message - no client')
}
if (!registerParams) {
throw new Error('Failed to verify message - no registerParams saved')
}
// Start signing the signature modal so it does not show up
// in sign 2.5
const account = composeDidPkh(
`${getChainIdFromMessage(params.message)}:${getAddressFromMessage(params.message)}`
)
if (await client.getAccountIsRegistered(account)) {
return true
}
// Unregister account if registered with a faulty registration.
try {
await client.unregister({ account })
} catch (e) {}
await client.register({
registerParams: {
allApps: true,
cacaoPayload: {
...registerParams.cacaoPayload,
...params.cacao?.p,
iss: account
},
privateIdentityKey: registerParams.privateIdentityKey
},
signature: params.signature
})
return true
}
export const verifyMessage = async (
params: SIWEVerifyMessageArgs,
client: Web3InboxClient | null
) => {
try {
const messageIsValid = await verifySiweMessage(params, client)
const account = `${getChainIdFromMessage(params.message)}:${getAddressFromMessage(params.message)}`
if (messageIsValid) {
await waitFor(() => client!.getAccountIsRegistered(account))
}
return messageIsValid
} catch (e) {
return false
}
}
Referencesβ
- isRegistered: A boolean of whether or not the account currently set is registered
- prepareRegistration: Prepare registration params
- register: Register using a signature and register params
- isLoading: A boolean, representing if an account is being registered
Some suggested methods of signing the message:
@wagmi/core
signMessage
method- The
useSignMessage
hook in@wagmi
- Ethers.js
Wallet.signMessage
method
import { signMessageAsync } from '@wagmi/core'
const { registerParams, signature } = await client.prepareRegistration({
account
})
const isRegistered = await client.getAccountIsRegistered(account)
const signature = await signMessageAsync({ message })
await register({ registerParams, signature })
Referencesβ
- prepareRegistration: Prepare registration params
- register: Register using a signature and register params
- getAccountIsRegistered: Returns if account is registered
Some suggested methods of signing the message:
- Ethers.js
Wallet.signMessage
method @wagmi/core
signMessage
method- The
useSignMessage
hook in@wagmi
Managing Subscriptionβ
Subscribe, Unsubscribe, Get Subscription, Check if Subscribed.
When using differentAccount
, the passed account needs to be previously registered.
This use case is for Dapps that have multile active accounts or wallets with multiple active accounts.
differentAccount
can be used for all the below hooks and functions that accept account
- React
- JavaScript
const { subscribe, isLoading: isSubscribing } = useSubscribe()
const { unsubscribe, isLoading: isUnsubscribing } = useUnsubscribe()
// get subscription of current user to current dapp
const { data: subscription, getSubscription } = useSubscription()
// getSubscription can be used to get information about different dapps programatically
const subscriptionToSameDappFromDifferentAccount = getSubscription(differentAccount)
const subscriptionToDifferentDappFromSameAccount = getSubscription(undefined, differentDappDomain)
const subscriptionToDifferentDappFromDifferentAccount = getSubscription(
differentAccount,
differentDappDomain
)
// subscribe to current dapp from current user
subscribe()
// subscribe to current dapp from different user
subscribe(differentAccount)
// subscribe to different dapp from current user
subscribe(undefined, differentDappDomain)
// subscribe to different dapp from different user
subscribe(differentAccount, differentDappDomain)
// unsubscribe from current dapp
unsubscribe()
// get all subscriptions for current account
const subscriptions = useAllSubscriptions()
const isSubscribed = Boolean(subscription)
Referencesβ
- account (Optional): CAIP-10 account
- domain (Optional): dapp domain
- subscribe: Function to subscribe to current dApp
() => void
- unsubscribe: Function to unsubscribe to current dApp
() => void
- isSubscribed: Reactive state, checking if subscribed to dApp
Boolean
- isSubscribing: If
subscribe()
is in-progress and has not finished yet - isUnsubscribing: If
unsubscribe()
is in-progress and has not finished yet - subscription: Reactive state, returning current subscription information, of type:
{
topic: string
account: string
relay: relayertypes.protocoloptions
metadata: Metadata
scope: ScopeMap
expiry: number
symkey: string
unreadCount: number
}
- subscriptions: Reactive state, returning array of current subscriptions
// check if current account is subscribed to current dapp
const isSubscribed = client.isSubscribedToDapp()
// watch if current account is subscribed to current dapp
client.watchIsSubscribed(isSubbed => console.log({ isSubbed }))
// subscribe to current dapp with current account
await client.subscribeToDapp()
// subscribe to same dapp with different account
await client.subscribeToDapp(differentAccount)
// subscribe to different dapp with current account
await client.subscribeToDapp(undefined, differentDomain)
// subscribe to different dapp with different account
await client.subscribeToDapp(differentAccount, differentDomain)
// unsubscribe from current dapp with current account
await client.unsubscribeFromDapp()
// get current account's subscription to current dapp
const subscription = client.getSubscription()
// watch current account's subscription to current dapp
client.watchSubscription(subscription => console.log({ subscription }))
// get current account's subscriptions
const subscriptions = client.getSubscriptions()
// watch current account's subscriptions
client.watchSubscriptions(subscriptions => console.log({ subscriptions }))
Referencesβ
- account (Optional): CAIP-10 account
- domain (Optional): dapp domain
- subscription: Non-Reactive state, returning current subscription information, of type:
{
topic: string
account: string
relay: relayertypes.protocoloptions
metadata: Metadata
scope: ScopeMap
expiry: number
symkey: string
unreadCount: number
}
- subscription: Non-Reactive state, returning array of current subscriptions
Managing Notificationsβ
Get notifications
- React
- JavaScript
// watch notifications of current account's subscription to current dapp
const notificationsPerPage = 5
const isInfiniteScroll = true
const unreadFirst = true
const {
data: notifications,
nextPage,
markNotificationsAsRead,
markAllNotificationsAsRead
} = useNotifications(
notificationsPerPage,
isInfiniteScroll,
account,
domain,
unreadFirst,
onRead // optional function to run whenever messages are read
)
// marking a single notification as read
await notifications[0].markAsRead();
// mark specific notifications as read for default account and under default domain
await markNotificationsAsRead(notifications.slice(2).map(n => n.id));
// mark specific notifications as read for specified account under default domain
await markNotificationsAsRead(notifications.slice(2).map(n => n.id), differentAccount);
// mark specific notifications as read for default account under specified domain
await markNotificationsAsRead(notifications.slice(2).map(n => n.id), undefined, differentDomain);
// mark specific notifications as read for specified account under specified domain
await markNotificationsAsRead(notifications.slice(2).map(n => n.id), differentAccount, differentDomain);
// mark all notifications as read for default account under default domain
await markAllNotificationsAsRead();
// mark all notifications as read for specified account under default domain
await markAllNotificationsAsRead(differentAccount);
// mark all notifications as read for default account under specified domain
await markAllNotificationsAsRead(undefined, differentDomain);
// mark all notifications as read for specified account under specified domain
await markAllNotificationsAsRead(differentAccount, differentDomain);
Referencesβ
- useNotifications()
- notificationsPerPage: Number representing how many notifications to get per fetch
- isInfiniteScroll: Whether or not to keep already fetched notifications when getting next page
- params: (optional) Additional parameters
- unreadFirst: (optional, default
true
, since 1.3.0) Whether or not unread messages should be sorted at the top, regardless of timestamp
- nextPage: A function to be called to fetch the next page of notifications
- notifications: Array of notifications, of type
- notification.read: Mark the notification as read
- markNotificationsAsRead: Takes an array of notification IDs and marks them as read. Max 1000 IDs
- markAllNotificationsAsRead: Mark all notifications as read.
{
title: string
sentAt: number
body: string
id: string
isRead: boolean
url: string | null
type: string
markAsRead: () => Promise<void>
}
You can retrieve notifications using pagination. One approach is to provide the last notification's ID as the starting point:
const notificationsPage = client.getNotificationHistory({
limit: 3,
// The `id` of the last notification, for example:
startingAfter: 'some-notification-id'
})
const notificationsPerPage = 5
const isInfiniteScroll = true
const unreadFirst = true
let notifications = []
const onUpdate = ({notifications: fetchedNotifications}: GetNotificationsReturn) => {
notifications = fetchedNotifications
}
const {
nextPage,
markNotificationAsRead,
markAllNotificationsAsRead
} = client.pageNotifications(
notificationsPerPage,
isInfiniteScroll,
specifiedAccount // OR undefined,
specifiedDomain // OR undefined,
unreadFirst
)(onUpdate)
// marking a single notification as read
await notifications[0].markAsRead();
// mark specific notifications as read
await markNotificationsAsRead(notifications.slice(2).map(n => n.id));
// mark all notifications as read
await markAllNotificationsAsRead();
Referencesβ
- pageNotifications:
- notificationsPerPage: Number representing how many notifications to get per fetch
- isInfiniteScroll: Whether or not to keep already fetched notifications when getting next page
- *params: (optional) Additional parameters
- unreadFirst: (optional, default
true
, since 1.3.0) Whether or not unread messages should be sorted at the top, regardless of timestamp
- onUpdate:: A callback that will be called whenever notifications get updated
- nextPage:: A function to be called to fetch the next page of notifications
- notifications: Array of notifications, of type
- notification.markAsRead: Mark the notification as read
- markNotificationsAsRead: Takes an array of notification IDs and marks them as read. Max 1000 IDs
- markAllNotificationsAsRead: Mark all notifications as read.
{
title: string
sentAt: number
body: string
id: string
isRead: boolean // since 1.3.0
url: string | null
type: string
read: () => Promise<void> // since 1.3.0
}
Notification Typesβ
Manage and fetch notification types.
- React
- JavaScript
const { data: types, update } = useNotificationTypes()
Referencesβ
- update:
(enabledScopeNames: string[]) -> void
- types: Map of scopes (Notification types)
type ScopeMap = Record<
string,
{
name: string
description: string
enabled: boolean
}
>
// get scopes of current account's subscription to current dapp
const types = client.getNotificationTypes()
// watch scopes of specific account's subscription to specific dapp
client.watchNotificationTypes(scp => {
console.log(scp)
})
client.update(['enabledType-1', 'enabledType-2'])
Referencesβ
- update:
(enabledScopeNames: string[]) -> void
- types: Map of scopes (Notification types)
type ScopeMap = Record<
string,
{
name: string
description: string
enabled: boolean
}
>
Registering for Device Push Notificationsβ
If you wish to receive live push notifications to your React Native or Web app, you must integrate with Firebase Messaging. More information about how to integrate with Firebase can be found here.
Your integration will obtain a token from Firebase and you will need to pass this token to the Web3Inbox SDK using the registerWithPushServer()
function.
- React
- JavaScript
import { getToken } from 'firebase/messaging'
const { data: client } = useWeb3InboxClient()
// initialize Firebase's messaging object via Firebase's `getMessaging` function
const firebaseToken = getToken(firebaseMessaging, {
vapidKey: 'YOUR_FIREBASE_VAPID_KEY'
})
client.registerWithPushServer(firebaseToken)
Referencesβ
registerWithPushServer
:(token: string, platform: 'fcm' | 'apns' = 'fcm') => void
Either APNs or FCM can be used to receive push notifications to the device. The token
you provide may be a token from either platform, provided the platform
argument matches.
import { getToken } from 'firebase/messaging
// initialize Firebase's messaging object via Firebase's `getMessaging` function
const firebaseToken = getToken(firebaseMessaging, {
vapidKey: "YOUR_FIREBASE_VAPID_KEY"
})
// The Client ID that registered with this token, can be used for debugging purposes or logs
const clientId = client.registerWithPushServer(firebaseToken)
Referencesβ
registerWithPushServer
:(token: string, platform: 'fcm' | 'apns') => string
Either APNS or FCM can be used to recieve push notifications. Token here is the respective platform's token.
- React
- JavaScript
Listening For Eventsβ
This can be used to listen to, for example, messages recieved in realtime.
const { data: client } = useWeb3InboxClient()
client.on('notify_message', ({ message }) => {
console.log(notification.title)
})
Referencesβ
message
: Notification of type:
interface NotifyNotification {
title: string
sentAt: number
body: string
id: string
url: string | null
type: string
}
client.on('notify_message', ({ notification }) => {
console.log(notification.title)
})
Referencesβ
message
: Notification of type:
interface NotifyNotification {
title: string
sentAt: number
body: string
id: string
url: string | null
type: string
}
Was this helpful?