# Home Source: https://docs.sequence.xyz/home
Build with Sequence

The modular crypto infrastructure stack that unifies wallets, 1-click cross-chain payments, and real-time data layers across EVMs.

Quickstarts & Boilerplates

Spin up a React app with social/email auth and a non-custodial wallet. Launch a wallet on your domain with passkeys, social auth, and time-lock recovery. Use Trails SDK to enable 1-click cross-chain payments with any wallet. Fetch live token balances for wallets and contracts across EVMs, plus webhooks. Launch a hosted primary-sale storefront with built-in checkout. Explore all available templates and starter projects.

Explore SDKs

Integrate wallets and auth in React, Next.js, or Vue. One-click, cross-chain checkout and funding flows. React Native wallets for iOS and Android apps. Wallets, Indexer, payments, and marketplace tools for Unity. } href="/sdk/unreal"> Wallets, Indexer, payments, and marketplace tools for Unreal.

Explore APIs & Backend SDKs

Real-time balances and activity across any EVM, plus webhooks. Send transactions with gas sponsorship and auto estimation. Aggregated listings and sales data for NFT collections. Access any Sequence service from Go. Access any Sequence service from Node.js. Dockerized backend for simplified blockchain reads/writes with secure key management.
# Overview Source: https://docs.sequence.xyz/sdk/overview Overview of the various SDKs available for integrating with the Sequence developer platform. Sequence provides multiple SDKs to help you integrate blockchain functionality into your applications across different platforms and languages.

Javascript

A complete web3 development stack for building apps and games on Ethereum chains. Includes wallet integration, transaction management, and smart contract interactions.

Web SDKs

React components and hooks for easy integration of Sequence Wallet, Marketplace, Checkout, API, Wallet Widget and more.

Unity

Custom-built SDK for Unity game development, providing lightweight Ethereum integration and wallet functionality optimized for gaming applications.

Unreal

Native SDK for Unreal Engine, enabling seamless blockchain integration for games. Features wallet connectivity, transaction handling, and authentication systems.

Go

Full-featured SDK for Go/Golang backends, powering Sequence's own infrastructure. Includes wallet management, transaction handling, and Ethereum interactions.

Mobile

React Native SDK for building mobile applications with complete Sequence Embedded Wallet and Indexer integration.

## Key Features * **Multi-Platform Support**: Build applications across web, mobile, and game platforms * **Wallet Integration**: Easy-to-use wallet connectors for popular frameworks * **Smart Contract Interaction**: Tools for deploying and interacting with smart contracts * **Transaction Management**: Simplified transaction creation, signing, and sending * **Type Safety**: Strong typing support in TypeScript and Go implementations * **Extensive Documentation**: Detailed guides and API references for each SDK ### Feature Comparison This table provides a high-level comparison of the features available in the Sequence Headless Wallet, Web, Unity, and Unreal SDKs. | Feature | Typescript Wallet SDK | Web SDK (React) | Unity SDK | Unreal SDK | | :------------------- | :------------------------- | :------------------------------ | :------------------------- | :------------------------- | | **Target Platform** | Web (Headless) | Web (React) | Unity | Unreal Engine | | **UI Components** | No | Yes (Pre-built, Customizable) | Prefabs | Prefabs | | **Authentication** | Yes (Email, Social, Guest) | Yes (Email, Social, Guest) | Yes (Email, Social, Guest) | Yes (Email, Social, Guest) | | **Wallet Support** | Embedded / Ecosystem | Embedded / Ecosystem / External | Embedded / Ecosystem | Embedded / Ecosystem | | **Inventory** | No | Yes | Yes | Yes | | **On-Ramp** | No | Via Wallet UI | Via Prefabs | Via Prefabs | | **Integrated Swaps** | No | Yes | Yes | Yes | | **Checkout** | No | Yes | Yes | Yes | **Note:** Features listed as "Via Core SDK" or similar mean that while the specific SDK might not implement the feature directly, it relies on underlying Sequence services or the core TypeScript SDK to provide that functionality, often facilitated by the integrated wallet experience. ## Getting Started Choose the SDK that best matches your platform and development needs: * For web applications: * Use our [Web SDKs](/sdk/web/overview) for React applications * Use the [TypeScript SDK](/sdk/typescript/overview) for core functionality For game development: * Use the [Unity SDK](/sdk/unity/overview) for Unity games * Use the [Unreal SDK](/sdk/unreal/overview) for Unreal Engine games For backend services, check out the [Go SDK](/sdk/go/overview) For mobile apps, explore the [React Native SDK](/sdk/mobile) ## Support Need help choosing or implementing an SDK? Join our [Discord community](https://discord.gg/sequence) for support and discussions. # Web SDKs Source: https://docs.sequence.xyz/sdk/web/overview A comprehensive toolkit of Web3 SDKs that seamlessly integrate into your application. We provide your users with a smooth and secure onboarding experience. With our robust tools built on the popular [wagmi](https://wagmi.sh/) library, unlock a realm of possibilities in the world of web3. Our toolkit includes: * [@0xsequence/connect](https://www.npmjs.com/package/@0xsequence/connect) * [@0xsequence/checkout](https://www.npmjs.com/package/@0xsequence/checkout) * [@0xsequence/hooks](https://www.npmjs.com/package/@0xsequence/hooks) * [@0xsequence/wallet-widget](https://www.npmjs.com/package/@0xsequence/wallet-widget) * [@0xsequence/marketplace-sdk](https://www.npmjs.com/package/@0xsequence/marketplace-sdk) ## Key Features * **Seamless Auth**: Connect via popular social logins such as Google, Apple, Facebook or use email, passkeys or any external wallet! * **Ecosystem Wallet**: A cross-application and self-custodial smart contract wallet that users can create to interact with any application on the Ecosystem. * **Smart Sessions**: Allow users to pre-approve a set of granular permissions, enabling a fluid experience or powerful automation, all while maintaining user security and self-custody. * **Swap Hooks**: Easily plug in our swap hooks to your application to enable token swaps. * **Link Wallets**: Allow your users to link multiple wallets to their account. * **Chain Abstraction**: Build a chain abstracted experience by using our hooks to fetch multi-chain balances, coin prices, transactions and more. * **Web3 Inventory**: Provide your users with a web3-enabled inventory, enabling them to manage their coins and collectibles all within your own application. * **NFT Checkout**: Enable users to purchase collectibles within Sequence Checkout using a credit card or crypto. * **Wallet Widget**: A production ready wallet widget with built-in swap, transaction history, inventory, fiat onramp and more. /sdk/web/wallet-sdk/embedded/overview * **Customizability**: Brand the connect modal with your own logo, color scheme and configure it with your social providers and wallets you want to service. * **Marketplace UI & Hooks**: Easiest way to build your own Web3 Marketplace without managing infrastructure. Explore the potential of our Web SDK's by trying out our [demo](https://0xsequence.github.io/web-sdk/)! ## Next Steps Connect your users to your application with social auth, email, passkeys or external wallets. The easiest way to checkout NFTs and other assets using a credit card or crypto. Use our extensive toolkit of hooks to query coin prices, swap routes, swap quotes, balances, history and more by leveraging the Sequence API and Indexer. Get a production ready wallet widget with built-in swap, transaction history, inventory, fiat onramp and more with a few lines of code. Build your own Web3 Marketplace by using Sequence's Aggregated Marketplace technology with React Hooks and pre-built UI components. Ready to onboard users into your app ? Start with the [Ecosystem Wallet (v6)](/sdk/web/wallet-sdk/ecosystem/getting-started). # Getting started Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/ecosystem/getting-started Learn how to get started with Ecosystem Wallet Web SDK First make sure you have created a Sequence Project account, if you don't have one, you can create one [here](https://sequence.build/), you will need your `Project Access Key` in order to continue. Our Web SDKs are built on top of wagmi, so for advanced configurations, sending transactions, calling contracts, etc., please refer to the [wagmi documentation](https://wagmi.sh/react/WagmiConfig). ```bash theme={null} npm install @0xsequence/connect wagmi viem # or pnpm install @0xsequence/connect wagmi viem # or yarn add @0xsequence/connect wagmi viem ``` Next, create the Ecosystem Wallet configuration. **Required for Ecosystem Wallet** * `projectAccessKey` * `walletUrl` **Optional** * `dappOrigin` * `signIn.projectName`, `appName` * `chainIds`, `defaultChainId` * `explicitSession` (optional; request explicit session permissions + limits) * `includeFeeOptionPermissions`, `enableImplicitSession` * `nodesUrl`, `relayerUrl` * `walletConnect` ```typescript [config.ts] theme={null} import { createConfig, createExplicitSession } from "@0xsequence/connect"; export const config: any = createConfig({ projectAccessKey: "AQAAAAAAAABtDHG1It7lxRF_9bbxw4diip8", walletUrl: 'https://acme-wallet.ecosystem-demo.xyz', // Optional dappOrigin: window.location.origin, signIn: { projectName: 'Sequence Web SDK Demo' }, appName: 'Sequence Web SDK Demo', chainIds: [42161], defaultChainId: 42161, google: true, apple: true, email: true, explicitSession: createExplicitSession({ ... }) }); ``` The `walletUrl` is the URL of the Ecosystem Wallet your dApp will use, for our demo, we are using the [Acme Ecosystem Wallet](https://acme-wallet.ecosystem-demo.xyz). The `dappOrigin` is the origin of your dapp, used to verify where the user is coming from. The `explicitSession` object allows your dapp to request specific permissions from the user upon connection. These permissions can authorize your dapp to perform certain actions on the user's behalf for a defined period, creating a more seamless user experience with no transaction prompts or allowing automations. See: [Permissions Deep Dive](/sdk/web/wallet-sdk/ecosystem/permissions-deep-dive) and [Token Directory](/sdk/web/wallet-sdk/ecosystem/token-directory). ### Fee options behavior (important) When your app sends transactions via Sequence relaying, the relayer needs to determine **how fees are paid**. * If you want the SDK to automatically request the necessary fee-related permissions when creating an explicit session, enable `includeFeeOptionPermissions`. * If you disable it, you are responsible for including whatever fee-related permissions are required for the fee option you expect to use. If fee payment cannot be satisfied, transactions may fail at dispatch time even if the core contract-call permission looks correct. `nativeTokenSpending` is optional. If omitted, the session will default to no native-token spending allowance. For example, let's create an explicit session that allows your dapp to `deposit 100 USDC into the AAVE V3 pool on Arbitrum, on behalf of the user for the next 24 hours` ```typescript [config.ts] theme={null} import { createConfig, createContractPermission } from "@0xsequence/connect"; import { parseEther, parseUnits } from "viem"; export const USDC_ADDRESS_ARBITRUM = '0xaf88d065e77c8cC2239327C5EDb3A432268e5831' export const AAVE_V3_POOL_ADDRESS_ARBITRUM = '0x794a61358D6845594F94dc1DB02A252b5b4814aD' export const config: any = createConfig({ projectAccessKey: "AQAAAAAAAABtDHG1It7lxRF_9bbxw4diip8", walletUrl: 'https://acme-wallet.ecosystem-demo.xyz', // Optional dappOrigin: window.location.origin, signIn: { projectName: 'Sequence Web SDK Demo', }, appName: 'Sequence Web SDK Demo', chainIds: [42161], defaultChainId: 42161, google: true, apple: true, email: true, explicitSession: createExplicitSession({ chainId: 42161, nativeTokenSpending: { valueLimit: parseEther('0.01'), // Allow spending up to 0.01 ETH for gas fees }, expiresIn: { hours: 24, // Session lasts for 24 hours }, permissions: [ createContractPermission({ address: AAVE_V3_POOL_ADDRESS_ARBITRUM, functionSignature: 'function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode)', rules: [ { param: 'asset', type: 'address', condition: 'EQUAL', value: USDC_ADDRESS_ARBITRUM }, { param: 'amount', type: 'uint256', condition: 'LESS_THAN_OR_EQUAL', value: parseUnits('100', 6), // Max cumulative amount of 100 USDC cumulative: true } ] }) ] }) }); ``` When a user connects their wallet, they will be prompted to grant permissions to the dApp. Once approved, actions like supplying USDC to AAVE can be executed without requiring additional pop-ups, and can even be automated while the user is offline. Wrap your application with the `SequenceConnect` Provider to enable the use of the package’s hooks and components throughout your application. The configuration we created in [step 2](/sdk/web/wallet-sdk/ecosystem/getting-started#create-a-config) needs to be passed into the `config` of the provider. ```typescript [main.tsx] theme={null} import React from "react"; import ReactDOM from "react-dom/client"; import "./index.css"; import App from "./App"; import { config } from "./config"; import { SequenceConnect } from "@0xsequence/connect"; function Dapp() { return ( ); } ReactDOM.createRoot(document.getElementById("root")!).render( ); export default Dapp ``` ```typescript [App.tsx] theme={null} import './App.css' import { useOpenConnectModal } from '@0xsequence/connect' function App() { const {setOpenConnectModal} = useOpenConnectModal() return ( <> ) } export default App ``` The user will be prompted to approve the permissions when connecting. Main dashboard interface ```bash theme={null} npm install @0xsequence/connect wagmi viem # or pnpm install @0xsequence/connect wagmi viem # or yarn add @0xsequence/connect wagmi viem ``` Next, create the Ecosystem Wallet configuration. **Required for Ecosystem Wallet** * `projectAccessKey` * `walletUrl` **Optional** * `dappOrigin` * `signIn.projectName`, `appName` * `chainIds`, `defaultChainId` * `explicitSession` (optional; request explicit session permissions + limits) * `includeFeeOptionPermissions`, `enableImplicitSession` * `nodesUrl`, `relayerUrl` * `walletConnect` ```typescript [config.ts] theme={null} import { createConfig, createExplicitSession } from "@0xsequence/connect"; export const config: any = createConfig({ projectAccessKey: "AQAAAAAAAABtDHG1It7lxRF_9bbxw4diip8", signIn: { projectName: 'Sequence Web SDK Demo', }, walletUrl: 'https://acme-wallet.ecosystem-demo.xyz', dappOrigin: window.location.origin, appName: 'Sequence Web SDK Demo', chainIds: [42161], defaultChainId: 42161, google: true, apple: true, email: true, explicitSession: createExplicitSession({ ... }) }); ``` The `walletUrl` is the URL of the Ecosystem Wallet you dApp will use, for our demo, we are using the [Acme Ecosystem Wallet](https://acme-wallet.ecosystem-demo.xyz). The `dappOrigin` is the origin of your dapp, used to verify where the user is coming from. The `explicitSession` object allows your dapp to request specific permissions from the user upon connection. These permissions can authorize your dapp to perform certain actions on the user's behalf for a defined period, creating a more seamless user experience with no transaction prompts. `nativeTokenSpending` is optional. If omitted, the session will default to no native-token spending allowance. For example, let's create an explicit session that allows your dapp to `deposit 100 USDC into the AAVE V3 pool on Arbitrum, on behalf of the user for the next 24 hours` ```typescript [config.ts] theme={null} import { createConfig, createContractPermission } from "@0xsequence/connect"; import { parseEther, parseUnits } from "viem"; export const USDC_ADDRESS_ARBITRUM = '0xaf88d065e77c8cC2239327C5EDb3A432268e5831' export const AAVE_V3_POOL_ADDRESS_ARBITRUM = '0x794a61358D6845594F94dc1DB02A252b5b4814aD' export const config: any = createConfig({ projectAccessKey: "AQAAAAAAAABtDHG1It7lxRF_9bbxw4diip8", signIn: { projectName: 'Sequence Web SDK Demo', }, walletUrl: 'https://acme-wallet.ecosystem-demo.xyz', dappOrigin: window.location.origin, appName: 'Sequence Web SDK Demo', chainIds: [42161], defaultChainId: 42161, google: true, apple: true, email: true, explicitSession: createExplicitSession({ chainId: 42161, nativeTokenSpending: { valueLimit: parseEther('0.01'), // Allow spending up to 0.01 ETH for gas fees }, expiresIn: { hours: 24, // Session lasts for 24 hours }, permissions: [ createContractPermission({ address: AAVE_V3_POOL_ADDRESS_ARBITRUM, functionSignature: 'function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode)', rules: [ { param: 'asset', type: 'address', condition: 'EQUAL', value: USDC_ADDRESS_ARBITRUM }, { param: 'amount', type: 'uint256', condition: 'LESS_THAN_OR_EQUAL', value: parseUnits('100', 6), // Max cumulative amount of 100 USDC cumulative: true } ] }) ] }) }); ``` When a user connects their wallet, they will be prompted to grant permissions to the dApp. Once approved, actions like supplying USDC to AAVE can be executed without requiring additional pop-ups, and can even be automated while the user is offline. Wrap your application with the `SequenceConnect` Provider to enable the use of the package’s hooks and components throughout your application. The configuration we created in [step 2](/sdk/web/wallet-sdk/ecosystem/getting-started#create-a-config) needs to be passed into the `config` of the provider. ```typescript [src/app/providers.tsx] theme={null} "use client"; import React from "react" import { config } from "./config" import { SequenceConnect } from "@0xsequence/connect" const Providers = ({ children }: { children: React.ReactNode }) => { return ( {children} ) } export default Providers; ``` Wrap your app in the Providers component. ```typescript [src/app/layout.tsx] theme={null} import type { Metadata } from "next"; import { Geist, Geist_Mono } from "next/font/google"; import "./globals.css"; import Providers from "./providers"; const geistSans = Geist({ variable: "--font-geist-sans", subsets: ["latin"], }); const geistMono = Geist_Mono({ variable: "--font-geist-mono", subsets: ["latin"], }); export const metadata: Metadata = { title: "Create Next App", description: "Generated by create next app", }; export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { return ( {children} ); } ``` ```typescript [App.tsx] theme={null} "use client" import { useOpenConnectModal } from '@0xsequence/connect' function Home() { const { setOpenConnectModal } = useOpenConnectModal() return ( <> ) } export default Home ``` The user will be prompted to approve the permissions when connecting. Main dashboard interface # useChain Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/ecosystem/hooks/useChain Hook for retrieving chain configuration information ## Import ```tsx theme={null} import { useChain } from '@0xsequence/connect' ``` ## Usage ```tsx theme={null} import { useChain } from '@0xsequence/connect' function App() { // Get current chain configuration const currentChain = useChain() // Get configuration for a specific chain (e.g., Ethereum Mainnet) const ethereumChain = useChain(1) return (

Current Chain

{currentChain && (

Name: {currentChain.name}

Chain ID: {currentChain.id}

Network: {currentChain.network}

Native Currency: {currentChain.nativeCurrency.symbol}

)}

Ethereum Mainnet

{ethereumChain && (

Name: {ethereumChain.name}

Chain ID: {ethereumChain.id}

Network: {ethereumChain.network}

Native Currency: {ethereumChain.nativeCurrency.symbol}

)}
) } ``` ## Parameters | Parameter | Type | Description | | --------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------ | | `chainId` | `number \| undefined` | Optional chain ID to get configuration for a specific chain. If not provided, returns the current chain's configuration. | ## Return Type: `Chain | undefined` The hook returns a `Chain` object from wagmi's chain configurations or `undefined` if the chain is not found. ```tsx theme={null} interface Chain { id: number name: string network: string nativeCurrency: { name: string symbol: string decimals: number } rpcUrls: { default: { http: string[] webSocket?: string[] } public: { http: string[] webSocket?: string[] } } blockExplorers?: { default: { name: string url: string } } // ... other chain-specific properties } ``` ### Properties #### id `number` The unique identifier of the blockchain network. #### name `string` The human-readable name of the blockchain network. #### network `string` The network identifier string. #### nativeCurrency `object` Information about the chain's native currency. ```tsx theme={null} { name: string // Full name of the currency symbol: string // Currency symbol decimals: number // Number of decimal places } ``` #### rpcUrls `object` URLs for connecting to the network's RPC endpoints. #### blockExplorers `object | undefined` Information about block explorers for the chain. ## Notes This hook provides easy access to chain configuration information from wagmi's chain configurations. It's particularly useful when you need to: * Access details about the currently connected chain * Get configuration for a specific chain by ID * Retrieve chain-specific information like: * Network details * Native currency information * RPC endpoints * Block explorer URLs The hook is commonly used in conjunction with other Sequence hooks when working with transactions, indexer clients, or network-specific features. # useExplicitSessions Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/ecosystem/hooks/useExplicitSessions Hook for managing explicit sessions for Sequence V3 wallet connections ## Import ```tsx theme={null} import { useExplicitSessions } from '@0xsequence/connect' ``` ## Usage ```tsx theme={null} import { createContractPermission, useExplicitSessions, type ExplicitSessionParams, type ExplicitSession } from '@0xsequence/connect' import { useEffect, useState } from 'react' import { parseUnits } from 'viem' function App() { const { isLoading, error, addExplicitSession, modifyExplicitSession, getExplicitSessions } = useExplicitSessions() const [sessions, setSessions] = useState([]) // Load existing sessions useEffect(() => { const loadSessions = async () => { try { const existingSessions = await getExplicitSessions() setSessions(existingSessions) } catch (err) { console.error('Failed to load sessions:', err) } } loadSessions() }, [getExplicitSessions]) // Function to handle modifying an existing explicit session const handleModifySession = () => { const newPermission = createContractPermission({ address: '0x...', functionSignature: 'function testContract() public' }) const currentSession = sessions[0] const modifiedSession = { ...currentSession, permissions: [...currentSession.permissions!, newPermission] } modifyExplicitSession(modifiedSession) } // Handle creating a new explicit session const handleCreateSession = async () => { try { const tokenSpendingSession: ExplicitSessionParams = { chainId: 42161, nativeTokenSpending: { valueLimit: 0n, }, expiresIn: { days: 3 }, permissions: [ createContractPermission({ address: '0x...', functionSignature: 'function transfer(address to, uint256 amount)', rules: [ { param: 'amount', type: 'uint256', condition: 'LESS_THAN_OR_EQUAL', value: parseUnits('100', 6), // Max cumulative amount of 100 USDC cumulative: true } ] }) ] } await addExplicitSession(tokenSpendingSession) // Refresh sessions after creating a new one const updatedSessions = await getExplicitSessions() setSessions(updatedSessions) } catch (err) { console.error('Failed to create session:', err) } } if (isLoading) { return
Creating session...
} if (error) { return
Error: {error.message}
} return (

Explicit Sessions

Existing Sessions ({sessions.length})

{sessions.map((session, index) => (

Session Address: {session.sessionAddress}

Chain ID: {session.chainId}

Permissions: {session.permissions?.map(permission => permission.target).join(', ')}

))}
) } ``` ## Return Type The hook returns an object with the following properties: ```tsx theme={null} type UseExplicitSessionsReturnType = { isLoading: boolean error: Error | null addExplicitSession: (params: ExplicitSessionParams, includeFeeOptionPermissions?: boolean) => Promise modifyExplicitSession: (explicitSession: ExplicitSession) => Promise getExplicitSessions: () => Promise } ``` ### Properties #### isLoading `boolean` A boolean indicating if the session request operation is in progress. #### error `Error | null` An error object if the last operation failed, otherwise `null`. #### addExplicitSession `(params: ExplicitSessionParams, includeFeeOptionPermissions?: boolean) => Promise` ```typescript theme={null} type ExplicitSession = { sessionAddress: Address.Address valueLimit: bigint deadline: bigint permissions: Permission.Permission[] chainId: number type: 'explicit' } ``` Function to create a new explicit session. #### modifyExplicitSession `(explicitSession: ExplicitSession) => Promise` ```typescript theme={null} type ExplicitSession = { sessionAddress: Address.Address valueLimit: bigint deadline: bigint permissions: Permission.Permission[] chainId: number type: 'explicit' } ``` Function to modify an existing explicit session. #### getExplicitSessions `() => Promise` Function to get all explicit sessions for the connected wallet. ## Notes This hook provides functionality for managing explicit sessions in Sequence V3 wallet connections. Key features: * Create new explicit sessions with custom permissions and spending limits * Retrieve all existing explicit sessions for the connected wallet * Modify existing explicit sessions * Built-in error handling for common connection issues * Loading states for better user experience * Automatic session filtering to only show explicit sessions # useFeeOptions Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/ecosystem/hooks/useFeeOptions Hook for handling fee options for unsponsored transactions ## Import ```tsx theme={null} import { useFeeOptions } from '@0xsequence/connect' import { zeroAddress } from 'viem' ``` ## Usage ```tsx theme={null} import { useFeeOptions } from '@0xsequence/connect' import { useEffect, useState } from 'react' function App() { // Use the hook with default balance checking // This will return the wallet balance for each fee option const [ pendingFeeOptionConfirmation, confirmPendingFeeOption, rejectPendingFeeOption ] = useFeeOptions() // Or skip balance checking if needed // const [pendingFeeOptionConfirmation, confirmPendingFeeOption, rejectPendingFeeOption] = // useFeeOptions({ skipFeeBalanceCheck: true }) const [selectedFeeOptionTokenAddress, setSelectedFeeOptionTokenAddress] = useState() // Initialize with first option when fee options become available useEffect(() => { if (pendingFeeOptionConfirmation) { console.log('Pending fee options: ', pendingFeeOptionConfirmation.options) // You could select the first fee option by default if (pendingFeeOptionConfirmation.options.length > 0) { const firstOption = pendingFeeOptionConfirmation.options[0] setSelectedFeeOptionTokenAddress(firstOption.token.contractAddress || '') } } }, [pendingFeeOptionConfirmation]) // Handle fee option selection and confirmation const handleConfirmFee = (tokenAddress: string) => { if (pendingFeeOptionConfirmation) { confirmPendingFeeOption(pendingFeeOptionConfirmation.id, tokenAddress) } } // Handle fee option rejection const handleRejectFee = () => { if (pendingFeeOptionConfirmation) { rejectPendingFeeOption(pendingFeeOptionConfirmation.id) } } // Render fee options UI if (pendingFeeOptionConfirmation) { return (

Select Fee Payment Token

{pendingFeeOptionConfirmation.options.map((option) => (
setSelectedFeeOptionTokenAddress(option.token.contractAddress || zeroAddress)} />
))}
) } return
No pending fee confirmation
} ``` ## Parameters The hook accepts an optional configuration object with the following properties: ```tsx theme={null} interface FeeOptionsConfig { skipFeeBalanceCheck?: boolean } ``` | Parameter | Type | Description | | --------------------- | --------- | ---------------------------------------------------------- | | `skipFeeBalanceCheck` | `boolean` | Whether to skip checking token balances (default: `false`) | ## Return Type: `UseFeeOptionsReturnType` The hook returns a tuple with the following elements: ```tsx theme={null} type UseFeeOptionsReturnType = [ pendingFeeOptionConfirmation: FeeOptionConfirmation | undefined, confirmPendingFeeOption: (id: string, feeTokenAddress: string) => void, rejectPendingFeeOption: (id: string) => void ] ``` ### Properties #### pendingFeeOptionConfirmation `FeeOptionConfirmation | undefined` Object containing the current fee confirmation details if a transaction is pending, or `undefined` if no transaction is pending confirmation. ```tsx theme={null} type FeeOptionConfirmation = { id: string // Unique identifier for the fee confirmation options: Relayer.FeeOption[] | FeeOptionExtended[] // Available fee options with balance information chainId: number // Chain ID where the transaction will be executed } ``` When `skipFeeBalanceCheck` is `false`, the options will be of type `FeeOptionExtended`, which includes balance information: ```tsx theme={null} type FeeOptionExtended = Relayer.FeeOption & { balance: string // Raw balance string balanceFormatted: string // Formatted balance with proper decimals hasEnoughBalanceForFee: boolean // Indicates if wallet has enough balance } ``` #### confirmPendingFeeOption `(id: string, feeTokenAddress: string) => void` Function to confirm the selected fee option. | Parameter | Type | Description | | ----------------- | -------- | ------------------------------------------------------------------------------------ | | `id` | `string` | The fee confirmation ID | | `feeTokenAddress` | `string` | The address of the token to use for fee payment (use `zeroAddress` for native token) | #### rejectPendingFeeOption `(id: string) => void` Function to reject the current fee option selection. | Parameter | Type | Description | | --------- | -------- | --------------------------------- | | `id` | `string` | The fee confirmation ID to reject | ## Notes This hook provides functionality for handling Sequence V3 fee options for unsponsored transactions. Key features: * Intercept fee options for a transaction in Native Token and ERC20 tokens * Automatically fetch user wallet balances for each fee option (unless `skipFeeBalanceCheck` is `true`) * Allow users to select their preferred fee token through a UI component * Confirm or reject fee selections * Shared state management across multiple hook instances The hook integrates with the Sequence V3 connector to intercept fee confirmation requests and presents a user interface to allow selection of the fee token. It uses shared state management to ensure consistent behavior across multiple instances of the hook. For a detailed guide on how to use the hook, see the [Pay gas in ERC20](/sdk/web/wallet-sdk/embedded/guides/pay-gas-in-erc20) guide. # useHasPermission Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/ecosystem/hooks/useHasPermission Hook to check whether the current Sequence V3 session can execute a set of transactions ## Import ```tsx theme={null} import { useHasPermission } from '@0xsequence/connect' ``` ## Usage ```tsx theme={null} import { useHasPermission } from '@0xsequence/connect' import { encodeFunctionData, type TransactionRequest } from 'viem' function App() { const { checkPermission, isLoading, error, data } = useHasPermission() const check = async () => { const txs: TransactionRequest[] = [ { to: '0x0000000000000000000000000000000000000000', data: encodeFunctionData({ abi: [ { type: 'function', name: 'foo', stateMutability: 'nonpayable', inputs: [], outputs: [] } ], functionName: 'foo' }) } ] const allowed = await checkPermission({ chainId: 42161, transactions: txs }) console.log('Allowed:', allowed) } return (
{isLoading &&
Checking...
} {error &&
Error: {error.message}
} {data !== undefined &&
Allowed: {data ? 'Yes' : 'No'}
}
) } ``` ## Parameters ```tsx theme={null} type HasPermissionParams = { chainId: number transactions: TransactionRequest[] } ``` ## Return Type ```tsx theme={null} type UseHasPermissionReturnType = { isLoading: boolean error: Error | null data: boolean | undefined checkPermission: (params: HasPermissionParams) => Promise } ``` ## Notes * This hook uses the Sequence V3 connector internally. * Each transaction must include a `to` address. # useListAccounts Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/ecosystem/hooks/useListAccounts Hook to list all accounts associated with the current WaaS session ## Import ```tsx theme={null} import { useListAccounts } from '@0xsequence/connect' ``` ## Usage ```tsx theme={null} import { useListAccounts } from '@0xsequence/connect' function AccountsList() { const { data, isLoading, error, refetch } = useListAccounts() if (isLoading) return
Loading accounts...
if (error) return
Error: {error.message}
return (
Current Account ID: {data?.currentAccountId}
{data?.accounts.map(account => (
ID: {account.id}
Type: {account.type}
{account.email &&
Email: {account.email}
} {account.issuer &&
Issuer: {account.issuer}
}
))}
) } ``` ## Return Type: `UseListAccountsResult` The hook returns an object with the following properties: ```tsx theme={null} interface UseListAccountsResult { /** The accounts data if available */ data?: IntentResponseAccountList /** Whether the query is currently loading */ isLoading: boolean /** Any error that occurred during the query */ error: Error | null /** Function to manually refetch the accounts */ refetch: () => Promise } enum IdentityType { None = "None", Guest = "Guest", OIDC = "OIDC", Email = "Email", PlayFab = "PlayFab", Stytch = "Stytch" } interface Account { id: string; type: IdentityType; issuer?: string; email?: string; } interface IntentResponseAccountList { accounts: Array; currentAccountId: string; } ``` ### Properties #### data `IntentResponseAccountList | undefined` The list of accounts if the query was successful. Contains an array of account objects with properties like `id` and `address`. #### isLoading `boolean` Whether the query is currently in progress. Useful for showing loading states. #### error `Error | null` Any error that occurred during the query. Will be `null` if no error occurred. #### refetch `() => Promise` Function to manually trigger a refresh of the accounts list. ## Features * **Automatic Data Fetching**: Automatically fetches accounts when WaaS connection is available * **Caching**: Results are cached for 1 minute to prevent unnecessary refetches * **Error Handling**: Proper error handling for missing WaaS connector or initialization issues * **Type Safety**: Full TypeScript support for all returned data * **React Query Integration**: Uses React Query for efficient state management and caching # useOpenConnectModal Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/ecosystem/hooks/useOpenConnectModal Hook for opening the connect modal ## Import ```tsx theme={null} import { useOpenConnectModal } from '@0xsequence/connect' ``` ## Usage ```tsx theme={null} import { useOpenConnectModal } from '@0xsequence/connect' function App() { const { setOpenConnectModal, openConnectModalState } = useOpenConnectModal() const handleConnect = () => { setOpenConnectModal(true) // Open the connect modal } return ( <> {openConnectModalState && (
Connect modal is open!
)} ) } ``` ## Return Type: `UseOpenConnectModalReturnType` The hook returns an object with the following properties: ```tsx theme={null} type UseOpenConnectModalReturnType = { isConnectModalOpen: boolean setOpenConnectModal: (isOpen: boolean) => void openConnectModalState: boolean } ``` ### Properties #### setOpenConnectModal `(isOpen: boolean) => void` Function to open or close the Connect modal. **Parameters:** | Parameter | Type | Description | | --------- | --------- | ------------------------------------------------------------- | | `isOpen` | `boolean` | Whether the modal should be open (`true`) or closed (`false`) | #### openConnectModalState `boolean` The current open state of the Connect modal (`true` if open, `false` if closed). #### isConnectModalOpen `boolean` Current open state of the Connect modal (same value as `openConnectModalState`). ## Notes This hook provides methods to control the Connect modal that allows users to connect their wallets to your application. The Connect modal provides various wallet connection options including Sequence wallet and external wallets. # useSendWalletTransaction Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/ecosystem/hooks/useSendWalletTransaction Hook to send a transaction via the Sequence wallet popup (wallet action) ## Import ```tsx theme={null} import { useSendWalletTransaction } from '@0xsequence/connect' ``` ## Usage ```tsx theme={null} import { useSendWalletTransaction } from '@0xsequence/connect' function App() { const { sendTransactionAsync, isLoading, error, data, reset } = useSendWalletTransaction() const send = async () => { const hash = await sendTransactionAsync({ chainId: 42161, transaction: { to: '0x0000000000000000000000000000000000000000', data: '0x' } }) console.log('tx hash', hash) } return (
{isLoading &&
Sending...
} {error &&
Error: {error.message}
} {data &&
Hash: {data}
}
) } ``` ## Parameters ```tsx theme={null} type SendWalletTransactionParams = { chainId: number transaction: TransactionRequest } ``` ## Return Type ```tsx theme={null} type UseSendWalletTransactionReturnType = { isLoading: boolean error: Error | null data: string | undefined sendTransaction: (params: SendWalletTransactionParams) => void sendTransactionAsync: (params: SendWalletTransactionParams) => Promise reset: () => void } ``` ## Notes * This hook uses the Sequence V3 connector and opens the wallet popup for user approval. * `transaction.to` is required. # useSignInEmail Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/ecosystem/hooks/useSignInEmail Hook to retrieve the email address associated with the connected wallet ## Import ```tsx theme={null} import { useSignInEmail } from '@0xsequence/connect' ``` ## Usage ```tsx theme={null} import { useSignInEmail } from '@0xsequence/connect' function App() { const email = useSignInEmail() return (

User Information

{email ? (

Connected with email: {email}

) : (

No email associated with connected wallet

)}
) } ``` ## Return Type ```tsx theme={null} string | null ``` The hook returns: * A `string` containing the email address when a wallet is connected and has an associated email * `null` when: * No wallet is connected * The connected wallet has no associated email * The wallet has been disconnected ## State Management The hook manages the email state by: 1. Monitoring the wallet connection status 2. Retrieving the stored email when a wallet connects 3. Clearing the email when the wallet disconnects 4. Persisting the email in local storage using the `WaasSignInEmail` key ## Notes This hook is designed to work with both: * Sequence WaaS (Wallet-as-a-Service) wallets * Universal wallet types The hook integrates with Sequence's storage system to maintain email persistence across sessions while ensuring proper cleanup when wallets are disconnected. # useStorage Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/ecosystem/hooks/useStorage Hook for accessing the storage instance of the Sequence Connect client ## Import ```tsx theme={null} import { useStorage, useStorageItem } from '@0xsequence/connect' ``` ### Usage ```tsx theme={null} import { useStorage, signEthAuthProof, validateEthProof } from '@0xsequence/connect' import { useWalletClient, usePublicClient } from 'wagmi' function App() { const { data: walletClient } = useWalletClient() const publicClient = usePublicClient() const storage = useStorage() const generateEthAuthProof = async () => { if (!walletClient || !publicClient || !storage) { return } try { // Use storage to generate an auth proof const proof = await signEthAuthProof(walletClient, storage) console.log('proof:', proof) const isValid = await validateEthProof(walletClient, publicClient, proof) console.log('isValid?:', isValid) } catch (e) { console.error(e) } } return ( ) } ``` ### Return Type `Storage | null` Returns the Storage instance if available, or null if not configured. ## useStorageItem Hook to retrieve a specific item from the Sequence Connect storage. ### Usage ```tsx theme={null} import { useStorageItem } from '@0xsequence/connect' function App() { const { data: authToken, isLoading } = useStorageItem('authToken') if (isLoading) { return
Loading...
} return (
{authToken ? 'Authenticated' : 'Not authenticated'}
) } ``` ### Parameters | Parameter | Type | Description | | --------- | ------------------- | --------------------------------------- | | `key` | `keyof StorageItem` | The key of the storage item to retrieve | ### Return Type `UseQueryResult` Returns a react-query result containing the storage item data, with the following properties: | Property | Type | Description | | ----------- | ---------------- | ---------------------------------------------- | | `data` | `StorageItem[K]` | The retrieved storage item data | | `isLoading` | `boolean` | Whether the data is currently loading | | `isError` | `boolean` | Whether an error occurred during data fetching | | `error` | `Error` | The error object if an error occurred | | ... | ... | Other react-query properties | ## Notes These hooks provide access to the storage layer used by Sequence Connect for persisting authentication data, wallet state, and other client-side storage needs. The `useStorage` hook is commonly used for operations that require direct access to the storage layer, such as generating authentication proofs, while `useStorageItem` provides a convenient way to access specific items with react-query integration. # useTheme Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/ecosystem/hooks/useTheme Hook to access and modify theme and modal position settings ## Import ```tsx theme={null} import { useTheme } from '@0xsequence/connect' ``` ## Usage ```tsx theme={null} import { useTheme } from '@0xsequence/connect' function App() { const { theme, setTheme, position, setPosition } = useTheme() return (

Theme Settings

Modal Position

) } ``` ## Return Type ```tsx theme={null} interface ThemeHookReturn { theme: 'light' | 'dark' setTheme: (theme: 'light' | 'dark') => void position: ModalPosition setPosition: (position: ModalPosition) => void } type ModalPosition = | 'center' | 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' ``` ### Properties #### theme `'light' | 'dark'` The current theme setting. #### setTheme `(theme: 'light' | 'dark') => void` Function to update the theme setting. #### position `ModalPosition` The current modal position setting. #### setPosition `(position: ModalPosition) => void` Function to update the modal position setting. # useWalletSettings Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/ecosystem/hooks/useWalletSettings Hook to access and modify wallet configuration settings ## Import ```tsx theme={null} import { useWalletSettings } from '@0xsequence/connect' ``` ## Usage ```tsx theme={null} import { useWalletSettings } from '@0xsequence/connect' function WalletConfigPanel() { const { displayedAssets, readOnlyNetworks, setDisplayedAssets, hideExternalConnectOptions, hideConnectedWallets, hideSocialConnectOptions } = useWalletSettings() // Example function to add a new asset const addNewAsset = (contractAddress: string, chainId: number) => { setDisplayedAssets([ ...displayedAssets, { contractAddress, chainId } ]) } // Example function to check if network is read-only const isNetworkReadOnly = (chainId: number) => { return readOnlyNetworks?.includes(chainId) } return (

Wallet Settings

Displayed Assets

    {displayedAssets.map(asset => (
  • Chain ID: {asset.chainId}, Contract: {asset.contractAddress}
  • ))}

Network Status

    {[1, 137, 10].map(chainId => (
  • Chain {chainId}: {isNetworkReadOnly(chainId) ? 'Read-only' : 'Active'}
  • ))}
) } ``` ## Return Type ```tsx theme={null} interface WalletSettingsReturn { displayedAssets: Array<{ contractAddress: string chainId: number }> readOnlyNetworks: number[] | undefined setDisplayedAssets: (assets: Array<{ contractAddress: string chainId: number }>) => void hideExternalConnectOptions?: boolean hideConnectedWallets?: boolean hideSocialConnectOptions?: boolean } ``` ### Properties #### displayedAssets `Array<{ contractAddress: string, chainId: number }>` Array of assets to display in the wallet interface. Each asset is defined by: * `contractAddress`: The token contract address * `chainId`: The network ID where the token exists #### readOnlyNetworks `number[] | undefined` Array of network IDs where transactions are disabled. These networks are available for viewing balances and transaction history, but users cannot initiate new transactions. #### setDisplayedAssets `(assets: Array<{ contractAddress: string, chainId: number }>) => void` Function to update the list of displayed assets. Takes an array of asset objects, each containing a contract address and chain ID. #### hideExternalConnectOptions `boolean | undefined` Whether external wallets are hidden in the Connect Modal. #### hideConnectedWallets `boolean | undefined` Whether connected wallets are hidden in the Connect Modal. #### hideSocialConnectOptions `boolean | undefined` Whether social wallets (email/social logins) are hidden in the Connect Modal. ## Notes This hook provides access to wallet display settings and network status information. Key features: * Asset display list management * Read-only network status information * Type-safe configuration updates Common use cases: * Managing visible token list * Checking if networks are read-only * Building settings interfaces Best practices: * Validate contract addresses before adding to displayed assets * Check network read-only status before attempting transactions * Keep displayed assets list up to date The hook is commonly used in wallet configuration interfaces to manage which assets are displayed and check network status. # Overview Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/ecosystem/overview ## Overview [@0xsequence/connect v6](https://www.npmjs.com/package/@0xsequence/connect/v/6.0.0) is the React Hooks SDK for the Ecosystem Wallet. It combines social auth, passkeys, account recovery, wallet linking, sessions and permissions management to deliver a complete Web2 like experience for your users. With a small bundle size, it's the fastest way to add a complete, non-custodial ecosystem smart wallet experience to your DApp. ### Key features * Social auth (Email, Google, Apple) * Passkeys * Account Recovery * Wallet Linking * Smart sessions management * Customizable theming * Built in UI components # Demos Check out our live demos: See a demo of an Ecosystem Wallet. See a demo of how an Ecosystem Wallet is used in a game. # Examples Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/ecosystem/smart-sessions/examples ## Aave ### Supply USDC to Aave V3 With this session, dApp is able to supply up to 100 USDC into the Aave V3 pool on Arbitrum for 24 hours. It can only supply on behalf of the user wallet. ```typescript theme={null} import { type ExplicitSessionParams } from "@0xsequence/connect"; export const USDC_ADDRESS_ARBITRUM = '0xaf88d065e77c8cC2239327C5EDb3A432268e5831' export const AAVE_V3_POOL_ADDRESS_ARBITRUM = '0x794a61358D6845594F94dc1DB02A252b5b4814aD' const aaveSupplySession: ExplicitSessionParams = { chainId: 42161, nativeTokenSpending: { valueLimit: 0n, }, expiresIn: { hours: 24, }, permissions: [ createContractPermission({ address: AAVE_V3_POOL_ADDRESS_ARBITRUM, functionSignature: 'function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode)', rules: [ { param: 'asset', type: 'address', condition: 'EQUAL', value: USDC_ADDRESS_ARBITRUM, }, { param: 'onBehalfOf', type: 'address', condition: 'EQUAL', value: {userWalletAddress}, }, { param: 'amount', type: 'uint256', condition: 'LESS_THAN_OR_EQUAL', value: parseUnits('100', 6), }, ], }), ], }; ``` ### Withdraw USDC from Aave Pool With this session, dApp is able to withdraw up to 100 USDC from the Aave V3 pool on Arbitrum for 24 hours. It can only withdraw to the user's wallet address. ```typescript theme={null} import { type ExplicitSessionParams } from "@0xsequence/connect"; export const USDC_ADDRESS_ARBITRUM = '0xaf88d065e77c8cC2239327C5EDb3A432268e5831' export const AAVE_V3_POOL_ADDRESS_ARBITRUM = '0x794a61358D6845594F94dc1DB02A252b5b4814aD' const aaveWithdrawSession: ExplicitSessionParams = { chainId: 42161, nativeTokenSpending: { valueLimit: 0n, }, expiresIn: { hours: 24, }, permissions: [ createContractPermission({ address: '0x...', functionSignature: 'function withdraw(address asset, uint256 amount, address to)', rules: [ { param: 'asset', type: 'address', condition: 'EQUAL', value: USDC_ADDRESS_ARBITRUM, }, { param: 'amount', type: 'uint256', condition: 'LESS_THAN_OR_EQUAL', value: parseUnits('100', 6), }, { param: 'to', type: 'address', condition: 'EQUAL', value: {userWalletAddress}, }, ], }), ], }; ``` ### Supply ETH to Aave With this session, dApp is able to supply up to 0.1 ETH to the Aave V3 pool on Arbitrum for 24 hours. It can only supply on behalf of the user wallet, so dApp cannot increase its own position. ```typescript theme={null} import { type ExplicitSessionParams } from "@0xsequence/connect"; export const AAVE_V3_WRAPPED_TOKEN_GATEWAY_ADDRESS_ARBITRUM = '0x794a61358D6845594F94dc1DB02A252b5b4814aD' export const AAVE_V3_POOL_ADDRESS_ARBITRUM = '0x794a61358D6845594F94dc1DB02A252b5b4814aD' const aaveSupplyETHSession: ExplicitSessionParams = { chainId: 42161, nativeTokenSpending: { valueLimit: parseEther('0.1'), }, expiresIn: { hours: 24, }, permissions: [ createContractPermission({ address: AAVE_V3_WRAPPED_TOKEN_GATEWAY_ADDRESS_ARBITRUM, functionSignature: 'function depositETH(address pool, address onBehalfOf, uint16 referralCode)', rules: [ { param: 'pool', type: 'address', condition: 'EQUAL', value: AAVE_V3_POOL_ADDRESS_ARBITRUM }, { param: 'onBehalfOf', type: 'address', condition: 'EQUAL', value: {userWalletAddress}, } ] }), ], }; ``` ### Borrow USDC from Aave With this session, dApp is able to borrow up to 100 USDC from the Aave V3 pool on Arbitrum for 24 hours. It can only borrow on behalf of the user wallet. ```typescript theme={null} import { type ExplicitSessionParams } from "@0xsequence/connect"; export const USDC_ADDRESS_ARBITRUM = '0xaf88d065e77c8cC2239327C5EDb3A432268e5831' export const AAVE_V3_POOL_ADDRESS_ARBITRUM = '0x794a61358D6845594F94dc1DB02A252b5b4814aD' const aaveBorrowSession: ExplicitSessionParams = { chainId: 42161, nativeTokenSpending: { valueLimit: 0n, }, expiresIn: { hours: 24, }, permissions: [ createContractPermission({ address: AAVE_V3_POOL_ADDRESS_ARBITRUM, functionSignature: 'function borrow(address asset, uint256 amount, uint256 interestRateMode, uint16 referralCode, address onBehalfOf)', rules: [ { param: 'asset', type: 'address', condition: 'EQUAL', value: USDC_ADDRESS_ARBITRUM, }, { param: 'amount', type: 'uint256', condition: 'LESS_THAN_OR_EQUAL', value: parseUnits('100', 6), // 100 USDC }, { param: 'onBehalfOf', type: 'address', condition: 'EQUAL', value: {userWalletAddress}, } ], }), ], }; ``` # Overview Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/ecosystem/smart-sessions/overview ## What Are Smart Sessions? Smart Sessions are the key to unlocking a seamless, Web2-like user experience in your dApp. Instead of asking users to approve every single transaction, a Smart Session allows a user to grant your dApp a temporary, secure, and strictly limited set of permissions. Think of it less like handing over a master key, and more like giving your application a special-purpose keycard with clear rules and an expiration date. This is extremely useful for enabling powerful features like: * **Seamless UX:** Eliminate repetitive wallet pop-ups for common actions like staking, swapping, or listing items. * **Automation:** Execute transactions on a user's behalf, even when they are offline, for features like automated strategies or subscription services. * **Granular Security:** Define exactly what your dApp can and cannot do, minimizing risk and building user trust. *** ## How It Works: Key Concepts When you configure a Smart Session, there are a few important concepts that the SDK handles to make the developer experience as simple as possible. ### Paying for Gas with Native Tokens (ETH, MATIC, etc.) To allow session-signed transactions to include native token value, set a budget using `nativeTokenSpending.valueLimit`. If you want the wallet to present fee token options (including native token fees), enable fee option permissions (for example, by using `includeFeeOptionPermissions` when creating explicit sessions). This will request the additional permissions needed for fee payments. ### Paying for Gas with ERC-20 Tokens (USDC, etc.) Fee token options are provided through the fee-options flow. When enabled, the SDK can request the necessary permissions for ERC-20 fee payments and handle the selected fee token automatically. ### Security Best Practice: The Principle of Least Privilege We **strongly recommend** adding specific `rules` to every function permission you define. This enforces the **principle of least privilege**: granting a session only the *exact* permissions it needs to perform its job, and nothing more. While you *can* grant unrestricted access to a contract by providing an empty `functions` array, this should be done with caution as it gives the session broad authority. It is always more secure to be explicit. For example, locking an `approve` function to a specific `spender` address is always safer than leaving it open for any address. By defining clear rules, you build more secure Smart Sessions and provide greater peace of mind for your users. # More Information For a more detailed explanation of how Smart Sessions work, see [here](/solutions/wallets/ecosystems/smart-sessions). # Utils Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/ecosystem/smart-sessions/utils To make the process of creating smart sessions easier, we provide a set of helper functions. ## `createContractPermission` This helper function is used to create a permission for a smart contract function. ### Example ```typescript theme={null} import { createContractPermission } from "@0xsequence/connect"; const AAVE_V3_POOL_ADDRESS_ARBITRUM = '0x794a61358D6845594F94dc1DB02A252b5b4814aD' const permission = createContractPermission({ address: AAVE_V3_POOL_ADDRESS_ARBITRUM, functionSignature: 'function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode)', rules: [ { param: 'asset', type: 'address', condition: 'EQUAL', value: USDC_ADDRESS_ARBITRUM }, { param: 'amount', type: 'uint256', condition: 'LESS_THAN_OR_EQUAL', value: parseUnits('1', 6), cumulative: true } ] }); ``` ### Params ```typescript theme={null} type CreateContractPermissionOptions = { /** The address of the target contract. */ address: Address /** * The human-readable function signature. * Example: 'function transfer(address to, uint256 amount)' */ functionSignature?: string /** An array of rules to apply to the function's arguments. */ rules?: Rule[] /** * If true, this function can only be successfully called once during the session. * @default false */ onlyOnce?: boolean } ``` #### `address` The address of the target contract. #### `functionSignature` The human-readable function signature. #### `rules` An array of rules to apply to the function's arguments. ```typescript theme={null} type Rule = { /** The name of the parameter from the function signature (e.g., 'to', 'amount'). */ param: string /** The type of the parameter (address, uint256, etc.). */ type: ParamType /** The comparison to perform on the parameter (EQUAL, NOT_EQUAL, GREATER_THAN_OR_EQUAL, LESS_THAN_OR_EQUAL). */ condition: RuleCondition /** The value to compare against. Must match the `type`. */ value: string | number | bigint | boolean /** * Determines if the rule's value is a cumulative total across all calls to this function. * @example * For a `transfer` function on an ERC20 token, if we set a rule for the `amount` parameter to be 10 and we set `cumulative` * to `true` then the dApp can make as many transfer calls as it wants but in total it cannot transfer more than 10 tokens. * If `cumulative` is `false` then the dApp can transfer 10 tokens as many times as it wants if other conditions are met. * This makes sense only for number values like amount of transfers, etc. * @default true */ cumulative?: boolean } ``` #### `onlyOnce` If true, this function can only be successfully called once during the session. ### Return type Returns a Permission. ```typescript theme={null} type Permission = { target: Address.Address rules: ParameterRule[] } ``` ## `createContractPermissions` Same as [`createContractPermission`](#createcontractpermission), but it creates multiple permissions for the same contract. ### Example ```typescript theme={null} import { createContractPermissions } from "@0xsequence/connect"; const permissions = createContractPermissions({ address: AAVE_V3_POOL_ADDRESS_ARBITRUM, functions: [ { functionSignature: 'function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode)', rules: [ { param: 'asset', type: 'address', condition: 'EQUAL', value: USDC_ADDRESS_ARBITRUM }, { param: 'amount', type: 'uint256', condition: 'LESS_THAN_OR_EQUAL', value: parseUnits('1', 6), cumulative: true } ] }, { functionSignature: 'function withdraw(address asset, uint256 amount, address to)', rules: [ { param: 'asset', type: 'address', condition: 'EQUAL', value: USDC_ADDRESS_ARBITRUM }, { param: 'amount', type: 'uint256', condition: 'LESS_THAN_OR_EQUAL', value: parseUnits('1', 6), cumulative: true } ] } ] }); ``` ### Params ```typescript theme={null} /** * The options object for creating permissions. */ export type CreateContractPermissionsOptions = { /** The address of the target contract. */ address: Address /** An array of permissions for one or more functions on this contract. */ functions?: FunctionPermission[] | undefined | null } ``` #### `address` The address of the target contract. #### `functions` An array of `FunctionPermission` ```typescript theme={null} type FunctionPermission = { /** * The human-readable function signature. * Example: 'function transfer(address to, uint256 amount)' */ functionSignature: string /** An array of rules to apply to the function's arguments. */ rules?: Rule[] /** * If true, this function can only be successfully called once during the session. * @default false */ onlyOnce?: boolean } ``` ### Return type Returns a `Permission[]`. ```typescript theme={null} type Permission = { target: Address.Address rules: ParameterRule[] } ``` See these utilities in action [here](/sdk/web/wallet-sdk/ecosystem/smart-sessions/examples#supply-usdc-to-aave-v3). # Analytics Source: https://docs.sequence.xyz/solutions/builder/analytics Sequence's analytics feature allows users to easily track key metrics in Sequence Builder without additional work. By using Sequence SDKs/APIs, analytics events are sent to Databeat for real-time storage and visualization. When you use Sequence, via our SDKs, to build your application, you can see key insights in Sequence Builder. You don't need to do any additional work to see valuable metrics about your project, such as the number of connected wallets, active users or daily transaction requests. You can also query your analytics programmatically or connect to services like Dune via our [APIs](/api-references/analytics/overview). #### How it works When requests are made with Sequence SDKs/APIs, analytics events are fired and sent to our internal analytics system, Databeat. Databeat anonymizes the data and stores it in a secure database designed for high-volume, real-time applications. The metrics you see in Builder are queried from the database, in real-time, for your project and presented in insightful visualizations. All metrics and graphs are given under five categories which you can see each in different tabs in the Analytics section: * Summary * Acquisition * Engagement * Retention * Monetization ## Summary The Summary enables you to check all the most relevant metrics of your project with a quick glance. It gives you high-level metrics that you can then explore in more detail in the other tabs. In this tab, you’ll see the following metrics: * **Total unique users:** Counts all unique users logged into your app lifetime-to-date. * **Daily active users:** A user is considered active once they log in to your app by connecting their wallet. This time series chart shows the daily active users for the last 90 days. * **Average daily active users:** Shows the average daily active users lifetime-to-date. * **Average stickiness:** It measures the percentage of monthly active users (MAU) interacting with your app daily. It is calculated as Daily active users (DAU) / monthly active users (MAU). * **Total transacting users:** The total number of users buying or selling assets in your marketplace. This only considers users transacting in your marketplace, deployed via Builder. It won’t include users transacting in other marketplaces. Sequence Builder analytics summary In summary tab, almost all metrics are given for your app's lifetime. But you have the option to look at your data for different time periods by toggling the filter in the top right corner in the other sections. The default value is the last 30 days for all date filters. ## Acquisition This section includes all relevant metrics for new users coming into your app with a variety of dimensions. In this tab, you will see the total. monthly, weekly and daily new users. A user is considered new when they log in to your app for the first time.\ Total new users counts the total number of new users coming into your app for the selected time period which can be set using the filter in the top right corner. Monthly, weekly or daily new users are time series charts showing new users logging in over the selected time period. Sequence Builder analytics acquisition ## Engagement The Engagement tab shows the main metrics for user activity. You can see weekly and monthly active users, where they come from, and how they are accessing your app. You can use the date filter in the top-right to change the timeline of your metrics. In this tab, you’ll see the following metrics: * **Monthly/Weekly Active Users:** Once a user logs in to your app, they are considered active in a given period. Monthly and Weekly Active Users charts count the total number of active users in the given period * **Monthly Active Users by Segment:** Counts the number of active users by segment on a monthly basis. Our segments are defined as: * *New users:* Users logged in for the first time in a given month * *Users from previous month:* User returning from being active in the previous month * *Old users:* Users who were not active in the previous month but logged in an earlier month. * **Users by country/OS/device/browser:** Number of users broken down by each dimension for the selected time period. Sequence Builder analytics engagement ## Retention In the Retention tab, you can see key metrics on how your app is engaging with users and getting them to come back. In this tab, you’ll see the following metrics: * **Avg D1/D7/D14/D28 Retention:** Average number of users coming back to the app after 1/7/14/28 day(s) from the day they started using the app by first seen date. These numbers are averaged for the cohorts selected. * **Wallet Retentions:** % of users coming back to the app after 'd' day from the day they started using the app by first seen date. Each time series shows a different 'd' day retention and cohorts are given on the x-axis. * **Rolling stickiness:** The daily ratio of daily active users (DAU) to rolling monthly active users (MAU) which shows how frequently users are returning back to the app on a daily basis compared to the total number of unique active users over the month. Sequence Builder analytics retention ## Monetization In the Monetization tab, you can see and track the wallet transactions of your users. We show only the transaction requests sent by the users in the current version of our analytics dashboards, but this will expand into a more comprehensive view of all user transactions by estimating the value of transactions in USD. In this tab, you’ll find the following metrics: * **Daily/Weekly/Monthly Transacting Users:** Number of transacting users in each segment. Our segments are defined as: * *New users:* Users logged in for the first time in a given month * *Users from previous month:* User returning from being active in the previous month * *Old users:* Users who were not active in the previous month but logged in an earlier month. * **Monthly Transacting Users by Segment:** % of users coming back to the app after 'd' day from the day they started using the app by first seen date. Each time series shows a different 'd' day retention and cohorts are given on the x-axis. * **Transacting User Conversion:** The percentage of total users who have transacted at least once. * **Monthly/Daily Total Transaction Users Conversion:** The percentage of monthly active users who who have transacted at least once. * **Total/Monthly/Daily Transaction Requests:** Total number of transactions sent in a given period. * **Total/Monthly/Daily Marketplace Transactions:** The number of transactions that have occurred on your marketplace on a daily basis. Sequence Builder analytics monetization # How to Manage Item Metadata in Sequence Builder Source: https://docs.sequence.xyz/solutions/builder/collections/manage-item-metadata This guide explains how to manage token metadata in Sequence Builder with the help from Pinata for IPFS hosting. ## Introduction Following this guide, you can easily manage token metadata for your contract items in Sequence Builder, with a little help from [Pinata](https://www.pinata.cloud/) for IPFS hosting. ## Step 1: Prepare Your Token Images and Metadata First things first, gather all your token images. For each token, you'll need a metadata file named `id.json` (like `1.json`, `2.json`, etc.). These files should look something like this at a minimum: ```json theme={null} { "name": "Token Name", "description": "Token Description", "image": "ipfs://" } ``` As you can guess, you can build from these basics. You could have your unique item attributes embedded in this token and generated on the fly. ## Step 2: Set Up on Pinata.cloud Head over to [Pinata.cloud](https://www.pinata.cloud/) and create an account. Upload each of your token images as separate files. Next, update the metadata JSON files with the `ipfs` address for each token. To do this, simply copy the CID (Content Identifier) for each file from Pinata and paste it after `ipfs://` in your JSON files. It should look like this: ```json theme={null} { "name": "Token Name", "description": "Token Description", "image": "ipfs://QmdJzQExj2wnNY7pNNn4KauzckjH4vA5xhoxmmis919Ev3" } ``` Configure Pinata ## Step 3: Upload Your Metadata Files Now, gather all your JSON metadata files into a single folder on your computer. Use Pinata's 'Upload > Folder' feature to upload this folder. Then, copy the CID for the entire folder. Upload Metadata ## Step 4: Get the Folder URL Click on name of the folder you created on Pinata. This will open a new tab showing all your uploaded JSON files. Copy the URL of this folder. Get Folder URL from Pinata ## Step 5: Set Up on Sequence Builder Navigate to [Sequence Builder](https://sequence.build/), set up your account, and create your project on the network of your choice. In the Contracts section, click on "Deploy New Contract". Configure Contract on Builder ## Step 6: Deploy Your Contract Select "Web3 Game Item Collection (ERC-1155)" and name your contract. Sequence Builder will automatically deploy your contract on-chain. Deploy Contract ## Step 7: Move to Contract Details Once you sign the transaction, your contract is ready! Click on it to view the details screen. Contract Details ## Step 8: Update Contract Attributes Navigate to the “Write Contract” section. This is where you can modify attributes of your freshly deployed ERC-1155 contract. Two methods are what you should focus on for now: * `setBaseMetadataURI` allows the creator to set the base metadata URL for this contract. You want this to point to the JSON files you’ve created, depending on NFT ID. * `mint` mints one of your tokens and sends it to an address of your choosing. ## Step 9: Set the Base Metadata URI Scroll to `setBaseMetadataURI`, expand it, and under `tokenBaseURI` paste the URL for the JSON folder preview you got from Pinata earlier. It should look something like this: ``` https://azure-wooden-lemur-911.mypinata.cloud/ipfs/QmW5gvYGWb98GsN8VjTRWu4pLn6jryEXNxZKNWpPhVwtDm/ ``` Click “Write” and you will be prompted to sign again. This will modify the contract on-chain to set the metadata base. Essentially any token ID you provide will be appended to this URL, along with the `.json` suffix. So if you mint token ID 123, it will look for `tokenBaseURI + 123.json`. Base Metadata Setup ## Step 10: Minting Time Finally, it's time to mint! Scroll up to `mint`, expand it, and fill in the details: * `to (address)`: This is the address that the token will be sent to. Use your Sequence wallet address or any other valid address. * `tokenId (uint256)`: This is your token ID. As long as you have a `tokenId.json` file already uploaded to pinata.cloud under the folder, it will work. * `amount (uint256)`: The number of tokens to mint (usually 1). * `data (bytes)`: Enter `0x00` for this simple process. Mint test ## Step 11: Finalize and Admire Click "Write" and sign the transaction. Congratulations, you've just minted a token! Head over to the "Tokens" section to see your minted tokens with their names and images. Finalize Minting ## Step 12: Updating Metadata If you make mistakes with the token metadata, you can always update it and then call the Sequence Metadata refresh endpoint to reload the specific tokens: ``` curl -X GET "https://metadata.sequence.app/tokens/mumbai/0xb392c99d9f8e3e0b248e5c283818be5bf5cecca7/1/refresh" ``` This is in the format: `https://metadata.sequence.app/tokens////refresh` Now that you are ready to mint, you might want to read about [how you can launch your own serverless endpoint for securely minting tokens](/guides/mint-collectibles-serverless). # Manage NFT Collections in Sequence Builder Source: https://docs.sequence.xyz/solutions/builder/collections/quickstart The Sequence Builder allows you to manage Collections of collectible metadata, including details, images, and properties. You can link Collections to deployable contracts for easy crafting flows. Control updates and public/private viewing of collection info on Sequence servers. The Sequence Builder offers the ability to manage Collections of collectible metadata, including: collectible details, images, and properties. Within the Builder, Collections can be linked to deployable contracts from the Builder for easy crafting flows. Media and metadata is saved to Sequence servers where certain functionality allows you to have control over updates and public or private viewing of your collection information. [APIs](/api-references/metadata/overview) are also available to manage your NFT collection metadata. ## 1. Create a Collection First navigate to your project from the top left hand drop down of [Sequence Builder](https://sequence.build) and select the `Collections` page view from the left nav, then select the `+ Create a collection` create collection Then input your details for the collection, like `Collection Name`, `Description` for the contract info, `Collection Data` being `Visible (Public)` or `Private (Hidden)` where for the data to be viewable select Visible (Public), and include your projects `External Link` to a website. add details to collection ## 2. Link a Contract After a collection has been created you can first link a contract by deploying a collectible contract (i.e. `ERC1155` or `ERC721`) and having the `baseMetadataURI` being set on the deployment by selecting the `Link contract` Then select the `Deploy new contract` link a contract Select your contract type or upload your own contract type Next, you will be able to see the details of the contract type contract type chosen And complete your contract details, specifying the `Network`, `Contract Name`, and `Royalties`, whether to publish the Collectible on the [Token Directory](/api-references/indexer/examples/metadata-tips) and finally select `Deploy Contract` to then complete the transaction signing in the Sequence popup. contract details If you deploy from Builder on production networks, treat the deployment as self-funded. Gas Sponsorship can still be useful for relayed interactions after the contract is deployed, but the deployment transaction itself may still require the deploying wallet to pay gas. Then you will notice if you check out the `Read Contract` section tab of the contract, if you `Read` from the `baseURI` it will show you the metadata url from Sequence where when read from the Indexer, `.json` will get appended to the end to reference the json for the collectible. read base uri ## 3. Create a Collectible In order to create a Collectible as part of the Collection, return to the `Collections` page and select the `+ Add a collectible` add a collectible Then update the details like `Collectible Name` and `Description`, then upload your artwork by selecting the greyish field update collectible details #### Add a metadata property You can also add certain properties to your collectible, by selecting the `+ Add a property` which can be useful for inscribing more information like numbers or strings when using the metadata in any game. add a property Assigning the key and value to each property asign properties Complete the prior steps until you get your final result of a collectible added to a collection final result of collectible added ## 4. Update Info in Settings At any point you can update the details for your collectible in the settings settings Once in settings, you can update any one of the information fields, like: `Collection Name`, `Description`, visibility of `Collection data`, and an `External Link` to reference a website on the web. settings #### Delete Collection Data You can delete all of the Collection data for the contract by selecting `Delete collection data` which will permanently delete data all data, an action that cannot be undone. ## 5. Reference Metadata Token URI Currently in order to `Link Contract` you can't use predeployed contracts, but you can read the `Token Metadata URI` from the Collection to set your existing contracts' `setBaseMetadataURI`. The URI can be retrieved by accessing `Metadata URIs` button copy metadata uris Then copy the `Token Metadata URI` from the modal and use the URI to write to a contract with the `setBaseMetadataURI` function, or, use to reference metadata directly in an application by appending a `.json` to the URI to access the metadata access metadata uris # How to Deploy in-game Currency in Sequence Builder Source: https://docs.sequence.xyz/solutions/builder/contracts/deploy-ERC20-currency Learn how to create your own in-game currency by deploying and minting from an ERC20 contract. Understand the difference between fungible and non-fungible tokens. ## Introduction In this guide, we'll walk you through the process of creating your own in-game currency through deploying and minting from an ERC20 contract. Currency tokens add new and interesting dimensions to in-game economies, transactions, and player interactions to unlock and distribute value. #### What is an ERC20 token? An ERC20 token is a digital coin - what makes it special is that it follows a [set of rules called ERC20](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/), making it easy to use in different places on the internet. These tokens often represent value or be used for specific purposes. Unlike the other common token - NFT's, these tokens are fungible. #### Fungibility vs Non-Fungibility This is the key distinction to understand. Fungible tokens (like ERC20 tokens) are interchangeable, and each unit is the same as every other unit, just like dollars or euros. They can easily be split or combined into different quantities. Non-fungible tokens (like ERC721 tokens) represent unique items with individual properties, such as digital art or collectibles. Each token is distinct and not directly exchangeable with another on a like-for-like basis. Prerequisite: Create a Project This guide assumes that you have already [signed up for Builder and created a Project](/solutions/builder/getting-started). ## Step 1: Navigate to contracts Start by selecting your `project` in the top left and corner for what you want to create the currency for, and head to the `contracts` section and select `+ Deploy new contract` select project and new contract ## Step 2: Select Currency Token Click `View more contracts` view more contracts Select the Currency Token contract and click `deploy` to deploy your Sequence audited contract select currency and deploy button ## Step 3: Specify contract details Complete the contract details by specifying a `name` and `symbol` for your contract. select currency and deploy button Note: While you can change the `name` and `symbol` later in the builder interface where it will update across the sequence stack, popular explorers do not reindex the information, so what you put first remains ## Step 4: Deploy your contract Deploy your contract from the popup window at [http://sequence.app/sign-transaction](http://sequence.app/sign-transaction), and sign the message by selecting `confirm` On production networks, treat Builder deployments as self-funded. Even if you have configured Gas Sponsorship for related wallets or contracts, the wallet performing the deployment may still need enough native gas token to pay for the deployment transaction. All testnets will be free to transact on ## Step 5: Add a Minter Role to the contract First start by selecting your contract you just deployed in the `contracts` section select contract Next, head to the `Write Contract` section write contract In the `grantRole` section of the write contract tab navigation, complete with the following details: `bytes32 role`: `0x9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6` `address account`: `` Where the wallet address is just copied from the top right hand corner to be able to send tokens to your wallet copy address grant role Complete by selecting `write` and signing the transaction in the popup window, like before With a confirmation message showing `Response Success` The role string inputted is the result of `solidityPackedKeccak256("MINTER_ROLE")` in solidity or `ethers.solidityPackedKeccak256(ethers.toUtf8Bytes("MINTER_ROLE"))` in javascript It's a typical pattern to use offchain compute like a cloudflare worker with a relayer wallet sending transactions, which would be inputted in the account field, more on how to accomplish this [here](/guides/mint-collectibles-serverless#mint-collectibles-using-a-gasless-serverless-transactions-api) ## Step 6: Mint tokens to your wallet address Navigate to the `mint` card in the `Write Contract` section and input your wallet address that you would like to receive tokens to and amount of tokens in 18 decimals. So for 100 tokens you would input: `100000000000000000000` mint tokens ## Step 7: Confirm your minted currency And you're done! You can view the transactions submitted to the blockchain for your wallet address in the `Transactions` tab navigation view currency transactions # How to Deploy an Item Collection Contract in Sequence Builder Source: https://docs.sequence.xyz/solutions/builder/contracts/deploy-an-item-collection This guide provides a detailed walkthrough on setting up and deploying a Web3 Game Item contract in Builder. It discusses the differences between ERC721 and ERC1155 contracts, walks through the steps of deploying a contract. This guide walks through how to setup and deploy a Web3 Game Item contract in Builder. Prerequisite: Create a Project This guide assumes that you have already [signed up for Builder and created a Project](/solutions/builder/getting-started). #### ERC721 vs. ERC1155 Both contracts mint NFTs, but ERC721, being the earlier standard, has gained widespread adoption, particularly in digital collectibles. Known for its simplicity and ease to audit for security, ERC721 tokens are distinct, contributing to their recognition in various NFT marketplaces. Typically you would use an ERC721 contract if: you're dealing with the single same asset, multiplied, or a multiplicity of 1 item with many in a collection Example `ERC721`: [Azuki](https://etherscan.io/token/0xed5af388653567af2f388e6224dc7c4b3241c544) In contrast, ERC1155 offers versatility with efficient batch operations for both fungible and non-fungible tokens in a single contract, where typically you would be dealing with a multiplicity of a many items to many quanties relationship. However, this flexibility introduces complexity, necessitating careful security attention. Example `ERC1155`: [Skyweaver](https://polygonscan.com/token/0x631998e91476da5b870d741192fc5cbc55f5a52e) ## Step 1: Navigate to contracts Start by selecting your `project` in the top left and corner for what you want to create the collectible for, and head to the `contracts` section and select `+ Deploy new contract` select project and new contract ## Step 2: Choose your collectible type Then make your choice of Web3 Game Item Collection (ERC1155) or NFT Collection (ERC721), for this example we'll walk you through a Web3 Game Item Collection (ERC1155) select game item The only difference in deployment between an `ERC1155` vs `ERC721` is that you add a `symbol` to an ERC721 NFT Collection ## Step 3: Specify contract details Complete the contract details by specifying a `Contract Name` and `Owner` for your contract, with the option to input Royalties. Make sure the Owner address is the Sequence Wallet in the top-right hand corner and that you have funds in this wallet on production networks, otherwise on testnet - we sponsor these transactions for you. deploy game item On production networks, treat Builder deployments as self-funded. Even if you have configured Gas Sponsorship for related wallets or contracts, the wallet performing the deployment may still need enough native gas token to pay for the deployment transaction. Note: While you can change the `name` later in the builder interface where it will update across the sequence stack, popular explorers do not reindex the information, so what you put first remains ## Step 4: Deploy your contract Deploy your contract from the popup window at [http://sequence.app/sign-transaction](http://sequence.app/sign-transaction), and sign the message by selecting `confirm` Deploy your contract by signing the message in the popup window from the Sequence Wallet All testnets will be free to transact on. ### Optional: Add a Minter Role to the contract Sequence contracts have Access Control options by default. In some cases, you may want to grant a specific address permissions in order to call various functions such as `mint()`. First start by selecting your contract you just deployed in the `contracts` section select contract Next, head to the `Write Contract` section write contract In the `grantRole` section of the write contract tab navigation grant role Complete with the following details: `bytes32 role`: `0x9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6` `address account`: `` Where the wallet address is the address that you would like to give permissions to mint to, specifically any Sequence wallet. copy address Complete by selecting `write` and signing the transaction in the popup window, like before With a confirmation message showing `Response Success` The role string inputted is the result of `solidityPackedKeccak256("MINTER_ROLE")` in solidity or `ethers.solidityPackedKeccak256(ethers.toUtf8Bytes("MINTER_ROLE"))` in javascript It's a typical pattern to use offchain compute like a cloudflare worker with a relayer wallet sending transactions, which would be inputted in the account field, more on how to accomplish this [here](/guides/mint-collectibles-serverless#mint-collectibles-using-a-gasless-serverless-transactions-api) ## Step 6: Mint tokens to your wallet address Navigate to the `mint` card in the `Write Contract` section and input the `to` being the wallet address you would like to receive the token to, the `tokenId` (typically starting at 0), and `amount` of tokens, and finally the `data` section you can just input `0x00`, which typically represent Additional data with no specified format. mint tokens ## Step 7: Confirm your minted collectible And you're done! You can view the transactions submitted to the blockchain for your wallet address in the `Transactions` tab navigation view currency transactions # Deploying a Primary Sales Contract in Sequence Builder Source: https://docs.sequence.xyz/solutions/builder/contracts/deploy-primary-sales-contract This guide provides a detailed walkthrough on setting up and deploying a Primary Sales Contract in Builder. It discusses the differences between ERC721 and ERC1155 contracts, walks through the steps of deploying a contract. ### How to Deploy a Primary Sales Contract in Sequence Builder This guide walks through how to setup and deploy the contracts for launching a primary sale - suitable for an NFT Drop, in-game store, and more. Current Builder behavior: Treat Builder contract deployments as self-funded transactions on production networks. Even if you have configured Gas Sponsorship for related wallets or contracts, the wallet performing the deployment may still need enough native gas token to pay for deployment. After the contracts are deployed, sponsorship can still be used for supported relayed interactions with those contracts. Start by selecting your desired `project` you would like to create a sale for and head to `Contracts > Deploy`. Follow this [guide](/solutions/builder/contracts/deploy-an-item-collection) in order to deploy a collectible contract as well as upload the collection metadata that you wish to create a sale for. select game item Once successfully deployed, return to the contracts page and select `+ Deploy new contract` again. Then select the appropriate ERC721 or ERC1155 sale contract that corresponds to your previously deployed collectible contract in step 2 and click `Deploy sale contract`. Deploy Sale Contract Navigate to the mint details tab for your primary sales contract. Fill out the mint details with your desired sale parameters. Mint Access * `Supply Cap`: This is the amount of supply of tokens that users can mint via the Sale contract * `Cost`: Is the cost amount in GWEI of minting a single token. In this example, we set it to 0 to easily mint from Builder, but when deploying in production this should match what you wish to charge your users. * `Start and End Time`: Start and end time of the sale. If the current time is within the date range provided, this will activate the sale. Consider setting the date range to the future if desired. * `Payment Token`: You can select the native token on the chain or a custom currency as well that the sale is in. * `Sale Type`: You can also opt to choose between a Public or Private mint. When selecting a private mint, you can also choose a list of allowlisted participants that is uploaded using our [Audience](https://sequence.build/project/default/audience/) feature. Important to note, that for a private mint you will need to pass in a merkle proof that corresponds to the merkle root added in the sale details in order to mint. Not to worry though, we provide this logic in our boilerplates by default. For this walkthrough, we will assume you are creating a public mint. Copy the Sales contract address, then you can navigate to the specific contract and select the settings to view Permissions. contract settings Once you have the modal open, select the `Permissions` tab and you can `Edit`, or, `+ Add Collaborator`. add collaborator Then complete the form with the Sales contract address to add as a collaborator and select the dropdown to assign the `Minter` role. assign role Finally, complete and sign the transaction update the contract Access Control. Now that you've got your contracts configured, let's try to do a test mint! Return to your deployed Sale contract and select `Write contract`. We will then click on the `mint()` function and pass in a few parameters: * `to`: this is the address that the NFT is being minted to. Generally this would be the user who paid, but we can simply pass in our Builder address located in the top-right hand corner. * `amount`: The amount of NFTs to mint, we will simply mint 1. * `paymentToken`: For a custom currency, you would pass in that currency's address. However for native tokens it will be `0x0000000000000000000000000000000000000000`. * `maxTotal`: The maximum amount of the given currency that can be paid. * `proof`: For a public mint, you can simply leave this field blank. In a private mint, this would be the generated proof that corresponds to the user's address & previously provided merkle root. Grant Minter Role Once all that information is filled out, go ahead and click `Write` to build the transaction, then `Confirm` to mint the token! What's next? You can now utilize the sale contracts publicly on your website for an NFT drop or use these contracts for your in-game store to sell game items to your players. We also recommend taking a look at our \[Sequence Pay boilerplate]\(([https://github.com/0xsequence-demos/sequence-pay-boilerplate](https://github.com/0xsequence-demos/sequence-pay-boilerplate)), which leverages the sale contracts to enable various use cases such as Fiat Payments with a credit card or ability to pay in any currency for your sale. # How to Deploy a Soulbound Token Contract in Sequence Builder Source: https://docs.sequence.xyz/solutions/builder/contracts/deploy-soulbound-token Learn how to deploy Soulbound Token contracts in Sequence Builder for non-transferable, exclusive game assets. This guide covers setup, key steps, and best practices for deploying non-tradable NFTs. Discover how to set up and deploy Soulbound Token contracts in Sequence Builder. Soulbound Tokens are perfect for creating unique, non-transferable game assets, including Battlepasses, memberships, and exclusive in-game items that stay permanently with the player. ## Overview of Soulbound Tokens Soulbound Tokens (SBTs) are non-transferable, non-sellable on-chain assets designed to provide exclusive, enduring value in Web3 environments. Since they cannot be transferred or traded, SBTs are ideal for representing permanent, achievement-based, or membership-related digital items. Here are some common use cases: * **Game Passes and Memberships**: Use Soulbound Tokens for Battlepasses, memberships, or loyalty programs that stay permanently in a user’s wallet, ensuring exclusive access for the intended holder. * **Achievement Badges**: Reward players with unique achievement badges that serve as a testament to their progress and accomplishments, visible to all but non-tradable. * **Event Tickets and Certifications**: Provide secure, non-transferable tickets for exclusive in-game events or educational certifications for skills achieved within a game environment. * **Identity and Reputation Systems**: Establish identity-based or reputation-based tokens that signify trust or credibility, supporting fair-play and user engagement. Soulbound Tokens are especially beneficial for game developers and communities aiming to provide lasting value without the need for speculative trading. Prerequisite: Create a Project This guide assumes that you have already [signed up for Builder and created a Project](/solutions/builder/getting-started). ## Step 1: Navigate to contracts Start by selecting your `project` in the top left corner for which you want to create the collectible, then go to the `Deploy` section, select `Contracts`, and select the `Contracts` button to add a new contract. ## Step 2: Choose your collectible type Select either Web3 Game Item Collection (ERC1155) or NFT Collection (ERC721) for your Soulbound Token. For this guide, we'll walk through a Web3 Game Item Collection (ERC1155), ideal for creating non-transferable Soulbound Tokens. ## Step 3: Specify contract details Provide details for the contract by specifying a `Contract Name` and `Owner`. You also have the option to set Royalties. Ensure that the Owner address matches the Sequence Wallet in the top-right corner, with adequate funds in this wallet on production networks. For testnet transactions, we sponsor them for you. deploy game item On production networks, treat Builder deployments as self-funded. Even if you have configured Gas Sponsorship for related wallets or contracts, the wallet performing the deployment may still need enough native gas token to pay for the deployment transaction. Note: Changing the `name` later will update it across the Sequence stack, but popular explorers will not reindex the information. Your initial entry will remain in these systems. ## Step 4: Deploy your contract Deploy your contract via the popup window at [http://sequence.app/sign-transaction](http://sequence.app/sign-transaction), and confirm by signing the message. Deploy your contract by signing the message in the popup window from the Sequence Wallet ## Step 5: Mint tokens to your wallet address Navigate to the `mint` card in the `Write Contract` section and input the `to` being the wallet address you would like to receive the token to, the `tokenId` (typically starting at 0), and `amount` of tokens, and finally the `data` section you can just input `0x00`, which typically represent Additional data with no specified format. mint tokens ## Step 6: Confirm your minted collectible And you're done! You can view the transactions submitted to the blockchain for your wallet address in the `Transactions` tab navigation view currency transactions # Contracts Source: https://docs.sequence.xyz/solutions/builder/contracts/overview Sequence Builder offers a user-friendly platform for smart contract deployment and management. Choose from contract templates or upload custom contracts, deploy directly to your chosen network. Sequence Builder simplifies smart contract deployment and management with a suite of user-friendly features. Import, deploy, and add contract collaborators to a smart contract in the contracts dashboard and interact directly with your contract. On production networks, treat Builder contract deployments as self-funded transactions. Even if you have configured Gas Sponsorship for related wallets or contracts, the deploying wallet may still need enough native gas token to pay for the deployment transaction. Gas Sponsorship is better thought of as support for relayed interactions after a contract is already deployed. ##### What are my deployment options? Deployment of contracts with Sequence Builder is simplified through a streamlined process directly within our dashboard. Choose from various contract templates (ERC1155, ERC721, ERC20). The Builder also gives you the option to upload your own custom contracts - saved to your project - and can be deployed directly to a network of your choosing. ##### What contract interactions can I do? Sequence Builder provides a comprehensive contract dashboard, allowing users to explore and monitor various smart contract activities like transactions, balance, and tokens. Performing read and executing write operations on contracts becomes effortless, making it easy for actions such as minting and collaborations. ## Watch a Contract be deployed with Builder
} href="/sdk/unreal/wallets/embedded-wallet/setup" /> Run the following from your terminal to clone the starter repo. ```bash React theme={null} npx sequence-cli boilerplates create-embedded-wallet-react-starter ``` ```bash Next theme={null} npx sequence-cli boilerplates create-embedded-wallet-nextjs-starter ``` Open your browser and navigate to `http://localhost:4444`. Click on Connect to initiate the authentication process. You can now test the Embedded wallet with the boilerplate! Now, let's configure your own project. Navigate to embedded wallet configuration for your project on Builder. Enter your recovery wallet address and set a password, then Create Configuration. Be aware that this configuration cannot be changed at a later date. Navigate to the cloned directory and copy & paste this configuration in the file `.env` replacing the existing configuration. Ensure you update the `PROJECT_ACCESS_KEY` and `WAAS_CONFIG_KEY` with the new keys located on the integration page. ```tsx theme={null} # Update with your project access key VITE_PROJECT_ACCESS_KEY="AQAAAAAAAKJcPk5v95BJE-Q7GwdlY9hPuAM" # Update with your WAAS_CONFIG_KEY VITE_WAAS_CONFIG_KEY="eyJwcm9qZWN0SWQiOjQxNTY0LCJycGNTZXJ2ZXIiOiJodHRwczovL3dhYXMuc2VxdWVuY2UuYXBwIn0=" VITE_GOOGLE= NULL VITE_APPLE= NULL VITE_WALLET_CONNECT_ID= NULL VITE_CHAINS= 80002 VITE_DEFAULT_CHAIN= 80002 ``` Save your `.env` file, run `pnpm dev` from the root directory, and navigate back to `http://localhost:4444`. Sign into your wallet using email to test the wallet actions again. You are done! You can now see your wallet connection on the Overview page and the keys are scoped to your project. As next steps: * You can now setup various [social authentication providers](/solutions/builder/embedded-wallet#login-providers). * [Use more features of our web-sdk](/sdk/web/wallet-sdk/embedded/guides/send-sponsored-tx). * [Request a ID token from Sequence to validate users on your backend](/sdk/headless-wallet/verification). # Wallet Linking: Embedded Wallet Authentication & External Wallet Sign-in Source: https://docs.sequence.xyz/solutions/wallets/developers/embedded-wallet/wallet-linking This guide demonstrates how to integrate a parent Embedded Wallet with web2 authentication methods for wallet linking purposes. It covers signing into a social login provider and linking using signatures from an external wallet signed in via Web SDK stored privately and securely. # Wallet Linking Overview Wallet Linking enables the ability for a developer to create a verifiable association between two wallets from a single user. Generally, this is a link between an embedded wallet for a game or application and an external wallet, such as Metamask. This solves a number of issues for games such as: * Validating a user holds an NFT, but doesn't want to move their valuable asset around for token-gating or reward distributions. * Easy migration for flow of funds or liquidity from an external wallet to the embedded wallet for a game. * Verifiying a number of ERC20 tokens a user holds to provide governance rights. Using Sequence SDKs, the embedded wallet session can be instantiated from nearly any platform such as Mobile, Web, PC or Console so users can enjoy a seamless game experience. However, when desired, a user is directed to an external browser session to link additional wallets. ## Try a Demo :::info Try out how wallet linking works [here](https://demo-waas-wallet-link-initiator.pages.dev/) by authenticating with your social login using an Embedded Wallet ::: Dive into the implementation for your own game or application, by following our integration guide below. # Integrating Wallet Linking Time to complete: 25-35 minutes In this guide, we will showcase how to sign into an [Embedded Wallet](/solutions/wallets/developers/embedded-wallet/overview) using traditional authentication like email or social login. Then, in order to link an external wallet address using Web SDK (now Web SDK) to your Embedded Wallet, we will sign a message which creates a queryable set of addresses for a single user profile stored off-chain privately. Finally, other features of the API will be delved into, like listing total wallets linked and removal of the state of linked wallets, both using signatures for privacy preserving means. # Demo Give a [try of an example demo](https://demo-waas-wallet-link.pages.dev/) or [view the full source code](https://github.com/0xsequence-demos/demo-embedded-wallet-linking). # Quickstart Try a quickstart application with a CLI command in your terminal to run locally: ### Clone the repo ```shell theme={null} git clone https://github.com/0xsequence-demos/demo-embedded-wallet-linking.git && cd ./demo-embedded-wallet-linking ``` ### Copy environment variables ```shell theme={null} cp .example.env .env ``` ### Run locally ```shell theme={null} pnpm install && pnpm dev ``` Once you have tested out the example, simply update the `.env` file with your Embedded Wallet configuration after creating a project with [Builder](https://sequence.build): 1. `Waas Config Key` [used for the Embedded Wallet](/solutions/builder/embedded-wallet). 2. `Project Access Key` [used for the Embedded Wallet](/solutions/builder/getting-started#claim-an-api-access-key). 3. How to obtain a `Google Client ID` for [social authentication with Embedded Wallets](/solutions/builder/embedded-wallet/google-configuration). # Using the Wallet Linking API ## 1. Integrating the API Interface File In order to begin using the API, an interface file is integrated into the cloned application so the Sequence API can be called upon conveniently. The [source code for the interface can be found here](https://github.com/0xsequence-demos/demo-embedded-wallet-linking/blob/master/src/api/api.gen.ts) which then is instantiated with the existing Sequence server like such: ```typescript theme={null} import { API, // API interface LinkedWallet // typed class } from "./api.gen"; const api = new API("https://dev-api.sequence.app", fetch); ``` #### Simple examples using the API functions integrated in the repository using `0xsequence/waas` and `wagmi` packages: 1. [`linkWallet(...)`](/solutions/wallets/developers/embedded-wallet/wallet-linking#2-link-an-external-wallet-to-an-embedded-wallet) 2. [`getLinkedWallets(...)`](/solutions/wallets/developers/embedded-wallet/wallet-linking#3-retrieving-linked-wallets) 3. [`removeLinkedWallet(...)`](/solutions/wallets/developers/embedded-wallet/wallet-linking#4-removing-linked-wallets) ## 2. Link an external wallet to an embedded wallet In order to link an external wallet (e.g. EOA, Sequence Universal Wallet, etc.) to an Embedded Wallet, we first need to authenticate the user with an embedded wallet which is categorized as the `parent` wallet. Once authenticated, we would then authenticate them again using Web SDK where the user signs a message after authentication to validate ownership of that wallet. That message will be passed to the `linkWallet` API endpoint, with the following typed arguments and return types (negating the optional values): ```typescript theme={null} interface LinkWalletArgs { parentWalletAddress: string // Address of the Embedded Wallet parentWalletMessage: string // Message from the Embedded Wallet parentWalletSignature: string // Signature from Embedded Wallet linkedWalletAddress: string // External wallet address you want to link linkedWalletMessage: string // Message from the external wallet linkedWalletSignature: string // Signature from the external wallet signatureChainId: string // ChainId which you want to verify, using 137 in the example. linkedWalletType?: string // Optional value to identify what type of wallet is being connected, i.e., 'sequence' } interface LinkWalletReturn { status: boolean } linkWallet(args: LinkWalletArgs, headers?: object, signal?: AbortSignal): Promise ``` ### Sign Message to Attest to Owning an Address There are two signatures required: one for the Embedded Wallet signing the Web SDK wallet address (linked wallet), and the linked wallet (from Web SDK) signing the parent wallet address (Embedded Wallet). You can sign any message presented to the user, as long as the message and signature are consistent with what is passed to the API later. For example, using the following code in React with Wagmi to obtain this information using Sequence: ```typescript theme={null} import { ... useSignMessage, useAccount, ... } from "wagmi"; function App() { const { signMessageAsync } = useSignMessage(); const { address: kitWalletAddress } = useAccount(); const getSignaturesForLinking = async () => { const parentWalletMessage = "linked wallet with address " const linkedWalletMessage = "parent wallet with address " const parentMessage = parentWalletMessage + kitWalletAddress const parentWalletAddress = await sequenceWaas.getAddress() const linkingMessage = "Link to " + linkedWalletMessage + parentWalletAddress const response: any = await signMessageAsync({ message: linkingMessage, }) const parentSignatureRes = await sequenceWaas.signMessage({ message: parentMessage }) const parentSignature = parentSignatureRes.data.signature const linkedSignature = response const linkedWalletAddress = kitWalletAddress return { parentWalletAddress, linkedWalletAddress, parentMessage, linkingMessage, parentSignature, linkedSignature } } } ``` ### Use API to Add Signature Payload & Parent Wallet Address Call the previous `getSignaturesForLinking` function and unpack the response to pass the responses into the `api.linkWallet` function: ```typescript theme={null} function App(){ const connections = useConnections(); ... const linkWallet = async () => { const signaturesResult = await getSignaturesForLinking() const { parentWalletAddress, linkedWalletAddress, parentMessage, linkingMessage, parentSignature, linkedSignature } = signaturesResult const connectorName = connections[0]?.connector.name; const response = await api.linkWallet({ signatureChainId: "137", // network chosen for both embedded wallet and Web SDK linkedWalletType: connectorName, parentWalletAddress, parentWalletMessage: parentMessage, parentWalletSignature: parentSignature, linkedWalletAddress: linkedWalletAddress!, linkedWalletMessage: linkingMessage, linkedWalletSignature: linkedSignature, }) console.log(`status: ${response.status}`) } } ``` ## 3. Retrieving Linked Wallets To protect the privacy of users, you can pass in a signature generated from the parent Embedded Wallet in order to retrieve the list of wallet addresses that is linked to a parent wallet address. The API will return the linked wallet objects in the following format: ```typescript theme={null} interface LinkedWallet { id: number walletType?: string walletAddress: string linkedWalletAddress: string createdAt?: string } interface GetLinkedWalletsReturn { linkedWallets: Array } ``` And this can be accomplished in the following way, by passing in a message, getting a signature from the parent Embedded Wallet, checking to see the signature is readable, then passing the variables: `parentWalletAddress`,`parentWalletMessage`,`parentWalletSignature` and `signatureChainId` to the API: ```typescript theme={null} const getLinkedWallets = async () => { const parentWalletAddress = await sequenceWaas.getAddress() const message = "parent wallet with address " + parentWalletAddress const signature = await sequenceWaas.signMessage({ message: message, }) if (!signature.data.signature) { console.error("Could not get signature from wallet to be linked") throw new Error("Could not get signature from wallet to be linked") } const response = await api.getLinkedWallets({ parentWalletAddress: parentWalletAddress as `0x${string}`, parentWalletMessage: message, parentWalletSignature: signature.data.signature, signatureChainId: "137", }) response.linkedWallets.map((linkedWallet: LinkedWallet) => console.log(linkedWallet)) return response.linkedWallets } ``` ## 4. Removing Linked Wallets Finally, if you no longer want to keep a wallet linked off-chain to a parent wallet, you can perform a signature by both wallet instances (Embedded Wallet & Web SDK linked wallet), and pass in the linked wallet address, [like in step 6](/solutions/wallets/developers/embedded-wallet/wallet-linking#2-link-an-external-wallet-to-an-embedded-wallet) in order to remove the linked state: ### Sign Message to Attest to Removing a Linked Address ```typescript theme={null} import { ... useAccount, useSignMessage ... } from "wagmi"; function App() { const { address: kitWalletAddress } = useAccount(); const { signMessageAsync } = useSignMessage(); const getSignaturesForUnlinking = async () => { const parentWalletMessage = "linked wallet with address " const linkedWalletMessage = "parent wallet with address " const parentWalletAddress = await sequenceWaas.getAddress() const linkingMessage = "Unlink from " + linkedWalletMessage + parentWalletAddress const response: any = await signMessageAsync({ message: linkingMessage, }) const parentSignatureRes = await sequenceWaas.signMessage({ message: parentMessage }) const parentSignature = parentSignatureRes.data.signature const linkedSignature = response const linkedWalletAddress = kitWalletAddress return { parentWalletAddress, linkedWalletAddress, parentMessage, linkingMessage, parentSignature, linkedSignature } } } ``` ### Use API to Add Signature Payload for Parent Address ```typescript theme={null} function App(){ ... const unLinkWallet = async () => { const signaturesResult = await getSignaturesForUnlinking() const { parentWalletAddress, linkedWalletAddress, parentMessage, linkingMessage, parentSignature, linkedSignature } = signaturesResult; const response = await api.removeLinkedWallet({ signatureChainId: "137", // network chosen for both Embedded Wallet and Web SDK parentWalletAddress, parentWalletMessage: parentMessage, parentWalletSignature: parentSignature, linkedWalletAddress: linkedWalletAddress!, linkedWalletMessage: linkingMessage, linkedWalletSignature: linkedSignature, }); console.log(`status: ${response.status}`) } } ``` ## Conclusion We've provided a sample application that allows you to authenticate a user with your embedded wallet configuration, validate a message from an external wallet, and then link these together using the Sequence Linking API. Furthermore, we went over how to use these API functions using simple examples from React & Wagmi. You can either use the standalone application we've provided or leverage the same flow in your own application from here. # Wallets for Developers Source: https://docs.sequence.xyz/solutions/wallets/developers/overview Use this page to choose the right integration path and jump to the relevant guides. Connect your app to an Ecosystem Wallet hosted on your ecosystem's domain. Users authenticate with passkeys, social auth, or email preconfigured on the wallet. Keep your current Embedded Wallet integration for existing apps. Use your own social auth or email auth. ## Ecosystem Wallet Quickstarts You can use the following quickstarts to integrate with an existing Ecosystem Wallet. If you don't have an Ecosystem Wallet to integrate to, you can connect to the Sequence Ecosystem Wallet demo at [acme-wallet.ecosystem-demo.xyz](https://acme-wallet.ecosystem-demo.xyz). Fastest way to add a complete, non-custodial smart wallet experience to a web-based application. Add a complete, non-custodial smart wallet experience to a Unity-based application. ## Embedded Wallets You might want to continue leveraging our Embedded Wallet product for the time being if: * You have a production integration that relies on the Embedded Wallet architecture. * You need a short-term prototype while your Ecosystem Wallet is being set up. * See [Embedded Wallet docs](/solutions/wallets/developers/embedded-wallet/overview) and plan a medium-term migration to Ecosystem Wallet. ## Next steps * Start with the [Ecosystem Wallet quickstart](/solutions/wallets/developers/ecosystem-wallet/react_quickstart). * If you operate a chain or plan an ecosystem-wide wallet, go to [For Ecosystems](/solutions/wallets/ecosystems/overview). # Custom Wallet Source: https://docs.sequence.xyz/solutions/wallets/ecosystems/custom-wallet Build a fully custom Ecosystem Wallet using the Wallet Development Kit on top of Sequence infrastructure. Self-host critical components if needed. The **Wallet Development Kit (WDK)** lets you build a custom Ecosystem Wallet while using Sequence infrastructure for identity, sessions, transactions, and data. You own the UI, routing, and product decisions, and you can self-host critical components where required. * Package: `@0xsequence/wallet-wdk` * Repo: [sequence.js](https://github.com/0xsequence/sequence.js) ## What you build vs what we provide | Area | You build | Sequence provides | | ----------------- | --------------------------------------- | ----------------------------------------------------------------------------------------- | | UI/UX | Wallet screens, flows, routing, theming | Reference components and SDKs | | Auth and sessions | Choose login UX, wire flows | Identity Instrument (session attestations), Smart Sessions model | | Transactions | App-specific flows and UX | [Transaction API](/solutions/infrastructure/transaction-api) for relaying and sponsorship | | Data | Custom views and analytics | [Indexer](/solutions/indexer/overview) for balances, NFTs, events, prices | | Node access | Optional custom providers | [Blockchain RPC](/solutions/infrastructure/blockchain-rpc) via Node Gateway | | Backend | Optional business logic | [Sidekick](/solutions/infrastructure/sidekick) for secure server-side endpoints | ## Available capabilities * **Smart Sessions** and session attestations for scoped, low-friction execution. * **Passkeys and social logins** with enclave-signed sessions. * **Cross-chain accounts** with a single on-chain configuration root (signers, sessions, recovery). * **Timed recovery keys** for private passphrase support with time-based recovery. * **Developer integrations**: Web, React Native, Unity, and Unreal via existing SDKs. * **Services**: Indexer for reads, Transaction API for writes, Node Gateway RPC for raw calls. ## High-level integration flow Add the package: pnpm add @0xsequence/wallet-wdk. Decide which components you will self-host (e.g., UI, Identity Instrument) versus use hosted. Set the wallet domain, supported chains, branding, and session policies. Use Builder for environment, keys, and policy management. Use the Identity Instrument for session attestations. Implement the login and session callback flow, and store session keys securely. Read with [Indexer](/solutions/indexer/overview), write with [Transaction API](/solutions/infrastructure/transaction-api), and access nodes with [Blockchain RPC](/solutions/infrastructure/blockchain-rpc). Validate Smart Session scopes, recovery paths, and cross-chain actions. Roll out on your domain. ## Notes on self-hosting * **[Identity Instrument](/solutions/wallets/ecosystems/identity-instrument)** can be self-hosted in your own AWS Nitro Enclave environment if your compliance model requires it. * You can run your own **[Sidekick](/solutions/infrastructure/sidekick)** for controlled server-side writes and key custody. * Contracts, audits, and deployments are documented in [Technical References](/solutions/technical-references/overview). ## Next steps * Explore the repo: [sequence.js](https://github.com/0xsequence/sequence.js). * Share [For Developers](/solutions/wallets/developers/overview) with app teams integrating into your ecosystem. * Review [Smart Sessions](/solutions/wallets/ecosystems/smart-sessions) and [For Ecosystems](/solutions/wallets/ecosystems/overview). * Get in touch with us to get started: [Contact Us](https://sequence.xyz/contact). # Guard Firewall Source: https://docs.sequence.xyz/solutions/wallets/ecosystems/guard-firewall Ecosystem-level review signer that evaluates every transaction against policies, simulations, and blacklists before allowing execution. **Guard Firewall** is a Sequence-operated review signer that evaluates transactions before they are sent on-chain. It enforces ecosystem policies, performs threat simulations via third-party integrations, and can block or allow transactions by signing or withholding a **guard signature**. Ecosystem admins can also maintain **blacklists** of malicious apps or contracts. ```mermaid theme={null} sequenceDiagram autonumber participant App as App participant Guard as Guard Firewall participant Relayer as Transaction API participant Chain as EVM Chain participant User as User (OTP) App->>Guard: 1) Submit signed txn bundle Guard->>Guard: 2) Run threat assessment simulation Guard-->>Guard: Simulation results & risk score alt 3) Guard accepts Guard-->>App: Return co-signed transaction else 4) Guard rejects Guard-->>App: OTP confirmation required App->>User: Prompt for OTP User-->>App: Provide OTP App->>Guard: Resubmit with OTP proof Guard-->>App: Return co-signed transaction (requirements satisfied) end App->>Relayer: 5) Submit fully signed transaction Relayer->>Chain: 6) Relay/broadcast on EVM chain ``` ## Policy model Policies are configured per ecosystem and can include: * **App registration and blacklists**: only registered apps/origins may submit; admins can blacklist apps or contracts. * **Risk thresholds**: block transactions that exceed a risk score returned by the simulator. * **Method and contract allowlists**: restrict which contracts and function selectors can be called. * **Spend limits and token rules**: cap per-interval outflows by token, recipient, or app. * **Emergency kill switch**: fail-closed mode that blocks all or specific scopes. ## Threat simulation Guard can perform real-time threat analysis on the transaction payload (calldata, value, state deltas). Based on the ecosystem configuration, Guard applies policy thresholds and signs or denies the transaction, or requires OTP confirmation. ```mermaid theme={null} sequenceDiagram autonumber participant App as App participant Guard as Guard Firewall participant Sims as Simulator participant User as User App->>Guard: 1) Submit txn bundle + Session Key + Attestation Guard->>Sims: 2) Run threat assessment simulation Sims-->>Guard: Simulation results (risk score, findings) Guard->>Guard: Evaluate policies (rules, allowlist/blacklist) alt 3) Guard accepts Guard-->>App: Return co-signed transaction else 4) Guard rejects Guard-->>App: OTP confirmation required App->>User: Prompt for OTP User-->>App: Provide OTP App->>Guard: Resubmit with OTP proof Guard-->>App: Return co-signed transaction (requirements met) end ``` ## Blacklist controls * Admins can blacklist apps, origins, or contracts. Blacklists take precedence and cause immediate denials. * Lists are propagated to the Guard and cached with short TTL; updates are near-real-time. ## Implementation guidance * Require a **Guard signature** in your session or wallet policy so transactions cannot bypass review. * Register apps and origins in your ecosystem admin, define policies, and set risk thresholds. * Keep blacklists curated and respond quickly to incident intel. # Hosted Wallet Source: https://docs.sequence.xyz/solutions/wallets/ecosystems/hosted-wallet Launch an Ecosystem Wallet on your domain with Sequence-operated infrastructure, branding control, Smart Sessions, and passkey-based auth. ecosystem wallet The **Hosted Wallet** is the fastest way to launch an Ecosystem Wallet on your domain. Sequence operates the wallet infrastructure while you control branding, configuration, and policies in Builder. Your developers then integrate against a stable, attested wallet surface across all your apps. ## What you get * **Your domain and brand**: run at `wallet.yourdomain.com` with your theme, logo, and copy. * **Smart Sessions**: scoped, sandboxed permissions per app to reduce signing spam and protect users. * **Passkeys and familiar logins**: support for passkeys plus email/social logins; external wallets can be linked. * **Attested identity**: sessions are signed by an enclave-based Identity Instrument; apps never handle social auth keys. * **Cross-chain by default**: multi-chain accounts, balances, and transactions. * **Admin in Builder**: configure chains, branding, session policies, and integrations from an ecosystem admin panel. * **Production ops**: Sequence runs the wallet stack, Identity Instrument, monitoring, and updates. Smart Sessions are central to ecosystem safety and UX. Learn more in [Smart Sessions](/solutions/wallets/ecosystems/smart-sessions). ## How it works In Builder, set your wallet domain, branding, supported chains, and initial policies. Enable passkeys and connect your identity providers. Session attestations are issued by the enclave-based Identity Instrument. Create Smart Session scopes for your apps (methods, limits, timeouts), and register app origins. Sequence provisions and operates the wallet on your domain. Your developers connect apps using the standard integration flow. ## Security and reliability * **Non-custodial**: users control their keys; timed recovery keys can be enabled. * **Hardware isolation**: critical signing and identity attestations use TEEs (AWS Nitro Enclaves). * **Key Machine**: only the latest wallet configuration is accepted on-chain; supports safe key rotation. * **Audited architecture**: see [Technical References](/solutions/technical-references/overview) for contracts, audits, and deployments. ## Who it is for Chains and ecosystems that want a branded wallet, fast time to market, and managed operations without building a wallet from scratch. ## Next steps * Review [For Ecosystems](/solutions/wallets/ecosystems/overview) and [Smart Sessions](/solutions/wallets/ecosystems/smart-sessions). * Share [For Developers](/solutions/wallets/developers/overview) with partner teams to integrate their apps. * Get in touch with us to get started: [Contact Us](https://sequence.xyz/contact). # Identity Instrument Source: https://docs.sequence.xyz/solutions/wallets/ecosystems/identity-instrument Enclave-backed service that verifies user identity, binds device Auth Keys, and signs session attestations for Ecosystem Wallets. **Identity Instrument** is an enclave-backed service (TEE in AWS Nitro Enclaves) responsible for authenticating users with either email/phone confirmation via OTP or an OIDC-compatible identity provider (IdP, such as Google or Apple). It binds a device-generated **Auth Key** to the authenticated user, and uses an **Identity Signer** to sign session attestations or digests. Applications never handle IdP client secrets directly; the Identity Instrument mediates the exchange and issues the final signature. ## Cryptographic Attestation Identity Instrument is deployed from an EIF (Enclave Image File) published as a public GitHub release. An EIF is built deterministically from the codebase and a set of **measurements** are derived from all the code included in the build. This means that a build at a specific commit will always produce the same measurements. These measurements are **attested** by the AWS Nitro system that ensures that they are valid for the exact built that they describe. This is done with a document called **cryptographic attestation** that is signed by the AWS PKI (Public Key Infrastructure), it can be validated by anyone. The attestation is included in every request to AWS KMS that verifies its validity. Trusted Third Parties (entities tasked with managing the KMS keys used to encrypt Identity Instrument data) set up the KMS keys with policies that only allow access to the key if the correct EIF is deployed, identified by its measurements. Every response from Identity Instrument contains the attestation in the HTTP header `X-Attestation-Document`. All of the above combines to ensure that Identity Instrument is secure and **publicly verifiable**. ## Authentication modes Identity Instrument supports two authentication modes: * OTP Auth (email/phone) * OAuth AuthCode with PKCE (ecosystem mediated) ### OTP Auth (email/phone) The `OTP` authentication mode is used to send a randomly generated Code directly to the destination specified by the User. That destination becomes the identity with which the Auth Key is associated. The way the Code is sent depends on the Identity Type used (e.g. email message, text message, etc.) but in every case the flow remains the same. The Identity Signer is retrieved or created based on the destination (email address, phone number, etc.) ```mermaid theme={null} sequenceDiagram participant User participant Client participant Nitro as Identity Instrument Client ->> Client: Generate Auth Key Client ->> Nitro: Initiate Auth Nitro ->> Nitro: Generate and store Code & Challenge Nitro -->> User: Send Code Nitro -->> Client: Challenge User ->> Client: Code Client ->> Client: Combine Code & Challenge Client ->> Nitro: Register Auth ``` ### OAuth AuthCode with AuthCodePKCE The AuthCodePKCE authentication mode uses the OAuth2 "Authorization Code Flow" to retrieve user profile from an external Identity Provider. By utilizing the Proof of Key Code Exchange (PKCE) OAuth2 extension, the Client is never able to exchange the authorization code, even if it's in possession of the Client Secret. This is enforced by a random Code Verifier that is generated and stored securely by Identity Instrument. Its hash, called Code Challenge, is used by the Client to start the IdP authentication process. The original Code Verifier is sent by Identity Instrument with the token request. The Identity Provider ensures that it hashes to the same value as sent in the initial request, preventing token exchange if the process wasn't initiated by Identity Instrument. ```mermaid theme={null} sequenceDiagram participant Client participant OAuth IdP participant Nitro as Identity Instrument participant Secure Store Client ->> OAuth IdP: Authenticate OAuth IdP -->> Client: Authorization Code Client ->> Client: Generate Auth Key Client ->> Nitro: Initiate Auth Nitro ->> Nitro: Store Verifier
(hashed authorization code) Client ->> Nitro: Register Auth Nitro ->> Secure Store: Request Client Secret Secure Store -->> Nitro: Client Secret Nitro ->> OAuth IdP: Exchange Code
for Access Token OAuth IdP -->> Nitro: Access Token Nitro ->> OAuth IdP: Request User Info OAuth IdP -->> Nitro: User Info ``` ## Encryption Pool Identity Instrument encrypts its data (such as signer EOA private keys) using AES-256-CBC with private keys selected randomly from a global cipher key pool. Each of these cipher (encryption) keys is split into 3 parts using Shamir's secret sharing, requiring a minimum of 2 parts in order to decrypt a given cipher key. Each part is then encrypted using a different remote AWS KMS encryption key. Only the resulting ciphertexts are stored in Identity Instrument's database. Two of the KMS keys are owned and controlled by separate Trusted Third Parties - organizations unaffiliated with Sequence. The third KMS is owned and controlled by Sequence itself. This means that in the end each signer private key is secured by a 2/3 remote key setup where no single entity has access to the data. At the same time, losing a Trusted Third Party doesn't compromise the system nor lead to data loss, provided the other 2 TTPs are still active. ## Security properties * Applications never receive IdP client secrets; only the enclave performs the exchange. * PKCE prevents code interception during OAuth redirects. * Enclave attestation lets ecosystems verify they are talking to the correct service binary. * Key rotations and config migrations are supported without downtime via the pool generations. ## References * [Identity Instrument Github Repo](https://github.com/0xsequence/identity-instrument) * [TEE Verifier (TypeScript)](https://github.com/0xsequence/tee-verifier.js) * [TEE Verifier (Go)](https://github.com/0xsequence/tee-verifier) # Wallets for Ecosystems Source: https://docs.sequence.xyz/solutions/wallets/ecosystems/overview Ecosystem Wallet is a consumer-ready smart wallet that runs on your domain and serves all your apps. It combines passkeys, social auth, timed recovery keys, and sandboxed permissions to deliver higher security with less friction. ecosystems overview ## Why ecosystems adopt this solution * **One wallet across all your apps** on your domain and branded for your ecosystem. * **Smart Sessions** remove security risks by sandboxing permissions for each app. See [Smart Sessions](/solutions/wallets/ecosystems/smart-sessions). * **Passkeys** provide strong, phishing-resistant auth without seed phrases. * **Timed recovery keys** provide private passphrase support with time-based recovery for best-in-class security. See [Timed Recovery](/solutions/wallets/ecosystems/timed-recovery). * **Attested identity** using a TEE service that signs session attestations and keeps social auth secrets out of reach from any app. See [Identity Instrument](/solutions/wallets/ecosystems/identity-instrument). * **Ecosystem Admin** in Builder to configure chains, branding, session policies, and integrations. ## Deployment options Sequence runs the wallet on your domain with your branding. Control configuration in Builder and launch on a custom domain. Build a wallet with the Wallet Development Kit on top of Sequence infrastructure. Critical components can be self-hosted. ## Architecture basics * **Smart Sessions**: scoped permissions that enable apps to execute under sandboxed rules. See [Smart Sessions](/solutions/wallets/ecosystems/smart-sessions). * **Identity Instrument**: a Nitro-enclave service that validates IdP logins and signs session attestations. Your apps never handle raw IdP client secrets. See [Identity Instrument](/solutions/wallets/ecosystems/identity-instrument). * **Merkleized wallet configuration**: a single on-chain root covers signers, sessions, recovery, and extensions. See [Wallet Configuration](/solutions/wallets/ecosystems/wallet-config). * **Guard Firewall**: reviews every transaction for malicious activity, and enforces ecosystem-level blacklists and policies. See [Guard Firewall](/solutions/wallets/ecosystems/guard-firewall). *** ## Demo Discover Apps on the Sequence Ecosystem Wallet. ## Next steps * Evaluate [Hosted Wallet](/solutions/wallets/ecosystems/hosted-wallet) vs [Custom Wallet](/solutions/wallets/ecosystems/custom-wallet). * Share with your developers: [For Developers](/solutions/wallets/developers/overview). * Get in touch with us to get started: [Contact Us](https://sequence.xyz/contact). # Smart Sessions Source: https://docs.sequence.xyz/solutions/wallets/ecosystems/smart-sessions Sequence's Smart Sessions provide a seamless way to interact with apps by reducing wallet pop-ups and improving user experience. ## The Problem with Web3 UX Today In Web3 today, the user experience is often interrupted. Every swap, every listing, every minor action requires a wallet pop-up, forcing you to "sign" and approve. This creates friction and makes apps feel clunky compared to the smooth apps we use every day. ## What Are Smart Sessions? **Smart Sessions is a solution to this problem.** A Smart Session is a secure, temporary, and strictly limited set of permissions that you grant to an app. Instead of approving every single transaction, you approve a session once, allowing the app to perform a range of pre-agreed actions on your behalf. This eliminates constant pop-ups and unlocks a fluid, Web2-like experience without sacrificing security or self-custody. > 💡 **Think of it this way:** It's less like handing over your master key (your main wallet signer) and more like giving an application a special-purpose keycard with very clear rules and limitations. ## Two Types of Smart Sessions Sequence offers two distinct types of Smart Sessions, each designed for a different purpose: * **Implicit Sessions:** For ultimate convenience within a single, trusted app. * **Explicit Sessions:** For powerful, granular control over any on-chain action. *** ## 1. Implicit Sessions: The "In-App Convenience Pass" An Implicit Session is the simplest and most common type of Smart Session. Its entire purpose is to make your experience inside a single app as smooth as possible. ```mermaid theme={null} flowchart TD U[👤 User] --> C["Clicks 'Connect Wallet'
on App"] C --> S["✔️ Session Created"] S --> F["🛡️ Digital Fence is Established
(Scoped to the App Domain)"] F --> SW["✔️ Swap App's Token
(Instant & Pop-up Free)"] F --> ST["✔️ Stake in App's Pool
(Instant & Pop-up Free)"] F -.-> EC["⚠️ Attempt to directly call an external contract
(e.g., main USDC contract)"] EC --> B["⛔ BLOCKED ON-CHAIN
The session is not valid outside the fence"] style F fill:#d9edf7,stroke:#2a6496,stroke-width:1px,color:#000 style S fill:#d9edf7,stroke:#2a6496,stroke-width:1px,color:#000 style SW fill:#fff,stroke:#666,color:#000 style ST fill:#fff,stroke:#666,color:#000 style EC fill:#fff,stroke:#666,stroke-dasharray: 3 3,color:#000 style B fill:#f2dede,stroke:#a94442,stroke-width:1px,color:#000 ``` ### 🎯 The Core Idea When you connect to an app you trust, you are creating a "trust boundary" around that app's website domain. An Implicit Session gives that app a pass to operate freely only within its own walls. ### ⚙️ How It Works 1. **Connect & Trust:** You connect your wallet to an app (e.g., `app.my-defi-protocol.com`) 2. **Silent Approval:** A session is automatically and silently created that is cryptographically locked to that specific domain without the user having to approve it. 3. **Seamless Experience:** You can now perform any action inside that app, swapping, staking, listing, without any further pop-ups. It just works. ### 🔒 The Security Guardrail This session is useless anywhere else. If the app was malicious and tried to use this session to call a contract outside its domain (like the USDC contract), the transaction would be automatically rejected on-chain. The session is only valid for the app's own smart contracts. The app will configure the permissions in the [Sequence Builder](https://sequence.build) All transactions must be sponsored by the DApp itself when using Implicit Sessions since using any other currency as a fee option is treated as an external contract interaction and will be blocked. ### 📊 Implicit Sessions at a Glance | Aspect | Details | | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Best For** | Day-to-day use of a fully gas sponsored DApp, 0 pop-ups, with no need for external contract interactions. | | **Key Feature** | Maximum convenience. Eliminates all signing pop-ups within a trusted app environment | | **Analogy** | A keycard for a specific building. It lets you move freely between all the rooms inside, but it won't open the door to the building next door. | | **Drawback:** | The DApp has to sponsor the gas fees for all transactions and it cannot interact with any external smart contract, locked to the app's own smart contracts. | *** ## 2. Explicit Sessions: The "Programmable Permission Slip" An Explicit Session is a more advanced and powerful tool. It's designed for when an app needs to perform very specific tasks that interact with other external protocols. ```mermaid theme={null} flowchart TD U[👤 User] --> C["Connects to App &
Logs In"] C --> P["📄 App Proposes Session Rules
(For a seamless swap experience)"] P --> R["📝 User Reviews Granular Rules:
- Action: transfer() on USDC Contract
- Target: Only App's Swap Router
- Limit: Up to 100 USDC
- Expires: 24 hours"] R --> A["🙋 User Explicitly Approves
This Exact Set of Rules"] A --> V["⚙️ On-Chain Validation Activated"] V -->|Invalid Action: Transfer USDC to other address| B1["⛔ BLOCKED
(Target is not the Swap Router)"] V -->|Valid Action: Swap using 50 USDC| OK["✔️ ALLOWED
(All rules are met)"] V -->|Invalid Action: Swap using 101 USDC| B2["⛔ BLOCKED
(Exceeds value limit)"] style P fill:#d9edf7,stroke:#2a6496,stroke-width:1px,color:#000 style R fill:#d9edf7,stroke:#2a6496,stroke-width:1px,color:#000 style A fill:#337ab7,stroke:#2a6496,stroke-width:1px,color:#fff style V fill:#d9edf7,stroke:#2a6496,stroke-width:1px,color:#000 style OK fill:#dff0d8,stroke:#3c763d,stroke-width:1px,color:#000 style B1 fill:#f2dede,stroke:#a94442,stroke-width:1px,color:#000 style B2 fill:#f2dede,stroke:#a94442,stroke-width:1px,color:#000 ``` ### 🎯 The Core Idea Instead of trusting an app and its smart contracts only, you are approving a precise list of rules for a temporary signer that can interact with any smart contract. You are building a custom permission slip that says exactly what can be done, where it can be done, how much can be spent, for how long, and for which contracts. ### ⚙️ How It Works 1. **The app proposal:** The app presents your wallet with a list of very specific permissions it needs. For example: * "Allow me to call the `transfer` function on the `USDC contract`." * "... with the `recipient` address `0x...` only" * "...for a `cumulative` total of no more than `100` USDC." * "...for a duration of `24 hours`." 2. **You Explicitly Approve the Rules:** Your wallet displays these rules in a human-readable format. You review and approve this exact set of conditions. 3. **The app Executes:** The app can now perform those actions automatically, with 0 pop-ups. ### 🔒 The Security Guardrail The power of Explicit Sessions comes from their granularity. Each rule is validated on-chain. If the app tries to do anything outside the approved scope, like spend 101 USDC instead of 100, or call the `approve` function instead of `transfer`, the transaction will fail. ### 📊 Explicit Sessions at a Glance | Aspect | Details | | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Best For** | Granular control over any action, not tied to your app's smart contracts only. | | **Key Feature** | Granular, programmable control. You define the exact scope of what the app is allowed to do with no restrictions. | | **Analogy** | A keycard that can work for many buildings but you have to first sign a contract defining the exact rules for each building, only then you can use it. | | **Drawback:** | The user has to carefully review and approve the DApp's permissions adding 1 extra step in the UX. | ### Versatile Integrations Best part is that you can combine the two types of sessions together to get the best of both worlds. Whenever you go out of scope on an Implicit Session, Sequence SDKs will automatically switch a single-transaction approval state, functioning like an EOA. For repeated actions outside of an Implicit Session, you can request an Explicit Session for a seamless integration. # Timed Recovery Source: https://docs.sequence.xyz/solutions/wallets/ecosystems/timed-recovery Ecosystem Wallets come with built-in timed recovery, enabling passphrase-based recovery of any wallet with a 24-word recovery phrase and a 30-day lockdown. At recovery start, the user provides a recipient wallet address; the system queues a deterministic transfer bundle to move inventory to that recipient after the delay. Finalization is not automatic: once the countdown completes, the user returns and executes the queued transactions using an EOA wallet (for example MetaMask). The recovery request is visible on-chain. Watchtower emails the registered address throughout the window. If Sequence infrastructure is unavailable, recovery still works using the standalone recovery tool and session metadata replicated on Arweave. ## Design goals and security properties * Enforced delay: Recovery cannot finalize before 30 days. This removes instant, silent takeover paths common with mnemonic-only backup and recovery modes. * Deterministic effect: The queued payload is a fixed transfer plan to a user-specified recipient. Auditors and operators can pre-compute and monitor the exact outcome. * On-chain observability: The queued request is public. Watchtower sends escalating email notifications to the recovery email. * Sequence independence: Contracts are self-sufficient. Users can run the standalone recovery tool. Session metadata required by the client is continuously backed up to Arweave chain for permanent storage. The only requirement is that the target EVM chain must be live. ## Prerequisites and configuration * 24-word recovery phrase: Created for the wallet via UI or SDK. Used only for recovery authorization. * Recovery notifications email: Bound to the recovery key at mnemonic creation. Used by Watchtower. * Optional encrypted digital backup: Store an encrypted form of the mnemonic in a reputable password manager (for example 1Password). Protect it with a memorized decryption password that is not stored with the encrypted blob. ## Recovery flow (user UX) 1. User is logged in, creates the recovery signer mnemonic, and adds the signer to the wallet with the existing session. 2. At a later date, user is logged out and initiates the recovery flow from the main auth screen. 3. User enters the recovery mnemonic. The wallet derives the recovery EOA, fetches wallet session metadata, and shows an inventory preview. 4. User provides a target recipient wallet address (must be different from the source wallet). The wallet constructs and queues a transfer bundle for recovery. 5. User initiates recovery. The UI shows the exact date and time to return. The request is recorded on-chain and Watchtower notification cadence begins. 6. User can return at any time to see the live countdown. 7. If the local device does not have the stored recovery-waiting state, the user re-enters the recovery mnemonic. The wallet detects the active recovery and shows the countdown. 8. After the countdown completes (T+30 days), the user triggers execution of the queued transfer bundle using an EOA wallet (for example MetaMask). Inventory moves to the recipient wallet. ```mermaid theme={null} sequenceDiagram participant User participant WalletApp as Ecosystem Wallet participant RecoveryContract as Recovery contract participant Recipient as Recipient wallet participant EOA as EOA wallet User->>WalletApp: Start Recovery with 24 word passphrase WalletApp-->>WalletApp: Recovery wallet derived and validated WalletApp-->>User: Inventory preview User->>WalletApp: Provide EOA recipient address + inventory items to transfer WalletApp->>EOA: Prepared recovery payload with transfers bundle EOA->>RecoveryContract: Sign and queue recovery payload RecoveryContract-->>WalletApp: Payload queued and timestamped Note over User,RecoveryContract: 30-day countdown User->>WalletApp: Return any time to view countdown alt Re-Auth if Needed User->>WalletApp: Re-enter 24 word passphrase WalletApp-->>User: Detect active recovery and show countdown end User->>WalletApp: At T+30, re-connect EOA (i.e. MetaMask) WalletApp->>EOA: Prepare final proof EOA->>RecoveryContract: Submit final proof RecoveryContract->>WalletApp: Authorize transfers bundle WalletApp-->>Recipient: Assets transferred Recipient-->>User: Continue on recipient wallet ``` ## Notifications * On queue, Watchtower emails the recovery email registered at mnemonic creation. * Frequency increases as T+30 approaches. * If Sequence email infrastructure is unavailable, on-chain visibility remains. Integrators can run independent watchers and notifications. * User with access to the wallet can cancel the recovery request at any time. ## FAQ Q: Do users regain interactive access to the original wallet at T+30?\ A: No. The model moves inventory to the specified recipient. Users proceed with the recipient wallet. Q: Can an active recovery be stopped?\ A: Yes. Any time before finalization. Stopping or rotating configuration invalidates the queued payload. Q: What if Sequence services are offline?\ A: Recovery still works. Users run the standalone recovery tool. The tool reads session metadata from Arweave (continuous backups) and submits the same on-chain steps. Only requirement is that the EVM chain must be live. Q: What are the costs?\ A: Gas to queue the payload, gas to finalize, and gas for the transfer bundle. Q: What if the user loses the 24-word phrase?\ A: If both main access and the recovery phrase are lost, recovery is not possible. Users are guided to maintain offline storage plus an encrypted backup. If the user still has at least one open session on a device, they can start recovery using the active session, even if they never created a recovery key. # Merkleized Wallet Configuration Source: https://docs.sequence.xyz/solutions/wallets/ecosystems/wallet-config Single-root wallet configuration for Ecosystem Wallets, enabling signers, sessions, recovery, and extensions with efficient on-chain proofs. Ecosystem Wallets store a single **Merkle root** on-chain that commits to the entire wallet configuration: signers, weights, thresholds, passkey authenticators, Smart Session rules, recovery mechanisms, and future extensions. Actions provide **Merkle proofs** to validate the parts of the configuration that are relevant at execution time. ## Model * **Root**: the wallet contract stores one hash root. * **Leaves**: typed records for signers, sessions, recovery, passkeys, and modules. * **Extensions**: modules interpret specific leaf types (e.g., session enforcement, passkeys). * **Proofs**: execution supplies Merkle proofs for the leaves it needs (e.g., signer weight, session rule). ```mermaid theme={null} flowchart TD Root[Merkle Root on-chain] subgraph OffchainConfig["Off-chain configuration tree"] A[Signer leaves] B[Session rules] C[Passkey authenticators] D[Recovery config] E[Future modules] end OffchainConfig -->|hash| Root Tx[Transaction] -->|proofs for needed leaves| Root ``` ## Updating configuration Configuration updates (add device, change session limits, rotate keys) happen off-chain by computing a new tree and root. **Key Machine** service attests to the latest root; transactions can include or reference this attestation so the wallet accepts only the latest configuration. ```mermaid theme={null} sequenceDiagram participant User participant Wallet participant Key Machine User->>Wallet: Propose new config (off-chain tree) Wallet->>Key Machine: Submit new root Key Machine-->>Wallet: Attest current root (signed) User->>Wallet: Execute tx with proofs + checkpointer attestation Wallet->>Wallet: Verify proofs match attested root Wallet-->>User: Execute ``` ## Smart Sessions and Passkeys * **Smart Sessions**: leaves define scopes for a session key (allowed contracts/functions, spend limits, expiries). Execution validates the session key and rule proofs before allowing actions. * **Passkeys**: passkey authenticators are leaves; devices produce WebAuthn signatures that are validated by the passkey extension using the relevant leaf proof. ## Recovery * **Timed recovery keys**: a recovery leaf encodes a time-lock window; initiating recovery starts a countdown where existing signers can cancel. After expiry, the recovery key can rotate primary signers. ## Efficiency * Only the root is stored on-chain; proofs are provided as calldata when needed. * Packing and bitmap techniques minimize calldata for multi-sig or multi-proof cases. ## Cross-chain coherency * The same root governs all chains for a wallet; checkpointer attestations allow each network to accept only the canonical root, preventing replay with stale configurations. ## References * [Wallet Contracts](https://github.com/0xsequence/wallet-contracts-v3) # Overview Source: https://docs.sequence.xyz/solutions/wallets/overview Sequence Ecosystem Wallet is a non-custodial smart wallet designed for chains and ecosystems. It combines passkeys, social auth, timed recovery keys, and sandboxed permissions to deliver higher security with less friction. ## Choose your path Connect your app to an existing Ecosystem Wallet, handle auth and Smart Sessions, and ship on Web, Mobile, Unity, or Unreal. Plan and launch an ecosystem-wide wallet on your domain. Choose hosted or custom, understand Smart Sessions, and deployment options. Are you an existing **Sequence Embedded Wallet** user? See the docs here: [Embedded Wallet](/solutions/wallets/developers/embedded-wallet/overview). ## Why Sequence Ecosystem Wallet * **One address per user across apps and chains** — consistent identity and no more token fragmentation. * **Smart Sessions** isolate permissions per app for maximum security and fewer signatures. See [Smart Sessions](/solutions/wallets/ecosystems/smart-sessions). * **Seamless onboarding** with email, social auth, passkeys, or external wallets. * **Cross-chain by default** with built-in swaps, on-ramps, and combined portfolio views. * **Developer-first SDKs** for Web, Mobile, Unity, and Unreal. * **Enterprise-grade security**: hardware-isolated signers (TEEs), and public attestations for every deployment. * **Timed recovery keys** provide private passphrase support with time-based recovery for best-in-class security. See [Timed Recovery](/solutions/wallets/ecosystems/timed-recovery). ## For Ecosystems ecosystem wallet * **One wallet that works everywhere** on your domain and branded for your ecosystem. * **Eliminate fragmentation**: a single address and inventory across your ecosystem, with sandboxed Smart Sessions protecting users and protocols. * **Branded wallet UX**: hosted by Sequence on your domain, or fully custom with the Wallet Development Kit. * **Fast developer adoption**: app teams integrate in minutes with Web, Mobile, Unity, and Unreal SDKs. * **Curated discovery**: wallet surfaces ecosystem apps and assets. * **Security by design**: isolated signing keys, hardware-backed TEEs, public attestations for every deployment secured by Quantstamp and CoinCover. * **Ecosystem Admin** in Builder to configure chains, branding, session policies and app/domain blacklists. 👉 Learn more: [Wallets for Ecosystems](/solutions/wallets/ecosystems/overview) ## For Developers ecosystem wallet * **Production-ready smart wallets** on any platform without building wallet infra. * **Zero-config auth** with Google, Apple, email, and passkeys. * **Frontend SDKs** for Web, React Native, Unity, and Unreal. * **Backend SDKs** for mints, transfers, batching, and monitoring. * **Sidekick backend**: a dockerized web3 backend with secure key management. * Works across **DeFi, payments, fintech, stablecoins, NFTs, and games**. * **Built for real use cases**: * **DeFi & payments**: gas-sponsored onboarding, built-in swap and on-ramp, real-time balances, cross-chain transactions. * **Games**: embedded wallet UI, token portability across titles, Smart Sessions for in-game permissions, one-click marketplace checkout. 👉 Learn more: [Wallets for Developers](/solutions/wallets/developers/overview) # Boostrap your Ecosystem Wallet Game Source: https://docs.sequence.xyz/sdk/unity/bootstrap Using the provided boilerplates to quickly get your integration up and running. Sequence's Unity SDK includes a range of features to help you bootstrap your game. Import our Boilerplates from the `Demo` samples in the Package Manager UI. Create them using the `BoilerplateFactory` as shown below. Feel free to adjust the UI and logic inside the samples to fit your needs. Ensure that your codebase has access to the `Sequence.Boilerplates.asmdef` assembly. Checkout the `BoilerplateController.cs` for more integration examples. ## Ecosystem Wallet ### Login Window Create the `EcosystemWalletLoginWindow` prefab to authenticate users as a Guest, with Email OTP, Google- or Apple Sign In. [Checkout the Ecosystem Wallet Setup section](/sdk/unity/wallets/ecosystem-wallet/setup) for more details on how to configure your project to connect to an Ecosytem of your choice. ```csharp theme={null} BoilerplateFactory.OpenEcosystemWalletLoginWindow(parent); ``` **parent (Transform)** Transform inside of a Canvas object. ### Profile Create the `EcosystemWalletProfile` prefab to sign messages, add more sessions and view wallet details. ```csharp theme={null} BoilerplateFactory.OpenEcosystemWalletProfile(parent, wallet); ``` **parent (Transform)** Transform inside of a Canvas object. **wallet (EcosystemWallet.IWallet)** The Ecosystem Wallet instance. ### Transactions Create the `EcosystemWalletTransactions` prefab to test sending transactions with pre-configured permissions. ```csharp theme={null} BoilerplateFactory.OpenEcosystemWalletTransactions(parent, wallet); ``` **parent (Transform)** Transform inside of a Canvas object. **wallet (EcosystemWallet.IWallet)** The Ecosystem Wallet instance. ## Embedded Wallet Embedded Wallet Boilerplates use Arbitrum Sepolia by default. Do the following to switch them to your preferred chain `EmbeddedWalletAdapter.GetInstance().Chain = Chain.TestnetPolygonAmoy;` ### Login Window Create the `EmbeddedWalletLoginWindow` prefab to authenticate users as a Guest, with Email OTP, Google- or Apple Sign In. [Checkout the Authentication section](/sdk/unity/wallets/embedded-wallet/onboard/authentication/intro) for more details on how to configure your project for each login option. ```csharp theme={null} BoilerplateFactory.OpenEmbeddedWalletLoginWindow(parent); ``` **parent (Transform)** Transform inside of a Canvas object. ### In-Game Shop Accelerate your game growth by selling items directly to your players. Create the `SequencePlayerProfile` prefab to show an In-Game Shop that utilizes game items from a ERC1155 contract, which users purchase using any custom or existing ERC20 currency. [Primary Sales Contract](/solutions/builder/contracts/deploy-primary-sales-contract/): Learn how to set up and deploy contracts for launching a primary sale. ```csharp theme={null} BoilerplateFactory.OpenSequenceInGameShop(parent, wallet, chain, collectionAddress, saleContractAddress, itemsForSale, onClose); ``` **parent (Transform)** Transform inside of a Canvas object. **wallet (IWallet)** The wallet instance you receive from the SequenceWallet.OnWalletCreated event after completing the login process. **chain (Chain)** The chain type (Ethereum, Sepolia, ..) on which the specified contract is deployed. **collectionAddress (string)** ERC1155 contract address. Deploy your own contract on Builder first. **saleContractAddress (string)** ERC1155 Sale contract address when you deploy your sale on Builder. **itemsForSale (int\[])** Array of token Ids which you wish to sell to your players. **onClose (Action)** Optional. Callback when the user closes this window. ### Daily Rewards Reward users with NFTs or Collectibles for playing your game for consecutive days. Deploy our server boilerplate which performs the mint transaction whenever they claim their reward. Make sure to deploy our [Daily Rewards Server Boilerplate](https://github.com/0xsequence-demos/daily-rewards-server-boilerplate) img ```csharp theme={null} BoilerplateFactory.OpenSequenceDailyRewards(parent, wallet, chain, apiUrl, onClose); ``` **parent (Transform)** Transform inside of a Canvas object. **wallet (IWallet)** The wallet instance you receive from the SequenceWallet.OnWalletCreated event after completing the login process. **chain (Chain)** The chain type (Ethereum, Sepolia, ..) on which the specified contract is deployed. **apiUrl (string)** The API url you receive after deploying the required server boilerplate. **onClose (Action)** Optional. Callback when the user closes this window. ### Player Profile Create the `SequencePlayerProfile` prefab to manage your current profile. This includes functionalities such as Sign Out, linking external wallets, sending native tokens, and QR code to receive funds. img ```csharp theme={null} BoilerplateFactory.OpenSequencePlayerProfile(parent, wallet, chain, onClose); ``` **parent (Transform)** Transform inside of a Canvas object. **wallet (IWallet)** The wallet instance you receive from the SequenceWallet.OnWalletCreated event after completing the login process. **chain (Chain)** The chain type (Ethereum, Sepolia, ..) on which the specified contract is deployed. **onClose (Action)** Optional. Callback when the user closes this window. ### Inventory Create the `SequenceInventory` prefab to show all items owned by a user from any ERC1155 or ERC721 contract. img ```csharp theme={null} BoilerplateFactory.OpenSequenceInventory(parent, wallet, chain, collections, onClose); ``` **parent (Transform)** Transform inside of a Canvas object. **wallet (IWallet)** The wallet instance you receive from the SequenceWallet.OnWalletCreated event after completing the login process. **chain (Chain)** The chain type (Ethereum, Sepolia, ..) on which the specified contract is deployed. **collectionAddress (string\[])** Array of RC1155 or ERC721 contract addresses. Deploy your own contract on Builder first. **onClose (Action)** Optional. Callback when the user closes this window. ### Sign Messages Create the `SequenceSignMessage` prefab to show a modal that lets you sign a specified text. img ```csharp theme={null} BoilerplateFactory.OpenSequenceSignMessage(parent, wallet, chain, onClose); ``` **parent (Transform)** Transform inside of a Canvas object. **wallet (IWallet)** The wallet instance you receive from the SequenceWallet.OnWalletCreated event after completing the login process. **chain (Chain)** The chain type (Ethereum, Sepolia, ..) on which the specified contract is deployed. **onClose (Action)** Optional. Callback when the user closes this window. # Installation Source: https://docs.sequence.xyz/sdk/unity/installation ## Package Manager - Recommended ### OpenUPM 1. [Install OpenUPM](https://openupm.com/#get-started-with-cli-optional) 2. Open a command line at the root of your Unity project 3. `openupm add xyz.0xsequence.waas-unity` ### or using Package Manager UI 1. Ensure you have Git 2.14.0 or above installed on your machine 2. Open Package Manager (Window > Package Manager) 3. Click the "+" icon in the Package Manager window > "Add package from git URL..." 4. Paste this url and click Add or press Enter on your keyboard `https://github.com/0xsequence/sequence-unity.git?path=/Packages/Sequence-Unity` ### Setup 1. Open Package Manager (Window > Package Manager) 2. From Package Manager, click on "Samples" 3. Import "Setup" from Samples Setup a) This will import a Resources folder with some boilerplate UI prefabs for you to use in your project. 4. Import `TMP Essentials` (if you haven't already). Note: Unity should prompt you to do this automatically if you attempt to Play or Build with a TextMeshPro object in your scene. Import TMPro ### Samples In addition to this documentation, we've also provided you with a few samples to help with using our SDK. These can be found by: 1. Opening Package Manager 2. Finding our SDK "Sequence WaaS SDK" 3. Click on "Samples" 4. Click "Import" next to any sample you wish to install. This will create a Samples folder under Assets and import the sample there. The sample will be completely mutable as it lives within your Assets folder. Samples The second sample "Demo Scene" is sample scene that showcases some of the features of our SDK. It serves as a useful supplement to the documentation. Note that you will need to import `Setup` in order for this demo to work properly. The third sample "Useful Scripts" contains useful scripts and Prefabs that make integrating the SDK easier. ## Manual Installing via Package Manager will put the SDK in a read-only state - note: you will still be able to modify the UI when using Package Manager. For most use cases, this is ideal. However, we recognize that some advanced users will want the flexibility to edit the SDK as they see fit. Please note that if you do chose this route that updating the SDK will become more challenging because any changes you make will be overwritten and these changes can easily go unnoticed in a version control system. In general, we feel it is safer to import the SDK in read-only mode via Package Manager and write wrappers to extend as needed, but we empower you to work with our SDK how you see fit. 1. Add [Newtonsoft.json](https://docs.unity3d.com/Packages/com.unity.nuget.newtonsoft-json@3.0/manual/index.html) to your project (if it isn't there already) via package manager. Click on the "+" icon in the Package Manager window > "Add package by name..." and add `com.unity.nuget.newtonsoft-json`. 2. Download [the latest release of the Sequence Unity SDK UnityPackage](https://github.com/0xsequence/sequence-unity/releases) 3. Drag the `.unitypackage` file into your project window and import it 4. Import `TMP Essentials` (if you haven't already). Note: Unity should prompt you to do this automatically if you attempt to Play or Build with a TextMeshPro object in your scene. # Overview Source: https://docs.sequence.xyz/sdk/unity/overview Documentation for Unity SDK overview for the Sequence infrastructure stack for web3 gaming. # Introduction The Sequence Unity Embedded Wallet SDK provides full Sequence [Embedded Wallet](/sdk/headless-wallet) and [Indexer](/api-references/indexer/overview) integration for your Unity Games, integrated with our own purpose-built for Unity SequenceEthereum library. That's right, no Nethereum required! This SDK follows [Semantic Versioning](https://semver.org/) (`major.minor.patch`). Breaking changes will always cause a `major` version increment, non-breaking new features will cause a `minor` version increment, and bugfixes will cause a `patch` version increment. ## Requirements Unity 2021.3.6f1 or later * Android * iOS * PC standalone -> (Mono builds only when using Social Sign in -> the system commands throw exceptions when doing IL2CPP builds -> see [OpenIdAuthentication.PlatformSpecificSetup](https://github.com/0xsequence/sequence-unity/blob/master/Packages/Sequence-Unity/Sequence/SequenceSDK/Authentication/OpenIdAuthenticator.cs.cs#L244)) * Mac standalone -> (Mono builds only when using Social Sign in -> in our testing MacOS doesn't pick up custom URL schemes automatically unless you run some system commands first; these system commands only work on Mono -> see [OpenIdAuthentication.PlatformSpecificSetup](https://github.com/0xsequence/sequence-unity/blob/master/Packages/Sequence-Unity/Sequence/SequenceSDK/Authentication/OpenIdAuthenticator.cs#L244)) * WebGL ## Additional Resources In addition to reading these docs, you can also checkout [our guide](/guides/jelly-forest-unity-guide) that details how we made the Jelly Forest demo game. # Unity Ecosystem Wallet Authentication Source: https://docs.sequence.xyz/sdk/unity/wallets/ecosystem-wallet/authentication Ecosystem Wallet Documentation for Sequence's Unity SDK. Start with an implicit session which is restricted to contracts built by Sequence. Alternatively, you can choose to add a `IPermissions` object to each Sign In call, if you want to connect to an explicit session directly. [Learn how to construct permissions.](/sdk/unity/wallets/ecosystem-wallet/permissions) ### Recover wallet from storage This function returns `null` when no wallet is found. ```csharp theme={null} IWallet wallet = SequenceWallet.RecoverFromStorage(); ``` ### Create an Interface to Sign In ```csharp theme={null} SequenceConnect connect = new SequenceConnect(); ``` ### Get Ecosystem Config Get configuration data from the Ecosystem. This includes data such as the name, description, enabled chains and auth providers. ```csharp theme={null} EcosystemConfig config = await connect.GetEcosystemConfig(); string name = config.name; EcosystemAuthProvider[] authProviders = config.enabledProviders; ``` ### Sign In with Email ```csharp theme={null} string email = "your.mail@example.com"; IWallet wallet = await connect.SignInWithEmail(email); ``` ### Sign In with Google ```csharp theme={null} IWallet wallet = await connect.SignInWithGoogle(); ``` ### Sign In with Apple ```csharp theme={null} IWallet wallet = await connect.SignInWithApple(); ``` ### Sign In with Passkey ```csharp theme={null} IWallet wallet = await connect.SignInWithPasskey(); ``` ### Sign In with Mnemonic ```csharp theme={null} IWallet wallet = await connect.SignInWithMnemonic(); ``` # Unity Ecosystem Wallet Blockchain Interactions Source: https://docs.sequence.xyz/sdk/unity/wallets/ecosystem-wallet/blockchain-interactions Ecosystem Wallet Documentation for Sequence's Unity SDK. ## Sign messages Sign messages on an external browser. ```csharp theme={null} Chain chain = Chain.TestnetAbitrumSepolia; string message = "Your message to sign."; SignMessageResponse response = await wallet.SignMessage(chain, message); string signature = response.signature; ``` ## Send transactions Send transactions without paying for gas fees on any testnet or when using Gas Sponsorship. ```csharp theme={null} Chain chain = Chain.TestnetAbitrumSepolia; Address to = new Address("0x33985d320809E26274a72E03268c8a29927Bc6dA"); ITransaction[] transactions = new Transaction[] { new Transaction(to, 0, "implicitEmit()"), new Transaction(to, 0, "explicitEmit()") }; string txnHash = await wallet.SendTransaction(chain, transactions); ``` ## Send transactions using Fee Options Get available fee options for the user and choose one to use when sending the transaction. ```csharp theme={null} Chain chain = Chain.TestnetAbitrumSepolia; Address to = new Address("0x33985d320809E26274a72E03268c8a29927Bc6dA"); ITransaction[] transactions = new Transaction[] { new Transaction(to, 0, "implicitEmit()"), new Transaction(to, 0, "explicitEmit()") }; FeeOption[] feeOptions = await _wallet.GetFeeOption(chain, transactions); FeeOption feeOption = feeOptions[0]; // Choose a way to select the appropriate option string txnHash = await wallet.SendTransaction(chain, transactions, feeOption); ``` ### Check if your wallet supports a transaction You can do the same call for multiple transactions at once if you pass in a `Transactions[]` array. ```csharp theme={null} Chain chain = Chain.TestnetAbitrumSepolia; Address to = new Address("0x33985d320809E26274a72E03268c8a29927Bc6dA"); ITransaction transaction = new Transaction(to, 0, "implicitEmit()"); bool supported = await wallet.SupportsTransaction(chain, transaction); ``` # Manage Unity Ecosystem Wallet Sessions Source: https://docs.sequence.xyz/sdk/unity/wallets/ecosystem-wallet/manage-sessions Ecosystem Wallet Documentation for Sequence's Unity SDK. ### Add Session Add additional sessions to your existing login method. Every session shares the same wallet address with the possibility of assigning different permissions for each session. You must provide a `IPermissions` object whenever you call `AddSession`. [Learn how to construct permissions.](/sdk/unity/wallets/ecosystem-wallet/permissions) ```csharp theme={null} Address contractAddress = new Address("0x33985d320809E26274a72E03268c8a29927Bc6dA"); BigInteger deadline = new BigInteger(DateTimeOffset.UtcNow.ToUnixTimeSeconds() * 1000 + 1000 * 60 * 5000); IPermissions permissions = new ContractPermissions(Chain.TestnetAbitrumSepolia, contractAddress, deadline, 0); await wallet.AddSession(permissions); ``` ### Disconnect Sign out will clear the local storage. ```csharp theme={null} wallet.Disconnect(); ``` ### Get All Session Wallets Get all available sessions that you are currently connected to. ```csharp theme={null} Address[] signerAddresses = wallet.GetAllSigners(); ``` ## Events ### On Wallet Created The `WalletCreated` event is called whenever you sign in or you recover a wallet from storage. ```csharp theme={null} SequenceWallet.WalletCreated += wallet => { // Integrate your own logic to handle wallet creations. } ``` ### On Wallet Disconnected The Disconnected event is called whenever you hit `wallet.Disconnect()`. This means, you need to re-connect. ```csharp theme={null} SequenceWallet.Disconnected += () => { // Integrate your own logic to handle disconnects. } ``` # Unity Ecosystem Wallet Permissions Source: https://docs.sequence.xyz/sdk/unity/wallets/ecosystem-wallet/permissions Ecosystem Wallet Documentation for Sequence's Unity SDK. ### Parameters * **Chain:** The chain this signer is allowed to interact with. * **Target:** The contract address this signer is allowed to interact with. * **Deadline:** The deadline for this permission as a UTC timestamp in milliseconds. * **Value Limit:** The maximum total amount of native tokens this signer can send. * **Parameter Rules:** The rules that define how this signer is allowed to interact with the target contract. ### Single contract permission ```csharp theme={null} Chain chain = Chain.TestnetAbitrumSepolia; Address contractAddress = new Address("0x33985d320809E26274a72E03268c8a29927Bc6dA"); BigInteger deadline = new BigInteger(DateTimeOffset.UtcNow.ToUnixTimeSeconds() * 1000 + 1000 * 60 * 5000); BigInteger valueLimit = 0; IPermissions permissions = new ContractPermissions(chain, contractAddress, deadline, valueLimit); ``` ### Permissions with multiple targets ```csharp theme={null} Chain chain = Chain.TestnetAbitrumSepolia; Address contractAddress1 = new Address("0x7F5c764cBc14f9669B88837ca1490cCa17c31607"); Address contractAddress2 = new Address("0x33985d320809E26274a72E03268c8a29927Bc6dA"); IPermissions permissions = new Permissions(chain, new ContractPermissions(contractAddress1, deadline, valueLimit), new ContractPermissions(contractAddress2, deadline, valueLimit)); ``` ### Parameter rules ```csharp theme={null} var rule = new ParameterRule { cumulative = false, operation = (int)ParameterOperation.equal, value = Array.Empty(), offset = new BigInt(0), mask = Array.Empty(), }; ContractPermissions permissions = new ContractPermission(...); permissions.AddRule(rule); ``` # Unity SDK Setup for Ecosystem Wallets Source: https://docs.sequence.xyz/sdk/unity/wallets/ecosystem-wallet/setup Ecosystem Wallet Documentation for Sequence's Unity SDK. Sign in and create a project on [Sequence Builder](https://sequence.build). Next, create a SequenceConfig ScriptableObject in Unity: `Assets` > `Create` > `Sequence` > `SequenceConfig` and place it inside your `Resources` directory. Make sure you insert the required fields: * **Builder API Key:** Your Project Access Key from your [Builder project.](https://sequence.build/) * **Wallet App Url:** The URL of the Ecosystem you want to connect to. If you are unsure, use `https://v3.sequence-dev.app` as a default. You can optionally get the configured auth providers from the Ecosystem directly and check if your target auth method, like Email or Google, is supported. Next, let's call an auth method like Google. This will redirect the user to an external browser to authenticate against the Ecosystem. You have two options to authenticate. You either create an implicit- or explicit session. You create an implicit session by passing no node to the `Permissions` field. Implicit session will only allow transactions to contracts from the Ecosystem. For this demo, let's instead create an explicit session for a specific contract. ```csharp theme={null} // Let's create the permissions object Chain chain = Chain.TestnetAbitrumSepolia; Address contractAddress = new Address("0x33985d320809E26274a72E03268c8a29927Bc6dA"); BigInteger deadline = new BigInteger(DateTimeOffset.UtcNow.ToUnixTimeSeconds() * 1000 + 1000 * 60 * 5000); BigInteger valueLimit = 0; IPermissions permissions = new ContractPermissions(chain, contractAddress, deadline, valueLimit); // Let's call the Sign-In method SequenceConnect connect = new SequenceConnect(); IWallet wallet = await connect.SignInWithGoogle(permissions); // Optionally, get the Ecosystem config to check your auth providers EcosystemConfig config = await connect.GetEcosystemConfig(); ``` Import the `Demo` sample from Unity's Package Manager. Additionally, checkout our boilerplate script [EcosystemWalletLoginWindow](https://github.com/0xsequence/sequence-unity/blob/master/Packages/Sequence-Unity/Sequence/SequenceBoilerplates/Scripts/EcosystemWallet/EcosystemWalletLoginWindow.cs) for integration details. You can use this Boilerplate inside your project after importing the Demo Samples. Then, simply call this function: `BoilerplateFactory.OpenEcosystemWalletLogin(parent)` If you have installed the SDK as a `.unitypackage` file, please locate the Demo scene inside Unity's `Project` window under `Packages > Sequence SDK > Sequence > Samples > Demo` # Intro Source: https://docs.sequence.xyz/sdk/unity/wallets/embedded-wallet/onboard/authentication/intro # Authentication - Introduction As an Embedded Wallet SDK, authentication is extremely important. Authentication works by establishing a session signing wallet through association with user credentials. For more on how our Embedded Wallet works, please [see Embedded Wallet docs](/solutions/wallets/developers/embedded-wallet/overview). To implement authentication, we recommend using our [SequenceLoginWindow](/sdk/unity/bootstrap#login) boilerplate. We recommend having the `Canvas Scaler` component attached to your `Canvas` use the "Scale with Screen Size" UI Scale Mode. This will make it so that the login window (and any other UI elements under this Canvas) are scaled automatically when switching between build targets. This will provide you easy access to two authentication methods: 1. [Email + OTP Sign In](/sdk/unity/wallets/embedded-wallet/onboard/authentication/email) 2. [OIDC-based Social Sign In](/sdk/unity/wallets/embedded-wallet/onboard/authentication/oidc) The SDK also provides support for: 3. [PlayFab Sign In](/sdk/unity/wallets/embedded-wallet/onboard/authentication/playfab) 4. [Guest Sign In](/sdk/unity/wallets/embedded-wallet/onboard/authentication/guest) ## Retrieving the `SequenceWallet` Once you've obtained credentials from one of the supported authentication methods (please see their respective documentation), you'll want to catch a reference to your newly created `SequenceWallet`. Please subscribe to the `SequenceWallet.OnWalletCreated` event. This can be done with the following code snippet: ```csharp theme={null} SequenceWallet.OnWalletCreated += OnWalletCreatedHandler; public void OnWalletCreatedHandler(SequenceWallet wallet) { // Do something } ``` where `OnWalletCreatedHandler` is a function accepting a `SequenceWallet` as it's only parameter. If you're unfamiliar with working with events in Unity, check out this great [Reddit post](https://www.reddit.com/r/gamedev/comments/u3hz2v/how_to_use_events_a_supersimple_unity_example/)! ## Error Handling In order to catch errors during the login process, please make sure to subscribe to the `OnLoginFailed` event. ```csharp theme={null} SequenceLogin login = SequenceLogin.GetInstance(); login.OnLoginFailed += OnLoginFailedHandler; public void OnLoginFailedHandler(string message, LoginMethod method, string email, List loginMethods = default) { Debug.LogError($"Error logging in: {message} with login method {method} and email {email}"); } ``` # Unity SDK Setup for Embedded Wallets Source: https://docs.sequence.xyz/sdk/unity/wallets/embedded-wallet/setup Documentation for Unity SDK setup for the Sequence infrastructure stack for web3 gaming. [Configure your Embedded Wallet](/sdk/headless-wallet/quickstart) in the Sequence Builder Install the latest version of Sequence's Unity SDK from [OpenUPM](/sdk/unity/installation#openupm), or use [Unity's Package Manager UI](/sdk/unity/installation#or-using-package-manager-ui) and use the following Git URL `https://github.com/0xsequence/sequence-unity.git?path=/Packages/Sequence-Unity` Sign in and create a project on [Sequence Builder](https://sequence.build). Download your config file from Builder as shown below. Place this file in the root of a `Resources` folder. Start by checking if a wallet session is available from storage: ```csharp theme={null} bool recovered = await EmbeddedWalletAdapter.GetInstance().TryRecoverWalletFromStorage(); ``` If that returns `false` you should ask the user to sign. Import the `Setup` Sample from the Package Manager UI which will place a set of boilerplates into your project in a `Resources/` directory. Create the [Login Boilerplate](/sdk/unity/bootstrap) to send a one-time password to the specified email address. Once you’ve your first features integrated, you can continue with [additional login providers](/sdk/unity/wallets/embedded-wallet/onboard/authentication/intro) such as Google, Apple, or PlayFab. ```csharp theme={null} BoilerplateFactory.OpenSequenceLoginWindow(parent); ``` Sequence's Unity SDK includes a variety of [Boilerplates](/sdk/unity/bootstrap) to help you quickly start your game. Once everything is configured, you can create prefabs to display an Player Profile, Inventory, or In-Game Shop. Checkout [how to integrate a Player Profile.](/sdk/unity/bootstrap) ```csharp theme={null} BoilerplateFactory.OpenSequencePlayerProfile(parent, wallet, chain); ``` Start with the `EmbeddedWalletAdapter` to quickstart your integration with a few one-liners and you are ready to go. When you want to customize your integration, checkout our other docs such as [authenticating users](/sdk/unity/wallets/embedded-wallet/onboard/authentication/intro) or [how to send transactions.](/sdk/unity/wallets/embedded-wallet/blockchain-interactions) ```csharp theme={null} EmbeddedWalletAdapter adapter = EmbeddedWalletAdapter.GetInstance(); // Recover your wallet from storage bool recovered = await adapter.TryRecoverWalletFromStorage(); // Otherwise, create a new session via Google Sign-In bool successful = await adapter.GoogleLogin(); // Next, let's send a transaction string recipientAddress = "0xabc123.."; string currencyAddress = "0xabc123.."; BigInteger amount = 1000; await adapter.SendToken(recipientAddress, amount, currencyAddress); ``` ## Configuration Parameters `Url Scheme` - You must replace this with a string that is unique to your application. This is very important. Failure to do so will cause unexpected behaviour when signing in with social sign in and it will not work. `StoreSessionPrivateKeyInSecureStorage` - Available on select platforms: we have integrated with the platform's native secure storage system. If enabled, we will store session wallet info (including the private key) in secure storage and automatically attempt to recover the session for the user after closing the app (so they won't need to login again). With this disabled (default) or on an unsupported platform, the session wallet's private keys never leave the application's runtime memory; however, your user will need to sign in again anytime they close the app. The default `SequenceLoginWindow` Boilerplate (see [Bootstrap your Game](/sdk/unity/bootstrap)) will handle this behaviour for you automatically, navigating to the appropriate page. `EnableMultipleAccountsPerEmail` - By default, the SDK will only allow users to create one account per email. The account is initially associated with the login method used (email + OTP, PlayFab, Google, etc.); the user can associate additional login methods with their account (more on this in the [Authentication section](/sdk/unity/wallets/embedded-wallet/onboard/authentication/federated-accounts)). If `EnableMultipleAccountsPerEmail` is enabled, users have the option to create multiple accounts per email address (associated with different login methods). While we have enabled this functionality, we, in general, feel this behaviour may be confusing to end-users and recommend integrators keep this option in the default disabled status. Before proceeding, please make sure you have properly configured the Embedded Wallet in the Builder. See this [guide](/solutions/builder/embedded-wallet/configuration). Please double check that you have copy and pasted the configuration keys from the Builder correctly! This is the most common issue reported when integrating our SDK. If you receive an "invalid tenant" response, you have messed up your configuration! See this [guide](/solutions/builder/embedded-wallet/configuration). # Getting started Source: https://docs.sequence.xyz/sdk/web/checkout-sdk/getting-started Learn how to get started with Checkout SDK This package is dependent on [Connect SDK](/sdk/web/wallet-sdk/ecosystem/getting-started). Follow the steps [here](/sdk/web/wallet-sdk/ecosystem/getting-started). ```bash theme={null} npm install @0xsequence/checkout # or pnpm install @0xsequence/checkout # or yarn add @0xsequence/checkout ``` ```typescript [main.tsx] theme={null} import React from "react"; import ReactDOM from "react-dom/client"; import "./index.css"; import App from "./App"; import { config } from "./config"; import { SequenceConnect } from "@0xsequence/connect"; import { SequenceCheckoutProvider } from "@0xsequence/checkout"; function Dapp() { return ( ); } ReactDOM.createRoot(document.getElementById("root")!).render( ); ``` Now you can start using hooks like [useSelectPaymentModal](/sdk/web/checkout-sdk/hooks/useSelectPaymentModal). # useAddFundsModal Source: https://docs.sequence.xyz/sdk/web/checkout-sdk/hooks/useAddFundsModal Hook for managing the add on-ramp modal ## Import ```tsx theme={null} import { useAddFundsModal } from '@0xsequence/checkout' ``` ## Usage ```tsx theme={null} import { useAddFundsModal } from '@0xsequence/checkout' function App() { const { triggerAddFunds } = useAddFundsModal() const walletAddress = '0x123...' // User's wallet address const handleAddFunds = () => { triggerAddFunds({ walletAddress, defaultFiatAmount: '50', defaultCryptoCurrency: 'USDC', onOrderSuccessful: (data) => { console.log('Order successful!', data) } }) } return ( ) } ``` If you receive a 403 error when trying to load Transak's URL, it means your domain needs to be whitelisted. Please contact us for assistance in resolving this issue. ## Return Type: `UseAddFundsModalReturnType` The hook returns an object with the following properties: ```tsx theme={null} type UseAddFundsModalReturnType = { triggerAddFunds: (settings: AddFundsSettings) => void closeAddFunds: () => void addFundsSettings: AddFundsSettings | undefined } ``` ### Properties #### triggerAddFunds `(settings: AddFundsSettings) => void` Opens the On-ramp modal with the specified parameters. **Parameters:** | Parameter | Type | Description | | ----------------------- | --------------------- | ---------------------------------------------------------------- | | `walletAddress` | `string \| Hex` | The address of the wallet to receive funds | | `fiatAmount` | `string` | (Optional) The exact fiat amount to be used | | `fiatCurrency` | `string` | (Optional) The currency for the fiat amount (e.g., 'USD', 'EUR') | | `defaultFiatAmount` | `string` | (Optional) The default fiat amount to display | | `defaultCryptoCurrency` | `string` | (Optional) The default cryptocurrency to purchase | | `cryptoCurrencyList` | `string` | (Optional) Comma-separated list of available cryptocurrencies | | `networks` | `string` | (Optional) Comma-separated list of available networks | | `onClose` | `() => void` | (Optional) Callback when the modal is closed | | `onOrderCreated` | `(data: any) => void` | (Optional) Callback when a new order is created | | `onOrderSuccessful` | `(data: any) => void` | (Optional) Callback when order completes successfully | | `onOrderFailed` | `(data: any) => void` | (Optional) Callback when order fails | #### closeAddFunds `() => void` Closes the On-ramp modal. #### addFundsSettings `AddFundsSettings | undefined` **AddFundsSettings Interface:** ```tsx theme={null} interface AddFundsSettings { walletAddress: string | Hex fiatAmount?: string fiatCurrency?: string defaultFiatAmount?: string defaultCryptoCurrency?: string cryptoCurrencyList?: string networks?: string onClose?: () => void onOrderCreated?: (data: any) => void onOrderSuccessful?: (data: any) => void onOrderFailed?: (data: any) => void } ``` The current settings configuration for the On-ramp modal. ## Notes This hook provides methods to control the On-ramp modal powered by Transak, allowing users to buy cryptocurrency with a credit/debit card directly within your application. # useCheckoutModal Source: https://docs.sequence.xyz/sdk/web/checkout-sdk/hooks/useCheckoutModal Hook for managing a simple checkout modal ## Import ```tsx theme={null} import { useCheckoutModal } from '@0xsequence/checkout' ``` ## Usage ```tsx theme={null} import { useCheckoutModal } from '@0xsequence/checkout' import { polygon } from 'viem/chains' import { useAccount } from 'wagmi' function Home() { const { address } = useAccount() const { triggerCheckout, closeCheckout, settings } = useCheckoutModal() const handleCheckout = () => { // NFT purchase settings const chainId = polygon.id const orderbookAddress = '0xfdb42A198a932C8D3B506Ffa5e855bC4b348a712' const nftQuantity = '1' const tokenContractAddress = '0xabcdef...' // NFT contract address const tokenId = '123' // NFT token ID triggerCheckout({ creditCardCheckout: { chainId, contractAddress: orderbookAddress, recipientAddress: address || '', currencyQuantity: '100000', currencySymbol: 'USDC', currencyAddress: '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359', currencyDecimals: '6', nftId: tokenId, nftAddress: tokenContractAddress, nftQuantity, approvedSpenderAddress: orderbookAddress, calldata: "0x...", onSuccess: (txHash) => console.log('Success!', txHash) }, orderSummaryItems: [ { chainId: chainId, contractAddress: orderbookAddress, quantityRaw: nftQuantity, tokenId: tokenId, } ] }) } return ( ) } export default Home ``` ### Properties #### triggerCheckout `(settings: CheckoutSettings) => void` Opens the Checkout modal with the specified parameters. **Parameters:** The `settings` object can include the following properties: | Property | Type | Description | | -------------------- | -------- | -------------------------------------- | | `creditCardCheckout` | `object` | Settings for credit card checkout flow | | `orderSummaryItems` | `array` | Items to display in the order summary | The `creditCardCheckout` object includes: | Parameter | Type | Description | | ------------------------ | -------------------------- | -------------------------------------------------- | | `chainId` | `number` | The blockchain network ID | | `contractAddress` | `string` | The address of the contract to interact with | | `recipientAddress` | `string` | The address to receive the purchased item | | `currencyQuantity` | `string` | The quantity of currency to use for payment | | `currencySymbol` | `string` | The symbol of the currency (e.g., 'USDC') | | `currencyAddress` | `string` | The address of the currency token contract | | `currencyDecimals` | `string` | The number of decimals for the currency | | `nftId` | `string` | The ID of the NFT being purchased | | `nftAddress` | `string` | The address of the NFT contract | | `nftQuantity` | `string` | The quantity of NFTs to purchase | | `approvedSpenderAddress` | `string` | The address allowed to spend tokens | | `calldata` | `string` | The encoded function call data for the transaction | | `onSuccess` | `(txHash: string) => void` | Callback when transaction succeeds | The `orderSummaryItems` array contains objects with: | Parameter | Type | Description | | ---------- | -------- | ------------------------ | | `title` | `string` | The title of the item | | `subtitle` | `string` | The subtitle of the item | | `imageUrl` | `string` | URL of the item's image | #### closeCheckout `() => void` Closes the Checkout modal. #### settings `CheckoutSettings | undefined` The current settings configuration for the Checkout modal. ## Notes This hook provides methods to control the Checkout modal that allows users to complete purchases using various payment methods. Checkout supports credit card payments and crypto payments for purchasing digital assets. # useSelectPaymentModal Source: https://docs.sequence.xyz/sdk/web/checkout-sdk/hooks/useSelectPaymentModal Hook for opening the payment selection modal ## Import ```tsx theme={null} import { useSelectPaymentModal } from '@0xsequence/checkout' ``` ## Usage ```typescript [abis/mintFunctionAbi.ts] theme={null} const mintFunctionAbi = { type: 'function', name: 'mint', inputs: [ { name: 'to', type: 'address', internalType: 'address' }, { name: 'tokenIds', type: 'uint256[]', internalType: 'uint256[]' }, { name: 'amounts', type: 'uint256[]', internalType: 'uint256[]' }, { name: 'data', type: 'bytes', internalType: 'bytes' }, { name: 'expectedPaymentToken', type: 'address', internalType: 'address' }, { name: 'maxTotal', type: 'uint256', internalType: 'uint256' }, { name: 'proof', type: 'bytes32[]', internalType: 'bytes32[]' } ], outputs: [], stateMutability: 'payable' } ``` ```tsx [components/BuyNFT.tsx] theme={null} import { useSelectPaymentModal } from '@0xsequence/checkout' import { encodeFunctionData, toHex } from 'viem' import { useAccount } from 'wagmi' import { mintFunctionAbi } from '../abis/erc1155' function BuyNFT() { const { address } = useAccount() const { openSelectPaymentModal } = useSelectPaymentModal() const handleCheckout = () => { if (!address) return // ERC-20 payment settings const currencyAddress = '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359' // USDC on Polygon const salesContractAddress = '0xe65b75eb7c58ffc0bf0e671d64d0e1c6cd0d3e5b' const collectionAddress = '0xdeb398f41ccd290ee5114df7e498cf04fac916cb' const price = '20000' // Price in smallest unit (0.02 USDC) const chainId = 137 // Polygon // NFT details const collectibles = [ { tokenId: '1', quantity: '1' } ] // Transaction data for the ERC-1155 mint function const purchaseTransactionData = encodeFunctionData({ abi: [mintFunctionAbi], functionName: 'mint', args: [ address, collectibles.map(c => BigInt(c.tokenId)), collectibles.map(c => BigInt(c.quantity)), toHex(0), currencyAddress, price, [toHex(0, { size: 32 })] ] }) // Open the payment selection modal openSelectPaymentModal({ collectibles, chain: chainId, price, targetContractAddress: salesContractAddress, recipientAddress: address, currencyAddress, collectionAddress, creditCardProviders: ['transak'], onSuccess: (txnHash: string) => { console.log('success!', txnHash) }, onError: (error: Error) => { console.error(error) }, onClose: () => { console.log('modal closed!') }, txData: purchaseTransactionData }) } return ( ) } export default BuyNFT ``` Payment Selection Modal ## Return Type: `UseSelectPaymentModalReturnType` The hook returns an object with the following properties: ```tsx theme={null} type UseSelectPaymentModalReturnType = { openSelectPaymentModal: (settings: SelectPaymentSettings) => void closeSelectPaymentModal: () => void selectPaymentSettings: SelectPaymentSettings | undefined } ``` ### Properties #### openSelectPaymentModal `(settings: SelectPaymentSettings) => void` Function to open the Payment Selection modal with the specified settings. **Parameters:** The `settings` object can include the following properties: | Parameter | Type | Description | | ----------------------- | -------------------------------------------- | --------------------------------------------------------- | | `collectibles` | `Array<{tokenId: string, quantity: string}>` | Array of collectibles to purchase | | `chain` | `number` | Blockchain network ID | | `price` | `string` | Price in smallest unit of the currency | | `targetContractAddress` | `string` | Address of the contract to interact with | | `recipientAddress` | `string` | Address to receive the purchased items | | `currencyAddress` | `string` | Address of the currency token contract | | `collectionAddress` | `string` | Address of the NFT collection contract | | `creditCardProviders` | `string[]` | List of supported credit card providers (e.g., 'transak') | | `copyrightText` | `string` | Copyright text to display in the modal | | `onSuccess` | `(txnHash: string) => void` | Callback when transaction succeeds | | `onError` | `(error: Error) => void` | Callback when an error occurs | | `onClose` | `() => void` | Callback when the modal is closed | | `txData` | `string` | Encoded transaction data for the purchase | #### closeSelectPaymentModal `() => void` Function to close the Payment Selection modal. #### selectPaymentSettings `SelectPaymentSettings | undefined` The current settings configuration for the Payment Selection modal. ## Notes This hook provides methods to control the Payment Selection modal that allows users to purchase digital assets with multiple payment options. The modal offers various payment methods including: * Pay with cryptocurrency from the user's wallet * Swap tokens to pay with a different cryptocurrency * Pay with credit/debit card * Receive funds from another wallet # useSwapModal Source: https://docs.sequence.xyz/sdk/web/checkout-sdk/hooks/useSwapModal Hook for opening the swap modal ## Import ```tsx theme={null} import { useSwapModal } from '@0xsequence/checkout' ``` ## Usage ```tsx theme={null} import { useSwapModal } from '@0xsequence/checkout' import { encodeFunctionData, parseAbi } from 'viem' function App() { const { openSwapModal } = useSwapModal() const handleSwap = () => { // Target token information const chainId = 137 // Polygon const toTokenAddress = '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359' // USDC on Polygon const toTokenAmount = '20000' // 0.02 USDC (in smallest units) // Optional: Transaction to execute after swap is completed const data = encodeFunctionData({ abi: parseAbi(['function demo()']), functionName: 'demo', args: [] }) // Open the swap modal openSwapModal({ onSuccess: () => { console.log('swap successful!') }, chainId, toTokenAddress, toTokenAmount, postSwapTransactions: [ { to: '0x37470dac8a0255141745906c972e414b1409b470', data } ], title: 'Swap and Pay', description: 'Select a token in your wallet to swap to 0.2 USDC.' }) } return ( ) } ``` ## Return Type: `UseSwapModalReturnType` The hook returns an object with the following properties: ```tsx theme={null} type UseSwapModalReturnType = { openSwapModal: (settings: SwapModalSettings) => void closeSwapModal: () => void swapModalSettings: SwapModalSettings | undefined } ``` ### Properties #### openSwapModal `(settings: SwapModalSettings) => void` Function to open the Swap modal with the specified settings. **Parameters:** The `settings` object can include the following properties: | Parameter | Type | Description | | ---------------------- | ----------------------------------- | -------------------------------------------------------------------------- | | `chainId` | `number` | Blockchain network ID where the swap will occur | | `toTokenAddress` | `string` | Address of the target token contract | | `toTokenAmount` | `string` | Amount of the target token in smallest units | | `postSwapTransactions` | `Array<{to: string, data: string}>` | (Optional) Transactions to execute after the swap completes | | `disableMainCurrency` | `boolean` | (Optional) If true, disables swapping using the main currency of the chain | | `title` | `string` | (Optional) Custom title for the swap modal | | `description` | `string` | (Optional) Custom description for the swap modal | | `onSuccess` | `() => void` | (Optional) Callback when swap is successful | | `onError` | `(error: Error) => void` | (Optional) Callback when an error occurs | | `onClose` | `() => void` | (Optional) Callback when the modal is closed | | `blockConfirmations` | `number` | (Optional) Number of block confirmations to wait for the swap to complete | #### closeSwapModal `() => void` Function to close the Swap modal. #### swapModalSettings `SwapModalSettings | undefined` The current settings configuration for the Swap modal. ```tsx theme={null} export interface SwapModalSettings { chainId: number toTokenAddress: string toTokenAmount: string title?: string description?: string disableMainCurrency?: boolean postSwapTransactions?: Transaction[] blockConfirmations?: number onSuccess?: (txHash: string) => void } ``` ## Notes This hook provides methods to control the Swap modal that allows users to swap tokens in their wallet to a target currency. The Swap modal enables users to select tokens from their wallet to swap to a specified target token, with the option to execute additional transactions after the swap completes. # useTransferFundsModal Source: https://docs.sequence.xyz/sdk/web/checkout-sdk/hooks/useTransferFundsModal Hook to manage the transfer funds modal state and configuration ## Import ```tsx theme={null} import { useTransferFundsModal } from '@0xsequence/checkout' ``` ## Usage ```tsx theme={null} import { useTransferFundsModal } from '@0xsequence/checkout' import { useAccount } from 'wagmi' function App() { const { openTransferFundsModal } = useTransferFundsModal() const { address } = useAccount() const handleOpenTransfer = () => { openTransferFundsModal({ walletAddress: address || '' }) } return (
) } ``` ## Return Type: `UseTransferFundsModalReturnType` The hook returns an object with the following properties: ```tsx theme={null} type UseTransferFundsModalReturnType = { openTransferFundsModal: (settings: TransferFundsSettings) => void closeTransferFundsModal: () => void transferFundsSettings: TransferFundsSettings | null } ``` ### Properties #### openTransferFundsModal `(settings: TransferFundsSettings) => void` ```tsx theme={null} interface TransferFundsSettings { walletAddress: string | Hex onClose?: () => void } ``` Function to open the transfer funds modal with the specified configuration. **Parameters:** | Parameter | Type | Description | | ---------- | ----------------------- | ------------------------------------------------- | | `settings` | `TransferFundsSettings` | Configuration object for the transfer funds modal | #### closeTransferFundsModal `() => void` Function to close the transfer funds modal. #### transferFundsSettings `TransferFundsSettings | null` ```tsx theme={null} interface TransferFundsSettings { walletAddress: string | Hex onClose?: () => void } ``` The current settings configuration for the transfer funds modal, or `null` if the modal is closed. # Getting started Source: https://docs.sequence.xyz/sdk/web/hooks-sdk/getting-started Learn how to get started with Hooks SDK If you want to use this package without [@0xsequence/connect](/sdk/web/wallet-sdk/ecosystem/getting-started), you can do so by following the steps below. ```bash theme={null} npm install @0xsequence/hooks @tanstack/react-query wagmi # or pnpm install @0xsequence/hooks @tanstack/react-query wagmi # or yarn add @0xsequence/hooks @tanstack/react-query wagmi ``` Get your project access key from the [Sequence Builder](https://sequence.build). ```typescript [config.ts] theme={null} import { mainnet, polygon } from "wagmi/chains" import { createConfig, http } from "wagmi" import { QueryClient } from "@tanstack/react-query" const wagmiConfig = createConfig({ chains: [mainnet, polygon], transports: { [mainnet.id]: http('https://mainnet.example.com'), [polygon.id]: http('https://polygon.example.com'), }, }) const queryClient = new QueryClient() export { wagmiConfig, queryClient } ``` ```typescript [main.tsx] theme={null} import React from "react"; import ReactDOM from "react-dom/client"; import "./index.css"; import App from "./App"; import { SequenceHooksProvider } from "@0xsequence/hooks"; import { WagmiProvider } from "wagmi"; import { queryClient, wagmiConfig } from "./config"; import { QueryClientProvider } from "@tanstack/react-query"; function Dapp() { return ( ); } ReactDOM.createRoot(document.getElementById("root")!).render( ); export default Dapp; ``` Now you can start using hooks like [useGetCoinPrices](/sdk/web/hooks-sdk/hooks/useGetCoinPrices). If you want to use this pacakge with [@0xsequence/connect](/sdk/web/wallet-sdk/ecosystem/getting-started), you can do so by following the steps below. Follow the steps [here](/sdk/web/wallet-sdk/ecosystem/getting-started). ```bash theme={null} npm install @0xsequence/hooks # or pnpm install @0xsequence/hooks # or yarn add @0xsequence/hooks ``` ```typescript [main.tsx] theme={null} import React from "react"; import ReactDOM from "react-dom/client"; import "./index.css"; import App from "./App"; import { config } from "./config"; import { SequenceConnect } from "@0xsequence/connect"; import { SequenceHooksProvider } from "@0xsequence/hooks"; function Dapp() { return ( ); } ReactDOM.createRoot(document.getElementById("root")!).render( ); export default Dapp; ``` Now you can start using hooks like [useGetCoinPrices](/sdk/web/hooks-sdk/hooks/useGetCoinPrices). # useGetCoinPrices Source: https://docs.sequence.xyz/sdk/web/hooks-sdk/hooks/useGetCoinPrices Hook to fetch current prices for a list of tokens ## Import ```tsx theme={null} import { useGetCoinPrices } from '@0xsequence/hooks' ``` ## Usage ```tsx theme={null} import { useGetCoinPrices } from '@0xsequence/hooks' function TokenPriceDisplay() { const tokens = [ { chainId: 1, contractAddress: '0x0000000000000000000000000000000000000000' // ETH }, { chainId: 137, contractAddress: '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174' // USDC on Polygon } ] const { data: prices, isLoading, error, isError, isSuccess } = useGetCoinPrices(tokens) if (isLoading) { return
Loading prices...
} if (isError) { return
Error: {error.message}
} return (

Token Prices

{isSuccess && prices && ( prices.map((price) => (
{price?.price?.value} {price?.price?.currency}
)) )}
) } export default TokenPriceDisplay; ``` ## Parameters ### tokens `Token[]`: Array of objects with `chainId` and `contractAddress` representing the tokens you'd like prices for. ```tsx theme={null} interface Token { chainId: number // EVM chain ID (e.g., 1 = Ethereum, 137 = Polygon) contractAddress: string // Token contract address on that chain } ``` * For native tokens (e.g., ETH on Ethereum, MATIC on Polygon), set `contractAddress` to **`ZERO_ADDRESS`**. * For ERC-20 tokens, provide the token’s actual contract address on the specified `chainId`. **Examples** ```tsx theme={null} const tokens: Token[] = [ { chainId: 1, contractAddress: ZERO_ADDRESS }, // ETH (native) { chainId: 137, contractAddress: ZERO_ADDRESS }, // MATIC (native) { chainId: 1, contractAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" }, // USDC on Ethereum ]; ``` ### options `HooksOptions` (optional) ```tsx theme={null} interface HooksOptions { retry?: boolean // Whether to retry failed requests (defaults to true) disabled?: boolean // Whether to disable the query } ``` ## Return Type The hook returns a React Query result object: ```tsx theme={null} interface Price { value: number currency: string } { data: { token: Token, price?: Price, price24hChange?: Price, floorPrice?: Price, buyPrice?: Price, sellPrice?: Price, updatedAt: string }[] isLoading: boolean // Whether the initial request is in progress error: Error | null // Any error that occurred isError: boolean // Whether an error occurred isSuccess: boolean // Whether the request was successful } ``` # useGetCollectiblePrices Source: https://docs.sequence.xyz/sdk/web/hooks-sdk/hooks/useGetCollectiblePrices Hook to fetch current market prices for NFTs/collectibles ## Import ```tsx theme={null} import { useGetCollectiblePrices } from '@0xsequence/hooks' ``` ## Usage ```tsx theme={null} import { useGetCollectiblePrices } from '@0xsequence/hooks' function NFTPriceDisplay() { const tokens = [ { chainId: 1, contractAddress: '0x34d85c9CDeB23FA97cb08333b511ac86E1C4E258', // Example NFT collection tokenId: '123' } ] const { data: prices, isLoading, error, isError, isSuccess } = useGetCollectiblePrices(tokens) if (isLoading) { return
Loading prices...
} if (isError) { return
Error: {error.message}
} return (

NFT Prices

{isSuccess && prices && (
    {prices.map((price, index) => (
  • Collection: {tokens[index].contractAddress}
    Token ID: {tokens[index].tokenId}
    Floor Price: {price.floorPrice.value} {price.floorPrice.currency}
    Buy Price: {price.buyPrice.value} {price.buyPrice.currency}
    Sell Price: {price.sellPrice.value} {price.sellPrice.currency}
  • ))}
)}
) } ``` ### tokens `Token[]`: Array of objects with `chainId` and `contractAddress` representing the tokens you'd like prices for. ```tsx theme={null} interface Token { chainId: number // EVM chain ID (e.g., 1 = Ethereum, 137 = Polygon) contractAddress: string // Token contract address on that chain tokenId: string // The specific token ID within the collection } ``` ### options `HooksOptions` (optional) ```tsx theme={null} interface HooksOptions { retry?: boolean // Whether to retry failed requests (defaults to true) disabled?: boolean // Whether to disable the query } ``` ## Return Type The hook returns a React Query result object: ```tsx theme={null} interface Price { value: number currency: string } { data: { token: Token, price?: Price, price24hChange?: Price, floorPrice?: Price, buyPrice?: Price, sellPrice?: Price, updatedAt: string }[] isLoading: boolean // Whether the initial request is in progress error: Error | null // Any error that occurred isError: boolean // Whether an error occurred isSuccess: boolean // Whether the request was successful } ``` # useGetContractInfo Source: https://docs.sequence.xyz/sdk/web/hooks-sdk/hooks/useGetContractInfo Hook for fetching token contract information including native tokens ## Import ```tsx theme={null} import { useGetContractInfo } from '@0xsequence/hooks' ``` ## Usage ```tsx theme={null} import { useGetContractInfo } from '@0xsequence/hooks' import { ZERO_ADDRESS } from '@0xsequence/utils' // Example 1: Fetch NFT Collection Info function NFTCollectionDetails() { const { data: contractInfo, isLoading, isError } = useGetContractInfo({ chainID: "1", // Ethereum mainnet contractAddress: "0x..." }) if (isLoading) return
Loading collection details...
if (isError) return
Error loading collection
return (
{contractInfo?.name}

{contractInfo?.name}

Type: {contractInfo?.type} Symbol: {contractInfo?.symbol}
) } // Example 2: Display Native Token Info function NativeTokenInfo() { const { data: ethInfo } = useGetContractInfo({ chainID: "1", contractAddress: ZERO_ADDRESS // For native ETH }) return (
{ethInfo?.symbol}

{ethInfo?.name}

Decimals: {ethInfo?.decimals}

) } ``` ## Return Type: `UseQueryResult` The hook returns all properties from React Query's `UseQueryResult` with contract information data. Here's the detailed structure: ```tsx theme={null} interface ContractInfo { chainId: number; address: string; source: string; name: string; type: string; symbol: string; decimals?: number; logoURI: string; deployed: boolean; bytecodeHash: string; extensions: ContractInfoExtensions; updatedAt: string; notFound: boolean; queuedAt?: string; status: ResourceStatus; } ``` ### Properties #### data `ContractInfo | undefined` Object containing contract information: * `chainId`: The numeric chain identifier (e.g. 1 for Ethereum mainnet) * `address`: The contract's blockchain address in hex format * `source`: The source/origin of the contract metadata (e.g. "sequence", "opensea", etc) * `name`: The human-readable name of the contract or token * `type`: The contract's interface type ("ERC20", "ERC721", "ERC1155") * `symbol`: The token's symbol/ticker (e.g. "ETH", "USDC") * `decimals`: The number of decimal places for token amounts (e.g. 18 for ETH) * `logoURI`: URL to the token/contract's logo image * `deployed`: Boolean indicating if contract is deployed on-chain * `bytecodeHash`: Hash of the contract's deployed bytecode * `extensions`: Additional metadata fields specific to the contract type * `updatedAt`: ISO timestamp of when the metadata was last updated * `notFound`: Boolean indicating if contract metadata could not be found * `queuedAt`: ISO timestamp of when metadata indexing was queued * `status`: Current status of the metadata ("READY", "PENDING", "ERROR") For native tokens (when using `ZERO_ADDRESS`), the response is enriched with network-specific information. #### isLoading `boolean` Loading state for the data fetch. #### isError `boolean` Error state indicating if the query failed. #### error `Error | null` Any error that occurred during data fetching. ## Parameters The hook accepts two parameters: ### args: `GetContractInfoArgs` ```tsx theme={null} interface GetContractInfoArgs { chainID: string contractAddress: string } ``` | Parameter | Type | Description | | ----------------- | -------- | --------------------------------------------------- | | `chainID` | `string` | Chain ID as string (e.g., "1" for Ethereum mainnet) | | `contractAddress` | `string` | Contract address or `ZERO_ADDRESS` for native token | ### options: `HooksOptions` ```tsx theme={null} interface HooksOptions { disabled?: boolean retry?: boolean } ``` | Parameter | Type | Description | | ---------- | --------- | ------------------------------------------------------- | | `disabled` | `boolean` | (Optional) Disable the query from automatically running | | `retry` | `boolean` | (Optional) Whether to retry failed queries | # useGetExchangeRate Source: https://docs.sequence.xyz/sdk/web/hooks-sdk/hooks/useGetExchangeRate Hook to fetch current exchange rates from USD to other currencies ## Import ```tsx theme={null} import { useGetExchangeRate } from '@0xsequence/hooks' ``` ## Usage ```tsx theme={null} import { useGetExchangeRate } from '@0xsequence/hooks' function CurrencyConverter() { const usdAmount = 100 const { data: rate = 1, isLoading, error, isError, isSuccess } = useGetExchangeRate('EUR') if (isLoading) { return
Loading rates...
} if (isError) { return
Error: {error.message}
} return (

Currency Conversion

{isSuccess && (

{usdAmount} USD = {usdAmount * rate} EUR

Current Rate: 1 USD = {rate} EUR

)}
) } // Example with multiple currencies function MultiCurrencyDisplay() { const currencies = ['EUR', 'GBP', 'JPY'] return (

USD Exchange Rates

{currencies.map(currency => ( ))}
) } function CurrencyRate({ currency }) { const { data: rate = 1 } = useGetExchangeRate(currency) return (
1 USD = {rate} {currency}
) } ``` ## Parameters ### toCurrency `string` The target currency code (e.g., 'EUR', 'GBP', 'JPY'). If 'USD' is provided, returns 1 as the conversion rate. ### options `HooksOptions` (optional) ```tsx theme={null} interface HooksOptions { retry?: boolean // Whether to retry failed requests (defaults to true) disabled?: boolean // Whether to disable the query } ``` ## Return Type The hook returns a React Query result object: ```tsx theme={null} { data: number // The exchange rate value from USD to target currency isLoading: boolean // Whether the initial request is in progress error: Error | null // Any error that occurred isError: boolean // Whether an error occurred isSuccess: boolean // Whether the request was successful } ``` # useGetMultipleContractsInfo Source: https://docs.sequence.xyz/sdk/web/hooks-sdk/hooks/useGetMultipleContractsInfo Hook for fetching contract information for multiple tokens and NFTs in parallel ## Import ```tsx theme={null} import { useGetMultipleContractsInfo } from '@0xsequence/hooks' ``` ## Usage ```tsx theme={null} import { useGetMultipleContractsInfo } from '@0xsequence/hooks' function CrossChainPortfolio() { const { data: contractsInfo, isLoading, isError } = useGetMultipleContractsInfo([ // NFTs { chainID: "1", contractAddress: "0x..." }, { chainID: "137", contractAddress: "0x..." }, // ERC20 Tokens { chainID: "1", contractAddress: "0x..." }, { chainID: "137", contractAddress: "0x..." } ]) if (isLoading) return
Loading portfolio...
if (isError) return
Error loading portfolio
const nfts = contractsInfo?.filter(info => info.type === 'ERC721' || info.type === 'ERC1155' ) || [] const tokens = contractsInfo?.filter(info => info.type === 'ERC20' ) || [] return (

NFT Collections

{nfts.map((nft, index) => (
{nft.name}

{nft.name}

Type: {nft.type} Chain ID: {nft.chainID} {nft.description && (

{nft.description}

)}
))}

Tokens

{tokens.map((token, index) => (
{token.symbol}

{token.name}

Symbol: {token.symbol} Decimals: {token.decimals} Chain ID: {token.chainID}
))}
) } ``` ## Return Type: `UseQueryResult` The hook returns all properties from React Query's `UseQueryResult` with an array of contract information. Here's the detailed structure: ```tsx theme={null} interface ContractInfo { chainId: number; address: string; source: string; name: string; type: string; symbol: string; decimals?: number; logoURI: string; deployed: boolean; bytecodeHash: string; extensions: ContractInfoExtensions; updatedAt: string; notFound: boolean; queuedAt?: string; status: ResourceStatus; } ``` ### Properties #### data `ContractInfo[] | undefined` Array of objects containing contract information for each requested contract: * `name`: Contract or token name * `symbol`: Token symbol * `decimals`: Number of decimals (for ERC20 tokens) * `logoURI`: URL of the contract/token logo * `type`: Contract type (ERC20, ERC721, ERC1155) * `verified`: Whether the contract is verified * `description`: Optional contract description * `websiteURL`: Optional project website URL * `imageURL`: Optional project image URL * `bannerURL`: Optional banner image URL * `chainID`: Chain ID where the contract exists #### isLoading `boolean` Loading state for the data fetch. #### isError `boolean` Error state indicating if the query failed. #### error `Error | null` Any error that occurred during data fetching. ## Parameters The hook accepts two parameters: ### args: `GetContractInfoArgs[]` ```tsx theme={null} interface GetContractInfoArgs { chainID: string contractAddress: string } ``` | Parameter | Type | Description | | ----------------- | -------- | --------------------------------------------------- | | `chainID` | `string` | Chain ID as string (e.g., "1" for Ethereum mainnet) | | `contractAddress` | `string` | Contract address to fetch info for | ### options: `HooksOptions` ```tsx theme={null} interface HooksOptions { disabled?: boolean retry?: boolean } ``` | Parameter | Type | Description | | ---------- | --------- | ------------------------------------------------------- | | `disabled` | `boolean` | (Optional) Disable the query from automatically running | | `retry` | `boolean` | (Optional) Whether to retry failed queries | # useGetNativeTokenBalance Source: https://docs.sequence.xyz/sdk/web/hooks-sdk/hooks/useGetNativeTokenBalance Hook for fetching native token balances across multiple chains ## Import ```tsx theme={null} import { useGetNativeTokenBalance } from '@0xsequence/hooks' ``` ## Usage ```tsx theme={null} import { useGetNativeTokenBalance } from '@0xsequence/hooks' import { useAccount } from 'wagmi' function NativeBalances() { const { address } = useAccount() const { data: balances, isLoading, isError, error } = useGetNativeTokenBalance({ accountAddress: address || '', chainIds: [1, 137] // Fetch ETH on Ethereum and POL on Polygon }) if (isLoading) return
Loading...
if (isError) return
Error: {error.message}
return (
{balances?.map(balance => (

Chain {balance.chainId}

Balance: {balance.balance}

Token: {balance.contractAddress}

))}
) } ``` ## Return Type: `UseQueryResult` The hook returns all properties from React Query's `UseQueryResult` with token balance data. Here's the detailed structure: ```tsx theme={null} interface TokenBalance { contractType: ContractType; contractAddress: string; accountAddress: string; tokenID?: string; balance: string; blockHash: string; blockNumber: number; chainId: number; uniqueCollectibles: string; isSummary: boolean; contractInfo?: ContractInfo; tokenMetadata?: TokenMetadata; } ``` ### Properties #### data `TokenBalance[] | undefined` Array of token balance objects containing: * `chainId`: The chain ID where the balance was fetched from * `accountAddress`: The address whose balance was queried * `contractAddress`: The address of the native token (typically zero address) * `balance`: The balance amount in the token's base units * `contractType`: The type of contract (e.g., ERC20, ERC721, ERC1155) * `contractInfo`: Additional contract information * `tokenMetadata`: Metadata about the token * `blockHash`: The hash of the block in which the balance was recorded * `blockNumber`: The number of the block in which the balance was recorded * `uniqueCollectibles`: The number of unique collectibles * `isSummary`: Whether the balance is a summary * `tokenID`: The ID of the token (for ERC721 and ERC1155 tokens) #### isLoading `boolean` Loading state for the data fetch. #### isError `boolean` Error state indicating if the query failed. #### error `Error | null` Any error that occurred during data fetching. ## Parameters The hook accepts two parameters: ### args: `GetNativeTokenBalanceArgs` ```tsx theme={null} interface GetNativeTokenBalanceArgs { chainIds?: Array; networks?: Array; accountAddress?: string; } ``` | Parameter | Type | Description | | ---------------- | ---------- | --------------------------------------------- | | `accountAddress` | `string` | The address to fetch balances for | | `chainIds` | `number[]` | Array of chain IDs to fetch balances from | | `networks` | `string[]` | Array of network names to fetch balances from | ### options: `HooksOptions` ```tsx theme={null} interface HooksOptions { disabled?: boolean retry?: boolean } ``` | Parameter | Type | Description | | ---------- | --------- | ------------------------------------------------------- | | `disabled` | `boolean` | (Optional) Disable the query from automatically running | | `retry` | `boolean` | (Optional) Whether to retry failed queries | # useGetSingleTokenBalance Source: https://docs.sequence.xyz/sdk/web/hooks-sdk/hooks/useGetSingleTokenBalance Hook to fetch the balance of a specific token (native or ERC20) for an account on a specific chain ## Import ```tsx theme={null} import { useGetSingleTokenBalance } from '@0xsequence/hooks' ``` ## Usage ```tsx theme={null} import { useGetSingleTokenBalance } from '@0xsequence/hooks' function TokenBalance() { // Fetch native ETH balance const { data: ethBalance, isLoading, error } = useGetSingleTokenBalance({ chainId: 1, accountAddress: '0x...', contractAddress: 0x0000000000000000000000000000000000000000 }) // Fetch USDC balance const { data: usdcBalance } = useGetSingleTokenBalance({ chainId: 1, accountAddress: '0x...', contractAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' // USDC }) if (isLoading) return
Loading balances...
if (error) return
Error: {error.message}
return (

ETH Balance: {ethBalance?.balance}

USDC Balance: {usdcBalance?.balance}

) } ``` ## Parameters ### GetSingleTokenBalanceArgs | Parameter | Type | Description | | -------------------- | --------- | ----------------------------------------------------------------- | | `chainId` | `number` | The chain ID to fetch the balance from | | `accountAddress` | `string` | The address to fetch the balance for | | `contractAddress` | `string` | The token contract address (use `ZERO_ADDRESS` for native tokens) | | `tokenId` | `string` | Optional. The token ID for ERC721/ERC1155 tokens | | `hideUnlistedTokens` | `boolean` | Optional. If true, filters out unverified tokens | ### HooksOptions | Parameter | Type | Description | | ------------------ | --------- | --------------------------------------------------- | | `retry` | `boolean` | Whether to retry failed requests (default: `false`) | | `disabled` | `boolean` | Whether to disable the query | | `hideCollectibles` | `boolean` | If true, filters out ERC721 and ERC1155 tokens | ## Return Type The hook returns a React Query result object with the following properties: ```tsx theme={null} { data: TokenBalance | undefined isLoading: boolean error: Error | null // ... other React Query properties } ``` ### TokenBalance The returned data contains token balance information: ```tsx theme={null} interface TokenBalance { contractType: ContractType; contractAddress: string; accountAddress: string; tokenID?: string; balance: string; blockHash: string; blockNumber: number; chainId: number; uniqueCollectibles: string; isSummary: boolean; contractInfo?: ContractInfo; tokenMetadata?: TokenMetadata; } ``` ## Notes This hook provides a convenient way to fetch token balances for specific accounts and contracts. Key features: * **Native Token Support**: Use `ZERO_ADDRESS` for native tokens (ETH, MATIC, etc.) * **ERC20 Support**: Works with any ERC20 token contract * **NFT Support**: Supports ERC721 and ERC1155 tokens with optional `tokenId` * **Caching**: Uses React Query for efficient caching and background updates * **Error Handling**: Provides error states for failed requests * **Loading States**: Includes loading indicators for better UX The hook automatically handles different token types and provides a unified interface for accessing token balance information. # useGetSwapQuote Source: https://docs.sequence.xyz/sdk/web/hooks-sdk/hooks/useGetSwapQuote Hook for fetching quotes for a swap ## Import ```tsx theme={null} import { useGetSwapQuote } from '@0xsequence/hooks' ``` ## Usage ```tsx theme={null} import { useGetSwapQuote } from '@0xsequence/hooks' function SwapComponent() { const { data: swapQuote, isLoading } = useGetSwapQuote({ params: { walletAddress: '0x123...', fromTokenAddress: '0x456...', toTokenAddress: '0x789...', toTokenAmount: '1000000000000000000', // amount to buy in wei chainId: 1, includeApprove: true, slippageBps: 100 // 1% slippage } }) if (isLoading) return
Loading...
return (
{swapQuote && (
Price: {swapQuote.price} Max Price: {swapQuote.maxPrice} Transaction Value: {swapQuote.transactionValue}
)}
) } ``` ## Return Type: `UseQueryResult` The hook returns all properties from React Query's `UseQueryResult` with swap quote data. Here's the detailed structure of the swapQuote. ```tsx theme={null} interface LifiSwapQuote { currencyAddress: string; currencyBalance: string; price: string; maxPrice: string; to: string; transactionData: string; transactionValue: string; approveData: string; amount: string; amountMin: string; } ``` ### Properties #### data `SwapQuote | undefined` The swap quote object containing: * `currencyAddress`: Address of the currency to be swapped * `currencyBalance`: Balance of the currency in the user's wallet * `price`: The current price for the swap * `maxPrice`: Maximum price allowed for the swap (includes slippage) * `to`: The target contract address that handles the swap * `transactionData`: Encoded transaction data for executing the swap * `transactionValue`: The value to be sent with the transaction (for native tokens) * `approveData`: Encoded approval transaction data (if includeApprove is true and needed) * `amount`: The amount of currency to be received * `amountMin`: The minimum amount to be received after slippage #### isLoading `boolean` Loading state for the data fetch. #### isError `boolean` Error state indicating if the query failed. #### error `Error | null` Any error that occurred during data fetching. ## Parameters The hook accepts two parameters: ### args: `GetLifiSwapQuoteArgs` ```tsx theme={null} interface GetLifiSwapQuoteArgs { params: GetLifiSwapQuoteParams } interface GetLifiSwapQuoteParams { chainId: number; walletAddress: string; fromTokenAddress: string; toTokenAddress: string; fromTokenAmount?: string; toTokenAmount?: string; includeApprove: boolean; slippageBps: number; } ``` | Parameter | Type | Description | | ------------------------- | --------- | --------------------------------------------------- | | `params.chainId` | `number` | The chain ID where the swap will occur | | `params.walletAddress` | `string` | The address of the user's wallet | | `params.fromTokenAddress` | `string` | The address of the token to sell | | `params.toTokenAddress` | `string` | The address of the token to buy | | `params.fromTokenAmount` | `string` | (Optional) The amount of token to sell (in wei) | | `params.toTokenAmount` | `string` | (Optional) The amount of token to buy (in wei) | | `params.includeApprove` | `boolean` | Whether to include approval transaction data | | `params.slippageBps` | `number` | Maximum allowed slippage in basis points (100 = 1%) | **Note**: You must provide either `fromTokenAmount` or `toTokenAmount`, but not both. ### options: `HooksOptions` ```tsx theme={null} interface HooksOptions { disabled?: boolean retry?: boolean } ``` | Parameter | Type | Description | | ---------- | --------- | ------------------------------------------------------------- | | `disabled` | `boolean` | (Optional) Disable the query from automatically running | | `retry` | `boolean` | (Optional) Whether to retry failed queries (defaults to true) | # useGetSwapRoutes Source: https://docs.sequence.xyz/sdk/web/hooks-sdk/hooks/useGetSwapRoutes Hook for fetching available routes for a swap ## Import ```tsx theme={null} import { useGetSwapRoutes } from '@0xsequence/hooks' ``` This hook replaces the `useGetSwapPrices` hook which was removed in v5.2.3. ## Usage ```tsx theme={null} import { useGetSwapRoutes } from '@0xsequence/hooks' import { useState } from 'react' function SwapList() { const [selectedCurrency, setSelectedCurrency] = useState('') const toTokenAddress = '0x...' const toTokenAmount = '1000000000' const walletAddress = '0x...' const chainId = 137 const { data: swapRoutes = [], isLoading, isError } = useGetSwapRoutes({ walletAddress, toTokenAddress, toTokenAmount, chainId }) if (isLoading) return
Loading swap options...
if (isError) return
Error loading swap options
const noOptionsFound = swapRoutes.flatMap(route => route.fromTokens).length === 0 if (noOptionsFound) return
No swap options found
return (
{swapRoutes.flatMap(route => route.fromTokens).map(token => (
setSelectedCurrency(token.address)} style={{ border: selectedCurrency === token.address ? '2px solid blue' : '1px solid gray', padding: '10px', margin: '5px', cursor: 'pointer' }} > {token.symbol} {token.symbol}: {token.name}
Required: {token.price}
))}
) } export default SwapList ``` ## Return Type: `UseQueryResult` The hook returns all properties from React Query's `UseQueryResult` with swap routes data. Here's the detailed structure of the `LifiSwapRoute` object: ```tsx theme={null} interface LifiToken { chainId: number; address: string; symbol: string; name: string; decimals: number; priceUsd: number; price?: string; coinKey: string; logoUri: string; } interface LifiSwapRoute { fromChainId: number; toChainId: number; fromTokens: Array; toTokens: Array; } ``` ### Properties #### data `LifiSwapRoute[] | undefined` Array of swap route objects containing: ##### route * `fromChainId`: The chain ID of the token to sell * `toChainId`: The chain ID of the token to buy * `fromTokens`: Array of tokens that can be used to pay for the swap * `toTokens`: Array of tokens that can be received from the swap #### isLoading `boolean` Loading state for the data fetch. #### isError `boolean` Error state indicating if the query failed. #### error `Error | null` Any error that occurred during data fetching. ## Parameters The hook accepts two parameters: ### args: `UseGetSwapRoutesArgs` ```tsx theme={null} interface UseGetSwapRoutesArgs { walletAddress: string toTokenAddress: string chainId: number toTokenAmount: string } ``` | Parameter | Type | Description | | ---------------- | -------- | -------------------------------------- | | `walletAddress` | `string` | The address of the user's wallet | | `toTokenAddress` | `string` | The address of the token to buy | | `chainId` | `number` | The chain ID where the swap will occur | | `toTokenAmount` | `string` | The amount of token to buy (in wei) | ### options: `HooksOptions` ```tsx theme={null} interface HooksOptions { disabled?: boolean retry?: boolean } ``` | Parameter | Type | Description | | ---------- | --------- | ------------------------------------------------------------- | | `disabled` | `boolean` | (Optional) Disable the query from automatically running | | `retry` | `boolean` | (Optional) Whether to retry failed queries (defaults to true) | ## Additional Notes * This hook uses React Query to fetch and cache swap routes from the Sequence API. * Stale time is set to one hour by default to avoid refreshing quotes while the user is completing transactions. * This hook will not return "fromTokens" that the user does not have in their wallet. # useGetTokenBalancesByContract Source: https://docs.sequence.xyz/sdk/web/hooks-sdk/hooks/useGetTokenBalancesByContract Hook for fetching multiple token balances by contract addresses ## Import ```tsx theme={null} import { useGetTokenBalancesByContract } from '@0xsequence/hooks' ``` ## Usage ```tsx theme={null} import { useGetTokenBalancesByContract } from '@0xsequence/hooks' import { useAccount } from 'wagmi' import { ContractVerificationStatus } from '@0xsequence/connect' function TokenBalances() { const { address } = useAccount() const { data: balances, isLoading, isError } = useGetTokenBalancesByContract({ chainIds: [1], // Ethereum mainnet filter: { contractAddresses: [ '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC '0xdac17f958d2ee523a2206206994597c13d831ec7' // USDT ], accountAddresses: [address || ''], contractStatus: ContractVerificationStatus.VERIFIED // Optional: only fetch verified contracts } }, { hideCollectibles: true // Optional: filter out NFTs }) if (isLoading) return
Loading...
if (isError) return
Error fetching balances
return (
{balances?.map(balance => (

{balance.contractInfo?.symbol || 'Unknown Token'}

Balance: {balance.balance}

Contract: {balance.contractAddress}

{balance.contractInfo && ( {balance.contractInfo.symbol} )}
))}
) } ``` ## Return Type: `UseQueryResult` The hook returns all properties from React Query's `UseQueryResult` with token balance data. Here's the detailed structure: ```tsx theme={null} interface TokenBalance { contractType: ContractType contractAddress: string accountAddress: string tokenID?: string balance: string blockHash: string blockNumber: number chainId: number uniqueCollectibles: string isSummary: boolean contractInfo?: ContractInfo tokenMetadata?: TokenMetadata } ``` ### Properties #### data `TokenBalance[] | undefined` Array of token balance objects containing: * `contractType`: Type of the token contract (ERC20, ERC721, ERC1155) * `contractAddress`: Address of the token contract * `accountAddress`: Address of the account holding the tokens * `balance`: Token balance as a string (in base units) * `chainId`: Chain ID where the token exists * `blockHash`: Hash of the block where balance was last updated * `blockNumber`: Block number where balance was last updated * `tokenID`: Optional token ID for NFTs * `contractInfo`: Optional token contract information including name, symbol, decimals, and logo URL * `tokenMetadata`: Optional metadata about the token * `uniqueCollectibles`: Number of unique collectibles * `isSummary`: Whether the balance is a summary #### isLoading `boolean` Loading state for the data fetch. #### isError `boolean` Error state indicating if the query failed. #### error `Error | null` Any error that occurred during data fetching. ## Parameters The hook accepts two parameters: ### args: `GetTokenBalancesByContractArgs` ```tsx theme={null} enum ContractVerificationStatus { VERIFIED = "VERIFIED", UNVERIFIED = "UNVERIFIED", ALL = "ALL" } interface GetTokenBalancesByContractArgs { chainIds: number[] filter: { contractAddresses: string[] accountAddresses?: string[] contractStatus?: ContractVerificationStatus } } ``` | Parameter | Type | Description | | -------------------------- | ---------------------------- | ----------------------------------------------------------- | | `chainIds` | `number[]` | Array of chain IDs to fetch balances from | | `filter.contractAddresses` | `string[]` | Array of token contract addresses to fetch balances for | | `filter.accountAddresses` | `string[]` | (Optional) Array of account addresses to fetch balances for | | `filter.contractStatus` | `ContractVerificationStatus` | (Optional) Filter for contract verification status | ### options: `BalanceHookOptions` ```tsx theme={null} interface BalanceHookOptions { disabled?: boolean retry?: boolean hideCollectibles?: boolean } ``` | Parameter | Type | Description | | ------------------ | --------- | --------------------------------------------------------- | | `disabled` | `boolean` | (Optional) Disable the query from automatically running | | `retry` | `boolean` | (Optional) Whether to retry failed queries | | `hideCollectibles` | `boolean` | (Optional) If true, filters out ERC721 and ERC1155 tokens | # useGetTokenBalancesDetails Source: https://docs.sequence.xyz/sdk/web/hooks-sdk/hooks/useGetTokenBalancesDetails Hook for fetching detailed token balances including metadata across multiple chains ## Import ```tsx theme={null} import { useGetTokenBalancesDetails } from '@0xsequence/hooks' ``` ## Usage ```tsx theme={null} import React from 'react' import { useGetTokenBalancesDetails } from '@0xsequence/hooks' import { ContractVerificationStatus } from '@0xsequence/connect' import { useAccount } from 'wagmi' function TokenPortfolio() { const { address } = useAccount() const { data: tokens, isLoading, isError } = useGetTokenBalancesDetails({ chainIds: [1, 137], // Ethereum and Polygon filter: { accountAddresses: [address || ''], omitNativeBalances: false, contractStatus: ContractVerificationStatus.VERIFIED, // Optional: include only specific tokens contractWhitelist: [ '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2' // WETH ] } }) if (isLoading) return
Loading portfolio...
if (isError) return
Error loading portfolio
return (
{tokens?.map(token => (
{token.contractType === 'ERC721' || token.contractType === 'ERC1155' ? ( // NFT display
{token.tokenMetadata?.name}

{token.tokenMetadata?.name}

{token.tokenMetadata?.description}

{token.tokenMetadata?.attributes?.map(attr => ( {attr.trait_type}: {attr.value} ))}
) : ( // Fungible token display
{token.contractInfo?.logoURI && ( {token.contractInfo.symbol} )} {token.contractInfo?.symbol || 'Unknown Token'} Balance: {token.balance} Chain: {token.chainId}
)}
))}
) } ``` ## Return Type: `UseQueryResult` The hook returns all properties from React Query's `UseQueryResult` with token balance data, including metadata. Here's the detailed structure: ```tsx theme={null} interface TokenBalance { contractType: ContractType contractAddress: string accountAddress: string tokenID?: string balance: string blockHash: string blockNumber: number chainId: number uniqueCollectibles: string isSummary: boolean contractInfo?: ContractInfo tokenMetadata?: TokenMetadata } ``` ### Properties #### data `TokenBalance[] | undefined` Array of token balance objects containing: * `contractType`: Type of the token contract (NATIVE, ERC20, ERC721, ERC1155) * `contractAddress`: Address of the token contract * `accountAddress`: Address of the account holding the tokens * `balance`: Token balance as a string (in base units) * `chainId`: Chain ID where the token exists * `blockHash`: Hash of the block where balance was last updated * `blockNumber`: Block number where balance was last updated * `tokenID`: (for NFTs) ID of the token * `contractInfo`: Token contract information including name, symbol, decimals, and logo URL * `tokenMetadata`: (for NFTs) Detailed token metadata including name, description, image URL, and attributes * `uniqueCollectibles`: Number of unique collectibles * `isSummary`: Whether the balance is a summary #### isLoading `boolean` Loading state for the data fetch. #### isError `boolean` Error state indicating if the query failed. #### error `Error | null` Any error that occurred during data fetching. ## Parameters The hook accepts two parameters: ### args: `GetTokenBalancesDetailsArgs` ```tsx theme={null} interface GetTokenBalancesDetailsArgs { chainIds: number[] filter: { accountAddresses: string[] contractWhitelist?: string[] contractBlacklist?: string[] omitNativeBalances?: boolean contractStatus?: ContractVerificationStatus } } ``` | Parameter | Type | Description | | --------------------------- | ---------------------------- | -------------------------------------------------- | | `chainIds` | `number[]` | Array of chain IDs to fetch balances from | | `filter.accountAddresses` | `string[]` | Array of account addresses to fetch balances for | | `filter.contractWhitelist` | `string[]` | (Optional) Array of contract addresses to include | | `filter.contractBlacklist` | `string[]` | (Optional) Array of contract addresses to exclude | | `filter.omitNativeBalances` | `boolean` | (Optional) If true, excludes native token balances | | `filter.contractStatus` | `ContractVerificationStatus` | (Optional) Filter for contract verification status | ### options: `BalanceHookOptions` ```tsx theme={null} interface BalanceHookOptions { disabled?: boolean retry?: boolean hideCollectibles?: boolean } ``` | Parameter | Type | Description | | ------------------ | --------- | --------------------------------------------------------- | | `disabled` | `boolean` | (Optional) Disable the query from automatically running | | `retry` | `boolean` | (Optional) Whether to retry failed queries | | `hideCollectibles` | `boolean` | (Optional) If true, filters out ERC721 and ERC1155 tokens | # useGetTokenBalancesSummary Source: https://docs.sequence.xyz/sdk/web/hooks-sdk/hooks/useGetTokenBalancesSummary Hook for fetching summarized token balances across multiple chains ## Import ```tsx theme={null} import { useGetTokenBalancesSummary } from '@0xsequence/hooks' ``` ## Usage ```tsx theme={null} import React from 'react' import { useGetTokenBalancesSummary } from '@0xsequence/hooks' import { ContractVerificationStatus } from '@0xsequence/connect' import { useAccount } from 'wagmi' import { formatUnits } from 'viem' function TokenBalancesList() { const { address } = useAccount() const { data: tokens, isLoading, isError } = useGetTokenBalancesSummary({ chainIds: [1, 137], // Ethereum and Polygon filter: { accountAddresses: [address || ''], omitNativeBalances: false, contractStatus: ContractVerificationStatus.VERIFIED, // Optional: filter specific tokens contractWhitelist: [ '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2' // WETH ] } }) if (isLoading) return
Loading balances...
if (isError) return
Error loading balances
return (
{tokens?.map(token => (
{token.contractInfo?.logoURI && ( {token.contractInfo.symbol} )}

{token.contractInfo?.symbol || 'Unknown'}

{token.contractInfo?.name}

{token.contractInfo?.decimals ? formatUnits(token.balance, token.contractInfo.decimals) : token.balance} Chain: {token.chainId}
))}
) } ``` ## Return Type: `UseQueryResult` The hook returns all properties from React Query's `UseQueryResult` with token balance data. Here's the detailed structure: ```tsx theme={null} interface TokenBalance { contractType: ContractType contractAddress: string accountAddress: string balance: string blockHash: string blockNumber: number chainId: number uniqueCollectibles: string isSummary: boolean contractInfo?: { name: string symbol: string decimals: number logoURI: string } } ``` ### Properties #### data `TokenBalance[] | undefined` Array of token balance objects containing: * `contractType`: Type of the token contract (NATIVE, ERC20, ERC721, ERC1155) * `contractAddress`: Address of the token contract * `accountAddress`: Address of the account holding the tokens * `balance`: Token balance as a string (in base units) * `chainId`: Chain ID where the token exists * `blockHash`: Hash of the block where balance was last updated * `blockNumber`: Block number where balance was last updated * `uniqueCollectibles`: Number of unique collectibles * `isSummary`: Whether the balance is a summary * `contractInfo`: Basic token contract information including name, symbol, decimals, and logo URL #### isLoading `boolean` Loading state for the data fetch. #### isError `boolean` Error state indicating if the query failed. #### error `Error | null` Any error that occurred during data fetching. ## Parameters The hook accepts two parameters: ### args: `GetTokenBalancesSummaryArgs` ```tsx theme={null} interface GetTokenBalancesSummaryArgs { chainIds: number[] filter: { accountAddresses: string[] contractWhitelist?: string[] contractBlacklist?: string[] omitNativeBalances?: boolean contractStatus?: ContractVerificationStatus } } ``` | Parameter | Type | Description | | --------------------------- | ---------------------------- | -------------------------------------------------- | | `chainIds` | `number[]` | Array of chain IDs to fetch balances from | | `filter.accountAddresses` | `string[]` | Array of account addresses to fetch balances for | | `filter.contractWhitelist` | `string[]` | (Optional) Array of contract addresses to include | | `filter.contractBlacklist` | `string[]` | (Optional) Array of contract addresses to exclude | | `filter.omitNativeBalances` | `boolean` | (Optional) If true, excludes native token balances | | `filter.contractStatus` | `ContractVerificationStatus` | (Optional) Filter for contract verification status | ### options: `BalanceHookOptions` ```tsx theme={null} interface BalanceHookOptions { disabled?: boolean retry?: boolean hideCollectibles?: boolean } ``` | Parameter | Type | Description | | ------------------ | --------- | --------------------------------------------------------- | | `disabled` | `boolean` | (Optional) Disable the query from automatically running | | `retry` | `boolean` | (Optional) Whether to retry failed queries | | `hideCollectibles` | `boolean` | (Optional) If true, filters out ERC721 and ERC1155 tokens | # useGetTokenMetadata Source: https://docs.sequence.xyz/sdk/web/hooks-sdk/hooks/useGetTokenMetadata Hook for fetching token-specific metadata for individual tokens within a contract ## Import ```tsx theme={null} import { useGetTokenMetadata } from '@0xsequence/hooks' ``` ## Usage ```tsx theme={null} import { useGetTokenMetadata } from '@0xsequence/hooks' // Example 1: Single NFT Details function NFTDetails({ contractAddress, tokenId }) { const { data: tokensMetadata, isLoading, isError } = useGetTokenMetadata({ chainID: "1", // Ethereum mainnet contractAddress, tokenIDs: [tokenId] }) if (isLoading) return
Loading NFT details...
if (isError) return
Error loading NFT
const nft = tokensMetadata?.[0] if (!nft) return
NFT not found
return (
{nft.name}

{nft.name}

{nft.description}

{nft.attributes?.map(attr => (
{attr.trait_type} {attr.value} {attr.rarity && ( {attr.rarity}% )}
))}
) } // Example 2: Batch NFT Collection Display function NFTCollectionGrid({ contractAddress, tokenIds }) { const { data: tokensMetadata, isLoading, isError } = useGetTokenMetadata({ chainID: "1", contractAddress, tokenIDs: tokenIds // Will automatically chunk into batches of 50 }) if (isLoading) return
Loading collection...
if (isError) return
Error loading collection
return (
{tokensMetadata?.map(token => (
{token.name}

{token.name}

{token.attributes && (
{token.attributes.slice(0, 3).map(attr => ( {attr.trait_type}: {attr.value} ))}
)}
))}
) } ``` ## Return Type: `UseQueryResult` The hook returns all properties from React Query's `UseQueryResult` with token metadata. Here's the detailed structure: ```tsx theme={null} interface TokenMetadata { tokenId: string; source: string; name: string; description?: string; image?: string; video?: string; audio?: string; properties?: { [key: string]: any; }; attributes: Array<{ [key: string]: any; }>; image_data?: string; external_url?: string; background_color?: string; animation_url?: string; decimals?: number; updatedAt?: string; assets?: Array; status: ResourceStatus; queuedAt?: string; lastFetched?: string; } ``` ### Properties #### data `TokenMetadata[] | undefined` Array of objects containing metadata for each requested token: * `tokenId`: ID of the specific token * `source`: Source/origin of the token metadata (e.g. "sequence", "opensea") * `name`: Name of the specific token (e.g., "Bored Ape #1234") * `description`: Description of the specific token * `image`: Token image URL (automatically proxied through image service) * `video`: Video URL if token has video content * `audio`: Audio URL if token has audio content * `properties`: Additional metadata properties as key-value pairs * `attributes`: Array of trait objects for NFTs * `image_data`: Raw SVG/image data if provided * `external_url`: External URL associated with the token * `background_color`: Background color in hex format * `animation_url`: URL for animated content * `decimals`: Token decimals (for ERC1155 fungible tokens) * `updatedAt`: ISO timestamp of last metadata update * `assets`: Array of additional asset files * `status`: Current status of the metadata ("READY", "PENDING", "ERROR") * `queuedAt`: ISO timestamp when metadata indexing was queued * `lastFetched`: ISO timestamp of last successful fetch #### isLoading `boolean` Loading state for the data fetch. #### isError `boolean` Error state indicating if the query failed. #### error `Error | null` Any error that occurred during data fetching. ## Parameters The hook accepts two parameters: ### args: `GetTokenMetadataArgs` ```tsx theme={null} interface GetTokenMetadataArgs { chainID: string contractAddress: string tokenIDs: string[] } ``` | Parameter | Type | Description | | ----------------- | ---------- | --------------------------------------------------- | | `chainID` | `string` | Chain ID as string (e.g., "1" for Ethereum mainnet) | | `contractAddress` | `string` | Contract address of the token/NFT | | `tokenIDs` | `string[]` | Array of token IDs to fetch metadata for | ### options: `HooksOptions` ```tsx theme={null} interface HooksOptions { disabled?: boolean retry?: boolean } ``` | Parameter | Type | Description | | ---------- | --------- | ------------------------------------------------------- | | `disabled` | `boolean` | (Optional) Disable the query from automatically running | | `retry` | `boolean` | (Optional) Whether to retry failed queries | # useGetTransactionHistory Source: https://docs.sequence.xyz/sdk/web/hooks-sdk/hooks/useGetTransactionHistory Hook for fetching and paginating through transaction history ## Import ```tsx theme={null} import { useGetTransactionHistory } from '@0xsequence/hooks' ``` ## Usage ```tsx theme={null} import { useGetTransactionHistory } from '@0xsequence/hooks' function TransactionList() { const { data, fetchNextPage, hasNextPage, isLoading, isFetchingNextPage } = useGetTransactionHistory({ chainId: 1, accountAddresses: ['0x123...'], // Optional filters: // contractAddress: '0x456...', // tokenId: '1' }) if (isLoading) return
Loading...
return (
{data?.pages.map(page => page.transactions.map(tx => (
Transaction: {tx.txnHash} Block: {tx.blockNumber} Time: {tx.timestamp}
)) )} {hasNextPage && ( )}
) } ``` ## Return Type: `UseGetTransactionHistoryReturnType` The hook returns all properties from React Query's `UseInfiniteQueryResult` with transaction history data. Here's the detailed structure: ```tsx theme={null} type UseGetTransactionHistoryReturnType = UseInfiniteQueryResult< InfiniteData, Error > ``` ### Properties #### data `InfiniteData | undefined` The paginated transaction history data containing multiple pages. Each page includes: ##### transactions Array of transaction objects with the following properties: * `txnHash`: Transaction hash * `blockNumber`: Block number where transaction was mined * `blockHash`: Hash of the block * `chainId`: Chain ID where transaction occurred * `metaTxnID`: Optional meta transaction ID * `transfers`: Optional array of transaction transfers * `timestamp`: Transaction timestamp ##### page Pagination information object containing: * `page`: Next page number * `more`: Whether more results exist in the next page * `pageSize`: Number of results per page #### fetchNextPage `() => Promise` Function to load the next page of transactions. #### hasNextPage `boolean` Boolean indicating if more transactions are available to load. #### isLoading `boolean` Loading state for the initial data fetch. #### isFetching `boolean` Loading state for any data fetch (initial or subsequent). #### isFetchingNextPage `boolean` Loading state specifically for next page fetch. #### error `Error | null` Any error that occurred during data fetching. ## Parameters The hook accepts two parameters: ### args: `UseGetTransactionHistoryArgs` ```tsx theme={null} interface UseGetTransactionHistoryArgs { chainId: number accountAddresses: string[] contractAddress?: string tokenId?: string page?: { page: number } } ``` | Parameter | Type | Description | | ------------------ | ---------- | -------------------------------------------------- | | `chainId` | `number` | The chain ID to fetch transactions from | | `accountAddresses` | `string[]` | The addresses to fetch transaction history for | | `contractAddress` | `string` | (Optional) Filter transactions by contract address | | `tokenId` | `string` | (Optional) Filter transactions by token ID | | `page` | `object` | (Optional) Pagination configuration | ### options: `HooksOptions` ```tsx theme={null} interface HooksOptions { disabled?: boolean retry?: boolean } ``` | Parameter | Type | Description | | ---------- | --------- | ------------------------------------------------------- | | `disabled` | `boolean` | (Optional) Disable the query from automatically running | | `retry` | `boolean` | (Optional) Whether to retry failed queries | ## Notes This hook provides methods to fetch transaction history with support for infinite scrolling. It can filter transactions by contract address and token ID, making it useful for both general account history and specific asset history views. The hook uses `@tanstack/react-query` internally for data fetching and caching, with a stale time of 30 seconds. # useGetTransactionHistorySummary Source: https://docs.sequence.xyz/sdk/web/hooks-sdk/hooks/useGetTransactionHistorySummary Hook for fetching and combining transaction history across multiple chains ## Import ```tsx theme={null} import { useGetTransactionHistorySummary } from '@0xsequence/hooks' ``` ## Usage ```tsx theme={null} import { useGetTransactionHistorySummary } from '@0xsequence/hooks' import { useAccount } from 'wagmi' function TransactionHistory() { const { address } = useAccount() const { data: transactions, isLoading, isError, error } = useGetTransactionHistorySummary({ accountAddress: address || '', chainIds: [1, 137] // Fetch from Ethereum and Polygon }) if (isLoading) return
Loading...
if (isError) return
Error: {error.message}
return (
{transactions?.map(tx => (

Transaction: {tx.txnHash}

Chain: {tx.chainId}

Time: {new Date(tx.timestamp).toLocaleString()}

{tx.transfers?.map((transfer, index) => (

From: {transfer.from}

To: {transfer.to}

Value: {transfer.value}

))}
))}
) } ``` ## Return Type: `UseQueryResult` The hook returns all properties from React Query's `UseQueryResult` with transaction data. Here's the detailed structure: ```tsx theme={null} interface TxnTransfer { transferType: TxnTransferType; contractAddress: string; contractType: ContractType; from: string; to: string; tokenIds?: Array; amounts: Array; logIndex: number; contractInfo?: ContractInfo; tokenMetadata?: { [key: string]: TokenMetadata; }; } interface Transaction { txnHash: string chainId: number timestamp: string blockNumber: number blockHash: string metaTxnID?: string transfers?: Array } ``` ### Properties #### data `Transaction[] | undefined` Array of transactions from all specified chains, sorted by timestamp (newest first). Each transaction includes: * `txnHash`: Transaction hash * `chainId`: Chain ID where transaction occurred * `timestamp`: Transaction timestamp * `blockNumber`: Block number where transaction was mined * `blockHash`: Hash of the block * `metaTxnID`: Optional meta transaction ID * `transfers`: Array of transfer objects with normalized addresses #### isLoading `boolean` Loading state for the initial data fetch. #### isError `boolean` Error state indicating if the query failed. #### error `Error | null` Any error that occurred during data fetching. ## Parameters The hook accepts two parameters: ### args: `GetTransactionHistorySummaryArgs` ```tsx theme={null} interface GetTransactionHistorySummaryArgs { accountAddress: string chainIds: number[] } ``` | Parameter | Type | Description | | ---------------- | ---------- | --------------------------------------------- | | `accountAddress` | `string` | The account address to fetch transactions for | | `chainIds` | `number[]` | Array of chain IDs to fetch transactions from | ### options: `HooksOptions` ```tsx theme={null} interface HooksOptions { disabled?: boolean retry?: boolean } ``` | Parameter | Type | Description | | ---------- | --------- | ------------------------------------------------------- | | `disabled` | `boolean` | (Optional) Disable the query from automatically running | | `retry` | `boolean` | (Optional) Whether to retry failed queries | # useIndexerClient Source: https://docs.sequence.xyz/sdk/web/hooks-sdk/hooks/useIndexerClient Hook for managing a Sequence Indexer client for a specific chain ## Import ```tsx theme={null} import { useIndexerClient } from '@0xsequence/hooks' ``` ## Usage ```tsx theme={null} import { useIndexerClient } from '@0xsequence/hooks' import { ContractVerificationStatus } from '@0xsequence/connect' function TokenBalanceChecker() { const chainId = 1 // Ethereum mainnet const indexerClient = useIndexerClient(chainId) const { address } = useAccount() const checkBalance = async () => { // Get native token balance const nativeBalance = await indexerClient.getNativeTokenBalance({ accountAddress: address }) // Get token balances const tokenBalances = await indexerClient.getTokenBalancesSummary({ filter: { accountAddresses: [address], contractStatus: ContractVerificationStatus.ALL, omitNativeBalances: true } }) console.log('Native balance:', nativeBalance) console.log('Token balances:', tokenBalances) } return ( ) } ``` ## Return Type: `SequenceIndexer` Returns a `SequenceIndexer` instance configured for the specified chain ID. ## Parameters ### chainId `ChainId` The chain ID to create an indexer client for. Must be a supported chain ID from `@0xsequence/network`. ## Related Hooks For applications that need to work with multiple chains simultaneously, consider using `useIndexerClients`. It accepts an array of chain IDs and returns a Map of indexer clients, enabling parallel operations across different networks. ### Usage with `useIndexerClients` ```tsx theme={null} import { useIndexerClients } from '@0xsequence/hooks' const TransactionFetcher = () => { // Get indexer clients for Ethereum mainnet and Polygon const indexerClients = useIndexerClients([1, 137]) // Use the clients to fetch data const fetchData = async () => { // Get Ethereum client const ethClient = indexerClients.get(1) // Get Polygon client const polygonClient = indexerClients.get(137) // Make parallel requests const [ethData, polygonData] = await Promise.all([ ethClient.getTransactionHistory(...), polygonClient.getTransactionHistory(...) ]) } } ``` # useIndexerGatewayClient Source: https://docs.sequence.xyz/sdk/web/hooks-sdk/hooks/useIndexerGatewayClient Hook for accessing the Sequence Indexer Gateway client for multi-chain queries ## Import ```tsx theme={null} import { useIndexerGatewayClient } from '@0xsequence/hooks' ``` ## Usage ```tsx theme={null} import { useIndexerGatewayClient } from '@0xsequence/hooks' import { useAccount } from 'wagmi' function MultiChainBalances() { const { address } = useAccount() const indexerGatewayClient = useIndexerGatewayClient() // Example: Fetch token balances across chains const fetchBalances = async () => { const response = await indexerGatewayClient.getTokenBalancesSummary({ chainIds: [1, 137], // Ethereum and Polygon filter: { accountAddresses: [address || ''], omitNativeBalances: false } }) return response } return (
{/* ... */}
) } ``` ## Return Type: `SequenceIndexerGateway` The hook returns a `SequenceIndexerGateway` instance configured with your project's settings. This client provides methods for querying token data across multiple chains in a single request. ### Available Methods The returned client includes the following methods: ```tsx theme={null} interface SequenceIndexerGateway { // Token Balance Methods getNativeTokenBalance(args: GetNativeTokenBalanceArgs): Promise getTokenBalances(args: GetTokenBalancesArgs): Promise getTokenBalancesSummary(args: GetTokenBalancesSummaryArgs): Promise getTokenBalancesDetails(args: GetTokenBalancesDetailsArgs): Promise getTokenBalancesByContract(args: GetTokenBalancesByContractArgs): Promise // Balance Updates getBalanceUpdates(args: GetBalanceUpdatesArgs): Promise // Service Status Methods ping(): Promise version(): Promise runtimeStatus(): Promise } ``` ## Parameters The hook doesn't accept any parameters, but uses configuration from the `useConfig` hook: ```tsx theme={null} interface Config { projectAccessKey: string env: { indexerGatewayUrl: string // ... other environment settings } } ``` The configuration determines: * The gateway URL for API requests * Your project's access key for authentication * Environment-specific settings The client is memoized based on the `projectAccessKey` to prevent unnecessary re-instantiation. # useMetadataClient Source: https://docs.sequence.xyz/sdk/web/hooks-sdk/hooks/useMetadataClient Hook for accessing the Sequence Metadata client for token and contract metadata ## Import ```tsx theme={null} import { useMetadataClient } from '@0xsequence/hooks' ``` ## Usage ```tsx theme={null} import { useMetadataClient } from '@0xsequence/hooks' function CustomMetadataFetcher() { const metadataClient = useMetadataClient() const [metadata, setMetadata] = useState(null) const [isLoading, setIsLoading] = useState(false) const fetchContractMetadata = async () => { setIsLoading(true) try { // Fetch metadata for a specific contract const response = await metadataClient.getContractInfo({ chainID: "1", contractAddress: "0x..." }) setMetadata(response.contractInfo) } catch (error) { console.error('Failed to fetch metadata:', error) } finally { setIsLoading(false) } } // Example of batch token metadata fetch const fetchBatchTokenMetadata = async () => { setIsLoading(true) try { const response = await metadataClient.getTokenMetadata({ chainID: "1", contractAddress: "0x...", tokenIDs: ["1", "2", "3"] }) setMetadata(response.tokenMetadata) } catch (error) { console.error('Failed to fetch token metadata:', error) } finally { setIsLoading(false) } } return (
{isLoading &&
Loading...
} {metadata && (
          {JSON.stringify(metadata, null, 2)}
        
)}
) } ``` ## Return Type: `SequenceMetadata` The hook returns a configured instance of the `SequenceMetadata` client. Here's the detailed structure: ```tsx theme={null} interface SequenceMetadata { // Service Methods ping(headers?: object, signal?: AbortSignal): Promise version(headers?: object, signal?: AbortSignal): Promise runtimeStatus(headers?: object, signal?: AbortSignal): Promise // Task Management Methods getTask(args: GetTaskArgs, headers?: object, signal?: AbortSignal): Promise getTaskStatus(args: GetTaskStatusArgs, headers?: object, signal?: AbortSignal): Promise // Token Metadata Methods getTokenMetadata(args: GetTokenMetadataArgs, headers?: object, signal?: AbortSignal): Promise getTokenMetadataBatch(args: GetTokenMetadataBatchArgs, headers?: object, signal?: AbortSignal): Promise searchTokenMetadata(args: SearchTokenMetadataArgs, headers?: object, signal?: AbortSignal): Promise searchTokenIDs(args: SearchTokenIDsArgs, headers?: object, signal?: AbortSignal): Promise tokenCollectionFilters(args: TokenCollectionFiltersArgs, headers?: object, signal?: AbortSignal): Promise // Token Refresh Methods refreshTokenMetadata(args: RefreshTokenMetadataArgs, headers?: object, signal?: AbortSignal): Promise enqueueTokensForRefresh(args: EnqueueTokensForRefreshArgs, headers?: object, signal?: AbortSignal): Promise getTokenRefreshStatus(args: GetTokenRefreshStatusArgs, headers?: object, signal?: AbortSignal): Promise getTokenRefreshResult(args: GetTokenRefreshResultArgs, headers?: object, signal?: AbortSignal): Promise cancelRefreshJob(args: CancelRefreshJobArgs, headers?: object, signal?: AbortSignal): Promise // Contract Methods getContractInfo(args: GetContractInfoArgs, headers?: object, signal?: AbortSignal): Promise getContractInfoBatch(args: GetContractInfoBatchArgs, headers?: object, signal?: AbortSignal): Promise searchContractInfo(args: SearchContractInfoArgs, headers?: object, signal?: AbortSignal): Promise searchContractInfoBatch(args: SearchContractInfoBatchArgs, headers?: object, signal?: AbortSignal): Promise refreshContractInfo(args: RefreshContractInfoArgs, headers?: object, signal?: AbortSignal): Promise refreshContractTokens(args: RefreshContractTokensArgs, headers?: object, signal?: AbortSignal): Promise refreshAllContractTokens(args: RefreshAllContractTokensArgs, headers?: object, signal?: AbortSignal): Promise // Search Methods searchMetadata(args: SearchMetadataArgs, headers?: object, signal?: AbortSignal): Promise searchTokens(args: SearchTokensArgs, headers?: object, signal?: AbortSignal): Promise searchContracts(args: SearchContractsArgs, headers?: object, signal?: AbortSignal): Promise // Niftyswap Methods getNiftyswapTokenQuantity(args: GetNiftyswapTokenQuantityArgs, headers?: object, signal?: AbortSignal): Promise getNiftyswapUnitPrices(args: GetNiftyswapUnitPricesArgs, headers?: object, signal?: AbortSignal): Promise getNiftyswapUnitPricesWithQuantities(args: GetNiftyswapUnitPricesWithQuantitiesArgs, headers?: object, signal?: AbortSignal): Promise // Mint Monitor Methods addContractToMintMonitor(args: AddContractToMintMonitorArgs, headers?: object, signal?: AbortSignal): Promise removeContractFromMintMonitor(args: RemoveContractFromMintMonitorArgs, headers?: object, signal?: AbortSignal): Promise mintMonitorJobStatus(args: MintMonitorJobStatusArgs, headers?: object, signal?: AbortSignal): Promise mintMonitorTriggerJob(args: MintMonitorTriggerJobArgs, headers?: object, signal?: AbortSignal): Promise // Contract Sync Methods syncContractTokens(args: SyncContractTokensArgs, headers?: object, signal?: AbortSignal): Promise abortContractSync(args: AbortContractSyncArgs, headers?: object, signal?: AbortSignal): Promise contractSyncJobStatus(args: ContractSyncJobStatusArgs, headers?: object, signal?: AbortSignal): Promise // Directory Methods directoryGetNetworks(args: DirectoryGetNetworksArgs, headers?: object, signal?: AbortSignal): Promise directoryGetCollections(args: DirectoryGetCollectionsArgs, headers?: object, signal?: AbortSignal): Promise directorySearchCollections(args: DirectorySearchCollectionsArgs, headers?: object, signal?: AbortSignal): Promise } ``` ### Available Methods #### Service Methods * `ping`: Check service availability * `version`: Get metadata service version information * `runtimeStatus`: Get current runtime status of the service #### Task Management Methods * `getTask`: Get details of a specific task * `getTaskStatus`: Get status of a task #### Token Metadata Methods * `getTokenMetadata`: Fetch metadata for specific tokens * `getTokenMetadataBatch`: Batch fetch token metadata * `searchTokenMetadata`: Search through token metadata * `searchTokenIDs`: Search for specific token IDs * `tokenCollectionFilters`: Get available filters for token collections #### Token Refresh Methods * `refreshTokenMetadata`: Refresh metadata for specific tokens * `enqueueTokensForRefresh`: Queue tokens for metadata refresh * `getTokenRefreshStatus`: Check status of token refresh * `getTokenRefreshResult`: Get results of token refresh * `cancelRefreshJob`: Cancel an ongoing refresh job #### Contract Methods * `getContractInfo`: Fetch metadata for a single contract * `getContractInfoBatch`: Batch fetch contract metadata * `searchContractInfo`: Search through contract metadata * `searchContractInfoBatch`: Batch search contract metadata * `refreshContractInfo`: Refresh contract metadata * `refreshContractTokens`: Refresh tokens for a contract * `refreshAllContractTokens`: Refresh all tokens for a contract #### Search Methods * `searchMetadata`: Search through all metadata * `searchTokens`: Search for specific tokens * `searchContracts`: Search for specific contracts #### Niftyswap Methods * `getNiftyswapTokenQuantity`: Get token quantity information from Niftyswap * `getNiftyswapUnitPrices`: Get unit prices from Niftyswap * `getNiftyswapUnitPricesWithQuantities`: Get unit prices with quantities from Niftyswap #### Mint Monitor Methods * `addContractToMintMonitor`: Add contract to mint monitoring * `removeContractFromMintMonitor`: Remove contract from mint monitoring * `mintMonitorJobStatus`: Check status of mint monitoring job * `mintMonitorTriggerJob`: Trigger a mint monitoring job #### Contract Sync Methods * `syncContractTokens`: Sync tokens for a contract * `abortContractSync`: Abort an ongoing contract sync * `contractSyncJobStatus`: Check status of contract sync #### Directory Methods * `directoryGetNetworks`: Get available networks * `directoryGetCollections`: Get collections directory * `directorySearchCollections`: Search through collections directory ## Parameters The hook doesn't accept any parameters but uses configuration from the `useConfig` hook: ```tsx theme={null} interface Config { env: { metadataUrl: string // ... other environment settings } projectAccessKey: string jwt?: string } ``` The configuration determines: * The metadata service URL * Your project's access key for authentication * Optional JWT for authenticated requests The client is memoized based on the `projectAccessKey` and `jwt` to prevent unnecessary re-instantiation. # CollectibleCard Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/components/CollectibleCard A versatile card component for displaying collectibles in marketplace and shop contexts ## Import ```tsx theme={null} import { CollectibleCard } from "@0xsequence/marketplace-sdk/react"; ``` ## Usage ### Data Hooks The SDK provides specialized hooks to fetch and format data for the CollectibleCard component: #### Market Cards ```tsx theme={null} import { useListMarketCardData } from "@0xsequence/marketplace-sdk/react"; const { collectibleCards, isLoading, hasNextPage, isFetchingNextPage, fetchNextPage, } = useListMarketCardData({ orderbookKind, collectionType, filterOptions, searchText, showListedOnly, collectionAddress, chainId, }); ``` #### Shop Cards For shop cards, there are two hooks based on the contract type: ```tsx theme={null} // For ERC721 tokens import { useList721ShopCardData } from "@0xsequence/marketplace-sdk/react"; const { collectibleCards, isLoading } = useList721ShopCardData({ primarySaleItemsWithMetadata, chainId, contractAddress, salesContractAddress, enabled: contractType === ContractType.ERC721, }); // For ERC1155 tokens import { useList1155ShopCardData } from "@0xsequence/marketplace-sdk/react"; const { collectibleCards, isLoading } = useList1155ShopCardData({ chainId, contractAddress, salesContractAddress, enabled: contractType === ContractType.ERC1155, primarySaleItemsWithMetadata, }); ``` These hooks handle: * Data fetching and formatting * Loading states * Pagination (for market cards) * Type-specific data requirements * Integration with filters and search ### Examples Example of using the CollectibleCard component in a marketplace context: ```tsx theme={null} import { CollectibleCard } from "@0xsequence/marketplace-sdk/react"; export default function MarketExample() { return ( { console.log(`Clicked collectible ${tokenId}`); }} /> ); } ``` Example showing the CollectibleCard in a shop context: ```tsx theme={null} import { CollectibleCard } from "@0xsequence/marketplace-sdk/react"; export default function ShopExample() { return ( ); } ``` Example demonstrating offer functionality: Collectible Card with Offers ```tsx theme={null} import { CollectibleCard } from "@0xsequence/marketplace-sdk/react"; export default function OffersExample() { return ( { console.log('Offer clicked', order); e.preventDefault(); }} onCannotPerformAction={(action) => { console.log(`Cannot perform action: ${action}`); }} /> ); } ``` ## Parameters The component accepts different props based on the marketplace type: ### Base Props These properties are shared by all card types: ```tsx theme={null} interface MarketplaceCardBaseProps { collectibleId: string; chainId: number; collectionAddress: Address; collectionType?: ContractType; assetSrcPrefixUrl?: string; cardLoading?: boolean; marketplaceType?: MarketplaceType; isTradable?: boolean; } ``` | Parameter | Type | Description | | ------------------- | ----------------- | -------------------------------------------------- | | `collectibleId` | `string` | Unique identifier for the collectible | | `chainId` | `number` | The blockchain network ID | | `collectionAddress` | `Address` | The smart contract address of the collection | | `collectionType` | `ContractType` | Optional. The type of contract (ERC721 or ERC1155) | | `assetSrcPrefixUrl` | `string` | Optional URL prefix for asset sources | | `cardLoading` | `boolean` | Optional flag to show loading state | | `marketplaceType` | `MarketplaceType` | Optional. Type of marketplace ('market' or 'shop') | | `isTradable` | `boolean` | Optional flag indicating if the item can be traded | ### Shop Card Props Additional properties for shop cards (`marketplaceType="shop"`): ```tsx theme={null} interface ShopCardSpecificProps { salesContractAddress: Address; tokenMetadata: TokenMetadata; salePrice?: { amount: string; currencyAddress: Address; }; saleStartsAt?: string; saleEndsAt?: string; quantityDecimals?: number; quantityInitial?: string; quantityRemaining?: string; unlimitedSupply?: boolean; } ``` | Parameter | Type | Description | | ---------------------- | --------------- | --------------------------------------------------------- | | `salesContractAddress` | `Address` | The address of the sales contract | | `tokenMetadata` | `TokenMetadata` | Metadata for the token including name, description, image | | `salePrice` | `object` | Optional. Price information including amount and currency | | `saleStartsAt` | `string` | Optional. Sale start timestamp | | `saleEndsAt` | `string` | Optional. Sale end timestamp | | `quantityDecimals` | `number` | Optional. Number of decimals for quantity | | `quantityInitial` | `string` | Optional. Initial supply amount | | `quantityRemaining` | `string` | Optional. Remaining supply amount | | `unlimitedSupply` | `boolean` | Optional. Whether the supply is unlimited | ### Market Card Props Additional properties for market cards (`marketplaceType="market"`): ```tsx theme={null} interface MarketCardSpecificProps { orderbookKind?: OrderbookKind; collectible?: CollectibleOrder; onCollectibleClick?: (tokenId: string) => void; onOfferClick?: (params: { order?: Order; e: React.MouseEvent; }) => void; balance?: string; balanceIsLoading: boolean; onCannotPerformAction?: (action: CollectibleCardAction) => void; prioritizeOwnerActions?: boolean; } ``` | Parameter | Type | Description | | ------------------------ | ------------------ | --------------------------------------------------- | | `orderbookKind` | `OrderbookKind` | Optional. Type of orderbook | | `collectible` | `CollectibleOrder` | Optional. Collectible order information | | `onCollectibleClick` | `function` | Optional. Handler for collectible click events | | `onOfferClick` | `function` | Optional. Handler for offer click events | | `balance` | `string` | Optional. User's balance of this collectible | | `balanceIsLoading` | `boolean` | Whether the balance is currently loading | | `onCannotPerformAction` | `function` | Optional. Handler for unauthorized actions | | `prioritizeOwnerActions` | `boolean` | Optional. Whether to prioritize owner actions in UI | ## Features ### Card Variants The component supports two main variants: 1. **Market Card**: Used for displaying collectibles in a marketplace context with: * Current listing price * Highest offer indicator * Balance/ownership information * Buy/Offer actions 2. **Shop Card**: Used for primary sales with: * Sale price * Supply information * Sale status * Purchase actions ### Automatic Type Detection The component automatically handles different token standards: * ERC-721 (Non-fungible tokens) * ERC-1155 (Semi-fungible tokens) ### Loading States Built-in loading states are provided: ```tsx theme={null} ``` ### Price Formatting The component includes sophisticated price formatting with: * Currency symbol display * Overflow/underflow indicators * Support for various token decimals * "Free" indicator for zero prices ## Integration Examples ### Market Content Integration Here's a complete example of integrating the CollectibleCard in a marketplace context: ```tsx theme={null} import { CollectibleCard, useListMarketCardData, } from "@0xsequence/marketplace-sdk/react"; export function MarketContent({ collectionAddress, chainId, onCollectibleClick, }) { const { collectibleCards, isLoading, hasNextPage, isFetchingNextPage, fetchNextPage, } = useListMarketCardData({ orderbookKind, collectionType, filterOptions, searchText, showListedOnly, collectionAddress, chainId, }); return (
{collectibleCards.map((card, index) => ( ))}
); } ``` ### Shop Content Integration Example of integrating the CollectibleCard in a shop context with contract type handling: ```tsx theme={null} import { CollectibleCard, useList721ShopCardData, useList1155ShopCardData, } from "@0xsequence/marketplace-sdk/react"; export function ShopContent({ saleContractAddress, collectionAddress, chainId, onCollectibleClick, }) { // Choose hook based on contract type const { collectibleCards, isLoading } = contractType === ContractType.ERC721 ? useList721ShopCardData({ primarySaleItemsWithMetadata, chainId, contractAddress: collectionAddress, salesContractAddress: saleContractAddress, enabled: true, }) : useList1155ShopCardData({ chainId, contractAddress: collectionAddress, salesContractAddress: saleContractAddress, enabled: true, primarySaleItemsWithMetadata, }); return (
{collectibleCards.map((card, index) => ( ))}
); } ``` ## Notes The `MarketplaceCollectibleCard` component is designed to handle various marketplace scenarios with: * Responsive layout * Loading states * Price formatting * Supply tracking * Action handling * Owner-specific features * Offer management When using with ERC-1155 tokens, note that: * Balance is displayed as "Owned: X" format * Supply information is shown for shop items * Quantity tracking is supported ### Best Practices 1. **Data Fetching** * Use the appropriate data hook based on your context (market/shop) and contract type (ERC721/ERC1155) * Enable conditional fetching using the `enabled` prop when necessary * Handle loading states appropriately 2. **Event Handling** * Implement click handlers for both the card and specific actions (buy, offer) * Use the `onCannotPerformAction` callback to handle unauthorized actions 3. **Display** * Wrap cards in buttons for clickable behavior * Use appropriate className for layout and spacing * Consider implementing infinite scroll or pagination for large collections # Media Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/components/Media Component for displaying various types of collectible assets ## Import ```tsx theme={null} import { Media } from "@0xsequence/marketplace-sdk/react"; ``` ## Usage ### Examples Basic example of using the Media component to display an image: ```tsx theme={null} import { Media } from "@0xsequence/marketplace-sdk/react"; export default function BasicExample() { return ( ); } ``` Example showing how to handle multiple assets with fallback: ```tsx theme={null} import { Media } from "@0xsequence/marketplace-sdk/react"; export default function MultipleAssetsExample() { return ( ); } ``` Example with a custom fallback component: ```tsx theme={null} import { Media } from "@0xsequence/marketplace-sdk/react"; export default function CustomFallbackExample() { const CustomFallback = () => (

Asset not available

); return ( } /> ); } ```
## Parameters The component accepts the following props: ```tsx theme={null} interface MediaProps { name?: string; assets: (string | undefined)[]; assetSrcPrefixUrl?: string; className?: string; containerClassName?: string; mediaClassname?: string; isLoading?: boolean; fallbackContent?: React.ReactNode; shouldListenForLoad?: boolean; } ``` | Parameter | Type | Description | | --------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------- | | `name` | `string` | Optional name for the collectible, used as alt text for images | | `assets` | `(string \| undefined)[]` | Array of asset URLs to try loading. The component will attempt to load each asset in order until one succeeds | | `assetSrcPrefixUrl` | `string` | Optional URL prefix to prepend to asset URLs | | `className` | `string` | Optional CSS class name for the component container | | `containerClassName` | `string` | Optional CSS class name for the outer container | | `mediaClassname` | `string` | Optional CSS class name for the media element itself | | `isLoading` | `boolean` | Optional flag to show loading state | | `fallbackContent` | `React.ReactNode` | Optional custom content to display when no assets can be loaded | | `shouldListenForLoad` | `boolean` | Optional flag to enable/disable load event listeners (defaults to true) | ## Supported Media Types The Media component automatically detects and handles different types of content: * **Images**: Renders standard image files (PNG, JPG, GIF, etc.) * **Videos**: Supports video files with autoplay, loop, and controls * **3D Models**: Renders 3D models using ModelViewer component * **HTML**: Displays HTML content in a sandboxed iframe ## Features ### Automatic Content Type Detection The component automatically detects the content type of the asset and renders the appropriate element: ```tsx theme={null} ``` ### Fallback Chain If an asset fails to load, the component will: 1. Try the next asset in the assets array 2. If all assets fail, display the custom fallback content 3. If no fallback content is provided, show the default chess tile pattern ### Loading States The component includes built-in loading states: ```tsx theme={null} ``` ## Notes The `Media` component is designed to handle various types of collectible assets with built-in: * Automatic content type detection * Fallback handling * Loading states * Safari compatibility adjustments When using with video content, note that: * Videos autoplay by default * Videos are muted by default for autoplay compatibility # Getting Started with Marketplace SDK Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/getting-started Learn how to integrate Marketplace SDK into your application with guidance on installation, configuration, and implementing the make offer feature # Getting Started Let's create a simple React application that can display and interact with collectibles. We'll set up wallet connection and basic collectible viewing functionality. Before you begin coding, you'll need to set up your project: 1. Go to [Sequence Builder](https://sequence.build) 2. Create a new project 3. Follow our [White-label Marketplace Guide](https://docs.sequence.xyz/solutions/payments/marketplace/overview) 4. Note down your Project ID and API Access Key We'll use Vite with React and TypeScript for this guide. You can use any package manager, but we'll use pnpm in our examples: ```bash theme={null} # Create a new project pnpm create vite@latest my-marketplace-app -- --template react-ts # Navigate to the project directory cd my-marketplace-app # Install dependencies pnpm install ``` Install the Marketplace SDK and its peer dependencies: ```bash theme={null} pnpm add @0xsequence/marketplace-sdk @0xsequence/connect wagmi viem @tanstack/react-query ``` Create a new file `src/config/sdk.ts` to store your SDK configuration: ```tsx theme={null} import type { SdkConfig } from "@0xsequence/marketplace-sdk"; export const sdkConfig = { projectId: "YOUR_PROJECT_ID", projectAccessKey: "YOUR_PROJECT_ACCESS_KEY", } satisfies SdkConfig; ``` Make sure to replace `YOUR_PROJECT_ID` and `YOUR_PROJECT_ACCESS_KEY` with your actual project credentials. You can find your Project ID at `https://sequence.build/project/{YOUR_PROJECT_ID}/overview` and your Project Access Key at `https://sequence.build/project/{YOUR_PROJECT_ID}/settings/apikeys` in the [Sequence Builder](https://sequence.build) dashboard. Create a new file `src/providers.tsx` to configure the necessary providers: ```tsx theme={null} import { MarketplaceProvider, MarketplaceQueryClientProvider, ModalProvider, createWagmiConfig, getQueryClient, marketplaceConfigOptions, } from "@0xsequence/marketplace-sdk/react"; import { useQuery } from "@tanstack/react-query"; import { WagmiProvider } from "wagmi"; import { SequenceConnectProvider, type ConnectConfig, } from "@0xsequence/connect"; import { sdkConfig } from "./config/sdk"; interface ProvidersProps { children: React.ReactNode; } export default function Providers({ children }: ProvidersProps) { const queryClient = getQueryClient(); const { data: marketplaceConfig, isLoading } = useQuery( marketplaceConfigOptions(sdkConfig), queryClient ); if (isLoading) { return
Loading configuration...
; } if (!marketplaceConfig) { return
Failed to load marketplace configuration
; } const connectConfig: ConnectConfig = { projectAccessKey: sdkConfig.projectAccessKey, signIn: { projectName: marketplaceConfig.settings.title, }, }; const wagmiConfig = createWagmiConfig(marketplaceConfig, sdkConfig); return ( {children} ); } ```
Update your `main.tsx` to use the Providers component: ```tsx theme={null} import React from 'react' import ReactDOM from 'react-dom/client' import App from './App' import Providers from './providers' import './index.css' ReactDOM.createRoot(document.getElementById('root')!).render( ) ``` Create a new component `src/components/CollectibleCard.tsx` to display and interact with collectibles: ```tsx theme={null} import { useCollectible, useMakeOfferModal, useMarketplaceConfig, useOpenConnectModal, } from "@0xsequence/marketplace-sdk/react"; import type { Address } from "viem"; import { useAccount } from "wagmi"; export default function CollectibleCard() { const { data: marketplaceConfig, isLoading: isMarketplaceConfigLoading } = useMarketplaceConfig(); const { isConnected } = useAccount() const { openConnectModal } = useOpenConnectModal() const collection = marketplaceConfig?.market.collections[0]; const chainId = collection?.chainId as number; const collectionAddress = collection?.itemsAddress as Address; const collectibleId = "0"; const { data: collectible, isLoading: isCollectibleLoading, error: collectibleError } = useCollectible({ chainId, collectionAddress, collectibleId, }); const { show } = useMakeOfferModal(); if (isMarketplaceConfigLoading || isCollectibleLoading) return
Loading...
; if (collectibleError) return
Error: {collectibleError.message}
; if (!collectible) return
No collectible found
; return (
{collectible.name}

{collectible.name}

{isConnected ? ( ) : ( )}
); } ``` Make sure you have minted at least one collectible in your collection, then use that collectible's ID as the `collectibleId` While Sequence Connect is recommended for the best experience, you can use other wallet providers with the Marketplace SDK. For custom wallet connectors, see our guide on [custom connectors](/sdk/web/wallet-sdk/embedded/custom-connectors).
Update your `App.tsx` to use the new components: ```tsx theme={null} import NFTCard from "./nft-card"; export default function App() { return ( ); } ``` Start your development server: ```bash theme={null} pnpm run dev ``` Your marketplace application will be running at `http://localhost:5173`. You can now: 1. Connect your wallet using the connect button 2. View collectible details 3. Make offers on the collectible using the Make Offer button
## Next Steps Now that you have the basics working, you can: * Create collectible listings * Manage orders * Customize the UI * Check out our other guides for more features Need help? Join our [Discord community](https://discord.gg/sequence). # useBuyModal Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-actions/useBuyModal Hook for managing the buy modal interface for collectible purchases ## Import ```typescript theme={null} import { useBuyModal } from "@0xsequence/marketplace-sdk/react"; ``` ## Usage Make sure you have followed the [Getting Started](https://docs.sequence.xyz/sdk/web/marketplace-sdk/getting-started) guide to get the collection address and chainId. ### Examples Example of implementing a market purchase (secondary sales) using the `useBuyModal` hook: This example uses the [`useLowestListing`](/sdk/web/marketplace-sdk/hooks/marketplace-data/useLowestListing) hook from marketplace-sdk. If there is no lowestListing with the given parameters, it means there is no orderId available, and therefore the item cannot be bought. First, create a main component that handles marketplace configuration loading and validation: ```typescript theme={null} import { useBuyModal, useLowestListing, useMarketplaceConfig, } from '@0xsequence/marketplace-sdk/react'; import type { Address } from 'viem'; function MarketPurchaseExample() { const { data: marketplaceConfig, isLoading: isMarketplaceConfigLoading } = useMarketplaceConfig(); // Handle loading states if (isMarketplaceConfigLoading) { return
Loading marketplace config...
; } if (!marketplaceConfig) { return (
No marketplace config available
); } const collection = marketplaceConfig.market.collections[0]; if (!collection) { return
No collections available
; } const chainId = collection.chainId; const collectionAddress = collection.itemsAddress as Address; return ( ); } ```
Next, create the actual market purchase component that uses properly validated data: ```typescript theme={null} interface MarketPurchaseProps { chainId: number; collectionAddress: Address; collectibleId: string; } function MarketPurchase({ chainId, collectionAddress, collectibleId, }: MarketPurchaseProps) { const { data: lowestListing, isLoading: isLoadingLowestListing, isError: isErrorLowestListing, } = useLowestListing({ collectionAddress, chainId, tokenId: collectibleId, }); const { show: showMarketModal } = useBuyModal({ onSuccess: ({ hash, orderId }) => { console.log('Market purchase successful', { hash, orderId }); }, onError: (error) => { console.error('Market purchase failed:', error.message); }, }); const handleMarketBuy = () => { if (!lowestListing || isLoadingLowestListing) return; showMarketModal({ chainId, collectionAddress, collectibleId, orderId: lowestListing.orderId, marketplace: lowestListing.marketplace, }); }; if (isLoadingLowestListing) { return
Loading listing...
; } if (isErrorLowestListing || !lowestListing) { return (
Error loading listing or no listing found
); } return (

Market Purchase

Price: ${lowestListing.priceUSDFormatted}

); } ```
Example of implementing a shop purchase (primary sales) using the `useBuyModal` hook: This example uses the [`useListPrimarySaleItems`](/sdk/web/marketplace-sdk/hooks/marketplace-data/useListPrimarySaleItems) hook from marketplace-sdk. The hook fetches primary sale items from a specific contract. If there is no primarySaleItem with the given parameters or if the supply is 0, the item cannot be bought. First, create a main component that handles marketplace configuration loading and validation: ```typescript theme={null} import { useBuyModal, useListPrimarySaleItems, useMarketplaceConfig, } from '@0xsequence/marketplace-sdk/react'; import type { Address } from 'viem'; function ShopPurchaseExample() { const { data: marketplaceConfig, isLoading: isMarketplaceConfigLoading } = useMarketplaceConfig(); // Handle loading states if (isMarketplaceConfigLoading) { return
Loading marketplace config...
; } if (!marketplaceConfig) { return (
No marketplace config available
); } const collection = marketplaceConfig.shop.collections[0]; if (!collection) { return
No shop collections available
; } const chainId = collection.chainId; const collectionAddress = collection.itemsAddress as Address; const saleContractAddress = collection.saleAddress as Address; return ( ); } ```
Next, create the actual shop purchase component that uses properly validated data: ```typescript theme={null} interface ShopPurchaseProps { chainId: number; collectionAddress: Address; saleContractAddress: Address; collectibleId: string; } function ShopPurchase({ chainId, collectionAddress, saleContractAddress, collectibleId, }: ShopPurchaseProps) { const { show: showBuyModal } = useBuyModal({ onSuccess: ({ hash }) => { console.log('Shop purchase successful', { hash }); }, onError: (error) => { console.error('Shop purchase failed:', error.message); }, }); // Fetch primary sale items const { data: primarySaleItems, isLoading: isLoadingPrimarySale } = useListPrimarySaleItems({ chainId, primarySaleContractAddress: saleContractAddress, filter: { includeEmpty: true, }, }); const primarySaleItem = primarySaleItems?.pages[0]?.primarySaleItems[0]?.primarySaleItem; const handleShopBuy = () => { if (!primarySaleItem) return; showBuyModal({ chainId, collectionAddress, salesContractAddress: saleContractAddress, cardType: 'shop', quantityDecimals: 0, quantityRemaining: Number(primarySaleItem.supply), items: [ { tokenId: collectibleId, quantity: '1', }, ], salePrice: { amount: primarySaleItem.priceAmount ?? '0', currencyAddress: (primarySaleItem.currencyAddress as Address) ?? '0x', }, }); }; if (isLoadingPrimarySale) { return
Loading primary sale items...
; } if (!primarySaleItem) { return (
No primary sale items available
); } return (

Shop Purchase

Available: {primarySaleItem.supply ?? 0}

); } ```
## Parameters The hook accepts an optional `callbacks` object with the following properties: ```typescript theme={null} interface ModalCallbacks { onSuccess?: ({ hash, orderId }: { hash?: Hash; orderId?: string }) => void; onError?: (error: Error) => void; successActionButtons?: Array<{ label: string; action: () => void }>; } ``` | Parameter | Type | Description | | -------------------------------- | ---------------------------------------------------------------- | -------------------------------------------------------------------------- | | `callbacks.onSuccess` | `({ hash, orderId }: { hash?: Hash; orderId?: string }) => void` | Optional callback function called when the purchase is successful | | `callbacks.onError` | `(error: Error) => void` | Optional callback function called when an error occurs during the purchase | | `callbacks.successActionButtons` | `Array<{ label: string; action: () => void }>` | Optional array of action buttons to show on success | ## Return Type The hook returns an object with the following methods: ```typescript theme={null} { show: (args: BuyModalProps) => void close: () => void } ``` ### Methods #### show `(args: BuyModalProps) => void` Opens the buy modal with the specified parameters. The `BuyModalProps` can be either `ShopBuyModalProps` or `MarketplaceBuyModalProps` depending on the purchase type. For market purchases (Secondary sales): ```typescript theme={null} interface MarketplaceBuyModalProps extends BuyModalBaseProps { marketplaceType?: "market"; collectibleId: string; marketplace: MarketplaceKind; orderId: string; } ``` For shop purchases (Primary sales): ```typescript theme={null} interface ShopBuyModalProps extends BuyModalBaseProps { marketplaceType: "shop"; salesContractAddress: Address; items: Array & { tokenId?: string }>; quantityDecimals: number; quantityRemaining: number; salePrice: { amount: string; currencyAddress: Address; }; unlimitedSupply?: boolean; } ``` Both types extend from `BuyModalBaseProps`: ```typescript theme={null} interface BuyModalBaseProps { chainId: number; collectionAddress: Address; skipNativeBalanceCheck?: boolean; nativeTokenAddress?: Address; marketplaceType?: MarketplaceType; customCreditCardProviderCallback?: (buyStep: Step) => void; successActionButtons?: Array<{ label: string; action: () => void }>; } ``` #### close `() => void` Closes the buy modal. ## Notes The `useBuyModal` hook provides a convenient way to manage the buy modal interface for collectible purchases. It handles: * Opening and closing the modal * Managing the purchase flow state * Error handling and success callbacks * Support for both primary and secondary sales # useCancelOrder Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-actions/useCancelOrder The useCancelOrder hook allows users to cancel a listing of an NFT that is currently for sale on the Marketplace. It handles the cancellation process and transaction execution. ```ts theme={null} import { useCancelOrder } from '@0xsequence/marketplace-sdk/react'; ## Into your React component: const { cancelOrder } = useCancelOrder({ chainId, collectionAddress }); const onClickCancel = () => { cancelOrder({ marketplace, orderId, }); }; return ; ``` ```ts theme={null} interface UseCancelOrderArgs { collectionAddress: string; chainId: number; onSuccess?: ({ hash, orderId }: { hash?: string; orderId?: string; }) => void; onError?: (error: Error) => void; } ``` ```ts theme={null} interface CancelOrderArgs { orderId: string; marketplace: MarketplaceKind; } ``` # useCreateListingModal Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-actions/useCreateListingModal Hook for managing the create listing modal interface for collectible sales ## Import ```typescript theme={null} import { useCreateListingModal } from "@0xsequence/marketplace-sdk/react"; ``` Create Listing Modal ## Usage Make sure you have followed the [Getting Started](https://docs.sequence.xyz/sdk/web/marketplace-sdk/getting-started) guide to get the collection address and chainId. ### Examples Example of implementing a basic listing creation using the `useCreateListingModal` hook: This example uses the [`useCollectible`](/sdk/web/marketplace-sdk/hooks/marketplace-data/useCollectible) and [`useBalanceOfCollectible`](/sdk/web/marketplace-sdk/hooks/marketplace-data/useBalanceOfCollectible) hooks from marketplace-sdk to verify ownership and get collectible details. ```typescript theme={null} export default function BasicListingExample() { const { address: accountAddress } = useAccount(); const { data: marketplaceConfig, isLoading: isMarketplaceConfigLoading } = useMarketplaceConfig(); const collection = marketplaceConfig?.market.collections[0]; const chainId = collection?.chainId as number; const collectionAddress = collection?.itemsAddress as Address; const collectibleId = '0'; const orderbookKind = OrderbookKind.sequence_marketplace_v2; // Get collectible metadata const { data: collectible, isLoading: isLoadingCollectible, isError: isErrorCollectible, } = useCollectible({ chainId, collectionAddress, collectibleId, }); // Check if user owns the collectible const { data: balance, isLoading: isLoadingBalance, isError: isErrorBalance, } = useBalanceOfCollectible({ collectionAddress, collectableId: collectibleId, userAddress: accountAddress as Address, chainId, query: { enabled: !!accountAddress, }, }); const { show: showCreateListingModal } = useCreateListingModal({ onSuccess: ({ hash, orderId }) => { console.log('Listing created successfully', { hash, orderId }); }, onError: (error) => { console.error('Listing creation failed:', error.message); }, }); const handleCreateListing = () => { if (!collectible || !balance || Number(balance) === 0) return; showCreateListingModal({ chainId, collectionAddress, collectibleId, orderbookKind, }); }; const isOwner = balance && Number(balance) > 0; const isLoading = isLoadingCollectible || isLoadingBalance; const hasError = isErrorCollectible || isErrorBalance; return (

Create Listing

{collectible && (

Name: {collectible.name}

Collectible ID: {collectibleId}

Owned: {balance?.balance || '0'}

)}
); } ```
Example of implementing listing creation from a user's inventory: This example demonstrates how to integrate the listing modal with inventory management, allowing users to list collectibles they own. ```typescript theme={null} export default function InventoryListingExample() { const { address: accountAddress } = useAccount(); const { data: marketplaceConfig, isLoading: isMarketplaceConfigLoading } = useMarketplaceConfig(); const collection = marketplaceConfig?.market.collections[0]; const chainId = collection?.chainId as number; const collectionAddress = collection?.itemsAddress as Address; const orderbookKind = OrderbookKind.sequence_marketplace_v2; // Get user's inventory for this collection const { data: inventoryData, isLoading: isLoadingInventory, error: inventoryError, } = useInventory({ accountAddress: accountAddress as Address, collectionAddress, chainId, query: { enabled: !!accountAddress, }, }); const { show: showCreateListingModal } = useCreateListingModal({ onSuccess: ({ hash, orderId }) => { console.log('Listing created successfully', { hash, orderId }); // Optionally refetch inventory to update UI }, onError: (error) => { console.error('Failed to create listing:', error.message); }, successActionButtons: [ { label: 'View Listing', action: () => { // Navigate to listing or marketplace console.log('Navigate to listing'); }, }, ], }); const handleListCollectible = (tokenId: string) => { showCreateListingModal({ chainId, collectionAddress, collectibleId: tokenId, orderbookKind, }); }; if (isLoadingInventory) { return
Loading inventory...
; } if (inventoryError) { return
Error loading inventory: {inventoryError.message}
; } if (!inventoryData?.collectibles?.length) { return
No collectibles found in your inventory
; } return (

Your Collection - Create Listings

{inventoryData.collectibles.map((collectible) => (
{collectible.metadata.image && ( {collectible.metadata.name} )}

{collectible.metadata.name}

Collectible ID: {collectible.metadata.tokenId}

Balance: {collectible.balance}

))}
); } ```
## Parameters The hook accepts an optional `callbacks` object with the following properties: ```typescript theme={null} interface ModalCallbacks { onSuccess?: ({ hash, orderId }: { hash?: Hash; orderId?: string }) => void; onError?: (error: Error) => void; successActionButtons?: Array<{ label: string; action: () => void }>; } ``` | Parameter | Type | Description | | -------------------------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------ | | `callbacks.onSuccess` | `({ hash, orderId }: { hash?: Hash; orderId?: string }) => void` | Optional callback function called when the listing is created successfully | | `callbacks.onError` | `(error: Error) => void` | Optional callback function called when an error occurs during listing creation | | `callbacks.successActionButtons` | `Array<{ label: string; action: () => void }>` | Optional array of action buttons to show on success | ## Return Type The hook returns an object with the following methods: ```tsx theme={null} { show: (args: ShowCreateListingModalArgs) => void close: () => void } ``` ### Methods #### show `(args: ShowCreateListingModalArgs) => void` Opens the create listing modal with the specified parameters. ```typescript theme={null} interface ShowCreateListingModalArgs { collectionAddress: Address; chainId: number; collectibleId: string; orderbookKind?: OrderbookKind; } ``` | Parameter | Type | Required | Description | | ------------------- | --------------- | -------- | ----------------------------------------------------------------- | | `collectionAddress` | `Address` | Yes | The contract address of the collection | | `chainId` | `number` | Yes | The blockchain network ID (e.g., 1 for Ethereum, 137 for Polygon) | | `collectibleId` | `string` | Yes | The collectible ID of the collectible to list | | `orderbookKind` | `OrderbookKind` | No | The orderbook type to use (defaults to sequence\_marketplace\_v2) | #### close `() => void` Closes the create listing modal. ## Notes The `useCreateListingModal` hook provides a convenient way to manage the create listing modal interface for collectible sales. It handles: * Opening and closing the modal * Managing the listing creation flow state * Price and quantity input validation * Expiration date selection * Error handling and success callbacks * Transaction approval and execution steps * Support for different orderbook types ### Prerequisites Before using this hook, ensure: 1. **User Authentication**: The user must be connected with a wallet 2. **Ownership Verification**: Use hooks like [`useBalanceOfCollectible`](/sdk/web/marketplace-sdk/hooks/marketplace-data/useBalanceOfCollectible) to verify the user owns the collectible 3. **Collectible Data**: Use [`useCollectible`](/sdk/web/marketplace-sdk/hooks/marketplace-data/useCollectible) to get metadata for the collectible being listed 4. **Network Configuration**: Ensure the marketplace is configured for the target chain ### Related Hooks * [`useCollectible`](/sdk/web/marketplace-sdk/hooks/marketplace-data/useCollectible) - Get collectible metadata * [`useBalanceOfCollectible`](/sdk/web/marketplace-sdk/hooks/marketplace-data/useBalanceOfCollectible) - Check ownership * [`useInventory`](/sdk/web/marketplace-sdk/hooks/marketplace-data/useInventory) - Get user's collectibles * [`useListListingsForCollectible`](/sdk/web/marketplace-sdk/hooks/marketplace-data/useListListingsForCollectible) - Get existing listings # useMakeOfferModal Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-actions/useMakeOfferModal Hook for managing the make offer modal interface for creating offers on collectibles ## Import ```typescript theme={null} import { useMakeOfferModal } from "@0xsequence/marketplace-sdk/react"; ``` ## Usage Make sure you have followed the [Getting Started](https://docs.sequence.xyz/sdk/web/marketplace-sdk/getting-started) guide to get the collection address and chainId. ### Example Example of implementing the make offer functionality using the `useMakeOfferModal` hook: ```typescript theme={null} export default function MakeOfferExample() { const { data: marketplaceConfig, isLoading: isMarketplaceConfigLoading } = useMarketplaceConfig(); const collection = marketplaceConfig?.market.collections[0]; const chainId = collection?.chainId as number; const collectionAddress = collection?.itemsAddress as Address; const collectibleId = '0'; const orderbookKind = collection?.destinationMarketplace; const { show: showMakeOfferModal } = useMakeOfferModal({ onSuccess: ({ hash }) => { console.log('Offer created successfully', { hash }); }, onError: (error) => { console.error('Failed to create offer:', error.message); }, }); const handleMakeOffer = () => { showMakeOfferModal({ chainId, collectionAddress, collectibleId, orderbookKind, // Optional - defaults to sequence_marketplace_v2 }); }; return (

Make Offer

); } ``` ## Parameters The hook accepts an optional `callbacks` object with the following properties: ```typescript theme={null} interface ModalCallbacks { onSuccess?: ({ hash, orderId }: { hash?: Hash; orderId?: string }) => void; onError?: (error: Error) => void; successActionButtons?: Array<{ label: string; action: () => void }>; } ``` | Parameter | Type | Description | | -------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------------------- | | `callbacks.onSuccess` | `({ hash, orderId }: { hash?: Hash; orderId?: string }) => void` | Optional callback function called when the offer is created successfully | | `callbacks.onError` | `(error: Error) => void` | Optional callback function called when an error occurs during offer creation | | `callbacks.successActionButtons` | `Array<{ label: string; action: () => void }>` | Optional array of action buttons to show on success | ## Return Type The hook returns an object with the following methods: ```typescript theme={null} { show: (args: ShowMakeOfferModalArgs) => void close: () => void } ``` ### Methods #### show `(args: ShowMakeOfferModalArgs) => void` Opens the make offer modal with the specified parameters. ```typescript theme={null} interface ShowMakeOfferModalArgs { collectionAddress: Address; chainId: number; collectibleId: string; orderbookKind?: OrderbookKind; } ``` | Parameter | Type | Description | | ------------------- | --------------- | ---------------------------------------------------------------------------------- | | `collectionAddress` | `Address` | The contract address of the NFT collection | | `chainId` | `number` | The blockchain network chain ID where the collection exists | | `collectibleId` | `string` | The token ID of the specific collectible to make an offer on | | `orderbookKind` | `OrderbookKind` | Optional. The marketplace orderbook to use (defaults to `sequence_marketplace_v2`) | #### OrderbookKind Values You can import the `OrderbookKind` type from the marketplace SDK: ```typescript theme={null} import { OrderbookKind } from "@0xsequence/marketplace-sdk"; ``` ```typescript theme={null} enum OrderbookKind { unknown = "unknown", sequence_marketplace_v1 = "sequence_marketplace_v1", sequence_marketplace_v2 = "sequence_marketplace_v2", blur = "blur", opensea = "opensea", looks_rare = "looks_rare", } ``` #### close `() => void` Closes the make offer modal. ## Notes The `useMakeOfferModal` hook provides a convenient way to manage the make offer modal interface for creating offers on collectibles. It handles: * Opening and closing the modal * Managing the offer creation flow state * Token approval for the offer currency (if required) * Error handling and success callbacks * Support for different marketplace orderbooks * Offer expiration date management (defaults to 7 days) * Currency selection and price input validation The modal allows users to: * Select the offer price and currency * Set the offer quantity (for ERC-1155 tokens) * Choose an expiration date for the offer * Complete the necessary blockchain transactions (approval + offer creation) # useSellModal Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-actions/useSellModal Hook for managing the sell modal interface for accepting offers on collectibles ## Import ```typescript theme={null} import { useSellModal } from "@0xsequence/marketplace-sdk/react"; ``` Sell Modal ## Usage The `useSellModal` hook provides a convenient way to manage the sell modal interface for accepting offers on collectibles. This modal is specifically used when a user wants to sell their collectible to an existing offer (bid) on the marketplace. Make sure you have followed the [Getting Started](https://docs.sequence.xyz/sdk/web/marketplace-sdk/getting-started) guide to get the collection address and chainId. ### Basic Example This example uses the [`useBalanceOfCollectible`](/sdk/web/marketplace-sdk/hooks/marketplace-data/useBalanceOfCollectible) hook from marketplace-sdk to verify ownership before showing the sell modal. ```typescript theme={null} import { useSellModal, useBalanceOfCollectible, useListOffersForCollectible, } from "@0xsequence/marketplace-sdk/react"; import { useAccount } from "wagmi"; import type { Address } from "viem"; import type { Order } from "@0xsequence/marketplace-sdk"; export default function SellToOfferExample() { const { address: accountAddress } = useAccount(); const { data: marketplaceConfig, isLoading: isMarketplaceConfigLoading } = useMarketplaceConfig(); const collection = marketplaceConfig?.market.collections[0]; const chainId = collection?.chainId as number; const collectionAddress = collection?.itemsAddress as Address; // Replace with your collectible ID that has at least one offer const collectibleId = "0"; // Check if user owns the collectible const { data: balance, isLoading: isLoadingBalance, isError: isErrorBalance, } = useBalanceOfCollectible({ collectionAddress, collectableId: collectibleId, userAddress: accountAddress, chainId, }); // Get available offers for this collectible const { data: offersData, isLoading: isLoadingOffers, error: offersError, } = useListOffersForCollectible({ chainId, collectionAddress, collectibleId, }); const { show: showSellModal } = useSellModal({ onSuccess: ({ hash, orderId }) => { console.log("Sale completed successfully", { hash, orderId }); }, onError: (error) => { console.error("Sale failed:", error.message); }, }); const handleSellToOffer = (offer: Order) => { if (!balance || Number(balance) === 0) return; showSellModal({ chainId, collectionAddress, tokenId: collectibleId, order: offer, }); }; const isOwner = balance && Number(balance) > 0; const isLoading = isLoadingBalance || isLoadingOffers; const hasError = isErrorBalance || offersError; const hasOffers = offersData?.orders && offersData.orders.length > 0; if (isLoading) { return
Loading...
; } if (hasError) { return
Error loading data
; } if (!isOwner) { return
You don't own this collectible
; } if (!hasOffers) { return
No offers available for this collectible
; } return (

Available Offers

Collectible ID: {collectibleId}

Your Balance: {balance}

{offersData.orders.map((offer) => (

Price: {offer.priceAmount} {offer.priceCurrency?.symbol}

From: {offer.createdBy}

Expires:{" "} {new Date(offer.validUntil * 1000).toLocaleDateString()}

))}
); } ``` ## Parameters The hook accepts an optional `callbacks` object with the following properties: ```typescript theme={null} interface ModalCallbacks { onSuccess?: ({ hash, orderId }: { hash?: Hash; orderId?: string }) => void; onError?: (error: Error) => void; successActionButtons?: Array<{ label: string; action: () => void }>; } ``` | Parameter | Type | Description | | -------------------------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------- | | `callbacks.onSuccess` | `({ hash, orderId }: { hash?: Hash; orderId?: string }) => void` | Optional callback function called when the sale is completed successfully | | `callbacks.onError` | `(error: Error) => void` | Optional callback function called when an error occurs during the sale | | `callbacks.successActionButtons` | `Array<{ label: string; action: () => void }>` | Optional array of action buttons to show on success | ## Return Type The hook returns an object with the following methods: ```tsx theme={null} { show: (args: ShowSellModalArgs) => void close: () => void } ``` ### Methods #### show `(args: ShowSellModalArgs) => void` Opens the sell modal with the specified parameters to accept an offer. ```typescript theme={null} interface ShowSellModalArgs { collectionAddress: Address; chainId: number; tokenId: string; order: Order; } ``` | Parameter | Type | Required | Description | | ------------------- | --------- | -------- | ----------------------------------------------------------------- | | `collectionAddress` | `Address` | Yes | The contract address of the collection | | `chainId` | `number` | Yes | The blockchain network ID (e.g., 1 for Ethereum, 137 for Polygon) | | `tokenId` | `string` | Yes | The collectible ID of the collectible being sold | | `order` | `Order` | Yes | The offer order object containing price, buyer, and other details | #### close `() => void` Closes the sell modal. ## Notes The `useSellModal` hook provides a convenient way to manage the sell modal interface for accepting offers on collectibles. It handles: * Opening and closing the modal * Managing the sale transaction flow state * Token approval steps (if required) * Transaction execution and signature steps * Error handling and success callbacks * Support for different marketplace types * Integration with WaaS (Wallet as a Service) fee options ### Prerequisites Before using this hook, ensure: 1. **User Authentication**: The user must be connected with a wallet 2. **Ownership Verification**: Use hooks like [`useBalanceOfCollectible`](/sdk/web/marketplace-sdk/hooks/marketplace-data/useBalanceOfCollectible) to verify the user owns the collectible 3. **Valid Offer**: Ensure there's a valid offer (Order object) to accept ### Related Hooks * [`useBalanceOfCollectible`](/sdk/web/marketplace-sdk/hooks/marketplace-data/useBalanceOfCollectible) - Check ownership * [`useListOffersForCollectible`](/sdk/web/marketplace-sdk/hooks/marketplace-data/useListOffersForCollectible) - Get available offers # useTransferModal Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-actions/useTransferModal Hook that provides functions to transfer NFTs from your account to another account ## Return An object containing the `show` and `close` functions to initiate NFT transfers from your account to another account ## Import ```typescript theme={null} import { useTransferModal } from "@0xsequence/marketplace-sdk/react"; ``` ## Example Basic usage: ```typescript theme={null} const { show: showTransferModal } = useTransferModal(); return ( ); ``` # Marketplace Data Hooks Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-data/overview The data hooks are essential for retrieving key Marketplace information in your application. Useful for fetching listings, offers, and other relevant data to power your UI. ## Recommended hooks The useListCollectibles hook retrieves the current listings and offers in a collection from your Marketplace. Useful for accessing and managing listings and offers efficiently The useListCollectiblesPaginated hook efficiently retrieves and manages current listings and offers from your Marketplace, making it ideal for displaying paginated NFTs within a collection # useBalanceOfCollectible Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-data/useBalanceOfCollectible Hook to fetch the balance of a specific collectible for a user ## Parameters | Name | Type | Description | | ------ | ---- | -------------------------------------- | | `args` | | The arguments for fetching the balance | ## Returns Query result containing the balance data ## Example ```typescript theme={null} const { data, isLoading, error } = useBalanceOfCollectible({ collectionAddress: "0x123...", collectableId: "1", userAddress: "0x456...", chainId: 1, query: { enabled: true, refetchInterval: 10000, }, }); ``` # useCollectible Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-data/useCollectible Hook to fetch metadata for a specific collectible This hook retrieves metadata for an individual NFT from a collection, including properties like name, description, image, attributes, etc. ## Parameters | Name | Type | Description | | -------- | ---- | ------------------------------------------------------------------------------- | | `params` | | Configuration parameters | | `params` | | .chainId - The chain ID (must be number, e.g., 1 for Ethereum, 137 for Polygon) | | `params` | | .collectionAddress - The collection contract address | | `params` | | .collectibleId - The token ID of the collectible | | `params` | | .query - Optional React Query configuration | ## Returns Query result containing the collectible metadata ## Example Basic usage: ```typescript theme={null} const { data: collectible, isLoading } = useCollectible({ chainId: 137, collectionAddress: '0x631998e91476da5b870d741192fc5cbc55f5a52e', collectibleId: '12345' }) ``` With custom query options: ```typescript theme={null} const { data } = useCollectible({ chainId: 137, collectionAddress: '0x631998e91476da5b870d741192fc5cbc55f5a52e', collectibleId: '12345', query: { enabled: Boolean(collectionAddress && tokenId), staleTime: 30_000 } }) ``` ## Basic Usage ```typescript theme={null} import { useCollectible } from '@0xsequence/marketplace-sdk/react/hooks'; const result = useCollectible({ // Add your parameters here }); ``` # useCollection Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-data/useCollection The useCollection hook retrieves information about a specific collection address in your Marketplace from Builder. The returned data includes details such as the chainId, address, symbol, and more. ```typescript theme={null} import { useCollection } from "@0xsequence/marketplace-sdk/react"; ## Into your React component: const { data: collectionData } = useCollection({ chainId: 137, collectionAddress: "0x0e5566a108e617baedbebb44e3fcc7bf03e3a839", query: { enabled: true, }, }); console.log(collectionData); ``` ```typescript theme={null} interface UseCollectionArgs { chainId: number; collectionAddress: Address; query?: { enabled?: boolean; }; } ``` Contains the collection data. Indicates whether the data is currently loading. # useCollectionBalanceDetails Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-data/useCollectionBalanceDetails The useCollectionBalanceDetails hook retrieves the token balances of multiple wallet addresses across one or more specified collections in your Marketplace from Builder. ```typescript theme={null} import { useCollectionBalanceDetails } from "@0xsequence/marketplace-sdk/react"; // Into your React component: const { data: collectionBalanceDetailsData } = useCollectionBalanceDetails({ chainId: 421614, filter: { accountAddresses: ["0x2b54eAE39bdcDbBE1bbe001a4329C38cD58679D1"], omitNativeBalances: true, contractWhitelist: ["0x36631c1e690714192614364ae9629850b546d194"], }, query: { enabled: true, }, }); console.log(collectionBalanceDetailsData); ``` ```typescript theme={null} interface UseCollectionBalanceDetailsArgs { chainId: number; filter: { accountAddresses: Address[]; omitNativeBalances: boolean; contractWhitelist?: Address[]; }; query?: { enabled?: boolean; }; } ``` Contains the token balances data. Indicates whether the data is currently loading. # useCollectionDetails Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-data/useCollectionDetails The useCollectionDetails hook retrieves information about a specific collection address. ```typescript theme={null} import { useCollectionDetails } from "@0xsequence/marketplace-sdk/react"; ## Into your React component: const { data: collectionDetailsData } = useCollectionDetails({ chainId: 421614, collectionAddress: "0x36631c1e690714192614364ae9629850b546d194" }); console.log(collectionDetailsData); ``` ```typescript theme={null} interface UseCollectionDetailsArgs { collectionAddress: string; chainId: number; } ``` Contains the collection data. Indicates whether the data is currently loading. # useCountListingsForCollectible Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-data/useCountListingsForCollectible Hook to get the count of listings for a specific collectible Counts the number of active listings for a given collectible in the marketplace. Useful for displaying listing counts in UI components ## Parameters | Name | Type | Description | | -------------------------- | ---------------------- | ---------------------------------------------------------------------- | | `params.config` | `SdkConfig` | Configuration parameters | | `params.chainId` | `number` | The chain ID (must be a number, e.g., 1 for Ethereum, 137 for Polygon) | | `params.collectionAddress` | `string` | The collection contract address | | `params.collectibleId` | `string` | The specific collectible/token ID | | `params.filter` | `OrdersFilter` | Optional filter criteria for listings | | `params.query` | `StandardQueryOptions` | Optional React Query configuration (from TanStack Query) | ## Returns Query result containing the count of listings ## Example Basic usage: ```typescript theme={null} const { data: listingCount, isLoading } = useCountListingsForCollectible({ chainId: 137, collectionAddress: '0x...', collectibleId: '123' }); ``` With filter: ```typescript theme={null} const { data: filteredCount } = useCountListingsForCollectible({ chainId: 137, collectionAddress: '0x...', collectibleId: '123', filter: { priceRange: { min: '1000000000000000000' } } }); ``` # useCountOfCollectables Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-data/useCountOfCollectables The useCountOfCollectables hook returns the number of NFTs in a collection. ```typescript theme={null} import { OrderSide } from "@0xsequence/marketplace-sdk"; import { useCountOfCollectables } from "@0xsequence/marketplace-sdk/react"; const countOfCollectables = useCountOfCollectables({ chainId, collectionAddress, side: OrderSide.listing, filter: { searchText: text, includeEmpty, properties, }, }); ``` ```typescript theme={null} interface UseCountOfCollectables { chainId: ChainId; collectionAddress: CollectionAddress; query?: { enabled?: boolean }; filter?: { includeEmpty: boolean; searchText?: string; properties?: { name: string; type: PropertyType; min?: number; max?: number; values?: any[]; }[]; marketplaces?: MarketplaceKind[]; inAccounts?: string[]; notInAccounts?: string[]; ordersCreatedBy?: string[]; ordersNotCreatedBy?: string[]; }; side?: OrderSide; } ``` Numeric response data. Indicates whether the data is currently loading. # useCountOffersForCollectible Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-data/useCountOffersForCollectible Hook to get the count of offers for a specific collectible Counts the number of active offers for a given collectible in the marketplace. Useful for displaying offer counts in UI components ## Parameters | Name | Type | Description | | -------------------------- | ---------------------- | ---------------------------------------------------------------------- | | `params.config` | `SdkConfig` | Configuration parameters | | `params.chainId` | `number` | The chain ID (must be a number, e.g., 1 for Ethereum, 137 for Polygon) | | `params.collectionAddress` | `string` | The collection contract address | | `params.collectibleId` | `string` | The specific collectible/token ID | | `params.filter` | `OrdersFilter` | Optional filter criteria for offers | | `params.query` | `StandardQueryOptions` | Optional React Query configuration (from TanStack Query) | ## Returns Query result containing the count of offers ## Example Basic usage: ```typescript theme={null} const { data: offerCount, isLoading } = useCountOffersForCollectible({ chainId: 137, collectionAddress: '0x...', collectibleId: '123' }); ``` With filter: ```typescript theme={null} const { data: filteredCount } = useCountOffersForCollectible({ chainId: 137, collectionAddress: '0x...', collectibleId: '123', filter: { priceRange: { min: '1000000000000000000' } } }); ``` # useCurrency Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-data/useCurrency Hook to fetch currency details from the marketplace Retrieves detailed information about a specific currency by its contract address. The currency data is cached from previous currency list calls when possible ## Parameters | Name | Type | Description | | ------------------------ | ---------------------- | ---------------------------------------------------------------------- | | `params.config` | `SdkConfig` | Configuration parameters | | `params.chainId` | `number` | The chain ID (must be a number, e.g., 1 for Ethereum, 137 for Polygon) | | `params.currencyAddress` | `string` | The currency contract address | | `params.query` | `StandardQueryOptions` | Optional React Query configuration (from TanStack Query) | ## Returns Query result containing currency details ## Example Basic usage: ```typescript theme={null} const { data, isLoading } = useCurrency({ chainId: 137, currencyAddress: '0x...' }); ``` With custom query options: ```typescript theme={null} const { data, isLoading } = useCurrency({ chainId: 1, currencyAddress: '0x...', query: { enabled: true } }); ``` # useFilters Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-data/useFilters Hook to fetch metadata filters for a collection Retrieves property filters for a collection from the metadata service, with support for marketplace-specific filter configuration including exclusion rules and custom ordering ## Parameters | Name | Type | Description | | ------------------------------ | ---------------------- | ---------------------------------------------------------------------- | | `params.config` | `SdkConfig` | Configuration parameters | | `params.chainId` | `number` | The chain ID (must be a number, e.g., 1 for Ethereum, 137 for Polygon) | | `params.collectionAddress` | `string` | The collection contract address to fetch filters for | | `params.showAllFilters` | `boolean` | Whether to show all filters or apply marketplace filtering | | `params.excludePropertyValues` | `boolean` | Whether to exclude property values from the response | | `params.query` | `StandardQueryOptions` | Optional React Query configuration (from TanStack Query) | ## Returns Query result containing property filters for the collection ## Example Basic usage: ```typescript theme={null} const { data: filters, isLoading } = useFilters({ chainId: 137, collectionAddress: '0x1234...' }); if (filters) { console.log(`Found ${filters.length} filters`); filters.forEach(filter => { console.log(`${filter.name}: ${filter.values?.join(', ')}`); }); } ``` With marketplace filtering disabled: ```typescript theme={null} const { data: allFilters } = useFilters({ chainId: 1, collectionAddress: '0x5678...', showAllFilters: true, // Bypass marketplace filter rules query: { enabled: Boolean(selectedCollection), staleTime: 300000 // Cache for 5 minutes } }); ``` Exclude property values for faster loading: ```typescript theme={null} const { data: filterNames } = useFilters({ chainId: 137, collectionAddress: collectionAddress, excludePropertyValues: true, // Only get filter names, not values query: { enabled: Boolean(collectionAddress) } }) ``` # useFloorOrder Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-data/useFloorOrder Hook to fetch the floor order for a collection Retrieves the lowest priced order (listing) currently available for any token in the specified collection from the marketplace ## Parameters | Name | Type | Description | | -------------------------- | ---------------------- | ---------------------------------------------------------------------- | | `params.config` | `SdkConfig` | Configuration parameters | | `params.chainId` | `number` | The chain ID (must be a number, e.g., 1 for Ethereum, 137 for Polygon) | | `params.collectionAddress` | `string` | The collection contract address | | `params.filter` | `OrdersFilter` | Optional filter criteria for collectibles | | `params.query` | `StandardQueryOptions` | Optional React Query configuration (from TanStack Query) | ## Returns Query result containing the floor order data for the collection ## Example Basic usage: ```typescript theme={null} const { data, isLoading } = useFloorOrder({ chainId: 137, collectionAddress: '0x...' }); ``` With filters and custom query options: ```typescript theme={null} const { data, isLoading } = useFloorOrder({ chainId: 1, collectionAddress: '0x...', filter: { minPrice: '1000000000000000000' // 1 ETH in wei }, query: { refetchInterval: 30000, enabled: hasCollectionAddress } }); ``` # useGetCountOfFilteredOrders Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-data/useGetCountOfFilteredOrders The useGetCountOfFilteredOrders hook returns the number of filtered orders in a collection ## Parameters | Name | Type | Description | | -------------------------- | ---------------------- | -------------------------------------------------------- | | `params.chainId` | `number` | The chain ID (e.g., 1 for Ethereum, 137 for Polygon) | | `params.collectionAddress` | `string` | The collection contract address | | `params.config` | `SdkConfig` | Optional SDK configuration parameters | | `params.side` | `OrderSide` | The order side to count (listing or offer) | | `params.filter` | `OrdersFilter` | Optional filter for the orders | | `params.query` | `StandardQueryOptions` | Optional React Query configuration (from TanStack Query) | ## Returns Query result containing a number of filtered orders in a collection ## Import ```typescript theme={null} import { useGetCountOfFilteredOrders } from "@0xsequence/marketplace-sdk/react"; ``` ## Example Basic usage: ```typescript theme={null} const { data: countOfOrders } = useGetCountOfFilteredOrders({ chainId, collectionAddress, side: OrderSide.listing, filter: { searchText, properties: filterOptions, } }); ``` # useGetCountOfPrimarySaleItems Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-data/useGetCountOfPrimarySaleItems The useGetCountOfPrimarySaleItems hook returns the number of filtered primary sale items in a collection ## Parameters | Name | Type | Description | | -------------------------- | ---------------------- | -------------------------------------------------------- | | `params.chainId` | `number` | The chain ID (e.g., 1 for Ethereum, 137 for Polygon) | | `params.collectionAddress` | `string` | The collection contract address | | `params.config` | `SdkConfig` | Optional SDK configuration parameters | | `params.side` | `OrderSide` | The order side to count (listing or offer) | | `params.filter` | `OrdersFilter` | Optional filter for the orders | | `params.query` | `StandardQueryOptions` | Optional React Query configuration (from TanStack Query) | ## Returns A query result containing an object with a `count` property representing the number of filtered primary sale items in a collection. ## Import ```typescript theme={null} import { useGetCountOfPrimarySaleItems } from "@0xsequence/marketplace-sdk/react"; ``` ## Example Basic usage: ```typescript theme={null} const { data: countOfPrimarySalesItems } = useGetCountOfPrimarySaleItems({ chainId: 1, primarySaleContractAddress: "0x00" }); console.log(countOfPrimarySalesItems?.count); ``` # useHighestOffer Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-data/useHighestOffer Hook to fetch the highest offer for a collectible Retrieves the highest offer currently available for a specific token in a collection from the marketplace ## Parameters | Name | Type | Description | | -------------------------- | ---------------------- | ---------------------------------------------------------------------- | | `params.chainId` | `number` | The chain ID (must be a number, e.g., 1 for Ethereum, 137 for Polygon) | | `params.collectionAddress` | `string` | The collection contract address | | `params.tokenId` | `string` | The token ID within the collection | | `params.filter` | `OrderFilter` | Optional filter for orders | | `params.query` | `StandardQueryOptions` | Optional React Query configuration (from TanStack Query) | ## Returns Query result containing the highest offer data or null if no offers exist ## Example Basic usage: ```typescript theme={null} const { data, isLoading } = useHighestOffer({ chainId: 137, collectionAddress: '0x...', tokenId: '1' }); ``` With custom query options: ```typescript theme={null} const hasTokenId = true; const { data, isLoading } = useHighestOffer({ chainId: 1, collectionAddress: '0x...', tokenId: '42', query: { refetchInterval: 15000, enabled: hasTokenId } }); ``` # useInventory Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-data/useInventory Fetches a user's collectible inventory for a specific collection with infinite scroll This hook combines data from both the marketplace API and indexer to provide a complete view of owned collectibles. It automatically detects LAOS ERC-721 collections and handles them appropriately. The hook ensures all owned tokens are returned, even if they're not listed in the marketplace. ## Parameters | Name | Type | Description | | ------ | ---- | ------------------------------------------------------------ | | `args` | | Configuration for inventory fetching | | `args` | | .accountAddress - The wallet address to fetch inventory for | | `args` | | .collectionAddress - The collection contract address | | `args` | | .chainId - The blockchain network ID | | `args` | | .query - Optional query configuration | | `args` | | .query.enabled - Whether to enable the query (default: true) | ## Returns returns.isFetchingNextPage - True while fetching next page ## Example Basic usage with pagination: ```typescript theme={null} const { data, fetchNextPage, hasNextPage, isLoading } = useInventory({ accountAddress: '0x...', collectionAddress: '0x...', chainId: 137 }); const allCollectibles = data?.pages.flatMap(page => page.collectibles) ?? []; return (
{allCollectibles.map(item => ( ))} {hasNextPage && ( )}
); ``` With filtering and balance display: ```typescript theme={null} const { data } = useInventory({ accountAddress: userAddress, collectionAddress: collection.address, chainId: collection.chainId, query: { enabled: !!userAddress && isConnected } }); // Get all items across pages const inventory = data?.pages.flatMap(p => p.collectibles) ?? []; // Show ERC1155 balances inventory.forEach(item => { if (item.contractType === ContractType.ERC1155) { console.log(`Token ${item.metadata.tokenId}: ${item.balance} owned`); } }); ``` ## Basic Usage ```typescript theme={null} import { useInventory } from '@0xsequence/marketplace-sdk/react/hooks'; const result = useInventory({ // Add your parameters here }); ``` # useListCollectibles Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-data/useListCollectibles The useListCollectibles hook retrieves the current listings and offers in a collection from your Marketplace. Useful for accessing and managing listings and offers efficiently. ```ts theme={null} import { OrderSide } from '@0xsequence/marketplace-sdk'; import { useListCollectibles } from '@0xsequence/marketplace-sdk/react'; ## Into your React component: const { data: collectibles, isLoading: collectiblesLoading, fetchNextPage: fetchNextCollectibles, } = useListCollectibles({ chainId, collectionAddress, filter: { // # Optional filters includeEmpty, searchText, properties, }, side: OrderSide.listing, }); const collectiblesFlat = collectibles?.pages.flatMap((p) => p.collectibles) ?? []; return (
{collectiblesFlat?.map((collectible) => ( // Your Collectibles component ))}
); ``` ```ts theme={null} interface UseListCollectiblesArgs { chainId: string; side: OrderSide; collectionAddress: `0x${string}`; page?: { page: number; pageSize: number; sort?: { order: SortOrder$1; column: string; }[]; more?: boolean; }; filter?: { includeEmpty: boolean; searchText?: string; properties?: { type: PropertyType; name: string; values?: any[]; max?: number; min?: number; }[]; marketplaces?: MarketplaceKind[]; inAccounts?: string[]; notInAccounts?: string[]; ordersCreatedBy?: string[]; ordersNotCreatedBy?: string[]; }; query?: { enabled?: boolean; }; } ``` Contains the paginated collectible orders data. List of collectible orders returned in pages. Indicates whether the data is currently loading. This function allows you to fetch the next "page" of results. # useListCollectiblesPaginated Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-data/useListCollectiblesPaginated The useListCollectiblesPaginated hook efficiently retrieves and manages current listings and offers from your Marketplace, making it ideal for displaying paginated NFTs within a collection. ```ts theme={null} import { OrderSide } from '@0xsequence/marketplace-sdk'; import { useListCollectiblesPaginated } from '@0xsequence/marketplace-sdk/react'; const chainId = 137; const searchText = ""; const enabled = true; const includeEmpty = true; const properties = []; const pageSize = 30; const currentPage = 1; const collectionAddress = "0x0e5566a108e617baedbebb44e3fcc7bf03e3a839"; ## Into your React component: const { data: collectiblesResponse, isLoading: collectiblesLoading, } = useListCollectiblesPaginated({ chainId: String(chainId), collectionAddress, side: OrderSide.listing, filter: { // # Optional filters includeEmpty, searchText, properties, }, page: { page: currentPage, pageSize, }, query: { page: currentPage, pageSize, enabled, }, }); const collectiblesList = collectiblesResponse?.collectibles ?? []; return (
{collectiblesList?.map((collectible) => ( // Your Collectibles component ))}
); ``` ```ts theme={null} interface UseListCollectiblesPaginatedArgs { chainId: string; side: OrderSide; collectionAddress: `0x${string}`; page?: { page: number; pageSize: number; sort?: { order: SortOrder$1; column: string; }[]; more?: boolean; }; filter?: { includeEmpty: boolean; searchText?: string; properties?: { type: PropertyType; name: string; values?: any[]; max?: number; min?: number; }[]; marketplaces?: MarketplaceKind[]; inAccounts?: string[]; notInAccounts?: string[]; ordersCreatedBy?: string[]; ordersNotCreatedBy?: string[]; }; query: { page: number; pageSize: number; enabled?: boolean; }; } ``` Contains the collectible orders data. List of collectible orders. Indicates whether the data is currently loading. # useListCollections Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-data/useListCollections Hook to fetch collections from marketplace configuration Retrieves all collections configured in the marketplace, with optional filtering by marketplace type. Combines metadata from the metadata API with marketplace configuration to provide complete collection information. ## Parameters | Name | Type | Description | | -------------------------- | ------------------- | --------------------------------------------- | | `params.config` | `SdkConfig` | Optional configuration parameters | | `params.marketplaceConfig` | `MarketplaceConfig` | Optional Marketplace configuration parameters | | `params.cardType` | `CardType` | Optional filter by marketplace type | | `params.query` | `any` | Optional React Query configuration | ## Returns Query result containing an array of collections with metadata configured in Sequence Builder ## Import ```typescript theme={null} import { useCollection } from "@0xsequence/marketplace-sdk/react"; ``` ## Example Basic usage: ```typescript theme={null} const { data: collections, isLoading } = useListCollections(); if (isLoading) return
Loading collections...
; return (
{collections?.map(collection => (
{collection.name}
))}
); ``` Filtering by marketplace type: ```typescript theme={null} const { data: marketCollections } = useListCollections({ cardType: 'market' }); ``` # useListListingsForCollectible Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-data/useListListingsForCollectible Hook to fetch listings for a specific collectible Fetches active listings (sales) for a specific token from the marketplace with support for filtering and pagination. ## Parameters | Name | Type | Description | | -------- | ---- | ------------------------------------------------------------------------------- | | `params` | | Configuration parameters | | `params` | | .chainId - The chain ID (must be number, e.g., 1 for Ethereum, 137 for Polygon) | | `params` | | .collectionAddress - The collection contract address | | `params` | | .collectibleId - The specific token ID to fetch listings for | | `params` | | .filter - Optional filtering parameters (marketplace, currencies, etc.) | | `params` | | .page - Optional pagination parameters | | `params` | | .query - Optional React Query configuration | ## Returns Query result containing listings data for the collectible ## Example Basic usage: ```typescript theme={null} const { data, isLoading } = useListListingsForCollectible({ chainId: 137, collectionAddress: '0x...', collectibleId: '123' }) ``` With pagination: ```typescript theme={null} const { data } = useListListingsForCollectible({ chainId: 1, collectionAddress: '0x...', collectibleId: '456', page: { page: 2, pageSize: 20 } }) ``` With filtering: ```typescript theme={null} const { data } = useListListingsForCollectible({ chainId: 137, collectionAddress: '0x...', collectibleId: '789', filter: { marketplace: [MarketplaceKind.sequence_marketplace_v2], currencies: ['0x...'] // Specific currency addresses } }) ``` ## Basic Usage ```typescript theme={null} import { useListListingsForCollectible } from '@0xsequence/marketplace-sdk/react/hooks'; const result = useListListingsForCollectible({ // Add your parameters here }); ``` # useListOffersForCollectible Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-data/useListOffersForCollectible Fetches all offers for a specific collectible This hook retrieves a list of active offers made on a specific collectible, including offer details like price, expiry, and maker information. Results can be filtered and paginated as needed. ## Parameters | Name | Type | Description | | ------ | ---- | ---------------------------------------------------- | | `args` | | Configuration for fetching offers | | `args` | | .chainId - The blockchain network ID | | `args` | | .collectionAddress - The collection contract address | | `args` | | .collectibleId - The specific token ID | | `args` | | .filter - Optional filter for offers | | `args` | | .page - Optional pagination configuration | ## Returns returns.error - Error object if fetching fails Make sure you have followed the [Getting Started](https://docs.sequence.xyz/sdk/web/marketplace-sdk/getting-started) guide to get the collection address and chainId. ## Example Basic usage: ```typescript theme={null} const { data: marketplaceConfig, isLoading: isMarketplaceConfigLoading } = useMarketplaceConfig(); const collection = marketplaceConfig?.market.collections[0]; const chainId = collection?.chainId as number; const collectionAddress = collection?.itemsAddress as Address; const collectibleId = "0"; const { data, isLoading } = useListOffersForCollectible({ chainId, collectionAddress, collectibleId, }); if (isLoading) return
Loading offers...
; return (

{data?.offers.length || 0} offers

{data?.offers.map((offer) => ( ))}
); ``` With sorting and pagination: ```typescript theme={null} const { data } = useListOffersForCollectible({ chainId: 1, collectionAddress: collectionAddress, collectibleId: tokenId, page: { page: 1, pageSize: 20, }, sort:[{column: "price_usd", order: SortOrder.DESC}] }); // Show highest offers first const topOffers = data?.offers.slice(0, 3); ``` Checking for user's offers: ```typescript theme={null} const { address } = useAccount(); const { data } = useListOffersForCollectible({ chainId, collectionAddress, collectibleId, filter: { createdBy: [String(userAddress)], }, }); const hasUserOffer = (data?.offers.length || 0) > 0; ``` # useListPrimarySaleItems Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-data/useListPrimarySaleItems Hook for fetching paginated primary sale items ## Import ```tsx theme={null} import { useListPrimarySaleItems } from "@0xsequence/marketplace-sdk"; ``` ## Usage ```tsx theme={null} import { useListPrimarySaleItems } from "@0xsequence/marketplace-sdk"; function App() { const { data, isLoading, hasNextPage, fetchNextPage, isFetchingNextPage } = useListPrimarySaleItems({ chainId: 137, primarySaleContractAddress: "0x123...", page: { pageSize: 20, }, }); if (isLoading) { return
Loading...
; } return (
{data?.pages.map((page, i) => (
{page.items.map((item) => (
{item.name} - {item.price}
))}
))} {hasNextPage && ( )}
); } ``` ## Return Type: `UseInfiniteQueryResult` The hook returns a React Query infinite query result object with the following key properties: ```tsx theme={null} type UseInfiniteQueryResult = { data: { pages: Array<{ items: PrimarySaleItem[]; nextCursor?: string; }>; pageParams: unknown[]; }; isLoading: boolean; error: Error | null; hasNextPage: boolean; fetchNextPage: () => Promise; isFetchingNextPage: boolean; // ... other React Query infinite query properties }; ``` ### Parameters | Parameter | Type | Description | | ---------------------------- | -------- | ---------------------------------------------------- | | `chainId` | `number` | The chain ID (e.g., 1 for Ethereum, 137 for Polygon) | | `primarySaleContractAddress` | `string` | The primary sale contract address | | `filter` | `object` | (Optional) Filter parameters for the query | | `filter.status` | `string` | (Optional) Filter by item status (e.g., 'active') | | `page` | `object` | (Optional) Pagination configuration | | `page.pageSize` | `number` | (Optional) Number of items per page | | `query` | `object` | (Optional) React Query configuration options | | `config` | `object` | (Optional) SDK configuration options | ### Query Options You can customize the query behavior using the optional parameters: ```tsx theme={null} const { data, isLoading } = useListPrimarySaleItems({ chainId: 1, primarySaleContractAddress: "0x...", filter: { status: "active", }, page: { pageSize: 20, }, query: { enabled: isReady, refetchInterval: 30000, // Refetch every 30 seconds }, }); ``` ## Notes This hook is useful for: * Displaying a list of primary sale items with infinite scroll * Building marketplace primary sale pages * Showing available items for initial sale * Managing paginated data loading The hook automatically handles: * Infinite scrolling pagination * Data fetching and caching * Loading and error states * Type-safe responses Make sure to handle the loading states appropriately, especially `isFetchingNextPage` when implementing infinite scroll functionality. The `primarySaleContractAddress` must be a valid contract address that supports primary sales. Invalid addresses will result in failed queries. # useLowestListing Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-data/useLowestListing Hook for fetching the lowest priced listing for a collectible ## Import ```tsx theme={null} import { useLowestListing } from "@0xsequence/marketplace-sdk"; ``` ## Usage ```tsx theme={null} import { useLowestListing } from "@0xsequence/marketplace-sdk"; function App() { const { data, isLoading } = useLowestListing({ chainId: 137, collectionAddress: "0x123...", tokenId: "1", }); if (isLoading) { return
Loading...
; } return (
{data ? (
Lowest price: {data.price}
) : (
No listings available
)}
); } ``` ## Return Type: `UseQueryResult` The hook returns a React Query result object with the following key properties: ```tsx theme={null} type UseQueryResult = { data: LowestListingData | null; isLoading: boolean; error: Error | null; // ... other React Query properties }; ``` ### Parameters | Parameter | Type | Description | | ------------------- | -------- | ---------------------------------------------------- | | `chainId` | `number` | The chain ID (e.g., 1 for Ethereum, 137 for Polygon) | | `collectionAddress` | `string` | The collection contract address | | `tokenId` | `string` | The token ID within the collection | | `query` | `object` | (Optional) React Query configuration options | | `config` | `object` | (Optional) SDK configuration options | ### Query Options You can customize the query behavior using the optional `query` parameter: ```tsx theme={null} const { data, isLoading } = useLowestListing({ chainId: 1, collectionAddress: "0x...", tokenId: "42", query: { refetchInterval: 15000, // Refetch every 15 seconds enabled: hasTokenId, // Only run query when tokenId is available // ... other React Query options }, }); ``` ## Notes This hook is useful for: * Displaying the current lowest price for a specific Collectible * Building price comparison features The hook automatically handles: * Data fetching and caching * Loading and error states * Type-safe responses Make sure to provide valid chain IDs and contract addresses. Invalid parameters will result in failed queries. # useMarketCurrencies Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-data/useMarketCurrencies The useMarketCurrencies hook retrieves the list of currencies accepted by a specific contract address in your Marketplace from Builder. Each currency includes information such as its name, contractAddress, symbol, decimals, and image. ```typescript theme={null} import { useMarketCurrencies } from "@0xsequence/marketplace-sdk/react"; ## Into your React component: const { data: currenciesData } = useMarketCurrencies({ chainId: 137, collectionAddress: "0x0e5566a108e617baedbebb44e3fcc7bf03e3a839", includeNativeCurrency: true, query: { enabled: true, }, }); console.log(currenciesData); ``` ```typescript theme={null} interface UseMarketCurrenciesArgs { chainId: number; includeNativeCurrency?: boolean; collectionAddress?: Address; query?: { enabled?: boolean; }; } ``` Contains the marketplace currencies data. Indicates whether the data is currently loading. # useMarketplaceConfig Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/hooks/marketplace-data/useMarketplaceConfig The useMarketplaceConfig hook retrieves your Marketplace's configuration, including collections, social links, title, and other settings from Builder. ```ts theme={null} import { useMarketplaceConfig } from "@0xsequence/marketplace-sdk/react"; ## Into your React component: const data = useMarketplaceConfig(); ``` Unique identifier of the marketplace publisher. The title of the marketplace. A brief description of the marketplace. Social media links associated with the marketplace. URL of the marketplace's favicon. URL of the Marketplace banner for landing page Array of collections from the marketplace. Configuration options for wallet integrations. Layout configuration for the marketplace's landing page. URL of the marketplace's logo. URL of the marketplace's banner. URL of the custom font used in the marketplace. URL of the ogImage Custom CSS styles for the marketplace. URL of the marketplace manifest file. # Marketplace SDK Source: https://docs.sequence.xyz/sdk/web/marketplace-sdk/overview Marketplace SDK is a comprehensive toolkit that seamlessly integrates our Marketplaces into applications. [`@0xsequence/marketplace-sdk`](https://www.npmjs.com/package/@0xsequence/marketplace-sdk) helps you integrate NFT marketplaces into your applications. It supports both NFTs (ERC721) and Semi-Fungible Tokens (ERC1155), providing a simple interface to work with Sequence marketplace. Key features: * Simple and intuitive marketplace API * Create and manage NFT listings and offers * Track marketplace activities and orders * Ready-to-use React hooks and components * Built with TypeScript * Optimized data fetching with React Query and Wagmi Ready to start? Check out our [Getting Started](/sdk/web/marketplace-sdk/getting-started) guide. # useProjectAccessKey Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/ecosystem/hooks/useProjectAccessKey Hook to access the project access key from the Sequence Connect configuration ## Import ```tsx theme={null} import { useProjectAccessKey } from '@0xsequence/connect' ``` ## Usage ```tsx theme={null} import { useProjectAccessKey } from '@0xsequence/connect' function App() { const projectAccessKey = useProjectAccessKey() return (
{projectAccessKey && (

Project access key is configured

)}
) } ``` ## Return Type The hook returns a string value: ```tsx theme={null} string ``` ### Return Value #### projectAccessKey `string` The project access key configured for the application. This key is used to authenticate and identify your application with Sequence services. **Description:** The project access key is a required configuration parameter that: * Authenticates your application with Sequence services * Identifies your specific project/application * Enables access to various SDK features including marketplace integration and wallet connections * Must be provided during the initial configuration of the Sequence Connect context **Example Usage:** ```tsx theme={null} // Using with marketplace integration const projectAccessKey = useProjectAccessKey() const marketplaceClient = new MarketplaceIndexer(apiUrl, projectAccessKey) ``` ## Notes This hook provides access to the project access key that was configured when setting up the Sequence Connect context. The project access key is essential for: * **Authentication**: Verifying your application's identity with Sequence services * **Authorization**: Determining what features and resources your application can access * **Billing**: Associating usage with your specific project for billing purposes * **Rate Limiting**: Managing API rate limits per project # useSequenceSessionState Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/ecosystem/hooks/useSequenceSessionState Hook to access Sequence session state and wallet information ## Import ```tsx theme={null} import { useSequenceSessionState } from '@0xsequence/connect' ``` ## Usage ```tsx theme={null} import { useSequenceSessionState } from '@0xsequence/connect' function App() { const sessionState = useSequenceSessionState() // Check if sessions are initialized if (!sessionState.isInitialized) { return
Session state is not initialized
} return (

Wallet: {sessionState.walletAddress}

Login Method: {sessionState.loginMethod}

User Email: {sessionState.userEmail}

Number of active explicit sessions: {sessionState.sessions.filter(s => s.type === 'explicit').length}

) } ``` ## Return Type: `SessionState` The hook returns an object with the following properties: ```tsx theme={null} interface SessionState { isInitialized: boolean walletAddress: `0x${string}` | null sessions: Session[] loginMethod: string | null userEmail: string | null } ``` ### Properties #### isInitialized `boolean` Indicates whether the Sequence session has been initialized. This is useful for determining when the session data is ready to be used. #### walletAddress `\`0x\$\` | null\` The current wallet address if connected, or `null` if no wallet is connected. #### sessions `Session[]` Array of all active sessions. Each session contains information about the connection type and permissions. #### loginMethod `string | null` The method used to log in (e.g., 'email', 'social', etc.) or `null` if not logged in. #### userEmail `string | null` The email address associated with the current session, or `null` if not available. ## Example: Checking Session Initialization ```tsx theme={null} import { useSequenceSessionState } from '@0xsequence/connect' function SessionStatus() { const sessionState = useSequenceSessionState() // Wait for initialization before using session data if (!sessionState.isInitialized) { return
Loading session...
} // Check if user has any sessions const hasSessions = sessionState.sessions.length > 0 const hasImplicitSession = sessionState.sessions.some(s => s.type === 'implicit') const hasExplicitSession = sessionState.sessions.some(s => s.type === 'explicit') return (

Session Status

Initialized: {sessionState.isInitialized ? 'Yes' : 'No'}

Wallet: {sessionState.walletAddress || 'Not connected'}

Has Sessions: {hasSessions ? 'Yes' : 'No'}

Has Implicit Session: {hasImplicitSession ? 'Yes' : 'No'}

Has Explicit Session: {hasExplicitSession ? 'Yes' : 'No'}

Login Method: {sessionState.loginMethod || 'Unknown'}

User Email: {sessionState.userEmail || 'Not available'}

) } ``` ## Notes This hook provides real-time access to Sequence session state and automatically updates when session information changes. It's particularly useful for: * Checking if the session is ready before performing operations * Accessing wallet connection status * Monitoring active sessions and their types * Getting user authentication information The hook automatically subscribes to session updates and will re-render your component when the session state changes. # useWallets Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/ecosystem/hooks/useWallets Hook for managing connected wallets ## Features This hook provides a unified interface for managing connected wallets, both embedded (WaaS) and external wallets. The user is prompted to sign a transaction with their active wallet in order to link wallets enabling read-only functionality. Key features: * Get information about all connected wallets * Set a specific wallet as active * Disconnect wallets * View linked wallets for embedded wallets * Refresh the list of linked wallets For embedded wallets (Wallet-as-a-Service), the hook automatically fetches linked wallets if available. Linked wallets are additional wallets that have been connected to the primary embedded wallet. ## Import ```tsx theme={null} import { useWallets } from '@0xsequence/connect' ``` ## Usage ```tsx theme={null} import { useWallets } from '@0xsequence/connect' function App() { const { wallets, linkedWallets, setActiveWallet, disconnectWallet, refetchLinkedWallets } = useWallets() return (

Connected Wallets

{wallets.map(wallet => (
{wallet.name}: {wallet.address.slice(0, 6)}...{wallet.address.slice(-4)} {wallet.isActive ? ' (Active)' : ''} {wallet.isEmbedded ? ' (Embedded)' : ''}
))}
{linkedWallets && linkedWallets.length > 0 && ( <>

Linked Wallets

{linkedWallets.map(linkedWallet => (
{linkedWallet.walletAddress.slice(0, 6)}...{linkedWallet.walletAddress.slice(-4)}
))}
)}
) } ``` ## Return Type: `UseWalletsReturnType` The hook returns an object with the following properties: ```tsx theme={null} interface UseWalletsReturnType { wallets: ConnectedWallet[] linkedWallets: LinkedWallet[] | undefined setActiveWallet: (address: string) => Promise disconnectWallet: (address: string) => Promise refetchLinkedWallets: () => Promise } ``` ### Properties #### wallets `ConnectedWallet[]` Array of all connected wallets. ```tsx theme={null} interface ConnectedWallet { id: string // Unique identifier for the wallet (connector id) name: string // Display name of the wallet address: string // The wallet's Ethereum address isActive: boolean // Whether this wallet is currently active isEmbedded: boolean // Whether this is an embedded wallet (WaaS) signInMethod: string // Login method for this wallet } ``` #### linkedWallets `LinkedWallet[] | undefined` Array of linked wallets for the active embedded wallet (if any). Only available when using a WaaS wallet. ```tsx theme={null} interface LinkedWallet { id: number; walletType?: string; walletAddress: string; linkedWalletAddress: string; createdAt?: string; } ``` #### setActiveWallet `(address: string) => Promise` Function to set a wallet as active by its address. | Parameter | Type | Description | | --------- | -------- | --------------------------------------------------- | | `address` | `string` | The Ethereum address of the wallet to set as active | #### disconnectWallet `(address: string) => Promise` Function to disconnect a wallet by its address. | Parameter | Type | Description | | --------- | -------- | ------------------------------------------------ | | `address` | `string` | The Ethereum address of the wallet to disconnect | #### refetchLinkedWallets `() => Promise` Function to refresh the list of linked wallets. Useful after linking a new wallet. # Custom Configuration Options Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/embedded/custom-configuration The Configuration section allows developers to customize the Web SDK by passing options to the `SequenceConnect` wrapper. Developers can customize the Web SDK experience by passing configuration options to the `SequenceConnect` wrapper. Here's how you can configure the kit using these options: ```jsx theme={null} const connectConfig = { defaultTheme: 'light', position: 'top-left', ... } ``` ## Configuration Overview The following is the available configuration customization options, or, [see below for all the options in-depth](/sdk/web/wallet-sdk/embedded/custom-configuration#available-options): ```typescript theme={null} interface CreateConfigOptions { appName: string projectAccessKey: string chainIds?: number[] defaultChainId?: number disableAnalytics?: boolean defaultTheme?: Theme position?: ModalPosition signIn?: { logoUrl?: string projectName?: string useMock?: boolean } displayedAssets?: Array<{ contractAddress: string chainId: number }> ethAuth?: EthAuthSettings wagmiConfig?: WagmiConfig // optional wagmiConfig overrides waasConfigKey: string enableConfirmationModal?: boolean walletConnect?: | boolean | { projectId: string } google?: | boolean | { clientId: string } apple?: | boolean | { clientId: string rediretURI: string } email?: | boolean | { legacyEmailAuth?: boolean } X?: | boolean | { clientId: string redirectURI: string } guest?: boolean additionalWallets?: any[] } ``` ## Custom Styling and Design You can customize the visual appearance of Web SDK connect modal by providing a custom theme object to the `defaultTheme` configuration option. Here's an example of how to implement custom styling: ```typescript theme={null} import { createConfig } from "@0xsequence/connect"; const CUSTOM_THEME = { backgroundPrimary: "rgba(35, 100, 32, 1)", backgroundSecondary: "navy", }; export const config = createConfig("waas", { projectAccessKey: projectAccessKey, defaultTheme: CUSTOM_THEME, // ... other config options }); ``` ### Available Theme Variables The following theme variables can be customized: ```typescript theme={null} // Text Colors text100: string; // 'rgba(255, 255, 255, 1)' text80: string; // 'rgba(255, 255, 255, 0.8)' text50: string; // 'rgba(255, 255, 255, 0.5)' textInverse100: string; // 'rgba(0, 0, 0, 1)' // Background Colors backgroundPrimary: string; // 'rgba(0, 0, 0, 1)' backgroundSecondary: string; // 'rgba(255, 255, 255, 0.1)' backgroundContrast: string; // 'rgba(0, 0, 0, 0.5)' backgroundMuted: string; // 'rgba(255, 255, 255, 0.05)' backgroundControl: string; // 'rgba(255, 255, 255, 0.25)' backgroundInverse: string; // 'rgba(255, 255, 255, 1)' backgroundBackdrop: string; // 'rgba(34, 34, 34, 0.9)' backgroundOverlay: string; // 'rgba(0, 0, 0, 0.7)' backgroundRaised: string; // 'rgba(54, 54, 54, 0.7)' // Button Colors buttonGlass: string; // 'rgba(255, 255, 255, 0.15)' buttonEmphasis: string; // 'rgba(0, 0, 0, 0.5)' buttonInverse: string; // 'rgba(255, 255, 255, 0.8)' // Border Colors borderNormal: string; // 'rgba(255, 255, 255, 0.25)' borderFocus: string; // 'rgba(255, 255, 255, 0.5)' ``` You can override any combination of these variables to create your custom theme. The values can be provided in any valid CSS color format (rgba, hex, named colors, etc.). # Available Options ## Sequence App Development ### `appName` | Type | Default | | ------ | --------- | | string | undefined | An internal software naming value that is not presented to the user. ### `projectAccessKey` | Type | Default | | ------ | --------- | | string | undefined | The project access key that is required, obtained from [Sequence Builder](https://sequence.build) ### `ethAuth` as EthAuthSettings ```typescript theme={null} { /*app name*/ app?: string /** expiry number (in seconds) that is used for ETHAuth proof. Default is 1 week in seconds. */ expiry?: number /** origin hint of the dapp's host opening the wallet. This value will automatically * be determined and verified for integrity, and can be omitted. */ origin?: string /** nonce is an optional number to be passed as ETHAuth's nonce claim for replay protection. **/ nonce?: number } ``` ### `waasConfigKey` | Type | Default | | ------ | --------- | | string | undefined | The Embedded Wallet configuration key required for WaaS wallets, configured within the [Sequence Builder](https://sequence.build). ## Network ### `chainIds` | Type | Default | | --------- | --------- | | number\[] | undefined | A list of chain Ids. e.g. \[1, 137] ### `defaultChainId` | Type | Default | | ------ | --------- | | number | undefined | The chain Id that is first used for signatures and transactions. ## UI User Interface based parameters that augment the modal interface. ### Sign In Modal Configuration (`signIn`) The `signIn` object is used to configure the sign in modal. #### `signIn.logoUrl` Enable a dark theme to Web SDK | Type | Default | | ------ | --------- | | string | undefined | URL of the logo to be shown in the sign in modal. #### `signIn.projectName` Add a project name to Web SDK | Type | Default | | ------ | --------- | | string | undefined | Name of the project to be shown in the sign in modal. #### `signIn.useMock` | Type | Default | | ------- | --------- | | boolean | undefined | Removes the ability to make live blockchain requests if set to `true` by using the [wagmi mock connector](https://wagmi.sh/core/api/connectors/mock#mock) ### `position` | Type | Default | | ------ | ------- | | string | center | The position parameter determines the location of the various modals on the screen. Possible values include: * center * middle-right * middle-left * top-center * top-right * top-left * bottom-center * bottom-right * bottom-left ### `defaultTheme` | Type | Default | | ---------------- | ------- | | string or object | dark | The defaultTheme determines the color palette used for styling the modal. Possible values include: * 'light' * 'dark' * object Specific colors can be overwritten by passing a theme override object. The [Sequence Builder](https://sequence.build/) provides a useful playground for toying with the colors in Web SDK. ## Wallet Parameters that entail wallet configuration options ### `disableAnalytics` | Type | Default | | ------- | --------- | | boolean | undefined | Turning on and off the analytics feature that is connected to your [Sequence Builder](http://sequence.build) project. ### `displayedAssets` | Type | Default | | ----------------------------------------------------- | --------- | | \[\{ contractAddress: string, chainId: number }, ...] | undefined | If provided, this will determine which assets are to be displayed in the in-game wallet modal main view. By passing a list of displayed assets, only assets from the provided list will be displayed in the main view. In the case that no assets are provided, all owned assets can be displayed in the main view. ### `enableConfirmationModal` | Type | Default | | ------- | --------- | | boolean | undefined | Enable confirmations for when sending transaction ## Sign in providers The various sign in providers that create wallet connections for the user: ### `walletConnect` | Type | Default | | ---------------------------------- | ----------- | | `false` \| `{ projectId: string }` | `undefined` | ### `google` | Type | Default | | --------------------------------- | ----------- | | `false` \| `{ clientId: string }` | `undefined` | ### `apple` | Type | Default | | ------------------------------------------------------ | ----------- | | `false` \| `{ clientId: string, redirectURI: string }` | `undefined` | ### `email` | Type | Default | | ------------------------------------------- | ----------- | | `boolean` \| `{ legacyEmailAuth: boolean }` | `undefined` | # Create Universal Default Connectors While we generally recommed using Embedded Wallets with SequenceKit, as an alternative, you can also use leverage our Universal Wallet configuration. When creating a wagmi `connectors` variable, import the `getDefaultConnectors` function from the `@0xsequence/kit` package, and include a Wallet Connect ID obtained from [here](https://cloud.walletconnect.com/app), a default chain ID, app name, and the `projectAccessKey`, then [continue with the integration from the quickstart](/sdk/web/wallet-sdk/embedded/getting-started). ```typescript [config.ts] theme={null} import { getDefaultConnectors } from '@0xsequence/kit' ... export const projectAccessKey = '' const connectors = getDefaultConnectors( "universal", { walletConnectProjectId: 'wallet-connect-id', defaultChainId: 1, appName: 'demo app', projectAccessKey }) export const config = createConfig({ transports, connectors, chains }) ``` # Custom Connectors in Web SDK Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/embedded/custom-connectors Learn how to create and integrate custom connectors with Web SDK. Follow step-by-step instructions to build your own connector using existing templates. Web SDK provides official connectors via the [@0xsequence/connect-connectors](https://github.com/0xsequence/web-sdk/tree/master/packages/connect/src/connectors) package. However, you can also integrate custom connectors with Web SDK to support additional wallets. This guide will walk you through creating and using custom connectors. ## Creating a Custom Connector To create a custom connector, you can use an existing connector as a basis. For example, the [Metamask Connector](https://github.com/0xsequence/web-sdk/tree/master/packages/connect/src/connectors/metaMask) is a good starting point. Here's an example of how to create a custom connector: ```tsx theme={null} export const myCustomConnector = (options: MyCustomConnectorOptions) => ({ id: 'my-custom-connector', name: 'My Custom Connector', logoDark: MyCustomLogoDark, logoLight: MyCustomLogoLight, createConnector: () => { const connector = myCustomConnector(options); return connector; }, }); ``` Make sure to provide a unique `id` for your connector to avoid conflicts with other connectors. You can also customize fields such as `name`, `logoDark`, and `logoLight` to control how the connector appears in Web SDK. The `createConnector` function from wagmi should return an initialized connector. Web SDK connectors are wrappers of Wagmi connectors, so you can use an official Wagmi connector if available, or create your own if needed. For more details on creating custom connectors, refer to [Wagmi's guide on Custom Connectors](https://wagmi.sh/examples/custom-connector). # Using Custom Connectors When using custom connectors, you can't rely on the `getDefaultConnectors` utility function. Instead, you need to pass custom configurations to Web SDK. First, create a list of connectors, including your custom connector, and provide it to the Wagmi configuration: ```tsx theme={null} import { getConnectWallets } from '@0xsequence/connect'; import { createConfig } from 'wagmi'; const projectAccessKey = ''; const connectors = getConnectWallets(projectAccessKey, [ google({ defaultNetwork: 137, connect: { app: 'my-app', projectAccessKey: '' } }), // ... other connectors myCustomConnector({ appName: 'my-app' }), ]); const config = createConfig({ transports, connectors, chains }) ``` Next, use your custom connector by specifying its `id` in either the `socialAuthOptions` or `walletAuthOptions` field of the Web SDK configuration: ```tsx theme={null} const kitConfig = { signIn: { socialAuthOptions: ['google', 'facebook'], walletAuthOptions: ['metamask', 'my-custom-connector'], } }; return ( ); ``` # Share Your Custom Connectors Feel free to contribute your custom connectors by creating a [pull request](https://github.com/0xsequence/web-sdk/pulls). This way, others can benefit from your work and enjoy seamless integration with Sequence Web SDK's. Share the love ❤️ by expanding the ecosystem of custom connectors! # Ethers v6 Migration Guide Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/embedded/ethers-v6-migration Support for ethers v6 and migration guides for moving code from ethers v5 to v6 The @0xsequence package v2.0 now requires at a minimum the Ethers version `ethers`. If you are unable to upgrade to ethers v6, then you can use v1.10.5 of @0xsequence or 3.0.0 of @0xsequence/kit. If you've been developing with `ethers@^5.0.0` in the past, outlined below are the common ways using Ethers with Sequence will change for you: ## Static and Default RPC Provider To use ethers to connect and make [RPC](https://en.wikipedia.org/wiki/Remote_procedure_call) calls to a blockchain node in order to query information, doing so in a static or default way both have differences: ```typescript provider.ts theme={null} // v5 const provider = new ethers.providers.StaticJsonRpcProvider(chainConfig.rpcUrl); // v6: If you know the network ahead of time and wish // to avoid even a single eth_chainId call const provider = new ethers.JsonRpcProvider(chainConfig.rpcUrl, undefined, { staticNetwork: new ethers.Network('', ) }); // v6: If you want the network automatically detected, // this will query eth_chainId only once const provider = new ethers.JsonRpcProvider(chainConfig.rpcUrl, undefined, { staticNetwork: true }); ``` ## Big Number Support If you're using big numbers to generate randomly spaced token ID's, nonces, or some other application of large string based numbers, ethers now supports built-in ES2020 BigInt offered by modern JavaScript environments. ```typescript bigNumber.ts theme={null} // v5 value = BigNumber.from("1000") // v6 // Notice the suffix n (using literal notation). value = 1000n // v6 // Using the BigInt function for strings value = BigInt("1000") ``` ## Removal of Ethers Utilities Using Ethers you will notice there is no longer a `ethers.utils` path. Therefore, all paths should be updated without the `utils`: ```typescript contract_parameters.ts theme={null} // v5 const amountBigNumber = ethers.utils.parseUnits(String(price), 18); // currency price based on correct decimals for token contract const erc20Interface = new ethers.utils.Interface([ "function approve(address spender, uint256 amount) external returns (bool)" ]); // v6 const amountBigNumber = ethers.parseUnits(String(price), 18); // currency price based on correct decimals for token contract const erc20Interface = new ethers.Interface([ "function approve(address spender, uint256 amount) external returns (bool)" ]); ``` ## Utility Hash Value Packing If you're using ethers utilities to perform signature creation then using `ecrecover` on-chain, signature creation is now slightly different: ```typescript signature_creation.ts theme={null} // v5 const hash = ethers.utils.solidityKeccak256(['uint', 'uint'], [value1, blockNumber]) const arr = ethers.utils.arrayify(hash) const signature = await wallet.signMessage(arr) // v6 const hash = ethers.solidityPackedKeccak256(['uint', 'uint'], [value1, blockNumber]) const arr = ethers.getBytes(hash) const signature = await wallet.signMessage(arr) ``` For complete information on the differences of Ethers `v5` to `v6` you can read more [here](https://docs.ethers.org/v6/migrating/) in the official docs. # Getting Started with Web SDK for Embedded Wallet Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/embedded/getting-started Learn how to get started with Web SDK by installing the necessary packages and using the wagmi connectors to utilize an Embedded Wallet or Native EOA Wallet for authentication. # Setting Up your Dapp First make sure you have created a Sequence account, if you don't have one, you can create one [here](https://sequence.build/), you will need your `Project Access Key` and `Waas Config Key` in order to use the Web SDK. To utilize the `SequenceConnect` wrapper for connecting web3 wallets to your application, follow these steps: Web SDK is built on top of wagmi, so for advanced configurations, sending transactions, calling contracts, etc., please refer to the [wagmi documentation](https://wagmi.sh/react/WagmiConfig). We will start by creating a [React](https://react.dev/) project with [vite](https://vitejs.dev/): ```sh theme={null} npm create vite # or pnpm create vite # or yarn create vite ``` ```bash theme={null} npm install @0xsequence/connect @0xsequence/hooks wagmi ethers viem 0xsequence @tanstack/react-query # or pnpm install @0xsequence/connect @0xsequence/hooks wagmi ethers viem 0xsequence @tanstack/react-query # or yarn add @0xsequence/connect @0xsequence/hooks wagmi ethers viem 0xsequence @tanstack/react-query ``` Next, create the configuration. * If you want to allow WalletConnect you will also need a [walletConnectProjectId](https://cloud.reown.com/sign-in). * To setup Google Login follow the [Google Configuration for Embedded Wallet](../../../../solutions/builder/embedded-wallet/google-configuration). * To setup Apple Login follow the [Apple Configuration for Embedded Wallet](../../../../solutions/builder/embedded-wallet/apple-configuration). * To setup X (Twitter) Login follow the [X (Twitter) Configuration for Embedded Wallet](../../../../solutions/builder/embedded-wallet/x-configuration). * To setup Gues Mode follow the [Guest Mode Configuration for Embedded Wallet](../../../../solutions/builder/embedded-wallet/guest-wallet-configuration). ```typescript [config.ts] theme={null} import { createConfig } from "@0xsequence/connect"; // Waas config export const waasConfig: any = createConfig('waas', { projectAccessKey: "", defaultTheme: 'dark', signIn: { projectName: 'Sequence Web SDK Demo', }, appName: 'Sequence Web SDK Demo', chainIds: [1], defaultChainId: 1, waasConfigKey: 'waas-config-key', guest: true, email: true, google: { clientId 'your-google-client-id' }, apple: { clientId: 'your-apple-client-id', redirectURI: window.location.origin + window.location.pathname }, X: { clientId: 'MVZ6aHMyNmMtSF9mNHVldFR6TV86MTpjaQ', redirectURI: window.location.origin + '/auth-callback-X' }, walletConnect: { projectId: walletConnectProjectId }, }); // Universal config export const universalConfig: any = createConfig('universal', { projectAccessKey: "", defaultTheme: 'dark', signIn: { projectName: 'Sequence Web SDK Demo', }, appName: 'Sequence Web SDK Demo', chainIds: [1], defaultChainId: 1, walletConnect: { projectId: walletConnectProjectId } }) ``` In order to customize further, [you can view additional configuration parameters.](/sdk/web/wallet-sdk/embedded/custom-configuration) The configuration we created in [step 3](/sdk/web/wallet-sdk/embedded/getting-started#create-a-config) needs to be passed into the providers below in the `main.tsx`. ```typescript [main.tsx] theme={null} import React from "react"; import ReactDOM from "react-dom/client"; import "./index.css"; import App from "./App"; import { config } from "./config"; import { SequenceConnect } from "@0xsequence/connect"; function Dapp() { return ( ); } ReactDOM.createRoot(document.getElementById("root")!).render( ); ``` ```typescript [App.tsx] theme={null} import './App.css' import { useOpenConnectModal } from '@0xsequence/connect' function App() { const {setOpenConnectModal} = useOpenConnectModal() return ( <> ) } export default App ``` For web3 interactions, wagmi exposes a set of React hooks that make it convenient for common functions like sending transactions. ```bash theme={null} npm install @0xsequence/connect @0xsequence/hooks wagmi ethers viem 0xsequence @tanstack/react-query # or pnpm install @0xsequence/connect @0xsequence/hooks wagmi ethers viem 0xsequence @tanstack/react-query # or yarn add @0xsequence/connect @0xsequence/hooks wagmi ethers viem 0xsequence @tanstack/react-query ``` For compatibility reasons with wagmi and [@walletconnect](https://docs.reown.com/appkit/next/core/installation#extra-configuration) packages, we need to add the following to our next.config.js file: ```bash theme={null} // Path: next.config.js const nextConfig = { webpack: (config) => { config.externals.push("pino-pretty", "lokijs", "encoding"); return config; }, }; ``` This will get rid of the warnings related to `pino-pretty`. Next, create the configuration. * If you want to allow WalletConnect you will also need a [walletConnectProjectId](https://cloud.reown.com/sign-in). * To setup Google Login follow the [Google Configuration for Embedded Wallet](../../../../solutions/builder/embedded-wallet/google-configuration). * To setup Apple Login follow the [Apple Configuration for Embedded Wallet](../../../../solutions/builder/embedded-wallet/apple-configuration). * To setup X (Twitter) Login follow the [X (Twitter) Configuration for Embedded Wallet](../../../../solutions/builder/embedded-wallet/x-configuration). * To setup Gues Mode follow the [Guest Mode Configuration for Embedded Wallet](../../../../solutions/builder/embedded-wallet/guest-wallet-configuration). ```typescript [config.ts] theme={null} import { createConfig } from "@0xsequence/connect"; // Waas config export const waasConfig: any = createConfig('waas', { projectAccessKey: "", defaultTheme: 'dark', signIn: { projectName: 'Sequence Web SDK Demo', }, appName: 'Sequence Web SDK Demo', chainIds: [1], defaultChainId: 1, waasConfigKey: 'waas-config-key', guest: true, email: true, google: { clientId 'your-google-client-id' }, apple: { clientId: 'your-apple-client-id', redirectURI: window.location.origin + window.location.pathname }, X: { clientId: 'MVZ6aHMyNmMtSF9mNHVldFR6TV86MTpjaQ', redirectURI: window.location.origin + '/auth-callback-X' }, walletConnect: { projectId: walletConnectProjectId }, }); // Universal config export const universalConfig: any = createConfig('universal', { projectAccessKey: "", defaultTheme: 'dark', signIn: { projectName: 'Sequence Web SDK Demo', }, appName: 'Sequence Web SDK Demo', chainIds: [1], defaultChainId: 1, walletConnect: { projectId: walletConnectProjectId } }) ``` In order to customize further, [you can view additional configuration parameters.](/sdk/web/wallet-sdk/embedded/custom-configuration) The configuration we created in [step 3](/sdk/web/wallet-sdk/embedded/getting-started#create-a-config) needs to be passed to the SequenceConnect provider. Create a separate "providers.tsx" file to wrap your app in the Providers component. ```typescript [src/app/providers.tsx] theme={null} "use client"; import React from "react" import { config } from "./config" import { SequenceConnect } from "@0xsequence/connect" const Providers = ({ children }: { children: React.ReactNode }) => { return ( {children} ) } export default Providers; ``` Wrap your app in the Providers component. ```typescript [src/app/layout.tsx] theme={null} import type { Metadata } from "next"; import { Geist, Geist_Mono } from "next/font/google"; import "./globals.css"; import Providers from "./providers"; const geistSans = Geist({ variable: "--font-geist-sans", subsets: ["latin"], }); const geistMono = Geist_Mono({ variable: "--font-geist-mono", subsets: ["latin"], }); export const metadata: Metadata = { title: "Create Next App", description: "Generated by create next app", }; export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { return ( {children} ); } ``` ```typescript [App.tsx] theme={null} "use client" import { useOpenConnectModal } from '@0xsequence/connect' function Home() { const { setOpenConnectModal } = useOpenConnectModal() return ( <> ) } export default Home ``` For web3 interactions, wagmi exposes a set of React hooks that make it convenient for common functions like sending transactions. For web3 interactions, wagmi exposes a set of React hooks that make it convenient for common functions like sending transactions. # Checkout Modal Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/embedded/guides/checkout The Checkout Modal provides developers with an easy way to implement cryptocurrency payments. Sequence Checkout allows users to easily purchase an ERC721 or ERC1155 token with a primary or secondary sales contract such as a marketplace, with the following payment options: * Purchase with any cryptocurrency in the wallet. * Receive funds from another wallet to a Sequence wallet and purchase. * Pay using a credit or debit card which will intelligently detect the correct provider for each region, chain and currency. * Pay with another cryptocurrency in a wallet by doing an automated swap and purchase. We have an integrated checkout flow that you can leverage by installing the dedicated library `@0xsequence/checkout` and using it in conjunction with `@0xsequence/connect`. In order to enable credit card payments for checkout, please get in touch with the Sequence team as your contract address will need to be allowlisted and go through a KYB process for your organization. Credit card payments only work on various networks mainnets # Installation and Setup To integrate the checkout feature, follow these steps: ```bash theme={null} npm install @0xsequence/checkout # or pnpm install @0xsequence/checkout # or yarn add @0xsequence/checkout ``` ```jsx theme={null} import { SequenceCheckoutProvider } from '@0xsequence/checkout' import { SequenceConnect } from '@0xsequence/connect' import { config } from './config' const App = () => { return ( ) } ``` Now we have the setup done, let's see how to use the checkout modal for different use cases. ## Custom Contract We instantiate the `useSelectPaymentModal` hook to open the checkout modal and pass a settings object. In addition, for custom contracts, you can specify a contract ABI along with encoding the call data, in this case we are using `ethers` and `viem`'s `encodeFunctionData` utility. ```tsx theme={null} import { useAccount } from 'wagmi' import { useSelectPaymentModal, type SelectPaymentSettings } from '@0xsequence/checkout' import { toHex } from 'viem' import { encodeFunctionData } from 'viem' const MyComponent = () => { const { address } = useAccount() const { openSelectPaymentModal } = useSelectPaymentModal() const onClick = () => { if (!address) { return } const currencyAddress = '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359' const salesContractAddress = '0xe65b75eb7c58ffc0bf0e671d64d0e1c6cd0d3e5b' const collectionAddress = '0xdeb398f41ccd290ee5114df7e498cf04fac916cb' const price = '20000' const chainId = 137 const erc1155SalesContractAbi = [ { type: 'function', name: 'mint', inputs: [ { name: 'to', type: 'address', internalType: 'address' }, { name: 'tokenIds', type: 'uint256[]', internalType: 'uint256[]' }, { name: 'amounts', type: 'uint256[]', internalType: 'uint256[]' }, { name: 'data', type: 'bytes', internalType: 'bytes' }, { name: 'expectedPaymentToken', type: 'address', internalType: 'address' }, { name: 'maxTotal', type: 'uint256', internalType: 'uint256' }, { name: 'proof', type: 'bytes32[]', internalType: 'bytes32[]' } ], outputs: [], stateMutability: 'payable' } ] const collectibles = [ { tokenId: '1', quantity: '1' } ] const purchaseTransactionData = encodeFunctionData({ abi: erc1155SalesContractAbi, functionName: 'mint', args: [ address, collectibles.map(c => BigInt(c.tokenId)), collectibles.map(c => BigInt(c.quantity)), toHex(0), currencyAddress, price, [toHex(0, { size: 32 })] ] }) const selectPaymentModalSettings: SelectPaymentSettings = { collectibles: [ { tokenId: '1', quantity: '1' } ], chain: chainId, price, targetContractAddress: salesContractAddress, recipientAddress: address, currencyAddress, collectionAddress, creditCardProviders: ['transak'], copyrightText: 'ⓒ2024 Sequence', onSuccess: (txnHash: string) => { console.log('success!', txnHash) }, onError: (error: Error) => { console.error(error) }, txData: purchaseTransactionData, } openSelectPaymentModal(selectPaymentModalSettings) } return } ``` Congratulations! You’ve just learned how to use the Checkout Modal with Web SDK. # On-ramp Overview Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/embedded/guides/on-ramp The checkout on-ramp modal in Web SDK allows developers to easily onboard users with fiat currency into cryptocurrency using a credit card. With this integration, one can use a credit card to purchase tokens across many different networks. ## Integration To integrate the on-ramp feature, follow these steps: Make sure you completed the [Getting Started](/sdk/web/wallet-sdk/embedded/getting-started) guide. ```bash theme={null} npm install @0xsequence/checkout # or pnpm install @0xsequence/checkout # or yarn add @0xsequence/checkout ``` ```jsx theme={null} import { SequenceCheckoutProvider } from '@0xsequence/checkout' import { SequenceConnect } from '@0xsequence/connect' import { config } from './config' const App = () => { return ( ) } ``` Call the `triggerAddFunds` function to cause a modal to appear ```js theme={null} import { useAddFundsModal } from '@0xsequence/checkout' import { useAccount } from 'wagmi' const MyComponent = () => { const { address: recipientAddress } = useAccount() const { triggerAddFunds: toggleAddFunds } = useAddFundsModal() const onClick = () => { toggleAddFunds({ walletAddress: recipientAddress, }) } return ( ) } ``` Congratulations! You’ve just learned how to add funds to your wallet using Web SDK. # Configuration Overview The following is the available configuration customization options for toggleAddFunds params ```ts theme={null} interface AddFundsSettings { walletAddress: string | Hex // Address of the wallet where funds will be added fiatAmount?: string // Specify the amount in fiat to add fiatCurrency?: string // Specify the fiat currency (e.g., USD, EUR) defaultFiatAmount?: string // Default amount in fiat to add defaultCryptoCurrency?: string // Default cryptocurrency to use (e.g., ETH, BTC) cryptoCurrencyList?: string // List of cryptocurrencies available for selection. Example: "USDT,BTC,USDC" networks?: string // Specify network(s) to use for the transaction. Example: "mainnet,ethereum" onClose?: () => void // Callback function to execute when the modal is closed } ``` # On-ramp and Swap to a custom token Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/embedded/guides/on-ramp-and-swap On-ramp to a supported token and swap to your own custom token. Most of the well known tokens are already supported but for some cases you might want your users to be able to swap to a custom token. This example will show you how to do that in two steps using our web SDK. ## Integration To integrate the on-ramp and swap to a custom token, follow these steps: Make sure you completed the [Getting Started](/sdk/web/wallet-sdk/embedded/getting-started) guide. Complete the [On-ramp](/sdk/web/wallet-sdk/embedded/guides/on-ramp) guide After the on-ramp is successful, we can use the `onOrderSuccessful` callback to update the state of the app. ```tsx theme={null} import { useState } from 'react' import { useAddFundsModal } from '@0xsequence/checkout' import { useAccount } from 'wagmi' export const OnRampAndSwap = () => { const { triggerAddFunds: toggleAddFunds } = useAddFundsModal() const { address: smartWalletAddress } = useAccount() const [canSwap, setCanSwap] = useState(true) const onTriggerAddFunds = () => { if (smartWalletAddress) { toggleAddFunds({ walletAddress: smartWalletAddress, onOrderSuccessful(data) { console.log('Order successful', data) setCanSwap(true) }, }) } } return ( <> ) } ``` Once the on-ramp is successful, we can use the `useSwapModal` hook to swap the purchased token to your own custom token. It will take a few minutes (1-3 minutes) for the on-ramped token to be available in the smart wallet so make sure to check the balance before opening the swap modal. If you have enough balance of a supported payment token, the modal will display it as a payment option, you don't need to specify a payment token. Make sure your custom token has enough liquidity on the chain you are executing the swap on. ```tsx theme={null} import { useState } from 'react' import { SwapModalSettings, useAddFundsModal, useSwapModal } from '@0xsequence/checkout' import { useAccount } from 'wagmi' export const OnRampAndSwap = () => { const { triggerAddFunds: toggleAddFunds } = useAddFundsModal() const { openSwapModal } = useSwapModal() const { address: smartWalletAddress, chainId } = useAccount() const [canSwap, setCanSwap] = useState(true) const toTokenAmount = '10000000000' // amount in wei const toTokenAddress = '0x...' // custom token address const onTriggerAddFunds = () => { if (smartWalletAddress) { toggleAddFunds({ walletAddress: smartWalletAddress, onOrderSuccessful(data) { console.log('Order successful', data) setCanSwap(true) }, }) } } const onSwap = () => { const swapModalSettings: SwapModalSettings = { onSuccess: () => { console.log('Swap successful') }, chainId, toTokenAddress, toTokenAmount, title: `Buy our custom token`, description: 'Choose your payment method' } openSwapModal(swapModalSettings) } return ( <> {canSwap ? : } ) } ``` Congratulations! You’ve just learned how to on-ramp and swap to a custom token using Web SDK. # Pay Gas in ERC20 Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/embedded/guides/pay-gas-in-erc20 Learn how to pay gas in ERC20 using Web SDK Make sure you completed the [Getting Started](/sdk/web/wallet-sdk/embedded/getting-started) guide. Next, we'll create a simple page that allows users to send an unsponsored transaction using their smart wallet's native currency, nothing special here. ```typescript theme={null} import React from 'react'; import { useAccount, useSendTransaction } from 'wagmi'; export const ERC20GasPaymentExample = () => { const { address } = useAccount(); const { sendTransaction, isPending, isSuccess, data: txHash } = useSendTransaction(); const sendUnsponsored = () => { if (!address) return; // Send a simple 0 value transaction to yourself sendTransaction({ to: address, value: BigInt(0), gas: null }); }; return ( <>

Address: {address}

{isPending &&

Pending...

} {isSuccess &&

Success! Tx Hash: {txHash}

}
) } ```
We'll use the `useWaasFeeOptions` hook to allow users to pay gas in ERC20. Behind the scenes, the WaaS connector intercepts this transaction request and triggers the fee confirmation flow. Now that we declared the `useWaasFeeOptions` hook, it has set up an effect that overrides the default `feeConfirmationHandler` of the WaaS provider adding the possibility to pay with ERC20 tokens. ```typescript theme={null} import React, { useState, useEffect } from 'react'; import { useWaasFeeOptions } from '@0xsequence/connect'; import { useAccount, useSendTransaction } from 'wagmi'; export const ERC20GasPaymentExample = () => { const { address } = useAccount(); const [pendingFeeOptionConfirmation, confirmPendingFeeOption] = useWaasFeeOptions(); const { sendTransaction, isPending, isSuccess, data: txHash } = useSendTransaction(); const [selectedFeeTokenName, setSelectedFeeTokenName] = useState(); useEffect(() => { if (pendingFeeOptionConfirmation && pendingFeeOptionConfirmation.options.length > 0) { setSelectedFeeTokenName(pendingFeeOptionConfirmation.options[0].token.name); } }, [pendingFeeOptionConfirmation]); const sendUnsponsored = () => { if (!address) return; // Send a simple 0 value transaction to yourself sendTransaction({ to: address, value: BigInt(0), gas: null }); }; return ( <>

Address: {address}

{isPending &&

Pending...

} {isSuccess &&

Success! Tx Hash: {txHash}

}
) } ``` In this example we default to the first option, in the next step we'll add a UI to allow users to choose the fee token they want to pay with.
Next, we'll add a fee token selector to allow users to choose the fee token they want to pay with. Each fee option also contains a boolean property called `hasEnoughBalanceForFee` that you can use to inform the user if they have enough balance to pay for the fee as well as a `balance` property that contains the balance of the token. ```typescript theme={null} import { useState, useEffect } from 'react'; import { useWaasFeeOptions } from '@0xsequence/connect'; import { formatUnits } from 'viem'; import { useAccount, useSendTransaction } from 'wagmi'; export const ERC20GasPaymentExample = () => { const { address } = useAccount(); // 1. Set up the fee options hook const [pendingFeeOptionConfirmation, confirmPendingFeeOption, rejectPendingFeeOption] = useWaasFeeOptions(); // 2. Set up transaction hook const { sendTransaction, isPending, isSuccess, data: txHash } = useSendTransaction(); // 3. Track selected fee token const [selectedFeeTokenName, setSelectedFeeTokenName] = useState(); // 4. Initialize with first option when fee options become available useEffect(() => { if (pendingFeeOptionConfirmation && pendingFeeOptionConfirmation.options.length > 0) { setSelectedFeeTokenName(pendingFeeOptionConfirmation.options[0].token.name); } }, [pendingFeeOptionConfirmation]); // 5. Function to send an unsponsored transaction const sendUnsponsored = () => { if (!address) return; // Send a dummy tx sendTransaction({ to: address, value: BigInt(0), gas: null }); }; return (

ERC20 Gas Payment Example

{isSuccess && txHash && (

Transaction successful! Hash: {txHash}

)} {/* Fee selection UI appears when needed */} {pendingFeeOptionConfirmation && (

Select Token to Pay Gas Fees

)}
); }; ```
Congratulations! You've just learned how to pay gas in ERC20 using Web SDK. # Send a sponsored transaction Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/embedded/guides/send-sponsored-tx In this tutorial, we'll learn how to send sponsored transactions using Web SDK. Make sure you completed the [Getting Started](/sdk/web/wallet-sdk/embedded/getting-started) guide. If you plan to send transactions on mainnet, you need to setup your gas tank. Go to [Gas Sponsorhip](/solutions/builder/gas-sponsorship) to learn how to setup your gas tank. All Sequence smart wallet transactions are sponsored by default on all testnets except [Porcini Testnet](https://chainlist.org/chain/7672). Next, we'll create a simple component to send a sponsored transaction. ```typescript theme={null} import React from 'react'; import { useAccount, useSendTransaction } from 'wagmi'; export const SponsoredTransactionExample = () => { const { address } = useAccount(); const { sendTransaction, isPending, isSuccess, data: txHash } = useSendTransaction(); const sendSponsoredTx = () => { if (!address) return; // Sending a dummy tx sendTransaction({ to: address, value: BigInt(0), gas: null }); }; return (

Your Wallet Address

{address || 'Not connected'}

{isSuccess && (
Transaction Successful!

Transaction Hash:

{txHash}

)}
) } ```
Congratulations! You've just learned how to send a sponsored transaction using Web SDK. # Smart Swaps Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/embedded/guides/smart-swaps Sequence Smart Swaps auto detects eligible currencies in the user's wallet and swaps them to the target currency. Developers can define the target currency and Sequence will handle everything, including the UI and flow through Web SDK. The power of smart swaps is intelligently detecting the currencies available to the user as well as batching multiple transactions together to if the user is utilizing a Sequence wallet to simplify the UX. You can say goodbye to separate `approve` and `transfer` transactions! If you intend to use smart swaps with your custom token, please ensure you provide sufficient liquidity for your token (preferably USDC, USDT, or ETH) on a supported DEX such as Uniswap. Smart Swaps are only supported on mainnets, such as: * Ethereum * Arbitrum * Avalanche * Base * Blast * BSC * Optimism * Polygon * ... Here are some of our supported liquidity pool providers: `UniSwap` `SushiSwap` `Pancake Swap` `Curve` `Balancer` `Bancor` `Synapse` `Solidly` # Installation and Setup To integrate the Swap feature with Web SDK, follow these steps: ```bash theme={null} npm install @0xsequence/checkout # or pnpm install @0xsequence/checkout # or yarn add @0xsequence/checkout ``` ```jsx theme={null} import { SequenceCheckoutProvider } from '@0xsequence/checkout' import { SequenceConnect } from '@0xsequence/connect' import { config } from './config' const App = () => { return ( ) } ``` * `toTokenAddress`: The target currency address, this is the token the user will receive after the swap. * `toTokenAmount`: The target currency amount, this is the amount the user will receive after the swap. * `postSwapTransactions`: An optional array of transactions to be executed after the swap, using the swapped tokens. * `title`: The modal's title. * `description`: A description of the swap and payment process. * `chainId`: The chain id of the target currency. * `onSuccess`: A callback function that is called when the swap is successful. ```jsx theme={null} import { useSwapModal, type SwapModalSettings } from '@0xsequence/checkout' const MyComponent = () => { const { openSwapModal } = useSwapModal() const onClick = () => { const chainId = 137 const toTokenAddress = '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359' const toTokenAmount = '20000' const contractAbiInterface = new ethers.Interface(['function demo()']) // Optionally, replace with your contract's abi interface const data = contractAbiInterface.encodeFunctionData('demo', []) as `0x${string}` // Optionally, replace 'demo' with the function you want to call, const swapModalSettings: SwapModalSettings = { onSuccess: () => { console.log('swap successful!') }, chainId, toTokenAddress, toTokenAmount, postSwapTransactions: [ // Optionally, replace with the transaction you would like to execute after the swap has taken place. { to: '0x37470dac8a0255141745906c972e414b1409b470', data } ], title: 'Swap and Pay', description: 'Select a token in your wallet to swap to 0.2 USDC.' } openSwapModal(swapModalSettings) } return } ``` Congratulations! You’ve just learned how to use smart swaps with Web SDK. # Web Verification Guide Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/embedded/guides/verification The content provides a detailed guide on verifying ownership of an Embedded Wallet address using a nonce and optional time expiry. A common use case is that you authenticate the user on the client, but you want to also validate this token as well as corresponding user information on your backend. In this case, Sequence provides a function to retrieve a JWT which can be verified using your JWT library of choice for your given framework. Below we outline an example using our Web SDK, Wagmi, and an Express server. If you're not using the Web SDK but instead working with the Embedded Wallet and TypeScript, you can go [here](/sdk/headless-wallet/verification) to see how to handle the verification process. An example client & server demonstrating the below is available [here](https://github.com/0xsequence-demos/web-sdk-id-token-verification) ### Implementation Once a user has authenticated with an embedded wallet on the client, simply call the corresponding function in order get a JWT from Sequence. ```typescript theme={null} import { useConnect } from "wagmi"; type IdTokenResponse = { idToken: string; expiresIn: number; }; export function GetIdToken() { const { connectors } = useConnect(); const handleClick = async () => { const waasConnector = connectors.find( (connector) => "sequenceWaas" in connector ) as { sequenceWaas?: { getIdToken: () => Promise } } | undefined; const waas = waasConnector?.sequenceWaas; if (!waas) return; try { const { idToken, expiresIn } = await waas.getIdToken(); console.log({ idToken, expiresIn }); } catch (error) { console.error("Failed to get ID token:", error); } }; return ; } ``` Make a POST request to your backend with the queried JWT. ```typescript theme={null} const response = await fetch(BACKEND_ENDPOINT, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ sequenceToken: idToken }), }); ``` From our express server that the JWT was passed to, we simply import our preferred JWT library to verify the information and initialize our JWKS to verify against. It is also important to ensure that your expected audience is set correctly so that the claim will be properly verified. ```typescript theme={null} import * as jwt from "jsonwebtoken"; import * as jwksClient from "jwks-rsa"; ...serverConfig // Initialize the JWKS client const client = jwksClient({ jwksUri: "https://waas.sequence.app/.well-known/jwks.json", cache: true, cacheMaxAge: 86400000, // 1 day }); // Should be equal to the audience claim in the JWT that you want to verify which will be of the form https://sequence.build/project/*projectID* const EXPECTED_AUDIENCE = "https://sequence.build/project/*PROJECT_ID*" ``` Now we can parse the JWT, verify it against our JWKS URI, then validate any of the claims. ```typescript theme={null} const decodedToken = jwt.decode(token, { complete: true }); if (!decodedToken || typeof decodedToken === "string") { throw new Error("Invalid token"); } const kid = decodedToken.header.kid; const signingKey = await getSigningKey(kid); const publicKey = ( signingKey as jwksClient.CertSigningKey | jwksClient.RsaSigningKey ).getPublicKey(); console.log(EXPECTED_AUDIENCE); const verified = jwt.verify(token, publicKey, { algorithms: ["RS256"], // Specify the expected algorithm audience: EXPECTED_AUDIENCE, // Verify the audience claim }); // Verifying Email claim if (!verified.email || typeof verified.email !== "string") { throw new Error("Invalid email claim"); } ``` From here, you now have verified the information corresponding to the JWT and can safely update your backend as needed. # useChain Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/embedded/hooks/useChain Hook for retrieving chain configuration information ## Import ```tsx theme={null} import { useChain } from '@0xsequence/connect' ``` ## Usage ```tsx theme={null} import { useChain } from '@0xsequence/connect' function App() { // Get current chain configuration const currentChain = useChain() // Get configuration for a specific chain (e.g., Ethereum Mainnet) const ethereumChain = useChain(1) return (

Current Chain

{currentChain && (

Name: {currentChain.name}

Chain ID: {currentChain.id}

Network: {currentChain.network}

Native Currency: {currentChain.nativeCurrency.symbol}

)}

Ethereum Mainnet

{ethereumChain && (

Name: {ethereumChain.name}

Chain ID: {ethereumChain.id}

Network: {ethereumChain.network}

Native Currency: {ethereumChain.nativeCurrency.symbol}

)}
) } ``` ## Parameters | Parameter | Type | Description | | --------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------ | | `chainId` | `number \| undefined` | Optional chain ID to get configuration for a specific chain. If not provided, returns the current chain's configuration. | ## Return Type: `Chain | undefined` The hook returns a `Chain` object from wagmi's chain configurations or `undefined` if the chain is not found. ```tsx theme={null} interface Chain { id: number name: string network: string nativeCurrency: { name: string symbol: string decimals: number } rpcUrls: { default: { http: string[] webSocket?: string[] } public: { http: string[] webSocket?: string[] } } blockExplorers?: { default: { name: string url: string } } // ... other chain-specific properties } ``` ### Properties #### id `number` The unique identifier of the blockchain network. #### name `string` The human-readable name of the blockchain network. #### network `string` The network identifier string. #### nativeCurrency `object` Information about the chain's native currency. ```tsx theme={null} { name: string // Full name of the currency symbol: string // Currency symbol decimals: number // Number of decimal places } ``` #### rpcUrls `object` URLs for connecting to the network's RPC endpoints. #### blockExplorers `object | undefined` Information about block explorers for the chain. ## Notes This hook provides easy access to chain configuration information from wagmi's chain configurations. It's particularly useful when you need to: * Access details about the currently connected chain * Get configuration for a specific chain by ID * Retrieve chain-specific information like: * Network details * Native currency information * RPC endpoints * Block explorer URLs The hook is commonly used in conjunction with other Sequence hooks when working with transactions, indexer clients, or network-specific features. # useCheckWaasFeeOptions Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/embedded/hooks/useCheckWaasFeeOptions Hook for checking transaction fee options in Sequence This hook will be deprecated in v6, it can only be used with [Connect SDK v5.](/sdk/web/wallet-sdk/embedded/getting-started) ## Import ```tsx theme={null} import { useCheckWaasFeeOptions } from '@0xsequence/connect' ``` ## Usage ```tsx theme={null} import { useCheckWaasFeeOptions } from '@0xsequence/connect' function App() { const checkFeeOptions = useCheckWaasFeeOptions() const handleTransaction = async () => { // Example transaction const transaction = { to: '0x...', value: '1000000000000000000', // 1 ETH data: '0x...' } const { isSponsored, feeOptions, feeQuote } = await checkFeeOptions({ transactions: [transaction], chainId: 1 // Ethereum Mainnet }) if (isSponsored) { console.log('Transaction is sponsored!') } else if (feeOptions) { console.log('Available fee options:', feeOptions) console.log('Fee quote:', feeQuote) // Handle fee payment selection } } return (
) } ``` ## Return Type The hook returns a function with the following signature: ```tsx theme={null} (params: { transactions: Transaction[] chainId: number }) => Promise<{ feeQuote: string | undefined feeOptions: FeeOption[] | undefined isSponsored: boolean }> ``` ### Parameters #### transactions `Transaction[]` Array of transactions to check fee options for. ```tsx theme={null} interface Transaction { to: string value?: string data?: string // ... other transaction properties } ``` #### chainId `number` The ID of the blockchain network where the transaction will be executed. ### Return Object Properties #### isSponsored `boolean` Indicates whether the transaction will be sponsored (true) or requires fee payment (false). #### feeOptions `FeeOption[] | undefined` Available fee payment options if the transaction is not sponsored. ```tsx theme={null} interface FeeOption { token: { symbol: string decimals: number address: string } // ... other fee option properties } ``` #### feeQuote `string | undefined` The fee quote for the transaction if available. ## Notes This hook is specifically designed for use with Sequence and provides functionality to: * Check if a transaction will be sponsored * Get available fee options for unsponsored transactions * Retrieve fee quotes for transactions # useListAccounts Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/embedded/hooks/useListAccounts Hook to list all accounts associated with the current WaaS session ## Import ```tsx theme={null} import { useListAccounts } from '@0xsequence/connect' ``` ## Usage ```tsx theme={null} import { useListAccounts } from '@0xsequence/connect' function AccountsList() { const { data, isLoading, error, refetch } = useListAccounts() if (isLoading) return
Loading accounts...
if (error) return
Error: {error.message}
return (
Current Account ID: {data?.currentAccountId}
{data?.accounts.map(account => (
ID: {account.id}
Type: {account.type}
{account.email &&
Email: {account.email}
} {account.issuer &&
Issuer: {account.issuer}
}
))}
) } ``` ## Return Type: `UseListAccountsResult` The hook returns an object with the following properties: ```tsx theme={null} interface UseListAccountsResult { /** The accounts data if available */ data?: IntentResponseAccountList /** Whether the query is currently loading */ isLoading: boolean /** Any error that occurred during the query */ error: Error | null /** Function to manually refetch the accounts */ refetch: () => Promise } enum IdentityType { None = "None", Guest = "Guest", OIDC = "OIDC", Email = "Email", PlayFab = "PlayFab", Stytch = "Stytch" } interface Account { id: string; type: IdentityType; issuer?: string; email?: string; } interface IntentResponseAccountList { accounts: Array; currentAccountId: string; } ``` ### Properties #### data `IntentResponseAccountList | undefined` The list of accounts if the query was successful. Contains an array of account objects with properties like `id` and `address`. #### isLoading `boolean` Whether the query is currently in progress. Useful for showing loading states. #### error `Error | null` Any error that occurred during the query. Will be `null` if no error occurred. #### refetch `() => Promise` Function to manually trigger a refresh of the accounts list. ## Features * **Automatic Data Fetching**: Automatically fetches accounts when WaaS connection is available * **Caching**: Results are cached for 1 minute to prevent unnecessary refetches * **Error Handling**: Proper error handling for missing WaaS connector or initialization issues * **Type Safety**: Full TypeScript support for all returned data * **React Query Integration**: Uses React Query for efficient state management and caching # useOpenConnectModal Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/embedded/hooks/useOpenConnectModal Hook for opening the connect modal ## Import ```tsx theme={null} import { useOpenConnectModal } from '@0xsequence/connect' ``` ## Usage ```tsx theme={null} import { useOpenConnectModal } from '@0xsequence/connect' function App() { const { setOpenConnectModal, openConnectModalState } = useOpenConnectModal() const handleConnect = () => { setOpenConnectModal(true) // Open the connect modal } return ( <> {openConnectModalState && (
Connect modal is open!
)} ) } ``` ## Return Type: `UseOpenConnectModalReturnType` The hook returns an object with the following properties: ```tsx theme={null} type UseOpenConnectModalReturnType = { setOpenConnectModal: (isOpen: boolean) => void openConnectModalState: boolean } ``` ### Properties #### setOpenConnectModal `(isOpen: boolean) => void` Function to open or close the Connect modal. **Parameters:** | Parameter | Type | Description | | --------- | --------- | ------------------------------------------------------------- | | `isOpen` | `boolean` | Whether the modal should be open (`true`) or closed (`false`) | #### openConnectModalState `boolean` The current open state of the Connect modal (`true` if open, `false` if closed). ## Notes This hook provides methods to control the Connect modal that allows users to connect their wallets to your application. The Connect modal provides various wallet connection options including Sequence wallet and external wallets. # useProjectAccessKey Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/embedded/hooks/useProjectAccessKey Hook to access the project access key from the Sequence Connect configuration ## Import ```tsx theme={null} import { useProjectAccessKey } from '@0xsequence/connect' ``` ## Usage ```tsx theme={null} import { useProjectAccessKey } from '@0xsequence/connect' function App() { const projectAccessKey = useProjectAccessKey() return (
{projectAccessKey && (

Project access key is configured

)}
) } ``` ## Return Type The hook returns a string value: ```tsx theme={null} string ``` ### Return Value #### projectAccessKey `string` The project access key configured for the application. This key is used to authenticate and identify your application with Sequence services. **Description:** The project access key is a required configuration parameter that: * Authenticates your application with Sequence services * Identifies your specific project/application * Enables access to various SDK features including marketplace integration and wallet connections * Must be provided during the initial configuration of the Sequence Connect context **Example Usage:** ```tsx theme={null} // Using with marketplace integration const projectAccessKey = useProjectAccessKey() const marketplaceClient = new MarketplaceIndexer(apiUrl, projectAccessKey) ``` ## Notes This hook provides access to the project access key that was configured when setting up the Sequence Connect context. The project access key is essential for: * **Authentication**: Verifying your application's identity with Sequence services * **Authorization**: Determining what features and resources your application can access * **Billing**: Associating usage with your specific project for billing purposes * **Rate Limiting**: Managing API rate limits per project # useSequenceWaaS Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/embedded/hooks/useSequenceWaas Hook to create and access a Sequence WaaS instance ## Import ```tsx theme={null} import { useSequenceWaaS } from '@0xsequence/connect' ``` ## Usage ```tsx theme={null} import { useSequenceWaaS } from '@0xsequence/connect' function App() { const sequenceWaaS = useSequenceWaaS() const handleWaaSOperation = async () => { try { // Use the WaaS instance to get connected accounts const response = await sequenceWaaS.listAccounts() console.log('Accounts:', response.accounts) } catch (error) { console.error('WaaS operation failed:', error) } } return (
) } ``` ## Return Type The hook returns a `SequenceWaaS` instance: ```tsx theme={null} SequenceWaaS ``` ### Return Value #### sequenceWaaS `SequenceWaaS` A configured Sequence WaaS (Wallet as a Service) instance that provides access to various wallet and blockchain operations. **Description:** The returned WaaS instance is automatically configured with: * **Project Access Key**: Retrieved from the Connect configuration context * **WaaS Config Key**: Retrieved from the social link configuration This instance can be used to perform various wallet operations, manage accounts, and interact with blockchain services. ## Notes This hook provides a pre-configured Sequence WaaS instance that is ready to use for various wallet operations. The WaaS instance is automatically configured with the necessary credentials from your Connect setup. # useSignInEmail Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/embedded/hooks/useSignInEmail Hook to retrieve the email address associated with the connected wallet ## Import ```tsx theme={null} import { useSignInEmail } from '@0xsequence/connect' ``` ## Usage ```tsx theme={null} import { useSignInEmail } from '@0xsequence/connect' function App() { const email = useSignInEmail() return (

User Information

{email ? (

Connected with email: {email}

) : (

No email associated with connected wallet

)}
) } ``` ## Return Type ```tsx theme={null} string | null ``` The hook returns: * A `string` containing the email address when a wallet is connected and has an associated email * `null` when: * No wallet is connected * The connected wallet has no associated email * The wallet has been disconnected ## State Management The hook manages the email state by: 1. Monitoring the wallet connection status 2. Retrieving the stored email when a wallet connects 3. Clearing the email when the wallet disconnects 4. Persisting the email in local storage using the `WaasSignInEmail` key ## Notes This hook is designed to work with both: * Sequence WaaS (Wallet-as-a-Service) wallets * Universal wallet types The hook integrates with Sequence's storage system to maintain email persistence across sessions while ensuring proper cleanup when wallets are disconnected. # useSocialLink Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/embedded/hooks/useSocialLink Hook to manage social link modal state and configuration ## Import ```tsx theme={null} import { useSocialLink } from '@0xsequence/connect' ``` ## Usage ```tsx theme={null} import { useSocialLink } from '@0xsequence/connect' function App() { const { isSocialLinkOpen, waasConfigKey, setIsSocialLinkOpen } = useSocialLink() const handleOpenSocialLink = () => { setIsSocialLinkOpen(true) } const handleCloseSocialLink = () => { setIsSocialLinkOpen(false) } return (
{isSocialLinkOpen && (

Social Link modal is open

WaaS Config Key: {waasConfigKey || 'Not available'}

)}
) } ``` ## Return Type: `UseSocialLinkReturnType` The hook returns an object with the following properties: ```tsx theme={null} type UseSocialLinkReturnType = { isSocialLinkOpen: boolean waasConfigKey: string | null setIsSocialLinkOpen: (isOpen: boolean) => void } ``` ### Properties #### isSocialLinkOpen `boolean` Indicates whether the social link modal is currently open (`true`) or closed (`false`). #### waasConfigKey `string | null` The WaaS configuration key associated with the social link functionality, or `null` if not available. #### setIsSocialLinkOpen `(isOpen: boolean) => void` Function to open or close the social link modal. **Parameters:** | Parameter | Type | Description | | --------- | --------- | ------------------------------------------------------------- | | `isOpen` | `boolean` | Whether the modal should be open (`true`) or closed (`false`) | # useStorage Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/embedded/hooks/useStorage Hook for accessing the storage instance of the Sequence Connect client ## Import ```tsx theme={null} import { useStorage, useStorageItem } from '@0xsequence/connect' ``` ### Usage ```tsx theme={null} import { useStorage, signEthAuthProof, validateEthProof } from '@0xsequence/connect' import { useWalletClient, usePublicClient } from 'wagmi' function App() { const { data: walletClient } = useWalletClient() const publicClient = usePublicClient() const storage = useStorage() const generateEthAuthProof = async () => { if (!walletClient || !publicClient || !storage) { return } try { // Use storage to generate an auth proof const proof = await signEthAuthProof(walletClient, storage) console.log('proof:', proof) const isValid = await validateEthProof(walletClient, publicClient, proof) console.log('isValid?:', isValid) } catch (e) { console.error(e) } } return ( ) } ``` ### Return Type `Storage | null` Returns the Storage instance if available, or null if not configured. ## useStorageItem Hook to retrieve a specific item from the Sequence Connect storage. ### Usage ```tsx theme={null} import { useStorageItem } from '@0xsequence/connect' function App() { const { data: authToken, isLoading } = useStorageItem('authToken') if (isLoading) { return
Loading...
} return (
{authToken ? 'Authenticated' : 'Not authenticated'}
) } ``` ### Parameters | Parameter | Type | Description | | --------- | ------------------- | --------------------------------------- | | `key` | `keyof StorageItem` | The key of the storage item to retrieve | ### Return Type `UseQueryResult` Returns a react-query result containing the storage item data, with the following properties: | Property | Type | Description | | ----------- | ---------------- | ---------------------------------------------- | | `data` | `StorageItem[K]` | The retrieved storage item data | | `isLoading` | `boolean` | Whether the data is currently loading | | `isError` | `boolean` | Whether an error occurred during data fetching | | `error` | `Error` | The error object if an error occurred | | ... | ... | Other react-query properties | ## Notes These hooks provide access to the storage layer used by Sequence Connect for persisting authentication data, wallet state, and other client-side storage needs. The `useStorage` hook is commonly used for operations that require direct access to the storage layer, such as generating authentication proofs, while `useStorageItem` provides a convenient way to access specific items with react-query integration. # useTheme Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/embedded/hooks/useTheme Hook to access and modify theme and modal position settings ## Import ```tsx theme={null} import { useTheme } from '@0xsequence/connect' ``` ## Usage ```tsx theme={null} import { useTheme } from '@0xsequence/connect' function App() { const { theme, setTheme, position, setPosition } = useTheme() return (

Theme Settings

Modal Position

) } ``` ## Return Type ```tsx theme={null} interface ThemeHookReturn { theme: 'light' | 'dark' setTheme: (theme: 'light' | 'dark') => void position: ModalPosition setPosition: (position: ModalPosition) => void } type ModalPosition = | 'center' | 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' ``` ### Properties #### theme `'light' | 'dark'` The current theme setting. #### setTheme `(theme: 'light' | 'dark') => void` Function to update the theme setting. #### position `ModalPosition` The current modal position setting. #### setPosition `(position: ModalPosition) => void` Function to update the modal position setting. # useWaasFeeOptions Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/embedded/hooks/useWaasFeeOptions Hook for handling WaaS fee options for gas payments ## Import ```tsx theme={null} import { useWaasFeeOptions } from '@0xsequence/connect' ``` ## Usage ```tsx theme={null} import { useWaasFeeOptions } from '@0xsequence/connect' import { useEffect, useState } from 'react' function App() { // Use the hook with default balance checking // This will return the wallet balance for each fee option const [ pendingFeeOptionConfirmation, confirmPendingFeeOption, rejectPendingFeeOption ] = useWaasFeeOptions() // Or skip balance checking if needed // const [pendingFeeOptionConfirmation, confirmPendingFeeOption, rejectPendingFeeOption] = // useWaasFeeOptions({ skipFeeBalanceCheck: true }) const [selectedFeeOptionTokenName, setSelectedFeeOptionTokenName] = useState() // Initialize with first option when fee options become available useEffect(() => { if (pendingFeeOptionConfirmation) { console.log('Pending fee options: ', pendingFeeOptionConfirmation.options) // You could select the first fee option by default if (pendingFeeOptionConfirmation.options.length > 0) { const firstOption = pendingFeeOptionConfirmation.options[0] setSelectedFeeOptionTokenName(firstOption.token.symbol) } } }, [pendingFeeOptionConfirmation]) // Handle fee option selection and confirmation const handleConfirmFee = (tokenAddress: string | null) => { if (pendingFeeOptionConfirmation) { confirmPendingFeeOption(pendingFeeOptionConfirmation.id, tokenAddress) } } // Handle fee option rejection const handleRejectFee = () => { if (pendingFeeOptionConfirmation) { rejectPendingFeeOption(pendingFeeOptionConfirmation.id) } } // Render fee options UI if (pendingFeeOptionConfirmation) { return (

Select Fee Payment Token

{pendingFeeOptionConfirmation.options.map((option) => (
setSelectedFeeOptionTokenName(option.token.symbol)} />
))}
) } return
No pending fee confirmation
} ``` ## Parameters The hook accepts an optional configuration object with the following properties: ```tsx theme={null} interface WaasFeeOptionsConfig { skipFeeBalanceCheck?: boolean } ``` | Parameter | Type | Description | | --------------------- | --------- | ---------------------------------------------------------- | | `skipFeeBalanceCheck` | `boolean` | Whether to skip checking token balances (default: `false`) | ## Return Type: `UseWaasFeeOptionsReturnType` The hook returns a tuple with the following elements: ```tsx theme={null} type UseWaasFeeOptionsReturnType = [ pendingFeeOptionConfirmation: WaasFeeOptionConfirmation | undefined, confirmPendingFeeOption: (id: string, feeTokenAddress: string | null) => void, rejectPendingFeeOption: (id: string) => void ] ``` ### Properties #### pendingFeeOptionConfirmation `WaasFeeOptionConfirmation | undefined` Object containing the current fee confirmation details if a transaction is pending, or `undefined` if no transaction is pending confirmation. ```tsx theme={null} type WaasFeeOptionConfirmation = { id: string // Unique identifier for the fee confirmation options: FeeOptionExtended[] | FeeOption[] // Available fee options with balance information chainId: number // Chain ID where the transaction will be executed } ``` When `skipFeeBalanceCheck` is `false`, the options will be of type `FeeOptionExtended`, which includes balance information: ```tsx theme={null} type FeeOptionExtended = FeeOption & { balance: string // Raw balance string balanceFormatted: string // Formatted balance with proper decimals hasEnoughBalanceForFee: boolean // Indicates if wallet has enough balance } ``` #### confirmPendingFeeOption `(id: string, feeTokenAddress: string | null) => void` Function to confirm the selected fee option. | Parameter | Type | Description | | ----------------- | ---------------- | ----------------------------------------------------------------------------- | | `id` | `string` | The fee confirmation ID | | `feeTokenAddress` | `string \| null` | The address of the token to use for fee payment (use `null` for native token) | #### rejectPendingFeeOption `(id: string) => void` Function to reject the current fee option selection. | Parameter | Type | Description | | --------- | -------- | --------------------------------- | | `id` | `string` | The fee confirmation ID to reject | ## Notes This hook provides functionality for handling WaaS (Wallet as a Service) fee options for unsponsored transactions. Key features: * Get available fee options for a transaction in Native Token and ERC20 tokens * Automatically fetch user wallet balances for each fee option (unless `skipFeeBalanceCheck` is `true`) * Allow users to select their preferred fee token * Confirm or reject fee selections The hook integrates with the Sequence WaaS provider to intercept fee confirmation requests and presents a user interface to allow selection of the fee token. For a detailed guide on how to use the hook, see the [Pay gas in ERC20](/sdk/web/wallet-sdk/embedded/guides/pay-gas-in-erc20) guide. # useWalletSettings Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/embedded/hooks/useWalletSettings Hook to access and modify wallet configuration settings ## Import ```tsx theme={null} import { useWalletSettings } from '@0xsequence/connect' ``` ## Usage ```tsx theme={null} import { useWalletSettings } from '@0xsequence/connect' function WalletConfigPanel() { const { displayedAssets, readOnlyNetworks, setDisplayedAssets } = useWalletSettings() // Example function to add a new asset const addNewAsset = (contractAddress: string, chainId: number) => { setDisplayedAssets([ ...displayedAssets, { contractAddress, chainId } ]) } // Example function to check if network is read-only const isNetworkReadOnly = (chainId: number) => { return readOnlyNetworks?.includes(chainId) } return (

Wallet Settings

Displayed Assets

    {displayedAssets.map(asset => (
  • Chain ID: {asset.chainId}, Contract: {asset.contractAddress}
  • ))}

Network Status

    {[1, 137, 10].map(chainId => (
  • Chain {chainId}: {isNetworkReadOnly(chainId) ? 'Read-only' : 'Active'}
  • ))}
) } ``` ## Return Type ```tsx theme={null} interface WalletSettingsReturn { displayedAssets: Array<{ contractAddress: string chainId: number }> readOnlyNetworks: number[] | undefined setDisplayedAssets: (assets: Array<{ contractAddress: string chainId: number }>) => void } ``` ### Properties #### displayedAssets `Array<{ contractAddress: string, chainId: number }>` Array of assets to display in the wallet interface. Each asset is defined by: * `contractAddress`: The token contract address * `chainId`: The network ID where the token exists #### readOnlyNetworks `number[] | undefined` Array of network IDs where transactions are disabled. These networks are available for viewing balances and transaction history, but users cannot initiate new transactions. #### setDisplayedAssets `(assets: Array<{ contractAddress: string, chainId: number }>) => void` Function to update the list of displayed assets. Takes an array of asset objects, each containing a contract address and chain ID. ## Notes This hook provides access to wallet display settings and network status information. Key features: * Asset display list management * Read-only network status information * Type-safe configuration updates Common use cases: * Managing visible token list * Checking if networks are read-only * Building settings interfaces Best practices: * Validate contract addresses before adding to displayed assets * Check network read-only status before attempting transactions * Keep displayed assets list up to date The hook is commonly used in wallet configuration interfaces to manage which assets are displayed and check network status. # useWallets Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/embedded/hooks/useWallets Hook for managing connected wallets ## Features This hook provides a unified interface for managing connected wallets, both embedded (WaaS) and external wallets. The user is prompted to sign a transaction with their active wallet in order to link wallets enabling read-only functionality. Key features: * Get information about all connected wallets * Set a specific wallet as active * Disconnect wallets * View linked wallets for embedded wallets * Refresh the list of linked wallets For embedded wallets (Wallet-as-a-Service), the hook automatically fetches linked wallets if available. Linked wallets are additional wallets that have been connected to the primary embedded wallet. ## Import ```tsx theme={null} import { useWallets } from '@0xsequence/connect' ``` ## Usage ```tsx theme={null} import { useWallets } from '@0xsequence/connect' function App() { const { wallets, linkedWallets, setActiveWallet, disconnectWallet, refetchLinkedWallets } = useWallets() return (

Connected Wallets

{wallets.map(wallet => (
{wallet.name}: {wallet.address.slice(0, 6)}...{wallet.address.slice(-4)} {wallet.isActive ? ' (Active)' : ''} {wallet.isEmbedded ? ' (Embedded)' : ''}
))}
{linkedWallets && linkedWallets.length > 0 && ( <>

Linked Wallets

{linkedWallets.map(linkedWallet => (
{linkedWallet.walletAddress.slice(0, 6)}...{linkedWallet.walletAddress.slice(-4)}
))}
)}
) } ``` ## Return Type: `UseWalletsReturnType` The hook returns an object with the following properties: ```tsx theme={null} interface UseWalletsReturnType { wallets: ConnectedWallet[] linkedWallets: LinkedWallet[] | undefined setActiveWallet: (address: string) => Promise disconnectWallet: (address: string) => Promise refetchLinkedWallets: () => Promise } ``` ### Properties #### wallets `ConnectedWallet[]` Array of all connected wallets. ```tsx theme={null} interface ConnectedWallet { id: string // Unique identifier for the wallet (connector id) name: string // Display name of the wallet address: string // The wallet's Ethereum address isActive: boolean // Whether this wallet is currently active isEmbedded: boolean // Whether this is an embedded wallet (WaaS) } ``` #### linkedWallets `LinkedWallet[] | undefined` Array of linked wallets for the active embedded wallet (if any). Only available when using a WaaS wallet. ```tsx theme={null} interface LinkedWallet { id: number; walletType?: string; walletAddress: string; linkedWalletAddress: string; createdAt?: string; } ``` #### setActiveWallet `(address: string) => Promise` Function to set a wallet as active by its address. | Parameter | Type | Description | | --------- | -------- | --------------------------------------------------- | | `address` | `string` | The Ethereum address of the wallet to set as active | #### disconnectWallet `(address: string) => Promise` Function to disconnect a wallet by its address. | Parameter | Type | Description | | --------- | -------- | ------------------------------------------------ | | `address` | `string` | The Ethereum address of the wallet to disconnect | #### refetchLinkedWallets `() => Promise` Function to refresh the list of linked wallets. Useful after linking a new wallet. # Migrate to v5 (Web SDK) Source: https://docs.sequence.xyz/sdk/web/wallet-sdk/embedded/migration Sequence Kit (v4) is now Web SDK (v5), here are the biggest changes. React 19 is supported on Web SDK! ## Installing new dependencies All of our hook libraries have been renamed, here are the new dependencies you need to get started with Web SDK: ```bash New theme={null} npm install @0xsequence/connect @0xsequence/hooks wagmi ethers viem 0xsequence @tanstack/react-query # or pnpm install @0xsequence/connect @0xsequence/hooks wagmi ethers viem 0xsequence @tanstack/react-query # or yarn add @0xsequence/connect @0xsequence/hooks wagmi ethers viem 0xsequence @tanstack/react-query ``` ```bash Old theme={null} npm install @0xsequence/kit @0xsequence/waas wagmi ethers viem 0xsequence @0xsequence/design-system@^1.9.0 motion @tanstack/react-query # or pnpm install @0xsequence/kit @0xsequence/waas wagmi ethers viem 0xsequence @0xsequence/design-system@^1.9.0 motion @tanstack/react-query # or yarn add @0xsequence/kit @0xsequence/waas wagmi ethers viem 0xsequence @0xsequence/design-system@^1.9.0 motion @tanstack/react-query ``` ## Configuring your app Main differences when it comes to configuration: ```tsx New theme={null} import React from "react"; import ReactDOM from "react-dom/client"; import "./index.css"; import App from "./App"; import { SequenceConnect } from "@0xsequence/connect"; import { SequenceCheckoutProvider } from "@0xsequence/checkout" import { config } from "./config"; function Dapp() { return ( ); } ReactDOM.createRoot(document.getElementById("root")!).render( ); ``` ```tsx Old theme={null} import React from "react"; import ReactDOM from "react-dom/client"; import "./index.css"; import App from "./App"; import { SequenceKit } from "@0xsequence/kit"; import { KitCheckoutProvider } from "@0xsequence/kit-checkout"; import { config } from "./config"; import '@0xsequence/design-system/styles.css' function Dapp() { return ( ); } ReactDOM.createRoot(document.getElementById("root")!).render( ); ``` * `@0xsequence/kit` -> `@0xsequence/connect` for authentication * `@0xsequence/kit` -> `@0xsequence/wallet-widget` for wallet UI * `@0xsequence/kit-checkout` -> `@0xsequence/checkout` * no need to manually import the `@0xsequence/design-system/styles.css` when using `@0xsequence/connect` * `@0xsequence/connect` is compatible with `@0xsequence/design-system` v2 * `KitProvider` is now `SequenceConnectProvider` * `KitCheckoutProvider` is now `SequenceCheckoutProvider` * `KitWalletProvider` is now `SequenceWalletProvider` ## Connecting your app ```tsx New theme={null} import './App.css' import { useOpenConnectModal } from '@0xsequence/connect' function App() { const {setOpenConnectModal} = useOpenConnectModal() return ( <> ) } export default App ``` ```tsx Old theme={null} import './App.css' import { useOpenConnectModal } from '@0xsequence/kit' function App() { const {setOpenConnectModal} = useOpenConnectModal() return ( <> ) } export default App ``` ## Tailwind css Web SDK uses Tailwind v4, if you are using Tailwind v3, you need to upgrade. # Getting started Source: https://docs.sequence.xyz/sdk/web/wallet-widget-sdk/getting-started Learn how to get started with Wallet Widget SDK This package is dependent on [Connect SDK](/sdk/web/wallet-sdk/ecosystem/getting-started). Follow the steps [here](/sdk/web/wallet-sdk/ecosystem/getting-started). ```bash theme={null} npm install @0xsequence/wallet-widget # or pnpm install @0xsequence/wallet-widget # or yarn add @0xsequence/wallet-widget ``` ```typescript [main.tsx] theme={null} import React from "react"; import ReactDOM from "react-dom/client"; import "./index.css"; import { config } from "./config"; import App from "./App"; import { SequenceWalletProvider } from "@0xsequence/wallet-widget"; import { SequenceConnect } from "@0xsequence/connect"; function Dapp() { return ( ); } ReactDOM.createRoot(document.getElementById("root")!).render( ); ``` Now you can open the Wallet Widget using the [useOpenWalletModal](/sdk/web/wallet-widget-sdk/hooks/useOpenWalletModal) hook. ```typescript [App.tsx] theme={null} import { injected, useAccount, useConnect } from 'wagmi' import './App.css' import { useOpenWalletModal } from '@0xsequence/wallet-widget' function App() { const { isConnected } = useAccount() const { connect } = useConnect() const { setOpenWalletModal } = useOpenWalletModal() return ( <> {isConnected ? : } ) } export default App ``` Wallet Widget # useOpenWalletModal Source: https://docs.sequence.xyz/sdk/web/wallet-widget-sdk/hooks/useOpenWalletModal Hook for opening the wallet inventory modal ## Import ```tsx theme={null} import { useOpenWalletModal } from '@0xsequence/wallet-widget' ``` ## Usage ```tsx theme={null} import './App.css' import { useOpenWalletModal } from '@0xsequence/wallet-widget' function App() { // Get the function to open/close the wallet modal const { setOpenWalletModal } = useOpenWalletModal() // Function to handle opening the wallet inventory home page const openWalletWidget = () => { setOpenWalletModal(true) // Open the wallet modal to view tokens } // Function to handle opening the wallet inventory swap page const openWalletWidgetSwapPage = () => { setOpenWalletModal(true, { defaultNavigation: { location: 'swap' } }) // Open the wallet modal to view tokens } return (
) } export default App ``` ## Return Type: `UseOpenWalletModalReturnType` The hook returns an object with the following properties: ```tsx theme={null} type UseOpenWalletModalReturnType = { setOpenWalletModal: (isOpen: boolean, options?: WalletOptions) => void openWalletModalState: boolean } ``` ### Properties #### setOpenWalletModal `(isOpen: boolean, options?: WalletOptions) => void` Function to open or close the Wallet modal. **Parameters:** | Parameter | Type | Description | | --------- | --------------- | ------------------------------------------------------------- | | `isOpen` | `boolean` | Whether the modal should be open (`true`) or closed (`false`) | | `options` | `WalletOptions` | Optional settings for the Wallet modal | ```tsx theme={null} interface WalletOptions { defaultNavigation?: Navigation } type Navigation = | BasicNavigation | CoinDetailsNavigation | CollectibleDetailsNavigation | CollectionDetailsNavigation | TransactionDetailsNavigation | SendCoinNavigation | SendCollectibleNavigation | SwapCoinNavigation | SwapCoinListNavigation ``` #### openWalletModalState `boolean` The current open state of the Wallet modal (`true` if open, `false` if closed). ## Notes This hook provides methods to control the Wallet Inventory modal that allows users to view their tokens and NFTs. The Wallet modal displays all tokens, NFTs and collectibles present in the connected wallet. # GetWebhookListener Source: https://docs.sequence.xyz/api-references/indexer/endpoints/default/get-webhook-listener ../indexer.json post /rpc/Indexer/GetWebhookListener # FetchTransactionReceipt Source: https://docs.sequence.xyz/api-references/indexer/endpoints/public/fetch-transaction-receipt ../indexer.json post /rpc/Indexer/FetchTransactionReceipt # FetchTransactionReceiptWithFilter Source: https://docs.sequence.xyz/api-references/indexer/endpoints/public/fetch-transaction-receipt-with-filter ../indexer.json post /rpc/Indexer/FetchTransactionReceiptWithFilter # GetBalanceUpdates Source: https://docs.sequence.xyz/api-references/indexer/endpoints/public/get-balance-updates ../indexer.json post /rpc/Indexer/GetBalanceUpdates # GetNativeTokenBalance Source: https://docs.sequence.xyz/api-references/indexer/endpoints/public/get-native-token-balance ../indexer.json post /rpc/Indexer/GetNativeTokenBalance # GetTokenBalances Source: https://docs.sequence.xyz/api-references/indexer/endpoints/public/get-token-balances ../indexer.json post /rpc/Indexer/GetTokenBalances # GetTokenBalancesByContract Source: https://docs.sequence.xyz/api-references/indexer/endpoints/public/get-token-balances-by-contract ../indexer.json post /rpc/Indexer/GetTokenBalancesByContract # GetTokenBalancesDetails Source: https://docs.sequence.xyz/api-references/indexer/endpoints/public/get-token-balances-details ../indexer.json post /rpc/Indexer/GetTokenBalancesDetails # GetTokenBalancesSummary Source: https://docs.sequence.xyz/api-references/indexer/endpoints/public/get-token-balances-summary ../indexer.json post /rpc/Indexer/GetTokenBalancesSummary # GetTokenSupplies Source: https://docs.sequence.xyz/api-references/indexer/endpoints/public/get-token-supplies ../indexer.json post /rpc/Indexer/GetTokenSupplies # GetTokenSuppliesMap Source: https://docs.sequence.xyz/api-references/indexer/endpoints/public/get-token-supplies-map ../indexer.json post /rpc/Indexer/GetTokenSuppliesMap # GetTransactionHistory Source: https://docs.sequence.xyz/api-references/indexer/endpoints/public/get-transaction-history ../indexer.json post /rpc/Indexer/GetTransactionHistory # SubscribeBalanceUpdates Source: https://docs.sequence.xyz/api-references/indexer/endpoints/public/subscribe-balance-updates ../indexer.json post /rpc/Indexer/SubscribeBalanceUpdates # SubscribeEvents Source: https://docs.sequence.xyz/api-references/indexer/endpoints/public/subscribe-events ../indexer.json post /rpc/Indexer/SubscribeEvents # SubscribeReceipts Source: https://docs.sequence.xyz/api-references/indexer/endpoints/public/subscribe-receipts ../indexer.json post /rpc/Indexer/SubscribeReceipts # AddWebhookListener Source: https://docs.sequence.xyz/api-references/indexer/endpoints/secret/add-webhook-listener ../indexer.json post /rpc/Indexer/AddWebhookListener # GetAllWebhookListeners Source: https://docs.sequence.xyz/api-references/indexer/endpoints/secret/get-all-webhook-listeners ../indexer.json post /rpc/Indexer/GetAllWebhookListeners # PauseAllWebhookListeners Source: https://docs.sequence.xyz/api-references/indexer/endpoints/secret/pause-all-webhook-listeners ../indexer.json post /rpc/Indexer/PauseAllWebhookListeners # RemoveWebhookListener Source: https://docs.sequence.xyz/api-references/indexer/endpoints/secret/remove-webhook-listener ../indexer.json post /rpc/Indexer/RemoveWebhookListener # ResumeAllWebhookListeners Source: https://docs.sequence.xyz/api-references/indexer/endpoints/secret/resume-all-webhook-listeners ../indexer.json post /rpc/Indexer/ResumeAllWebhookListeners # ToggleWebhookListener Source: https://docs.sequence.xyz/api-references/indexer/endpoints/secret/toggle-webhook-listener ../indexer.json post /rpc/Indexer/ToggleWebhookListener # UpdateWebhookListener Source: https://docs.sequence.xyz/api-references/indexer/endpoints/secret/update-webhook-listener ../indexer.json post /rpc/Indexer/UpdateWebhookListener # Indexer Installation Source: https://docs.sequence.xyz/api-references/indexer/installation Sequence Indexer is a simple API to query any blockchain token and NFT data. Below are instructions on how to integrate the Sequence Indexer API into your Webapps, Games, and backends. In case you missed it, please also see the [Indexer Overview](/api-references/indexer/overview). ## Installation The Sequence Indexer is built as a HTTP API with RPC endpoints that you may call directly from your Webapp, Game or server backend. Below you'll find information on the RPC endpoint schema with sample curl commands, along with examples in both Javascript/Typescript and Go. We provide SDKs for [Web / node.js](https://github.com/0xsequence/sequence.js) and [Go](https://github.com/0xsequence/go-sequence). Or if you'd like to integrate the Indexer with another language target, simply follow the API reference below to implement the HTTP requests. Additionally, read the Typescript client source code as [reference implementation of the Indexer API client](https://github.com/0xsequence/sequence.js/blob/master/packages/services/indexer/src/indexer.gen.ts) as well. ### Web / node.js Installation ```bash npm theme={null} npm install 0xsequence ethers ``` or ```bash pnpm theme={null} pnpm install 0xsequence ethers ``` or ```bash yarn theme={null} yarn add 0xsequence ethers ``` This code requires an API Access Key from [Sequence Builder](https://sequence.build). ```ts theme={null} import { SequenceIndexer } from '@0xsequence/indexer' // see https://docs.sequence.xyzhttps://status.sequence.info for list of // indexer hosts for the chain you'd like to query const indexer = new SequenceIndexer('https://mainnet-indexer.sequence.app', 'AQAAAAAAAF_JvPALhBthL7VGn6jV0YDqaFY') // see examples below for the kinds of queries you can make const tokenBalances = await indexer.getTokenBalances(...) ``` **NOTE:** if you're using `@0xsequence/indexer` from node.js, we recommend using node v18.x or newer.
### Go Installation ```bash Terminal theme={null} go get -u github.com/0xsequence/go-sequence@latest ``` then in your app, ```go Go theme={null} import ( "github.com/0xsequence/go-sequence/indexer" ) // see https://docs.sequence.xyzhttps://status.sequence.info for list of // indexer hosts for the chain you'd like to query seqIndexer := indexer.NewIndexer("https://polygon-indexer.sequence.app", "AQAAAAAAAF_JvPALhBthL7VGn6jV0YDqaFY") // see examples below for the kinds of queries you can make accountAddress := "ACCOUNT_ADDRESS" includeMetadata := true metadataOptions := indexer.MetadataOptions{ VerifiedOnly: true, } _, tokenBalances, err := seqIndexer.GetTokenBalances(context.Background(), &accountAddress, nil, nil, &includeMetadata, &metadataOptions, nil, nil) ``` ### Unity or Unreal Installation The Sequence Indexer is integrated directly inside of the respective [Sequence Unity](/sdk/unity/) and [Sequence Unreal](/sdk/unreal/overview) SDKs. # Indexer Source: https://docs.sequence.xyz/api-references/indexer/overview The Sequence Indexer is a backend web3 service that makes it easy to query real-time blockchain state such as token balances, history, supplies and NFT metadata. The Indexer automatically indexes every ERC20, ERC721 and ERC1155 token from Ethereum-compatible chains. The Sequence Indexer is a powerful tool that can be used to build wallets, apps, and games that need to query on-chain data. It is designed to be fast, reliable, and easy to use. It leverages the [Sequence Node Gateway](/api-references/node-gateway) which monitors nodes health, intelligently routes requests to the available nodes and caches the most recent request responses. This means that Node providers going down are no longer a problem, as the Node Gateway will automatically route to a healthy provider making sure that Indexer always stays at the top of the chain with no downtime. The other benefit of using the Indexer is that it is using built in-house, next-generation, LSM-tree based databases to store the data. It makes it super fast to query and index data. The data is available in real-time with low latency. You can query it using a simple REST API or one of our SDKs. The Indexer API allows you to query all token balances, history and other information for all Ethereum compatible chains. In order to make it one go to place for all your token data needs, we have included [Sequence Metadata](/api-references/metadata/overview) support for all tokens. This means that you can easily render tokens in your apps, games, or wallets without the need to fetch metadata from a separate API. In fact, the Sequence Wallet uses the Indexer behind the scenes so it can seamlessly render all token information in any wallet. But of course, the Indexer is a modular piece of infrastructure, and you may use it directly from your app, game, or even from a server. **Features:** * Super-fast API to query all token balances, history, metadata and NFTs with multi-chain support * Real-time indexing of ERC20, ERC721 and ERC1155 transactions across EVM-compatible chains * Automatically detects all tokens on the chain, without the need for a contract registry * Resilient to node failures and chain re-organizations * Easily listen for specific events and transactions on-chain accurately with a simple API * Built-in token / nft metadata support to easily render tokens in your apps / games * High uptime and availability ## Supported Networks & Endpoints You can see the [full list of supported networks here](https://status.sequence.info). ## Getting Started Here are a few example queries you can make to a blockchain from your app, game, or wallet: * [Fetch all tokens & NFTS in any wallet including all metadata](/api-references/indexer/examples/fetch-tokens) * [Fetch the transaction history for any wallet address](/api-references/indexer/examples/transaction-history) * [Fetch all unique tokens in a particular ERC20/721/1155 contract, including total supplies](/api-references/indexer/examples/unique-tokens) * [What is the total token supply of an ERC20 token? What is the total token supply of all the ERC1155 tokens in a particular contract?](/api-references/indexer/examples/unique-tokens) * [Fetch the transaction history for any token contract address](/api-references/indexer/examples/transation-history-token-contract) * [Listen to transactions for particular tokens/contracts/addresses via webhooks](/api-references/indexer/examples/webhook-listener) # Overview Source: https://docs.sequence.xyz/api-references/overview Overview of the various APIs available for integrating with the Sequence developer platform. ## Authentication Most Sequence APIs require authentication using either: * **Project Access Key**: For client-side requests, these are listed as `public`. * **Service Token**: For server-side requests that require elevated permissions, these require passing a secret bearer token and listed as `secret`. You can generate these credentials in the [Sequence Builder](https://sequence.build) dashboard. ## Rate Limits API rate limits vary by tier and available MAUs. Check your project settings in the Sequence Builder dashboard for your specific limits. # Overview Source: https://docs.sequence.xyz/sdk/go/overview Go SDK documentation for the Sequence infrastructure stack for web3 gaming. ## Go A complete Sequence SDK is also available in Go: [https://github.com/0xsequence/go-sequence](https://github.com/0xsequence/go-sequence). [go-sequence](https://github.com/0xsequence/go-sequence) is the equivalent of [0xsequence](https://github.com/0xsequence/sequence.js) but for Go / Golang backends. In fact, all of Sequence's infrastructure is written in Go and is built with [go-sequence](https://github.com/0xsequence/go-sequence). ## ethkit As part of the Sequence open source tools, our team has also built [ethkit](https://github.com/0xsequence/ethkit), which is an Ethereum dev toolkit for Go backends. [ethkit](https://github.com/0xsequence/ethkit) supports EOA wallets, and you can think of it like `ethers.js` but for Go. # Embedded Wallet Account Federation Source: https://docs.sequence.xyz/sdk/headless-wallet/account-federation The content provides detailed information on implementing the ability to federate and link single or multiple wallets to a main embedded wallet session, describing best practices when combined with ephemeral guest wallets to be converted to permanent on-chain embedded wallets. Sequence Embedded Wallets offered enable the ability to federate multiple social accounts to a single wallet address. This enables experiences to have a single on-chain address, while allowing users to access the wallet through multiple points of identity authentication. An important feature of Embedded Wallet Account Federation is that these wallets will aggregate based on the first signed-in login provider, whether authenticated via social, email, or a guest wallet. This means the wallet address is based on the first signed-in wallet and subsequent sign-in's will link to that initial wallet. When a federated account has been connected to a main account, logging out and individually using that previously linked account will yield the same address into the future. ## Social Provider Account Federation The following allows a developer to initiate an authentication using `initAuth` using the [same parameters as the first signed-in session on the `WaaS` object](/sdk/headless-wallet/use-wallets#authenticated-embedded-wallet) with an additional guest or social provider, where the provider `challenge` is returned and passed to the `linkAccount` function: ```ts theme={null} const challenge = await sequence.initAuth({/* same params as signIn function */}) const linkResponse = await sequence.linkAccount(challenge) ``` ## Email One-Time Password Account Federation Using the one-time password email approach to authenticate requires the password sent to the users' email to be passed into the challenge, and called via the `linkAccount` function: ```ts theme={null} const challenge = await sequence.initAuth({ email }) // if the linking account is email then you need to provide the answer (code) const linkResponse = await sequence.linkAccount(challenge.withAnswer(code)) ``` ## Account Federation with Guest Wallets It is common practice for games to enable a user to sign-in within the background of an application with a [guest wallet](/sdk/headless-wallet/authentication#guest-embedded-wallet), have that wallet stored in the cache by the SDK, then later prompt the user for a social login provider to link to the first initial wallet using one of the [previously explained approaches](/sdk/headless-wallet/account-federation#embedded-wallet-account-federation). Therefore, if assets have been accumulated in the wallet, transactions performed on-chain, or signatures have been saved, the wallet can have continuity. Using a guest wallet first approach can enable a user to try a game or experience invisibly, before authenticating for the long term and smoothing the onboarding process. Developers can use the above methodologies once a guest is authenticated in order to ensure the user can reaccess their account going forward. ## List Accounts Calling `listAccounts` will return an object with the following: an array of `accounts` object(s) (with `id`, `type`, and `issuer`), as well as the `currentAccountId`, for example: `"Guest:0x0104...`: ```ts theme={null} import { SequenceWaaS } from "@0xsequence/waas"; const sequence = new SequenceWaaS( { projectAccessKey: `${process.env.VITE_PROJECT_ACCESS_KEY}`, waasConfigKey: `${process.env.VITE_WAAS_CONFIG_KEY}`, network: "arbitrum-nova", } ) ... // authentication const response = await sequence.listAccounts() console.log(response.accounts) console.log(response.currentAccountId) ``` ## Removing accounts You can also remove accounts from the list of accounts previously associated with your configuration: ```ts theme={null} // Call list accounts const accounts = await sequence.listAccounts(); const accountId = accounts[0].id; // Get the ID of the first account try { await sequence.removeAccount(accountId); } catch (error) { console.error('Failed to remove account:', error); } ``` # Initialization and Authentication Source: https://docs.sequence.xyz/sdk/headless-wallet/authentication The Authentication feature in Embedded Wallets simplifies account management, authentication, and session control for your application. * [**Initialize SDK**](/sdk/headless-wallet/authentication#initialize-sdk): Initialize the SDK with your project access key and Embedded Wallet Tenant key. * [**Authenticating Users**](/sdk/headless-wallet/authentication#authentication-methods): Ensure the SDK is initialized with a social, email or guest wallet via one of our offered sign-in options to begin using WaaS functions. * [**Retrieve User information from Social**](/sdk/headless-wallet/authentication#retrieve-user-information-from-social-providers): Retrieve user data from social provider authentication methods. ## Install SDK ```bash pnpm theme={null} pnpm install @0xsequence/waas ``` ```bash npm theme={null} npm install @0xsequence/waas ``` ```bash yarn theme={null} yarn add @0xsequence/waas ``` ## Initialize SDK The Embedded Wallet can be initialized using a Social Authentication `OAuth` token (or [PlayFab `ticket`](/sdk/headless-wallet/authentication#authenticating-with-playfab)), email, or as an ephemeral `Guest Wallet` for providing wallet functions. Before you can use the Sequence WaaS SDK, you need to obtain the following configuration keys from the Sequence Builder: * `WaaSConfigKey`: This key can be learned about [here](/solutions/builder/embedded-wallet/configuration) * `ProjectAccessKey`: This key can be learned about [here](/solutions/builder/embedded-wallet/configuration) And initialize the SDK in the following way, which we recommend in a `config.ts` file: ```ts config.ts theme={null} import { SequenceWaaS } from "@0xsequence/waas"; export const sequence = new SequenceWaaS( { projectAccessKey: `${process.env.VITE_PROJECT_ACCESS_KEY}`, waasConfigKey: `${process.env.VITE_WAAS_CONFIG_KEY}`, network: "arbitrum-nova", } ); ``` Then, choose your approach to authenticate your users: * [Authentication with Social Provider](/sdk/headless-wallet/authentication#social-provider-authentication) * [Authentication via Email](/sdk/headless-wallet/authentication#email-authentication) * [Authentication as a Guest](/sdk/headless-wallet/authentication#guest-embedded-wallet) Enable Email (Legacy), Stytch, and Guest Wallets, by directing yourself to [the Early Access Page](https://sequence.build/earlyaccess) and enable it via the toggle. ## Authentication Methods Signing in and signing up are the same operation; the account is automatically created if it doesn't already exist which will also instantiate a web3 wallet for the user automatically. ### Social Provider Authentication In order to authenticate your users with a social provider, you can simply retrieve the [JWT](https://jwt.io/introduction) `idToken` (or PlayFab ticket) from the social auth method, usually looking in the form of `eyJh...` if it's an `OAuth` token and pass to it the `signIn` function: ```typescript App.tsx theme={null} await sequence.signIn({ idToken }, "Session name"); ``` For more examples on authenticating with specific providers, please ensure your embedded wallet [configuration](/sdk/headless-wallet) is setup with the corresponding auth provider. Then reference the example implementation: * [Authentication with PlayFab](/sdk/headless-wallet/authentication#authenticating-with-playfab) * [Authentication with Google](/sdk/headless-wallet/authentication#authenticating-with-google) * [Authentication with Stytch](/sdk/headless-wallet/authentication#authenticating-with-stytch) * [Authentication with X (Twitter)](/sdk/headless-wallet/authentication#authenticating-with-x-twitter) ### Email Authentication The Embedded Wallet SDK can enable developers to pass an email and initiate an Embedded Wallet session based on the successful answer of a One-Time Password. The feature enables: * **Direct Email Support**: The SDK supports email sign-in when the key is generated with email scope. * **Secure User Flow**: After providing a user email, the Embedded Wallet Nitro API sends a One-Time Password (OTP) to this email. * **Authentication**: Enter the One-Time Password into the SDK to obtain an user wallet. ```ts theme={null} import { SequenceWaaS } from '@0xsequence/waas' const sequence = new SequenceWaaS({ projectAccessKey: `${process.env.VITE_PROJECT_ACCESS_KEY}`, waasConfigKey: `${process.env.VITE_WAAS_CONFIG_KEY}`, network: 'arbitrum-nova' }) sequence.onEmailAuthCodeRequired(async (respondWithCode: any) => { // you can now store the `respondWithCode` callback somewhere and call it when user submits the code from email // it may return error and be retried for maximum 3 times, while this is happening the promise returned from `signIn` is still pending await respondWithCode(otpCode) }) const emailResponse = await sequence.signIn({ email }) ``` ```json theme={null} { "sessionId": "0x63A21cCa14ed7454B9cF6466af422B5c597c6b57", "wallet": "0xd6043fe6f06d90ec2cB36cA5CD1B193A8515f350", "email": "email@domain" } ``` ### Guest Embedded Wallet The Guest wallet allows you to create an ephemeral wallet and authenticate a user without requiring them to login with a social provider or email, however is not retrievable if associated app data is deleted. You can enable Guest Wallets by directing yourself to [the Early Access Page](https://sequence.build/earlyaccess) and enable it via the toggle. To create a guest wallet, pass in a boolean `guest` key set to `true`, which will create an ephemeral wallet for use in the application with all Embedded Wallet functions possible. ```typescript App.tsx theme={null} await sequence.signIn({ guest: true }, "Session name"); ``` Assets stored in the guest wallet after a browser cache has been cleared - or if the user has uninstalled the app - will not be accessible by the user. In order to protect your users ensure that after any value has been transferred or is available for the user to claim, that you prompt the user to sign in with a social provider to ensure asset continuity. ### Check if a User is Signed-In A user session can be checked to see if they are logged in with the following function call: ```ts theme={null} if (await sequence.isSignedIn()){ ... // logged in } else { ... // not logged in } ``` ### Retrieving authenticated email When the WaaS object is called upon to sign in a user using an `idToken`, the email address of the user authenticated is returned in an `email` property of the returned object: ```typescript theme={null} const { email } = await sequence.signIn({ idToken }, "Session name") ``` ### Account Federation If a user tries to authenticate with the same credentials across different providers, for example the same address for email and Google, you will receive a conflict as a callback `sequence.onEmailConflict` that the account already exists to handle for your application. In this case, you may choose how you would like to address this: 1. Inform the user the account already exists and prompt them to login with the previous authentication method. Users can then link their accounts through [Account Federation](/sdk/headless-wallet/account-federation#embedded-wallet-account-federation) to utilize different authentication providers. This ensures a single address across multiple providers. 2. Alternatively, you can also run the async `forceCreate` function in the callback. The warning that an account already exists will be ignored and a second, separate wallet address will be created for the user that affiliated with the different login provider. Utilizing the `onEmailConflict` callback with `forceCreate` to create a second wallet for the user: ```typescript theme={null} const forceCreateFuncRef = useRef<(() => Promise) | null>(null); sequence.onEmailConflict(async (info, forceCreate) => { forceCreateFuncRef.current = forceCreate; // Optionally choose to force create a second wallet for the user setEmailConflictInfo(info); // Set the conflict info to inform the user setIsEmailConflictModalOpen(true); // Display a modal to inform the user what to do that an account exists }); ``` ## Authenticating with Specific Social Providers ### Authenticating with Playfab In order to leverage Playfab for authentication, you must first retrieve a Playfab Ticket. This can be done by calling the API directly or leveraging a Playfab client SDK. Then simply pass your configured titleId as well as a unique user identifier as a `CustomId`. For example, the an example call is below: ```ts theme={null} const playfabResponse = PlayFabClient.LoginWithCustomID({ TitleId: titleId, CustomId: "", CreateAccount: true, }) ``` Once you have retrieved a valid session ticket from Playfab, simply pass this to the sequence `signIn` function as a parameter to authenticate the user and create a valid session: ```ts theme={null} const response = await sequence.signIn( { playFabTitleId: import.meta.env.VITE_PLAYFAB_TITLE_ID, playFabSessionTicket: playfabResponse.data.SessionTicket }, 'playfab session' ) ``` It is important to ensure that the title ID that is configured in builder matches the title ID that is passed to PlayFab, otherwise you will receive an `Invalid Verifier` error. You can use a variety of unique user information as a parameter to pass to Playfab to retrieve the session ticket such as a user's accessToken from Google or a custom username. ### Authenticating with Google For example in React, we can leverage the `@react-oauth/google` package in order to generate an `idToken` and pass it to Sequence: Begin with a simple `main.tsx` file that sets up the WaaS SDK, the router, and the Google OAuth provider. ```ts theme={null} import { SequenceWaaS } from '@0xsequence/waas' import { GoogleOAuthProvider } from '@react-oauth/google' import { createHashRouter, RouterProvider } from 'react-router-dom' const sequence = new SequenceWaaS({ projectAccessKey: `${process.env.VITE_PROJECT_ACCESS_KEY}`, waasConfigKey: `${process.env.VITE_WAAS_CONFIG_KEY}`, network: 'arbitrum-nova' }) export const router = createHashRouter([ { path: '/login', element: }, { path: '/', element: } ]) ReactDOM.createRoot(document.getElementById('root')!).render( ) ``` Then we use the **`GoogleLogin`** component from the **`@react-oauth/google`** package for Google authentication. Once authenticated we trigger the **`handleGoogleLogin`** function when a user successfully logs into Google. ```ts theme={null} import { router, sequence } from './main' import { CredentialResponse, GoogleLogin } from '@react-oauth/google' function Login() { const [signingIn, setSigningIn] = useState(false) useEffect(() => { (async () => { if (await sequence.isSignedIn()) { router.navigate('/') } })() }, []) const handleGoogleLogin = async (tokenResponse: CredentialResponse) => { const walletAddress = await sequence.signIn({ idToken: tokenResponse.credential! }, "MacBook Pro - Chrome") console.log(`Wallet address: ${walletAddress}`) router.navigate('/') } return ( {(<> )} ) } export default Login ``` ### Authenticating with Stytch Ensure you [complete the configuration details](/sdk/headless-wallet/authentication#authenticating-with-stytch) for Stytch prior. You can see an example application in react with stytch [here](https://github.com/0xsequence-demos/stytch-embedded-wallet-react-boilerplate/tree/master) with example keys for testing. ### Implementation We will simply retrieve an `idToken` and pass that into the Embedded Wallet SDK. To do this for the signed in session for web using `@stytch/react`, use the following package `browser-cookies` to retrieve the `stytch_session_jwt` from the cookies after the callback once the redirect has been completed: ```typescript theme={null} import { SequenceWaaS } from '@0xsequence/waas' import cookies from 'browser-cookies' ... export const sequence = new SequenceWaaS({ projectAccessKey: `${process.env.VITE_PROJECT_ACCESS_KEY}`, waasConfigKey: `${process.env.VITE_WAAS_CONFIG_KEY}`, network: "arbitrum-nova", }); const idToken = cookies.get('stytch_session_jwt') await sequence.signIn({ idToken }, "Stytch Session name"); ``` ### Authenticating with X (Twitter) Ensure you [complete the configuration details](/solutions/builder/embedded-wallet/x-configuration) for X (Twitter) prior. To authenticate a user with X (formerly Twitter), you first need to obtain an access token through their OAuth 2.0 flow. Due to some complexities with X's API, we recommend using the Sequence X Auth Proxy as detailed in the configuration guide. Once you have the user's access token, you can pass it to the `signIn` method using the `xAccessToken` property: ```typescript theme={null} const response = await sequence.signIn({ xAccessToken: 'THE_USER_X_ACCESS_TOKEN' }, 'X session'); ``` Unlike other providers that use an `idToken` (OIDC), for X auth you will need to provide an `xAccessToken`. Please refer to the [X (Twitter) configuration guide](/solutions/builder/embedded-wallet/x-configuration) for more details. ## Retrieve User information from Social Providers Based on the way that your application is configured from perspective of the Authentication Providers, you have the option to parse user details that can be shared with applications to be integrated in some way. For example, as a simple way to create social inclusion of profiling in your experience, you can reference Profile photos used already within the respective ecosystems: Google & Apple. The following are details included in the returned JWT's: #### Google JWT Parsing `idToken` Contents * `iss` (aka Issuer) (string) - The issuer of the token. For tokens from Google, this is usually a URL like [https://accounts.google.com](https://accounts.google.com) or something similiar. * `azp` (aka Authorized party) (string) - The client ID of the authorized presenter. This claim is used in Google OAuth 2.0 to identify the party using the token. * `aud` (aka Audience) (string) - Intended audience of the token. Typically, this is your application's client ID. * `sub` (aka Subject) (string) - The unique identifier for the user. It is intended to be used to identify the user across multiple systems. * `hd` (aka Hosted Domain) (string) - It means that the user who has authenticated is from the respective domain. * `email` (string) - The user's email address, as registered in the authentication service. * `email_verified` (boolean) (string) - A boolean representing whether the email address has been verified as genuine. * `nonce` (string) - A string used to associate a client session with an ID token and to mitigate replay attacks. * `name` (string) - The full name of the user as registered in the authentication service. * `picture` (string) - URL of the user's profile picture. * `given_name` (string) - The user's first name. * `family_name` (string) - The user's last name. * `iat` (aka Issued at) (number) - The timestamp when the token was issued, represented in Unix time (seconds since Jan 1, 1970). * `exp` (aka Expiration time) (number) - The expiration timestamp of the token, beyond which the token should not be considered valid. #### Apple JWT Parsing `idToken` Contents * `iss` (string) - The issuer registered claim identifies the principal that issues the identity token. Because Apple generates the token, the value is [https://appleid.apple.com](https://appleid.apple.com). * `sub` (string) - The subject registered claim identifies the principal that's the subject of the identity token. Because this token is for your app, the value is the unique identifier for the user. * `aud` (string) - The audience registered claim identifies the recipient of the identity token. Because the token is for your app, the value is the client\_id from your developer account. * `iat` (number) - The issued at registered claim indicates the time that Apple issues the identity token, in the number of seconds since the Unix epoch in UTC. * `exp` (number) - The expiration time registered claim identifies the time that the identity token expires, in the number of seconds since the Unix epoch in UTC. The value must be greater than the current date and time when verifying the token. * `nonce` (string) - A string for associating a client session with the identity token. This value mitigates replay attacks and is present only if you pass it in the authorization request. * `nonce_supported` (boolean) - A Boolean value that indicates whether the transaction is on a nonce-supported platform. If you send a nonce in the authorization request, but don't see the nonce claim in the identity token, check this claim to determine how to proceed. If this claim returns true, treat nonce as mandatory and fail the transaction; otherwise, you can proceed treating the nonce as optional. * `email` (string) - A string value that represents the user's email address. The email address is either the user's real email address or the proxy address, depending on their private email relay service. This value may be empty for Sign in with Apple at Work & School users. For example, younger students may not have an email address. * `email_verified` (string || boolean) - A string or Boolean value that indicates whether the service verifies the email. The value can either be a string ("true" or "false") or a Boolean (true or false). The system may not verify email addresses for Sign in with Apple at Work & School users, and this claim is "false" or false for those users. * `is_private_email` (string || boolean) - A string or Boolean value that indicates whether the email that the user shares is the proxy address. The value can either be a string ("true" or "false") or a Boolean (true or false). * `real_user_status` (number) - An Integer value that indicates whether the user appears to be a real person. Use the value of this claim to mitigate fraud. The possible values are: 0 (or Unsupported), 1 (or Unknown), 2 (or LikelyReal). This claim is present only in iOS 14 and later, macOS 11 and later, watchOS 7 and later, tvOS 14 and later. The claim isn't present or supported for web-based apps. * `transfer_sub` (string) - A string value that represents the transfer identifier for migrating users to your team. This claim is present only during the 60-day transfer period after you transfer an app. #### Example JS Code for Parsing ```typescript theme={null} function parseJwt(token) { try { // Split the token into its three parts const parts = token.split('.'); if (parts.length !== 3) { throw new Error('JWT token must consist of three parts'); } // The payload is the second part. We decode it from base64 URL encoding. const decodedPayload = atob(parts[1].replace(/_/g, '/').replace(/-/g, '+')); // Parse the decoded payload as JSON const payload = JSON.parse(decodedPayload); // Return the payload object, which includes all the claims return payload; } catch (e) { console.error('Failed to parse JWT:', e); return null; } } // Example usage const token = 'eyJ...'; // Your JWT token here const jwtDetails = parseJwt(token); if (jwtDetails) { console.log('Email:', jwtDetails.email); console.log('Name:', jwtDetails.name); console.log('Picture:', jwtDetails.picture); // Access other fields similarly } ``` # Fee Options Source: https://docs.sequence.xyz/sdk/headless-wallet/fee-options The content provides detailed information on implementing Fee Options for gas fees when sending transactions using an Embedded Wallet with the Sequence stack. When implementing an Embedded Wallet, one will need to be able to pay for the gas fees on a non-testnet network to send a transaction. Fee options provide a quote to cover the gas fees only useable for a certain period of time (which is unique to the Sequence stack). To send a transaction successfully, you have a few directions you can take: * **Testnets**: Using a testnet, transactions with Sequence are free, not requiring a fee option inputted into the SDK call. * **Sponsored Contract or Wallet**: Having the smart contract or wallet sponsored, not requiring a fee option inputted into the SDK call. You can learn about sponsoring a contract or wallet [here](/solutions/builder/gas-sponsorship.mdx). * **Fee Options**: Using a Sequence API to get a custom fee quote and fee options object, pass both into the waas sdk call. [See below](/sdk/headless-wallet/fee-options#implementing-fee-options). You will know if you need to either sponsor your contract or wallet, or, implement fee options if you receive the following response from the WaaS API: ```shell theme={null} { "error": "WebrpcEndpoint", "code": 0, "msg": "endpoint error", "cause": "sending transaction: WebrpcEndpoint 0: endpoint error: failed to send transaction: Aborted 1005: Request aborted: failed to relay transaction: Aborted 1005: Request aborted: refusing to dispatch: missing required fee payment", "status": 400 } ``` ## Implementing Fee Options Before implementing the following "Fee Options" flow, you will need to ensure that your wallet has sufficienct funds to pay for your transaction on the specific network in the native currency. You can either transfer tokens to your wallet, or, use the [on-ramp feature](/sdk/web/wallet-sdk/embedded/guides/on-ramp) using the Web SDK solution. And ensure that the following packages are installed: ```shell theme={null} pnpm install @0xsequence/waas ethers ``` To implement fee options passed into the request, a first call to `sequence.feeOptions({...})` is required, which is wrapped in the following function `checkTransactionFeeOptions`: In the following examples, the `sequence` variable is an Embbeded Wallet object intialized from the `@0xsequence/waas` npm package with the `WaasConfigKey` and `ProjectAccessKey`. Learn how to do this [here](/sdk/headless-wallet/quickstart) ```typescript theme={null} import { FeeOption, Network, Transaction } from "@0xsequence/waas" .... async function checkTransactionFeeOptions({transactions, network}: {transactions: Transaction[], network: string | number }): Promise<{feeQuote: string | undefined, feeOptions: FeeOption[] | undefined, isSponsored: boolean}> { const resp = await sequence.feeOptions({ transactions: transactions, network: network, }) if (resp.data.feeQuote && resp.data.feeOptions) { return {feeQuote: resp.data.feeQuote, feeOptions: resp.data.feeOptions, isSponsored: false} } return {feeQuote: resp.data.feeQuote, feeOptions: resp.data.feeOptions, isSponsored: true} } ``` #### Implementing an ERC20 Transaction ```typescript theme={null} import { ethers } from 'ethers' import { erc20 } from '@0xsequence/waas' ... const response = await checkTransactionFeeOptions({ transactions: [erc20({ token: customTokenAddress, to: destinationAddress, value: ethers.parseUnits(amount, decimals).toString() })], network: 'arbitrum-nova' // i.e. network or chainID e.g. 42170 }) const tx = await sequence.sendERC20({ token: customTokenAddress, to: destinationAddress, value: ethers.parseUnits(amount, decimals), network: 'arbitrum-nova', transactionsFeeOption: response.feeOptions, transactionsFeeQuote: response.feeQuote }) ``` #### Implementing an ERC1155 / ERC721 Transaction For ERC721 just replace `erc1155({...})` with `erc721({...})` and call `sequence.sendERC721({...})` ```typescript theme={null} import { ethers } from 'ethers' import { erc1155, erc721 } from '@0xsequence/waas' ... const response = await checkTransactionFeeOptions({ transactions: [erc1155({ token: customTokenAddress, to: destinationAddress, values: [{ id: tokenID, amount: ethers.parseUnits(amount, 0) }] })], network: 'arbitrum-nova' // i.e. network or chainID e.g. 42170 }) const tx = await sequence.sendERC1155({ token: customTokenAddress, to: destinationAddress, values: [{ id: tokenID, amount: ethers.parseUnits(amount, 0) }], network: 'arbitrum-nova', transactionsFeeOption: response.feeOptions, transactionsFeeQuote: response.feeQuote }) ``` #### Implementing an Native Currency Transaction ```typescript theme={null} import { ethers } from 'ethers' const to = '0x...' const response = await checkTransactionFeeOptions({ transactions: [{ to, value: ethers.parseEther(amount), }], network: 'arbitrum-nova' }) const tx = await sequence.sendTransaction({ transactions: [{ to, value: ethers.parseEther(amount), }], network: 'arbitrum-nova', transactionsFeeOption: feeOption, transactionsFeeQuote: feeQuote }) ``` #### Implementing a Custom Contract Transaction ```typescript theme={null} import { delayedEncode } from '@0xsequence/waas' ... const response = await checkTransactionFeeOptions({ transactions: [delayedEncode({ to: contractAddress, abi: contractAbi, func: contractMethod, // e.g. "transfer" args: JSON.parse(contractMethodArgs), // e.g. [0x..., 1000] or named { "to": "0x...", "amount": "1000" } value: "0" })], network: 'arbitrum-nova' }) const tx = await sequence.callContract({ network: 'arbitrum-nova', to: contractAddress, abi: contractAbi, func: contractMethod, // e.g. "transfer" args: JSON.parse(contractMethodArgs), value: 0, transactionsFeeOption: response.feeOption, transactionsFeeQuote: response.feeQuote }) ``` # Headless Wallet Session Management — Sequence Docs Source: https://docs.sequence.xyz/sdk/headless-wallet/manage-sessions The Session Management feature in Auth + Embedded Wallet simplifies account management, authentication, and session control for your application. A valid session is opened during the Authentication process. Sequence Auth and Embedded Wallet handles the following aspects of your application: * [Check Valid Session](/sdk/headless-wallet/manage-sessions#validation-status): Manage blockchain accounts to sign up or sign in users. * [Control Session Validation](/sdk/headless-wallet/manage-sessions#control-session-validation): Authentication sessions to return important details to be consumed by your application to enhance the experience of games and applications. * [Close Session](/sdk/headless-wallet/manage-sessions#close-session): Manage the listing and dropping of sessions handled by the WaaS stack. ## Validation status To check the validation status of the current session, use the `isSessionValid` method. This returns `true` for email login and trusted social logins and `false` for custom logins until email validation is complete. ```ts theme={null} const isValid = await sequence.isSessionValid(); console.log(isValid); ``` ``` true ``` ### Trigger session validation Manually trigger a session validation with the `validateSession` method. This will send a code to the user's email. If validated within 10 minutes, the method returns `true`; otherwise, it returns `false`. ```ts theme={null} const result = await sequence.validateSession(); ``` ``` true ``` Once user receives the code, he can validate the session with the `finishValidateSession` method that takes the code as an argument. If the code is valid, the method returns `true`; otherwise, it returns `false`. ```ts theme={null} const result = await sequence.finishValidateSession("123456"); ``` ``` true ``` ### **Control Session Validation** The **`onValidationRequired`** callback is used to determine the need for session validation during actions like sending transactions or signing messages. If the callback returns **`true`**, it triggers session validation. If it returns **`false`**, the related action is cancelled. This mechanism ensures that only validated sessions can proceed with sensitive operations. ```ts theme={null} const tx = await sequence.sendERC20({ validation: { onValidationRequired: () => true, }, chainId: 42161, token: "0x6b175474e89094c44da98b954eedeac495271d0f", // DAI to: "0x27CabC9700EE6Db2797b6AC1e1eCe81C72A2cD8D", // Recipient value: "200000000000000000000", // 200 DAI }); ``` ### Listen for session validations Events like transaction sends may silently prompt session validation. Use the `onValidationRequired` hook to catch such instances. ```ts theme={null} sequence.onValidationRequired(() => { console.log("Session has been triggered for validation"); }); await sequence.sendTransaction({ chainId: 1 }, { to: "0x...", value: "1" }); ``` ``` Session has been triggered for validation ``` ## Manage Automatic session validation Automatic session validation occurs during actions that require validation. Manage this process using the onValidationRequired hook. ```ts theme={null} const tx = await sequence.sendTransaction({ chainId: 1, validation: { onValidationRequired: () => { console.log("Session has been triggered for validation"); return true; }, }, to: "0x061150e5574716DBb1a2cdf54b3DcE9F94395f65", value: "1", }); ``` By returning `true` or `false` from the `onValidationRequired` hook, you either continue or cancel the action, respectively. ## Close Session A session can be closed using the `id` of the session. Any session can be closed from any device with an active session. ```ts theme={null} import { SequenceWaaS } from '@0xsequence/waas' const sequence = new SequenceWaaS({ projectAccessKey: `${process.env.VITE_PROJECT_ACCESS_KEY}`, waasConfigKey: `${process.env.VITE_WAAS_CONFIG_KEY}`, network: 'arbitrum-nova' }) await sequence.signIn({ idToken }, "MacBook Pro - Chrome") const sessions = await sequence.listSessions() await sequence.dropSession({ sessionId: sessions[0].id }) ``` # On-ramp Source: https://docs.sequence.xyz/sdk/headless-wallet/on-ramp The on-ramp feature allows developers to integrate the Embedded Wallet with Web SDK, enabling users to easily purchase fiat currency using a credit or debit card through a simplified react component. Since the Embedded Wallet product can be integrated with [Web SDK](/sdk/web/overview), a developer can allow their users to purchase fiat via a credit or debit card with the use of a simplified react component. Integration steps can be found [here](/sdk/web/wallet-sdk/embedded/guides/on-ramp) # Headless Wallet Quickstart Source: https://docs.sequence.xyz/sdk/headless-wallet/quickstart Connect your users to your App with the Sequence Embedded Wallet. For Unreal or Unity integration, go to [Unreal](/sdk/unreal/wallets/embedded-wallet/setup) or [Unity](/sdk/unity/installation). Run the following from your terminal to clone the starter repo. ```bash Javascript theme={null} npx sequence-cli boilerplates create-email-embedded-wallet-react-starter ``` Select use Test Keys. Navigate to `localhost:4444` and enter your email to try out the authentication. Visit Sequence Builder and [configure your embedded wallet](/solutions/builder/embedded-wallet/configuration) to get keys specific to your project and authenticate your users. Simply replace the existing configuration keys in the .env file. Now that you have a working authentication, you can take look at our examples for the most common functions: * [Sign messages](/sdk/headless-wallet/use-wallets#sign-messages) * [Send transactions](/sdk/headless-wallet/use-wallets#send-transactions) * [Call contracts](/sdk/headless-wallet/use-wallets#call-any-contract) * [Verify a user on your backend](/sdk/headless-wallet/verification#prerequisite-deployment-of-a-parent-wallet) We are using example variables in the .env file, so we recommend creating a project on [Sequence Builder](https://sequence.build/project/default/wallet/embedded-wallet) and [setting up your own wallet configuration](/sdk/headless-wallet) and update the environment variables to use more social providers for authentication, customize email templates, and more. # Transaction receipts Source: https://docs.sequence.xyz/sdk/headless-wallet/transaction-receipts The content explains the generation of transaction receipts for successful and failed transactions. **Transaction Receipts:** Transactions return receipts indicating success or failure. Failed receipts are generated without transaction execution. **Successful Transaction Response:** A successful transaction provides a SentTransactionResponse. Always verify this response with the **`isSentTransactionResponse`** type guard before accessing the transaction hash. ```ts theme={null} import { Sequence, isSentTransactionResponse } from "@0xsequence/waas"; const waas = new SequenceWaaS( { projectAccessKey: `${process.env.PROJECT_ACCESS_KEY}`, waasConfigKey: `${process.env.WAAS_CONFIG_KEY}`, network: "arbitrum-nova", } ); await waas.signIn({ idToken }, "Session name"); const tx = await waas.sendTransaction({ chainId: 42161, transactions: [ { to: "0xD72C236Be524Ec24F72329317e2785E687105B69", value: "0", }, ], }); if (isSentTransactionResponse(tx)) { console.log(tx); } ``` **Understanding Transaction Details** **Fields in Transaction Responses:** * **txHash**: The hash of the transaction sent to the network. * **receipt.logs**: Logs emitted during the transaction. * **receipt.status**: Indicates if the transaction SUCCEEDED or FAILED. * **receipt.revertReason**: Explains why a transaction was reverted, if applicable. ```json theme={null} { "code": "transactionReceipt", "data": { "txHash": "0xf2e9f728abd65089f25efda5852e605ced377f4e2c89dbf143b124623ed09b2c", "metaTxHash": "acc36ed4ef40db74137266e48d863083a5c7e85e2735d69adafcb5b362b6cfc0", "nativeReceipt": { ... }, "receipt": { "id": "acc36ed4ef40db74137266e48d863083a5c7e85e2735d69adafcb5b362b6cfc0", "index": 0, "logs": [ { "address": "0x4d4EE1b8583e31fe789eAF2e1b6e011C220c10B6", "data": "0x0000000000000000000000001119e72b4af230becebd933d0e07f0eec51d8c2a0000000000000000000000000000000000000000000000000000000000000001", "topics": [ "0x1f180c27086c7a39ea2a7b25239d1ab92348f07ca7bb59d1438fcf527568f881" ] }, { "address": "0x4d4EE1b8583e31fe789eAF2e1b6e011C220c10B6", "data": "0x0000000000000000000000000000000000000000000000000000000000000000", "topics": [ "0x5c4eeb02dabf8976016ab414d617f9a162936dcace3cdef8c69ef6e262ad5ae7", "0xacc36ed4ef40db74137266e48d863083a5c7e85e2735d69adafcb5b362b6cfc0" ] } ], "receipts": [ ... ], "revertReason": null, "status": "SUCCEEDED" }, "request": { ... }, "simulations": [ ... ] } } ``` ## Failed transaction response An In-Game Wallet pre-empts failing transactions by simulating them on the network before actual submission. If the simulation fails, the transaction is not sent, and a FailedTransactionResponse is returned. ```ts theme={null} import { Sequence, isSentTransactionResponse } from "@0xsequence/waas"; const waas = new SequenceWaaS( { projectAccessKey: `${process.env.PROJECT_ACCESS_KEY}`, waasConfigKey: `${process.env.WAAS_CONFIG_KEY}`, network: "arbitrum-nova", } ); await waas.signIn({ idToken }, "Session name"); const tx = await waas.sendTransaction({ chainId: 137, transactions: [ { // This address always fails on Polygon, give it a try :D to: "0x839eE023B21f4Ffe2294025DE0AC30Ba7278D6Fd", value: "0", }, ], }); if (isSentTransactionResponse(tx)) { // ... This will never be executed } else { // tx can only be `SentTransactionResponse` or `FailedTransactionResponse` console.log(tx); } ``` ```json theme={null} { "code": "transactionFailed", "data": { "error": "This is an error message", "request": { "code": "sendTransaction", "expires": 1699443005, "identifier": "ts-sdk-1699442705965-0x153824576D03629b264683B430bBF9AcEA1d0975", "issued": 1699442705, "network": "137", "transactions": [ { "data": "0x", "to": "0x839eE023B21f4Ffe2294025DE0AC30Ba7278D6Fd", "type": "transaction", "value": "0x00" } ], "wallet": "0x4d4EE1b8583e31fe789eAF2e1b6e011C220c10B6" }, "simulations": [ { "executed": true, "gasLimit": 7908, "gasUsed": 5931, "reason": "This is an error message :)", "result": null, "succeeded": false } ] } } ``` # Using your Embedded Wallet Source: https://docs.sequence.xyz/sdk/headless-wallet/use-wallets The content provides detailed instructions on using the Sequence WaaS SDK for wallet management and transactions. Once the user has been authenticated, you can now utilize common web3 functions to interact with the blockchain - completely seamlessly. * [**Get Wallet Address**](/sdk/headless-wallet/use-wallets#get-wallet-address): Access the wallet linked to the user's authenticated account. This wallet serves as the gateway to all account functions. * [**Sign Messages**](/sdk/headless-wallet/use-wallets#sign-messages): Signing a message using the embedded wallet. * [**Send Transactions**](/sdk/headless-wallet/use-wallets#send-transactions): After a user has been authenticated, use the WaaS SDK to send transactions using crafted EVM calldata. ### Get Wallet Address Each user's wallet address is unique, cannot be changed, and is 42 characters long, starting with `0x`: ```ts theme={null} import { SequenceWaaS } from "@0xsequence/waas"; const sequence = new SequenceWaaS( { projectAccessKey: `${process.env.VITE_PROJECT_ACCESS_KEY}`, waasConfigKey: `${process.env.VITE_WAAS_CONFIG_KEY}`, network: "arbitrum-nova", } ); const { wallet } = await sequence.signIn({ idToken }, "Session name") const address = await sequence.getAddress(); console.log(address == wallet) // true console.log(address) ``` ``` 0xE4b10c53aa75E19E088cfDD0cff7D46a0E4206F0 ``` ### Sign Messages Wallets can sign messages, which can be validated both onchain and offchain: ```ts theme={null} import { SequenceWaaS } from "@0xsequence/waas"; const sequence = new SequenceWaaS( { projectAccessKey: `${process.env.PROJECT_ACCESS_KEY}`, waasConfigKey: `${process.env.WAAS_CONFIG_KEY}`, network: "arbitrum-nova", } ); await sequence.signIn({ idToken }, "Session name"); const signature = await sequence.signMessage({ chainId: 42170, message: "Hello world", }); console.log(signature); ``` ```json theme={null} { "code": "signedMessage", "data": { "message": "0x48656c6c6f20776f726c64", "signature": "0x0100010000000002012128ff2dd168dc250dc3da93db3131f737e6961a0000fe0100030000000006010001000074000197013331090a763fc7ef2216502cfbff5d855530f977a0ee6db3615722ed9bad498781d8ed72d52b5c9717708ac757f7789c9567e5468566179bd03f72d1fc7b1c010400002c01011111b16c6268897233eddea98a041b326b0faef2010122229ce37ccfee1cbab2b743b22c314b5667cf1a06020001000074000100deb9091f5beb1ebd8d91a1b81e562a70cdb3a1cdafc5e61087b18d1c221c570754ecbe056bdef5f82c388a9bf53f074521aeaf5afdeed3a2ba70adb89362631b010400002c0101444444444444444444444444444444444444444401015555555555555555555555555555555555555555030100a5a91b133336e5ef1c7e23c13974535018fab1c0" } } ``` ## Send Transactions All wallets can send transactions right after creation. No extra steps are required to create the wallet, as all users have a wallet by default. At any point when sending a transaction that requires a fee on a network, you can follow the Fee Options walkthrough for how to send a fee object alongside your transaction or cover gas fees for your users [found here](/sdk/headless-wallet/fee-options). ### Raw transaction * **Immediate Transactions:** Wallets are ready to send transactions immediately upon creation. * **Raw Transactions:** Specify transaction parameters such as recipient, value, and data. Gas limits and nonce are managed automatically. * **Network Requirements:** Transactions require specifying a **`chainId`** for the intended network., for example `1` for Ethereum mainnet, `42161` for Arbitrum, etc. Error Handling: Use `isSentTransactionResponse` to verify transactions before execution to prevent failures. WaaS checks that a transaction won't fail before it runs. If it does fail, you'll get an error message instead of a transaction receipt. See more in [transaction receipts](/sdk/headless-wallet/transaction-receipts). ```ts theme={null} import { Sequence, isSentTransactionResponse } from "@0xsequence/waas"; const sequence = new SequenceWaaS( { projectAccessKey: `${process.env.PROJECT_ACCESS_KEY}`, waasConfigKey: `${process.env.WAAS_CONFIG_KEY}`, network: "arbitrum-nova", } ); await sequence.signIn({ idToken }, "Session name"); const tx = await sequence.sendTransaction({ chainId: 42161, transactions: [ { to: "0x27CabC9700EE6Db2797b6AC1e1eCe81C72A2cD8D", value: "200000000000000000000", // 200 ETH data: "0x9fa2b3c4", }, ], }); if (isSentTransactionResponse(tx)) { console.log(tx); } ``` ```json theme={null} { "code": "transactionReceipt", "data": { "txHash": "0xf2e9f728abd65089f25efda5852e605ced377f4e2c89dbf143b124623ed09b2c", "metaTxHash": "acc36ed4ef40db74137266e48d863083a5c7e85e2735d69adafcb5b362b6cfc0", "nativeReceipt": { ... }, "receipt": { ... }, "request": { ... }, "simulations": [ ... ], } } ``` ### Send ERC20 Tokens Helper methods are available for common operations, such as sending ERC20 tokens. This automatically handles the `data` field of the transaction: ```ts theme={null} import { Sequence, isSentTransactionResponse } from "@0xsequence/waas"; const sequence = new SequenceWaaS( { projectAccessKey: `${process.env.PROJECT_ACCESS_KEY}`, waasConfigKey: `${process.env.WAAS_CONFIG_KEY}`, network: "mumbai", }, defaults.TEST ); await sequence.signIn({ idToken }, "Session name"); const tx = await sequence.sendERC20({ chainId: 42161, token: "0x6b175474e89094c44da98b954eedeac495271d0f", // DAI to: "0x27CabC9700EE6Db2797b6AC1e1eCe81C72A2cD8D", // Recipient value: "200000000000000000000", // 200 DAI }); if (isSentTransactionResponse(tx)) { console.log(tx); } ``` ```json theme={null} { "code": "transactionReceipt", "data": { "txHash": "0x1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3", "metaTxHash": "01a087979dccbbc49a45b72d987e5651d65bd97349ccbfdd601b0b7beee9ddc4", "nativeReceipt": { ... }, "receipt": { ... }, "request": { ... }, "simulations": [ ... ], } } ``` ### Send ERC721 Tokens Sending ERC721 tokens has a helper method. This automatically handles the `data` field of the transaction: ```ts theme={null} import { Sequence, isSentTransactionResponse } from "@0xsequence/waas"; const sequence = new SequenceWaaS( { projectAccessKey: `${process.env.PROJECT_ACCESS_KEY}`, waasConfigKey: `${process.env.WAAS_CONFIG_KEY}`, network: "arbitrum-nova", } ); await sequence.signIn({ idToken }); const tx = await sequence.sendERC721({ chainId: 42161, token: "0xF87E31492Faf9A91B02Ee0dEAAd50d51d56D5d4d", // Decentraland LAND to: "0x27CabC9700EE6Db2797b6AC1e1eCe81C72A2cD8D", // Recipient id: "33347671958251969419410711528313284722562", // Asset ID }); if (isSentTransactionResponse(tx)) { console.log(tx); } ``` ```json theme={null} { "code": "transactionReceipt", "data": { "txHash": "0x4936962d9972a70bffc27f376f55d9c60c12e762819fa6384fdb466664122b6e", "metaTxHash": "e6513a60b63359a365f0d3f05744d89823278ec829fc5cb4d275bb815d0f5887", "nativeReceipt": { ... }, "receipt": { ... }, "request": { ... }, "simulations": [ ... ], } } ``` ### Send ERC1155 Tokens Sending ERC1155 tokens is also supported: ```ts theme={null} import { Sequence, isSentTransactionResponse } from "@0xsequence/waas"; const sequence = new SequenceWaaS( { projectAccessKey: `${process.env.PROJECT_ACCESS_KEY}`, waasConfigKey: `${process.env.WAAS_CONFIG_KEY}`, network: "arbitrum-nova", } ); await sequence.signIn({ idToken }); const tx = await sequence.sendERC1155({ chainId: 137, token: "0x631998e91476da5b870d741192fc5cbc55f5a52e", // Skyweaver assets values: [ { id: "66547", // Asset ID value: "200", // Amount for this asset }, { id: "68572", value: "1000", }, ], }); ``` ### Call any Contract Use **`callContract`** to interact with any contract method, either through a function signature or ABI, supporting both named and positional arguments. ### Function Signature Providing a function signature is the easiest way to call a contract method, as it doesn't require an ABI. The function signature can be provided with named parameters or positional parameters. ##### Named Arguments ```ts theme={null} const tx = await sequence.callContract({ to: "0x503388C73Ca663eA34e103c11C9F47C9433af471", // Contract address abi: "mint(address to, uint256 tokenId)", // Function signature func: "mint", // Function name args: { to: "0xf439e432d54c2Bf5518A1901D3791070d4192986", tokenId: "1", }, value: 0, // Value to send }); ``` ##### Positional Arguments Notice that passing a named function signature with positional arguments is allowed. ```ts theme={null} const tx = await sequence.callContract({ to: "0x503388C73Ca663eA34e103c11C9F47C9433af471", // Contract address abi: "mint(address,uint256)", // Function signature func: "mint", // Function name args: ["0xf439e432d54c2Bf5518A1901D3791070d4192986", "1"], value: 0, // Value to send }); ``` #### ABI Providing an ABI is more verbose, but allows for more flexibility, as a single ABI can be used to call multiple methods. ABIs support named arguments and positional arguments. ```ts theme={null} const abi = `[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}]`; const tx = await sequence.callContract({ to: "0x6b175474e89094c44da98b954eedeac495271d0f", // Contract address abi: abi, // ABI func: "transfer", // Function name args: { _to: "0xf439e432d54c2Bf5518A1901D3791070d4192986", _value: "1", }, value: 0, // Value to send }); ``` **Transaction Permissions:** * **Email Accounts:** Transactions are enabled after the current session is confirmed via a link sent to the email or phone. * **Social Login Accounts:** Accounts like Google and Facebook can transact immediately after sign-in. * For more details, see [session management validation](/sdk/headless-wallet/manage-sessions#session-management). # Privy & Sequence Source: https://docs.sequence.xyz/sdk/headless-wallet/use-with-privy Learn how to use Privy as a signer for your Sequence Smart Wallet. In this guide, you'll learn how to use the core `sequence.js` libraries to seamlessly integrate Privy with Sequence, enabling your users to sign in and interact with your app through a Sequence Smart Wallet. This involves creating a Sequence wallet controlled by a user's Privy-managed EOA, and then using that Sequence wallet to send gasless transactions on Base Sepolia. We will be using Next.js 15, React 19, and Tailwind CSS 4. You'll need the Sequence, Privy, and wagmi/viem packages. ```bash theme={null} pnpm install @0xsequence/account @0xsequence/core @0xsequence/network @0xsequence/sessions @0xsequence/signhub @privy-io/react-auth @privy-io/wagmi-connector wagmi @privy-io/wagmi @tanstack/react-query viem ethers ``` You'll need to get a Privy App ID and Client ID. You can get these by creating a new app in the [Privy Dashboard](https://dashboard.privy.io/apps). Create an `.env.local` file in your project root and add your `NEXT_PUBLIC_PRIVY_APP_ID` and `NEXT_PUBLIC_PRIVY_CLIENT_ID`. Set up `WagmiProvider` and `PrivyProvider` in your a `providers.tsx` file. We do this to allow our app to use both Privy for authentication and wagmi for wallet interactions. ```tsx [providers.tsx] theme={null} 'use client' import { type PrivyClientConfig, PrivyProvider } from '@privy-io/react-auth' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { createConfig, WagmiProvider } from '@privy-io/wagmi' import { baseSepolia } from 'viem/chains' import { http } from 'wagmi' const queryClient = new QueryClient() const wagmiConfig = createConfig({ chains: [baseSepolia], transports: { [baseSepolia.id]: http() } }) const privyConfig: PrivyClientConfig = { embeddedWallets: { requireUserPasswordOnCreate: true, showWalletUIs: true }, loginMethods: ['wallet', 'email', 'google'], appearance: { showWalletLoginFirst: true }, defaultChain: baseSepolia } const APP_ID = process.env.NEXT_PUBLIC_PRIVY_APP_ID const CLIENT_ID = process.env.NEXT_PUBLIC_PRIVY_CLIENT_ID export default function Providers({ children }: { children: React.ReactNode }) { return ( {children} ) } ``` Wrap the App's layout with the Providers. ```tsx [layout.tsx] theme={null} import type { Metadata } from 'next' import { Geist, Geist_Mono } from 'next/font/google' import './globals.css' import Providers from './providers' const geistSans = Geist({ variable: '--font-geist-sans', subsets: ['latin'] }) const geistMono = Geist_Mono({ variable: '--font-geist-mono', subsets: ['latin'] }) export const metadata: Metadata = { title: 'Privy + Sequence', description: 'A demo showcasing how Sequence can be used with Privy' } export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) { return ( {children} ) } ``` Add the following types to `./constants/types.ts`. ```tsx [./constants/types.ts] theme={null} export type FlatTransaction = { to: string value?: string data?: string gasLimit?: string delegateCall?: boolean revertOnError?: boolean } export type TransactionsEntry = { subdigest?: string wallet: string space: string nonce: string chainId: string transactions: FlatTransaction[] } ``` Create a `StaticSigner` class in `./utils/StaticSigner.ts`. ```tsx [./utils/StaticSigner.ts] theme={null} import type { commons } from '@0xsequence/core' import type { signers } from '@0xsequence/signhub' import { type BytesLike, ethers } from 'ethers' type TransactionBundle = commons.transaction.TransactionBundle type SignedTransactionBundle = commons.transaction.SignedTransactionBundle type IntendedTransactionBundle = commons.transaction.IntendedTransactionBundle export class StaticSigner implements signers.SapientSigner { private readonly signatureBytes: Uint8Array private readonly savedSuffix: Uint8Array constructor( private readonly address: string, private readonly signature: string ) { const raw = ethers.getBytes(this.signature) // Separate last byte as suffix this.savedSuffix = raw.slice(-1) this.signatureBytes = raw.slice(0, -1) } async buildDeployTransaction(): Promise { return undefined } async predecorateSignedTransactions(): Promise { return [] } async decorateTransactions( og: IntendedTransactionBundle ): Promise { return og } async sign(): Promise { return this.signatureBytes } notifyStatusChange(): void {} suffix(): BytesLike { return this.savedSuffix } async getAddress() { return this.address } } ``` We need a couple of utility methods. Add this file in `./utils/index.ts`. ```tsx [index.ts] theme={null} import { Account } from '@0xsequence/account' import { trackers } from '@0xsequence/sessions' import { commons } from '@0xsequence/core' import { Orchestrator, signers } from '@0xsequence/signhub' import { allNetworks } from '@0xsequence/network' import type { FlatTransaction, TransactionsEntry } from '../constants/types' import { ethers } from 'ethers' import { StaticSigner } from './StaticSigner' export const TRACKER = new trackers.remote.RemoteConfigTracker( 'https://sessions.sequence.app' ) export const NETWORKS = allNetworks /** * Creates a new Sequence Account with the specified threshold and signers. * * @param threshold - The minimum weight required to authorize transactions. * @param signers - An array of signer objects with address and weight. * @returns A Promise that resolves to the created Account instance. */ export async function createSequenceAccount( threshold: number, signers: { address: string; weight: number }[] ): Promise { const account = await Account.new({ config: { threshold, // By default a random checkpoint is generated every second checkpoint: 0, signers: signers }, tracker: TRACKER, contexts: commons.context.defaultContexts, orchestrator: new Orchestrator([]), networks: NETWORKS }) return account } /** * Converts an array of FlatTransaction objects to Sequence Transaction objects. * * @param txs - Array of FlatTransaction objects to convert. * @returns An array of Sequence Transaction objects. */ export function toSequenceTransactions( txs: FlatTransaction[] ): commons.transaction.Transaction[] { return txs.map(toSequenceTransaction) } /** * Converts a FlatTransaction object to a Sequence Transaction object. * * @param tx - The FlatTransaction object to convert. * @returns The corresponding Sequence Transaction object. */ export function toSequenceTransaction( tx: FlatTransaction ): commons.transaction.Transaction { return { to: tx.to, value: tx.value ? BigInt(tx.value) : undefined, data: tx.data, gasLimit: tx.gasLimit ? BigInt(tx.gasLimit) : undefined, delegateCall: tx.delegateCall || false, revertOnError: tx.revertOnError || false } } /** * Creates an Account instance for a given address and optional signatures. * * @param args - Object containing the address and optional signatures array. * @returns An Account instance configured with the provided signers. */ export function accountFor(args: { address: string signatures?: { signer: string; signature: string }[] }) { const signers: signers.SapientSigner[] = [] if (args.signatures) { for (const { signer, signature } of args.signatures) { const signatureArr = ethers.getBytes(signature) if ( signatureArr.length === 66 && (signatureArr[64] === 0 || signatureArr[64] === 1) ) { signatureArr[64] = signatureArr[64] + 27 } signers.push(new StaticSigner(signer, ethers.hexlify(signatureArr))) } } return new Account({ address: args.address, tracker: TRACKER, contexts: commons.context.defaultContexts, orchestrator: new Orchestrator(signers), networks: NETWORKS }) } /** * Computes the digest for a given TransactionsEntry. * * @param tx - The TransactionsEntry containing transaction details. * @returns The digest string for the transactions. */ export function digestOf(tx: TransactionsEntry): string { return commons.transaction.digestOfTransactions( commons.transaction.encodeNonce(tx.space, tx.nonce), toSequenceTransactions(tx.transactions) ) } /** * Computes the subdigest for a given TransactionsEntry. * * @param tx - The TransactionsEntry containing transaction details. * @returns The subdigest string for the transactions. */ export function subdigestOf(tx: TransactionsEntry): string { const digest = digestOf(tx) return commons.signature.subdigestOf({ digest, chainId: tx.chainId, address: tx.wallet }) } /** * Converts Sequence Transactionish objects to an array of FlatTransaction objects. * * @param wallet - The wallet address associated with the transactions. * @param txs - The Sequence Transactionish object(s) to convert. * @returns An array of FlatTransaction objects. */ export function fromSequenceTransactions( wallet: string, txs: commons.transaction.Transactionish ): FlatTransaction[] { const sequenceTxs = commons.transaction.fromTransactionish(wallet, txs) return sequenceTxs.map((stx) => ({ to: stx.to, value: stx.value?.toString(), data: stx.data?.toString(), gasLimit: stx.gasLimit?.toString(), delegateCall: stx.delegateCall, revertOnError: stx.revertOnError })) } /** * Recovers the signer addresses from an array of signatures and a subdigest. * * @param signatures - Array of signature strings to recover signers from. * @param subdigest - The subdigest string used for recovery. * @returns An array of objects containing the signer address and signature. */ export function recoverSigner( signatures: string[], subdigest: string ): { signer: string; signature: string }[] { const res: { signer: string; signature: string }[] = [] for (const signature of signatures) { try { const r = commons.signer.recoverSigner(subdigest, signature) res.push({ signer: r, signature: signature }) } catch (e) { console.error('Failed to recover signature', e) } } return res } ``` ```tsx [page.tsx] theme={null} "use client" import { usePublicClient, useSignMessage } from "wagmi" import { accountFor, createSequenceAccount, subdigestOf, toSequenceTransactions } from "./utils" import { useState, useEffect } from "react" import { commons } from "@0xsequence/core" import { ethers } from "ethers" import { zeroAddress } from "viem" import { usePrivy } from "@privy-io/react-auth" const CHAIN_ID = 84532 export default function Home() { const { ready, authenticated, login, logout, user } = usePrivy() const publicClient = usePublicClient({ chainId: CHAIN_ID }) const { signMessageAsync } = useSignMessage() const [walletAddress, setWalletAddress] = useState<`0x${string}` | null>(null) const [txHash, setTxHash] = useState(null) const [loadingSendTx, setLoadingSendTx] = useState(false) const [isWalletDeployed, setIsWalletDeployed] = useState(false) const [checkingWalletDeployed, setCheckingWalletDeployed] = useState(true) useEffect(() => { const createWallet = async () => { if (user?.wallet && user.wallet.address) { const seqeunceAccount = await createSequenceAccount(1, [ { address: user.wallet.address, weight: 1 }, ]) const accountWithSig = accountFor({ address: seqeunceAccount.address, }) const status = await accountWithSig.status(CHAIN_ID) const wallet = accountWithSig.walletForStatus(CHAIN_ID, status) setCheckingWalletDeployed(true) const hasCode = await publicClient?.getCode({ address: accountWithSig.address as `0x${string}` }) setCheckingWalletDeployed(false) if (!hasCode) { wallet.deploy() // Wait for the wallet to be deploy, most of the times it takes less than 4 seconds await new Promise((resolve) => setTimeout(resolve, 4000)) } setWalletAddress(wallet.address as `0x${string}`) setIsWalletDeployed(true) setCheckingWalletDeployed(false) } else { setWalletAddress(null) setTxHash(null) } } createWallet() }, [user]) const handleSend = async () => { if (!user?.wallet?.address || !walletAddress) return setLoadingSendTx(true) const txs = [ { to: zeroAddress, data: "0x", value: "0", revertOnError: true }, ] const txe = { wallet: walletAddress, space: Date.now().toString(), nonce: "0", chainId: CHAIN_ID.toString(), transactions: txs, } const subdigest = subdigestOf(txe) const digestBytes = ethers.getBytes(subdigest) const signature = await signMessageAsync({ message: { raw: digestBytes } }) const suffixed = signature + "02" const account = accountFor({ address: walletAddress, signatures: [ { signer: user.wallet.address as `0x${string}`, signature: suffixed }, ], }) const sequenceTxs = toSequenceTransactions(txs) const status = await account.status(CHAIN_ID) const wallet = account.walletForStatus(CHAIN_ID, status) const signed = await wallet.signTransactions( sequenceTxs, commons.transaction.encodeNonce(txe.space, txe.nonce) ) const relayer = account.relayer(CHAIN_ID) const relayed = await relayer.relay(signed) setTxHash(relayed?.hash || null) setLoadingSendTx(false) } if (!ready) return (
Loading Privy...
) return (
{isWalletDeployed ? (
Smart Wallet Address
{walletAddress}
) : (
{checkingWalletDeployed ? (
Checking if wallet is deployed...
) : (
Deploying Sequence Smart Wallet...
)}
)} {walletAddress && ( )} {txHash && (
Transaction Hash
{txHash}
)}
) } ```
```bash theme={null} pnpm dev ```
# Headless Wallet Verification Source: https://docs.sequence.xyz/sdk/headless-wallet/verification The content provides a detailed guide on verifying ownership of an Embedded Wallet address using a nonce and optional time expiry. A common use case is that you authenticate the user on the client, but you want to also validate this token as well as corresponding user information on your backend. In this case, Sequence provides a function to retrieve a JWT which can be verified using your JWT library of choice for your given framework. Below we outline an example using Typescript and an express server. If you're not using the Embedded Wallet with TypeScript but instead working with the Web SDK, you can go [here](/sdk/web/wallet-sdk/embedded/guides/verification) to see how to handle the verification process. An example client & server demonstrating the below is available [here](https://github.com/0xsequence-demos/embedded-wallet-verify-session) ### Implementation Once a user has authenticated with an embedded wallet on the client, simply call the corresponding function in order get a JWT from Sequence. ```typescript theme={null} // Using Sequence.js const { idToken } = await sequence.getIdToken(); ``` Make a POST request to your backend with the queried JWT. ```typescript theme={null} const response = await fetch(BACKEND_ENDPOINT, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ sequenceToken: idToken }), }); ``` From our express server that the JWT was passed to, we simply import our preferred JWT library to verify the information and initialize our JWKS to verify against. It is also important to ensure that your expected audience is set correctly so that the claim will be properly verified. ```typescript theme={null} import * as jwt from "jsonwebtoken"; import * as jwksClient from "jwks-rsa"; ...serverConfig // Initialize the JWKS client const client = jwksClient({ jwksUri: "https://waas.sequence.app/.well-known/jwks.json", cache: true, cacheMaxAge: 86400000, // 1 day }); // Should be equal to the audience claim in the JWT that you want to verify which will be of the form https://sequence.build/project/*projectID* const EXPECTED_AUDIENCE = "https://sequence.build/project/*PROJECT_ID*" ``` Now we can parse the JWT, verify it against our JWKS URI, then validate any of the claims. ```typescript theme={null} const decodedToken = jwt.decode(token, { complete: true }); if (!decodedToken || typeof decodedToken === "string") { throw new Error("Invalid token"); } const kid = decodedToken.header.kid; const signingKey = await getSigningKey(kid); const publicKey = ( signingKey as jwksClient.CertSigningKey | jwksClient.RsaSigningKey ).getPublicKey(); console.log(EXPECTED_AUDIENCE); const verified = jwt.verify(token, publicKey, { algorithms: ["RS256"], // Specify the expected algorithm audience: EXPECTED_AUDIENCE, // Verify the audience claim }); // Verifying Email claim if (!verified.email || typeof verified.email !== "string") { throw new Error("Invalid email claim"); } ``` From here, you now have verified the information corresponding to the JWT and can safely update your backend as needed. # Mobile SDK for Embedded Wallet (React Native) Source: https://docs.sequence.xyz/sdk/mobile This content provides detailed instructions on integrating the Sequence Embedded Wallet SDK with React Native for complete wallet and indexer integration. The Sequence Embedded Wallet SDK can be used with React Native for complete Sequence [Embedded Wallet](/solutions/wallets/developers/embedded-wallet/overview) and [Indexer](/api-references/indexer/overview) integration. You can see a full example of how to use the SDK or download the template in the [Embedded Wallet React Native Demo](https://github.com/0xsequence/demo-waas-react-native) repository. ## Video Preview