# Architecture Overview
Source: https://docs.getpara.com/v2/concepts/architecture
An introduction to Para's architecture and core components
Para provides a robust and secure architecture for creating and managing universal embedded wallets across various blockchain
ecosystems. This overview introduces the key components and features of Para's design, setting the stage for a deeper
dive into its technical aspects.
## Core Concepts
Para's architecture leverages several key concepts:
1. **Multi-Party Computation (MPC) Key Management**: Para uses a 2-of-2 MPC system for secure key management, comprising
a User Share and a Cloud Key.
2. **Passkey**: This separate key leverages hardware secure enclaves while maintaining blockchain compatibility.
3. **Distributed Key Generation (DKG)**: Ensures that the full private key is never assembled in a single location.
4. **Passkeys and WebAuthn**: Implements the WebAuthn standard for enhanced security.
5. **Permissions Framework**: Allows granular control over transaction signing across multiple applications.
These components work together to provide a secure, flexible, and user-friendly wallet solution that can be embedded in
various applications across different platforms and blockchain ecosystems.
## Explore Para's Architecture
Dive deeper into specific aspects of Para's architecture and functionality:
Learn about Para's innovative approach to key management using MPC and hardware secure enclaves.
Explore the various security features that protect user assets and data in Para wallets.
Understand how Para enables secure wallet recovery in case of device loss or other issues.
Learn about Para's approach to universal embedded wallets and cross-application experiences.
Find answers to common technical questions about Para's architecture and functionality.
By leveraging these architectural components and features, Para provides a comprehensive solution for developers to
implement secure, user-friendly universal embedded wallets in their applications across various platforms and blockchain
ecosystems.
# Key Management System
Source: https://docs.getpara.com/v2/concepts/key-management
An in-depth look at Para's innovative approach to secure key management using MPC and hardware secure enclaves
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
Para's Key Management System forms the core of its security architecture, employing advanced cryptographic techniques to
safeguard user assets while ensuring usability across various platforms and blockchain ecosystems. At its heart is a
distributed (MPC) system that leverages (DKG) and distributed signing. This innovative approach ensures that user keys are never stored in a single
vulnerable location, and neither applications nor Para itself can access users' private keys, providing a robust
foundation for secure, non-custodial wallet management.
## Key Components
Para's key management system relies on a 2-of-2 MPC system comprised of three main components:
1. MPC Key 1: User Share
2. MPC Key 2: Para Share
3. Passkey
### User Share
The User Share is custodied by the user and acts like a hot wallet. It is accessible in the browser or on the user's
device, providing immediate control over assets while interacting with crypto applications.
### Cloud Share
The Cloud Share is managed by Para and stored securely in cloud hardware-security modules (HSMs). This setup provides a
secure off-device backup of the user's key, safeguarding the assets even in the event of device loss or compromise.
### Passkey
The Passkey is a unique feature of Para's system, designed to bridge the gap between device security capabilities and
blockchain requirements.
Most modern smartphones come with hardware secure enclaves, which are dedicated areas within the device's main processor
used for storing and protecting sensitive data. However, these enclaves primarily support the secp256r1 elliptic curve,
which differs from the secp256k1 curve used by most modern blockchains.
To address this, Para generates a separate Passkey. This key is used to authorize access to the Cloud Share, enabling
biometric authentication and signing on the secp256k1 curve. This process ensures users can leverage their device's
hardware security features while interacting seamlessly with blockchain networks.
## Key Generation and Management Process
1. **Distributed Key Generation**: When a user creates a wallet, Para initiates a DKG process. This generates the User
Share and Cloud Share without ever assembling the full private key in one place.
2. **Passkey Creation**: Simultaneously, an Passkey is generated and stored in the device's secure enclave.
3. **Cloud Share Storage**: The Cloud Share is securely stored in Para's HSMs.
4. **User Share Protection**: The User Share is protected by the user's authentication method (e.g., passkey,
biometrics) and stored securely on the device.
## Security Benefits
This key management system offers several security advantages:
* **No Single Point of Failure**: Since the private key is never fully assembled, there's no single point of
vulnerability.
* **Phishing Resistance**: Even if a user's email or social login is compromised, an attacker would still need physical
access to the user's device to initiate transactions.
* **Device Loss Protection**: If a user loses their device, they can still recover their wallet using the Cloud Share
and proper authentication.
* **Censorship Resistance**: Users have the option to export their Cloud Share, ensuring they maintain control over
their assets .
## Flexible Backup Mechanisms
Para supports flexible backup mechanisms and a key-based permissions system, allowing for customized security setups
based on specific application needs. These can be configured in the
By leveraging this advanced key management system, Para provides a secure, flexible, and user-friendly solution for
embedded wallets, balancing robust security with seamless user experience across various blockchain ecosystems.
# Wallet Recovery Process
Source: https://docs.getpara.com/v2/concepts/recovery
A guide to Para's secure wallet recovery mechanism
Para employs a robust recovery mechanism to ensure that wallet access remains resilient to events such as device loss or
phishing attempts. This document outlines the recovery process implemented in Para's infrastructure.
## How Para Enables Recovery
Para's recovery mechanism is designed to maintain user access to funds even if they lose access to their primary device.
This is achieved through a combination of recovery secrets, backup devices, and multi-factor authentication. The
recovery flow is managed through Para's web application, the Para Portal, eliminating the need for individual app
developers to implement their own recovery mechanisms.
When setting up a Para wallet, two key elements are generated:
1. **A unique recovery secret**: This is shared with the user client-side. The application has the option to store this secret. It's important to note that this secret is not related to the 2-of-2 MPC scheme and is solely used for restoring wallet access in case of device loss or theft. Para does not have access to this secret.
2. **A copy of the Cloud Share**: This is shared with the user in the Para Backup Kit. The Cloud Share is part of Para's two-key scheme, providing strong censorship resistance and protection against downtime.
In the event of a lost or stolen device, recovery is possible through two main methods: 1. **Keychain backup**: If
enabled, the key (k1) from the old device can be recovered on a new device. Using this key and the recovery secret,
the user can add a new Passkey (r1) to Para's allow list. 2. **Recovery secret**: If the user has their recovery
secret, they can initiate a recovery attempt via the Para Portal.
After successfully adding a new Passkey, Para prompts the user to perform a key rotation. This process generates an
entirely new set of keys, enhancing the security of the user's account and protecting against potential unauthorized
access to the old keys.
Users have the option to add backup devices (such as a laptop or smartwatch) during the wallet setup process. If a
primary device is lost, the user can log in from one of these backup devices. From there, they can add new devices and
remove lost ones, ensuring uninterrupted access to their wallet.
If the user cannot recover their User Share from their KeyChain backup or a secondary device, they can initiate a key rotation using the recovery key. This process includes:
1. Two-factor authentication (2FA) with their phone number or another multi-factor authentication (MFA) method.
2. This additional step ensures the integrity of the recovery process and protects against impersonation attempts.
## Security Measures
The recovery process requires multiple forms of verification, including the recovery secret and optional 2FA,
enhancing security against unauthorized access attempts.
After recovery, a full key rotation ensures that potentially compromised keys are invalidated, providing an
additional layer of security.
The option to add multiple backup devices provides redundancy and increases the likelihood of successful recovery in
various scenarios.
## Best Practices for Users
Store the recovery secret in a secure, offline location. Never share this secret with anyone, including Para.
Activate two-factor authentication for an additional layer of security during the recovery process.
Add multiple backup devices when possible to increase recovery options.
Periodically verify the ability to access the account from backup devices to ensure they remain functional.
By implementing this comprehensive recovery process, Para ensures that users have a secure and reliable method to regain
access to their wallets, balancing strong security measures with user-friendly processes.
# Security Mechanisms
Source: https://docs.getpara.com/v2/concepts/security
An in-depth exploration of Para's robust security features designed to protect user assets and data
Para employs a multi-layered approach to security, incorporating various mechanisms to protect user assets and data.
This document outlines the key security features implemented in Para's architecture.
## Multi-Party Computation (MPC)
At the core of Para's security is its use of Multi-Party Computation ([MPC](https://blog.getpara.com/what-is-mpc/)) for key management. MPC enhances security by:
* Preventing the entire private key from being in one location
* Eliminating single points of failure
* Enabling secure key generation and transaction signing without exposing the full private key
## Hardware Secure Enclaves
Para leverages hardware secure enclaves available in modern devices for additional security. These enclaves offer:
* A dedicated, isolated environment for sensitive operations
* Hardware-level protection for cryptographic keys
* Secure biometric authentication capabilities
## Passkeys and WebAuthn
Instead of traditional password-based authentication, Para implements the WebAuthn standard to create passkeys. This
approach:
* Eliminates risks associated with password-based authentication
* Leverages device-specific security features
* Provides phishing-resistant authentication
## Distributed Key Generation (DKG)
Para uses Distributed Key Generation to create key shares without ever assembling the full private key. DKG:
* Ensures no single party has access to the complete private key
* Provides protection against key theft during the generation process
* Allows for secure key refresh and rotation
## Permissions Framework
Para implements a sophisticated permissions system to control transaction signing across multiple applications. This
framework:
* Allows granular control over what actions applications can perform
* Mitigates risks associated with compromised applications
* Enables users to manage their wallet's exposure across different apps
## Two-Factor Authentication (2FA)
Para supports 2FA for additional account security, particularly during the wallet recovery process. The 2FA
implementation:
* Is an optional feature that can be enabled by users
* Utilizes time-based one-time passwords (TOTP)
* Adds an extra layer of security for critical operations
## Secure Backup and Recovery
Para provides robust mechanisms for wallet backup and recovery, including:
* Recovery secrets generated during wallet setup
* Support for multiple backup devices
* 48-hour delay for recovery attempts to prevent unauthorized access
* Para Backup Kit for censorship resistance
## Encryption and Secure Communication
All communication between the user's device, Para's servers, and connected applications is encrypted. This includes:
* Use of TLS for all network communications
* End-to-end encryption for sensitive data
* Secure storage of user data with encryption at rest
## Regular Security Audits
Para is committed to maintaining the highest security standards through regular third-party audits. The audit process
includes:
* Periodic audits by reputable security firms
* Comprehensive review of cryptographic implementations
* Continuous monitoring and improvement of security measures
## Censorship Resistance
Para's design ensures that [users maintain control over their assets](https://blog.getpara.com/censorship-resistance-why-its-critical-and-how-were-tackling-it/) even in the event of service disruptions. Measures
include:
* Option for users to export their Cloud Share
* Ability to sign transactions independently if Para services are unavailable
* Decentralized nature of key management prevents single points of failure
By implementing these comprehensive security mechanisms, Para provides a robust framework for protecting user assets and
data. This multi-layered approach ensures that Para-powered wallets remain secure against a wide range of potential
threats while maintaining a seamless user experience.
# Technical FAQ
Source: https://docs.getpara.com/v2/concepts/technical-faq
Frequently asked technical questions about implementing and using Para for developers
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
As you integrate Para into your applications, you may encounter various technical questions. This FAQ aims to address
the most common inquiries from developers, covering aspects of implementation, security, architecture, and integration.
If you don't find the answer you're looking for, our comprehensive documentation and support team are available to
assist you further.
Para uses the DKLS19 MPC algorithm and leverages an for core functions like distributed key generation, signing ceremonies, and non-custodial wallet generation. This ensures a robust and auditable foundation for Para's key management system.
Para uses the EIP712-specified transaction signature interface. Additionally, Para publishes an EIP-1193 Provider,
which is most commonly used via the Wagmi Connector. This ensures compatibility with a wide range of Ethereum-based
applications and tools.
Para uses sessions as a security measure when signing transactions. By default, session length is 90 minutes.
Developers can implement session refresh logic in their applications to maintain longer sessions if required.
While Para primarily uses MPC for key management, it is designed to work with ERC-4337 (Account Abstraction) out of
the box. This allows developers to leverage Para's security features while also taking advantage of AA capabilities if
desired.
As long as the Cloud Share sent during onboarding is not deleted by the user, they can always refresh keys, export, or
sign transactions independently. This design ensures that Para cannot censor transactions and provides a robust
fallback mechanism. Read our blog post on [censorship resistance](https://blog.getpara.com/censorship-resistance-why-its-critical-and-how-were-tackling-it/) for more details.
Para offers SDKs for: - TypeScript/React for web developers - React Native for mobile developers - Flutter for
cross-platform mobile development These SDKs provide a consistent interface for wallet management and transaction
signing across different platforms.
The biometric key is stored on-device in a secure enclave. For Ethereum-based transactions, Para uses secp256k1 curve
signatures. However, the secure enclave supports the secp256r1 curve. Para generates a secp256r1 key, which is used to
authorize a secp256k1 curve signature for ECDSA signatures, bridging this compatibility gap securely.
All UI elements and copy in the Para flow are fully configurable. Developers can whitelabel the product to match their
application's look and feel. While Para aims for a somewhat consistent user experience, copy, colors, and sizes are
fully customizable. Refer to the for detailed configuration options.
Para supports sign-in via Google, Apple, Twitter/X, Discord, and Facebook. This allows developers to offer a range of
authentication options to their users, potentially increasing adoption and ease of use.
Para's multi-app architecture allows the same wallet to be used across different applications while maintaining
security. It uses a permissions scheme that specifies what types of transactions an application can perform and which
ones require user approval. This is implemented through encrypted User Shares specific to each application and an
allow-list mechanism managed by Para.
Para implements a robust recovery mechanism involving: 1. A recovery secret generated during wallet setup 2. Option to
add backup devices 3. Two-factor authentication for additional security 4. A key rotation process after recovery to
ensure security The recovery process is managed through the Para Portal, reducing the implementation burden on
individual developers.
Para's architecture is designed to be blockchain-agnostic. It offers native support for: - All EVM-compatible chains -
Cosmos ecosystem - Solana Developers can integrate Para with popular libraries like ethers.js, viem, and CosmJS for
interacting with these networks. For full chain support please see our [chain support documentation](https://docs.getpara.com/v2/react/guides/custom-chains#additional-chains).
Universal embedded wallets in Para is achieved through:
1. Associating wallets with user identities (typically email addresses) rather than individual applications
2. Using MPC for secure key sharing across applications
3. Implementing a permissions framework for granular access control
4. Providing seamless authentication when users access new applications
Developers can leverage these features through Para's SDKs and APIs to enable users to access their wallets across different applications seamlessly.
Yes, users can export their private keys with Para. While we don't see many users export their private keys given Para wallets are universal and usable across apps and chains, users are able to do so in [Para Connect](https://connect.getpara.com/).
Multi-sigs require separate private keys to approve a transaction. MPC splits a single private key across multiple parties and parites jointly sign without ever reconstructing the key.
For further technical details or questions not covered here, please refer to our documentation or reach out to our
developer support team at .
# Universal Embedded Wallets
Source: https://docs.getpara.com/v2/concepts/universal-embedded-wallets
Exploring Para's approach to universal embedded wallets: portability and seamlessly cross-app
Para [universal embedded wallets](https://blog.getpara.com/universal-embedded-wallets/) allow users to seamlessly use their wallet across different applications and platforms, providing a more fluid and
user-friendly experience in the crypto ecosystem.
## Overview
In the crypto ecosystem, users often need to access the same wallet across various applications. However, this
convenience can pose security risks if not managed properly. Para's multi-app architecture addresses these challenges by
implementing a sophisticated permissions scheme that balances accessibility with security.
Universal embedded wallet functionality is not about transferring assets between wallets, but rather accessing the same wallet from
different applications and platforms.
## Key Components
Para's approach to universal embedded wallet portability leverages its unique architecture and security features:
Para associates wallets with user identities (typically email addresses) rather than individual applications
A granular permissions system ensures that applications only have the access they need, enhancing security in a
multi-app context
Users can log in to new applications using their Para credentials, automatically gaining access to their existing
universal embedded wallet
Para's MPC-based key management allows for secure key sharing across applications without exposing the full private key.
This implementation ensures that users can easily and securely use their Para universal embedded wallets across multiple applications while
maintaining strong security and privacy controls.
## Benefits
1. * Access the same wallet across multiple applications without complex key exports
2. * No need to manage multiple wallets or perform
3. * Consistent user experience across different platforms
4. * Permissions for transparent security and granular access confrol
1. * Easier onboarding of users who already have a Para universal embedded wallet
2. * Access to richer transaction history and liquidity from shared wallets
3. * Easily craft multi-app experiences and build an ecosystem
4. * request specific permissions based on the application's needs.
## Universal Embedded Wallets vs. Traditional Approaches
To understand the advantages of Para's wallet portability, let's compare it with traditional approaches:
| Feature | Third-Party Wallets | Traditional Embedded Wallets | Universal Embedded Wallets |
| ---------------------------------- | :-----------------: | :--------------------------: | :------------------------: |
| Portable across apps | ✔️ | | ✔️ |
| Smooth in-app UX | | ✔️ | ✔️ |
| Integrated with app functionality | | ✔️ | ✔️ |
| No browser extensions required | | ✔️ | ✔️ |
| Granular permissions per app | | | ✔️ |
| No manual key management for users | | | ✔️ |
This comparison highlights how Para Universal Embedded Wallets combine the best features of both third-party and traditional
embedded wallets, while also offering unique advantages such as granular permissions and simplified key management.
## Security Features
Each application can be granted specific permissions, limiting potential damage if one app is compromised.
The User Share is encrypted specifically for each application, preventing unauthorized access.
Each key sharing process includes a signature verification step to ensure authenticity.
Thanks to MPC, the full private key is never exposed to any single application or stored in one place.
## How Wallet Portability Works
When a user creates a Para universal embedded wallet in one application, it's associated with their identity (e.g., email).
When the user wants to use their wallet in a new application: - They log in with their Para credentials - The new
application requests specific permissions - Upon approval, the application gains access to the user's wallet
Para securely shares the necessary key information with the new application, without exposing the full private key.
The user can now seamlessly use their wallet across all connected applications, with each app respecting its granted permissions.
## Example Use Cases
1. **DeFi Dashboard**: An app that aggregates data from multiple DeFi protocols could request read-only permissions
across various chains.
2. **NFT Marketplace**: Could request permissions specifically for NFT-related transactions on relevant chains.
3. **Cross-Chain DEX**: Might request permissions for swap transactions across multiple chains.
## Preview: Upcoming Enhancements
Para is continuously working on enhancing universal embedded wallet experiences. Future developments may include:
* More granular permission controls
* Enhanced analytics and insights for users across their entire wallet usage
* More seamless cross-chain experiences
By providing true universal embedded wallet portability, Para aims to make the crypto experience more user-friendly and secure, paving the
way for broader adoption and more innovative multi-app ecosystems.
# Account Abstraction
Source: https://docs.getpara.com/v2/general/account-abstraction
Explore account abstraction integration options with Para across different platforms
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return
;
};
Account Abstraction (AA) enables a more intuitive and flexible blockchain experience by allowing for programmable accounts with features like gasless transactions, batched operations, and custom authorization logic.
Para serves as the Signer and EOA (Externally Owned Account) for smart wallets and is not a smart wallet itself. Para does not provide gas sponsorship, but you can use any of the supported providers to implement smart wallet functionality for your users.
## Choose Your Platform
Note that client-side support for account abstraction is not currently available for Swift and Flutter platforms. If you need account abstraction functionality in Flutter or Swift applications, it's recommended to use server-side account abstraction integration.
## Supported Providers
Para integrates with several leading Account Abstraction providers:
*
*
*
*
*
*
*
# Go Live Checklist
Source: https://docs.getpara.com/v2/general/checklist
A checklist to help you go live with the Para SDK.
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
Before going live, ensure you've completed the following steps:
* [x] 🔑 Create a account to manage your integration
* [x] Create and configure a `BETA` API Key for testing the integration
* [x] : Get the SDK or Modal Up and Running
* [x] Check out the or sections for help!
* [ ] ⛓ Get signing & on-chain connectivity set up and make sure you're able to sign transactions
* [ ] **\[EVM]**
* [ ] **\[Cosmos]** : Add on the `cosm.js` signer or plug in one of our wallet adapters for popular libraries
* [ ] : Decide if you'll be using Account Abstraction with Para
* [ ] : Connect Para users to your existing infrastructure
* [ ] 🔒 Ensure Security and Session Management works for your app
* [ ] : Decide what login methods you'd like to use
* [ ] Implement Logic
* [ ] Decide if you want to enable
* [ ] 🎨 Make Para your own with by adding the visual finishing touches
* [ ] : Configure Branding, UI and more
* [ ] 🚀 Test and go live!
* [ ] Make a `PRODUCTION` API Key (Note: you'll need to set up billing first)
* [ ] Walk through the
* [ ] Ping us if you'd like help testing anything
## Para Environments: `BETA` vs `PRODUCTION`
Para has two different environments. **NOTE: Wallets are not shared across environments**
`BETA` is intended for you to develop and test against, **not for production builds or real users and funds**
* `BETA` can be used with any plan, including the free tier
* This is the correct environment to use for local or staging builds
* `BETA` users can be deleted for your convenience while testing, and is limited to *50 max users per project*
`PRODUCTION` is intended for any real users/funds
* This is the correct environment to use for release or production builds
* `PRODUCTION` users can NOT be deleted, and have no per-project limit
# Glossary
Source: https://docs.getpara.com/v2/general/glossary
Glossary of key terms.
### Identity and Wallets
**Embedded wallet** – A non-custodial wallet built into an app, often invisible to users. Enables users to control assets without managing keys or apps.
**Passkey** – A device-native authentication method [(based on WebAuthn)](https://docs.getpara.com/alpha/concepts/key-management#passkey) used as a more secure and user-friendly alternative to passwords and private keys.
**Private key** – Cryptographic secret that grants control over a wallet. In [MPC setups](https://blog.getpara.com/what-is-mpc/), it’s never reconstructed or stored in full; access is managed through secure, distributed shares.
**Recovery (or Key Recovery)** – The process for regaining access to a wallet, typically complex and manual in crypto. [Solutions like social recovery and embedded wallet recovery with Para simplify this for mainstream users.](https://docs.getpara.com/alpha/concepts/recovery)
**Seed phrase** – A series of words that encode a wallet’s private keys. Often used for wallet backup, but vulnerable to phishing and user error. [(Increasingly replaced by passkeys or MPC.)](https://blog.getpara.com/what-is-mpc/)
**Session key** – A short-lived key used to sign actions during an app session without requiring full wallet access.
**Signer** – An entity (user, server, agent) that can authorize transactions for a wallet.
**Wallet address** – A unique identifier for a wallet, similar to a bank account number users can share to receive funds.
### App Infrastructure
**EVM / Solana / Cosmos** – refer to [different blockchains](https://docs.getpara.com/introduction/chain-support), each with its own ecosystem of developer tools, standards, and communities.
**Gas** – The fee paid to execute transactions on a blockchain (like network fees in fintech). In modern apps, gas can be abstracted away from users for smoother UX.
**Onchain / Offchain** – Indicates whether an action occurs on the blockchain or off of it. Onchain means the operation is happening directly on the blockchain, while offchain references to actions that take place on traditional servers or outside the blockchain.
**RPC (Remote Procedure Call)** – The bridge between an app and the blockchain, used to read/write onchain data.
**Rollup** – A type of scaling solution (e.g., [Optimism](https://www.optimism.io/), [Arbitrum](https://arbitrum.io/)) that processes transactions off the main chain and posts a summary onchain. Speeds things up and reduces gas costs.
**Smart contract** – Self-executing code on a blockchain that defines how an app behaves.
### Security and Privacy
**Custody** – Defines who controls the private keys, and therefore access to the funds in a wallet setup. In crypto, custody determines who has actual control. Wallets can either be custodial or non-custodial.
**Custodial** – A third party holds wallet keys or crypto assets on behalf of a user.
**Distributed MPC (Multi-Party Computation)** – A cryptographic method where multiple parties collaboratively compute a result, like signing a transaction, without ever revealing or reconstructing the full private key. It’s typically used alongside [Distributed Key Generation (DKG)](https://docs.getpara.com/concepts/key-management) for securely creating the key shares, and then applied during key signing. Enables secure, non-custodial access.
**Hardware wallet** – A physical device for storing crypto private keys offline.
**Non-custodial** – A setup where users retain full control of their wallet and assets. No third party can access their funds or sign on their behalf.
**Shamir Secret Sharing** – A cryptographic technique for splitting a secret (like a private key) into [multiple pieces](https://blog.getpara.com/what-is-mpc/#:~:text=number%20of%20shares.-,Shamir%20Secret%20Sharing,-2/2%20Shamir). A minimum number of these pieces must be recombined to form the original private key to sign transactins and messages. Less dynamic than MPC.
### Ecosystems & Fintech
**Liquidity** – How easily assets can be bought or sold without affecting price. Critical for user experience in swaps or trading.
**Stablecoin** – A token designed to maintain a stable value (often pegged to the US dollar). Widely used in fintech apps for payments.
**Token** – A digital asset, which can represent anything from currency to ownership in a protocol.
**USDC (USD Coin)** – A dollar-pegged stablecoin issued by [Circle](https://www.circle.com/usdc), backed 1:1 by cash and short-term U.S. government bonds. Widely used in crypto apps and exchanges.
**USDT (Tether)** – Another popular dollar-pegged stablecoin. Issued by [Tether](https://tether.to/), but with less transparency than USDC around its reserves.
# Migrating from Capsule to Para
Source: https://docs.getpara.com/v2/general/migration-from-capsule
Guide for migrating from @usecapsule/* packages to @getpara/*@alpha packages
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
## Overview
This guide covers the migration process from Capsule to Para SDKs. The migration includes package namespace changes,
method signature updates to use object parameters, and introduces new React hooks for state management.
## Package Changes
All packages have been migrated from the `@usecapsule` namespace to `@getpara`. Update your dependencies by replacing
`@usecapsule` with `@getpara` in your package.json:
```diff
{
"dependencies": {
- "@usecapsule/react-sdk": "^3.0.0",
- "@usecapsule/evm-wallet-connectors": "^3.0.0"
+ "@getpara/react-sdk@alpha": "^1.0.0",
+ "@getpara/evm-wallet-connectors@alpha": "^1.0.0"
}
}
```
All packages have been reset to version 1.0.0 under the new namespace. The functionality and package names remain the
same - only the organization prefix has changed from `@usecapsule` to `@getpara`.
```bash npm
npm install @getpara/[package-name]@alpha --save-exact
```
```bash yarn
yarn add @getpara/[package-name]@alpha --exact
```
```bash pnpm
pnpm add @getpara/[package-name]@alpha --save-exact
```
## Mobile SDK Updates
### Flutter
The Flutter package has moved from `capsule` to `para` on pub.dev:
```diff
dependencies:
- capsule: 0.7.0
+ para: ^1.0.0
```
Create instances using `Para()` instead of `Capsule()`. All method signatures remain unchanged.
### Swift
The Swift SDK package is now available at `github.com/getpara/swift-sdk`. The main class has been renamed from
`CapsuleManager` to `ParaManager`, while maintaining the same method signatures:
```diff
- let manager = CapsuleManager()
+ let manager = ParaManager()
```
Method signatures and functionality remain identical for both mobile SDKs - only the package names and main class
names have changed.
## Breaking Changes
### Method Updates
All methods have been updated to use object parameters instead of multiple arguments. This change improves
extensibility, type safety, and reflects our commitment to consistent API design.
```typescript
// Old
createUser(email: string)
// New
createUser({ email: string })
```
```typescript
// Old
createUserByPhone(phone: string, countryCode: string)
// New
createUserByPhone({ phone: string, countryCode: string })
```
```typescript
// Old
externalWalletLogin(address: string, type: string, provider?: string, addressBech32?: string)
// New
externalWalletLogin({
address: string,
type: string,
provider?: string,
addressBech32?: string
})
```
```typescript
// Old
createWallet(type: WalletType, skipDistribute?: boolean)
// New
createWallet({
type: WalletType,
skipDistribute?: boolean = false
})
```
```typescript
// Old
createWalletPerType(skipDistribute?: boolean, types?: WalletType[])
// New. Note: Function name changed, default value added, and types is now required
createWalletPerType({
skipDistribute?: boolean = false,
types: WalletType[]
})
```
```typescript
// Old
distributeNewWalletShare(
walletId: string,
userShare?: string,
skipBiometricShareCreation?: boolean,
forceRefreshRecovery?: boolean
)
// New
distributeNewWalletShare({
walletId: string,
userShare?: string,
skipBiometricShareCreation?: boolean = false,
forceRefresh?: boolean = false
})
```
```typescript
// Old
createWalletPreGen(
type: WalletType,
pregenIdentifier: string,
pregenIdentifierType?: PregenIdentifierType
)
// New
createPregenWallet({
type: WalletType,
pregenIdentifier: string,
pregenIdentifierType?: PregenIdentifierType
})
```
```typescript
// Old - Note: Function name changed
updateWalletIdentifierPreGen(
newIdentifier: string,
walletId: string,
newType?: PregenIdentifierType
)
// New
updatePregenWalletIdentifier({
walletId: string,
newPregenIdentifier: string,
newPregenIdentifierType?: PregenIdentifierType
})
```
```typescript
// Old
signMessage(
walletId: string,
messageBase64: string,
timeoutMs?: number,
cosmosSignDocBase64?: string
)
// New
signMessage({
walletId: string,
messageBase64: string,
timeoutMs?: number,
cosmosSignDocBase64?: string
})
```
```typescript
// Old
signTransaction(
walletId: string,
rlpEncodedTxBase64: string,
timeoutMs?: number,
chainId: string
)
// New
signTransaction({
walletId: string,
rlpEncodedTxBase64: string,
timeoutMs?: number,
chainId: string
})
```
All methods now use object parameters with optional properties defaulting to reasonable values. This change makes the
SDK more maintainable and easier to extend in the future.
## New Features: React Hooks
Para now includes React hooks for easier state management and SDK interaction. Here's a basic setup:
```typescript
import { ParaProvider, ParaModal } from "@getpara/react-sdk@alpha";
function App() {
return (
);
}
```
### Available Hooks
Access current account state and connection status
Get current wallet information and state
Create a new Para user account
Check if a user exists by email
Start the login process
Handle user logout
Maintain active user session
Create wallet after passkey verification
Sign messages with connected wallet
Sign transactions with connected wallet
Handle login flow and initial setup
Monitor account creation process
Access Para client instance
Control Para modal visibility
Manage wallet state
## Next Steps
1. Update your package dependencies to use `@getpara/*`@alpha packages
2. Migrate method calls to use new object parameters
3. Consider implementing React hooks for simpler state management
4. Review framework-specific integration guides for detailed setup instructions
# Integrate Para Docs MCP with AI Tools
Source: https://docs.getpara.com/v2/general/para-docs-mcp
Connect the Para Docs Mintlify MCP server to AI tools for direct documentation access and enhanced coding assistance
Connect the Para Docs MCP server to AI tools for seamless access to documentation, code examples, and guides. This integration enables AI assistants to search Para Docs directly via the Model Context Protocol.
## Prerequisites
* Active accounts for target AI tools
* Para Docs MCP server URL: `http://docs.getpara.com/mcp`
* AI tool with remote MCP connection support (may be in beta)
## Installation and Setup
Set up connections by adding the MCP server as a custom connector in each tool's settings.
### Configure ChatGPT Connection
1. Open ChatGPT settings from your avatar menu
2. Select **Connectors** in the sidebar
3. Click **Create** to open the New Connector dialog
4. Enter the MCP server URL: `http://docs.getpara.com/mcp`
5. Configure authentication if required (Para Docs MCP uses no security by default)
6. Save and test the connection
### Configure Claude Desktop
1. Navigate to **Settings > Extensions** in Claude Desktop
2. Click **Advanced settings** and locate the Extension Developer section
3. Add a custom connector with the remote MCP URL: `http://docs.getpara.com/mcp`
4. Note: Remote support is in beta; use local STDIO if preferred
5. Verify the connection in Claude's interface
### Configure Claude Code
1. Run the CLI command: `claude mcp add`
2. Follow the wizard to input the MCP server URL: `http://docs.getpara.com/mcp`
3. Select remote MCP support
4. Integrate tools like search and fetch for Para Docs access
5. Restart Claude Code to apply changes
### Configure Cursor
1. Open Cursor settings and navigate to **Models** or **API Keys**
2. Disable unnecessary models if needed
3. Add a custom model or provider, overriding the base URL to `http://docs.getpara.com/mcp`
4. Use agent mode for MCP interactions (similar to VS Code Copilot)
5. Verify by testing a documentation query in the editor
## Usage
Query the MCP server via your AI tool's interface after setup. Provide search terms to the "SearchParaDocs" tool for relevant results.
Ask your AI: "Search Para Docs for \[topic]"
The tool returns titles, snippets, and links to relevant documentation.
Review returned contextual content and follow links for full details.
Check for connection issues and retry if the server is unreachable.
## Example
### Query Example
```text
Search Para Docs for how to sign a basic message
```
### Expected Response
The MCP server returns structured results:
```json Response
{
"results": [
{
"title": "Sign Messages with Para",
"snippet": "Learn how to sign messages using Para's wallet integration...",
"link": "https://docs.getpara.com/v2/react/guides/web3-operations/sign-with-para"
},
{
"title": "Web3 Operations Guide",
"snippet": "Complete guide for signing transactions and messages...",
"link": "https://docs.getpara.com/v2/react/guides/web3-operations"
}
]
}
```
# Wallet Pregeneration
Source: https://docs.getpara.com/v2/general/pregen
Overview of generating pregenerated wallets for Para
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Wallet pregeneration allows you to create wallets in advance of user interactions, which can significantly improve user onboarding speeds and overall experience in your application. With pregeneration, you can create a wallet for any identifier (email, phone number, username, etc.), executing Para's 2-of-2 MPC protocol where your application initially maintains ownership over the user's share of the MPC.
The pregenerated wallet can later be claimed by the user associated with that identifier, transferring ownership of their share to them – if your application permits this option. This flexibility opens up numerous possibilities for streamlining user experiences and creating innovative onboarding flows.
## Choose Your Platform
Para supports wallet pregeneration across all supported platforms. Select your development platform to view platform-specific implementation details:
## Innovative Use Cases
Pregeneration enables powerful new ways to incorporate blockchain into your application:
* **Mass User Onboarding**: Create wallets for your existing user base or email lists instantly
* **Social Integration**: Generate wallets based on social identifiers like Twitter followers
* **Agent-Owned Wallets**: Allow AI agents or bots to create and manage wallets for specific functions
* **Server-Side Operations**: Create app-managed wallets to perform operations on behalf of users
* **Airdrops and Rewards**: Preload funds or NFTs into wallets that users can claim later
* **Staged Onboarding**: Let users experience your application before formally creating their wallet
These use cases represent just a few of the possibilities enabled by wallet pregeneration. The platform-specific guides provide detailed implementation instructions for your chosen environment.
# Deploy Para Integration to Production
Source: https://docs.getpara.com/v2/general/production-deployment
Transition your Para integration from development to production with updated configurations and security settings
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Deploy your Para integration to production by updating configurations and ensuring secure settings for real users.
## Prerequisites
You need these components before deploying to production:
* A working Para integration in development/beta environment
* Production API credentials from the [Para Developer Portal](https://developer.getpara.com/)
* Production domain with HTTPS enabled
* Latest Para SDK version installed
## Deployment Steps
Update your Para SDK to the latest version before going live. Use the newest v2.0 release for all projects to benefit from improvements and fixes.
Check your @getpara/\* package versions and update to the latest stable release. Latest SDK versions resolve many integration issues.
Align your project with the [current Para release](https://www.npmjs.com/package/@getpara/react-sdk?activeTab=versions)to access recent features and security patches for real users.
Create a production API key in the Para Developer Portal for your live environment.
Replace development credentials with production values in your environment variables.
Update all secrets and URLs in your .env file for production, including callback URLs and API endpoints.
Configure your integration to use the production environment instead of beta/development. Para provides two hosted environments: BETA for testing and PROD for live use.
Update your initialization from:
```javascript Development
const para = new ParaWeb(Environment.BETA, PARA_API_KEY);
```
To:
```javascript Production
const para = new ParaWeb(Environment.PROD, PARA_API_KEY);
```
Para's Beta and Production are separate environments. Wallets and users are not shared between them. Your production environment starts with no users, and requires a distinct production API key.
Update allowed origin settings in the Para developer portal to include your production domain. This Domain Security setting restricts API usage to specified origins.
Add entries like `https://yourapp.com` and production subdomains to the Allowed Origins list. Remove development URLs like `http://localhost:3000` if no longer needed.
HTTPS is required in production. Configuring allowed origins prevents unauthorized domains from using your Para integration.
Review your Para integration settings for production, especially user communications and UI:
### Verification Redirect URL
Set the verification redirect URL to point to your production application's confirmation page. This URL appears in verification emails Para sends to users. Update from localhost URLs to your live domain.
### Email Notification Preferences
Choose appropriate email settings for production. Para can send welcome emails and optional backup kit instructions to new users.
Configure email templates and branding (logo, app name) for real user emails based on your user experience strategy.
### Branding and UI Configuration
Customize the Para modal or widget to match your production app's branding (colors, fonts, icons). Configure theme options through the Para SDK or developer portal's branding section.
Deploy your updated application with production settings and perform end-to-end testing with real scenarios:
### Test User Sign-Up/Login
Create a new user account using a real email address or phone number. Ensure OTP codes are delivered and users can complete verification and wallet creation.
Test emails like [dev@test.getpara.com](mailto:dev@test.getpara.com) and dummy phone numbers will not work in production. Production requires real contact information and OTP verification.
Ensure you are signing transactions on the [appropriate network](https://docs.getpara.com/v2/introduction/chain-support).
### Functionality Check
Verify wallet operations work with production settings. Test retrieving wallet addresses or making test transactions on mainnet to confirm Para's production environment interacts correctly.
Verify session management and security features (persistent login/logout) behave as expected.
### Monitor and Review
Watch browser console and backend logs for errors like misconfigured API keys or CORS issues. If you encounter CORS or CSP errors, verify the origin matches your deployed URL exactly.
## Pricing Information
With [Para Free Tier](https://www.getpara.com/pricing) your first 1,200 monthly active users are free. Paid plans require billing information to upgrade.
## Next Steps
# Telegram Bots & Mini-Apps
Source: https://docs.getpara.com/v2/general/telegram
A user-friendly guide to quickly integrate Telegram Apps
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
For signing in to Para with Telegram, refer to .
Para supports both Telegram Bots and Mini-Apps.
are a way to program logic natively into the Telegram App interface via text-based prompts and commands. Telegram Bots feel native to the UX of Telegram, but are limited to the UX and functionality of text-based options and menus.
are an easy way to serve hosted web applications from within Telegram. Given Mini-Apps are added functionality to an existing
web app, they are much more flexible but have a UX pattern that deviates from the native Telegram experience.
## Telegram Bot
The most popular way to use Para in a Telegram Bot is to leverage with the .
You have the option of allowing your users to their pregenerated wallets, which can happen directly within Telegram or in a standalone app.
## Mini-App
You can build Mini-Apps two ways:
1. Use the with the password option.
2. Use with the web SDK in a web framework of your choice. Once you have a web example working, use Telegram to create an interface for getting and setting data, like in .
3. You'll need to decide where and how you want users to claim their pregenerated wallets. This can happen within
Telegram Mini-Apps or in a standalone app.
Telegram Storage APIs have some limitations on data size. You may need to implement chunking to work around this. See
this for more info.
# Troubleshooting
Source: https://docs.getpara.com/v2/general/troubleshooting
Something not working quite right? This is the section for you!
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Having trouble with your Para integration? You're in the right place. This section contains platform-specific troubleshooting guides to help you resolve common issues across different frameworks and environments.
Using an LLM (ChatGPT, Claude) or Coding Assistant (Cursor, Github Copilot)? Here are a few tips:
1. Include the for the most up-to-date help
2. Check out the for an interactive LLM using Para Examples Hub
## Choose Your Platform
### Web
### Mobile
## Popular Web Frameworks
If we're missing a troubleshooting guide for a framework you're using, please get in touch! We're constantly expanding our documentation to cover more environments.
### Integration Support
If you're experiencing issues that aren't resolved by our troubleshooting resources, please [contact our team](https://join.slack.com/t/para-community/shared_invite/zt-304keeulc-Oqs4eusCUAJEpE9DBwAqrg) for
assistance. To help us resolve your issue quickly, please include the following information in your request:
1
A detailed description of the problem you're encountering.
2
Any relevant error messages or logs.
3
Steps to reproduce the issue.
4
Details about your system or environment (e.g., device, operating system, software version).
Providing this information will enable our team to address your concerns more efficiently.
# User Data Management
Source: https://docs.getpara.com/v2/general/user-data
A comprehensive guide to managing user data when integrating Para into your application
Effective user data management is crucial when integrating Para into your application. This guide covers best practices
for handling user information, including storage, retrieval, and privacy considerations.
## User Data in Para
Para's approach to user data is designed with privacy and security in mind. Here's what you need to know:
Para only collects essential information required for account identification and recovery, typically just the
user's email address.
User data is securely stored and encrypted on Para's servers. However, the most sensitive information - the user's
private keys - are never fully stored in one place due to Para's MPC technology.
As a developer, you have limited direct access to user data stored by Para. This is by design to ensure user
privacy and security.
## Managing User Data in Your Application
While Para handles the core wallet functionality, you may need to manage additional user data in your application. Here
are some best practices:
### Storing User Information
When storing additional user information in your application:
1. Only store what's necessary for your application's functionality.
2. Use secure, encrypted storage methods.
3. Consider using Para's wallet ID as a unique identifier for your users.
Example of storing user data:
```typescript
type UserData = {
paraWalletId: string;
username: string;
preferences: Record;
};
// Assume you're using a secure database
async function storeUserData(userData: UserData) {
await database.users.insert(userData);
}
// Usage
const wallets = await para.getWallets();
const walletId = Object.values(wallets)[0].id;
await storeUserData({
paraWalletId: walletId,
username: "user123",
preferences: { theme: "dark" },
});
```
### Retrieving User Information
To retrieve user information:
1. Use Para's methods to get wallet-related information.
2. Fetch additional data from your own storage using the Para wallet ID as a reference.
Example:
```typescript
async function getUserData(email: string) {
const wallets = await para.getWallets();
const walletId = Object.values(wallets)[0].id;
// Fetch additional data from your storage
const userData = await database.users.findOne({ paraWalletId: walletId });
return {
walletId,
...userData,
};
}
```
### Updating User Data
When updating user data:
1. Use Para's methods for updating wallet-related information.
2. Update additional data in your own storage.
```typescript
async function updateUserPreferences(walletId: string, newPreferences: Record) {
// Update in your storage
await database.users.update({ paraWalletId: walletId }, { $set: { preferences: newPreferences } });
}
```
## Privacy and Security Considerations
When managing user data, always prioritize privacy and security:
Only collect and store data that is absolutely necessary for your application's functionality.
Always encrypt sensitive data, both in transit and at rest.
Implement strict access controls to ensure that only authorized personnel can access user data.
Conduct regular audits of your data management practices to ensure compliance with privacy regulations.
## Compliance with Regulations
Ensure your user data management practices comply with relevant regulations such as GDPR, CCPA, or other applicable
laws. This may include:
* Providing users with the ability to request their data
* Allowing users to delete their data
* Implementing data portability features
Example of a data deletion function:
```typescript
async function deleteUserData(walletId: string) {
// Delete from your storage
await database.users.delete({ paraWalletId: walletId });
// Note: Para wallet data cannot be deleted directly through the SDK
// Advise the user to contact Para support for complete account deletion
}
```
Remember that while you can delete user data from your own storage, Para wallet data is managed separately for
security reasons. Users should be directed to Para's official channels for complete account deletion requests.
## Best Practices for User Data Management
1. **Separation of Concerns**: Keep Para-related data separate from your application-specific user data.
2. **Regular Backups**: Implement a robust backup strategy for user data stored in your application.
3. **Transparent Policies**: Clearly communicate your data handling practices to users through privacy policies and
terms of service.
4. **Secure Transmission**: Always use secure, encrypted channels when transmitting user data.
5. **Data Validation**: Implement thorough input validation to prevent injection attacks and ensure data integrity.
## Troubleshooting
If you encounter issues with user data management:
1. Ensure you're using the latest version of the Para SDK.
2. Verify that you're correctly handling asynchronous operations when interacting with Para and your own data storage.
3. Double-check that you're using the correct wallet IDs and other identifiers.
4. Review your error handling to ensure you're catching and addressing all potential exceptions.
# Para Video Resources
Source: https://docs.getpara.com/v2/general/webinars
Check out talks by the Para team about our roadmap, MPC, and in-depth looks at Para's architecture and use cases.
Founder/CEO Nitya Subramanian covers how multi-party computation can enable flexible and programmable transactions at zkParis 2023
VIDEO
Design Lead Jonny Howle covers how embedded wallets, MPC, and account abstractin should be seen as components of a wallet's system that can deliver on progressive disclosure and UX for users.
VIDEO
Nitya Subramanian delves into various approaches key management and trust in blockchain transactions, both on-chain and off-chain at ETHDenver 2024.
VIDEO
Watch these videos to learn how to set up your Developer Portal account
VIDEO
# Chain Support
Source: https://docs.getpara.com/v2/introduction/chain-support
Build on any supported chain.
Para integrates seamlessly with all EVM chains, Solana, and Cosmos chains. To add support for any additional chains within these networks, include its chain ID and RPC endpoint. Breakdown below:
| Networks/RPCs | Chain ID | Supported |
| --------------------- | ------------ | --------- |
| Arbitrum | 42161 | ✅ |
| Arbitrum Sepolia | 421614 | ✅ |
| Avalanche C-Chain | 43114 | ✅ |
| Avalanche Fuji | 43113 | ✅ |
| Basecamp (Camp) | 123420001114 | ✅ |
| Base | 8453 | ✅ |
| Base Sepolia | 84532 | ✅ |
| Berachain Artio | 80085 | ✅ |
| Camp Testnet V2 | 325000 | ✅ |
| Basecamp (Camp) | 123420001114 | ✅ |
| Celo | 42220 | ✅ |
| Celo Alfajores | 44787 | ✅ |
| Eclipse | 17172 | ✅ |
| Ethereum | 1 | ✅ |
| Ethereum Sepolia | 11155111 | ✅ |
| Flow EVM | 747 | ✅ |
| Fluent | 20993 | ✅ |
| Holesky | 17000 | ✅ |
| Holesky Garnet | 17069 | ✅ |
| Holesky Redstone | 17001 | ✅ |
| Katana | 747474 | ✅ |
| Kaia | 8217 | ✅ |
| Linea | 59144 | ✅ |
| Linea Testnet | 59140 | ✅ |
| Mantle | 5000 | ✅ |
| Monad Testnet | 10143 | ✅ |
| Omni | 166 | ✅ |
| Optimism | 10 | ✅ |
| Optimism Sepolia | 11155420 | ✅ |
| Plasma Testnet | 9746 | ✅ |
| Plume | 98866 | ✅ |
| Polygon | 137 | ✅ |
| Polygon Amoy | 80002 | ✅ |
| Sei | 1329 | ✅ |
| Solana Devnet | 103 | ✅ |
| Soneium | 1868 | ✅ |
| Story | 1514 | ✅ |
| Vana | 1480 | ✅ |
| Zora | 7777777 | ✅ |
| Zora Sepolia | 999999999 | ✅ |
| Solana | — | ✅ |
| Noble (Cosmos Chain) | noble-1 | ✅ |
| Initia | interwoven1 | ✅ |
| Initia testnet | initiation-2 | ✅ |
| Osmosis(Cosmos Chain) | osmosis-1 | ✅ |
# Examples Hub
Source: https://docs.getpara.com/v2/introduction/examples
Explore Para's examples hub for integration patterns across web, mobile, and specific use cases
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Para provides a comprehensive collection of examples to help you integrate our technology across various platforms, frameworks, and use cases. Our repository contains working code samples for all supported platforms.
Looking for community-created examples? Check out for community-featured examples and integrations from bounties and hackathons covering Account Abstraction, Agents, Pregeneration, and more!
## Web Framework Examples
## Server Examples
## Mobile Examples
Para SDK supports React Native, Flutter, and Swift for native mobile experiences:
## Popular Feature Examples
## Blockchain Integration Examples
## Transaction Signing Libraries
## Specialized Examples
## Community Contributions
## Need Something Specific?
Don't see an example for your use case? Para's team is eager to create new examples to help you integrate with different libraries, third-party features, or providers.
# Framework Support
Source: https://docs.getpara.com/v2/introduction/framework-support
Supported Features Across Para's Frameworks
export const FeatureGrid = ({instanceId = `feature-grid-web`}) => {
if (typeof document === "undefined") return null;
const initializeFeatureGrid = () => {
const platforms = [{
id: "react-web",
name: "React/Web"
}, {
id: "node-server",
name: "Node/Server"
}, {
id: "react-native",
name: "React Native"
}, {
id: "swift",
name: "Swift"
}, {
id: "flutter",
name: "Flutter"
}, {
id: "android",
name: "Android (Coming Soon!)"
}];
const footnotes = [{
id: "1",
text: "Flutter SDK currently supports MetaMask and Phantom Wallet Auth. Swift SDK currently supports MetaMask Wallet Auth."
}, {
id: "2",
text: "While it's possible to launch the para-wrapped provider UIs with Native Mobile experiences, we have observed that onramp experiences are much smoother via direct integrations."
}];
const createStatus = (status, footnoteId = null) => {
const base = {
status
};
if (footnoteId) {
base.footnoteId = footnoteId;
}
return base;
};
const featureSections = [{
id: "signing",
title: "Signing",
features: [{
id: "signing-evm",
name: "EVM",
platforms: {
"react-web": createStatus("supported"),
"node-server": createStatus("supported"),
"react-native": createStatus("supported"),
"swift": createStatus("supported"),
"flutter": createStatus("supported"),
"android": createStatus("not-supported")
}
}, {
id: "signing-solana",
name: "Solana",
platforms: {
"react-web": createStatus("supported"),
"node-server": createStatus("supported"),
"react-native": createStatus("supported"),
"swift": createStatus("coming-soon"),
"flutter": createStatus("supported"),
"android": createStatus("not-supported")
}
}, {
id: "signing-cosmos",
name: "Cosmos",
platforms: {
"react-web": createStatus("supported"),
"node-server": createStatus("supported"),
"react-native": createStatus("supported"),
"swift": createStatus("coming-soon"),
"flutter": createStatus("coming-soon"),
"android": createStatus("not-supported")
}
}, {
id: "signing-server-side",
name: "Server-Side",
platforms: {
"react-web": createStatus("supported"),
"node-server": createStatus("supported"),
"react-native": createStatus("supported"),
"swift": createStatus("supported"),
"flutter": createStatus("supported"),
"android": createStatus("not-supported")
}
}]
}, {
id: "wallet-types",
title: "Wallet Types",
features: [{
id: "wallet-embedded",
name: "Embedded",
platforms: {
"react-web": createStatus("supported"),
"node-server": createStatus("supported"),
"react-native": createStatus("supported"),
"swift": createStatus("supported"),
"flutter": createStatus("supported"),
"android": createStatus("not-supported")
}
}, {
id: "wallet-external",
name: "External Wallets",
platforms: {
"react-web": createStatus("supported"),
"node-server": createStatus("not-supported"),
"react-native": createStatus("supported"),
"swift": createStatus("footnote", "1"),
"flutter": createStatus("footnote", "1"),
"android": createStatus("not-supported")
}
}, {
id: "wallet-pregen",
name: "Pregen Wallets",
platforms: {
"react-web": createStatus("supported"),
"node-server": createStatus("supported"),
"react-native": createStatus("supported"),
"swift": createStatus("supported"),
"flutter": createStatus("supported"),
"android": createStatus("not-supported")
}
}, {
id: "wallet-smart-accounts",
name: "Smart Accounts",
subitems: [{
id: "wallet-smart-accounts-evm",
name: "EVM",
platforms: {
"react-web": createStatus("supported"),
"node-server": createStatus("supported"),
"react-native": createStatus("supported"),
"swift": createStatus("supported"),
"flutter": createStatus("supported"),
"android": createStatus("not-supported")
}
}, {
id: "wallet-smart-accounts-solana",
name: "Solana",
platforms: {
"react-web": createStatus("coming-soon"),
"node-server": createStatus("coming-soon"),
"react-native": createStatus("coming-soon"),
"swift": createStatus("coming-soon"),
"flutter": createStatus("coming-soon"),
"android": createStatus("not-supported")
}
}],
platforms: {
"react-web": null,
"node-server": null,
"react-native": null,
"swift": null,
"flutter": null,
"android": null
}
}, {
id: "wallet-gas-sponsorship",
name: "Gas Sponsorship",
subitems: [{
id: "wallet-gas-sponsorship-evm",
name: "EVM",
platforms: {
"react-web": createStatus("supported"),
"node-server": createStatus("supported"),
"react-native": createStatus("supported"),
"swift": createStatus("supported"),
"flutter": createStatus("supported"),
"android": createStatus("not-supported")
}
}, {
id: "wallet-gas-sponsorship-solana",
name: "Solana",
platforms: {
"react-web": createStatus("coming-soon"),
"node-server": createStatus("coming-soon"),
"react-native": createStatus("coming-soon"),
"swift": createStatus("coming-soon"),
"flutter": createStatus("coming-soon"),
"android": createStatus("not-supported")
}
}],
platforms: {
"react-web": null,
"node-server": null,
"react-native": null,
"swift": null,
"flutter": null,
"android": null
}
}]
}, {
id: "authentication",
title: "Authentication",
features: [{
id: "auth-email-phone",
name: "Email + Phone",
platforms: {
"react-web": createStatus("supported"),
"node-server": createStatus("not-supported"),
"react-native": createStatus("supported"),
"swift": createStatus("supported"),
"flutter": createStatus("supported"),
"android": createStatus("not-supported")
}
}, {
id: "auth-social",
name: "Social Logins",
platforms: {
"react-web": createStatus("supported"),
"node-server": createStatus("not-supported"),
"react-native": createStatus("supported"),
"swift": createStatus("supported"),
"flutter": createStatus("supported"),
"android": createStatus("not-supported")
}
}, {
id: "auth-passkeys",
name: "Passkeys",
platforms: {
"react-web": createStatus("supported"),
"node-server": createStatus("supported"),
"react-native": createStatus("not-supported"),
"swift": createStatus("supported"),
"flutter": createStatus("supported"),
"android": createStatus("not-supported")
}
}, {
id: "auth-password",
name: "Password",
platforms: {
"react-web": createStatus("supported"),
"node-server": createStatus("coming-soon"),
"react-native": createStatus("not-supported"),
"swift": createStatus("coming-soon"),
"flutter": createStatus("coming-soon"),
"android": createStatus("not-supported")
}
}]
}, {
id: "on-off-ramps",
title: "On/Off Ramps",
features: [{
id: "ramps-stripe",
name: "Stripe",
platforms: {
"react-web": createStatus("supported"),
"node-server": createStatus("not-supported"),
"react-native": createStatus("footnote", "2"),
"swift": createStatus("footnote", "2"),
"flutter": createStatus("footnote", "2"),
"android": createStatus("not-supported")
}
}, {
id: "ramps-ramp",
name: "Ramp",
platforms: {
"react-web": createStatus("supported"),
"node-server": createStatus("not-supported"),
"react-native": createStatus("footnote", "2"),
"swift": createStatus("footnote", "2"),
"flutter": createStatus("footnote", "2"),
"android": createStatus("not-supported")
}
}, {
id: "ramps-moonpay",
name: "Moonpay",
platforms: {
"react-web": createStatus("supported"),
"node-server": createStatus("not-supported"),
"react-native": createStatus("footnote", "2"),
"swift": createStatus("footnote", "2"),
"flutter": createStatus("footnote", "2"),
"android": createStatus("not-supported")
}
}]
}, {
id: "permissions",
title: "Permissions",
features: [{
id: "permissions-main",
name: "Permissions",
subitems: [{
id: "permissions-evm",
name: "EVM",
platforms: {
"react-web": createStatus("supported"),
"node-server": createStatus("supported"),
"react-native": createStatus("supported"),
"swift": createStatus("coming-soon"),
"flutter": createStatus("coming-soon"),
"android": createStatus("not-supported")
}
}, {
id: "permissions-solana",
name: "Solana",
platforms: {
"react-web": createStatus("coming-soon"),
"node-server": createStatus("coming-soon"),
"react-native": createStatus("coming-soon"),
"swift": createStatus("coming-soon"),
"flutter": createStatus("coming-soon"),
"android": createStatus("not-supported")
}
}],
platforms: {
"react-web": null,
"node-server": null,
"react-native": null,
"swift": null,
"flutter": null,
"android": null
}
}]
}];
const icons = {
check: ` `,
minus: ` `,
clock: ` `,
chevronRight: ` `,
chevronDown: ` `
};
const styles = `
:root {
--background: #ffffff;
--foreground: #09090b;
--card: #ffffff;
--card-foreground: #09090b;
--popover: #ffffff;
--popover-foreground: #09090b;
--primary: #09090b;
--primary-foreground: #fafafa;
--secondary: #f4f4f5;
--secondary-foreground: #09090b;
--muted: #f4f4f5;
--muted-foreground: #71717a;
--accent: #f4f4f5;
--accent-foreground: #09090b;
--destructive: #ef4444;
--destructive-foreground: #fafafa;
--border: #e4e4e7;
--input: #e4e4e7;
--ring: #09090b;
--radius: 0.5rem;
--green-100: #dcfce7;
--green-600: #16a34a;
--amber-100: #fef3c7;
--amber-600: #d97706;
--blue-100: #dbeafe;
--blue-600: #2563eb;
--muted-hsl: 240, 4.8%, 95.9%;
}
.${instanceId}-container body {
font-family: "PPMORI";
background-color: var(--background);
color: var(--foreground);
margin: 0;
padding: 0;
box-sizing: border-box;
}
.${instanceId}-container *, .${instanceId}-container *::before, .${instanceId}-container *::after {
box-sizing: inherit;
}
.${instanceId}-container .feature-grid-container {
max-width: 1100px;
margin-left: auto;
margin-right: auto;
}
.${instanceId}-container .feature-card {
}
.${instanceId}-container .feature-card-header {
padding: 1.5rem;
padding-bottom: 0.75rem;
border-bottom: 1px solid var(--border);
}
.${instanceId}-container .feature-card-title {
font-size: 1.5rem;
font-weight: 600;
line-height: 2rem;
letter-spacing: -0.025em;
margin-bottom: 0.25rem;
}
.${instanceId}-container .feature-card-description {
color: var(--muted-foreground);
font-size: 0.875rem;
}
.${instanceId}-container .feature-card-content {
}
.${instanceId}-container .legend {
margin-bottom: 1rem;
display: flex;
flex-wrap: wrap;
gap: 1.5rem;
}
.${instanceId}-container .legend-item {
display: flex;
align-items: center;
gap: 0.5rem;
}
.${instanceId}-container .legend-icon {
height: 1.5rem;
width: 1.5rem;
border-radius: 9999px;
display: flex;
align-items: center;
justify-content: center;
}
.${instanceId}-container .legend-text {
font-size: 0.875rem;
color: var(--foreground);
}
.${instanceId}-container .status-icon-base {
height: 1.75rem;
width: 1.75rem;
border-radius: 9999px;
display: inline-flex;
align-items: center;
justify-content: center;
vertical-align: middle;
}
.${instanceId}-container .status-supported { background-color: var(--green-100); color: var(--green-600); }
.${instanceId}-container .status-not-supported { background-color: var(--muted); color: var(--muted-foreground); }
.${instanceId}-container .status-coming-soon { background-color: var(--amber-100); color: var(--amber-600); }
.${instanceId}-container .status-footnote {
background-color: var(--blue-100);
color: var(--blue-600);
cursor: help;
}
.${instanceId}-container .status-footnote span { font-size: 0.75rem; font-weight: 700; }
.${instanceId}-container .section {
margin-bottom: 1rem;
}
.${instanceId}-container .section:last-child {
margin-bottom: 0;
}
.${instanceId}-container .section-title {
font-size: 1.125rem;feat
font-weight: 600;
margin-bottom: 0.75rem;
}
.${instanceId}-container .separator {
border: 0;
border-top: 1px solid var(--border);
margin-top: 0.5rem;
margin-bottom: 0.5rem;
}
.${instanceId}-container .table-container {
overflow-x: auto;
}
.${instanceId}-container .feature-table {
width: 100%;
border-collapse: collapse;
caption-side: bottom;
font-size: 0.875rem;
margin-bottom: 0.5rem;
margin-top: 0.5rem;
}
.${instanceId}-container .feature-table th,
.${instanceId}-container .feature-table td {
padding: 0.75rem 0.5rem;
text-align: left;
vertical-align: middle;
border-bottom: 1px solid var(--border);
}
.${instanceId}-container .feature-table tr:last-child td {
border-bottom: none;
}
.${instanceId}-container .feature-table th {
font-weight: 500;
color: var(--muted-foreground);
text-transform: none;
white-space: nowrap;
}
.${instanceId}-container .feature-table th.platform-head {
width: 100px;
text-align: center;
white-space: normal;
}
.${instanceId}-container .feature-table th.feature-head { width: 250px; }
.${instanceId}-container .feature-table tbody tr.expandable-row {
cursor: pointer;
}
.${instanceId}-container .feature-table tbody tr.expandable-row:hover {
background-color: hsla(var(--muted-hsl, 240, 4.8%, 95.9%), 0.5);
}
.${instanceId}-container .feature-table tbody tr.subitem-row {
background-color: hsla(var(--muted-hsl, 240, 4.8%, 95.9%), 0.2);
}
.${instanceId}-container .feature-table td {
color: var(--foreground);
}
.${instanceId}-container .feature-table td.feature-cell {
font-weight: 500;
}
.${instanceId}-container .feature-cell-content {
display: flex;
align-items: center;
gap: 0.5rem;
}
.${instanceId}-container .subitem-cell-content {
display: flex;
align-items: center;
gap: 0.5rem;
padding-left: 1.5rem;
}
.${instanceId}-container .expand-icon {
margin-right: 0.5rem;
display: inline-flex;
align-items: center;
color: var(--muted-foreground);
flex-shrink: 0;
}
.${instanceId}-container .platform-cell {
text-align: center;
}
.${instanceId}-container .feature-card-footer {
padding: 1rem 1.5rem;
border-top: 1px solid var(--border);
display: flex;
flex-direction: column;
align-items: flex-start;
}
.${instanceId}-container .request-feature-button {
display: inline-block;
background-color: var(--background);
color: var(--foreground);
border: 1px solid var(--input);
padding: 0.375rem 0.75rem;
font-size: 0.875rem;
border-radius: calc(var(--radius) - 2px);
font-weight: 500;
cursor: pointer;
margin-bottom: 1rem;
transition: background-color 0.2s, color 0.2s;
text-decoration: none;
}
.${instanceId}-container .request-feature-button:hover {
background-color: var(--accent);
color: var(--accent-foreground);
}
.${instanceId}-container .footnotes-container {
width: 100%;
}
.${instanceId}-container .footnotes-title {
font-size: 0.875rem;
font-weight: 500;
margin-bottom: 0.5rem;
}
.${instanceId}-container .footnotes-list {
font-size: 0.75rem;
color: var(--muted-foreground);
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.${instanceId}-container .footnotes-list li span {
font-weight: 700;
margin-right: 0.25rem;
}
`;
function createElement(tag, classNames = [], attributes = {}, children = []) {
const element = document.createElement(tag);
if (classNames.length > 0) {
element.classList.add(...classNames);
}
for (const key in attributes) {
element.setAttribute(key, attributes[key]);
}
children.forEach(child => {
if (typeof child === 'string') {
element.appendChild(document.createTextNode(child));
} else if (child instanceof Node) {
element.appendChild(child);
} else if (typeof child === 'object' && child !== null && typeof child.outerHTML === 'string') {
element.innerHTML += child.outerHTML;
}
});
return element;
}
function createIconElement(iconSvg) {
const div = document.createElement('div');
if (typeof iconSvg === 'string') {
div.innerHTML = iconSvg.trim();
const svgElement = div.firstElementChild;
if (svgElement) {
svgElement.style.display = 'inline-block';
svgElement.style.verticalAlign = 'middle';
return svgElement;
}
}
return null;
}
function renderPlatformStatus(platformStatus) {
const wrapper = createElement('div', ['platform-cell']);
let statusElement = null;
if (!platformStatus) {
statusElement = createElement('div');
wrapper.appendChild(statusElement);
return wrapper;
}
switch (platformStatus.status) {
case "supported":
statusElement = createElement('div', ['status-icon-base', 'status-supported']);
statusElement.appendChild(createIconElement(icons.check));
break;
case "not-supported":
statusElement = createElement('div', ['status-icon-base', 'status-not-supported']);
statusElement.appendChild(createIconElement(icons.minus));
break;
case "coming-soon":
statusElement = createElement('div', ['status-icon-base', 'status-coming-soon']);
statusElement.appendChild(createIconElement(icons.clock));
break;
case "footnote":
statusElement = createElement('div', ['status-icon-base', 'status-footnote']);
const span = createElement('span', [], {}, [platformStatus.footnoteId || '?']);
statusElement.appendChild(span);
break;
default:
statusElement = createElement('div');
}
if (statusElement) {
wrapper.appendChild(statusElement);
}
return wrapper;
}
function createFeatureRow(feature, isSubitem = false) {
const uniqueFeatureId = `${instanceId}-${feature.id}`;
const row = createElement('tr', isSubitem ? ['subitem-row'] : []);
row.dataset.featureId = uniqueFeatureId;
const hasSubitems = feature.subitems && feature.subitems.length > 0;
if (hasSubitems) {
row.classList.add('expandable-row');
}
const featureCell = createElement('td', ['feature-cell']);
const featureCellContent = createElement('div', isSubitem ? ['subitem-cell-content'] : ['feature-cell-content']);
if (hasSubitems) {
const expandIconWrapper = createElement('span', ['expand-icon']);
expandIconWrapper.innerHTML = icons.chevronDown;
featureCellContent.appendChild(expandIconWrapper);
row.dataset.expanded = 'true';
row.dataset.subitemsTarget = `subitems-${uniqueFeatureId}`;
}
featureCellContent.appendChild(document.createTextNode(feature.name));
featureCell.appendChild(featureCellContent);
row.appendChild(featureCell);
platforms.forEach(platform => {
const platformCell = createElement('td', ['platform-cell']);
const status = feature.platforms ? feature.platforms[platform.id] : null;
platformCell.appendChild(renderPlatformStatus(status));
row.appendChild(platformCell);
});
return row;
}
function buildFeatureGrid() {
const container = createElement('div', ['feature-grid-container']);
const card = createElement('div', ['feature-card']);
const cardContent = createElement('div', ['feature-card-content']);
const legend = createElement('div', ['legend']);
const legendItems = [{
status: 'supported',
text: 'Supported',
icon: icons.check,
bg: '--green-100',
fg: '--green-600'
}, {
status: 'not-supported',
text: 'N/A',
icon: icons.minus,
bg: '--muted',
fg: '--muted-foreground'
}, {
status: 'coming-soon',
text: 'Coming Soon',
icon: icons.clock,
bg: '--amber-100',
fg: '--amber-600'
}, {
status: 'footnote',
text: 'See Footnote',
icon: '1',
bg: '--blue-100',
fg: '--blue-600',
isFootnote: true
}];
legendItems.forEach(item => {
const legendItem = createElement('div', ['legend-item']);
const iconDiv = createElement('div', ['legend-icon']);
iconDiv.style.backgroundColor = `var(${item.bg})`;
iconDiv.style.color = `var(${item.fg})`;
if (item.isFootnote) {
const span = createElement('span', [], {}, [item.icon]);
span.style.fontSize = '0.75rem';
span.style.fontWeight = '700';
iconDiv.appendChild(span);
} else {
const iconElement = createIconElement(item.icon);
if (iconElement) iconDiv.appendChild(iconElement);
}
legendItem.appendChild(iconDiv);
legendItem.appendChild(createElement('span', ['legend-text'], {}, [item.text]));
legend.appendChild(legendItem);
});
cardContent.appendChild(legend);
featureSections.forEach(section => {
const sectionDiv = createElement('div', ['section']);
sectionDiv.appendChild(createElement('h2', ['section-title'], {}, [section.title]));
sectionDiv.appendChild(createElement('hr', ['separator']));
const tableContainer = createElement('div', ['table-container']);
const table = createElement('table', ['feature-table']);
const thead = createElement('thead');
const headerRow = createElement('tr');
headerRow.appendChild(createElement('th', ['feature-head'], {}, ["Feature"]));
platforms.forEach(platform => {
const th = createElement('th', ['platform-head']);
th.innerHTML = platform.name;
headerRow.appendChild(th);
});
thead.appendChild(headerRow);
table.appendChild(thead);
const tbody = createElement('tbody');
section.features.forEach(feature => {
const featureRow = createFeatureRow(feature, false);
tbody.appendChild(featureRow);
if (feature.subitems && feature.subitems.length > 0) {
const uniqueFeatureId = `${instanceId}-${feature.id}`;
const subRows = feature.subitems.map(subitem => createFeatureRow(subitem, true));
subRows.forEach(subRow => {
subRow.classList.add(`subitems-${uniqueFeatureId}`);
tbody.appendChild(subRow);
});
}
});
table.appendChild(tbody);
tableContainer.appendChild(table);
sectionDiv.appendChild(tableContainer);
cardContent.appendChild(sectionDiv);
});
card.appendChild(cardContent);
const cardFooter = createElement('div', ['feature-card-footer']);
const mailtoLink = createElement('a', ['request-feature-button'], {
href: "mailto:support@getpara.com?subject=[DEV SUPPORT]",
target: "_blank",
rel: "noopener noreferrer"
});
mailtoLink.textContent = "Ask Us / Request a Feature";
cardFooter.appendChild(mailtoLink);
const footnotesContainer = createElement('div', ['footnotes-container']);
footnotesContainer.appendChild(createElement('h3', ['footnotes-title'], {}, ["Footnotes:"]));
const footnotesList = createElement('ul', ['footnotes-list']);
footnotes.forEach(note => {
const listItem = createElement('li');
const boldPart = createElement('span', [], {}, [`${note.id}.`]);
listItem.appendChild(boldPart);
listItem.appendChild(document.createTextNode(` ${note.text}`));
footnotesList.appendChild(listItem);
});
footnotesContainer.appendChild(footnotesList);
cardFooter.appendChild(footnotesContainer);
card.appendChild(cardFooter);
container.appendChild(card);
container.addEventListener('click', event => {
const expandableRow = event.target.closest('.expandable-row');
if (expandableRow) {
const targetClass = expandableRow.dataset.subitemsTarget;
if (!targetClass) return;
const isExpanded = expandableRow.dataset.expanded === 'true';
const subitemRows = container.querySelectorAll(`tr.${targetClass}`);
const icon = expandableRow.querySelector('.expand-icon');
subitemRows.forEach(row => {
row.style.display = isExpanded ? 'none' : '';
});
expandableRow.dataset.expanded = !isExpanded;
if (icon) {
icon.innerHTML = isExpanded ? icons.chevronRight : icons.chevronDown;
}
}
});
return container;
}
if (!document.getElementById('feature-grid-styles')) {
const styleSheet = document.createElement("style");
styleSheet.type = "text/css";
styleSheet.id = 'feature-grid-styles';
styleSheet.innerText = styles;
document.head.appendChild(styleSheet);
}
const wrapperElement = document.getElementById(instanceId);
if (wrapperElement) {
const featureGridElement = buildFeatureGrid();
while (wrapperElement.firstChild) {
wrapperElement.removeChild(wrapperElement.firstChild);
}
wrapperElement.appendChild(featureGridElement);
wrapperElement.classList.add(`${instanceId}-container`);
} else {
console.error(`FeatureGrid: Could not find wrapper element with ID ${instanceId}`);
}
};
setTimeout(initializeFeatureGrid, 1);
return
;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
This table outlines the current, quickly changing status of feature support across Para's SDKs.
We release new frameworks, then iteratively add features based on customer needs. If you don't see a feature you're
looking for here, - we may already be
working on it!
# Migrating from Para v1.x to v2.0 Alpha
Source: https://docs.getpara.com/v2/introduction/migration-to-alpha
Guide for migrating from Para version 1.x to Para's version 2.0 alpha release
Use this guide for assistance migrating from Para version 1.x to Para's version 2.0 alpha release. Para 2.0 is in active development, and feature changes are expected while we work toward the final stable version. Developers wanting the latest changes should use the alpha version.
## React SDK
### Summary of breaking changes
1. The `setup-para` CLI tool needs to run before running your app to ensure all `@getpara` libraries are properly polyfilled. It is recommended to do this in your `postinstall` step of your `package.json`, something like:
```bash
"postinstall": "yarn setup-para"
```
2. The `ParaProvider` is now required to be used when using the `@getpara/react-sdk`
3. A `queryClient` from `@tanstack/react-query` must be provided.
See the `@tanstack/react-query` [docs](https://tanstack.com/query/latest/docs/framework/react/quick-start) for more information on setting up a `QueryClient`
4. The `appName` prop has moved from a modal prop to a **required** config prop on the `ParaProvider`. This name will be used throughout the modal and in any external wallet providers that may be used.
5. The `ParaModal` no longer needs to be provided separately, it is automatically included with the `ParaProvider` and all modal props can be passed to the `ParaProvider`.
The `ParaModal` can still be provided separately if that is preferred. In this case the `disableEmbeddedModal: true` value should be passed to the `ParaProvider` config.
6. The `ParaModal` props, `isOpen` and `onClose`, are no longer required (though they can be provided if desired). These values are now handled by the `ParaProvider` and developers can use the `useModal` hook to control the modal state.
7. When using external wallets the Para connector libraries no longer need to be provided, just installed. All config values for these connectors can be passed to the `ParaProvider`.
### Migration
Migration to V2 can be done one of two ways:
1. (**PREFERRED**) Remove the `ParaModal` component you are providing and use the modal that the updated `ParaProvider` provides. This option offers the most code reduction and overall simpler developer experience.
2. Continue to use the `ParaModal` component you are providing in your app. This option is a bit quicker than the first but will lead to a poorer developer experience.
Remove your `` and use the one built into ``.
**Starting Code:**
```tsx Starting Code (Existing Provider)
{...REST_OF_YOUR_APP}
```
```tsx Starting Code (Without Existing Provider)
const Para = new Para("YOUR_API_KEY")
<>
{...REST_OF_YOUR_APP}
>
```
**After Migration:**
```tsx After Migration {7-11}
{...REST_OF_YOUR_APP}
{/* Note: is removed from here */}
```
Continue using your own `` by disabling the built-in one.
**Starting Code:**
```tsx Starting Code (Existing Provider)
{...REST_OF_YOUR_APP}
```
```tsx Starting Code (Without Existing Provider)
const Para = new Para("YOUR_API_KEY")
<>
{...REST_OF_YOUR_APP}
>
```
**After Migration:**
```tsx After Migration {8-10, 16}
{...REST_OF_YOUR_APP}
```
### Adding External Wallets
If you're using external wallets with Para currently, those configs can now be passed to the `ParaProvider` and the connectors will be instantiated for you. Assuming you already followed the migration steps above, a successful migration would look like:
```tsx Starting Code [expandable]
{
SELECTED_CHAIN_STATE_UPDATER_FN();
}}
multiChain
walletConnect={{ options: { projectId: 'YOUR_WALLETCONNECT_PROJECT_ID' } }}
>
{...REST_OF_YOUR_APP}
```
```tsx After Migration {11-41} [expandable]
{
SELECTED_CHAIN_STATE_UPDATER_FN();
},
chains: YOUR_COSMOS_CHAINS,
},
// grazProviderProps={}
},
solanaConnector: {
config: {
endpoint: YOUR_SOLANA_ENDPOINT,
chain: YOUR_SOLANA_NETWORK,
},
},
walletConnect: {
projectId: 'YOUR_WALLETCONNECT_PROJECT_ID',
},
}}
>
{...REST_OF_YOUR_APP}
```
Notes on the external wallet migration:
1. All wallets are provided by default, if you wish for them all to be provided you can remove the `wallets` value in the `externalWalletConfig`
2. If you only wish to use EVM wallets only the `evmConnector` config needs to be passed, the other connectors will be skipped in that case.
## Pregen Wallet Methods
Methods dealing with pregen wallets now use a simpler object-based notation to specify the type and identifier the wallet belongs to.
```tsx Email
// 1.x
await para.createPregenWallet({
pregenIdentifier: 'email@email.com',
pregenIdentifierType: 'EMAIL'
});
// 2.x
await para.createPregenWallet({ pregenId: { email: 'email@email.com' } });
```
```tsx Phone
// 1.x
await para.createPregenWallet({
pregenIdentifier: '+13105551234',
pregenIdentifierType: 'PHONE'
});
// 2.x
await para.createPregenWallet({ pregenId: { phone: '+13105551234' } });
```
```tsx Farcaster
// 1.x
await para.createPregenWallet({
pregenIdentifier: 'FarcasterUsername',
pregenIdentifierType: 'FARCASTER'
});
// 2.x
await para.createPregenWallet({ pregenId: { farcasterUsername: 'FarcasterUsername' } });
```
```tsx Telegram
// 1.x
await para.createPregenWallet({
pregenIdentifier: '1234567890',
pregenIdentifierType: 'TELEGRAM'
});
// 2.x
await para.createPregenWallet({ pregenId: { telegramUserId: '1234567890' } });
```
```tsx Discord
// 1.x
await para.createPregenWallet({
pregenIdentifier: 'DiscordUsername',
pregenIdentifierType: 'DISCORD'
});
// 2.x
await para.createPregenWallet({ pregenId: { discordUsername: 'DiscordUsername' } });
```
```tsx X (Twitter)
// 1.x
await para.createPregenWallet({
pregenIdentifier: 'XUsername',
pregenIdentifierType: 'TWITTER'
});
// 2.x
await para.createPregenWallet({ pregenId: { xUsername: 'XUsername' } });
```
```tsx Custom ID
// 1.x
await para.createPregenWallet({
pregenIdentifier: 'my-custom-id',
pregenIdentifierType: 'CUSTOM_ID'
});
// 2.x
await para.createPregenWallet({ pregenId: { customId: 'my-custom-id' } });
```
## Common Enums (optional)
Enum types used in certain methods, while still available, are now replaced with string union types. You will not be required to import these enums for methods that accept them.
```tsx {4}
import { WalletType } from '@getpara/web-sdk';
// Either is allowed
para.createWallet({ type: WalletType.EVM });
para.createWallet({ type: 'EVM' });
```
### Type Definitions
Ethereum Virtual Machine compatible wallet
Solana wallet
Cosmos wallet
DKLS wallet scheme
ED25519 wallet scheme
CGGMP wallet scheme
Google OAuth
Apple OAuth
Twitter/X OAuth
Discord OAuth
Facebook OAuth
Telegram OAuth
Farcaster OAuth
## Auth Objects
User identity attestations are now represented as auth objects with a single key and value, representing both the type of attestation and the relevant identifier. These objects are used for methods that require an attestation of this type, primarily those for authentication and pregenerated wallet management.
### Auth Object Examples
```tsx Email
const auth = { email: 'email@test.com' };
await para.signUpOrLogIn({ auth });
```
```tsx Phone
const auth = { phone: '+13105551234' };
await para.signUpOrLogIn({ auth });
```
```tsx Farcaster
const pregenId = { farcasterUsername: 'MyUsername' };
await para.createPregenWallet({ pregenId, type: 'EVM' });
```
```tsx Telegram
const pregenId = { telegramUserId: '1234567890' };
await para.createPregenWallet({ pregenId, type: 'EVM' });
```
```tsx Discord
const pregenId = { discordUsername: 'MyUsername' };
await para.createPregenWallet({ pregenId, type: 'EVM' });
```
```tsx X/Twitter
const pregenId = { xUsername: 'MyUsername' };
await para.createPregenWallet({ pregenId, type: 'EVM' });
```
```tsx Custom Pregen ID
const pregenId = { customId: 'my-custom-id' };
await para.createPregenWallet({ pregenId, type: 'EVM' });
```
Phone number auth objects expect a string in international format, beginning with a `+` and containing only numbers without spaces or extra characters, i.e.: `+${number}`. If your UI deals in separated country codes and national phone numbers, you may use the exported `formatPhoneNumber` function to combine them into a correctly formatted string.
```tsx
import { formatPhoneNumber } from '@getpara/web-sdk';
await para.signUpOrLogIn({ auth: { phone: '+13105551234' } });
// or, if your country code and national number are distinct:
await para.signUpOrLogIn({ auth: { phone: formatPhoneNumber('3105551234', '1') } });
```
## Cancelable Methods (optional)
This feature is available in the following SDKs:
* `@getpara/web-sdk`@alpha
* `@getpara/react-sdk`@alpha
* `@getpara/react-native-sdk`@alpha
For methods that wait for user action, such as `waitForLogin`, you may now pass a callback that is invoked on each polling interval, as well as a callback to indicate whether the method should be canceled and another invoked upon cancelation.
```tsx
let i = 0, popupWindow: Window;
await para.waitForLogin({
isCanceled: () => popupWindow?.closed,
onPoll: () => {
console.log(`Waiting for login, polled ${++i} times...`)
},
onCancel: () => {
console.log('Login canceled after popup window closed!');
}
});
```
## New Authentication Flow
The primary methods for authenticating via phone, email address, or third-party services have been overhauled and greatly simplified. If you are using a custom authentication UI, refer to the [Custom Authentication UI](/v2/react/guides/custom-ui-hooks) page for detailed instructions and code samples. For new developers, the [Para Modal](/v2/react/overview) is the preferred option to handle user authentication in your app.
## Modified Core Methods
We've streamlined and improved several core methods in version 2.0.0. The following sections outline what's changed and what actions you need to take.
These changes are required when upgrading to version 2.0.0. Make sure to update your code accordingly to avoid breaking your application.
* `checkIfUserExists`
* `initiateUserLogin`
* `createUser`
* `checkIfUserExistsByPhone`
* `initiateUserLoginForPhone`
* `createUserByPhone`
`signUpOrLogIn`
Modify your current authentication flow to use the new simplified `signUpOrLogIn` method as detailed on our Custom Authentication UI page.
This change simplifies the authentication process by consolidating multiple methods into a single, more intuitive function.
* `waitForLoginAndSetup`
* `waitForAccountCreation`
* `waitForPasskeyAndCreateWallet`
* `waitForLogin`
* `waitForSignup`
* `waitForWalletCreation`
Modify your current authentication flow to use the new simplified methods as detailed on our Custom Authentication UI page.
* `createPregenWallet`
* `createPregenWalletPerType`
* `updatePregenWalletIdentifier`
* `hasPregenWallet`
* `claimPregenWallets`
Modified to accept a single `pregenId` argument
Update your functions to use the new notation.
```javascript Before
para.createPregenWallet({
pregenIdentifier: 'email@email.com',
pregenIdentifierType: 'EMAIL'
})
```
```javascript After
para.createPregenWallet({
pregenId: {
email: 'email@email.com'
}
})
```
* `initiateFarcasterLogin`
* `waitForFarcasterStatus`
`verifyFarcaster`
Use the simplified `verifyFarcaster` method as detailed on our Custom Authentication UI page.
* `getOAuthUrl`
* `waitForOAuth`
`verifyOAuth`
Use the simplified `verifyOAuth` method as detailed on our Custom Authentication UI page.
`touchSession`
Destructuring is simpler, returning an object of type `SessionInfo` rather than `{ data: SessionInfo }`
Update existing usages to destructure the return value correctly.
* `check2FAStatus` (Deprecated)
* `enable2FA`
* `verify2FA`
* `setup2FA`
* `setup2fa` (Replaces `check2FAStatus`)
* `enable2fa`
* `verify2fa`
* Replace calls to `check2FAStatus` with `setup2fa`, which will now either return `{ isSetup: true }` or `{ isSetup: false, uri: string }` depending on the current user's settings
* Update function instances to use the new spelling with lowercase "fa"
React Native, Flutter, Swift
`login`
`loginWithPasskey`
Update function instances to use the new name.
# Migrate to Para
Source: https://docs.getpara.com/v2/introduction/migration-to-para
Already have some users in another auth or wallet system? Para makes it easy to migrate!
## Overview
Para makes it easy to migrate users and/or wallets from another system. As with any migration, there are many nuances to
consider, and a variety of options for how to approach a migration. First, you'll need to determine what type of
integration you want to complete.
## Migration Scope
New pregenerated wallets will be created for your existing users, which they can claim when they log in. Please see
our [GitHub repository](https://github.com/getpara/examples-hub/tree/2.0.0-alpha/web/) for a sample code snippet and
instructions on how to leverage pregenerated wallets.
In addition to creating new wallets, assets can be transferred either in a batch (if migrating from a custodial system) or just-in-time as users claim their wallet and log in. In this method, assets can be ported over, but users will receive a new wallet address with Para.
If you are following this path, please get in touch with Para as the specifics of a migration path and options vary based on your current provider.
Para can also support importing a private key if your provider offers an export private key option. Using this path, users can keep the same wallet address they currently have.
This feature is experimental and availability varies based on the provider currently being used. If you would like to follow this path, please get in touch with Para for more information and to get access.
## Migration Timing
For each of these options, there are two paths to migrating:
Move users over proactively. This option works best if: - You don't have assets to migrate - You're migrating with a
smart contract account setup - You're migrating from a custodian that has a batch export feature
As users onboard, migrate over their account and/or assets. This option works best if you need users to: - Sign a
transaction to onboard - Take an action such as exporting a private key and importing it into Para's system
Migrations can be tricky business! We're here to help, please get in touch and consider us your thought partners in
this process.
# Welcome
Source: https://docs.getpara.com/v2/introduction/welcome
Welcome to the Para Developer Docs! If you're looking to learn more about integrating Para or discover advanced features, you've come to the right place!
export const IconTileGrid = ({children}) => {
if (typeof document === "undefined") return null;
return
{children}
;
};
export const IconTileRow = ({title, children}) => {
if (typeof document === "undefined") return null;
return ;
};
export const IconTile = ({src, label, href, disabled = false, disabledLabel = "Talk to us!", id = 'icon-tile'}) => {
const [isHovered, setIsHovered] = useState(false);
const [isLabelVisible, setIsLabelVisible] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleMouseEnter = () => {
setIsHovered(true);
setIsLabelVisible(true);
};
const handleMouseLeave = () => {
setIsHovered(false);
setIsLabelVisible(false);
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Banner = ({title, description, primaryButton, secondaryButton, id = 'banner'}) => {
const hasTwoButtons = primaryButton && secondaryButton;
return ;
};
## Choose Your Framework
Para provides SDKs for various frameworks to help you integrate quickly and easily. Pick your preferred framework below to get started with the integration guide.
Looking to pregenerate wallets? Check out
## Integration Guides
Para supports any EVM, Solana, or Cosmos chain and is compatible with popular signing libraries. We also have adapters for wallet connector libraries.
## Additional Resources
Para provides a range of resources to help you troubleshoot and enhance your integration. Explore our examples hub for sample apps, or check out our troubleshooting guides for framework-specific solutions.
Using an LLM (ChatGPT, Claude) or Coding Assistant (Cursor, Github Copilot)? Here are a few tips:
1. Include the for the most up-to-date help
2. Check out the for an interactive LLM using Para Examples Hub
# What's New in Para v2.0 Alpha
Source: https://docs.getpara.com/v2/introduction/whats-new
A high-level overview of new features and improvements in Para v2.0 Alpha
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
## Overview
Para v2.0 Alpha represents a significant evolution in our SDK architecture and developer experience. This release introduces streamlined authentication flows, improved component structure, and enhanced wallet management while maintaining backward compatibility where possible.
## New Features
*We'll keep adding features as they get rolled out into alpha, check back in here for the latest!*
* **Guest Mode**: Let users ["Continue as Guest"](/v2/react/guides/customization/guest-mode) and provision them a wallet to experience your app before they sign up.
## Key Improvements
### Simplified Authentication
The v2.0 Alpha release dramatically simplifies authentication flows by consolidating multiple methods into single, intuitive interfaces:
* **Unified Entry Point**: The new `signUpOrLogIn` method replaces separate user existence checks, login initiation, and user creation methods
* **Standardized Auth State System**: A consistent state machine approach for tracking authentication progress
* **Enhanced OAuth Flow**: Streamlined third-party authentication with platforms like Google, Apple, and Discord
* **Improved Social Login**: Simplified Farcaster and Telegram login experiences
### Enhanced React Integration
React developers will find substantial improvements to the integration experience:
* **Single Provider Pattern**: The `ParaProvider` now handles all configuration needs
* **Built-in Modal**: Modal functionality is now included within the provider by default
* **React Query Integration**: Leverages the power of TanStack Query for predictable state management
* **Powerful Hooks**: New purpose-built hooks that encapsulate common authentication and wallet operations
### Streamlined Wallet Management
Wallet operations have been refined for better developer experience:
* **Simplified Pregen Wallet API**: More intuitive API for creating and managing pregenerated wallets
* **Improved Wallet Type System**: Better TypeScript support with string union types replacing enums
* **Consistent Identity Representation**: New auth object pattern for representing user identities
### Cancellable Operations
Long-running operations now support cancellation, improving the user experience:
* **Interactive Polling**: Long-running operations support cancellation callbacks
* **Progress Events**: Operations can emit progress events for better UI feedback
* **Error Recovery**: Improved error handling for interrupted operations
## Developer Experience Improvements
Beyond the technical enhancements, Para v2.0 Alpha brings significant developer experience improvements:
* **Object Parameter Pattern**: All methods now use a consistent object parameter pattern, improving code readability and extensibility
* **Reduced Boilerplate**: Common authentication flows require significantly less code
* **Better TypeScript Support**: Enhanced type definitions and more precise typing
* **Simplified Configuration**: External wallet configuration is now consolidated in one place
## Looking Forward
Para v2.0 Alpha represents our commitment to continuously improving the developer experience. As we progress toward the stable 2.0 release, we welcome your feedback on these changes.
For detailed technical information on migrating your existing Para integration to v2.0 Alpha, please refer to our
# Web Examples
Source: https://docs.getpara.com/v2/react/examples
Explore Para's web integration examples across popular frameworks
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Para offers a comprehensive collection of web examples to help you integrate our technology across your preferred
frontend frameworks. Our examples-hub repository follows a consistent naming convention with folders structured as
(e.g., `with-react-vite` or `with-vue-vite`).
Each framework folder contains lightweight, standalone examples that focus on specific Para SDKs or features,
demonstrating minimal implementation requirements. These examples are designed to showcase individual capabilities with
clean, focused code that you can easily adapt to your specific application needs and use cases.
## Para Web Examples
Browse our web examples showcasing Para integration with popular frameworks:
## Signing Examples
Explore different signing implementations with Para:
## Wallet Pregeneration
Para also supports specialized web integration scenarios:
## Specialized Integrations
Discover how Para integrates with platform-specific web applications:
## Need Something Specific?
Don't see an example for your use case? Para's team is eager to create new examples to help you integrate with different libraries, third-party features, or providers.
# Guest Mode
Source: https://docs.getpara.com/v2/react/guides/customization/guest-mode
Allow users to use your app via guest wallets without signing up.
Guest Mode allows you to provision one or more wallets for a new user so they can start using your app without going through the sign-up process.
With Guest Mode enabled, you can offer an option in the Para Modal for your users to get started with a guest account without signing up. When users eventually sign up, any previously created guest wallets will immediately be linked to their account.
## Integration Methods
There are two primary ways to implement Guest Mode:
The easiest way to implement Guest Mode is via the Para Modal. Simply set the corresponding configuration setting (`isGuestModeEnabled`) in your `ParaProvider` configuration to `true`.
This setting adds a "Continue as Guest" option to the modal sign-in screen, which closes the modal and performs wallet setup in the background. If the modal is reopened, guest users will see a special version of the account screen, from which they can proceed to finish signing up and then claim their existing wallets.
```tsx App.tsx {13}
import { ParaProvider, Environment } from "@getpara/react-sdk@alpha";
function App() {
return (
{
console.log('Guest wallets created!', event.detail);
}
}}
>
);
}
```
If you are using a custom UI implementation or you would like to enter Guest Mode before your user opens the Para Modal, you can use the `useCreateGuestWallets` hook to create guest wallets programmatically:
```tsx AppContent.tsx
import { useCreateGuestWallets } from "@getpara/react-sdk@alpha";
// This component must be wrapped within a `ParaProvider` to function properly
function AppContent() {
const { createGuestWallets, isPending, isError, error } = useCreateGuestWallets();
const onClickGuestLoginButton = () => {
createGuestWallets(
undefined,
{
onSuccess: (wallets) => {
console.log('Guest wallets created, app is now in Guest Mode:', wallets);
},
onError: (error) => {
console.error('Error creating guest wallets:', error);
},
onSettled: () => {
console.log('Guest wallets creation process settled.');
}
}
)
};
// ...
}
```
### Tracking Guest Wallet Creation
Whether you use the modal or a custom solution, you can monitor and reflect guest wallet creation status by using the `useCreateGuestWalletsState` hook. For example, you will likely want to block any signing-related interface actions until the wallets have been created.
```tsx AppContent.tsx
import { useCreateGuestWalletsState } from "@getpara/react-sdk@alpha";
function AppContent() {
const { isPending: isCreatingGuestWallets, error } = useCreateGuestWalletsState();
if (error) {
console.error('Error creating guest wallets:', error);
return Error creating guest wallets.
;
}
return (
{isCreatingGuestWallets ? (
Creating guest wallets...
) : (
Guest wallets created successfully!
)}
)
}
```
Due to implementation details of React Query, the `useCreateGuestWallets` hook will not reliably reflect the status of the Para Modal's guest wallet creation process. To monitor the modal operation's status from the rest of your app, you *must* instead use `useCreateGuestWalletsState`. The hook's return type resembles React Query's `UseMutationReturnType` type and has most of the same fields.
## Limitations
Currently, guest wallets are prevented from buying or selling crypto through the integrated onramp providers. If a guest wallet is funded, a message is presented to the user in the Para Modal account screen encouraging them to sign up and retain access to their funds. You are, of course, free to fund guest wallets if you desire, but note that you must be careful to maintain user access to the wallets to ensure no funds are lost.
We recommend using `getUserShare` and `setUserShare` to save and restore the user share for a guest wallet, just as you would for a pregenerated wallet.
# Cosmos Wallets
Source: https://docs.getpara.com/v2/react/guides/external-wallets/cosmos
Learn how to combine the Para Modal with Cosmos wallets.
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
This guide will walk you through the process of integrating Cosmos Wallets into your Para Modal and Para-enabled
application, allowing you to onboard new users and connect with existing users who may already have external wallets
like Keplr, Leap, Cosmostation and more.
## Prerequisites
Before integrating wallet connections, ensure you have an existing Para project with the Para Modal set up. If you
haven't set up Para yet, follow one of our Framework Setup guides like this guide.
### Setting up Cosmos Wallets
Para integrates with leading Cosmos wallets. Our integration leverages a modified fork of the React library.
#### Supported Wallets
Para supports the following Cosmos wallets:
* - A secure and user-friendly wallet for the Cosmos ecosystem
* - The interchain wallet for the Cosmos ecosystem
* - A comprehensive wallet and validator operator for Cosmos SDK-based blockchains
Import the necessary wallet connectors and chain configurations:
```typescript main.tsx
import { useState } from "react";
import {
ParaProvider,
ExternalWallet,
} from "@getpara/react-sdk";
import { cosmoshub, osmosis } from "@getpara/graz/chains";
import { type ChainInfo } from "keplr-wallet/types";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
```
If you encounter type issues with `@getpara/graz/chains`,@alpha you'll need to generate the chain files. You can:
1. Add a postinstall script to your package.json:
```json
{
"scripts": {
"postinstall": "graz --generate"
}
}
```
2. Or run `npx graz --generate` manually after installation
Set up your Cosmos chain configurations with the necessary RPC and REST endpoints. You can extend the existing chain configurations with your custom endpoints:
```typescript main.tsx
const cosmosChains: ChainInfo[] = [
{
...cosmoshub,
rpc: "https://rpc.cosmos.directory/cosmoshub", // Replace with your RPC endpoint
rest: "https://rest.cosmos.directory/cosmoshub", // Replace with your REST endpoint
},
{
...osmosis,
rpc: "https://rpc.cosmos.directory/osmosis",
rest: "https://rest.cosmos.directory/osmosis",
},
];
```
Similar to the Cosmos and Solana providers, configure the `ParaProvider` component by wrapping your application content in the `ParaProvider` component. Pass in the required configuration props:
```typescript main.tsx
export const App = () => {
const [chainId, setChainId] = useState(cosmoshub.chainId);
return (
{
setChainId({ selectedChainId: chainId });
},
chains: cosmosChains,
},
// grazProviderProps={}
},
walletConnect: {
projectId: 'your_walletconnect_project_id',
},
}>{
/* Your app content */}
);
};
```
For the ParaCosmosProvider wrapping you don't need to include a QueryClientProvider as the provider already includes
one.
### External Wallet Configuration
void", description: "Callback function when user switches chains", required: true },
{ name: "chains", type: "ChainInfo[]", description: "Array of Cosmos chain configurations", required: true },
{ name: "multiChain", type: "boolean", description: "Enable multi-chain support. Defaults to false", required: false }
]},
{ name: "grazProviderProps", type: "object", description: "Other props to pass to the `GrazProvider`", required: false }
]},
{ name: "walletConnect", type: "object", description: "", required: true, parameters: [
{ name: "projectId", type: "string", description: "Your WalletConnect (Reown) project id", required: true }
]}
]}
returns={{
type: "object"
}}
/>
The `ParaProvider` is built on top of
and supports all of its configuration options.
## External Wallets with Linked Embedded Wallets
You can also provision linked embedded wallets for external wallets.
In this case, the external wallet would be the Para auth method for the user’s embedded wallet (instead of an email or social login). Embedded wallets would be created according to your API key settings.
To enable this, you can include the `createLinkedEmbeddedForExternalWallets` prop to indicate which external wallets this setting should be applied to.
## Advanced Provider Pattern
Setting up a dedicated provider component that encapsulates all the necessary providers and modal state management is
considered a best practice. This pattern makes it easier to manage the modal state globally and handle session
management throughout your application.
### Server-Side Rendering Considerations
When using Next.js or other SSR frameworks, proper client-side initialization is crucial since web3 functionality relies
on browser APIs. There are two main approaches:
1. Using the `'use client'` directive in Next.js 13+:
* Add the directive at the component level where browser APIs are needed
* Ensures the CosmosProvider component and its dependencies only run on the client
* Maintains better code splitting and page performance
2. Using dynamic imports:
* Lazily loads the provider component
* Automatically handles client-side only code
* Provides fallback options during loading
## Configuring the Para Modal
After setting up your providers you need to configure the ParaModal component to display the external wallets and
authentication options to your users. You need to pass in the `externalWallets` and `authLayout` configuration options
to the ParaModal component to control which of the wallets show in the modal that were specified in the provider
configuration.
### Set the modal props
```typescript
paraModalConfig={{
authLayout: ["AUTH_FULL","EXTERNAL_FULL"]
theme: {
mode: "light",
foregroundColor: "#000000",
backgroundColor: "#FFFFFF",
accentColor: "#007AFF"
}
logo: yourLogoUrl
// ... other modal config
}}
```
#### Modal Props Config
Modal prop options for customizing the Para Modal are included below. For advanced customization options, refer to
.
", required: true },
{ name: "theme", type: "object", description: "", required: false, parameters: [
{ name: "mode", type: "'light' | 'dark'", description: "Color mode for the modal", required: false },
{ name: "foregroundColor", type: "string", description: "Primary text and content color (hex format)", required: false },
{ name: "backgroundColor", type: "string", description: "Modal background color (hex format)", required: false },
{ name: "accentColor", type: "string", description: "Highlight and button colors (hex format)", required: false }
]},
{ name: "logo", type: "string", description: "URL for your application logo", required: false },
{ name: "appName", type: "string", description: "Your application name displayed in the modal", required: false },
{ name: "para", type: "ParaClient", description: "Your initialized Para client instance", required: true },
{ name: "oAuthMethods", type: "OAuthMethod[]", description: "Array of supported OAuth authentication methods", required: false },
{ name: "disableEmailLogin", type: "boolean", description: "Disable email-based authentication", required: false },
{ name: "disablePhoneLogin", type: "boolean", description: "Disable phone-based authentication", required: false },
{ name: "recoverySecretStepEnabled", type: "boolean", description: "Enable the recovery secret step in the flow", required: false },
{ name: "onRampTestMode", type: "boolean", description: "Enable test mode for on-ramp features", required: false }
]}
returns={{
type: "component"
}}
/>
## External Wallet Verification
External wallet verification adds a verification step during external connection to ensure the user owns the wallet.
Enabling this feature establishes a valid Para session, which you can later use in your app to securely validate wallet ownership.
To enable this, set the following option on your `externalWalletConfig` of your `ParaProvider`:
```
externalWalletConfig={{
includeWalletVerification: true,
...REST_OF_CONFIG
}}
```
## Connection Only Wallets
Connection only external wallets bypass all Para functionality (account creation, user tracking, etc.) when connecting an external wallet. To enable this, set the following option on your `externalWalletConfig` of your `ParaProvider`:
```
externalWalletConfig={{
connectionOnly: true,
...REST_OF_CONFIG
}}
```
Since connection only wallets bypass Para, most Para functionality will be unavailable. This includes linked embedded wallets, external wallet verification, on & off ramping, etc.
## Examples
For an example of what the Para External Wallets Modal might look like in your application, check out our live demo:
For an example code implementation using Cosmos Wallets, check out our GitHub repository:
## Next Steps
Now that you have integrated Cosmos wallets into your Para Modal, you can explore more advanced features like signing
using the Para SDK with popular libraries like `CosmJS`.
# EVM Wallets
Source: https://docs.getpara.com/v2/react/guides/external-wallets/evm
Learn how to combine the Para Modal with EVM wallets.
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
This guide will walk you through the process of integrating EVM Wallets into your Para Modal and Para-enabled
application, allowing you to onboard new users and connect with existing users who may already have external wallets
like MetaMask, Coinbase Wallet and more.
## Prerequisites
Before integrating wallet connections, ensure you have an existing Para project with the Para Modal set up. If you
haven't set up Para yet, follow one of our Framework Setup guides like this guide.
## How It Works
Para's EVM wallet integration is powered by , the popular React hooks library for Ethereum. When you configure the `ParaProvider` with external wallet support, Para automatically creates and manages the Wagmi provider internally. This means:
* **No manual Wagmi setup required** - Para handles all Wagmi provider configuration
* **All Wagmi hooks available** - Use any Wagmi hook in your application alongside Para hooks
* **Unified configuration** - Configure chains and settings through Para's `externalWalletConfig`
* **Automatic connector management** - Para controls wallet connectors based on your configuration
## Setting up EVM Wallets
Setup is simple - just wrap your app in a provider and pass the appropriate props and configuration options to the
provider. Once configured, the Para modal and wallet options will automatically appear in the modal when opened.
Para provides seamless integration with popular EVM wallets including
, , , , , , , , , , and .
**Safe App Registration**: To use Safe as an external wallet, you'll need to register your application as a Safe App in the . This is required because Safe apps need to run within Safe's context to ensure proper security and functionality. The registration process involves providing your app's details and undergoing a review by the Safe team.
### Import components
Import the wallet connectors and supporting components you need. Adjust the imports based on which wallets you want to support:
```typescript main.tsx
import {
ParaProvider,
ExternalWallet,
} from "@getpara/react-sdk";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { sepolia, celo, mainnet, polygon } from "wagmi/chains";
```
### Configure the providers
Configure the `ParaProvider` component by wrapping your application content in the `QueryClientProvider` and `ParaProvider` components. Pass in the required configuration props:
```typescript main.tsx
const queryClient = new QueryClient();
export const App = () => {
return (
{/* Your app content */}
);
};
```
The `ParaProvider` automatically creates and manages the Wagmi provider internally. You only need to provide the `QueryClientProvider` - Para handles all Wagmi setup for you.
### External Wallet Configuration
are supported except `connectors` (which Para manages).", required: true, parameters: [
{ name: "chains", type: "Chain[]", description: "Array of supported EVM chains from wagmi/chains (e.g., mainnet, polygon, sepolia)", required: true },
{ name: "ssr", type: "boolean", description: "Enable SSR support for hydration. Set to `true` if experiencing hydration issues.", required: false },
{ name: "...wagmiConfig", type: "", description: "All other wagmi config values can be passed to this `config` object", required: false }
]},
{ name: "wagmiProviderProps", type: "object", description: "Other props to pass to the `WagmiProvider`", required: false }
]},
{ name: "walletConnect", type: "object", description: "", required: true, parameters: [
{ name: "projectId", type: "string", description: "Your WalletConnect (Reown) project id", required: true }
]}
]}
returns={{
type: "object"
}}
/>
**WalletConnect (Reown) Setup:** You'll need a WalletConnect project ID if you're using their connector. Get one from
the .
You can use an empty string for testing, but this isn't recommended for production.
The `ParaProvider` extends Wagmi's provider functionality, giving you access to all in your application. Place the provider near the root of your component tree for optimal performance.
## Accessing the Wagmi Configuration
Para provides two methods to access the Wagmi configuration depending on your use case:
### During Runtime (Inside ParaProvider)
Use the `getWagmiConfig` function when you need the configuration inside the ParaProvider context but outside of React hooks:
```typescript
import { getWagmiConfig } from "@getpara/evm-wallet-connectors@alpha";
// Use anywhere inside ParaProvider context
const wagmiConfig = getWagmiConfig();
// Now you can use with @wagmi/core actions
import { getAccount } from '@wagmi/core'
const account = getAccount(wagmiConfig)
```
### Before ParaProvider Initialization
If you need the Wagmi config before the ParaProvider mounts (e.g., for server-side operations or early initialization), use `createParaWagmiConfig`:
```typescript
import { createParaWagmiConfig } from "@getpara/evm-wallet-connectors@alpha";
// Initialize config early
const wagmiConfig = createParaWagmiConfig({
chains: [mainnet, polygon],
// ... other wagmi config options
});
// ParaProvider will automatically use this pre-created config
// when it mounts later
```
The `createParaWagmiConfig` function creates the same configuration that ParaProvider would create internally. This enables you to use the config with `@wagmi/core` actions before your React app renders.
## Server-Side Rendering (SSR) Considerations
When using Next.js or other SSR frameworks, proper client-side initialization is crucial since web3 functionality relies on browser APIs. **SSR management is the developer's responsibility**, and Para provides the tools to handle it effectively.
### Handling Hydration Issues
If you encounter hydration errors related to `@getpara/evm-wallet-connectors`, this indicates that Wagmi's store hydration is happening too eagerly. Since Para uses Wagmi internally, all apply:
1. **Enable SSR mode** in your configuration:
```typescript
externalWalletConfig={{
evmConnector: {
config: {
chains: [mainnet],
ssr: true, // Enable SSR support
},
},
// ... rest of config
}}
```
2. **Use dynamic imports** for client-side only rendering:
```typescript
import dynamic from 'next/dynamic'
const ParaProvider = dynamic(
() => import('@getpara/react-sdk@alpha').then(mod => mod.ParaProvider),
{ ssr: false }
)
```
3. **Add the `'use client'` directive** in Next.js 13+:
```typescript
'use client'
import { ParaProvider } from '@getpara/react-sdk'
export function Providers({ children }) {
// Provider implementation
}
```
### Cookie-Based Persistence
For advanced SSR scenarios where you want to persist wallet connection state across server renders, implement :
```typescript
import { cookieStorage, createStorage } from 'wagmi'
externalWalletConfig={{
evmConnector: {
config: {
chains: [mainnet],
ssr: true,
storage: createStorage({
storage: cookieStorage,
}),
},
},
// ... rest of config
}}
```
Cookie-based persistence requires proper cookie handling on your server. This is entirely managed by the developer - Para provides the configuration options, but implementation depends on your server framework.
## External Wallets with Linked Embedded Wallets
You can also provision linked embedded wallets for external wallets.
In this case, the external wallet would be the Para auth method for the user's embedded wallet (instead of an email or social login). Embedded wallets would be created according to your API key settings.
To enable this, you can include the `createLinkedEmbeddedForExternalWallets` prop to indicate which external wallets this setting should be applied to.
## Advanced Provider Pattern
Setting up a dedicated provider component that encapsulates all the necessary providers and modal state management is
considered a best practice. This pattern makes it easier to manage the modal state globally and handle session
management throughout your application.
## Configuring the Para Modal
After setting up your providers you need to configure the ParaModal component to display the external wallets and
authentication options to your users. You need to pass in the `externalWallets` and `authLayout` configuration options
to the ParaModal component to control which of the wallets show in the modal that were specified in the provider
configuration.
### Set the modal props
```typescript
paraModalConfig={{
authLayout: ["AUTH_FULL","EXTERNAL_FULL"]
theme: {
mode: "light",
foregroundColor: "#000000",
backgroundColor: "#FFFFFF",
accentColor: "#007AFF"
}
logo: yourLogoUrl
// ... other modal config
}}
```
#### Modal Props Config
Modal prop options for customizing the Para Modal are included below. For advanced customization options, refer to
.
", required: true },
{ name: "theme", type: "object", description: "", required: false, parameters: [
{ name: "mode", type: "'light' | 'dark'", description: "Color mode for the modal", required: false },
{ name: "foregroundColor", type: "string", description: "Primary text and content color (hex format)", required: false },
{ name: "backgroundColor", type: "string", description: "Modal background color (hex format)", required: false },
{ name: "accentColor", type: "string", description: "Highlight and button colors (hex format)", required: false }
]},
{ name: "logo", type: "string", description: "URL for your application logo", required: false },
{ name: "appName", type: "string", description: "Your application name displayed in the modal", required: false },
{ name: "para", type: "ParaClient", description: "Your initialized Para client instance", required: true },
{ name: "oAuthMethods", type: "OAuthMethod[]", description: "Array of supported OAuth authentication methods", required: false },
{ name: "disableEmailLogin", type: "boolean", description: "Disable email-based authentication", required: false },
{ name: "disablePhoneLogin", type: "boolean", description: "Disable phone-based authentication", required: false },
{ name: "recoverySecretStepEnabled", type: "boolean", description: "Enable the recovery secret step in the flow", required: false },
{ name: "onRampTestMode", type: "boolean", description: "Enable test mode for on-ramp features", required: false }
]}
returns={{
type: "component"
}}
/>
## External Wallet Verification via SIWE
External wallet verification via Sign in With Ethereum adds a verification step during external connection to ensure the user owns the wallet.
Enabling this feature establishes a valid Para session, which you can later use in your app to securely validate wallet ownership.
To enable this, set the following option on your `externalWalletConfig` of your `ParaProvider`:
```
externalWalletConfig={{
includeWalletVerification: true,
...REST_OF_CONFIG
}}
```
## Connection Only Wallets
Connection only external wallets bypass all Para functionality (account creation, user tracking, etc.) when connecting an external wallet. To enable this, set the following option on your `externalWalletConfig` of your `ParaProvider`:
```
externalWalletConfig={{
connectionOnly: true,
...REST_OF_CONFIG
}}
```
Since connection only wallets bypass Para, most Para functionality will be unavailable. This includes linked embedded wallets, external wallet verification, on & off ramping, etc.
## Examples
For an example of what the Para External Wallets Modal might look like in your application, check out our live demo:
For an example code implementation using EVM Wallets, check out our GitHub repository:
## Next Steps
Now that you have integrated EVM wallets into your Para Modal, you can explore more advanced features like signing using
the Para SDK with popular libraries like `Ethers.js`.
# Multichain Wallets
Source: https://docs.getpara.com/v2/react/guides/external-wallets/multichain
Learn how to combine EVM, Solana, and Cosmos wallets with the Para Modal.
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
This guide will walk you through the process of integrating multiple blockchain wallets into your Para Modal and
Para-enabled application. By combining EVM, Solana, and Cosmos wallet support, you can provide users with a seamless
multi-chain experience.
## Prerequisites
Before integrating wallet connections, ensure you have an existing Para
project with the Para Modal set up. If you haven't set up Para yet, follow one
of our Framework Setup guides like this guide.
## Setting up Multichain Support
Supporting multiple blockchain ecosystems is simple, all you need to do is install the necessary wallet connectors and
configure them within your Para Provider. Instructions for each connector can be found in the respective guides for each
ecosystem:
Multi chain wallets can only be connected to one chain at a time. Any wallets
that Para is setup to support across ecosystems will give the give the user a
choice of ecosystem selection before they connect their wallet.
## Examples
Check out our live demo of the Para Modal to configure all wallets:
For a code implementation, check out our GitHub repository:
## Next Steps
Now that you have integrated multichain wallet support, explore chain-specific features and integrations:
# Solana Wallets
Source: https://docs.getpara.com/v2/react/guides/external-wallets/solana
Learn how to combine the Para Modal with Solana wallets.
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
This guide will walk you through the process of integrating Solana Wallets into your Para Modal and Para-enabled
application, allowing you to onboard new users and connect with existing users who may already have external wallets
like Phantom, Backpack and more.
## Prerequisites
Before integrating wallet connections, ensure you have an existing Para project with the Para Modal set up. If you
haven't set up Para yet, follow one of our Framework Setup guides like this
guide.
## Setting up Solana Wallets
Setup is simple - just wrap your app in a provider and pass the appropriate props and configuration options to the
provider. Once configured, the Para modal and wallet options will automatically appear in the modal when opened.
Para provides seamless integration with popular Solana wallets including
, , , and .
### Import components
Import the wallet connectors and supporting components you need. Adjust the imports based on which wallets you want to support:
```typescript main.tsx
import { WalletAdapterNetwork } from "@solana/wallet-adapter-base";
import { clusterApiUrl } from "@solana/web3.js";
import {
ParaProvider,
ExternalWallet,
} from "@getpara/react-sdk";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
```
### Configure the Solana network
Set up your Solana network configuration. Choose the appropriate network for your deployment environment:
```typescript main.tsx
const solanaNetwork = WalletAdapterNetwork.Devnet;
const endpoint = clusterApiUrl(solanaNetwork);
```
### Configure the providers
Configure the `ParaProvider` component by wrapping your application content in the `QueryClientProvider` and `ParaProvider` components. Pass in the required configuration props:
```typescript main.tsx
export const App = () => {
return (
{/* Your app content */}
);
};
```
#### External Wallet Configuration
## External Wallets with Linked Embedded Wallets
You can also provision linked embedded wallets for external wallets.
In this case, the external wallet would be the Para auth method for the user’s embedded wallet (instead of an email or social login). Embedded wallets would be created according to your API key settings.
To enable this, you can include the `createLinkedEmbeddedForExternalWallets` prop to indicate which external wallets this setting should be applied to.
## Advanced Provider Pattern
Setting up a dedicated provider component that encapsulates all the necessary providers and modal state management is
considered a best practice. This pattern makes it easier to manage the modal state globally and handle session
management throughout your application.
### Server-Side Rendering Considerations
When using Next.js or other SSR frameworks, proper client-side initialization is crucial since web3 functionality relies
on browser APIs. There are two main approaches:
1. Using the `'use client'` directive in Next.js 13+:
* Add the directive at the component level where browser APIs are needed. If using a custom provider, add the
directive to the top of the provider file.
* Ensures the Web3Provider component and its dependencies only run on the client side
2. Using dynamic imports:
* In Next.js, use the `dynamic` function to import the provider component with `{ ssr: false }`.
* Lazily loads the provider component
* Automatically handles client-side only code
* Provides fallback options during loading
## Configuring the Para Modal
After setting up your providers you need to configure the ParaModal component to display the external wallets and
authentication options to your users. You need to pass in the `externalWallets` and `authLayout` configuration options
to the ParaModal component to control which of the wallets show in the modal that were specified in the provider
configuration.
### Set the modal props
```typescript
paraModalConfig={{
authLayout: ["AUTH_FULL","EXTERNAL_FULL"]
theme: {
mode: "light",
foregroundColor: "#000000",
backgroundColor: "#FFFFFF",
accentColor: "#007AFF"
}
logo: yourLogoUrl
// ... other modal config
}}
```
#### Modal Props Config
Modal prop options for customizing the Para Modal are included below. For advanced customization options, refer to
.
", required: true },
{ name: "theme", type: "object", description: "", required: false, parameters: [
{ name: "mode", type: "'light' | 'dark'", description: "Color mode for the modal", required: false },
{ name: "foregroundColor", type: "string", description: "Primary text and content color (hex format)", required: false },
{ name: "backgroundColor", type: "string", description: "Modal background color (hex format)", required: false },
{ name: "accentColor", type: "string", description: "Highlight and button colors (hex format)", required: false }
]},
{ name: "logo", type: "string", description: "URL for your application logo", required: false },
{ name: "appName", type: "string", description: "Your application name displayed in the modal", required: false },
{ name: "para", type: "ParaClient", description: "Your initialized Para client instance", required: true },
{ name: "oAuthMethods", type: "OAuthMethod[]", description: "Array of supported OAuth authentication methods", required: false },
{ name: "disableEmailLogin", type: "boolean", description: "Disable email-based authentication", required: false },
{ name: "disablePhoneLogin", type: "boolean", description: "Disable phone-based authentication", required: false },
{ name: "recoverySecretStepEnabled", type: "boolean", description: "Enable the recovery secret step in the flow", required: false },
{ name: "onRampTestMode", type: "boolean", description: "Enable test mode for on-ramp features", required: false }
]}
returns={{
type: "component"
}}
/>
## External Wallet Verification
External wallet verification adds a verification step during external connection to ensure the user owns the wallet.
Enabling this feature establishes a valid Para session, which you can later use in your app to securely validate wallet ownership.
To enable this, set the following option on your `externalWalletConfig` of your `ParaProvider`:
```
externalWalletConfig={{
includeWalletVerification: true,
...REST_OF_CONFIG
}}
```
## Connection Only Wallets
Connection only external wallets bypass all Para functionality (account creation, user tracking, etc.) when connecting an external wallet. To enable this, set the following option on your `externalWalletConfig` of your `ParaProvider`:
```
externalWalletConfig={{
connectionOnly: true,
...REST_OF_CONFIG
}}
```
Since connection only wallets bypass Para, most Para functionality will be unavailable. This includes linked embedded wallets, external wallet verification, on & off ramping, etc.
## Examples
For an example of what the Para External Wallets Modal might look like in your application, check out our live demo:
For an example code implementation using Solana Wallets, check out our GitHub repository:
## Next Steps
Now that you have integrated Solana wallets into your Para Modal, you can explore more advanced features like signing using the Para SDK with popular libraries like `Web3js`.
# Migrating from Reown to Para
Source: https://docs.getpara.com/v2/react/guides/migration-from-reown
Step-by-step guide for migrating your Reown (WalletConnect) application to Para SDK
Migrate your existing Reown (WalletConnect) application to Para's unified wallet system. Para simplifies wallet management by providing a single `ParaProvider` component that handles both embedded and external wallets while maintaining full Wagmi compatibility.
## Installation
Update your dependencies to replace Reown packages with Para SDK:
```bash Terminal
npm uninstall @reown/appkit @reown/appkit-adapter-wagmi
npm install @getpara/react-sdk@alpha --save-exact
```
For a full list of dependencies, refer to the [Quick Start Guide](/v2/react/quickstart).
## Setup
### Configure Constants
Create a constants file for your Para configuration:
```typescript src/config/constants.ts
import { Environment } from "@getpara/react-sdk";
export const API_KEY = process.env.NEXT_PUBLIC_PARA_API_KEY ?? ""; // Grab your API key from developer.getpara.com
export const ENVIRONMENT =
(process.env.NEXT_PUBLIC_PARA_ENVIRONMENT as Environment) || Environment.BETA;
if (!API_KEY) {
throw new Error("Missing NEXT_PUBLIC_PARA_API_KEY environment variable");
}
```
### Create Providers
Set up the Para provider to replace Reown's WagmiProvider:
```tsx src/context/ParaProvider.tsx
"use client";
import { ParaProvider as Provider } from "@getpara/react-sdk";
import { API_KEY, ENVIRONMENT } from "@/config/constants";
import { mainnet, polygon, sepolia } from "wagmi/chains";
import { cookieStorage, createStorage } from "wagmi";
export function ParaProvider({ children }: { children: React.ReactNode }) {
return (
{children}
);
}
```
### Update Root Layout
Replace your Reown context provider with the ParaProvider:
```tsx src/app/layout.tsx
import type { Metadata } from "next";
import "@getpara/react-sdk/styles.css";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ParaProvider } from "@/context/ParaProvider";
const queryClient = new QueryClient();
export const metadata: Metadata = {
title: "Your App",
description: "Powered by Para",
};
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
{children}
);
}
```
## Usage
### Connect Button
Replace Reown's ` ` with Para's modal hooks:
```tsx src/components/ConnectButton.tsx
"use client";
import { useAccount, useModal, useWallet } from "@getpara/react-sdk";
export function ConnectButton() {
const { openModal } = useModal();
const { data: wallet } = useWallet();
const { isConnected } = useAccount();
if (isConnected && wallet?.address) {
return (
openModal()} className="connect-button">
{wallet.address.slice(0, 6)}...{wallet.address.slice(-4)}
);
}
return (
openModal()} className="connect-button">
Connect Wallet
);
}
```
### Using Wagmi Hooks
`ParaProvider` maintains full Wagmi compatibility. Your existing Wagmi code continues to work within the Para context.
```tsx src/components/Balance.tsx
import { useAccount, useBalance } from "wagmi";
export function Balance() {
const { address } = useAccount();
const { data } = useBalance({ address });
if (!data) return null;
return (
Balance: {data.formatted} {data.symbol}
);
}
```
## Migration Checklist
* Remove `@reown/appkit` packages
* Install `@getpara/react-sdk`
* Keep Wagmi and Viem packages
* Run postinstall script
* Set environment variables
* Update Next.js config (remove Webpack externals)
* Import Para styles
* Configure chain list
* Replace ` ` with custom component
* Update provider hierarchy
* Test wallet connections
* Verify transaction flows
* Connect external wallets
* Test embedded login (email/social)
* Verify chain switching
* Check transaction signing
## Next Steps
Explore Para's React hooks for wallet interactions
Customize the Para modal appearance and behavior
Configure additional external wallet support
Learn about Para's session management
# Migrating from Thirdweb to Para
Source: https://docs.getpara.com/v2/react/guides/migration-from-thirdweb
Step-by-step guide for migrating your Thirdweb application to Para SDK
Migrate your existing Thirdweb application to Para's unified wallet system. Para provides similar wallet connection capabilities with additional features like embedded wallets and session management while maintaining a simple integration.
## Installation
Replace Thirdweb with Para SDK:
```bash Terminal
npm uninstall thirdweb
npm install @getpara/react-sdk @tanstack/react-query wagmi viem
```
For a full list of dependencies, refer to the [Quick Start Guide](/v2/react/quickstart).
## Configuration Changes
### Before: Thirdweb Client
Your existing Thirdweb client configuration:
```typescript lib/client.ts
import { createThirdwebClient } from "thirdweb";
export const client = createThirdwebClient({
clientId: process.env.NEXT_PUBLIC_THIRDWEB_CLIENT_ID!,
});
```
### After: Para Configuration
Replace with Para configuration:
```typescript src/config/constants.ts
import { Environment } from "@getpara/react-sdk";
export const API_KEY = process.env.NEXT_PUBLIC_PARA_API_KEY ?? "";
export const ENVIRONMENT =
(process.env.NEXT_PUBLIC_PARA_ENVIRONMENT as Environment) || Environment.BETA;
if (!API_KEY) {
throw new Error("Missing NEXT_PUBLIC_PARA_API_KEY environment variable");
}
```
## Provider Migration
### Before: Thirdweb Provider
Your existing Thirdweb provider in the layout:
```tsx app/layout.tsx
import type { Metadata } from "next";
import { ThirdwebProvider } from "thirdweb/react";
export const metadata: Metadata = {
title: "Your App",
description: "Your App Description",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
{children}
);
}
```
### After: Para Provider Setup
Create a Para provider component:
```tsx src/context/ParaProvider.tsx
"use client";
import { ParaProvider as Provider } from "@getpara/react-sdk";
import { API_KEY, ENVIRONMENT } from "@/config/constants";
import { mainnet, polygon, arbitrum } from "wagmi/chains";
export function ParaProvider({ children }: { children: React.ReactNode }) {
return (
{children}
);
}
```
Update your layout:
```tsx src/app/layout.tsx
import type { Metadata } from "next";
import "@getpara/react-sdk/styles.css";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ParaProvider } from "@/context/ParaProvider";
const queryClient = new QueryClient();
export const metadata: Metadata = {
title: "Your App",
description: "Your App Description",
};
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
{children}
);
}
```
## Connect Button Migration
### Before: Thirdweb ConnectButton
```tsx app/page.tsx
"use client";
import { ConnectButton } from "thirdweb/react";
import { client } from "@/lib/client";
export default function Home() {
return (
);
}
```
### After: Para Connect Button
```tsx src/components/ConnectButton.tsx
"use client";
import { useAccount, useModal, useWallet } from "@getpara/react-sdk";
export function ConnectButton() {
const { openModal } = useModal();
const { data: wallet } = useWallet();
const { isConnected } = useAccount();
if (isConnected && wallet?.address) {
return (
openModal()} className="connect-button">
{wallet.address.slice(0, 6)}...{wallet.address.slice(-4)}
);
}
return (
openModal()} className="connect-button">
Connect Wallet
);
}
```
Use it in your page:
```tsx src/app/page.tsx
import { ConnectButton } from "@/components/ConnectButton";
export default function Home() {
return (
);
}
```
## Hook Migration
### Account Information
```tsx Thirdweb
import { useActiveAccount } from "thirdweb/react";
function Account() {
const account = useActiveAccount();
return (
Address: {account?.address}
);
}
```
```tsx Para
import { useAccount } from "@getpara/react-sdk";
function Account() {
const { address } = useAccount();
return (
Address: {address}
);
}
```
### Wallet Connection Status
```tsx Thirdweb
import { useActiveWalletConnectionStatus } from "thirdweb/react";
function ConnectionStatus() {
const status = useActiveWalletConnectionStatus();
return (
Status: {status}
);
}
```
```tsx Para
import { useAccount } from "@getpara/react-sdk";
function ConnectionStatus() {
const { isConnected, isConnecting } = useAccount();
return (
Status: {isConnecting ? "connecting" : isConnected ? "connected" : "disconnected"}
);
}
```
### Disconnect Wallet
```tsx Thirdweb
import { useDisconnect } from "thirdweb/react";
function DisconnectButton() {
const { disconnect } = useDisconnect();
return (
Disconnect
);
}
```
```tsx Para
import { useDisconnect } from "wagmi";
function DisconnectButton() {
const { disconnect } = useDisconnect();
return (
disconnect()}>
Disconnect
);
}
```
## Smart Contract Interaction
Para uses Wagmi for contract interactions, providing a different approach than Thirdweb:
### Reading Contract Data
```tsx Thirdweb
import { getContract } from "thirdweb";
import { useReadContract } from "thirdweb/react";
import { client } from "@/lib/client";
const contract = getContract({
client,
chain: ethereum,
address: "0x...",
});
function ContractRead() {
const { data } = useReadContract({
contract,
method: "function balanceOf(address) returns (uint256)",
params: ["0x..."],
});
return {data?.toString()}
;
}
```
```tsx Para
import { useReadContract } from "wagmi";
const abi = [
{
name: "balanceOf",
type: "function",
inputs: [{ name: "owner", type: "address" }],
outputs: [{ name: "balance", type: "uint256" }],
},
] as const;
function ContractRead() {
const { data } = useReadContract({
address: "0x...",
abi,
functionName: "balanceOf",
args: ["0x..."],
});
return {data?.toString()}
;
}
```
### Writing to Contract
```tsx Thirdweb
import { prepareContractCall } from "thirdweb";
import { useSendTransaction } from "thirdweb/react";
function ContractWrite() {
const { mutate: sendTransaction } = useSendTransaction();
const handleTransfer = () => {
const transaction = prepareContractCall({
contract,
method: "function transfer(address, uint256)",
params: ["0x...", 100n],
});
sendTransaction(transaction);
};
return Transfer ;
}
```
```tsx Para
import { useWriteContract } from "wagmi";
function ContractWrite() {
const { writeContract } = useWriteContract();
const handleTransfer = () => {
writeContract({
address: "0x...",
abi,
functionName: "transfer",
args: ["0x...", 100n],
});
};
return Transfer ;
}
```
## Feature Comparison
| Feature | Thirdweb | Para |
| ------------------ | ------------ | ----------- |
| Wallet Connection | ✅ | ✅ |
| Social Login | Via Auth SDK | ✅ Built-in |
| Email/Phone Login | Via Auth SDK | ✅ Built-in |
| Smart Contracts | Custom SDK | Wagmi hooks |
| Chain Switching | ✅ | ✅ |
| Session Management | Limited | ✅ Advanced |
| Gas Sponsorship | Via Engine | ✅ Built-in |
## Advanced Features
### Social Login
Para includes social login without additional configuration:
```tsx src/context/ParaProvider.tsx
paraModalConfig={{
oAuthMethods: ["GOOGLE", "APPLE", "DISCORD", "TWITTER", "FACEBOOK"],
disableEmailLogin: false,
disablePhoneLogin: false,
}}
```
### Multi-Chain Support
```tsx src/context/ParaProvider.tsx
import { mainnet, polygon, arbitrum, optimism, base } from "wagmi/chains";
externalWalletConfig={{
evmConnector: {
config: {
chains: [mainnet, polygon, arbitrum, optimism, base],
},
},
}}
```
### Custom Theme
```tsx src/context/ParaProvider.tsx
paraModalConfig={{
theme: {
mode: "dark",
foregroundColor: "#FFFFFF",
backgroundColor: "#1A1A1A",
accentColor: "#6366F1",
borderRadius: "medium",
font: "Inter",
},
logo: "/logo.svg",
}}
```
## Migration Checklist
* Remove `thirdweb` package
* Install `@getpara/react-sdk`, `wagmi`, `viem`
* Add `@tanstack/react-query`
* Run Para postinstall script
* Replace Thirdweb client with Para configuration
* Update environment variables
* Configure supported chains
* Set up WalletConnect project ID if needed
* Replace `ThirdwebProvider` with `ParaProvider`
* Update `ConnectButton` implementation
* Migrate hooks to Para/Wagmi equivalents
* Update contract interaction code
* Test wallet connections
* Verify contract interactions
* Check chain switching
* Test social login if enabled
## Common Patterns
### Balance Display
```tsx src/components/Balance.tsx
import { useAccount, useBalance } from "wagmi";
import { formatEther } from "viem";
export function Balance() {
const { address } = useAccount();
const { data } = useBalance({ address });
if (!data) return null;
return (
{formatEther(data.value)} {data.symbol}
);
}
```
### Transaction History
```tsx src/components/TransactionHistory.tsx
import { useWallet } from "@getpara/react-sdk";
export function TransactionHistory() {
const { data: wallet } = useWallet();
// Para provides transaction history through the wallet object
const transactions = wallet?.transactions || [];
return (
{transactions.map((tx) => (
{tx.hash}
))}
);
}
```
## Next Steps
Learn about Wagmi hooks for contract interactions
Explore Para's React hooks
Implement session management
# Migrating from Web3Modal to Para
Source: https://docs.getpara.com/v2/react/guides/migration-from-walletconnect
Step-by-step guide for migrating your Web3Modal (WalletConnect) application to Para SDK
Migrate your existing Web3Modal application to Para's unified wallet system. Since both Web3Modal and Para use Wagmi internally, the migration involves replacing the Web3Modal provider with Para's `ParaProvider` while maintaining your existing Wagmi configuration.
## Installation
Replace Web3Modal packages with Para SDK while keeping Wagmi:
```bash Terminal
npm uninstall @web3modal/wagmi
npm install @getpara/react-sdk
npm run postinstall
```
For a full list of dependencies, refer to the [Quick Start Guide](/v2/react/quickstart).
## Configuration Changes
### Before: Web3Modal Config
Your existing Web3Modal configuration likely looks like this:
```typescript config/index.ts
import { cookieStorage, createStorage } from 'wagmi';
import { mainnet } from 'wagmi/chains';
import { http, createConfig } from 'wagmi';
import { walletConnect, injected, coinbaseWallet } from 'wagmi/connectors';
export const projectId = process.env.NEXT_PUBLIC_PROJECT_ID;
if (!projectId) throw new Error('Project ID is not defined');
const metadata = {
name: 'Web3Modal Example',
description: 'Web3Modal Example',
url: 'https://web3modal.com',
icons: ['https://avatars.githubusercontent.com/u/37784886'],
};
export const config = createConfig({
chains: [mainnet],
transports: {
[mainnet.id]: http(),
},
connectors: [
walletConnect({ projectId, metadata, showQrModal: false }),
injected({ shimDisconnect: true }),
coinbaseWallet({
appName: metadata.name,
appLogoUrl: metadata.icons[0],
}),
],
ssr: true,
storage: createStorage({
storage: cookieStorage,
}),
});
```
### After: Para Config
Transform your configuration for Para:
```typescript src/config/constants.ts
import { Environment } from "@getpara/react-sdk";
export const API_KEY = process.env.NEXT_PUBLIC_PARA_API_KEY ?? "";
export const ENVIRONMENT =
(process.env.NEXT_PUBLIC_PARA_ENVIRONMENT as Environment) || Environment.BETA;
export const PROJECT_ID = process.env.NEXT_PUBLIC_PROJECT_ID ?? "";
if (!API_KEY) {
throw new Error("Missing NEXT_PUBLIC_PARA_API_KEY environment variable");
}
```
## Provider Migration
### Before: Web3Modal Provider
Your existing Web3Modal provider:
```tsx context/Web3ModalProvider.tsx
'use client';
import React, { ReactNode } from 'react';
import { config, projectId } from '@/config';
import { createWeb3Modal } from '@web3modal/wagmi/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { State, WagmiProvider } from 'wagmi';
const queryClient = new QueryClient();
createWeb3Modal({
wagmiConfig: config,
projectId,
enableAnalytics: true,
});
export default function Web3ModalProvider({
children,
initialState,
}: {
children: ReactNode;
initialState?: State;
}) {
return (
{children}
);
}
```
### After: Para Provider
Replace with Para's provider, passing your Wagmi config:
```tsx src/context/ParaProvider.tsx
"use client";
import { ParaProvider as Provider } from "@getpara/react-sdk";
import { API_KEY, ENVIRONMENT, PROJECT_ID } from "@/config/constants";
import { mainnet } from "wagmi/chains";
import { cookieStorage, createStorage, http } from "wagmi";
export function ParaProvider({ children }: { children: React.ReactNode }) {
return (
{children}
);
}
```
## Layout Update
### Before: Web3Modal Layout
```tsx app/layout.tsx
import './globals.css';
import type { Metadata } from 'next';
import { headers } from 'next/headers';
import { cookieToInitialState } from 'wagmi';
import { config } from '@/config';
import Web3ModalProvider from '@/context/Web3ModalProvider';
export const metadata: Metadata = {
title: 'Your App',
description: 'Your App Description',
};
export default function RootLayout({ children }: { children: React.ReactNode }) {
const initialState = cookieToInitialState(config, headers().get('cookie'));
return (
{children}
);
}
```
### After: Para Layout
```tsx src/app/layout.tsx
import type { Metadata } from "next";
import "@getpara/react-sdk/styles.css";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ParaProvider } from "@/context/ParaProvider";
const queryClient = new QueryClient();
export const metadata: Metadata = {
title: "Your App",
description: "Your App Description",
};
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
{children}
);
}
```
## Connect Button Migration
### Before: Web3Modal Button
```tsx components/ConnectButton.tsx
'use client';
import { useWeb3Modal } from '@web3modal/wagmi/react';
export default function ConnectButton() {
const { open } = useWeb3Modal();
return open()}>Connect Wallet ;
}
```
### After: Para Button
```tsx src/components/ConnectButton.tsx
"use client";
import { useAccount, useModal, useWallet } from "@getpara/react-sdk";
export function ConnectButton() {
const { openModal } = useModal();
const { data: wallet } = useWallet();
const { isConnected } = useAccount();
if (isConnected && wallet?.address) {
return (
openModal()} className="connect-button">
{wallet.address.slice(0, 6)}...{wallet.address.slice(-4)}
);
}
return (
openModal()} className="connect-button">
Connect Wallet
);
}
```
## Configuration Mapping
Para maintains full Wagmi compatibility. Your existing Wagmi hooks and configuration continue to work seamlessly.
| Web3Modal Config | Para Config | Location |
| ------------------------ | -------------------------------- | ---------------------- |
| `projectId` | `walletConnect.projectId` | `externalWalletConfig` |
| `wagmiConfig.chains` | `evmConnector.config.chains` | `externalWalletConfig` |
| `wagmiConfig.transports` | `evmConnector.config.transports` | `externalWalletConfig` |
| `wagmiConfig.ssr` | `evmConnector.config.ssr` | `externalWalletConfig` |
| `wagmiConfig.storage` | `evmConnector.config.storage` | `externalWalletConfig` |
| `metadata.name` | `config.appName` | Root config |
| `metadata.description` | `config.description` | Root config |
## Advanced Configuration
### Multiple Chains
```tsx src/context/ParaProvider.tsx
import { mainnet, polygon, arbitrum, optimism } from "wagmi/chains";
// In ParaProvider
externalWalletConfig={{
evmConnector: {
config: {
chains: [mainnet, polygon, arbitrum, optimism],
transports: {
[mainnet.id]: http(),
[polygon.id]: http(),
[arbitrum.id]: http(),
[optimism.id]: http(),
},
},
},
}}
```
### Custom RPC Endpoints
```tsx src/context/ParaProvider.tsx
import { http } from "wagmi";
// In ParaProvider
externalWalletConfig={{
evmConnector: {
config: {
transports: {
[mainnet.id]: http("https://your-custom-rpc.com"),
},
},
},
}}
```
### Social Login Support
Para adds embedded wallet support automatically:
```tsx src/context/ParaProvider.tsx
paraModalConfig={{
authLayout: ["AUTH:FULL", "EXTERNAL:FULL"],
oAuthMethods: ["GOOGLE", "APPLE", "DISCORD", "TWITTER"],
disableEmailLogin: false,
disablePhoneLogin: false,
}}
```
## Using Wagmi Hooks
Your existing Wagmi code continues to work without changes:
```tsx src/components/AccountInfo.tsx
import { useAccount, useBalance, useEnsName } from "wagmi";
export function AccountInfo() {
const { address } = useAccount();
const { data: balance } = useBalance({ address });
const { data: ensName } = useEnsName({ address });
if (!address) return null;
return (
{ensName || address}
{balance?.formatted} {balance?.symbol}
);
}
```
## Migration Checklist
* Remove `@web3modal/wagmi` and `@web3modal/wagmi/react`
* Install `@getpara/react-sdk`
* Keep `wagmi`, `viem`, and `@tanstack/react-query`
* Run the Para postinstall script
* Move Wagmi config to `externalWalletConfig.evmConnector.config`
* Add Para API key to environment variables
* Migrate metadata to Para's config object
* Keep WalletConnect project ID for external wallets
* Replace Web3ModalProvider with ParaProvider
* Remove cookie state handling (Para manages internally)
* Keep QueryClientProvider wrapper
* Import Para styles
* Replace `useWeb3Modal` with `useModal`
* Update connect button component
* Keep all Wagmi hook usage unchanged
* Test wallet connections
## Common Issues
**SSR Hydration**: Para handles SSR internally. Remove manual cookie state management from your layout.
**Connector Configuration**: Para manages wallet connectors internally. Remove explicit connector imports from Wagmi.
## Next Steps
Explore Para's React hooks for wallet interactions
Customize the Para modal appearance
Configure multi-chain support
# Permissions
Source: https://docs.getpara.com/v2/react/guides/permissions
Configure user-facing transaction confirmation dialogs
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Permission prompts give applications the option to show users a Para-managed dialog to manually approve or deny any transaction or message signing events.
This feature is required when interacting with wallets created outside your app, but can also be enabled for all wallets/transactions in your application. We recommend enabling this feature if you prefer not to implement transaction approval/display flows, or if you want users to explicitly approve every transaction on an embedded wallet.
## How it Works
Permission prompts are mandatory in the following scenarios:
* **External Wallet Interaction**: When a user attempts to sign a message or execute a transaction using their wallet in an application that is different from where the wallet was created.
* **Multi-Application Transactions**: After a wallet has been used across multiple applications, any subsequent transactions will prompt the user for approval. This ensures that the user is aware of and consents to all interactions involving their wallet, regardless of the application being used.
To enable permission prompts for all transactions/wallets, activate "Always show transaction prompts" for your API key in the
## User Interaction
When a transaction or message signing event is initiated, users will see a popup containing the following details:
* **Message Details**: An encoded string representing the message.
* **Transaction Details**:
* `From`: The wallet address initiating the transaction.
* `To`: The recipient wallet address.
* `Amount`: The number of tokens being transferred.
* `Action`: The specific action being performed (e.g., token transfer, minting an NFT).
* `Conversion Rates`: Relevant exchange rates if applicable.
* `Chain Information`: Information about the blockchain being used.
## Technical Details
This feature is enabled by default when using the `signMessage` or `signTransaction` functions, either directly or
through supported signer libraries (e.g., Ethers, Cosmos).
There is a default 30-second timeout for approvals. If this does not work for your use case, please reach out to the
Para team for instructions on overriding this value.
### Transaction Events and Statuses
* **On Approval**: If the user approves the transaction or no approval is necessary, the `signMessage/signTransaction`
function will return a `SuccessfulSignatureRes` result, which will contain the signature.
* **On Denial or Timeout**: If the user denies the transaction or the timeout is reached, a `TransactionReviewError`
will be thrown that includes the `transactionReviewUrl` that must be handled by the implementing application.
## Error Handling
When implementing permission prompts, various errors can arise during the signing process. It's important to handle
these errors gracefully to ensure a smooth user experience. Below are common scenarios and recommended handling
strategies:
### 1. Transaction Denied
**Description**: The user denies the transaction or message signing request.
**Error Handling**:
```tsx
try {
await client.sendTokens(...);
} catch (error) {
if (error instanceof TransactionReviewDenied) {
console.warn("The transaction was denied by the user.");
}
}
```
### 2. Timeout Reached
**Description**: The user does not respond to the popup within the configured timeout period. This returns additional
properties of `transactionReviewUrl` and `pendingTransactionId`:
* `pendingTransactionId` - Can be used in conjunction with the `getPendingTransaction` function available via the
CorePara class (or WebPara, by extension). If it does not exist, that means the user has denied the transaction
request.
* `transactionReviewUrl` - Can be used to open a popup if desired, which will present the user with the sign message /
transaction popup.
**Error Handling**:
```tsx
try {
await client.sendTokens(...);
} catch (error) {
if (error instanceof TransactionReviewTimeout) {
console.warn("The transaction timed out. You can retry or direct the user to review.");
}
}
```
## Next Steps
To learn more about signing messages and transactions, check out the following guides:
# Wallet Pregeneration
Source: https://docs.getpara.com/v2/react/guides/pregen
Learn how to create and manage pregenerated wallets for users with Para's SDK
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
## Overview
Wallet Pregeneration allows you to create wallets for users before they set up a wallet with Para. This feature gives
you control over when users claim and take ownership of their wallet. This guide will walk you through the process of
creating, managing, and claiming pregenerated wallets using Para's SDK.
Pregenerated wallets can be associated with an email address, a phone number, a Twitter or Discord username, or a custom
ID of your choosing (for example, an external database ID). A Para user can attempt to claim any current pregenerated
wallets in their app storage.
* For email or phone, the user will need to have the same email address or phone number linked to their account.
* For Discord or Twitter, the user will need to have authenticated via those services on your application with the same
username.
* For a custom ID, the ID in question cannot have been claimed by another user. After a successful claim, only the first
user to claim a custom ID will thereafter be allowed to claim pregenerated wallets with that ID on your application.
## Creating a Pregenerated Wallet
Before creating a wallet for a user, it's a good practice to check if one already exists.
### Check if a pregenerated wallet exists
```typescript
const hasWallet = await para.hasPregenWallet({
pregenId: { email: 'user@example.com' },
});
```
### Create a pregenerated wallet if needed
```typescript
if (!hasWallet) {
const pregenWallet = await para.createPregenWallet({
type: 'EVM',
pregenId: { email: "user@example.com" },
});
console.log("Pregenerated Wallet ID:", pregenWallet.id);
}
```
### Method Parameters
",
description: "A promise that resolves to the created pregenerated wallet object"
}}
/>
### PregenAuth Type Definition
The identifier can be an email or phone number, a third-party user ID (for Farcaster, Telegram, Discord, or X), or a custom ID relevant to your application. Choose an identifier that works best for your application architecture.
## Storing and Managing User Share
After creating a pregenerated wallet, it's crucial to securely store the user share. This share is part of Para's 2/2
MPC protocol and remains the application's responsibility until the wallet is claimed.
To retrieve the user share for a pregenerated wallet, use the `getUserShare` method:
```typescript
const userShare: string = await para.getUserShare();
```
You must securely store this user share in your backend, associated with the user's identifier. If this share is lost,
the wallet becomes permanently inaccessible.
### Best Practices for Storing the UserShare
While temporarily managing the `UserShare`, it's important that you take extra care with how you store this information.
If you ever face a situation where data becomes compromised across your systems, reach out to the Para team so we can
work on possible key rotation. However, keep in mind that Para does not store backups of this share in case of data
loss.
To mitigate this category of risks, we've compiled a few best practices:
* Encrypt `UserShares` in-transit and at-rest.
* Ensure your database has backups and periodic replicas to mitigate against data deletion risks.
* Complete a fire drill prior to going live, testing scenarios such as:
* You are unable to access your DB
* Your DB is deleted
* An internal team member's credentials are compromised
Para is happy to offer pre-launch security reviews for teams in the Growth tier or above. Let us know if you need
help!
This share management is temporary - once the user claims their wallet, Para will handle the share security through the
user's authentication methods.
## Using a Pregenerated Wallet
Before using a pregenerated wallet for signing operations, you must first load the user share into your Para client
instance. Retrieve the `UserShare` from your secure storage and load it into Para using the `setUserShare` method:
```typescript
// Load the user share you previously stored securely
await para.setUserShare(userShare);
```
Once the share is loaded, the wallet becomes available for signing operations, just like any other Para wallet:
```typescript
// Sign a message directly
const messageBase64 = btoa("Hello, World!");
const signature = await para.signMessage({
walletId,
messageBase64,
});
```
You can perform this operation using either `@getpara/server-sdk`@alpha or `@getpara/react-sdk/@alpha@getpara/web-sdk`@alpha depending
on your application architecture. The Para client that has the user share loaded is the one that can perform signing
operations.
### Using with Ecosystem Libraries
Once the `userShare` is set, your Para client functions like any standard wallet. You can now easily integrate with
popular blockchain libraries to perform transactions and other operations.
For detailed integration guides with blockchain ecosystems, see:
*
*
*
## Claiming a Pregenerated Wallet
Claiming pregenerated wallets must be done client-side with the Para Client SDK. The Server SDK does not support the
key rotation operations required for wallet claiming.
Claiming transfers ownership of a pregenerated wallet to a user's Para account. This process requires:
1. The user must be fully authenticated with Para
2. The wallet's user share must be loaded into the Para client
3. The wallet's identifier must match the authenticated user's identifier
### Prerequisites for Claiming
#### Claiming with the modal
### Define the function `fetchPregenWalletsOverride`
This function retrieves the `userShare` associated with the passed `pregenId` from your backend.
```typescript
async function fetchPregenWalletsOverride(opts: { pregenId: PregenAuth }) => Promise<{ userShare?: string }> {
// logic to call backend and retrieve stored user share for given `pregenId`
return { userShare };
}
```
### Pass `fetchPregenWalletsOverride` as a field in `opts` to the `paraClientConfig`
This step allows our frontend logic to automatically fetch the correct `userShare` for claiming when the user is first creating an account through the modal flow.
```typescript
{children}
```
#### Claiming manually
### Authenticate the user
Ensure the user has completed Para's authentication flow and has an active session.
```typescript
// User must be authenticated through Para's systems
if (!(await para.isFullyLoggedIn())) {
// Redirect to authentication flow or show login modal
}
```
### Load the wallet's user share
Since this is a client side only operation, you need to securely send the `UserShare` from your server to the client. Once received, load it into the Para client:
```typescript
// Load the previously stored user share into the Para client
await para.setUserShare(userShare);
```
### Update wallet identifier if needed
Ensure the pregenerated wallet's identifier matches the authenticated user's identifier:
```typescript
// If you originally created the wallet with a custom identifier (like a UUID),
// update it to match the user's actual email or phone before claiming
await para.updatePregenWalletIdentifier({
walletId,
newPregenId: { email: user.email },
});
```
### Claiming the Wallet
Once prerequisites are met, you can claim the wallet:
```typescript
// Claim all pregenerated wallets associated with this user
const recoverySecret = await para.claimPregenWallets();
// Or claim specific wallets by identifier
const recoverySecret = await para.claimPregenWallets({
pregenId: { email: user.email },
});
```
If the userShare is already loaded into the Para client before authentication occurs, and if the pregenerated wallet's
identifier matches the authenticating user, the wallet will be automatically claimed during authentication.
### Controlling When Wallets are Claimed
You have control over when users claim their pregenerated wallets:
* **Delayed Claiming**: Only load the userShare and update the identifier when you're ready for the user to claim the
wallet. This allows your application to continue using the wallet on behalf of the user.
* **Immediate Claiming**: If you want immediate claiming upon user authentication, load the userShare before
authentication and ensure the identifiers match.
* **No Claiming**: Keep using different identifiers for the wallet than the user's actual identifier to prevent
automatic claiming.
This flexibility lets you design the optimal user experience for your application.
## Core Pregeneration Methods
",
description: "A promise that resolves to an array of pregenerated wallet entities"
}}
async={true}
/>
",
description: "A promise that resolves to true if a pregenerated wallet exists for the identifier"
}}
async={true}
/>
",
description: "A promise that resolves to the recovery secret for the claimed wallets, if available"
}}
async={true}
/>
",
description: "A promise that resolves when the identifier has been updated"
}}
async={true}
/>
",
description: "A promise that resolves to an array of created pregenerated wallets"
}}
async={true}
/>
",
description: "A promise that resolves when the user share has been loaded"
}}
async={true}
/>
## Best Practices and Considerations
Pregenerated wallets are app-specific until claimed. Before claiming, they can only be used within your application through the `UserShare`. After a user claims the wallet, it becomes part of their Para account, allowing them to use it across different Para-integrated applications. This transition from app-managed to user-managed is a key consideration in your implementation strategy.
Choose identifiers that align with your application architecture: - **Email/Phone**: Most common for user-facing
applications - **OAuth Identifiers**: Useful for social login integrations (Discord, Twitter) - **Custom IDs**: Ideal
for internal user management systems Consider your user onboarding flow when choosing identifiers. If you use custom
IDs initially, you'll need to update them to match the user's actual identifier (email/phone) before claiming can
occur.
The user share is critical security information that must be protected: - **Encryption**: Always encrypt user shares
both in transit and at rest - **Database Security**: Implement proper access controls for your share database -
**Backups**: Maintain regular database backups to prevent data loss - **Disaster Recovery**: Create processes for
handling compromise scenarios - **Key Rotation**: Have a plan for working with Para if key rotation becomes necessary
Consider implementing a fire drill before launching to test scenarios like database loss, access issues, or credential
compromise. Para offers security reviews for teams on Growth tier and above.
Plan your user experience around wallet claiming: - **Delayed Claiming**: Keep control of wallets until users are
ready for full ownership - **Automatic Claiming**: Configure for immediate claiming during authentication -
**Progressive Onboarding**: Start users with app-managed wallets, then transition to self-custody - **Educational
Elements**: Help users understand the transition from app-managed to self-custody The claiming process should feel
seamless and intuitive to users while giving you flexibility in your application architecture.
Be deliberate about the wallet types you create:
* **Match Blockchain Needs**: Select wallet types (EVM, Solana, Cosmos) based on your application's blockchain requirements
* **Multiple Types**: Consider creating multiple wallet types if your application spans multiple blockchains
* **Default Selection**: If your app supports multiple chains, create wallets for all required types during pregeneration
* **User Guidance**: Provide clear information about which blockchain networks are supported by each wallet
Understand the operational boundaries:
* **Server-side**: Create pregen wallets, store user shares, sign transactions (with loaded shares)
* **Client-side only**: Create and claim wallets, load user shares, sign transactions
Design your architecture with these constraints in mind, especially when planning how user shares will flow from your server to client during the claiming process. Implement secure methods to transfer the user share from your server to the client when needed for wallet claiming.
## Reference Example
For complete examples demonstrating the usage of pregeneration methods, refer to our examples repository:
# Web Session Management
Source: https://docs.getpara.com/v2/react/guides/sessions
Overview of authentication session management in Para for web applications
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
Para provides a comprehensive set of methods for managing authentication sessions in web applications. These sessions are crucial for secure transaction signing and other authenticated operations. Proper session management helps maintain security while ensuring a seamless user experience.
## Session Configuration
The Para session length is `2 hours` by default, but can be configured to up to 30 days through the . A user signing a message or transaction extends the session by the duration of the session length.
### Security Considerations
**Shorter Sessions (2 Hours - 1 Day):**
* Enhanced security for sensitive applications
* Reduced risk if device is compromised
* Better for shared or public devices
**Longer Sessions (1 Week - 1 Month):**
* Improved user experience with fewer logins
* Better for personal devices and trusted environments
* Consider implementing automatic session refresh
### Custom Session Length
For custom durations:
1. Select "Custom" option in the Developer Portal
2. Enter duration in minutes
3. Consider your application's specific security needs
4. Balance security with user experience
## Session Management Topics
Explore the different aspects of session management in Para:
## Quick Start
Here's a basic example of checking and maintaining a session:
```typescript
const para = new Para(apiKey);
// Check if session is active
const isActive = await para.isSessionActive();
if (!isActive) {
// Handle expired session - route to authentication
} else {
// Extend the session
await para.keepSessionAlive();
}
```
# Pregenerated Wallet Sessions
Source: https://docs.getpara.com/v2/react/guides/sessions-pregen
Session management for Para pregenerated wallets
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
When using pregenerated wallets, session management works differently as these wallets don't require traditional authentication.
## How Sessions Work with Pregenerated Wallets
For pregenerated wallets, the session is considered always active as long as the `UserShare` is loaded in the Para client instance. Traditional session expiration doesn't apply in this scenario.
```typescript
const para = new Para(apiKey);
// Set a pregenerated wallet
await para.setUserShare(userShare);
// Session checks will return true as long as userShare is loaded
const isActive = await para.isSessionActive(); // Always true for pre-gen wallets
```
## Session Management Methods for Pre-Generated Wallets
",
description: "A promise that resolves when the user share has been loaded"
}}
async={true}
/>
When a UserShare is loaded via `setUserShare()`, the session remains active indefinitely. Methods like `isSessionActive()` will return true as long as the UserShare remains loaded in the Para client instance.
## Learn More
## Best Practices
* **UserShare Management**: Ensure the UserShare remains loaded in the Para instance for continuous session availability
* **Security**: Store UserShares securely and never expose them in client-side code
* **Session Verification**: Remember that `isSessionActive()` will always return true for loaded pregenerated wallets
# Claim Staking Rewards
Source: https://docs.getpara.com/v2/react/guides/web3-operations/cosmos/claim-rewards
Claim accumulated staking rewards from delegated validators
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Withdraw your accumulated staking rewards from validators on Cosmos chains using CosmJS.
## Prerequisites
## Claim Rewards
```typescript
import { useCosmosClient } from "./useCosmosClient";
import { coins } from "@cosmjs/stargate";
import { MsgWithdrawDelegatorReward } from "cosmjs-types/cosmos/distribution/v1beta1/tx";
function ClaimRewards() {
const { signingClient } = useCosmosClient("https://rpc.cosmos.network");
const claimStakingRewards = async () => {
if (!signingClient) return;
const accounts = await signingClient.signer.getAccounts();
const delegator = accounts[0].address;
const validator = "cosmosvaloper1..."; // Replace with your validator
const msgWithdrawReward = {
typeUrl: "/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward",
value: MsgWithdrawDelegatorReward.fromPartial({
delegatorAddress: delegator,
validatorAddress: validator,
}),
};
const fee = {
amount: coins(5000, "uatom"),
gas: "200000",
};
try {
const result = await signingClient.signAndBroadcast(
delegator,
[msgWithdrawReward],
fee,
"Claiming rewards via Para"
);
console.log("Rewards claimed:", result.transactionHash);
console.log("Gas used:", result.gasUsed);
} catch (error) {
console.error("Failed to claim rewards:", error);
}
};
return (
Claim Rewards
);
}
```
## Next Steps
# Configure RPC Nodes with Cosmos Libraries
Source: https://docs.getpara.com/v2/react/guides/web3-operations/cosmos/configure-rpc
Set up and configure Cosmos RPC endpoints and clients using CosmJS
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Learn how to configure custom RPC endpoints for different Cosmos-based chains when using CosmJS with Para.
## Prerequisites
## Configure Chain-Specific RPC
```typescript
import { useCosmosClient } from "./useCosmosClient";
const CHAIN_CONFIGS = {
cosmos: {
rpc: "https://rpc.cosmos.network",
prefix: "cosmos"
},
osmosis: {
rpc: "https://osmosis-rpc.polkachu.com",
prefix: "osmo"
},
celestia: {
rpc: "https://celestia-rpc.publicnode.com",
prefix: "celestia"
},
dydx: {
rpc: "https://dydx-dao-rpc.polkachu.com",
prefix: "dydx"
}
};
function MultiChainExample() {
const cosmosClient = useCosmosClient(CHAIN_CONFIGS.cosmos.rpc, CHAIN_CONFIGS.cosmos.prefix);
const osmosisClient = useCosmosClient(CHAIN_CONFIGS.osmosis.rpc, CHAIN_CONFIGS.osmosis.prefix);
const checkChainStatus = async () => {
if (!cosmosClient.publicClient || !osmosisClient.publicClient) return;
const cosmosHeight = await cosmosClient.publicClient.getHeight();
const osmosisHeight = await osmosisClient.publicClient.getHeight();
console.log("Cosmos block height:", cosmosHeight);
console.log("Osmosis block height:", osmosisHeight);
};
return (
Check Chain Status
);
}
```
## Next Steps
# Execute Transactions with Cosmos Libraries
Source: https://docs.getpara.com/v2/react/guides/web3-operations/cosmos/execute-transactions
Interact with Cosmos modules and execute complex transactions using CosmJS
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Execute custom messages and interact with Cosmos modules using CosmJS with Para wallets.
## Prerequisites
## Execute Custom Messages
```typescript
import { useCosmosClient } from "./useCosmosClient";
import { coins } from "@cosmjs/stargate";
import { MsgSend } from "cosmjs-types/cosmos/bank/v1beta1/tx";
function CustomTransaction() {
const { signingClient } = useCosmosClient("https://rpc.cosmos.network");
const executeCustomMessage = async () => {
if (!signingClient) return;
const accounts = await signingClient.signer.getAccounts();
const sender = accounts[0].address;
const msgSend = {
typeUrl: "/cosmos.bank.v1beta1.MsgSend",
value: MsgSend.fromPartial({
fromAddress: sender,
toAddress: "cosmos1...", // Replace with recipient
amount: coins(1000000, "uatom"),
}),
};
const fee = {
amount: coins(5000, "uatom"),
gas: "200000",
};
try {
const result = await signingClient.signAndBroadcast(
sender,
[msgSend],
fee,
"Custom message via Para"
);
console.log("Transaction hash:", result.transactionHash);
console.log("Code:", result.code);
} catch (error) {
console.error("Transaction failed:", error);
}
};
return (
Execute Custom Message
);
}
```
## Next Steps
# Sponsor Gas Fees on Cosmos
Source: https://docs.getpara.com/v2/react/guides/web3-operations/cosmos/gas-sponsorship
Learn how to implement gas sponsorship on Cosmos networks using fee grants with Para
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
This guide demonstrates how to implement gas sponsorship on Cosmos networks using fee grants. Unlike EVM chains that use account abstraction for gasless transactions, Cosmos networks natively support gas sponsorship through fee grants, allowing a grantor address to pay for another account's transaction fees.
## Prerequisites
## Understanding Fee Grants
Fee grants in Cosmos allow one account (grantor) to pay transaction fees for another account (grantee). This mechanism provides native gas sponsorship without requiring smart contracts or account abstraction.
Key concepts:
* **Grantor**: The account that pays for gas fees
* **Grantee**: The account whose transactions are sponsored
* **Allowance**: Defines spending limits and expiration for the grant
Only one fee grant is allowed per granter-grantee pair. Self-grants are not permitted.
## Creating a Basic Fee Grant
Create a basic allowance to grant gas sponsorship to another address:
```typescript
import { MsgGrantAllowance } from "cosmjs-types/cosmos/feegrant/v1beta1/tx";
import { BasicAllowance } from "cosmjs-types/cosmos/feegrant/v1beta1/feegrant";
const granterAddress = paraSigner.address; // From your Para signer setup
const granteeAddress = "cosmos1grantee..."; // Replace with actual grantee address
// Create basic allowance with spending limits
const basicAllowance = BasicAllowance.fromPartial({
spendLimit: [{
denom: "uatom",
amount: "1000000" // 1 ATOM limit
}],
expiration: {
seconds: BigInt(Math.floor(Date.now() / 1000) + 86400), // 24 hours from now
nanos: 0
}
});
// Create the grant message
const grantMsg = {
typeUrl: "/cosmos.feegrant.v1beta1.MsgGrantAllowance",
value: MsgGrantAllowance.fromPartial({
granter: granterAddress,
grantee: granteeAddress,
allowance: {
typeUrl: "/cosmos.feegrant.v1beta1.BasicAllowance",
value: BasicAllowance.encode(basicAllowance).finish()
}
})
};
// Sign and broadcast the grant transaction
const result = await client.signAndBroadcast(
granterAddress,
[grantMsg],
"auto", // Let the client estimate gas
"Granting fee allowance"
);
```
## Using Fee Grants as a Grantee
Once a fee grant is established, the grantee can perform transactions with sponsored gas fees:
```typescript
// Create a signer for the grantee
const granteeSigner = new ParaProtoSigner(granteeParaInstance, "cosmos");
const granteeClient = await SigningStargateClient.connectWithSigner(rpcUrl, granteeSigner);
// Send tokens with sponsored gas
const result = await granteeClient.sendTokens(
granteeAddress,
"cosmos1recipient...",
[{ denom: "uatom", amount: "100000" }], // 0.1 ATOM
{
amount: [{ denom: "uatom", amount: "5000" }],
gas: "200000",
granter: granterAddress // This tells the network to use the fee grant
}
);
```
## Querying Fee Grants
Check existing grants before creating new ones:
```typescript
// Query grants for a specific grantee
const grantsByGrantee = await fetch(
`${restUrl}/cosmos/feegrant/v1beta1/allowances/${granteeAddress}`
).then(res => res.json());
// Query all grants by a specific granter
const grantsByGranter = await fetch(
`${restUrl}/cosmos/feegrant/v1beta1/issued/${granterAddress}`
).then(res => res.json());
// Query a specific grant
const specificGrant = await fetch(
`${restUrl}/cosmos/feegrant/v1beta1/allowance/${granterAddress}/${granteeAddress}`
).then(res => res.json());
```
## Other Allowance Types
### Periodic Allowance
Resets spending limits periodically:
```typescript
import { PeriodicAllowance } from "cosmjs-types/cosmos/feegrant/v1beta1/feegrant";
const periodicAllowance = PeriodicAllowance.fromPartial({
basic: {
spendLimit: [{
denom: "uatom",
amount: "10000000" // 10 ATOM total limit
}],
expiration: null // No expiration
},
period: { seconds: BigInt(86400), nanos: 0 }, // 24 hours
periodSpendLimit: [{
denom: "uatom",
amount: "1000000" // 1 ATOM per period
}]
});
```
### Allowed Message Allowance
Restricts which message types can be sponsored:
```typescript
import { AllowedMsgAllowance } from "cosmjs-types/cosmos/feegrant/v1beta1/feegrant";
const allowedMsgAllowance = AllowedMsgAllowance.fromPartial({
allowance: {
typeUrl: "/cosmos.feegrant.v1beta1.BasicAllowance",
value: BasicAllowance.encode(basicAllowance).finish()
},
allowedMessages: [
"/cosmos.bank.v1beta1.MsgSend",
"/cosmos.staking.v1beta1.MsgDelegate"
]
});
```
## Revoking Fee Grants
Remove a fee grant when it's no longer needed:
```typescript
import { MsgRevokeAllowance } from "cosmjs-types/cosmos/feegrant/v1beta1/tx";
const revokeMsg = {
typeUrl: "/cosmos.feegrant.v1beta1.MsgRevokeAllowance",
value: MsgRevokeAllowance.fromPartial({
granter: granterAddress,
grantee: granteeAddress
})
};
const result = await client.signAndBroadcast(
granterAddress,
[revokeMsg],
"auto"
);
```
## Advanced: Server-Controlled Gas Sponsorship
For production applications, use server-side controlled wallets as grantors while allowing users to authenticate client-side as grantees. This pattern uses Para's pregenerated wallets to create an app-controlled grantor wallet.
### Server-Side Setup
Create and manage a grantor wallet on your server:
```typescript
// server.ts
import { Para } from "@getpara/server-sdk@alpha";
import { SigningStargateClient } from "@cosmjs/stargate";
import { ParaProtoSigner } from "@getpara/cosmjs-adapter@alpha";
const serverPara = new Para(process.env.PARA_API_KEY);
// Create a pregen wallet for gas sponsorship
const grantorWallet = await serverPara.createPregenWallet({
type: 'COSMOS',
pregenId: { customId: "app-gas-sponsor-wallet" }
});
// Store the user share securely
const userShare = await serverPara.getUserShare();
// Store userShare in your secure database
```
### API Endpoint for Creating Grants
```typescript
// POST /api/create-fee-grant
async function createFeeGrantForUser(userAddress: string) {
// Load the grantor wallet
await serverPara.setUserShare(storedUserShare);
// Set up Cosmos client
const granterSigner = new ParaProtoSigner(serverPara, "cosmos");
const client = await SigningStargateClient.connectWithSigner(rpcUrl, granterSigner);
// Check if grant already exists
const existingGrant = await fetch(
`${restUrl}/cosmos/feegrant/v1beta1/allowance/${granterSigner.address}/${userAddress}`
).then(res => res.json());
if (existingGrant.allowance) {
// Revoke existing grant first
const revokeMsg = {
typeUrl: "/cosmos.feegrant.v1beta1.MsgRevokeAllowance",
value: MsgRevokeAllowance.fromPartial({
granter: granterSigner.address,
grantee: userAddress
})
};
await client.signAndBroadcast(
granterSigner.address,
[revokeMsg],
"auto"
);
}
// Create new grant with daily limit
const basicAllowance = BasicAllowance.fromPartial({
spendLimit: [{
denom: "uatom",
amount: "1000000" // 1 ATOM daily limit
}],
expiration: {
seconds: BigInt(Math.floor(Date.now() / 1000) + 86400),
nanos: 0
}
});
const grantMsg = {
typeUrl: "/cosmos.feegrant.v1beta1.MsgGrantAllowance",
value: MsgGrantAllowance.fromPartial({
granter: granterSigner.address,
grantee: userAddress,
allowance: {
typeUrl: "/cosmos.feegrant.v1beta1.BasicAllowance",
value: BasicAllowance.encode(basicAllowance).finish()
}
})
};
const result = await client.signAndBroadcast(
granterSigner.address,
[grantMsg],
"auto"
);
return {
transactionHash: result.transactionHash,
granterAddress: granterSigner.address
};
}
```
### Client-Side Integration
```typescript
// client.tsx
import { useParaWallet } from "@getpara/react-sdk@alpha";
import { SigningStargateClient } from "@cosmjs/stargate";
import { ParaProtoSigner } from "@getpara/cosmjs-adapter@alpha";
function MyApp() {
const { para, address } = useParaWallet();
const [granterAddress, setGranterAddress] = useState();
const setupGasSponsorship = async () => {
if (!address) return;
const response = await fetch('/api/create-fee-grant', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ userAddress: address })
});
const { granterAddress } = await response.json();
setGranterAddress(granterAddress);
};
const performSponsoredTransaction = async (recipientAddress: string, amount: string) => {
if (!para || !address || !granterAddress) return;
const signer = new ParaProtoSigner(para, "cosmos");
const client = await SigningStargateClient.connectWithSigner(rpcUrl, signer);
const result = await client.sendTokens(
address,
recipientAddress,
[{ denom: "uatom", amount }],
{
amount: [{ denom: "uatom", amount: "5000" }],
gas: "200000",
granter: granterAddress // App pays the gas fees
}
);
return result.transactionHash;
};
return (
<>
Activate Gas Sponsorship
performSponsoredTransaction("cosmos1...", "100000")}>
Send Sponsored Transaction
>
);
}
```
### Complete Server Implementation
```typescript
// Complete server implementation with grant management
class FeeGrantService {
private serverPara: Para;
private granterAddress?: string;
constructor() {
this.serverPara = new Para(process.env.PARA_API_KEY);
}
async initialize() {
// Load or create grantor wallet
const userShare = await loadUserShareFromDatabase();
await this.serverPara.setUserShare(userShare);
const signer = new ParaProtoSigner(this.serverPara, "cosmos");
this.granterAddress = signer.address;
}
async createGrant(userAddress: string, limitAmount: string, periodSeconds: number) {
const signer = new ParaProtoSigner(this.serverPara, "cosmos");
const client = await SigningStargateClient.connectWithSigner(rpcUrl, signer);
const allowance = BasicAllowance.fromPartial({
spendLimit: [{
denom: "uatom",
amount: limitAmount
}],
expiration: {
seconds: BigInt(Math.floor(Date.now() / 1000) + periodSeconds),
nanos: 0
}
});
const msg = {
typeUrl: "/cosmos.feegrant.v1beta1.MsgGrantAllowance",
value: MsgGrantAllowance.fromPartial({
granter: this.granterAddress,
grantee: userAddress,
allowance: {
typeUrl: "/cosmos.feegrant.v1beta1.BasicAllowance",
value: BasicAllowance.encode(allowance).finish()
}
})
};
return client.signAndBroadcast(this.granterAddress, [msg], "auto");
}
async revokeGrant(userAddress: string) {
const signer = new ParaProtoSigner(this.serverPara, "cosmos");
const client = await SigningStargateClient.connectWithSigner(rpcUrl, signer);
const msg = {
typeUrl: "/cosmos.feegrant.v1beta1.MsgRevokeAllowance",
value: MsgRevokeAllowance.fromPartial({
granter: this.granterAddress,
grantee: userAddress
})
};
return client.signAndBroadcast(this.granterAddress, [msg], "auto");
}
}
```
## Best Practices
* Set appropriate spending limits based on expected transaction volume
* Use expiration times to automatically clean up unused grants
* Monitor grant usage to control costs and detect abuse
* Consider using periodic allowances for regular users
* Use allowed message allowances to restrict transaction types
* Remember that creating and revoking grants also incur gas costs
Fee grants provide native gas sponsorship on Cosmos networks without requiring smart contracts, making them more efficient than EVM account abstraction solutions.
# IBC Cross-Chain Transfers
Source: https://docs.getpara.com/v2/react/guides/web3-operations/cosmos/ibc-transfers
Transfer tokens between Cosmos chains using Inter-Blockchain Communication
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Transfer tokens between different Cosmos chains using IBC (Inter-Blockchain Communication) with CosmJS.
## Prerequisites
## IBC Transfer
```typescript
import { useCosmosClient } from "./useCosmosClient";
import { coins } from "@cosmjs/stargate";
import { MsgTransfer } from "cosmjs-types/ibc/applications/transfer/v1/tx";
import { Height } from "cosmjs-types/ibc/core/client/v1/client";
function IBCTransfer() {
const { signingClient } = useCosmosClient("https://rpc.cosmos.network");
const sendIBCTransfer = async () => {
if (!signingClient) return;
const accounts = await signingClient.signer.getAccounts();
const sender = accounts[0].address;
const currentHeight = await signingClient.getHeight();
const timeoutHeight = Height.fromPartial({
revisionNumber: 1n,
revisionHeight: BigInt(currentHeight + 1000),
});
const msgTransfer = {
typeUrl: "/ibc.applications.transfer.v1.MsgTransfer",
value: MsgTransfer.fromPartial({
sourcePort: "transfer",
sourceChannel: "channel-141", // Osmosis channel
token: {
denom: "uatom",
amount: "1000000", // 1 ATOM
},
sender: sender,
receiver: "osmo1...", // Osmosis address
timeoutHeight: timeoutHeight,
timeoutTimestamp: 0n,
}),
};
const fee = {
amount: coins(5000, "uatom"),
gas: "250000",
};
try {
const result = await signingClient.signAndBroadcast(
sender,
[msgTransfer],
fee,
"IBC transfer via Para"
);
console.log("IBC transfer initiated:", result.transactionHash);
} catch (error) {
console.error("IBC transfer failed:", error);
}
};
return (
Send 1 ATOM to Osmosis
);
}
```
## Next Steps
# Query Wallet Balances with Cosmos Libraries
Source: https://docs.getpara.com/v2/react/guides/web3-operations/cosmos/query-balances
Check account balances and token holdings using CosmJS with Para wallets
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Query token balances for any Cosmos address or your connected Para wallet using CosmJS.
## Prerequisites
## Query Balances
```typescript
import { useCosmosClient } from "./useCosmosClient";
import { coins } from "@cosmjs/stargate";
function BalanceDisplay() {
const { publicClient, signingClient } = useCosmosClient("https://rpc.cosmos.network");
const [balances, setBalances] = useState([]);
const queryBalances = async () => {
const client = signingClient || publicClient;
if (!client) return;
const address = signingClient
? await signingClient.signer.getAccounts().then(accs => accs[0]?.address)
: "cosmos1..."; // Replace with any address to query
if (!address) return;
const allBalances = await client.getAllBalances(address);
setBalances(allBalances);
const atomBalance = await client.getBalance(address, "uatom");
console.log("ATOM balance:", atomBalance.amount, atomBalance.denom);
};
return (
Query Balances
{balances.map(balance => (
{balance.amount} {balance.denom}
))}
);
}
```
## Next Steps
# Query Validator Information
Source: https://docs.getpara.com/v2/react/guides/web3-operations/cosmos/query-validators
Get validator details, commission rates, and staking APY
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Query validator information to make informed staking decisions on Cosmos chains using CosmJS.
## Prerequisites
## Query Validators
```typescript
import { useCosmosClient } from "./useCosmosClient";
import { setupStakingExtension, QueryClient } from "@cosmjs/stargate";
function ValidatorInfo() {
const { publicClient, signingClient } = useCosmosClient("https://rpc.cosmos.network");
const [validators, setValidators] = useState([]);
const queryValidators = async () => {
const client = signingClient || publicClient;
if (!client) return;
const queryClient = QueryClient.withExtensions(
client.getTmClient(),
setupStakingExtension
);
try {
const { validators: activeValidators } = await queryClient.staking.validators("BOND_STATUS_BONDED");
const validatorInfo = activeValidators.slice(0, 10).map(validator => ({
name: validator.description.moniker,
operatorAddress: validator.operatorAddress,
tokens: validator.tokens,
commission: validator.commission.commissionRates.rate,
jailed: validator.jailed,
status: validator.status
}));
setValidators(validatorInfo);
if (signingClient) {
const accounts = await signingClient.signer.getAccounts();
const delegations = await queryClient.staking.delegatorDelegations(accounts[0].address);
console.log("Your delegations:", delegations);
}
} catch (error) {
console.error("Failed to query validators:", error);
}
};
return (
Query Top Validators
{validators.map(v => (
{v.name} - Commission: {v.commission}
))}
);
}
```
## Next Steps
# Send Tokens with Cosmos Libraries
Source: https://docs.getpara.com/v2/react/guides/web3-operations/cosmos/send-tokens
Transfer native tokens and execute IBC transfers using CosmJS with Para wallets
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Transfer tokens between Cosmos accounts using CosmJS with Para's secure wallet infrastructure.
## Prerequisites
## Send Tokens
```typescript
import { useCosmosClient } from "./useCosmosClient";
import { coins } from "@cosmjs/stargate";
function TokenTransfer() {
const { signingClient } = useCosmosClient("https://rpc.cosmos.network");
const sendTokens = async () => {
if (!signingClient) return;
const recipient = "cosmos1..."; // Replace with recipient address
const amount = coins(1000000, "uatom"); // 1 ATOM
const fee = {
amount: coins(5000, "uatom"),
gas: "200000",
};
try {
const accounts = await signingClient.signer.getAccounts();
const sender = accounts[0].address;
const result = await signingClient.sendTokens(
sender,
recipient,
amount,
fee,
"Sent via Para"
);
console.log("Transaction hash:", result.transactionHash);
console.log("Gas used:", result.gasUsed);
} catch (error) {
console.error("Transfer failed:", error);
}
};
return (
Send 1 ATOM
);
}
```
## Next Steps
# Setup Cosmos Libraries
Source: https://docs.getpara.com/v2/react/guides/web3-operations/cosmos/setup-libraries
Install and configure CosmJS for use with Para SDK on Cosmos chains
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Learn how to set up with Para SDK to interact with Cosmos-based blockchains.
## Prerequisites
## Installation
If using `cosmjs` and the `@getpara/react-sdk` you can use our hook or hook to access the CosmJS client and account without any additional setup.
```bash npm
npm install @getpara/cosmjs-v0-integration@alpha @cosmjs/stargate @cosmjs/proto-signing --save-exact
```
```bash yarn
yarn add @getpara/cosmjs-v0-integration@alpha @cosmjs/stargate @cosmjs/proto-signing --exact
```
```bash pnpm
pnpm add @getpara/cosmjs-v0-integration@alpha @cosmjs/stargate @cosmjs/proto-signing --save-exact
```
```bash bun
bun add @getpara/cosmjs-v0-integration@alpha @cosmjs/stargate @cosmjs/proto-signing --exact
```
## Library Setup
### Hook-Based Pattern
```typescript
import { useClient, useAccount } from "@getpara/react-sdk@alpha";
import { ParaProtoSigner } from "@getpara/cosmjs-v0-integration@alpha";
import { SigningStargateClient, StargateClient } from "@cosmjs/stargate";
import { useState, useEffect } from "react";
export function useCosmosClient(rpcUrl: string, prefix: string = "cosmos") {
const para = useClient();
const { isConnected, embedded } = useAccount();
const [publicClient, setPublicClient] = useState();
const [signingClient, setSigningClient] = useState();
useEffect(() => {
StargateClient.connect(rpcUrl).then(setPublicClient);
}, [rpcUrl]);
useEffect(() => {
if (!para || !isConnected || !embedded.isConnected) {
setSigningClient(undefined);
return;
}
para.getWalletsByType({ type: "Cosmos" }).then((wallets) => {
if (wallets.length === 0) return;
const signer = new ParaProtoSigner(para, prefix);
SigningStargateClient.connectWithSigner(rpcUrl, signer).then(setSigningClient);
});
}, [para, isConnected, embedded.isConnected, rpcUrl, prefix]);
return { publicClient, signingClient };
}
```
### Direct Client Pattern
```typescript
import { ParaWeb } from "@getpara/react-sdk@alpha";
import { ParaProtoSigner } from "@getpara/cosmjs-v0-integration@alpha";
import { SigningStargateClient, StargateClient } from "@cosmjs/stargate";
const para = new ParaWeb({ apiKey: process.env.NEXT_PUBLIC_PARA_API_KEY });
async function setupCosmosClients(rpcUrl: string, prefix: string = "cosmos") {
const publicClient = await StargateClient.connect(rpcUrl);
const isAuthenticated = await para.isSessionActive();
if (!isAuthenticated) {
return { publicClient, signingClient: null };
}
const wallets = await para.getWalletsByType({ type: "Cosmos" });
if (wallets.length === 0) {
return { publicClient, signingClient: null };
}
const signer = new ParaProtoSigner(para, prefix);
const signingClient = await SigningStargateClient.connectWithSigner(rpcUrl, signer);
return { publicClient, signingClient };
}
```
## Next Steps
# Sign Messages with Cosmos Libraries
Source: https://docs.getpara.com/v2/react/guides/web3-operations/cosmos/sign-messages
Sign direct and amino messages using CosmJS with Para wallets
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Sign arbitrary messages for authentication or verification using CosmJS with Para wallets.
## Prerequisites
## Sign Messages
```typescript
import { useCosmosClient } from "./useCosmosClient";
import { ParaProtoSigner, ParaAminoSigner } from "@getpara/cosmjs-v0-integration@alpha";
import { useClient } from "@getpara/react-sdk@alpha";
function MessageSigning() {
const para = useClient();
const { signingClient } = useCosmosClient("https://rpc.cosmos.network");
const signArbitraryMessage = async () => {
if (!para || !signingClient) return;
const protoSigner = new ParaProtoSigner(para, "cosmos");
const aminoSigner = new ParaAminoSigner(para, "cosmos");
const accounts = await protoSigner.getAccounts();
const address = accounts[0].address;
const signDoc = {
chain_id: "cosmoshub-4",
account_number: "0",
sequence: "0",
fee: {
amount: [],
gas: "0",
},
msgs: [],
memo: "Sign this message to authenticate with Para",
};
try {
const aminoSignature = await aminoSigner.signAmino(address, signDoc);
console.log("Amino signature:", aminoSignature.signature);
const message = new TextEncoder().encode("Hello Para!");
const directSignature = await protoSigner.signDirect(address, {
bodyBytes: message,
authInfoBytes: new Uint8Array(),
chainId: "cosmoshub-4",
accountNumber: 0n,
});
console.log("Direct signature:", directSignature.signature);
} catch (error) {
console.error("Signing failed:", error);
}
};
return (
Sign Message
);
}
```
## Next Steps
# Stake Tokens to Validators
Source: https://docs.getpara.com/v2/react/guides/web3-operations/cosmos/stake-tokens
Delegate tokens to Cosmos validators for staking rewards
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Delegate your tokens to validators on Cosmos chains to earn staking rewards using CosmJS.
## Prerequisites
## Stake Tokens
```typescript
import { useCosmosClient } from "./useCosmosClient";
import { coins } from "@cosmjs/stargate";
import { MsgDelegate } from "cosmjs-types/cosmos/staking/v1beta1/tx";
function StakeTokens() {
const { signingClient } = useCosmosClient("https://rpc.cosmos.network");
const delegateToValidator = async () => {
if (!signingClient) return;
const accounts = await signingClient.signer.getAccounts();
const delegator = accounts[0].address;
const validator = "cosmosvaloper1..."; // Replace with validator address
const msgDelegate = {
typeUrl: "/cosmos.staking.v1beta1.MsgDelegate",
value: MsgDelegate.fromPartial({
delegatorAddress: delegator,
validatorAddress: validator,
amount: {
denom: "uatom",
amount: "1000000", // 1 ATOM
},
}),
};
const fee = {
amount: coins(5000, "uatom"),
gas: "250000",
};
try {
const result = await signingClient.signAndBroadcast(
delegator,
[msgDelegate],
fee,
"Staking with Para"
);
console.log("Delegation successful:", result.transactionHash);
} catch (error) {
console.error("Delegation failed:", error);
}
};
return (
Stake 1 ATOM
);
}
```
## Next Steps
# Verify Signatures with Cosmos Libraries
Source: https://docs.getpara.com/v2/react/guides/web3-operations/cosmos/verify-signatures
Verify message and transaction signatures using CosmJS
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Verify signatures from signed messages to authenticate users or validate transactions using CosmJS.
## Prerequisites
## Verify Signatures
```typescript
import { verifyAminoSignature, verifyDirectSignature } from "@cosmjs/stargate";
import { fromBase64 } from "@cosmjs/encoding";
import { Secp256k1, Secp256k1Signature } from "@cosmjs/crypto";
function SignatureVerification() {
const verifySignature = async () => {
const pubkeyBase64 = "A08EGB7ro1ORuFhjOnZcSgwYlpe0DSFjVNUIkNNQxwKQ";
const signatureBase64 = "MEUCIQD02fsDPra8MtbRxG1CcjHnCDNrsyL0K0WDlhSAb9c1SgIgavB5559FUxuFMRkURerN6Ws6foXEP1pYSe0tYb2qvxE=";
const pubkey = fromBase64(pubkeyBase64);
const signature = fromBase64(signatureBase64);
const signDoc = {
chain_id: "cosmoshub-4",
account_number: "0",
sequence: "0",
fee: {
amount: [],
gas: "0",
},
msgs: [],
memo: "Sign this message to authenticate with Para",
};
try {
const isValid = await verifyAminoSignature(
signDoc,
{ pub_key: { type: "tendermint/PubKeySecp256k1", value: pubkeyBase64 }, signature: signatureBase64 }
);
console.log("Amino signature valid:", isValid);
const message = new TextEncoder().encode("Hello Para!");
const secp256k1 = await Secp256k1.makeKeypair(pubkey);
const sig = Secp256k1Signature.fromFixedLength(signature);
const directValid = await Secp256k1.verifySignature(sig, message, secp256k1.pubkey);
console.log("Direct signature valid:", directValid);
} catch (error) {
console.error("Verification failed:", error);
}
};
return (
Verify Signature
);
}
```
## Next Steps
# Configure RPC Endpoints
Source: https://docs.getpara.com/v2/react/guides/web3-operations/evm/configure-rpc
Set up custom RPC endpoints and chains with Web3 libraries
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Configure custom RPC endpoints and chains for networks using Web3 libraries. This guide uses public testnet RPCs for demonstration and shows minimal setup with predefined and custom chains where applicable.
## Prerequisites
You need to start with setting up your Web3 library clients with Para. This guide assumes you have already configured your Para instance and are ready to integrate with Ethers.js, Viem, or Wagmi.
## Configure Custom RPC Endpoints
```typescript
import { ethers } from "ethers";
import { ParaEthersSigner } from "@getpara/ethers-v6-integration";
// Example with predefined chain (Sepolia)
const chainId = 11155111;
const rpcUrl = "https://ethereum-sepolia-rpc.publicnode.com";
// Public RPC provider
const provider = new ethers.JsonRpcProvider(rpcUrl, chainId, {
staticNetwork: true
});
// Integrate with Para
const signer = new ParaEthersSigner(para, provider); // Assuming 'para' is your configured Para instance
// For other chains (predefined or custom), use the corresponding chainId and RPC URL
```
```typescript
import { createPublicClient, http } from "viem";
import { sepolia } from "viem/chains";
import { createParaViemClient, createParaAccount } from "@getpara/viem-v2-integration";
// Example with imported predefined chain (Sepolia) and custom RPC
const chain = sepolia;
const transport = http("https://ethereum-sepolia-rpc.publicnode.com");
const publicClient = createPublicClient({
chain,
transport
});
// Integrate with Para
const account = await createParaAccount(para); // Assuming 'para' is your configured Para instance
const walletClient = createParaViemClient(para, {
account,
chain,
transport
});
// Example with custom chain
const customChain = {
id: 99999,
name: "Custom Chain",
network: "custom",
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
rpcUrls: {
default: { http: ["https://custom-rpc.example.com"] },
},
};
const customTransport = http("https://custom-rpc.example.com");
const customPublicClient = createPublicClient({
chain: customChain,
transport: customTransport
});
// Integrate with Para
const customAccount = await createParaAccount(para);
const customWalletClient = createParaViemClient(para, {
account: customAccount,
chain: customChain,
transport: customTransport
});
```
```typescript
import { createConfig, http } from "wagmi";
import { sepolia } from "wagmi/chains";
import { paraConnector } from "@getpara/wagmi-v2-integration";
// Example with imported predefined chain (Sepolia) and custom RPC
const chains = [sepolia] as const;
// Integrate with Para
const connector = paraConnector({
para, // Assuming 'para' is your configured Para instance
chains,
appName: "Your App" // Replace with your app name
});
const config = createConfig({
chains,
connectors: [connector],
transports: {
[sepolia.id]: http("https://ethereum-sepolia-rpc.publicnode.com")
}
});
// Example including a custom chain
const customChain = {
id: 99999,
name: "Custom Chain",
network: "custom",
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
rpcUrls: {
default: { http: ["https://custom-rpc.example.com"] },
},
};
const extendedChains = [sepolia, customChain] as const;
const extendedConnector = paraConnector({
para,
chains: extendedChains,
appName: "Your App"
});
const extendedConfig = createConfig({
chains: extendedChains,
connectors: [extendedConnector],
transports: {
[sepolia.id]: http("https://ethereum-sepolia-rpc.publicnode.com"),
[customChain.id]: http("https://custom-rpc.example.com")
}
});
```
## Next Steps
# Estimate Gas for Transactions
Source: https://docs.getpara.com/v2/react/guides/web3-operations/evm/estimate-gas
Calculate gas costs for transactions including EIP-1559 gas pricing
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Accurately estimate gas costs for transactions to ensure reliable execution without overpaying. This guide covers gas estimation for simple transfers and smart contract interactions using , , and .
## Prerequisites
You need Web3 libraries configured with Para authentication.
## Estimate Gas for a Transaction
```typescript
import { ethers } from "ethers";
async function estimateGas(
provider: ethers.Provider,
to: string,
value: string,
data?: string,
maxFeePerGas?: string,
maxPriorityFeePerGas?: string
) {
const tx = {
to,
value: ethers.parseEther(value),
data: data || "0x",
...(maxFeePerGas ? { maxFeePerGas: ethers.parseUnits(maxFeePerGas, "gwei") } : {}),
...(maxPriorityFeePerGas ? { maxPriorityFeePerGas: ethers.parseUnits(maxPriorityFeePerGas, "gwei") } : {})
};
const gasEstimate = await provider.estimateGas(tx);
return gasEstimate;
}
```
```typescript
import { parseEther, parseGwei } from "viem";
async function estimateGas(
publicClient: PublicClient,
account: Account | `0x${string}`,
to: `0x${string}`,
value: string,
data?: `0x${string}`,
maxFeePerGas?: string,
maxPriorityFeePerGas?: string
) {
const gasEstimate = await publicClient.estimateGas({
account,
to,
value: parseEther(value),
data: data || "0x",
...(maxFeePerGas ? { maxFeePerGas: parseGwei(maxFeePerGas) } : {}),
...(maxPriorityFeePerGas ? { maxPriorityFeePerGas: parseGwei(maxPriorityFeePerGas) } : {})
});
return gasEstimate;
}
```
```typescript
import { useEstimateGas } from "wagmi";
import { parseEther, parseGwei } from "viem";
function EstimateGas({
to,
value,
data,
maxFeePerGas,
maxPriorityFeePerGas,
}: {
to: `0x${string}`;
value: string;
data?: `0x${string}`;
maxFeePerGas?: string;
maxPriorityFeePerGas?: string;
}) {
const { data: gas } = useEstimateGas({
to,
value: parseEther(value),
data: data || "0x",
...(maxFeePerGas ? { maxFeePerGas: parseGwei(maxFeePerGas) } : {}),
...(maxPriorityFeePerGas ? { maxPriorityFeePerGas: parseGwei(maxPriorityFeePerGas) } : {})
});
return (
// Your component JSX here
)
}
```
# Execute Transactions
Source: https://docs.getpara.com/v2/react/guides/web3-operations/evm/execute-transactions
Execute arbitrary transactions with lifecycle management using Web3 libraries
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Execute complex transactions with custom data and manage their lifecycle using Para.
## Prerequisites
You need Web3 libraries configured with Para authentication.
## Execute Raw Transactions
```typescript
import { ethers } from "ethers";
import { ParaEthersSigner } from "@getpara/ethers-v6-integration@alpha";
async function executeTransaction(
signer: ParaEthersSigner,
to: string,
data: string,
value?: string
) {
try {
const tx = {
to,
data,
value: value ? ethers.parseEther(value) : 0,
gasLimit: 100000
};
const populatedTx = await signer.populateTransaction(tx);
console.log("Populated transaction:", populatedTx);
const txResponse = await signer.sendTransaction(populatedTx);
console.log("Transaction sent:", txResponse.hash);
const receipt = await txResponse.wait();
console.log("Transaction mined:", receipt);
return {
hash: txResponse.hash,
blockNumber: receipt.blockNumber,
status: receipt.status,
gasUsed: receipt.gasUsed.toString()
};
} catch (error) {
console.error("Transaction failed:", error);
throw error;
}
}
```
```typescript
import { parseEther, encodeFunctionData } from "viem";
async function executeTransaction(
walletClient: any,
account: any,
to: `0x${string}`,
data: `0x${string}`,
value?: string
) {
try {
const request = await walletClient.prepareTransactionRequest({
account,
to,
data,
value: value ? parseEther(value) : 0n,
gas: 100000n
});
console.log("Prepared request:", request);
const hash = await walletClient.sendTransaction(request);
console.log("Transaction sent:", hash);
const receipt = await walletClient.waitForTransactionReceipt({
hash
});
return {
hash,
blockNumber: receipt.blockNumber,
status: receipt.status === "success" ? 1 : 0,
gasUsed: receipt.gasUsed.toString()
};
} catch (error) {
console.error("Transaction failed:", error);
throw error;
}
}
```
```typescript
import { usePrepareTransactionRequest, useSendTransaction } from "wagmi";
import { parseEther } from "viem";
function ExecuteTransaction() {
const { config } = usePrepareTransactionRequest({
to: "0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
data: "0x",
value: parseEther("0.01"),
gas: 100000n
});
const {
sendTransaction,
data: txData,
isLoading
} = useSendTransaction(config);
const handleExecute = () => {
sendTransaction?.();
};
return (
Execute Transaction
{txData &&
Transaction: {txData.hash}
}
);
}
```
## Execute Contract Functions
```typescript
const CONTRACT_ABI = [
"function setGreeting(string memory _greeting)",
"function greet() view returns (string)"
];
async function executeContractFunction(
signer: any,
contractAddress: string,
greeting: string
) {
try {
const contract = new ethers.Contract(
contractAddress,
CONTRACT_ABI,
signer
);
const estimatedGas = await contract.setGreeting.estimateGas(greeting);
console.log("Estimated gas:", estimatedGas.toString());
const tx = await contract.setGreeting(greeting, {
gasLimit: estimatedGas * 110n / 100n
});
console.log("Transaction hash:", tx.hash);
console.log("Waiting for confirmation...");
const receipt = await tx.wait();
console.log("Transaction confirmed");
const newGreeting = await contract.greet();
console.log("New greeting:", newGreeting);
return {
hash: tx.hash,
blockNumber: receipt.blockNumber,
newValue: newGreeting
};
} catch (error) {
console.error("Contract call failed:", error);
throw error;
}
}
```
```typescript
const CONTRACT_ABI = [
{
name: "setGreeting",
type: "function",
stateMutability: "nonpayable",
inputs: [{ name: "_greeting", type: "string" }],
outputs: []
},
{
name: "greet",
type: "function",
stateMutability: "view",
inputs: [],
outputs: [{ type: "string" }]
}
] as const;
async function executeContractFunction(
walletClient: any,
publicClient: any,
account: any,
contractAddress: `0x${string}`,
greeting: string
) {
try {
const gas = await publicClient.estimateContractGas({
address: contractAddress,
abi: CONTRACT_ABI,
functionName: "setGreeting",
args: [greeting],
account
});
const { request } = await publicClient.simulateContract({
address: contractAddress,
abi: CONTRACT_ABI,
functionName: "setGreeting",
args: [greeting],
account,
gas: gas * 110n / 100n
});
const hash = await walletClient.writeContract(request);
console.log("Transaction hash:", hash);
const receipt = await publicClient.waitForTransactionReceipt({
hash
});
const newGreeting = await publicClient.readContract({
address: contractAddress,
abi: CONTRACT_ABI,
functionName: "greet"
});
return {
hash,
blockNumber: receipt.blockNumber,
newValue: newGreeting
};
} catch (error) {
console.error("Contract call failed:", error);
throw error;
}
}
```
```typescript
import {
usePrepareContractWrite,
useContractWrite,
useContractRead
} from "wagmi";
const CONTRACT_ABI = [
{
name: "setGreeting",
type: "function",
stateMutability: "nonpayable",
inputs: [{ name: "_greeting", type: "string" }],
outputs: []
},
{
name: "greet",
type: "function",
stateMutability: "view",
inputs: [],
outputs: [{ type: "string" }]
}
] as const;
function ContractInteraction({
contractAddress
}: {
contractAddress: `0x${string}`
}) {
const { config } = usePrepareContractWrite({
address: contractAddress,
abi: CONTRACT_ABI,
functionName: "setGreeting",
args: ["Hello from Para!"]
});
const { write, data, isLoading } = useContractWrite(config);
const { data: greeting } = useContractRead({
address: contractAddress,
abi: CONTRACT_ABI,
functionName: "greet",
watch: true
});
return (
Current greeting: {greeting}
write?.()}
disabled={!write || isLoading}
>
Update Greeting
{data &&
Transaction: {data.hash}
}
);
}
```
## Next Steps
# Get Transaction Receipt
Source: https://docs.getpara.com/v2/react/guides/web3-operations/evm/get-transaction-receipt
Check transaction status, confirmations, and retrieve receipt details
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
After sending a transaction, you need to monitor its status and retrieve the receipt to confirm its execution. This guide demonstrates how to get transaction receipts using , , and .
## Prerequisites
You need Web3 libraries configured with Para authentication.
## Get Transaction Receipt
```typescript
import { ethers } from "ethers";
async function getTransactionReceipt(
provider: ethers.Provider,
txHash: string
) {
const receipt = await provider.getTransactionReceipt(txHash);
console.log("Transaction Receipt:", receipt);
return receipt;
}
async function waitForTransaction(provider: ethers.Provider, txHash: string) {
const receipt = await provider.waitForTransaction(txHash);
console.log("Transaction Confirmed:", receipt);
return receipt;
}
```
```typescript
async function getTransactionReceipt(
publicClient: any,
txHash: `0x${string}`
) {
const receipt = await publicClient.getTransactionReceipt({
hash: txHash,
});
console.log("Transaction Receipt:", receipt);
return receipt;
}
async function waitForTransactionReceipt(
publicClient: any,
txHash: `0x${string}`
) {
const receipt = await publicClient.waitForTransactionReceipt({
hash: txHash,
});
console.log("Transaction Confirmed:", receipt);
return receipt;
}
```
```typescript
import { useTransactionReceipt, useWaitForTransactionReceipt } from "wagmi";
function TransactionReceipt({ txHash }: { txHash: `0x${string}` }) {
const { data: receipt, isLoading } = useTransactionReceipt({
hash: txHash,
});
const { data: confirmedReceipt, isLoading: isConfirming } = useWaitForTransactionReceipt({
hash: txHash,
});
if (isLoading) return Loading receipt...
;
return (
Transaction Receipt
{JSON.stringify(receipt, null, 2)}
{isConfirming &&
Waiting for confirmation...
}
{confirmedReceipt && (
Confirmed Receipt
{JSON.stringify(confirmedReceipt, null, 2)}
)}
);
}
```
# Interact with Contracts
Source: https://docs.getpara.com/v2/react/guides/web3-operations/evm/interact-with-contracts
Read and write smart contract data and handle events using Web3 libraries
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Read data from smart contracts and execute write operations using Para's wallet infrastructure.
## Prerequisites
You need Web3 libraries configured with Para authentication.
## Read Contract Data
```typescript
import { ethers } from "ethers";
const CONTRACT_ABI = [
"function balanceOf(address owner) view returns (uint256)",
"function totalSupply() view returns (uint256)",
"function name() view returns (string)",
"function symbol() view returns (string)",
"function decimals() view returns (uint8)"
];
async function readContractData(
provider: ethers.Provider,
contractAddress: string,
userAddress: string
) {
const contract = new ethers.Contract(
contractAddress,
CONTRACT_ABI,
provider
);
const [balance, totalSupply, name, symbol, decimals] = await Promise.all([
contract.balanceOf(userAddress),
contract.totalSupply(),
contract.name(),
contract.symbol(),
contract.decimals()
]);
return {
balance: ethers.formatUnits(balance, decimals),
totalSupply: ethers.formatUnits(totalSupply, decimals),
name,
symbol,
decimals
};
}
```
```typescript
import { formatUnits } from "viem";
const CONTRACT_ABI = [
{
name: "balanceOf",
type: "function",
stateMutability: "view",
inputs: [{ name: "owner", type: "address" }],
outputs: [{ type: "uint256" }]
},
{
name: "totalSupply",
type: "function",
stateMutability: "view",
inputs: [],
outputs: [{ type: "uint256" }]
},
{
name: "name",
type: "function",
stateMutability: "view",
inputs: [],
outputs: [{ type: "string" }]
},
{
name: "symbol",
type: "function",
stateMutability: "view",
inputs: [],
outputs: [{ type: "string" }]
},
{
name: "decimals",
type: "function",
stateMutability: "view",
inputs: [],
outputs: [{ type: "uint8" }]
}
] as const;
async function readContractData(
publicClient: any,
contractAddress: `0x${string}`,
userAddress: `0x${string}`
) {
const results = await publicClient.multicall({
contracts: [
{
address: contractAddress,
abi: CONTRACT_ABI,
functionName: "balanceOf",
args: [userAddress]
},
{
address: contractAddress,
abi: CONTRACT_ABI,
functionName: "totalSupply"
},
{
address: contractAddress,
abi: CONTRACT_ABI,
functionName: "name"
},
{
address: contractAddress,
abi: CONTRACT_ABI,
functionName: "symbol"
},
{
address: contractAddress,
abi: CONTRACT_ABI,
functionName: "decimals"
}
]
});
const [balance, totalSupply, name, symbol, decimals] = results.map(r => r.result);
return {
balance: formatUnits(balance, decimals),
totalSupply: formatUnits(totalSupply, decimals),
name,
symbol,
decimals
};
}
```
```typescript
import { useContractReads } from "wagmi";
import { formatUnits } from "viem";
const CONTRACT_ABI = [
{
name: "balanceOf",
type: "function",
stateMutability: "view",
inputs: [{ name: "owner", type: "address" }],
outputs: [{ type: "uint256" }]
},
{
name: "totalSupply",
type: "function",
stateMutability: "view",
inputs: [],
outputs: [{ type: "uint256" }]
},
{
name: "name",
type: "function",
stateMutability: "view",
inputs: [],
outputs: [{ type: "string" }]
},
{
name: "symbol",
type: "function",
stateMutability: "view",
inputs: [],
outputs: [{ type: "string" }]
},
{
name: "decimals",
type: "function",
stateMutability: "view",
inputs: [],
outputs: [{ type: "uint8" }]
}
] as const;
function ContractData({
contractAddress,
userAddress
}: {
contractAddress: `0x${string}`;
userAddress: `0x${string}`;
}) {
const { data, isLoading } = useContractReads({
contracts: [
{
address: contractAddress,
abi: CONTRACT_ABI,
functionName: "balanceOf",
args: [userAddress]
},
{
address: contractAddress,
abi: CONTRACT_ABI,
functionName: "totalSupply"
},
{
address: contractAddress,
abi: CONTRACT_ABI,
functionName: "name"
},
{
address: contractAddress,
abi: CONTRACT_ABI,
functionName: "symbol"
},
{
address: contractAddress,
abi: CONTRACT_ABI,
functionName: "decimals"
}
]
});
if (isLoading) return Loading...
;
const [balance, totalSupply, name, symbol, decimals] =
data?.map(d => d.result) || [];
return (
Token: {name} ({symbol})
Balance: {formatUnits(balance || 0n, decimals || 18)}
Total Supply: {formatUnits(totalSupply || 0n, decimals || 18)}
);
}
```
## Write Contract Data
```typescript
const STAKING_ABI = [
"function stake(uint256 amount) payable",
"function unstake(uint256 amount)",
"function getStakedBalance(address user) view returns (uint256)",
"event Staked(address indexed user, uint256 amount)",
"event Unstaked(address indexed user, uint256 amount)"
];
async function stakeTokens(
signer: any,
contractAddress: string,
amount: string,
decimals: number
) {
try {
const contract = new ethers.Contract(
contractAddress,
STAKING_ABI,
signer
);
const parsedAmount = ethers.parseUnits(amount, decimals);
const tx = await contract.stake(parsedAmount);
console.log("Staking transaction:", tx.hash);
const receipt = await tx.wait();
console.log("Transaction confirmed");
const stakedEvent = receipt.logs.find(
log => log.topics[0] === contract.interface.getEvent("Staked").topicHash
);
if (stakedEvent) {
const parsedEvent = contract.interface.parseLog(stakedEvent);
console.log("Staked amount:", parsedEvent.args.amount.toString());
}
const newBalance = await contract.getStakedBalance(
await signer.getAddress()
);
return {
hash: tx.hash,
stakedAmount: ethers.formatUnits(newBalance, decimals)
};
} catch (error) {
console.error("Staking failed:", error);
throw error;
}
}
```
```typescript
import { parseUnits, formatUnits, parseEventLogs } from "viem";
const STAKING_ABI = [
{
name: "stake",
type: "function",
stateMutability: "payable",
inputs: [{ name: "amount", type: "uint256" }],
outputs: []
},
{
name: "unstake",
type: "function",
stateMutability: "nonpayable",
inputs: [{ name: "amount", type: "uint256" }],
outputs: []
},
{
name: "getStakedBalance",
type: "function",
stateMutability: "view",
inputs: [{ name: "user", type: "address" }],
outputs: [{ type: "uint256" }]
},
{
name: "Staked",
type: "event",
inputs: [
{ name: "user", type: "address", indexed: true },
{ name: "amount", type: "uint256" }
]
},
{
name: "Unstaked",
type: "event",
inputs: [
{ name: "user", type: "address", indexed: true },
{ name: "amount", type: "uint256" }
]
}
] as const;
async function stakeTokens(
walletClient: any,
publicClient: any,
account: any,
contractAddress: `0x${string}`,
amount: string,
decimals: number
) {
try {
const parsedAmount = parseUnits(amount, decimals);
const { request } = await publicClient.simulateContract({
address: contractAddress,
abi: STAKING_ABI,
functionName: "stake",
args: [parsedAmount],
account
});
const hash = await walletClient.writeContract(request);
console.log("Staking transaction:", hash);
const receipt = await publicClient.waitForTransactionReceipt({
hash
});
const logs = parseEventLogs({
abi: STAKING_ABI,
logs: receipt.logs
});
const stakedEvent = logs.find(log => log.eventName === "Staked");
if (stakedEvent) {
console.log("Staked amount:", stakedEvent.args.amount.toString());
}
const newBalance = await publicClient.readContract({
address: contractAddress,
abi: STAKING_ABI,
functionName: "getStakedBalance",
args: [account.address]
});
return {
hash,
stakedAmount: formatUnits(newBalance, decimals)
};
} catch (error) {
console.error("Staking failed:", error);
throw error;
}
}
```
```typescript
import {
usePrepareContractWrite,
useContractWrite,
useWaitForTransaction,
useContractRead
} from "wagmi";
import { parseUnits, formatUnits } from "viem";
const STAKING_ABI = [
{
name: "stake",
type: "function",
stateMutability: "payable",
inputs: [{ name: "amount", type: "uint256" }],
outputs: []
},
{
name: "getStakedBalance",
type: "function",
stateMutability: "view",
inputs: [{ name: "user", type: "address" }],
outputs: [{ type: "uint256" }]
}
] as const;
function StakeTokens({
contractAddress,
userAddress,
decimals = 18
}: {
contractAddress: `0x${string}`;
userAddress: `0x${string}`;
decimals?: number;
}) {
const amount = "100";
const { config } = usePrepareContractWrite({
address: contractAddress,
abi: STAKING_ABI,
functionName: "stake",
args: [parseUnits(amount, decimals)]
});
const {
write: stake,
data: txData,
isLoading: isStaking
} = useContractWrite(config);
const { isLoading: isConfirming } = useWaitForTransaction({
hash: txData?.hash
});
const { data: stakedBalance } = useContractRead({
address: contractAddress,
abi: STAKING_ABI,
functionName: "getStakedBalance",
args: [userAddress],
watch: true
});
return (
Staked: {formatUnits(stakedBalance || 0n, decimals)}
stake?.()}
disabled={!stake || isStaking || isConfirming}
>
Stake {amount} Tokens
{txData &&
Transaction: {txData.hash}
}
);
}
```
## Next Steps
# Manage Token Allowances
Source: https://docs.getpara.com/v2/react/guides/web3-operations/evm/manage-allowances
Approve tokens, check allowances, and implement permit signatures
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Manage ERC-20 token allowances to allow smart contracts to spend tokens on behalf of a user. This guide covers checking and setting allowances using , , and .
## Prerequisites
You need Web3 libraries configured with Para authentication.
## Manage Token Allowances
```typescript
import { ethers } from "ethers";
const ERC20_ABI = [
"function allowance(address owner, address spender) view returns (uint256)",
"function approve(address spender, uint256 amount) returns (bool)",
];
async function checkAllowance(
provider: ethers.Provider,
tokenAddress: string,
owner: string,
spender: string
) {
const contract = new ethers.Contract(tokenAddress, ERC20_ABI, provider);
const allowance = await contract.allowance(owner, spender);
return allowance;
}
async function approveToken(
signer: ethers.Signer,
tokenAddress: string,
spender: string,
amount: string
) {
const contract = new ethers.Contract(tokenAddress, ERC20_ABI, signer);
const tx = await contract.approve(spender, ethers.parseEther(amount));
await tx.wait();
return tx;
}
```
```typescript
import { parseEther } from "viem";
const ERC20_ABI = [
{
name: "allowance",
type: "function",
stateMutability: "view",
inputs: [
{ name: "owner", type: "address" },
{ name: "spender", type: "address" },
],
outputs: [{ type: "uint256" }],
},
{
name: "approve",
type: "function",
stateMutability: "nonpayable",
inputs: [
{ name: "spender", type: "address" },
{ name: "amount", type: "uint256" },
],
outputs: [{ type: "bool" }],
},
] as const;
async function checkAllowance(
publicClient: any,
tokenAddress: `0x${string}`,
owner: `0x${string}`,
spender: `0x${string}`
) {
const allowance = await publicClient.readContract({
address: tokenAddress,
abi: ERC20_ABI,
functionName: "allowance",
args: [owner, spender],
});
return allowance;
}
async function approveToken(
walletClient: any,
account: any,
tokenAddress: `0x${string}`,
spender: `0x${string}`,
amount: string
) {
const { request } = await walletClient.simulateContract({
account,
address: tokenAddress,
abi: ERC20_ABI,
functionName: "approve",
args: [spender, parseEther(amount)],
});
const hash = await walletClient.writeContract(request);
return hash;
}
```
```typescript
import { useReadContract, useWriteContract } from "wagmi";
import { parseEther } from "viem";
const ERC20_ABI = [
{
name: "allowance",
type: "function",
stateMutability: "view",
inputs: [
{ name: "owner", type: "address" },
{ name: "spender", type: "address" },
],
outputs: [{ type: "uint256" }],
},
{
name: "approve",
type: "function",
stateMutability: "nonpayable",
inputs: [
{ name: "spender", type: "address" },
{ name: "amount", type: "uint256" },
],
outputs: [{ type: "bool" }],
},
] as const;
function TokenAllowance(
tokenAddress: `0x${string}`,
owner: `0x${string}`,
spender: `0x${string}`
) {
const { data: allowance } = useReadContract({
address: tokenAddress,
abi: ERC20_ABI,
functionName: "allowance",
args: [owner, spender],
});
const { writeContract } = useWriteContract();
return (
Allowance: {allowance?.toString()}
writeContract({
address: tokenAddress,
abi: ERC20_ABI,
functionName: "approve",
args: [spender, parseEther("100")],
})
}
>
Approve 100 Tokens
);
}
```
# Query Wallet Balances
Source: https://docs.getpara.com/v2/react/guides/web3-operations/evm/query-balances
Check ETH and ERC-20 token balances using Web3 libraries with Para
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Query ETH and ERC-20 token balances for Para wallets across different networks.
## Prerequisites
You need Web3 libraries configured with Para authentication.
## Query ETH Balance
```typescript
import { ethers } from "ethers";
import { ParaEthersSigner } from "@getpara/ethers-v6-integration@alpha";
async function getETHBalance(signer: ParaEthersSigner, provider: ethers.Provider) {
const address = await signer.getAddress();
const balance = await provider.getBalance(address);
const formattedBalance = ethers.formatEther(balance);
console.log(`ETH Balance: ${formattedBalance} ETH`);
return {
wei: balance.toString(),
ether: formattedBalance
};
}
```
```typescript
import { formatEther } from "viem";
import { createParaAccount } from "@getpara/viem-v2-integration@alpha";
async function getETHBalance(publicClient: any, para: any) {
const account = await createParaAccount(para);
const balance = await publicClient.getBalance({
address: account.address
});
const formattedBalance = formatEther(balance);
console.log(`ETH Balance: ${formattedBalance} ETH`);
return {
wei: balance.toString(),
ether: formattedBalance
};
}
```
```typescript
import { useBalance, useAccount } from "wagmi";
function ETHBalance() {
const { address } = useAccount();
const { data, isError, isLoading } = useBalance({
address: address
});
if (isLoading) return Loading balance...
;
if (isError) return Error fetching balance
;
return (
ETH Balance: {data?.formatted} {data?.symbol}
Wei: {data?.value.toString()}
);
}
```
## Query ERC-20 Token Balance
```typescript
import { ethers } from "ethers";
const ERC20_ABI = [
"function balanceOf(address owner) view returns (uint256)",
"function decimals() view returns (uint8)",
"function symbol() view returns (string)"
];
async function getTokenBalance(
signer: any,
tokenAddress: string,
provider: ethers.Provider
) {
const contract = new ethers.Contract(tokenAddress, ERC20_ABI, provider);
const address = await signer.getAddress();
const [balance, decimals, symbol] = await Promise.all([
contract.balanceOf(address),
contract.decimals(),
contract.symbol()
]);
const formattedBalance = ethers.formatUnits(balance, decimals);
console.log(`${symbol} Balance: ${formattedBalance}`);
return {
raw: balance.toString(),
formatted: formattedBalance,
symbol,
decimals
};
}
```
```typescript
import { formatUnits } from "viem";
const ERC20_ABI = [
{
name: "balanceOf",
type: "function",
stateMutability: "view",
inputs: [{ name: "owner", type: "address" }],
outputs: [{ type: "uint256" }]
},
{
name: "decimals",
type: "function",
stateMutability: "view",
inputs: [],
outputs: [{ type: "uint8" }]
},
{
name: "symbol",
type: "function",
stateMutability: "view",
inputs: [],
outputs: [{ type: "string" }]
}
] as const;
async function getTokenBalance(
publicClient: any,
account: any,
tokenAddress: `0x${string}`
) {
const [balance, decimals, symbol] = await Promise.all([
publicClient.readContract({
address: tokenAddress,
abi: ERC20_ABI,
functionName: "balanceOf",
args: [account.address]
}),
publicClient.readContract({
address: tokenAddress,
abi: ERC20_ABI,
functionName: "decimals"
}),
publicClient.readContract({
address: tokenAddress,
abi: ERC20_ABI,
functionName: "symbol"
})
]);
const formattedBalance = formatUnits(balance, decimals);
console.log(`${symbol} Balance: ${formattedBalance}`);
return {
raw: balance.toString(),
formatted: formattedBalance,
symbol,
decimals
};
}
```
```typescript
import { useAccount, useContractReads } from "wagmi";
const ERC20_ABI = [
{
name: "balanceOf",
type: "function",
stateMutability: "view",
inputs: [{ name: "owner", type: "address" }],
outputs: [{ type: "uint256" }]
},
{
name: "decimals",
type: "function",
stateMutability: "view",
inputs: [],
outputs: [{ type: "uint8" }]
},
{
name: "symbol",
type: "function",
stateMutability: "view",
inputs: [],
outputs: [{ type: "string" }]
}
] as const;
function TokenBalance({ tokenAddress }: { tokenAddress: `0x${string}` }) {
const { address } = useAccount();
const { data, isLoading } = useContractReads({
contracts: [
{
address: tokenAddress,
abi: ERC20_ABI,
functionName: "balanceOf",
args: [address!]
},
{
address: tokenAddress,
abi: ERC20_ABI,
functionName: "decimals"
},
{
address: tokenAddress,
abi: ERC20_ABI,
functionName: "symbol"
}
]
});
if (isLoading) return Loading token balance...
;
const balance = data?.[0]?.result;
const decimals = data?.[1]?.result;
const symbol = data?.[2]?.result;
if (!balance || !decimals) return No balance data
;
const formatted = (Number(balance) / 10 ** decimals).toFixed(4);
return (
{symbol} Balance: {formatted}
);
}
```
## Next Steps
# Send Tokens
Source: https://docs.getpara.com/v2/react/guides/web3-operations/evm/send-tokens
Transfer ETH and ERC-20 tokens using Web3 libraries with Para
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Send ETH and ERC-20 token transfers securely using Para's wallet infrastructure.
## Prerequisites
You need Web3 libraries configured with Para authentication.
## Send ETH
```typescript
import { ethers } from "ethers";
import { ParaEthersSigner } from "@getpara/ethers-v6-integration@alpha";
async function sendETH(
signer: ParaEthersSigner,
toAddress: string,
amountInEther: string
) {
try {
const tx = await signer.sendTransaction({
to: toAddress,
value: ethers.parseEther(amountInEther)
});
console.log("Transaction hash:", tx.hash);
const receipt = await tx.wait();
console.log("Transaction confirmed in block:", receipt.blockNumber);
return {
hash: tx.hash,
blockNumber: receipt.blockNumber,
gasUsed: receipt.gasUsed.toString()
};
} catch (error) {
console.error("Transaction failed:", error);
throw error;
}
}
```
```typescript
import { parseEther } from "viem";
async function sendETH(
walletClient: any,
account: any,
toAddress: `0x${string}`,
amountInEther: string
) {
try {
const hash = await walletClient.sendTransaction({
account,
to: toAddress,
value: parseEther(amountInEther)
});
console.log("Transaction hash:", hash);
const receipt = await walletClient.waitForTransactionReceipt({
hash
});
console.log("Transaction confirmed in block:", receipt.blockNumber);
return {
hash,
blockNumber: receipt.blockNumber,
gasUsed: receipt.gasUsed.toString()
};
} catch (error) {
console.error("Transaction failed:", error);
throw error;
}
}
```
```typescript
import { useSendTransaction, useWaitForTransaction } from "wagmi";
import { parseEther } from "viem";
function SendETH() {
const {
data: txData,
isLoading,
sendTransaction
} = useSendTransaction();
const {
data: receipt,
isLoading: isConfirming
} = useWaitForTransaction({
hash: txData?.hash
});
const handleSend = async () => {
sendTransaction({
to: "0x742d35Cc6634C0532925a3b844Bc9e7595f7BBB2",
value: parseEther("0.01")
});
};
return (
{isLoading ? "Sending..." : "Send 0.01 ETH"}
{txData &&
Transaction Hash: {txData.hash}
}
{receipt &&
Confirmed in block: {receipt.blockNumber}
}
);
}
```
## Send ERC-20 Tokens
```typescript
import { ethers } from "ethers";
const ERC20_ABI = [
"function transfer(address to, uint256 amount) returns (bool)"
];
async function sendToken(
signer: any,
tokenAddress: string,
toAddress: string,
amount: string,
decimals: number
) {
try {
const contract = new ethers.Contract(
tokenAddress,
ERC20_ABI,
signer
);
const parsedAmount = ethers.parseUnits(amount, decimals);
const tx = await contract.transfer(toAddress, parsedAmount);
console.log("Transaction hash:", tx.hash);
const receipt = await tx.wait();
console.log("Transaction confirmed");
return {
hash: tx.hash,
blockNumber: receipt.blockNumber,
gasUsed: receipt.gasUsed.toString()
};
} catch (error) {
console.error("Token transfer failed:", error);
throw error;
}
}
```
```typescript
import { parseUnits } from "viem";
const ERC20_ABI = [
{
name: "transfer",
type: "function",
stateMutability: "nonpayable",
inputs: [
{ name: "to", type: "address" },
{ name: "amount", type: "uint256" }
],
outputs: [{ type: "bool" }]
}
] as const;
async function sendToken(
walletClient: any,
account: any,
tokenAddress: `0x${string}`,
toAddress: `0x${string}`,
amount: string,
decimals: number
) {
try {
const parsedAmount = parseUnits(amount, decimals);
const { request } = await walletClient.simulateContract({
account,
address: tokenAddress,
abi: ERC20_ABI,
functionName: "transfer",
args: [toAddress, parsedAmount]
});
const hash = await walletClient.writeContract(request);
console.log("Transaction hash:", hash);
const receipt = await walletClient.waitForTransactionReceipt({
hash
});
return {
hash,
blockNumber: receipt.blockNumber,
gasUsed: receipt.gasUsed.toString()
};
} catch (error) {
console.error("Token transfer failed:", error);
throw error;
}
}
```
```typescript
import { useContractWrite, useWaitForTransaction } from "wagmi";
import { parseUnits } from "viem";
const ERC20_ABI = [
{
name: "transfer",
type: "function",
stateMutability: "nonpayable",
inputs: [
{ name: "to", type: "address" },
{ name: "amount", type: "uint256" }
],
outputs: [{ type: "bool" }]
}
] as const;
function SendToken({
tokenAddress,
decimals
}: {
tokenAddress: `0x${string}`;
decimals: number;
}) {
const {
data: txData,
write: transfer,
isLoading
} = useContractWrite({
address: tokenAddress,
abi: ERC20_ABI,
functionName: "transfer"
});
const {
isLoading: isConfirming
} = useWaitForTransaction({
hash: txData?.hash
});
const handleTransfer = () => {
transfer({
args: [
"0x742d35Cc6634C0532925a3b844Bc9e7595f7BBB2",
parseUnits("10", decimals)
]
});
};
return (
{isLoading ? "Sending..." : "Send 10 Tokens"}
);
}
```
## Next Steps
# Setup Web3 Libraries
Source: https://docs.getpara.com/v2/react/guides/web3-operations/evm/setup-libraries
Configure Ethers.js, Viem, or Wagmi to work with Para's secure wallet infrastructure
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Learn how to set up popular Web3 libraries with Para. Choose from , , or to build your EVM application.
## Prerequisites
Before setting up Web3 libraries, you need an authenticated Para session.
## Installation
If using `viem` and the `@getpara/react-sdk` you can use our hook or hook to access the Viem client and account without any additional setup.
```bash npm
npm install @getpara/ethers-v6-integration@alpha ethers@^6 --save-exact
```
```bash yarn
yarn add @getpara/ethers-v6-integration@alpha ethers@^6 --exact
```
```bash pnpm
pnpm add @getpara/ethers-v6-integration@alpha ethers@^6 --save-exact
```
```bash bun
bun add @getpara/ethers-v6-integration@alpha ethers@^6 --exact
```
```bash npm
npm install @getpara/viem-v2-integration@alpha viem@^2 --save-exact
```
```bash yarn
yarn add @getpara/viem-v2-integration@alpha viem@^2 --exact
```
```bash pnpm
pnpm add @getpara/viem-v2-integration@alpha viem@^2 --save-exact
```
```bash bun
bun add @getpara/viem-v2-integration@alpha viem@^2 --exact
```
```bash npm
npm install @getpara/wagmi-v2-integration@alpha @tanstack/react-query wagmi@^2 viem --save-exact
```
```bash yarn
yarn add @getpara/wagmi-v2-integration@alpha @tanstack/react-query wagmi@^2 viem --exact
```
```bash pnpm
pnpm add @getpara/wagmi-v2-integration@alpha @tanstack/react-query wagmi@^2 viem --save-exact
```
```bash bun
bun add @getpara/wagmi-v2-integration@alpha @tanstack/react-query wagmi@^2 viem --exact
```
## Library Setup and Configuration
Configure your chosen Web3 library. You can use either a hook-based approach for React applications or a direct client setup for non-React environments or if you want to access the client outside of the `ParaProvider` context.
```typescript useEthers.ts
import { useClient, useAccount } from "@getpara/react-sdk";
import { ParaEthersSigner } from "@getpara/ethers-v6-integration";
import { ethers } from "ethers";
import { useMemo } from "react";
export function useEthers(rpcUrl: string = "https://ethereum-sepolia-rpc.publicnode.com") {
const para = useClient();
const { isConnected, embedded } = useAccount();
const clients = useMemo(() => {
// Create a provider connected to your RPC endpoint
const provider = new ethers.JsonRpcProvider(rpcUrl);
// Check if Para is initialized and user has wallets
if (!para || !isConnected || !embedded.wallets?.length) {
return { provider, signer: null };
}
// Filter for EVM-compatible wallets
const evmWallets = embedded.wallets.filter(w => w.type === "EVM");
if (evmWallets.length === 0) {
return { provider, signer: null };
}
// Create Para-enabled signer for transaction signing
const signer = new ParaEthersSigner(para, provider);
return { provider, signer };
}, [para, isConnected, embedded.wallets, rpcUrl]);
return clients;
}
```
```typescript useViem.ts
import { useClient, useAccount } from "@getpara/react-sdk";
import { createParaViemClient, createParaAccount } from "@getpara/viem-v2-integration";
import { createPublicClient, http } from "viem";
import { sepolia } from "viem/chains";
import { useMemo } from "react";
export function useViem(chain = sepolia, rpcUrl: string = "https://ethereum-sepolia-rpc.publicnode.com") {
const para = useClient();
const { isConnected, embedded } = useAccount();
const clients = useMemo(async () => {
// Create a public client for reading blockchain data
const publicClient = createPublicClient({
chain,
transport: http(rpcUrl)
});
// Check if Para is initialized and user has wallets
if (!para || !isConnected || !embedded.wallets?.length) {
return { publicClient, walletClient: null };
}
// Filter for EVM-compatible wallets
const evmWallets = embedded.wallets.filter(w => w.type === "EVM");
if (evmWallets.length === 0) {
return { publicClient, walletClient: null };
}
// Create Para account and wallet client for transactions
const account = await createParaAccount(para);
const walletClient = createParaViemClient(para, {
account,
chain,
transport: http(rpcUrl)
});
return { publicClient, walletClient };
}, [para, isConnected, embedded.wallets, chain, rpcUrl]);
return clients;
}
```
```typescript wagmi.config.ts
import { useClient, useAccount } from "@getpara/react-sdk";
import { paraConnector } from "@getpara/wagmi-v2-integration";
import { createConfig, http } from "wagmi";
import { sepolia } from "wagmi/chains";
import { useMemo } from "react";
export function useWagmiConfig() {
const para = useClient();
const { isConnected, embedded } = useAccount();
const config = useMemo(() => {
if (!para) return null;
// Check if user has EVM wallets
const evmWallets = embedded.wallets?.filter(w => w.type === "EVM") || [];
if (!isConnected || evmWallets.length === 0) {
// Return config without Para connector if no wallets
return createConfig({
chains: [sepolia],
transports: {
[sepolia.id]: http("https://ethereum-sepolia-rpc.publicnode.com")
}
});
}
// Create Para connector for wallet integration
const connector = paraConnector({
para,
chains: [sepolia],
appName: "Your App Name" // Replace with your app name
});
return createConfig({
chains: [sepolia],
connectors: [connector],
transports: {
[sepolia.id]: http("https://ethereum-sepolia-rpc.publicnode.com")
}
});
}, [para, isConnected, embedded.wallets]);
return config;
}
```
```typescript ethers-setup.ts
import { ParaEthersSigner } from "@getpara/ethers-v6-integration";
import { ethers } from "ethers";
import Para from "@getpara/web-sdk";
const PARA_API_KEY = "YOUR_PARA_API_KEY"; // Replace with your API key
export async function setupEthers(rpcUrl: string = "https://ethereum-sepolia-rpc.publicnode.com") {
// Initialize Para SDK with your API key
const para = new Para(PARA_API_KEY);
const provider = new ethers.JsonRpcProvider(rpcUrl);
// Verify user has an active session
const isAuthenticated = await para.isSessionActive();
if (!isAuthenticated) {
throw new Error("Para session not authenticated");
}
// Get user's EVM wallets
const wallets = await para.getWalletsByType({ type: "EVM" });
if (wallets.length === 0) {
throw new Error("No EVM wallets available");
}
// Create Para-enabled signer for transactions
const signer = new ParaEthersSigner(para, provider);
return { provider, signer, para };
}
```
```typescript viem-setup.ts
import { createParaViemClient, createParaAccount } from "@getpara/viem-v2-integration";
import { createPublicClient, http } from "viem";
import { sepolia } from "viem/chains";
import Para from "@getpara/web-sdk";
const PARA_API_KEY = "YOUR_PARA_API_KEY"; // Replace with your API key
export async function setupViem(chain = sepolia, rpcUrl: string = "https://ethereum-sepolia-rpc.publicnode.com") {
// Initialize Para SDK with your API key
const para = new Para(PARA_API_KEY);
// Create public client for reading blockchain data
const publicClient = createPublicClient({
chain,
transport: http(rpcUrl)
});
// Verify user has an active session
const isAuthenticated = await para.isSessionActive();
if (!isAuthenticated) {
throw new Error("Para session not authenticated");
}
// Get user's EVM wallets
const wallets = await para.getWalletsByType({ type: "EVM" });
if (wallets.length === 0) {
throw new Error("No EVM wallets available");
}
// Create Para account and wallet client for transactions
const account = await createParaAccount(para);
const walletClient = createParaViemClient(para, {
account,
chain,
transport: http(rpcUrl)
});
return { publicClient, walletClient, para };
}
```
## Next Steps
Now that you have Web3 libraries configured with Para, explore common operations.
# Sign Messages
Source: https://docs.getpara.com/v2/react/guides/web3-operations/evm/sign-messages
Sign plain text messages for authentication or verification with Web3 libraries
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Sign plain text messages using Para's secure signing infrastructure.
## Prerequisites
You need Web3 libraries configured with Para authentication.
## Sign Personal Messages
```typescript
import { ethers } from "ethers";
import { ParaEthersSigner } from "@getpara/ethers-v6-integration@alpha";
async function signMessage(
signer: ParaEthersSigner,
message: string
) {
try {
const signature = await signer.signMessage(message);
console.log("Signature:", signature);
const address = await signer.getAddress();
const recoveredAddress = ethers.verifyMessage(message, signature);
console.log("Signer address:", address);
console.log("Recovered address:", recoveredAddress);
console.log("Signature valid:", address === recoveredAddress);
return {
signature,
address,
message,
isValid: address.toLowerCase() === recoveredAddress.toLowerCase()
};
} catch (error) {
console.error("Failed to sign message:", error);
throw error;
}
}
```
```typescript
import { verifyMessage } from "viem";
async function signMessage(
walletClient: any,
account: any,
message: string
) {
try {
const signature = await walletClient.signMessage({
account,
message
});
console.log("Signature:", signature);
const isValid = await verifyMessage({
address: account.address,
message,
signature
});
console.log("Signature valid:", isValid);
return {
signature,
address: account.address,
message,
isValid
};
} catch (error) {
console.error("Failed to sign message:", error);
throw error;
}
}
```
```typescript
import { useSignMessage } from "wagmi";
import { verifyMessage } from "viem";
function SignMessage() {
const {
data: signature,
isLoading,
signMessage,
variables
} = useSignMessage();
const handleSign = () => {
signMessage({
message: "Hello from Para!"
});
};
const verifySignature = async () => {
if (!signature || !variables?.message) return;
const isValid = await verifyMessage({
address: "0x...", // User's address
message: variables.message,
signature
});
console.log("Signature valid:", isValid);
};
return (
{isLoading ? "Signing..." : "Sign Message"}
{signature && (
Signature: {signature.slice(0, 20)}...
Verify Signature
)}
);
}
```
## Sign Structured Messages
```typescript
async function signStructuredMessage(
signer: ParaEthersSigner,
data: any
) {
try {
const message = JSON.stringify(data, null, 2);
const messageHash = ethers.hashMessage(message);
console.log("Message hash:", messageHash);
const signature = await signer.signMessage(message);
const signerAddress = await signer.getAddress();
const recoveredAddress = ethers.recoverAddress(
messageHash,
signature
);
return {
message,
messageHash,
signature,
signerAddress,
recoveredAddress,
isValid: signerAddress.toLowerCase() === recoveredAddress.toLowerCase()
};
} catch (error) {
console.error("Failed to sign structured message:", error);
throw error;
}
}
```
```typescript
import { hashMessage, recoverMessageAddress } from "viem";
async function signStructuredMessage(
walletClient: any,
account: any,
data: any
) {
try {
const message = JSON.stringify(data, null, 2);
const messageHash = hashMessage(message);
console.log("Message hash:", messageHash);
const signature = await walletClient.signMessage({
account,
message
});
const recoveredAddress = await recoverMessageAddress({
message,
signature
});
return {
message,
messageHash,
signature,
signerAddress: account.address,
recoveredAddress,
isValid: account.address.toLowerCase() === recoveredAddress.toLowerCase()
};
} catch (error) {
console.error("Failed to sign structured message:", error);
throw error;
}
}
```
```typescript
import { useAccount, useSignMessage } from "wagmi";
import { hashMessage } from "viem";
function SignStructuredMessage() {
const { address } = useAccount();
const { signMessage, data: signature } = useSignMessage();
const signData = (data: any) => {
const message = JSON.stringify(data, null, 2);
const messageHash = hashMessage(message);
console.log("Signing hash:", messageHash);
signMessage({ message });
};
const handleSign = () => {
const data = {
action: "authenticate",
timestamp: Date.now(),
nonce: Math.random().toString(36).substring(7)
};
signData(data);
};
return (
Sign Structured Data
{signature && (
Signature: {signature.slice(0, 30)}...
)}
);
}
```
## Next Steps
# Sign Typed Data (EIP-712)
Source: https://docs.getpara.com/v2/react/guides/web3-operations/evm/sign-typed-data
Sign structured data using the EIP-712 standard for improved security and UX
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Sign structured data according to the EIP-712 standard, which provides a more readable and secure signing experience for users. This guide covers signing typed data with , , and .
## Prerequisites
You need Web3 libraries configured with Para authentication.
## Sign Typed Data
```typescript
import { ethers } from "ethers";
async function signTypedData(
signer: ethers.Signer,
domain: any,
types: any,
value: any
) {
const signature = await signer.signTypedData(domain, types, value);
console.log("Signature:", signature);
return signature;
}
```
```typescript
async function signTypedData(
walletClient: any,
account: any,
domain: any,
types: any,
primaryType: string,
message: any
) {
const signature = await walletClient.signTypedData({
account,
domain,
types,
primaryType,
message,
});
console.log("Signature:", signature);
return signature;
}
```
```typescript
import { useSignTypedData } from "wagmi";
function SignTypedData(
domain: any,
types: any,
primaryType: string,
message: any
) {
const { data: signature, signTypedData } = useSignTypedData();
return (
signTypedData({
domain,
types,
primaryType,
message,
})
}
>
Sign Typed Data
{signature &&
Signature: {signature}
}
);
}
```
# Setup Smart Account Libraries
Source: https://docs.getpara.com/v2/react/guides/web3-operations/evm/smart-accounts/setup-libraries
Install and configure account abstraction providers like Alchemy, Biconomy, ZeroDev, and Safe
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
This guide shows you how to set up various account abstraction libraries to create and manage smart accounts using the standard and Para's Viem integration. These libraries allow you to interact with smart accounts, send user operations, and sponsor gas fees for transactions.
## Setup and Configuration
### Installation
```bash npm
npm install --save-exact @aa-sdk/core@latest @account-kit/infra@latest @account-kit/smart-contracts@latest viem
```
```bash yarn
yarn add --exact @aa-sdk/core@latest @account-kit/infra@latest @account-kit/smart-contracts@latest viem
```
```bash pnpm
pnpm add --save-exact @aa-sdk/core@latest @account-kit/infra@latest @account-kit/smart-contracts@latest viem
```
```bash bun
bun add --exact @aa-sdk/core@latest @account-kit/infra@latest @account-kit/smart-contracts@latest viem
```
### Configuration
```typescript useAlchemySmartAccount.ts
import { type WalletClient, http, createWalletClient } from "viem";
import { sepolia } from "viem/chains";
import { useViemAccount } from "@getpara/react-sdk";
import { WalletClientSigner } from "@aa-sdk/core";
import { createModularAccountAlchemyClient } from "@account-kit/smart-contracts";
import { alchemy } from "@account-kit/infra";
import { useState, useEffect } from "react";
// Configuration constants - Replace with your values
const CHAIN = sepolia; // Target chain
const ALCHEMY_RPC_URL = "https://eth-sepolia.g.alchemy.com/v2/YOUR_ALCHEMY_API_KEY"; // Replace with your Alchemy RPC URL
const GAS_POLICY_ID = "YOUR_ALCHEMY_GAS_POLICY_ID"; // Replace with your Alchemy gas policy ID
const salt = "YOUR_SALT"; // Used for account creation.
export const useAlchemySmartAccount = () => {
const { viemAccount, isLoading: accountLoading } = useViemAccount();
const [client, setClient] = useState(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const initializeClient = async () => {
if (!viemAccount || accountLoading) return;
try {
// Create a Viem WalletClient with the Para account
const walletClient: WalletClient = createWalletClient({
account: viemAccount,
chain: CHAIN,
transport: http(ALCHEMY_RPC_URL)
});
// Create WalletClientSigner from the Viem WalletClient
const walletClientSigner = new WalletClientSigner(walletClient, "wallet");
// Create modular account Alchemy client with the WalletClientSigner
const alchemyClient = await createModularAccountAlchemyClient({
transport: alchemy({ rpcUrl: ALCHEMY_RPC_URL }),
chain: CHAIN,
signer: walletClientSigner,
policyId: GAS_POLICY_ID,
salt,
});
setClient(alchemyClient);
} catch (error) {
console.error("Failed to initialize Alchemy client:", error);
} finally {
setIsLoading(false);
}
};
initializeClient();
}, [viemAccount, accountLoading]);
return { client, isLoading: isLoading || accountLoading };
};
```
### Installation
```bash npm
npm install --save-exact @biconomy/account@latest viem@latest
```
```bash yarn
yarn add --exact @biconomy/account@latest viem@latest
```
```bash pnpm
pnpm add --save-exact @biconomy/account@latest viem@latest
```
```bash bun
bun add --exact @biconomy/account@latest viem@latest
```
### Configuration
```typescript useBiconomySmartAccount.ts
import { type WalletClient, http, createWalletClient } from "viem";
import { sepolia } from "viem/chains";
import { useViemAccount } from "@getpara/react-sdk";
import { createSmartAccountClient } from '@biconomy/account';
import { useState, useEffect } from "react";
// Configuration constants - Replace with your values
const CHAIN = sepolia; // Target chain
const RPC_URL = "https://ethereum-sepolia-rpc.publicnode.com"; // Your RPC endpoint
const BUNDLER_API_KEY = 'YOUR_BICONOMY_BUNDLER_API_KEY'; // From dashboard.biconomy.io
const PAYMASTER_API_KEY = 'YOUR_BICONOMY_PAYMASTER_API_KEY'; // From dashboard.biconomy.io (optional for paymaster)
const BUNDLER_URL = `https://bundler.biconomy.io/api/v2/${CHAIN.id}/${BUNDLER_API_KEY}`; // Biconomy bundler URL
const PAYMASTER_URL = `https://paymaster.biconomy.io/api/v2/${CHAIN.id}/${PAYMASTER_API_KEY}`; // Biconomy paymaster URL (optional)
export const useBiconomySmartAccount = () => {
const { viemAccount, isLoading: accountLoading } = useViemAccount();
const [smartAccountClient, setSmartAccountClient] = useState(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const initializeClient = async () => {
if (!viemAccount || accountLoading) return;
try {
// Create a Viem WalletClient with the Para account
const walletClient: WalletClient = createWalletClient({
account: viemAccount,
chain: CHAIN,
transport: http(RPC_URL)
});
// Create Biconomy smart account client with the WalletClient
const client = await createSmartAccountClient({
signer: walletClient,
chainId: CHAIN.id,
bundlerUrl: BUNDLER_URL,
paymasterUrl: PAYMASTER_URL, // Optional; include for gasless tx support
});
setSmartAccountClient(client);
} catch (error) {
console.error("Failed to initialize Biconomy client:", error);
} finally {
setIsLoading(false);
}
};
initializeClient();
}, [viemAccount, accountLoading]);
return { smartAccountClient, isLoading: isLoading || accountLoading };
};
```
### Installation
```bash npm
npm install --save-exact @gelatonetwork/smartwallet viem
```
```bash yarn
yarn add --exact @gelatonetwork/smartwallet viem
```
```bash pnpm
pnpm add --save-exact @gelatonetwork/smartwallet viem
```
```bash bun
bun add --exact @gelatonetwork/smartwallet viem
```
### Configuration
```typescript useGelatoSmartAccount.ts
import { createPublicClient, http, createWalletClient } from "viem";
import { sepolia } from "viem/chains";
import { useViemAccount } from "@getpara/react-sdk";
import { createGelatoSmartWalletClient, accounts } from "@gelatonetwork/smartwallet";
import { useState, useEffect } from "react";
// Configuration constants - Replace with your values
const CHAIN = sepolia; // Target chain
const RPC_URL = "https://ethereum-sepolia-rpc.publicnode.com"; // Your RPC endpoint
const GELATO_API_KEY = "YOUR_GELATO_API_KEY"; // Gelato API key
const WALLET_INDEX = 0n; // Account index for deterministic addresses
export const useGelatoSmartAccount = () => {
const { viemAccount, isLoading: accountLoading } = useViemAccount();
const [smartWalletClient, setSmartWalletClient] = useState(null);
const [walletClient, setWalletClient] = useState(null);
const [kernelAccount, setKernelAccount] = useState(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const initializeClient = async () => {
if (!viemAccount || accountLoading) return;
try {
// Create a public client for the chain
const publicClient = createPublicClient({
chain: CHAIN,
transport: http(RPC_URL)
});
// Create Gelato Kernel account with Para as the owner
const kernel = await accounts.kernel({
owner: viemAccount,
client: publicClient,
index: WALLET_INDEX,
eip7702: false, // Disable EIP-7702 mode
});
// Create wallet client with the kernel account
const wallet = createWalletClient({
account: kernel,
chain: CHAIN,
transport: http(RPC_URL),
});
// Create Gelato smart wallet client for gasless transactions
const smartWallet = await createGelatoSmartWalletClient(wallet, {
apiKey: GELATO_API_KEY,
});
setKernelAccount(kernel);
setWalletClient(wallet);
setSmartWalletClient(smartWallet);
} catch (error) {
console.error("Failed to initialize Gelato client:", error);
} finally {
setIsLoading(false);
}
};
initializeClient();
}, [viemAccount, accountLoading]);
return { smartWalletClient, walletClient, kernelAccount, isLoading: isLoading || accountLoading };
};
```
### Installation
```bash npm
npm install --save-exact permissionless viem
```
```bash yarn
yarn add --exact permissionless viem
```
```bash pnpm
pnpm add --save-exact permissionless viem
```
```bash bun
bun add --exact permissionless viem
```
### Configuration
```typescript usePimlicoSmartAccount.ts
import { http, createPublicClient } from "viem";
import { sepolia } from "viem/chains";
import { useViemAccount } from "@getpara/react-sdk";
import { createSmartAccountClient, toSimpleSmartAccount } from "permissionless";
import { createPimlicoClient } from "permissionless/clients/pimlico";
import { entryPoint07Address } from "viem/account-abstraction";
import { useState, useEffect } from "react";
// Configuration constants - Replace with your values
const CHAIN = sepolia; // Target chain
const RPC_URL = "https://ethereum-sepolia-rpc.publicnode.com"; // Your RPC endpoint
const PIMLICO_API_KEY = 'YOUR_PIMLICO_API_KEY'; // From dashboard.pimlico.io
const PIMLICO_URL = `https://api.pimlico.io/v2/${CHAIN.id}/rpc?apikey=${PIMLICO_API_KEY}`;
export const usePimlicoSmartAccount = () => {
const { viemAccount, isLoading: accountLoading } = useViemAccount();
const [smartAccountClient, setSmartAccountClient] = useState(null);
const [pimlicoClient, setPimlicoClient] = useState(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const initializeClient = async () => {
if (!viemAccount || accountLoading) return;
try {
// Create Viem PublicClient (needed for smart account)
const publicClient = createPublicClient({
chain: CHAIN,
transport: http(RPC_URL)
});
// Create a SimpleAccount using the Para account as owner
const simpleSmartAccount = await toSimpleSmartAccount({
owner: viemAccount, // Para account acts as the EOA owner
client: publicClient,
entryPoint: {
address: entryPoint07Address,
version: "0.7"
}
// Optional: you can specify index for deterministic address
// index: 0n
});
// Create Pimlico client for bundler operations
const pimlico = createPimlicoClient({
transport: http(PIMLICO_URL),
entryPoint: {
address: entryPoint07Address,
version: "0.7"
}
});
// Create the Smart Account Client
const client = createSmartAccountClient({
account: simpleSmartAccount,
chain: CHAIN,
bundlerTransport: http(PIMLICO_URL),
paymaster: pimlico, // Optional: for gasless transactions
userOperation: {
estimateFeesPerGas: async () => {
return (await pimlico.getUserOperationGasPrice()).fast
}
}
});
setPimlicoClient(pimlico);
setSmartAccountClient(client);
} catch (error) {
console.error("Failed to initialize Pimlico client:", error);
} finally {
setIsLoading(false);
}
};
initializeClient();
}, [viemAccount, accountLoading]);
return { smartAccountClient, pimlicoClient, isLoading: isLoading || accountLoading };
};
```
### Installation
```bash npm
npm install --save-exact permissionless viem
```
```bash yarn
yarn add --exact permissionless viem
```
```bash pnpm
pnpm add --save-exact permissionless viem
```
```bash bun
bun add --exact permissionless viem
```
### Configuration
```typescript useSafeSmartAccount.ts
import { createWalletClient, http, createPublicClient } from "viem";
import { sepolia } from "viem/chains";
import { useViemAccount } from "@getpara/react-sdk";
import { createSmartAccountClient } from "permissionless";
import { toSafeSmartAccount } from "permissionless/accounts";
import { createPimlicoClient } from "permissionless/clients/pimlico";
import { entryPoint07Address } from "viem/account-abstraction";
import { useState, useEffect } from "react";
// Configuration constants - Replace with your values
const CHAIN = sepolia; // Target chain
const RPC_URL = "https://ethereum-sepolia-rpc.publicnode.com"; // Your RPC endpoint
const PIMLICO_API_KEY = 'YOUR_PIMLICO_API_KEY'; // From dashboard.pimlico.io
const PIMLICO_URL = `https://api.pimlico.io/v2/${CHAIN.id}/rpc?apikey=${PIMLICO_API_KEY}`;
export const useSafeSmartAccount = () => {
const { viemAccount, isLoading: accountLoading } = useViemAccount();
const [smartAccountClient, setSmartAccountClient] = useState(null);
const [safeAccount, setSafeAccount] = useState(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const initializeClient = async () => {
if (!viemAccount || accountLoading) return;
try {
// Create Viem WalletClient (used as the EOA owner)
const walletClient = createWalletClient({
account: viemAccount,
chain: CHAIN,
transport: http(RPC_URL)
});
// Create Viem PublicClient (needed for smart account)
const publicClient = createPublicClient({
chain: CHAIN,
transport: http(RPC_URL)
});
// Create a Safe account using the WalletClient as owner
const safe = await toSafeSmartAccount({
client: publicClient,
owners: [walletClient],
entryPoint: {
address: entryPoint07Address,
version: "0.7"
},
safeVersion: "1.4.1"
// Optional: index for deterministic address
// index: 0n
});
// Create Pimlico client for bundler operations
const pimlicoClient = createPimlicoClient({
transport: http(PIMLICO_URL),
entryPoint: {
address: entryPoint07Address,
version: "0.7"
}
});
// Create the Smart Account Client
const client = createSmartAccountClient({
account: safe,
chain: CHAIN,
bundlerTransport: http(PIMLICO_URL),
paymaster: pimlicoClient, // Optional: for gasless transactions
userOperation: {
estimateFeesPerGas: async () => {
return (await pimlicoClient.getUserOperationGasPrice()).fast
}
}
});
setSafeAccount(safe);
setSmartAccountClient(client);
} catch (error) {
console.error("Failed to initialize Safe client:", error);
} finally {
setIsLoading(false);
}
};
initializeClient();
}, [viemAccount, accountLoading]);
return { smartAccountClient, safeAccount, isLoading: isLoading || accountLoading };
};
```
### Installation
```bash npm
npm install --save-exact thirdweb viem
```
```bash yarn
yarn add --exact thirdweb viem
```
```bash pnpm
pnpm add --save-exact thirdweb viem
```
```bash bun
bun add --exact thirdweb viem
```
### Configuration
```typescript useThirdwebSmartAccount.ts
import { createWalletClient, http } from "viem";
import { sepolia } from "viem/chains";
import { useViemAccount } from "@getpara/react-sdk";
import { smartWallet } from "thirdweb/wallets";
import { viemAdapter } from "thirdweb/adapters/viem";
import { DEFAULT_ACCOUNT_FACTORY_V0_7 } from "thirdweb/wallets/smart";
import { createThirdwebClient } from "thirdweb";
import { useState, useEffect, useRef } from "react";
// Configuration constants - Replace with your values
const CHAIN = sepolia; // Target chain
const RPC_URL = "https://ethereum-sepolia-rpc.publicnode.com"; // Your RPC endpoint
const THIRDWEB_CLIENT_ID = "YOUR_THIRDWEB_CLIENT_ID"; // thirdweb client ID
const THIRDWEB_SECRET_KEY = "YOUR_THIRDWEB_SECRET_KEY"; // thirdweb secret
const WALLET_INDEX = 0n; // Account index for deterministic addresses
// Create singleton thirdweb client outside hook
const thirdwebClient = createThirdwebClient({
clientId: THIRDWEB_CLIENT_ID,
secretKey: THIRDWEB_SECRET_KEY,
});
export const useThirdwebSmartAccount = () => {
const { viemAccount, isLoading: accountLoading } = useViemAccount();
const [smartAccount, setSmartAccount] = useState(null);
const [isLoading, setIsLoading] = useState(true);
const clientRef = useRef(thirdwebClient);
useEffect(() => {
const initializeClient = async () => {
if (!viemAccount || accountLoading) return;
try {
// Create Viem wallet client with Para account
const viemWalletClient = createWalletClient({
account: viemAccount,
chain: CHAIN,
transport: http(RPC_URL),
});
// Convert Viem wallet to thirdweb wallet
const personalAccount = viemAdapter.walletClient.fromViem({
walletClient: viemWalletClient,
});
// Generate deterministic salt for the smart wallet
const salt = `0x${WALLET_INDEX.toString(16).padStart(64, "0")}`;
// Configure smart wallet with gas sponsorship
const smartWalletConfig = smartWallet({
chain: CHAIN,
sponsorGas: true, // Enable gasless transactions
factoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_7,
overrides: {
accountSalt: salt, // Deterministic address generation
},
});
// Connect the smart wallet with Para as the signer
const account = await smartWalletConfig.connect({
client: clientRef.current,
personalAccount,
});
setSmartAccount(account);
} catch (error) {
console.error("Failed to initialize Thirdweb client:", error);
} finally {
setIsLoading(false);
}
};
initializeClient();
}, [viemAccount, accountLoading]);
return { smartAccount, thirdwebClient: clientRef.current, isLoading: isLoading || accountLoading };
};
```
### Installation
```bash npm
npm install --save-exact @zerodevapp/sdk viem
```
```bash yarn
yarn add --exact @zerodevapp/sdk viem
```
```bash pnpm
pnpm add --save-exact @zerodevapp/sdk viem
```
```bash bun
bun add --exact @zerodevapp/sdk viem
```
### Configuration
```typescript useZeroDevSmartAccount.ts
import { createPublicClient, http, createWalletClient } from "viem";
import { sepolia } from "viem/chains";
import { useViemAccount } from "@getpara/react-sdk";
import { createKernelAccount, createKernelAccountClient } from "@zerodevapp/sdk";
import { useState, useEffect } from "react";
// Configuration constants - Replace with your values
const CHAIN = sepolia; // Target chain
const RPC_URL = "https://ethereum-sepolia-rpc.publicnode.com"; // Your RPC endpoint
const ZERODEV_PROJECT_ID = "YOUR_ZERODEV_PROJECT_ID"; // ZeroDev project ID
export const useZeroDevSmartAccount = () => {
const { viemAccount, isLoading: accountLoading } = useViemAccount();
const [kernelClient, setKernelClient] = useState(null);
const [kernelAccount, setKernelAccount] = useState(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const initializeClient = async () => {
if (!viemAccount || accountLoading) return;
try {
// Create a public client for the chain
const publicClient = createPublicClient({
chain: CHAIN,
transport: http(RPC_URL)
});
// Create wallet client with Para account
const walletClient = createWalletClient({
account: viemAccount,
chain: CHAIN,
transport: http(RPC_URL)
});
// Create Kernel account with Para as the signer
const kernel = await createKernelAccount(publicClient, {
plugins: {
sudo: walletClient
}
});
// Create Kernel account client with ZeroDev bundler
const client = createKernelAccountClient({
account: kernel,
chain: CHAIN,
transport: http(`https://rpc.zerodev.app/api/v2/bundler/${ZERODEV_PROJECT_ID}`),
});
setKernelAccount(kernel);
setKernelClient(client);
} catch (error) {
console.error("Failed to initialize ZeroDev client:", error);
} finally {
setIsLoading(false);
}
};
initializeClient();
}, [viemAccount, accountLoading]);
return { kernelClient, kernelAccount, isLoading: isLoading || accountLoading };
};
```
Smart Wallets contracts are deployed automatically on the first transaction by the provider. Meaning you don't need to deploy them manually. However, you can deploy them manually if you want by signing and sending an empty transaction.
## Next Steps
# Sponsor Transactions with Libraries
Source: https://docs.getpara.com/v2/react/guides/web3-operations/evm/smart-accounts/sponsor-transactions
Enable gasless transactions using paymasters with various AA providers
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Enable gasless transactions for users with sponsored gas fees using popular AA providers + Para. This guide covers how to configure gas sponsorship with various smart account libraries.
## Prerequisites
You need a Para-enabled smart account client configured with your AA provider. Gas sponsorship is typically configured during the initial client setup.
## Sponsor Transactions
```typescript
import { createModularAccountAlchemyClient } from "@account-kit/smart-contracts";
import { WalletClientSigner } from "@aa-sdk/core";
import { alchemy } from "@account-kit/infra";
// Gas sponsorship is enabled via the policyId parameter
const client = await createModularAccountAlchemyClient({
transport: alchemy({ rpcUrl: ALCHEMY_RPC_URL }),
chain: CHAIN,
signer: walletClientSigner, // Para-enabled WalletClientSigner
policyId: GAS_POLICY_ID, // ← Enables gas sponsorship
salt,
});
// The gas is automatically sponsored based on your policy
const userOpHash = await client.sendUserOperation({
uo: {
target: "0x...", // Recipient address
data: "0x", // Transaction data
value: 0n // ETH value to send
}
});
// Wait for the transaction to be mined
const receipt = await client.waitForUserOperationReceipt({ hash: userOpHash });
```
```typescript
import { createSmartAccountClient } from '@biconomy/account';
// Gas sponsorship is enabled via the paymasterUrl parameter
const smartAccountClient = await createSmartAccountClient({
signer: walletClient, // Para-enabled WalletClient
chainId: chain.id,
bundlerUrl,
paymasterUrl, // ← Enables gas sponsorship
});
// Specify SPONSORED mode in paymasterServiceData
const transaction = {
to: "0x...", // Recipient address
data: "0x", // Transaction data
value: "0" // ETH value as string
};
const userOpResponse = await smartAccountClient.sendTransaction(
transaction,
{
paymasterServiceData: {
mode: "SPONSORED" // ← Request gas sponsorship
}
}
);
const receipt = await userOpResponse.wait();
```
```typescript
import { createGelatoSmartWalletClient } from "@gelatonetwork/smartwallet";
// Gas sponsorship is enabled via the Gelato API key
const smartWalletClient = await createGelatoSmartWalletClient(
walletClient, // Para-enabled WalletClient with kernel account
{
apiKey: GELATO_API_KEY, // ← Enables gas sponsorship
}
);
// Gas is automatically sponsored when using the smart wallet client
const txHash = await smartWalletClient.sendTransaction({
to: "0x...", // Recipient address
value: 0n, // ETH value to send
data: "0x" // Transaction data
});
// Wait for the transaction to be mined
const receipt = await smartWalletClient.waitForTransactionReceipt({
hash: txHash
});
```
```typescript
import { createSmartAccountClient } from "permissionless";
import { createPimlicoClient } from "permissionless/clients/pimlico";
// Create Pimlico client for paymaster operations
const pimlicoClient = createPimlicoClient({
transport: http(PIMLICO_URL),
entryPoint: {
address: entryPoint07Address,
version: "0.7"
}
});
// Include paymaster in smart account client
const smartAccountClient = createSmartAccountClient({
account: simpleSmartAccount, // Para-enabled smart account
chain: CHAIN,
bundlerTransport: http(PIMLICO_URL),
paymaster: pimlicoClient, // ← Enables gas sponsorship
userOperation: {
estimateFeesPerGas: async () => {
return (await pimlicoClient.getUserOperationGasPrice()).fast
}
}
});
// Gas is automatically sponsored via the paymaster
const userOpHash = await smartAccountClient.sendUserOperation({
calls: [{
to: "0x...", // Recipient address
value: 0n, // ETH value to send
data: "0x" // Transaction data
}]
});
// Wait for the transaction to be mined
const receipt = await smartAccountClient.waitForUserOperationReceipt({
hash: userOpHash
});
```
```typescript
import { createSmartAccountClient } from "permissionless";
import { toSafeSmartAccount } from "permissionless/accounts";
import { createPimlicoClient } from "permissionless/clients/pimlico";
// Safe uses Pimlico as the paymaster provider
const pimlicoClient = createPimlicoClient({
transport: http(PIMLICO_URL),
entryPoint: {
address: entryPoint07Address,
version: "0.7"
}
});
const smartAccountClient = createSmartAccountClient({
account: safeAccount, // Para-enabled Safe account
chain: CHAIN,
bundlerTransport: http(PIMLICO_URL),
paymaster: pimlicoClient, // ← Enables gas sponsorship
userOperation: {
estimateFeesPerGas: async () => {
return (await pimlicoClient.getUserOperationGasPrice()).fast
}
}
});
// Gas is automatically sponsored via the paymaster
const userOpHash = await smartAccountClient.sendUserOperation({
calls: [{
to: "0x...", // Recipient address
value: 0n, // ETH value to send
data: "0x" // Transaction data
}]
});
// Wait for the transaction to be mined
const receipt = await smartAccountClient.waitForUserOperationReceipt({
hash: userOpHash
});
```
```typescript
import { smartWallet } from "thirdweb/wallets";
import { sendTransaction } from "thirdweb";
// Gas sponsorship is enabled via the sponsorGas flag
const smartWalletConfig = smartWallet({
chain: CHAIN,
sponsorGas: true, // ← Enables gas sponsorship
factoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_7,
overrides: {
accountSalt: salt,
},
});
// Connect the smart wallet with Para as the signer
const smartAccount = await smartWalletConfig.connect({
client: thirdwebClient,
personalAccount, // Para-enabled personal account
});
// Gas is automatically sponsored when sponsorGas is enabled
const transaction = {
chain: CHAIN,
client: thirdwebClient,
to: "0x...", // Recipient address
value: 0n, // ETH value to send
data: "0x" // Transaction data
};
const result = await sendTransaction({
transaction,
account: smartAccount // Uses the sponsored smart wallet
});
console.log("Sponsored transaction mined:", result.transactionHash);
```
```typescript
import { createKernelAccountClient, createZeroDevPaymasterClient } from "@zerodevapp/sdk";
import { http } from "viem";
// ZeroDev automatically sponsors gas when using their bundler URL
const kernelClient = createKernelAccountClient({
account: kernelAccount, // Para-enabled kernel account
chain: CHAIN,
transport: http(
`https://rpc.zerodev.app/api/v2/bundler/${ZERODEV_PROJECT_ID}`
), // ← Bundler URL includes sponsorship
});
// Optional: For explicit paymaster configuration
const paymasterClient = createZeroDevPaymasterClient({
chain: CHAIN,
transport: http(
`https://rpc.zerodev.app/api/v2/paymaster/${ZERODEV_PROJECT_ID}`
)
});
// Gas is automatically sponsored via the ZeroDev infrastructure
const userOpHash = await kernelClient.sendUserOperation({
callData: await kernelAccount.encodeCalls([{
to: "0x...", // Recipient address
value: 0n, // ETH value to send
data: "0x" // Transaction data
}])
});
// Wait for the transaction to be mined
const receipt = await kernelClient.waitForUserOperationReceipt({
hash: userOpHash
});
```
## Key Points
* **Gas sponsorship is configured during client setup** - Each provider has a specific parameter or configuration that enables sponsorship (policyId, paymasterUrl, apiKey, etc.)
* **Transactions are automatically sponsored** - Once configured, transactions sent through the smart account client will have their gas fees covered
* **No ETH required in user wallets** - Users can interact with your dApp without holding ETH for gas fees
* **Provider-specific limits may apply** - Check your provider's dashboard for sponsorship limits and policies
* **Smart Wallet Deployment** - Providers automatically handle smart wallet deployment if the account does not exist on first transaction
# Verify Signatures with EVM Libraries
Source: https://docs.getpara.com/v2/react/guides/web3-operations/evm/verify-signatures
Verify message and transaction signatures using Ethers, Viem, or Wagmi
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Verify the authenticity of signed messages and typed data to ensure they originated from the expected address.
## Prerequisites
You need Web3 libraries configured with Para authentication.
## Verify Personal Signatures
```typescript
import { ethers } from "ethers";
async function verifyPersonalSignature(
message: string,
signature: string,
signerAddress: string
) {
const recoveredAddress = ethers.verifyMessage(message, signature);
const isValid = recoveredAddress.toLowerCase() === signerAddress.toLowerCase();
console.log("Signature valid:", isValid);
return isValid;
}
```
```typescript
import { verifyMessage } from "viem";
async function verifyPersonalSignature(
address: `0x${string}`,
message: string,
signature: `0x${string}`
) {
const isValid = await verifyMessage({
address,
message,
signature,
});
console.log("Signature valid:", isValid);
return isValid;
}
```
```typescript
import { useVerifyMessage } from "wagmi";
function VerifyPersonalSignature({
address,
message,
signature,
}: {
address: `0x${string}`;
message: string;
signature: `0x${string}`;
}) {
const { data: isValid, isLoading } = useVerifyMessage({
address,
message,
signature,
});
if (isLoading) return Verifying signature...
;
return Signature valid: {isValid ? "Yes" : "No"}
;
}
```
## Verify Typed Data Signatures (EIP-712)
```typescript
import { ethers } from "ethers";
async function verifyTypedDataSignature(
domain: any,
types: any,
value: any,
signature: string,
signerAddress: string
) {
const recoveredAddress = ethers.verifyTypedData(domain, types, value, signature);
const isValid = recoveredAddress.toLowerCase() === signerAddress.toLowerCase();
console.log("Signature valid:", isValid);
return isValid;
}
```
```typescript
import { verifyTypedData } from "viem";
async function verifyTypedDataSignature(
address: `0x${string}`,
domain: any,
types: any,
primaryType: string,
message: any,
signature: `0x${string}`
) {
const isValid = await verifyTypedData({
address,
domain,
types,
primaryType,
message,
signature,
});
console.log("Signature valid:", isValid);
return isValid;
}
```
```typescript
import { useVerifyTypedData } from "wagmi";
function VerifyTypedDataSignature({
address,
domain,
types,
primaryType,
message,
signature,
}: {
address: `0x${string}`;
domain: any;
types: any;
primaryType: string;
message: any;
signature: `0x${string}`;
}) {
const { data: isValid, isLoading } = useVerifyTypedData({
address,
domain,
types,
primaryType,
message,
signature,
});
if (isLoading) return Verifying typed data signature...
;
return Typed Data Signature valid: {isValid ? "Yes" : "No"}
;
}
```
## Next Steps
# Watch Contract Events
Source: https://docs.getpara.com/v2/react/guides/web3-operations/evm/watch-events
Listen to smart contract events and parse event logs in real-time
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Subscribe to and filter smart contract events to react to on-chain activity in real-time.
## Prerequisites
You need Web3 libraries configured with Para authentication.
## Watch Contract Events
```typescript
import { ethers } from "ethers";
const ERC20_ABI = [
"event Transfer(address indexed from, address indexed to, uint256 value)"
];
async function watchTransferEvents(
provider: ethers.Provider,
tokenAddress: string
) {
const contract = new ethers.Contract(
tokenAddress,
ERC20_ABI,
provider
);
contract.on("Transfer", (from, to, value, event) => {
console.log(`Transfer Event: ${from} -> ${to}, Value: ${ethers.formatUnits(value, 18)}`);
console.log("Event details:", event);
});
console.log(`Listening for Transfer events on ${tokenAddress}...`);
}
async function stopWatchingTransferEvents(
provider: ethers.Provider,
tokenAddress: string
) {
const contract = new ethers.Contract(
tokenAddress,
ERC20_ABI,
provider
);
contract.off("Transfer");
console.log(`Stopped listening for Transfer events on ${tokenAddress}.`);
}
```
```typescript
import { createPublicClient, http } from "viem";
import { mainnet } from "viem/chains";
const ERC20_ABI = [
{
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",
},
] as const;
async function watchTransferEvents(
publicClient: any,
tokenAddress: `0x${string}`
) {
const unwatch = publicClient.watchContractEvent({
address: tokenAddress,
abi: ERC20_ABI,
eventName: "Transfer",
onLogs: (logs) => {
for (const log of logs) {
console.log(`Transfer Event: ${log.args.from} -> ${log.args.to}, Value: ${log.args.value}`);
console.log("Log details:", log);
}
},
});
console.log(`Listening for Transfer events on ${tokenAddress}...`);
return unwatch; // Return the unwatch function to stop listening later
}
```
```typescript
import { useWatchContractEvent } from "wagmi";
const ERC20_ABI = [
{
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",
},
] as const;
function WatchTransferEvents({ tokenAddress }: { tokenAddress: `0x${string}` }) {
useWatchContractEvent({
address: tokenAddress,
abi: ERC20_ABI,
eventName: "Transfer",
onLogs: (logs) => {
for (const log of logs) {
console.log(`Transfer Event: ${log.args.from} -> ${log.args.to}, Value: ${log.args.value}`);
console.log("Log details:", log);
}
},
});
return Listening for Transfer events on {tokenAddress}...
;
}
```
## Next Steps
# Get Wallet Data
Source: https://docs.getpara.com/v2/react/guides/web3-operations/get-wallet-address
Access wallet addresses and information using Para React hooks
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
## Get Current Wallet
Use the `useWallet` hook to access the currently selected wallet in the `ParaModal`.
```tsx
import { useWallet } from '@getpara/react-sdk';
export default function CurrentWallet() {
const { data: wallet } = useWallet();
if (!wallet) return No wallet connected
;
return (
Address: {wallet.address}
Type: {wallet.scheme}
ID: {wallet.id}
);
}
```
## Get All Wallets
Use the `useAccount` hook to access all user wallets for both embedded and external types.
```tsx
import { useAccount } from '@getpara/react-sdk';
export default function AllWallets() {
const { embedded, external } = useAccount();
// Get all embedded wallets
const wallets = embedded.wallets; // Record
const walletList = Object.values(wallets);
return (
{walletList.map((wallet) => (
{wallet.scheme}: {wallet.address}
))}
);
}
```
## Filter Wallets by Type
Access wallets filtered by blockchain type using the Para client.
```tsx
import { useClient } from '@getpara/react-sdk';
export default function WalletsByType() {
// useClient hook to access Para client
const para = useClient();
// Get wallets by type
const evmWallets = para.getWalletsByType('EVM');
const solanaWallets = para.getWalletsByType('SOLANA');
const cosmosWallets = para.getWalletsByType('COSMOS');
}
```
## Wallet Properties
Each wallet object for embedded wallets has the following properties:
## Next Steps
# Query Wallet Balance with Para
Source: https://docs.getpara.com/v2/react/guides/web3-operations/query-wallet-balance
Get wallet balances directly using Para's built-in balance methods
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
Para provides a simple React hook to query the native balance of a wallet. This is useful for checking available funds before performing transactions.
### useWalletBalance
",
description: "React Query result with balance as a string in wei/smallest unit"
}}
/>
### Basic Usage
```tsx
import { useWalletBalance } from '@getpara/react-sdk';
const { data: balance, isLoading, error } = useWalletBalance();
// Balance is returned as a string in wei (for EVM)
console.log(balance); // "1000000000000000000" (1 ETH in wei)
```
### Query Specific Wallet
```tsx
import { useWalletBalance } from '@getpara/react-sdk';
const { data: balance } = useWalletBalance({
walletId: 'wallet_123'
});
console.log(balance); // Balance in wei
```
### External Wallet with RPC
```tsx
import { useWalletBalance } from '@getpara/react-sdk';
const { data: balance } = useWalletBalance({
walletId: 'external_wallet_id',
rpcUrl: 'https://mainnet.infura.io/v3/YOUR_KEY'
});
console.log(balance); // Balance from external RPC
```
## Important Notes
* **EVM only**: Currently only supports EVM wallets. Returns `null` for COSMOS and SOLANA wallets
* **Native balance only**: Does not support token balances
* **Wei format**: Returns balance as a string in wei (smallest unit)
* **No formatting**: Returns raw balance value without formatting or symbol information
## Next Steps
Work directly with popular blockchain libraries for a more comprehensive approach to wallet interactions.
# Sign Messages with Para
Source: https://docs.getpara.com/v2/react/guides/web3-operations/sign-with-para
Learn how to sign a "Hello, Para!" message using the Para SDK
export const LinkListCard = ({imgUrl, title, links = [], horizontal = false, newTab = false}) => {
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
return
{imgUrl &&
}
{title &&
{title} }
{links.length > 0 &&
{links.map((link, index) => )}
}
;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
The `signMessage` method is a **low-level API** that signs raw bytes directly without any modifications. This is useful for verifying your Para integration with a simple "Hello, Para!" test after initial setup and authentication.
**Important:** `signMessage` signs raw bytes without standard modifications like EIP-191 message prefixes that libraries like Ethers and Viem automatically add. For production use, always use proper Web3 libraries that handle message formatting, encoding standards, and chain-specific requirements.
### Message Signing
This method signs the exact bytes you provide - perfect for initial "hello world" testing:
",
description: "React Query mutation result with signMessage function"
}}
/>
```tsx SignMessageExample.tsx
import { useSignMessage, useWallet } from '@getpara/react-sdk';
export default function SignMessageExample() {
const { mutateAsync: signMessageAsync } = useSignMessage();
const { data: wallet } = useWallet();
const handleSign = async () => {
if (!wallet) return;
const message = "Hello, Para!";
// Encode message to base64
const messageBase64 = btoa(message);
const result = await signMessageAsync({
walletId: wallet.id,
messageBase64
});
console.log('Signature result:', result);
};
return (
Sign Message
);
}
```
**When to use signMessage:** This method is best suited for signing simple text messages and basic authentication flows. For complex operations like transactions, typed data (EIP-712), or chain-specific functionality, **you should use the appropriate Web3 library** (Viem, Ethers, Solana Web3.js, CosmJS) as shown in the Next Steps below. These libraries provide proper encoding, type safety, and chain-specific features that signMessage alone cannot offer.
## Next Steps
Now that you've successfully verified your Para setup with a simple message signature, it's time to move on to more advanced operations. Depending on your target blockchain, you can explore the following libraries that integrate seamlessly with Para for signing transactions, typed data, and more:
# Set Compute Units and Priority Fees
Source: https://docs.getpara.com/v2/react/guides/web3-operations/solana/compute-units
Configure compute budget and priority fees for Solana transactions
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Optimize your Solana transactions by setting compute unit limits and priority fees. This helps ensure transactions succeed during network congestion and controls execution costs.
```typescript
import { useParaSolana } from './hooks/useParaSolana';
import {
Transaction,
SystemProgram,
LAMPORTS_PER_SOL,
PublicKey,
ComputeBudgetProgram
} from '@solana/web3.js';
function ComputeUnitsExample() {
const { connection, signer } = useParaSolana();
const sendWithPriorityFee = async () => {
const recipient = new PublicKey("RECIPIENT_ADDRESS");
// Get recent prioritization fees
const recentFees = await connection.getRecentPrioritizationFees();
const avgFee = recentFees.reduce((sum, fee) => sum + fee.prioritizationFee, 0) / recentFees.length;
const priorityFee = Math.ceil(avgFee * 1.2); // 20% above average
const transaction = new Transaction()
.add(
// Set compute unit limit
ComputeBudgetProgram.setComputeUnitLimit({
units: 200000, // Adjust based on your transaction needs
})
)
.add(
// Set priority fee
ComputeBudgetProgram.setComputeUnitPrice({
microLamports: priorityFee,
})
)
.add(
// Your actual transaction instruction
SystemProgram.transfer({
fromPubkey: signer.sender,
toPubkey: recipient,
lamports: LAMPORTS_PER_SOL * 0.1,
})
);
try {
const signature = await signer.sendTransaction(transaction, {
skipPreflight: false,
maxRetries: 3,
});
console.log("Transaction sent with priority fee:", signature);
console.log("Priority fee used:", priorityFee, "microLamports");
const confirmation = await connection.confirmTransaction(signature, "confirmed");
console.log("Transaction confirmed:", confirmation);
} catch (error) {
console.error("Transaction failed:", error);
}
};
return Send with Priority Fee ;
}
```
```typescript
import { useParaSolanaV2 } from './hooks/useParaSolanaV2';
import {
pipe,
createTransactionMessage,
setTransactionMessageFeePayer,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstruction,
getSystemInstruction,
getSetComputeUnitLimitInstruction,
getSetComputeUnitPriceInstruction,
address,
lamports
} from '@solana/web3.js';
function ComputeUnitsExample() {
const { rpc, signer } = useParaSolanaV2();
const sendWithPriorityFee = async () => {
const recipient = address("RECIPIENT_ADDRESS");
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
// Get recent prioritization fees
const { value: recentFees } = await rpc.getRecentPrioritizationFees().send();
const avgFee = recentFees.reduce((sum, fee) => sum + fee.prioritizationFee, 0n) / BigInt(recentFees.length);
const priorityFee = (avgFee * 120n) / 100n; // 20% above average
const transaction = pipe(
createTransactionMessage({ version: 0 }),
tx => setTransactionMessageFeePayer(signer.address, tx),
tx => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
tx => appendTransactionMessageInstruction(
getSetComputeUnitLimitInstruction({
units: 200000,
}),
tx
),
tx => appendTransactionMessageInstruction(
getSetComputeUnitPriceInstruction({
microLamports: priorityFee,
}),
tx
),
tx => appendTransactionMessageInstruction(
getSystemInstruction({
amount: lamports(100_000_000n),
destination: recipient,
source: signer.address,
}),
tx
)
);
try {
const [signature] = await signer.signAndSendTransactions([transaction]);
console.log("Transaction sent with priority fee:", signature);
console.log("Priority fee used:", priorityFee.toString(), "microLamports");
const status = await rpc.getSignatureStatuses([signature]).send();
console.log("Transaction status:", status);
} catch (error) {
console.error("Transaction failed:", error);
}
};
return Send with Priority Fee ;
}
```
```typescript
import { useParaAnchor } from './hooks/useParaAnchor';
import {
Transaction,
SystemProgram,
LAMPORTS_PER_SOL,
PublicKey,
ComputeBudgetProgram
} from '@solana/web3.js';
import * as anchor from '@project-serum/anchor';
function ComputeUnitsExample() {
const provider = useParaAnchor();
const sendWithPriorityFee = async () => {
const program = new anchor.Program(idl, provider);
// Get recent prioritization fees
const recentFees = await provider.connection.getRecentPrioritizationFees();
const avgFee = recentFees.reduce((sum, fee) => sum + fee.prioritizationFee, 0) / recentFees.length;
const priorityFee = Math.ceil(avgFee * 1.2);
// Create the main instruction
const ix = await program.methods
.someMethod()
.accounts({
user: provider.publicKey,
// ... other accounts
})
.instruction();
// Build transaction with compute budget instructions
const transaction = new Transaction()
.add(
ComputeBudgetProgram.setComputeUnitLimit({
units: 300000, // Higher for complex program calls
})
)
.add(
ComputeBudgetProgram.setComputeUnitPrice({
microLamports: priorityFee,
})
)
.add(ix);
try {
const signature = await provider.sendAndConfirm(transaction);
console.log("Transaction sent with priority fee:", signature);
console.log("Priority fee used:", priorityFee, "microLamports");
} catch (error) {
console.error("Transaction failed:", error);
}
};
return Execute with Priority ;
}
```
## Next Steps
# Configure RPC Endpoints with Solana Libraries
Source: https://docs.getpara.com/v2/react/guides/web3-operations/solana/configure-rpc
Set up and configure Solana RPC endpoints and connections using Web3.js or Anchor
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Configure custom RPC endpoints for Solana to optimize performance, use private nodes, or connect to different networks. This guide covers RPC setup for all supported libraries.
```typescript
import { ParaSolanaWeb3Signer } from '@getpara/solana-web3.js-v1-integration@alpha';
import { Connection, clusterApiUrl, Commitment } from '@solana/web3.js';
import { para } from './para';
function useCustomRPC() {
// Using Solana public RPC endpoints
const mainnetConnection = new Connection(
clusterApiUrl('mainnet-beta'),
'confirmed'
);
const devnetConnection = new Connection(
clusterApiUrl('devnet'),
'confirmed'
);
// Using custom RPC endpoint (e.g., QuickNode, Alchemy, Helius)
const customConnection = new Connection(
'https://your-custom-rpc-endpoint.com',
{
commitment: 'confirmed',
wsEndpoint: 'wss://your-custom-websocket-endpoint.com',
httpHeaders: {
'Authorization': 'Bearer YOUR_API_KEY',
},
disableRetryOnRateLimit: false,
confirmTransactionInitialTimeout: 30000,
}
);
// Create signers with different connections
const mainnetSigner = new ParaSolanaWeb3Signer(para, mainnetConnection);
const devnetSigner = new ParaSolanaWeb3Signer(para, devnetConnection);
const customSigner = new ParaSolanaWeb3Signer(para, customConnection);
// Example: Get network performance metrics
const checkPerformance = async () => {
const start = Date.now();
const slot = await customConnection.getSlot();
const latency = Date.now() - start;
console.log('Current slot:', slot);
console.log('RPC latency:', latency, 'ms');
const perfSamples = await customConnection.getRecentPerformanceSamples(5);
console.log('Recent performance:', perfSamples);
};
return { mainnetSigner, devnetSigner, customSigner, checkPerformance };
}
```
```typescript
import { createParaSolanaSigner } from '@getpara/solana-signers-v2-integration';
import { createSolanaRpc, createSolanaRpcSubscriptions } from '@solana/web3.js';
import { para } from './para';
function useCustomRPC() {
// Mainnet RPC
const mainnetRpc = createSolanaRpc('https://api.mainnet-beta.solana.com');
const mainnetRpcSubscriptions = createSolanaRpcSubscriptions('wss://api.mainnet-beta.solana.com');
// Devnet RPC
const devnetRpc = createSolanaRpc('https://api.devnet.solana.com');
// Custom RPC with authentication
const customRpc = createSolanaRpc('https://your-custom-rpc-endpoint.com', {
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
},
});
// Create signers with different RPC connections
const mainnetSigner = createParaSolanaSigner({ para, rpc: mainnetRpc });
const devnetSigner = createParaSolanaSigner({ para, rpc: devnetRpc });
const customSigner = createParaSolanaSigner({ para, rpc: customRpc });
// Example: Monitor slot updates via WebSocket
const monitorSlots = async () => {
const slotNotifications = await mainnetRpcSubscriptions
.slotNotifications()
.subscribe();
for await (const notification of slotNotifications) {
console.log('New slot:', notification.slot);
console.log('Parent:', notification.parent);
console.log('Root:', notification.root);
}
};
// Example: Get RPC health
const checkHealth = async () => {
const health = await customRpc.getHealth().send();
console.log('RPC health:', health);
const version = await customRpc.getVersion().send();
console.log('RPC version:', version);
};
return { mainnetSigner, devnetSigner, customSigner, monitorSlots, checkHealth };
}
```
```typescript
import { ParaSolanaWeb3Signer } from '@getpara/solana-web3.js-v1-integration@alpha';
import { Connection, Transaction, VersionedTransaction } from '@solana/web3.js';
import * as anchor from '@project-serum/anchor';
import { para } from './para';
function useCustomAnchorProvider() {
// Configure connection with custom options
const connection = new Connection(
'https://your-custom-rpc-endpoint.com',
{
commitment: 'confirmed',
wsEndpoint: 'wss://your-custom-websocket-endpoint.com',
httpHeaders: {
'Authorization': 'Bearer YOUR_API_KEY',
},
}
);
const signer = new ParaSolanaWeb3Signer(para, connection);
// Create Anchor wallet adapter
const wallet = {
publicKey: signer.sender,
signTransaction: async (tx: T): Promise => {
return await signer.signTransaction(tx);
},
signAllTransactions: async (txs: T[]): Promise => {
return await Promise.all(txs.map((tx) => signer.signTransaction(tx)));
},
};
// Create provider with custom options
const provider = new anchor.AnchorProvider(
connection,
wallet,
{
commitment: 'confirmed',
preflightCommitment: 'confirmed',
skipPreflight: false,
}
);
// Set as default provider
anchor.setProvider(provider);
// Example: Test connection
const testConnection = async () => {
const blockHeight = await connection.getBlockHeight();
console.log('Current block height:', blockHeight);
const epoch = await connection.getEpochInfo();
console.log('Epoch info:', epoch);
const supply = await connection.getSupply();
console.log('Total supply:', supply);
};
return { provider, testConnection };
}
```
## Next Steps
# Execute Transactions with Solana Libraries
Source: https://docs.getpara.com/v2/react/guides/web3-operations/solana/execute-transactions
Interact with Solana programs and execute complex transactions using Web3.js or Anchor
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Execute transactions on the Solana blockchain using Para's integrated signers. This includes signing and broadcasting transactions to the network.
```typescript
import { useParaSolana } from './hooks/useParaSolana';
import { Transaction, SystemProgram, LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js';
function SendTransaction() {
const { connection, signer } = useParaSolana();
const sendSOL = async () => {
if (!signer) {
console.error("No signer available. Connect wallet first.");
return;
}
const recipient = new PublicKey("RECIPIENT_ADDRESS_HERE");
const transaction = new Transaction().add(
SystemProgram.transfer({
fromPubkey: signer.sender,
toPubkey: recipient,
lamports: LAMPORTS_PER_SOL * 0.1,
})
);
try {
const signature = await signer.sendTransaction(transaction, {
skipPreflight: false,
preflightCommitment: "confirmed",
});
console.log("Transaction signature:", signature);
const confirmation = await connection.confirmTransaction(signature, "confirmed");
console.log("Transaction confirmed:", confirmation);
} catch (error) {
console.error("Transaction failed:", error);
}
};
return Send 0.1 SOL ;
}
```
```typescript
import { useParaSolanaKit } from './hooks/useParaSolanaKit';
import { Transaction, SystemProgram, LAMPORTS_PER_SOL } from '@solana/kit';
function SendTransaction() {
const { rpc, signer } = useParaSolanaKit();
const sendSOL = async () => {
if (!signer) {
console.error("No signer available. Connect wallet first.");
return;
}
const recipient = "RECIPIENT_ADDRESS_HERE";
const transaction = new Transaction().add(
SystemProgram.transfer({
fromPubkey: signer.sender,
toPubkey: recipient,
lamports: LAMPORTS_PER_SOL * 0.1,
})
);
const signatures = await signer.signAndSendTransactions([transaction]);
const signature = signatures[0];
console.log("Transaction signature:", signature);
const latestBlockhash = await rpc.getLatestBlockhash();
await rpc.confirmTransaction({
signature,
blockhash: latestBlockhash.value.blockhash,
lastValidBlockHeight: latestBlockhash.value.lastValidBlockHeight
});
console.log("Transaction confirmed");
};
return Send 0.1 SOL ;
}
```
```typescript
import { useParaAnchor } from './hooks/useParaAnchor';
import * as anchor from '@project-serum/anchor';
import { SystemProgram, LAMPORTS_PER_SOL } from '@solana/web3.js';
function AnchorTransaction() {
const provider = useParaAnchor();
const executeProgram = async () => {
if (provider.wallet.publicKey.equals(SystemProgram.programId)) {
console.error("No wallet connected. Please authenticate first.");
return;
}
const program = new anchor.Program(idl, provider);
try {
const tx = await program.methods
.initialize()
.accounts({
user: provider.publicKey,
systemProgram: SystemProgram.programId,
})
.rpc();
console.log("Transaction signature:", tx);
const confirmation = await provider.connection.confirmTransaction(tx, "confirmed");
console.log("Transaction confirmed:", confirmation);
} catch (error) {
console.error("Transaction failed:", error);
}
};
return Execute Program ;
}
```
## Next Steps
# Get Solana Transaction Status
Source: https://docs.getpara.com/v2/react/guides/web3-operations/solana/get-transaction-status
Check transaction confirmation status and finality on Solana
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Monitor transaction confirmation status and wait for finality on Solana. This guide covers checking transaction results and understanding commitment levels.
```typescript
import { useParaSolana } from './hooks/useParaSolana';
import { TransactionSignature, Commitment } from '@solana/web3.js';
function TransactionStatus() {
const { connection } = useParaSolana();
const checkTransactionStatus = async (signature: string) => {
try {
// Get signature status
const status = await connection.getSignatureStatus(signature);
if (status.value === null) {
console.log("Transaction not found");
return null;
}
console.log("Confirmations:", status.value.confirmations || "Max (32+)");
console.log("Confirmation status:", status.value.confirmationStatus);
console.log("Slot:", status.value.slot);
if (status.value.err) {
console.error("Transaction failed:", status.value.err);
return false;
}
return status.value.confirmationStatus;
} catch (error) {
console.error("Error checking status:", error);
throw error;
}
};
const waitForConfirmation = async (
signature: string,
commitment: Commitment = 'confirmed'
) => {
try {
const startTime = Date.now();
// Wait for confirmation with timeout
const confirmation = await connection.confirmTransaction(
signature,
commitment
);
const elapsed = Date.now() - startTime;
console.log(`Transaction confirmed in ${elapsed}ms`);
if (confirmation.value.err) {
throw new Error(`Transaction failed: ${confirmation.value.err}`);
}
// Get detailed transaction info
const txInfo = await connection.getTransaction(signature, {
commitment,
maxSupportedTransactionVersion: 0,
});
if (txInfo) {
console.log("Block time:", new Date(txInfo.blockTime! * 1000));
console.log("Fee:", txInfo.meta?.fee, "lamports");
console.log("Compute units consumed:", txInfo.meta?.computeUnitsConsumed);
}
return txInfo;
} catch (error) {
console.error("Confirmation error:", error);
throw error;
}
};
return (
checkTransactionStatus("YOUR_SIGNATURE")}>
Check Status
waitForConfirmation("YOUR_SIGNATURE", "finalized")}>
Wait for Finalization
);
}
```
```typescript
import { useParaSolanaV2 } from './hooks/useParaSolanaV2';
import { Signature, Commitment } from '@solana/web3.js';
function TransactionStatus() {
const { rpc } = useParaSolanaV2();
const checkTransactionStatus = async (signature: Signature) => {
try {
// Get multiple signature statuses
const { value: statuses } = await rpc
.getSignatureStatuses([signature])
.send();
const status = statuses[0];
if (!status) {
console.log("Transaction not found");
return null;
}
console.log("Confirmations:", status.confirmations || "Max (32+)");
console.log("Confirmation status:", status.confirmationStatus);
console.log("Slot:", status.slot);
if (status.err) {
console.error("Transaction failed:", status.err);
return false;
}
return status;
} catch (error) {
console.error("Error checking status:", error);
throw error;
}
};
const waitForConfirmation = async (
signature: Signature,
commitment: Commitment = 'confirmed'
) => {
try {
const startTime = Date.now();
// Poll for confirmation
let confirmed = false;
while (!confirmed) {
const { value: statuses } = await rpc
.getSignatureStatuses([signature])
.send();
const status = statuses[0];
if (status?.confirmationStatus === commitment ||
status?.confirmationStatus === 'finalized') {
confirmed = true;
if (status.err) {
throw new Error(`Transaction failed: ${JSON.stringify(status.err)}`);
}
}
// Wait before next poll
if (!confirmed) {
await new Promise(resolve => setTimeout(resolve, 1000));
}
// Timeout after 30 seconds
if (Date.now() - startTime > 30000) {
throw new Error('Transaction confirmation timeout');
}
}
const elapsed = Date.now() - startTime;
console.log(`Transaction confirmed in ${elapsed}ms`);
// Get transaction details
const { value: txInfo } = await rpc
.getTransaction(signature, {
commitment,
maxSupportedTransactionVersion: 0,
})
.send();
if (txInfo) {
console.log("Block time:", new Date(txInfo.blockTime * 1000));
console.log("Fee:", txInfo.meta.fee, "lamports");
console.log("Compute units:", txInfo.meta.computeUnitsConsumed);
}
return txInfo;
} catch (error) {
console.error("Confirmation error:", error);
throw error;
}
};
return (
checkTransactionStatus("YOUR_SIGNATURE" as Signature)}>
Check Status
waitForConfirmation("YOUR_SIGNATURE" as Signature, "finalized")}>
Wait for Finalization
);
}
```
```typescript
import { useParaAnchor } from './hooks/useParaAnchor';
import { TransactionSignature, Commitment } from '@solana/web3.js';
function TransactionStatus() {
const provider = useParaAnchor();
const checkTransactionStatus = async (signature: string) => {
try {
const status = await provider.connection.getSignatureStatus(signature);
if (status.value === null) {
console.log("Transaction not found");
return null;
}
console.log("Status:", status.value);
// For Anchor program errors, decode the logs
if (status.value.err) {
const tx = await provider.connection.getTransaction(signature, {
commitment: 'confirmed',
});
if (tx?.meta?.logMessages) {
console.log("Transaction logs:");
tx.meta.logMessages.forEach(log => console.log(log));
// Parse Anchor errors from logs
const anchorError = tx.meta.logMessages.find(log =>
log.includes('Program log: AnchorError')
);
if (anchorError) {
console.error("Anchor error found:", anchorError);
}
}
return false;
}
return status.value.confirmationStatus;
} catch (error) {
console.error("Error checking status:", error);
throw error;
}
};
const waitForAnchorTransaction = async (
signature: string,
commitment: Commitment = 'confirmed'
) => {
try {
// Use provider's built-in confirmation
await provider.connection.confirmTransaction(signature, commitment);
// Get parsed transaction
const tx = await provider.connection.getParsedTransaction(signature, {
commitment,
maxSupportedTransactionVersion: 0,
});
if (!tx) {
throw new Error('Transaction not found');
}
if (tx.meta?.err) {
// Extract error details
console.error("Transaction error:", tx.meta.err);
if (tx.meta.logMessages) {
console.log("Error logs:");
tx.meta.logMessages.forEach(log => console.log(log));
}
throw new Error('Transaction failed');
}
console.log("Transaction successful");
console.log("Fee:", tx.meta?.fee, "lamports");
console.log("Compute units:", tx.meta?.computeUnitsConsumed);
return tx;
} catch (error) {
console.error("Confirmation error:", error);
throw error;
}
};
return (
checkTransactionStatus("YOUR_SIGNATURE")}>
Check Status
waitForAnchorTransaction("YOUR_SIGNATURE", "finalized")}>
Wait for Finalization
);
}
```
## Next Steps
# Interact with Solana Programs
Source: https://docs.getpara.com/v2/react/guides/web3-operations/solana/interact-with-programs
Call program instructions and work with Anchor IDLs using Para
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Interact with Solana programs by calling instructions and working with Anchor IDLs. This guide covers manual instruction creation and Anchor's type-safe program interaction.
```typescript
import { useParaSolana } from './hooks/useParaSolana';
import { Transaction, TransactionInstruction, PublicKey, SystemProgram } from '@solana/web3.js';
import { Buffer } from 'buffer';
function InteractWithProgram() {
const { connection, signer } = useParaSolana();
const callProgram = async () => {
const programId = new PublicKey("YOUR_PROGRAM_ID");
// Example: Initialize account with custom data
const [pda] = PublicKey.findProgramAddressSync(
[Buffer.from("seed"), signer.sender.toBuffer()],
programId
);
// Create instruction data (program-specific)
const instructionData = Buffer.alloc(9);
instructionData.writeUInt8(0, 0); // Instruction index
instructionData.writeBigUInt64LE(BigInt(1000), 1); // Example parameter
const instruction = new TransactionInstruction({
keys: [
{ pubkey: signer.sender, isSigner: true, isWritable: true },
{ pubkey: pda, isSigner: false, isWritable: true },
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
],
programId,
data: instructionData,
});
const transaction = new Transaction().add(instruction);
try {
const signature = await signer.sendTransaction(transaction);
console.log("Program call signature:", signature);
const confirmation = await connection.confirmTransaction(signature, "confirmed");
console.log("Transaction confirmed:", confirmation);
} catch (error) {
console.error("Program call failed:", error);
}
};
return Call Program ;
}
```
```typescript
import { useParaSolanaKit } from './hooks/useParaSolanaKit';
import { PublicKey, SystemProgram, TransactionInstruction } from '@solana/web3.js';
import {
createTransactionMessage,
setTransactionMessageFeePayerSigner,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstructions,
signTransactionMessageWithSigners,
pipe,
} from '@solana/kit';
import { Buffer } from 'buffer';
function InteractWithProgram() {
const { rpc, signer } = useParaSolanaKit();
const callProgram = async () => {
if (!signer) {
console.error("No signer available. Connect wallet first.");
return;
}
const programId = new PublicKey("YOUR_PROGRAM_ID");
// Example: Initialize account with custom data
const [pda] = PublicKey.findProgramAddressSync(
[Buffer.from("seed"), signer.publicKey.toBuffer()],
programId
);
// Create instruction data (program-specific)
const instructionData = Buffer.alloc(9);
instructionData.writeUInt8(0, 0); // Instruction index
instructionData.writeBigUInt64LE(BigInt(1000), 1); // Example parameter
const instruction = new TransactionInstruction({
keys: [
{ pubkey: signer.publicKey, isSigner: true, isWritable: true },
{ pubkey: pda, isSigner: false, isWritable: true },
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
],
programId,
data: instructionData,
});
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
const transactionMessage = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayerSigner(signer.publicKey, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
(tx) => appendTransactionMessageInstructions([instruction], tx)
);
const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);
const signature = await rpc.sendTransaction(signedTransaction).send();
console.log("Program call signature:", signature);
await rpc.confirmTransaction({
signature,
blockhash: latestBlockhash.blockhash,
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight
});
console.log("Transaction confirmed");
};
return Call Program ;
}
```
```typescript
import { useParaAnchor } from './hooks/useParaAnchor';
import * as anchor from '@project-serum/anchor';
import { SystemProgram } from '@solana/web3.js';
import idl from './idl.json';
function InteractWithAnchorProgram() {
const provider = useParaAnchor();
const callAnchorProgram = async () => {
// Initialize program with IDL
const program = new anchor.Program(idl as any, provider);
// Generate keypair for new account
const newAccount = anchor.web3.Keypair.generate();
try {
// Example: Initialize an account
const tx = await program.methods
.initialize(new anchor.BN(1000))
.accounts({
user: provider.wallet.publicKey,
dataAccount: newAccount.publicKey,
systemProgram: SystemProgram.programId,
})
.signers([newAccount])
.rpc();
console.log("Transaction signature:", tx);
// Fetch account data
const account = await program.account.dataAccount.fetch(newAccount.publicKey);
console.log("Account data:", account);
// Example: Update the account
const updateTx = await program.methods
.update(new anchor.BN(2000))
.accounts({
user: provider.wallet.publicKey,
dataAccount: newAccount.publicKey,
})
.rpc();
console.log("Update transaction:", updateTx);
} catch (error) {
console.error("Anchor program call failed:", error);
}
};
return Call Anchor Program ;
}
```
## Next Steps
# Manage SPL Token Accounts
Source: https://docs.getpara.com/v2/react/guides/web3-operations/solana/manage-token-accounts
Create, close, and manage SPL token accounts on Solana
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Create and manage SPL token accounts for holding tokens on Solana. This includes creating Associated Token Accounts (ATAs) and closing empty accounts to reclaim SOL.
```typescript
import { useParaSolana } from './hooks/useParaSolana';
import { Transaction, PublicKey } from '@solana/web3.js';
import {
createAssociatedTokenAccountInstruction,
getAssociatedTokenAddress,
createCloseAccountInstruction,
TOKEN_PROGRAM_ID,
ASSOCIATED_TOKEN_PROGRAM_ID
} from '@solana/spl-token';
function ManageTokenAccounts() {
const { connection, signer } = useParaSolana();
const createTokenAccount = async (mint: string, owner?: string) => {
const mintPubkey = new PublicKey(mint);
const ownerPubkey = owner ? new PublicKey(owner) : signer.sender;
const ata = await getAssociatedTokenAddress(mintPubkey, ownerPubkey);
const accountInfo = await connection.getAccountInfo(ata);
if (accountInfo) {
console.log("Token account already exists:", ata.toString());
return ata;
}
const transaction = new Transaction().add(
createAssociatedTokenAccountInstruction(
signer.sender,
ata,
ownerPubkey,
mintPubkey,
TOKEN_PROGRAM_ID,
ASSOCIATED_TOKEN_PROGRAM_ID
)
);
try {
const signature = await signer.sendTransaction(transaction);
console.log("Created token account:", ata.toString());
console.log("Transaction signature:", signature);
return ata;
} catch (error) {
console.error("Failed to create token account:", error);
throw error;
}
};
const closeTokenAccount = async (tokenAccount: string) => {
const tokenAccountPubkey = new PublicKey(tokenAccount);
const transaction = new Transaction().add(
createCloseAccountInstruction(
tokenAccountPubkey,
signer.sender,
signer.sender,
[],
TOKEN_PROGRAM_ID
)
);
try {
const signature = await signer.sendTransaction(transaction);
console.log("Closed token account:", tokenAccount);
console.log("Transaction signature:", signature);
return signature;
} catch (error) {
console.error("Failed to close token account:", error);
throw error;
}
};
return (
createTokenAccount("USDC_MINT_ADDRESS")}>
Create USDC Account
closeTokenAccount("TOKEN_ACCOUNT_ADDRESS")}>
Close Token Account
);
}
```
```typescript
import { useParaSolanaV2 } from './hooks/useParaSolanaV2';
import {
pipe,
createTransactionMessage,
setTransactionMessageFeePayer,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstruction,
address
} from '@solana/web3.js';
import {
getCreateAssociatedTokenAccountInstruction,
findAssociatedTokenPda,
getCloseAccountInstruction
} from '@solana-program/token';
function ManageTokenAccounts() {
const { rpc, signer } = useParaSolanaV2();
const createTokenAccount = async (mint: string, owner?: string) => {
const mintAddress = address(mint);
const ownerAddress = owner ? address(owner) : signer.address;
const [ata] = await findAssociatedTokenPda({
mint: mintAddress,
owner: ownerAddress,
});
const accountInfo = await rpc.getAccountInfo(ata).send();
if (accountInfo.value) {
console.log("Token account already exists:", ata);
return ata;
}
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
const transaction = pipe(
createTransactionMessage({ version: 0 }),
tx => setTransactionMessageFeePayer(signer.address, tx),
tx => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
tx => appendTransactionMessageInstruction(
getCreateAssociatedTokenAccountInstruction({
ata,
mint: mintAddress,
owner: ownerAddress,
payer: signer,
}),
tx
)
);
try {
const [signature] = await signer.signAndSendTransactions([transaction]);
console.log("Created token account:", ata);
console.log("Transaction signature:", signature);
return ata;
} catch (error) {
console.error("Failed to create token account:", error);
throw error;
}
};
const closeTokenAccount = async (tokenAccount: string) => {
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
const transaction = pipe(
createTransactionMessage({ version: 0 }),
tx => setTransactionMessageFeePayer(signer.address, tx),
tx => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
tx => appendTransactionMessageInstruction(
getCloseAccountInstruction({
account: address(tokenAccount),
destination: signer.address,
authority: signer,
}),
tx
)
);
try {
const [signature] = await signer.signAndSendTransactions([transaction]);
console.log("Closed token account:", tokenAccount);
console.log("Transaction signature:", signature);
return signature;
} catch (error) {
console.error("Failed to close token account:", error);
throw error;
}
};
return (
createTokenAccount("USDC_MINT_ADDRESS")}>
Create USDC Account
closeTokenAccount("TOKEN_ACCOUNT_ADDRESS")}>
Close Token Account
);
}
```
```typescript
import { useParaAnchor } from './hooks/useParaAnchor';
import { Transaction, PublicKey } from '@solana/web3.js';
import {
createAssociatedTokenAccountInstruction,
getAssociatedTokenAddress,
createCloseAccountInstruction,
TOKEN_PROGRAM_ID,
ASSOCIATED_TOKEN_PROGRAM_ID
} from '@solana/spl-token';
function ManageTokenAccounts() {
const provider = useParaAnchor();
const createTokenAccount = async (mint: string, owner?: string) => {
const mintPubkey = new PublicKey(mint);
const ownerPubkey = owner ? new PublicKey(owner) : provider.publicKey;
const ata = await getAssociatedTokenAddress(mintPubkey, ownerPubkey);
const accountInfo = await provider.connection.getAccountInfo(ata);
if (accountInfo) {
console.log("Token account already exists:", ata.toString());
return ata;
}
const transaction = new Transaction().add(
createAssociatedTokenAccountInstruction(
provider.publicKey,
ata,
ownerPubkey,
mintPubkey,
TOKEN_PROGRAM_ID,
ASSOCIATED_TOKEN_PROGRAM_ID
)
);
try {
const signature = await provider.sendAndConfirm(transaction);
console.log("Created token account:", ata.toString());
console.log("Transaction signature:", signature);
return ata;
} catch (error) {
console.error("Failed to create token account:", error);
throw error;
}
};
const closeTokenAccount = async (tokenAccount: string) => {
const tokenAccountPubkey = new PublicKey(tokenAccount);
const transaction = new Transaction().add(
createCloseAccountInstruction(
tokenAccountPubkey,
provider.publicKey,
provider.publicKey,
[],
TOKEN_PROGRAM_ID
)
);
try {
const signature = await provider.sendAndConfirm(transaction);
console.log("Closed token account:", tokenAccount);
console.log("Transaction signature:", signature);
return signature;
} catch (error) {
console.error("Failed to close token account:", error);
throw error;
}
};
return (
createTokenAccount("USDC_MINT_ADDRESS")}>
Create USDC Account
closeTokenAccount("TOKEN_ACCOUNT_ADDRESS")}>
Close Token Account
);
}
```
## Next Steps
# Query Wallet Balances with Solana Libraries
Source: https://docs.getpara.com/v2/react/guides/web3-operations/solana/query-balances
Check SOL and SPL token balances using Solana Web3.js or Anchor with Para wallets
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Query SOL and SPL token balances for Para wallets using Solana libraries. This guide covers checking native SOL balances and SPL token balances.
```typescript
import { useParaSolana } from './hooks/useParaSolana';
import { LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js';
import { TOKEN_PROGRAM_ID, getAccount, getAssociatedTokenAddress } from '@solana/spl-token';
function WalletBalance() {
const { connection, signer } = useParaSolana();
const [solBalance, setSolBalance] = useState(0);
const [tokenBalance, setTokenBalance] = useState(0);
const fetchBalances = async () => {
try {
// Get SOL balance
const balance = await connection.getBalance(signer.sender);
setSolBalance(balance / LAMPORTS_PER_SOL);
// Get SPL token balance (example: USDC)
const usdcMint = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
const tokenAccount = await getAssociatedTokenAddress(
usdcMint,
signer.sender
);
try {
const accountInfo = await getAccount(connection, tokenAccount);
setTokenBalance(Number(accountInfo.amount) / 1e6); // USDC has 6 decimals
} catch (error) {
console.log("Token account not found");
setTokenBalance(0);
}
} catch (error) {
console.error("Error fetching balances:", error);
}
};
return (
Refresh Balances
SOL Balance: {solBalance}
USDC Balance: {tokenBalance}
);
}
```
```typescript
import { useParaSolanaV2 } from './hooks/useParaSolanaV2';
import { address, lamports } from '@solana/web3.js';
import { getAccount, getAssociatedTokenAddress } from '@solana/spl-token';
function WalletBalance() {
const { rpc, signer } = useParaSolanaV2();
const [solBalance, setSolBalance] = useState(0);
const [tokenBalance, setTokenBalance] = useState(0);
const fetchBalances = async () => {
try {
// Get SOL balance
const { value } = await rpc.getBalance(signer.address).send();
setSolBalance(Number(value) / 1e9);
// Get SPL token balance
const usdcMint = address("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
const tokenAccount = await getAssociatedTokenAddress(
usdcMint,
signer.address
);
const { value: accountData } = await rpc.getAccountInfo(tokenAccount).send();
if (accountData && accountData.data) {
const parsed = JSON.parse(accountData.data);
setTokenBalance(Number(parsed.parsed.info.tokenAmount.amount) / 1e6);
} else {
setTokenBalance(0);
}
} catch (error) {
console.error("Error fetching balances:", error);
}
};
return (
Refresh Balances
SOL Balance: {solBalance}
USDC Balance: {tokenBalance}
);
}
```
```typescript
import { useParaAnchor } from './hooks/useParaAnchor';
import { LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js';
import { TOKEN_PROGRAM_ID, getAccount, getAssociatedTokenAddress } from '@solana/spl-token';
function WalletBalance() {
const provider = useParaAnchor();
const [solBalance, setSolBalance] = useState(0);
const [tokenBalance, setTokenBalance] = useState(0);
const fetchBalances = async () => {
try {
// Get SOL balance
const balance = await provider.connection.getBalance(provider.publicKey);
setSolBalance(balance / LAMPORTS_PER_SOL);
// Get SPL token balance
const usdcMint = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
const tokenAccount = await getAssociatedTokenAddress(
usdcMint,
provider.publicKey
);
try {
const accountInfo = await getAccount(provider.connection, tokenAccount);
setTokenBalance(Number(accountInfo.amount) / 1e6);
} catch (error) {
console.log("Token account not found");
setTokenBalance(0);
}
} catch (error) {
console.error("Error fetching balances:", error);
}
};
return (
Refresh Balances
SOL Balance: {solBalance}
USDC Balance: {tokenBalance}
);
}
```
## Next Steps
# Send Tokens with Solana Libraries
Source: https://docs.getpara.com/v2/react/guides/web3-operations/solana/send-tokens
Transfer SOL tokens using Solana Web3.js or Anchor with Para wallets
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Transfer SOL tokens between wallets using Para's integrated signers with different Solana libraries.
```typescript
import { useParaSolana } from './hooks/useParaSolana';
import { Transaction, SystemProgram, LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js';
function SendTokens() {
const { connection, signer } = useParaSolana();
const sendSOL = async (recipient: string, amount: number) => {
if (!signer) {
console.error("No signer available. Connect wallet first.");
return;
}
const transaction = new Transaction().add(
SystemProgram.transfer({
fromPubkey: signer.sender,
toPubkey: new PublicKey(recipient),
lamports: LAMPORTS_PER_SOL * amount,
})
);
const signature = await signer.sendTransaction(transaction);
console.log("Transaction signature:", signature);
await connection.confirmTransaction(signature, "confirmed");
console.log("Transaction confirmed");
return signature;
};
return (
sendSOL("RECIPIENT_ADDRESS", 0.1)}>
Send 0.1 SOL
);
}
```
```typescript
import { useParaSolanaKit } from './hooks/useParaSolanaKit';
import { LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js';
import {
createTransactionMessage,
getTransferSolInstruction,
setTransactionMessageFeePayerSigner,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstructions,
signTransactionMessageWithSigners,
lamports,
pipe,
} from '@solana/kit';
function SendTokens() {
const { rpc, signer } = useParaSolanaKit();
const sendSOL = async (recipient: string, amount: number) => {
if (!signer) {
console.error("No signer available. Connect wallet first.");
return;
}
const transferAmount = lamports(LAMPORTS_PER_SOL * amount);
const recipientPublicKey = new PublicKey(recipient);
const transferInstruction = getTransferSolInstruction({
source: signer.publicKey,
destination: recipientPublicKey,
amount: transferAmount,
});
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
const transactionMessage = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayerSigner(signer.publicKey, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
(tx) => appendTransactionMessageInstructions([transferInstruction], tx)
);
const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);
const signature = await rpc.sendTransaction(signedTransaction).send();
console.log("Transaction signature:", signature);
await rpc.confirmTransaction({
signature,
blockhash: latestBlockhash.blockhash,
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight
});
console.log("Transaction confirmed");
return signature;
};
return (
sendSOL("RECIPIENT_ADDRESS", 0.1)}>
Send 0.1 SOL
);
}
```
```typescript
import { useParaAnchor } from './hooks/useParaAnchor';
import { Transaction, SystemProgram, LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js';
function SendTokens() {
const provider = useParaAnchor();
const sendSOL = async (recipient: string, amount: number) => {
if (provider.wallet.publicKey.equals(SystemProgram.programId)) {
console.error("No wallet connected. Please authenticate first.");
return;
}
const transaction = new Transaction().add(
SystemProgram.transfer({
fromPubkey: provider.wallet.publicKey,
toPubkey: new PublicKey(recipient),
lamports: LAMPORTS_PER_SOL * amount,
})
);
const signature = await provider.sendAndConfirm(transaction);
console.log("Transaction signature:", signature);
console.log("Transaction confirmed");
return signature;
};
return (
sendSOL("RECIPIENT_ADDRESS", 0.1)}>
Send 0.1 SOL
);
}
```
## Next Steps
# Setup Solana Libraries
Source: https://docs.getpara.com/v2/react/guides/web3-operations/solana/setup-libraries
Install and configure Solana Web3.js or Anchor for use with Para SDK
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Para supports multiple Solana libraries for blockchain interactions. Choose for standard operations, (@solana/web3.js-v2) for modern signing interfaces, or for program development.
## Installation
If using `@solana/signers` and the `@getpara/react-sdk` you can use our hook to access the Solana signer without any additional setup.
```bash npm
npm install @getpara/solana-web3.js-v1-integration@alpha @solana/web3.js --save-exact
```
```bash yarn
yarn add @getpara/solana-web3.js-v1-integration@alpha @solana/web3.js --exact
```
```bash pnpm
pnpm add @getpara/solana-web3.js-v1-integration@alpha @solana/web3.js --save-exact
```
```bash bun
bun add @getpara/solana-web3.js-v1-integration@alpha @solana/web3.js --exact
```
```bash npm
npm install @getpara/solana-signers-v2-integration@alpha @solana/kit --save-exact
```
```bash yarn
yarn add @getpara/solana-signers-v2-integration@alpha @solana/kit --exact
```
```bash pnpm
pnpm add @getpara/solana-signers-v2-integration@alpha @solana/kit --save-exact
```
```bash bun
bun add @getpara/solana-signers-v2-integration@alpha @solana/kit --exact
```
```bash npm
npm install @getpara/solana-web3.js-v1-integration@alpha @solana/web3.js @project-serum/anchor --save-exact
```
```bash yarn
yarn add @getpara/solana-web3.js-v1-integration@alpha @solana/web3.js @project-serum/anchor --exact
```
```bash pnpm
pnpm add @getpara/solana-web3.js-v1-integration@alpha @solana/web3.js @project-serum/anchor --save-exact
```
```bash bun
bun add @getpara/solana-web3.js-v1-integration@alpha @solana/web3.js @project-serum/anchor --exact
```
## Library Setup
```typescript hooks/useParaSolana.ts
import { useMemo } from 'react';
import { useClient, useAccount } from '@getpara/react-sdk';
import { ParaSolanaWeb3Signer } from '@getpara/solana-web3.js-v1-integration';
import { Connection, clusterApiUrl } from '@solana/web3.js';
export function useParaSolana() {
const para = useClient();
const { isConnected } = useAccount();
const { connection, signer } = useMemo(() => {
const connection = new Connection(clusterApiUrl('mainnet-beta'));
if (!para || !isConnected) {
return { connection, signer: null };
}
const wallets = para.getWalletsByType({ type: 'Solana' });
if (!wallets || wallets.length === 0) {
return { connection, signer: null };
}
const signer = new ParaSolanaWeb3Signer(para, connection);
return { connection, signer };
}, [para, isConnected]);
return { connection, signer };
}
```
```typescript hooks/useParaSolanaKit.ts
import { useMemo } from 'react';
import { useClient, useAccount } from '@getpara/react-sdk';
import { createParaSolanaSigner } from '@getpara/solana-signers-v2-integration';
import { createSolanaRpc } from '@solana/kit';
export function useParaSolanaKit() {
const para = useClient();
const { isConnected } = useAccount();
const { rpc, signer } = useMemo(() => {
const rpc = createSolanaRpc('https://api.mainnet-beta.solana.com');
if (!para || !isConnected) {
return { rpc, signer: null };
}
const wallets = para.getWalletsByType({ type: 'Solana' });
if (!wallets || wallets.length === 0) {
return { rpc, signer: null };
}
const signer = createParaSolanaSigner({ para, rpc });
return { rpc, signer };
}, [para, isConnected]);
return { rpc, signer };
}
```
```typescript hooks/useParaAnchor.ts
import { useMemo } from 'react';
import { useClient, useAccount } from '@getpara/react-sdk';
import { ParaSolanaWeb3Signer } from '@getpara/solana-web3.js-v1-integration';
import { Connection, clusterApiUrl, Transaction, VersionedTransaction, SystemProgram } from '@solana/web3.js';
import * as anchor from '@project-serum/anchor';
export function useParaAnchor() {
const para = useClient();
const { isConnected } = useAccount();
const provider = useMemo(() => {
const connection = new Connection(clusterApiUrl('mainnet-beta'));
if (!para || !isConnected) {
const readOnlyWallet = {
publicKey: SystemProgram.programId,
signTransaction: async (tx: T): Promise => {
throw new Error('Read-only provider: Authenticate to sign transactions.');
},
signAllTransactions: async (txs: T[]): Promise => {
throw new Error('Read-only provider: Authenticate to sign transactions.');
},
};
return new anchor.AnchorProvider(connection, readOnlyWallet, { commitment: 'confirmed' });
}
const wallets = para.getWalletsByType({ type: 'Solana' });
if (!wallets || wallets.length === 0) {
const readOnlyWallet = {
publicKey: SystemProgram.programId,
signTransaction: async (tx: T): Promise => {
throw new Error('No Solana wallet available');
},
signAllTransactions: async (txs: T[]): Promise => {
throw new Error('No Solana wallet available');
},
};
return new anchor.AnchorProvider(connection, readOnlyWallet, { commitment: 'confirmed' });
}
const signer = new ParaSolanaWeb3Signer(para, connection);
const wallet = {
publicKey: signer.sender,
signTransaction: async (tx: T): Promise => {
return await signer.signTransaction(tx);
},
signAllTransactions: async (txs: T[]): Promise => {
return await Promise.all(txs.map((tx) => signer.signTransaction(tx)));
},
};
return new anchor.AnchorProvider(connection, wallet, { commitment: 'confirmed' });
}, [para, isConnected]);
return provider;
}
```
```typescript
import { ParaSolanaWeb3Signer } from '@getpara/solana-web3.js-v1-integration';
import { Connection, clusterApiUrl } from '@solana/web3.js';
import { para } from './para';
const connection = new Connection(clusterApiUrl('mainnet-beta'));
const signer = new ParaSolanaWeb3Signer(para, connection);
```
```typescript
import { createParaSolanaSigner } from '@getpara/solana-signers-v2-integration';
import { createSolanaRpc } from '@solana/kit';
import { para } from './para';
const rpc = createSolanaRpc('https://api.mainnet-beta.solana.com');
const signer = createParaSolanaSigner({ para, rpc });
```
```typescript
import { ParaSolanaWeb3Signer } from '@getpara/solana-web3.js-v1-integration';
import { Connection, clusterApiUrl, Transaction, VersionedTransaction } from '@solana/web3.js';
import * as anchor from '@project-serum/anchor';
import { para } from './para';
const connection = new Connection(clusterApiUrl('mainnet-beta'));
const signer = new ParaSolanaWeb3Signer(para, connection);
const wallet = {
publicKey: signer.sender,
signTransaction: async (tx: T): Promise => {
return await signer.signTransaction(tx);
},
signAllTransactions: async (txs: T[]): Promise => {
return await Promise.all(txs.map((tx) => signer.signTransaction(tx)));
},
};
const provider = new anchor.AnchorProvider(connection, wallet, { commitment: 'confirmed' });
anchor.setProvider(provider);
```
## Next Steps
# SWIG Account Abstraction
Source: https://docs.getpara.com/v2/react/guides/web3-operations/solana/setup-swig
Build embedded wallets using SWIG AA provider with Para's infrastructure on Solana
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
SWIG provides account abstraction on Solana, enabling seamless embedded wallet experiences. This guide walks you through integrating SWIG with Para for embedded wallet creation.
## Prerequisites
Before starting this integration:
* Set up a Para account on their developer portal
* Generate an API Key
* Enable Solana as a supported network
* Basic understanding of React, TypeScript, and Solana
## Installation
Install the required dependencies for SWIG integration:
```bash
yarn add @getpara/react-sdk @tanstack/react-query @getpara/solana-web3.js-v1-integration @solana/web3.js @swig-wallet/classic @swig-wallet/coder
```
Install Vite polyfills for development:
```bash
yarn add vite-plugin-node-polyfills -D
```
## Setup
### Vite Configuration
Update your `vite.config.ts` for Solana compatibility:
```typescript
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { nodePolyfills } from "vite-plugin-node-polyfills";
import path from "path";
export default defineConfig({
plugins: [react(), nodePolyfills()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
});
```
### Environment Variables
Create a `.env.local` file in your project root:
```env
VITE_PARA_API_KEY=your_para_api_key
```
### Para Provider Setup
Create `providers.tsx` in your `src` directory:
```typescript
import React from "react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ParaProvider } from "@getpara/react-sdk";
import "@getpara/react-sdk/styles.css";
const queryClient = new QueryClient();
interface ProvidersProps {
children: React.ReactNode;
}
export function Providers({ children }: ProvidersProps) {
return (
{children}
);
}
```
## Authentication
Create a login button component with Para modal integration:
```tsx
import React from "react";
import { ParaModal, useModal, OAuthMethod, useAccount, useLogout } from "@getpara/react-sdk";
export const LoginButton: React.FC = () => {
const { openModal } = useModal();
const { data: account } = useAccount();
const { logoutAsync } = useLogout();
const handleClick = () => {
if (account?.isConnected) {
logoutAsync();
} else {
openModal();
}
};
return (
<>
{account?.isConnected ? "Sign out" : "Sign in with Para"}
>
);
};
```
## SWIG Account Creation
Create a SWIG account using Para's Solana Web3.js integration:
```tsx
import React, { useState, useEffect } from "react";
import { Connection, PublicKey, Transaction, LAMPORTS_PER_SOL } from "@solana/web3.js";
import { useAccount, useWallet, useClient } from "@getpara/react-sdk";
import { ParaSolanaWeb3Signer } from "@getpara/solana-web3.js-v1-integration";
import { Actions, Swig, findSwigPda, createEd25519AuthorityInfo } from "@swig-wallet/classic";
export const SwigAccountCreation: React.FC = () => {
const { data: account } = useAccount();
const { data: wallet } = useWallet();
const [swigAddress, setSwigAddress] = useState(null);
const [solBalance, setSolBalance] = useState(null);
const [isCreatingSwig, setIsCreatingSwig] = useState(false);
const para = useClient();
const connection = new Connection("https://api.devnet.solana.com");
const createSwigAccount = async () => {
if (!wallet?.address || !para) return;
setIsCreatingSwig(true);
try {
const id = new Uint8Array(32);
crypto.getRandomValues(id);
const paraPubkey = new PublicKey(wallet.address);
const [swigPdaAddress] = findSwigPda(id);
const signer = new ParaSolanaWeb3Signer(para, connection, wallet.id);
const rootAuthorityInfo = createEd25519AuthorityInfo(paraPubkey);
const rootActions = Actions.set().all().get();
const createSwigInstruction = Swig.create({
authorityInfo: rootAuthorityInfo,
id,
payer: paraPubkey,
actions: rootActions,
});
const transaction = new Transaction();
transaction.add(createSwigInstruction);
transaction.feePayer = paraPubkey;
const { blockhash } = await connection.getLatestBlockhash();
transaction.recentBlockhash = blockhash;
const signedTransaction = await signer.signTransaction(transaction);
const signature = await connection.sendRawTransaction(signedTransaction.serialize());
await connection.confirmTransaction({
signature,
blockhash,
lastValidBlockHeight: (await connection.getLatestBlockhash()).lastValidBlockHeight,
});
setSwigAddress(swigPdaAddress.toBase58());
setIsCreatingSwig(false);
console.log("Swig account created successfully!");
console.log("Swig address:", swigPdaAddress.toBase58());
console.log("Transaction signature:", signature);
} catch (error) {
console.error("Error in transaction signing:", error);
setIsCreatingSwig(false);
}
};
useEffect(() => {
const fetchBalance = async () => {
if (wallet?.address) {
try {
const balance = await connection.getBalance(new PublicKey(wallet.address));
setSolBalance(balance / LAMPORTS_PER_SOL);
} catch (e) {
setSolBalance(null);
}
}
};
fetchBalance();
}, [wallet?.address]);
if (!account?.isConnected || !wallet) {
return Please connect your wallet first
;
}
return (
You are signed in!
Wallet address: {wallet.address}
{solBalance !== null && (
Balance: {solBalance} SOL
)}
{swigAddress && (
Swig Account Created!
Address: {swigAddress}
)}
{!swigAddress && (
{isCreatingSwig ? "Creating Swig..." : "Create Swig Account"}
)}
);
};
```
## Complete Application
Here's the complete App component that brings everything together:
```tsx
import React from "react";
import { Providers } from "./providers";
import { LoginButton } from "./LoginButton";
import { SwigAccountCreation } from "./SwigAccountCreation";
export default function App() {
return (
SWIG + Para Integration
Using Para's Solana Web3.js integration for SWIG account creation
);
}
```
## Key Implementation Details
### SWIG Account Creation Process
The `createSwigAccount` function performs these critical steps:
1. **Generate Random ID**: Creates a unique 32-byte identifier for the SWIG account
2. **Create Para Signer**: Initializes `ParaSolanaWeb3Signer` with Para client and wallet
3. **Set Authority**: Establishes the Para-generated wallet as root authority
4. **Configure Actions**: Grants full permissions using `Actions.set().all().get()`
5. **Build Transaction**: Creates and configures the Solana transaction
6. **Sign & Send**: Uses Para's signer to sign and broadcast the transaction
### Important Notes
* **Devnet SOL Required**: You need devnet SOL in your Para-generated wallet before creating a SWIG account
* **Root Authority**: The Para-generated wallet becomes the root authority for the SWIG account
* **Error Handling**: The implementation includes proper error handling and loading states
* **Balance Display**: Shows wallet SOL balance and SWIG address after creation
## Testing Your Integration
1. Start your development server:
```bash
yarn dev
```
2. Open your browser to the displayed URL
3. Click "Sign in with Para" to authenticate
4. Send devnet SOL to your wallet address
5. Click "Create Swig Account" to create your SWIG account
## Best Practices
* Never commit API keys to version control
* Use environment variables for sensitive configuration
* Test thoroughly on Solana devnet before mainnet
* Implement proper error handling throughout the flow
* Store SWIG account information securely
## Resources
## Next Steps
Now that you have SWIG working with Para, you can:
* Implement additional SWIG functionality (transfers, token management)
* Customize the Para modal appearance and OAuth providers
* Add more complex transaction flows
* Implement additional security features like multi-signature support
* Integrate with other Solana protocols and applications
# Sign Messages with Solana Libraries
Source: https://docs.getpara.com/v2/react/guides/web3-operations/solana/sign-messages
Sign text and binary messages using Solana Web3.js or Anchor with Para
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Sign messages to prove ownership of a Solana address without submitting a transaction. This is commonly used for authentication and verification purposes.
```typescript
import { useParaSolana } from './hooks/useParaSolana';
import bs58 from 'bs58';
function SignMessage() {
const { signer } = useParaSolana();
const signMessage = async () => {
if (!signer) {
console.error("No signer available. Connect wallet first.");
return;
}
const message = "Hello, Solana!";
const messageBytes = new TextEncoder().encode(message);
const signature = await signer.signBytes(Buffer.from(messageBytes));
const signatureBase58 = bs58.encode(signature);
console.log("Message:", message);
console.log("Signature:", signatureBase58);
console.log("Signer:", signer.address);
};
return Sign Message ;
}
```
```typescript
import { useParaSolanaKit } from './hooks/useParaSolanaKit';
import { getUtf8Encoder } from '@solana/kit';
import bs58 from 'bs58';
function SignMessage() {
const { signer } = useParaSolanaKit();
const signMessage = async () => {
if (!signer) {
console.error("No signer available. Connect wallet first.");
return;
}
const message = "Hello, Solana!";
const messageBytes = getUtf8Encoder().encode(message);
const signatureResult = await signer.signMessages([
{ content: messageBytes, signatures: {} }
]);
const signatureBytes = signatureResult[0][signer.address];
const signatureBase58 = bs58.encode(signatureBytes);
console.log("Message:", message);
console.log("Signature:", signatureBase58);
console.log("Signer:", signer.address);
};
return Sign Message ;
}
```
```typescript
import { useParaAnchor } from './hooks/useParaAnchor';
import { useParaSolana } from './hooks/useParaSolana';
import bs58 from 'bs58';
function SignMessage() {
const provider = useParaAnchor();
const { signer } = useParaSolana();
const signMessage = async () => {
if (!signer) {
console.error("No signer available. Connect wallet first.");
return;
}
const message = "Hello, Anchor!";
const messageBytes = new TextEncoder().encode(message);
const signature = await signer.signBytes(Buffer.from(messageBytes));
const signatureBase58 = bs58.encode(signature);
console.log("Message:", message);
console.log("Signature:", signatureBase58);
console.log("Signer:", provider.wallet.publicKey.toString());
};
return Sign Message ;
}
```
## Next Steps
# Verify Signatures with Solana Libraries
Source: https://docs.getpara.com/v2/react/guides/web3-operations/solana/verify-signatures
Verify message and transaction signatures using Solana Web3.js or Anchor
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Verify Ed25519 signatures to confirm that a message was signed by a specific Solana address. Essential for authentication and ensuring data integrity.
## Verify Signatures
```typescript
import { useParaSolana } from './hooks/useParaSolana';
import { PublicKey } from '@solana/web3.js';
import nacl from 'tweetnacl';
import bs58 from 'bs58';
function VerifySignature() {
const { signer } = useParaSolana();
const verifyMessage = async () => {
if (!signer) {
console.error("No signer available. Connect wallet first.");
return;
}
const message = "Hello, Solana!";
const messageBytes = new TextEncoder().encode(message);
// Sign the message first
const signature = await signer.signBytes(Buffer.from(messageBytes));
const signatureBase58 = bs58.encode(signature);
// Verify the signature
try {
const publicKeyBytes = new PublicKey(signer.address).toBytes();
const isValid = nacl.sign.detached.verify(
messageBytes,
signature,
publicKeyBytes
);
console.log("Message:", message);
console.log("Signature:", signatureBase58);
console.log("Signature valid:", isValid);
console.log("Signer:", signer.address);
return isValid;
} catch (error) {
console.error("Verification failed:", error);
return false;
}
};
return Sign & Verify Message ;
}
```
```typescript
import { useParaSolanaKit } from './hooks/useParaSolanaKit';
import { getUtf8Encoder } from '@solana/kit';
import nacl from 'tweetnacl';
import bs58 from 'bs58';
function VerifySignature() {
const { signer } = useParaSolanaKit();
const verifyMessage = async () => {
if (!signer) {
console.error("No signer available. Connect wallet first.");
return;
}
const message = "Hello, Solana!";
const messageBytes = getUtf8Encoder().encode(message);
// Sign the message first
const signatureResult = await signer.signMessages([
{ content: messageBytes, signatures: {} }
]);
const signatureBytes = signatureResult[0][signer.address];
const signatureBase58 = bs58.encode(signatureBytes);
// Verify the signature
try {
const publicKeyBytes = bs58.decode(signer.address);
const isValid = nacl.sign.detached.verify(
messageBytes,
signatureBytes,
publicKeyBytes
);
console.log("Message:", message);
console.log("Signature:", signatureBase58);
console.log("Signature valid:", isValid);
console.log("Signer:", signer.address);
return isValid;
} catch (error) {
console.error("Verification failed:", error);
return false;
}
};
return Sign & Verify Message ;
}
```
```typescript
import { useParaAnchor } from './hooks/useParaAnchor';
import { useParaSolana } from './hooks/useParaSolana';
import nacl from 'tweetnacl';
import bs58 from 'bs58';
function VerifySignature() {
const provider = useParaAnchor();
const { signer } = useParaSolana();
const verifyMessage = async () => {
if (!signer) {
console.error("No signer available. Connect wallet first.");
return;
}
const message = "Hello, Anchor!";
const messageBytes = new TextEncoder().encode(message);
// Sign the message first
const signature = await signer.signBytes(Buffer.from(messageBytes));
const signatureBase58 = bs58.encode(signature);
// Verify the signature
try {
const publicKeyBytes = provider.wallet.publicKey.toBytes();
const isValid = nacl.sign.detached.verify(
messageBytes,
signature,
publicKeyBytes
);
console.log("Message:", message);
console.log("Signature:", signatureBase58);
console.log("Signature valid:", isValid);
console.log("Signer:", provider.wallet.publicKey.toString());
return isValid;
} catch (error) {
console.error("Verification failed:", error);
return false;
}
};
return Sign & Verify Message ;
}
```
## Next Steps
# Switch Active Wallet
Source: https://docs.getpara.com/v2/react/guides/web3-operations/switch-wallet
Change the currently selected wallet for blockchain operations
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
To switch wallets, use the `useWalletState` hook. This hook provides methods to manage the currently selected wallet and allows you to switch between different wallets.
### useWalletState
void, updateSelectedWallet: () => void }",
description: "Wallet state management object"
}}
/>
```tsx
import { useWalletState } from '@getpara/react-sdk';
const { selectedWallet, setSelectedWallet, updateSelectedWallet } = useWalletState();
// Switch to a specific wallet by ID
setSelectedWallet({ id: 'wallet_123' });
// Refresh selection from Para client state
updateSelectedWallet();
```
## Next Steps
# React SDK Overview
Source: https://docs.getpara.com/v2/react/overview
Complete guide to integrating Para's React SDK for Web3 authentication and wallet management
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Para's React SDK provides a comprehensive solution for Web3 authentication and wallet management in React applications. Navigate through our documentation to find the right integration path for your project.
## React Frameworks
Get started with Para in your preferred React framework. Each guide provides framework-specific setup instructions and best practices.
## Getting Started
Begin your Para integration journey with these essential resources designed to get you up and running quickly.
## Sign Transactions & Messages
Learn how to sign transactions and messages using Para's wallet infrastructure and integrate with popular Web3 libraries.
### Core Signing Operations
### Blockchain Libraries
### Smart Accounts
## Manage Users & Authentication
Implement secure authentication flows and manage user sessions with Para's comprehensive auth system.
### Wallet Connection Options
### Advanced Authentication
## Customize Your Integration
Tailor Para's appearance and behavior to match your brand and user experience requirements.
### Developer Portal Configuration
### UI Customization
## Advanced Features
Explore advanced capabilities and integration patterns for complex use cases.
### Resources & Support
# React SDK Quickstart
Source: https://docs.getpara.com/v2/react/quickstart
Get started with Para's React SDK in minutes with our interactive setup guide
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const SDKQuickstart = ({networks, snippets, id = 'sdk-quickstart'}) => {
const [selectedPackageManager, setSelectedPackageManager] = useState(null);
const [selectedNetworks, setSelectedNetworks] = useState(['EVM']);
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
if (snippets?.packageManagers?.length > 0 && !selectedPackageManager) {
setSelectedPackageManager(snippets.packageManagers[0]);
}
}, [snippets, selectedPackageManager]);
const handleSelectNetwork = network => {
if (selectedNetworks.includes(network)) {
if (selectedNetworks.length > 1) {
setSelectedNetworks(selectedNetworks.filter(n => n !== network));
}
} else {
setSelectedNetworks([...selectedNetworks, network]);
}
};
const dedent = str => {
if (typeof str !== "string") {
return "Error: No snippet code available for this selection.";
}
const lines = str.split("\n");
while (lines.length && lines[0].trim() === "") {
lines.shift();
}
while (lines.length && lines[lines.length - 1].trim() === "") {
lines.pop();
}
const minIndent = lines.reduce((min, line) => {
const match = line.match(/^(\s+)/);
if (match) {
return Math.min(min, match[1].length);
}
return 0;
}, Infinity);
if (!isFinite(minIndent) || minIndent === 0) return str;
return lines.map(line => line.slice(minIndent)).join("\n");
};
const getSnippets = (packageManager, networks) => {
try {
const {snippets: codeSnippets} = snippets;
if (networks.length > 1) {
if (codeSnippets && codeSnippets[packageManager] && typeof codeSnippets[packageManager].multi === "function") {
return codeSnippets[packageManager].multi(networks);
}
} else {
const network = networks[0];
if (codeSnippets && codeSnippets[packageManager] && codeSnippets[packageManager][network]) {
return codeSnippets[packageManager][network];
}
}
return {
install: packageManager === "npm" ? "npm install sdk-package" : packageManager === "yarn" ? "yarn add sdk-package" : packageManager === "pnpm" ? "pnpm add sdk-package" : packageManager === "pub" ? "pub add sdk_package" : "swift package add sdk-package",
setup: `const sdk = require('sdk-package');\nsdk.configure({ networks: ${JSON.stringify(networks)} });`
};
} catch (error) {
return {
install: "# Error loading snippet",
setup: "// Error loading snippet"
};
}
};
if (!mounted || !snippets) {
return
;
}
const currentPackageManagers = snippets.packageManagers || [];
const currentSnippets = getSnippets(selectedPackageManager, selectedNetworks);
const installCode = dedent(currentSnippets.install);
const setupCode = dedent(currentSnippets.setup);
return
{installCode}
{setupCode}
;
};
export const SDKSnippetsReact = {
packageManagers: ["npm", "yarn", "pnpm"],
snippets: {
npm: {
EVM: {
install: "npm install @getpara/react-sdk@alpha @tanstack/react-query @getpara/graz@alpha @cosmjs/cosmwasm-stargate @cosmjs/launchpad @cosmjs/proto-signing @cosmjs/stargate @cosmjs/tendermint-rpc @leapwallet/cosmos-social-login-capsule-provider long starknet wagmi viem @farcaster/mini-app-solana @farcaster/miniapp-sdk @farcaster/miniapp-wagmi-connector @solana-mobile/wallet-adapter-mobile @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-walletconnect @solana/web3.js --save-exact",
setup: `"use client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ParaProvider, useModal, useAccount, useWallet } from "@getpara/react-sdk";
import "@getpara/react-sdk/styles.css";
import { sepolia } from "wagmi/chains";
const queryClient = new QueryClient();
function HelloWorld() {
const { openModal } = useModal();
const { isConnected } = useAccount();
const { data: wallet } = useWallet();
return (
{!isConnected ? (
Connect Wallet
) : (
Connected: {wallet?.address}
)}
);
}
export default function App() {
return (
);
}`
},
Solana: {
install: "npm install @getpara/react-sdk@alpha @tanstack/react-query @getpara/graz@alpha @cosmjs/cosmwasm-stargate @cosmjs/launchpad @cosmjs/proto-signing @cosmjs/stargate @cosmjs/tendermint-rpc @leapwallet/cosmos-social-login-capsule-provider long starknet wagmi viem @farcaster/mini-app-solana @farcaster/miniapp-sdk @farcaster/miniapp-wagmi-connector @solana-mobile/wallet-adapter-mobile @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-walletconnect @solana/web3.js --save-exact",
setup: `"use client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ParaProvider, useModal, useAccount, useWallet } from "@getpara/react-sdk";
import "@getpara/react-sdk/styles.css";
import { WalletAdapterNetwork } from "@solana/wallet-adapter-base";
import { clusterApiUrl } from "@solana/web3.js";
const queryClient = new QueryClient();
const solanaNetwork = WalletAdapterNetwork.Devnet;
const endpoint = clusterApiUrl(solanaNetwork);
function HelloWorld() {
const { openModal } = useModal();
const { isConnected } = useAccount();
const { data: wallet } = useWallet();
return (
{!isConnected ? (
Connect Wallet
) : (
Connected: {wallet?.address}
)}
);
}
export default function App() {
return (
);
}`
},
Cosmos: {
install: "npm install @getpara/react-sdk@alpha @tanstack/react-query @getpara/graz@alpha @cosmjs/cosmwasm-stargate @cosmjs/launchpad @cosmjs/proto-signing @cosmjs/stargate @cosmjs/tendermint-rpc @leapwallet/cosmos-social-login-capsule-provider long starknet wagmi viem @farcaster/mini-app-solana @farcaster/miniapp-sdk @farcaster/miniapp-wagmi-connector @solana-mobile/wallet-adapter-mobile @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-walletconnect @solana/web3.js --save-exact",
setup: `"use client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ParaProvider, useModal, useAccount, useWallet } from "@getpara/react-sdk";
import "@getpara/react-sdk/styles.css";
import { cosmoshub } from "@getpara/graz/chains";
const queryClient = new QueryClient();
const cosmosChains = [cosmoshub];
function HelloWorld() {
const { openModal } = useModal();
const { isConnected } = useAccount();
const { data: wallet } = useWallet();
return (
{!isConnected ? (
Connect Wallet
) : (
Connected: {wallet?.address}
)}
);
}
export default function App() {
return (
);
}`
},
multi: selectedNetworks => {
const packages = ["@getpara/react-sdk@alpha", "@tanstack/react-query", "@getpara/graz@alpha", "@cosmjs/cosmwasm-stargate", "@cosmjs/launchpad", "@cosmjs/proto-signing", "@cosmjs/stargate", "@cosmjs/tendermint-rpc", "@leapwallet/cosmos-social-login-capsule-provider", "long", "starknet", "wagmi", "viem", "@farcaster/mini-app-solana", "@farcaster/miniapp-sdk", "@farcaster/miniapp-wagmi-connector", "@solana-mobile/wallet-adapter-mobile", "@solana/wallet-adapter-base", "@solana/wallet-adapter-react", "@solana/wallet-adapter-walletconnect", "@solana/web3.js"];
const imports = [`import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ParaProvider, useModal, useAccount, useWallet } from "@getpara/react-sdk";
import "@getpara/react-sdk/styles.css";`];
const wallets = [];
const connectorConfigs = [];
if (selectedNetworks.includes('EVM')) {
imports.push(`import { sepolia } from "wagmi/chains";`);
wallets.push('"METAMASK"');
connectorConfigs.push(` evmConnector: {
config: {
chains: [sepolia],
},
},`);
}
if (selectedNetworks.includes('Solana')) {
imports.push(`import { WalletAdapterNetwork } from "@solana/wallet-adapter-base";
import { clusterApiUrl } from "@solana/web3.js";`);
wallets.push('"PHANTOM", "SOLFLARE", "BACKPACK"');
connectorConfigs.push(` solanaConnector: {
config: {
endpoint,
chain: solanaNetwork,
appIdentity: {
uri: typeof window !== "undefined" ? \`\${window.location.protocol}//\${window.location.host}\` : "",
},
},
},`);
}
if (selectedNetworks.includes('Cosmos')) {
imports.push(`import { cosmoshub } from "@getpara/graz/chains";`);
wallets.push('"KEPLR", "LEAP"');
connectorConfigs.push(` cosmosConnector: {
config: {
chains: cosmosChains,
selectedChainId: cosmoshub.chainId,
},
},`);
}
const setupVars = [];
if (selectedNetworks.includes('Solana')) {
setupVars.push(`const solanaNetwork = WalletAdapterNetwork.Devnet;
const endpoint = clusterApiUrl(solanaNetwork);`);
}
if (selectedNetworks.includes('Cosmos')) {
setupVars.push(`const cosmosChains = [cosmoshub];`);
}
return {
install: `npm install ${packages.join(' ')} --save-exact`,
setup: `"use client";
${imports.join('\n')}
const queryClient = new QueryClient();
${setupVars.join('\n')}
function HelloWorld() {
const { openModal } = useModal();
const { isConnected } = useAccount();
const { data: wallet } = useWallet();
return (
{!isConnected ? (
Connect Wallet
) : (
Connected: {wallet?.address}
)}
);
}
export default function App() {
return (
);
}`
};
}
},
yarn: {
EVM: {
install: "yarn add @getpara/react-sdk@alpha @tanstack/react-query @getpara/graz@alpha @cosmjs/cosmwasm-stargate @cosmjs/launchpad @cosmjs/proto-signing @cosmjs/stargate @cosmjs/tendermint-rpc @leapwallet/cosmos-social-login-capsule-provider long starknet wagmi viem @farcaster/mini-app-solana @farcaster/miniapp-sdk @farcaster/miniapp-wagmi-connector @solana-mobile/wallet-adapter-mobile @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-walletconnect @solana/web3.js --exact",
setup: `"use client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ParaProvider, useModal, useAccount, useWallet } from "@getpara/react-sdk";
import "@getpara/react-sdk/styles.css";
import { sepolia } from "wagmi/chains";
const queryClient = new QueryClient();
function HelloWorld() {
const { openModal } = useModal();
const { isConnected } = useAccount();
const { data: wallet } = useWallet();
return (
{!isConnected ? (
Connect Wallet
) : (
Connected: {wallet?.address}
)}
);
}
export default function App() {
return (
);
}`
},
Solana: {
install: "yarn add @getpara/react-sdk@alpha @tanstack/react-query @getpara/graz@alpha @cosmjs/cosmwasm-stargate @cosmjs/launchpad @cosmjs/proto-signing @cosmjs/stargate @cosmjs/tendermint-rpc @leapwallet/cosmos-social-login-capsule-provider long starknet wagmi viem @farcaster/mini-app-solana @farcaster/miniapp-sdk @farcaster/miniapp-wagmi-connector @solana-mobile/wallet-adapter-mobile @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-walletconnect @solana/web3.js --exact",
setup: `"use client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ParaProvider, useModal, useAccount, useWallet } from "@getpara/react-sdk";
import "@getpara/react-sdk/styles.css";
import { WalletAdapterNetwork } from "@solana/wallet-adapter-base";
import { clusterApiUrl } from "@solana/web3.js";
const queryClient = new QueryClient();
const solanaNetwork = WalletAdapterNetwork.Devnet;
const endpoint = clusterApiUrl(solanaNetwork);
function HelloWorld() {
const { openModal } = useModal();
const { isConnected } = useAccount();
const { data: wallet } = useWallet();
return (
{!isConnected ? (
Connect Wallet
) : (
Connected: {wallet?.address}
)}
);
}
export default function App() {
return (
);
}`
},
Cosmos: {
install: "yarn add @getpara/react-sdk@alpha @tanstack/react-query @getpara/graz@alpha @cosmjs/cosmwasm-stargate @cosmjs/launchpad @cosmjs/proto-signing @cosmjs/stargate @cosmjs/tendermint-rpc @leapwallet/cosmos-social-login-capsule-provider long starknet wagmi viem @farcaster/mini-app-solana @farcaster/miniapp-sdk @farcaster/miniapp-wagmi-connector @solana-mobile/wallet-adapter-mobile @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-walletconnect @solana/web3.js --exact",
setup: `"use client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ParaProvider, useModal, useAccount, useWallet } from "@getpara/react-sdk";
import "@getpara/react-sdk/styles.css";
import { cosmoshub } from "@getpara/graz/chains";
const queryClient = new QueryClient();
const cosmosChains = [cosmoshub];
function HelloWorld() {
const { openModal } = useModal();
const { isConnected } = useAccount();
const { data: wallet } = useWallet();
return (
{!isConnected ? (
Connect Wallet
) : (
Connected: {wallet?.address}
)}
);
}
export default function App() {
return (
);
}`
},
multi: selectedNetworks => {
const packages = ["@getpara/react-sdk@alpha", "@tanstack/react-query", "@getpara/graz@alpha", "@cosmjs/cosmwasm-stargate", "@cosmjs/launchpad", "@cosmjs/proto-signing", "@cosmjs/stargate", "@cosmjs/tendermint-rpc", "@leapwallet/cosmos-social-login-capsule-provider", "long", "starknet", "wagmi", "viem", "@farcaster/mini-app-solana", "@farcaster/miniapp-sdk", "@farcaster/miniapp-wagmi-connector", "@solana-mobile/wallet-adapter-mobile", "@solana/wallet-adapter-base", "@solana/wallet-adapter-react", "@solana/wallet-adapter-walletconnect", "@solana/web3.js"];
const imports = [`import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ParaProvider, useModal, useAccount, useWallet } from "@getpara/react-sdk";
import "@getpara/react-sdk/styles.css";`];
const wallets = [];
const connectorConfigs = [];
if (selectedNetworks.includes('EVM')) {
imports.push(`import { sepolia } from "wagmi/chains";`);
wallets.push('"METAMASK"');
connectorConfigs.push(` evmConnector: {
config: {
chains: [sepolia],
},
},`);
}
if (selectedNetworks.includes('Solana')) {
imports.push(`import { WalletAdapterNetwork } from "@solana/wallet-adapter-base";
import { clusterApiUrl } from "@solana/web3.js";`);
wallets.push('"PHANTOM", "SOLFLARE", "BACKPACK"');
connectorConfigs.push(` solanaConnector: {
config: {
endpoint,
chain: solanaNetwork,
appIdentity: {
uri: typeof window !== "undefined" ? \`\${window.location.protocol}//\${window.location.host}\` : "",
},
},
},`);
}
if (selectedNetworks.includes('Cosmos')) {
imports.push(`import { cosmoshub } from "@getpara/graz/chains";`);
wallets.push('"KEPLR", "LEAP"');
connectorConfigs.push(` cosmosConnector: {
config: {
chains: cosmosChains,
selectedChainId: cosmoshub.chainId,
},
},`);
}
const setupVars = [];
if (selectedNetworks.includes('Solana')) {
setupVars.push(`const solanaNetwork = WalletAdapterNetwork.Devnet;
const endpoint = clusterApiUrl(solanaNetwork);`);
}
if (selectedNetworks.includes('Cosmos')) {
setupVars.push(`const cosmosChains = [cosmoshub];`);
}
return {
install: `yarn add ${packages.join(' ')} --exact`,
setup: `"use client";
${imports.join('\n')}
const queryClient = new QueryClient();
${setupVars.join('\n')}
function HelloWorld() {
const { openModal } = useModal();
const { isConnected } = useAccount();
const { data: wallet } = useWallet();
return (
{!isConnected ? (
Connect Wallet
) : (
Connected: {wallet?.address}
)}
);
}
export default function App() {
return (
);
}`
};
}
},
pnpm: {
EVM: {
install: "pnpm add @getpara/react-sdk@alpha @tanstack/react-query @getpara/graz@alpha @cosmjs/cosmwasm-stargate @cosmjs/launchpad @cosmjs/proto-signing @cosmjs/stargate @cosmjs/tendermint-rpc @leapwallet/cosmos-social-login-capsule-provider long starknet wagmi viem @farcaster/mini-app-solana @farcaster/miniapp-sdk @farcaster/miniapp-wagmi-connector @solana-mobile/wallet-adapter-mobile @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-walletconnect @solana/web3.js --save-exact",
setup: `"use client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ParaProvider, useModal, useAccount, useWallet } from "@getpara/react-sdk";
import "@getpara/react-sdk/styles.css";
import { sepolia } from "wagmi/chains";
const queryClient = new QueryClient();
function HelloWorld() {
const { openModal } = useModal();
const { isConnected } = useAccount();
const { data: wallet } = useWallet();
return (
{!isConnected ? (
Connect Wallet
) : (
Connected: {wallet?.address}
)}
);
}
export default function App() {
return (
);
}`
},
Solana: {
install: "pnpm add @getpara/react-sdk@alpha @tanstack/react-query @getpara/graz@alpha @cosmjs/cosmwasm-stargate @cosmjs/launchpad @cosmjs/proto-signing @cosmjs/stargate @cosmjs/tendermint-rpc @leapwallet/cosmos-social-login-capsule-provider long starknet wagmi viem @farcaster/mini-app-solana @farcaster/miniapp-sdk @farcaster/miniapp-wagmi-connector @solana-mobile/wallet-adapter-mobile @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-walletconnect @solana/web3.js --save-exact",
setup: `"use client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ParaProvider, useModal, useAccount, useWallet } from "@getpara/react-sdk";
import "@getpara/react-sdk/styles.css";
import { WalletAdapterNetwork } from "@solana/wallet-adapter-base";
import { clusterApiUrl } from "@solana/web3.js";
const queryClient = new QueryClient();
const solanaNetwork = WalletAdapterNetwork.Devnet;
const endpoint = clusterApiUrl(solanaNetwork);
function HelloWorld() {
const { openModal } = useModal();
const { isConnected } = useAccount();
const { data: wallet } = useWallet();
return (
{!isConnected ? (
Connect Wallet
) : (
Connected: {wallet?.address}
)}
);
}
export default function App() {
return (
);
}`
},
Cosmos: {
install: "pnpm add @getpara/react-sdk@alpha @tanstack/react-query @getpara/graz@alpha @cosmjs/cosmwasm-stargate @cosmjs/launchpad @cosmjs/proto-signing @cosmjs/stargate @cosmjs/tendermint-rpc @leapwallet/cosmos-social-login-capsule-provider long starknet wagmi viem @farcaster/mini-app-solana @farcaster/miniapp-sdk @farcaster/miniapp-wagmi-connector @solana-mobile/wallet-adapter-mobile @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-walletconnect @solana/web3.js --save-exact",
setup: `"use client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ParaProvider, useModal, useAccount, useWallet } from "@getpara/react-sdk";
import "@getpara/react-sdk/styles.css";
import { cosmoshub } from "@getpara/graz/chains";
const queryClient = new QueryClient();
const cosmosChains = [cosmoshub];
function HelloWorld() {
const { openModal } = useModal();
const { isConnected } = useAccount();
const { data: wallet } = useWallet();
return (
{!isConnected ? (
Connect Wallet
) : (
Connected: {wallet?.address}
)}
);
}
export default function App() {
return (
);
}`
},
multi: selectedNetworks => {
const packages = ["@getpara/react-sdk@alpha", "@tanstack/react-query", "@getpara/graz@alpha", "@cosmjs/cosmwasm-stargate", "@cosmjs/launchpad", "@cosmjs/proto-signing", "@cosmjs/stargate", "@cosmjs/tendermint-rpc", "@leapwallet/cosmos-social-login-capsule-provider", "long", "starknet", "wagmi", "viem", "@farcaster/mini-app-solana", "@farcaster/miniapp-sdk", "@farcaster/miniapp-wagmi-connector", "@solana-mobile/wallet-adapter-mobile", "@solana/wallet-adapter-base", "@solana/wallet-adapter-react", "@solana/wallet-adapter-walletconnect", "@solana/web3.js"];
const imports = [`import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ParaProvider, useModal, useAccount, useWallet } from "@getpara/react-sdk";
import "@getpara/react-sdk/styles.css";`];
const wallets = [];
const connectorConfigs = [];
if (selectedNetworks.includes('EVM')) {
imports.push(`import { sepolia } from "wagmi/chains";`);
wallets.push('"METAMASK"');
connectorConfigs.push(` evmConnector: {
config: {
chains: [sepolia],
},
},`);
}
if (selectedNetworks.includes('Solana')) {
imports.push(`import { WalletAdapterNetwork } from "@solana/wallet-adapter-base";
import { clusterApiUrl } from "@solana/web3.js";`);
wallets.push('"PHANTOM", "SOLFLARE", "BACKPACK"');
connectorConfigs.push(` solanaConnector: {
config: {
endpoint,
chain: solanaNetwork,
appIdentity: {
uri: typeof window !== "undefined" ? \`\${window.location.protocol}//\${window.location.host}\` : "",
},
},
},`);
}
if (selectedNetworks.includes('Cosmos')) {
imports.push(`import { cosmoshub } from "@getpara/graz/chains";`);
wallets.push('"KEPLR", "LEAP"');
connectorConfigs.push(` cosmosConnector: {
config: {
chains: cosmosChains,
selectedChainId: cosmoshub.chainId,
},
},`);
}
const setupVars = [];
if (selectedNetworks.includes('Solana')) {
setupVars.push(`const solanaNetwork = WalletAdapterNetwork.Devnet;
const endpoint = clusterApiUrl(solanaNetwork);`);
}
if (selectedNetworks.includes('Cosmos')) {
setupVars.push(`const cosmosChains = [cosmoshub];`);
}
return {
install: `pnpm add ${packages.join(' ')} --save-exact`,
setup: `"use client";
${imports.join('\n')}
const queryClient = new QueryClient();
${setupVars.join('\n')}
function HelloWorld() {
const { openModal } = useModal();
const { isConnected } = useAccount();
const { data: wallet } = useWallet();
return (
{!isConnected ? (
Connect Wallet
) : (
Connected: {wallet?.address}
)}
);
}
export default function App() {
return (
);
}`
};
}
}
}
};
export const SDKQuickstartNetworks = {
EVM: {
label: "EVM",
logo: "https://mintlify.s3-us-west-1.amazonaws.com/getpara/images/ethereum-eth-logo.png"
},
Solana: {
label: "Solana",
logo: "https://mintlify.s3-us-west-1.amazonaws.com/getpara/images/solana-sol-logo.png"
},
Cosmos: {
label: "Cosmos",
logo: "https://mintlify.s3-us-west-1.amazonaws.com/getpara/images/cosmos-atom-logo.png"
}
};
export const PackageManagerSelector = ({packageManagers, selectedPackageManager, onSelectPackageManager}) => {
return
{packageManagers.map(pm => onSelectPackageManager(pm)} />)}
;
};
export const NetworkSelector = ({networks, selectedNetworks, onSelectNetwork}) => {
return
{Object.entries(networks).map(([networkKey, network]) => onSelectNetwork(networkKey)} icon={ } />)}
;
};
export const CustomCodeBlock = ({title, children, id, language = 'javascript', pageName}) => {
const [showCopyTooltip, setShowCopyTooltip] = useState(false);
const [copyTooltipText, setCopyTooltipText] = useState('Copy');
const [showPageTooltip, setShowPageTooltip] = useState(false);
const [pageTooltipText, setPageTooltipText] = useState('Click to copy link');
const [mounted, setMounted] = useState(false);
const code = children?.toString().trim() || '';
const [highlightedCode, setHighlightedCode] = useState(code);
const codeRef = useRef(null);
useEffect(() => {
const loadHighlightJS = async () => {
if (typeof window !== 'undefined' && !window.hljs) {
try {
await new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js';
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
});
const styleLink = document.createElement('link');
styleLink.rel = 'stylesheet';
styleLink.href = 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css';
document.head.appendChild(styleLink);
} catch (error) {
console.error('Failed to load highlight.js:', error);
}
}
};
loadHighlightJS().then(() => {
setMounted(true);
});
}, []);
useEffect(() => {
if (mounted && window.hljs && codeRef.current) {
try {
const result = window.hljs.highlight(code, {
language
});
setHighlightedCode(result.value);
} catch (error) {
console.error('Syntax highlighting failed:', error);
setHighlightedCode(code);
}
}
}, [mounted, code, language]);
const handleCopy = async () => {
try {
await navigator.clipboard.writeText(code);
setCopyTooltipText('Copied!');
setShowCopyTooltip(true);
setTimeout(() => {
setShowCopyTooltip(false);
setTimeout(() => {
setCopyTooltipText('Copy');
}, 200);
}, 2000);
} catch (err) {
console.error('Failed to copy:', err);
}
};
const handlePageNameClick = async () => {
if (id) {
const newUrl = `${window.location.origin}${window.location.pathname}#${id}`;
window.location.hash = id;
try {
await navigator.clipboard.writeText(newUrl);
setPageTooltipText('Link copied!');
setShowPageTooltip(true);
setTimeout(() => {
setShowPageTooltip(false);
setTimeout(() => {
setPageTooltipText('Click to copy link');
}, 200);
}, 2000);
} catch (err) {
console.error('Failed to copy URL:', err);
}
}
};
if (!mounted) {
return
{title &&
{title} }
{pageName &&
{pageName}
}
;
}
return
{title &&
{title} }
{pageName &&
{pageName}
}
;
};
export const FilterSection = ({title, children, id}) => {
return ;
};
export const FilterButton = ({text, isActive, onClick, icon, id}) => {
const [isHovered, setIsHovered] = useState(false);
const showGradient = isActive || isHovered;
return
setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} onClick={onClick}>
{icon &&
{icon}
}
{text}
;
};
## Interactive Setup
**Need an API Key?** Head to the to create your account and get your API key. You'll need this to complete the integration above.
## Next Steps
Once you've integrated the SDK, explore these guides to enhance your application:
Learn how to sign transactions and messages with Para wallets
Configure your app settings, branding, and security in the Developer Portal
Manage user sessions, JWTs, and authentication flows
Explore all available React hooks for Para integration
# Para with Next.js
Source: https://docs.getpara.com/v2/react/setup/nextjs
A guide to integrate Para into a Next.js application
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
This guide will walk you through integrating Para SDK into your **Next.js** application, providing seamless user
authentication and wallet management.
This guide uses the **Next.js App Router**. For Pages Router, refer to the for setup instructions.
## Prerequisites
Before starting, you'll need a Para API key which you can obtain from the
Para Developer Portal. You can learn to create your account and get
your API key from the Developer Portal.
## Installation
Install the Para React SDK and React Query:
```bash npm
npm install @getpara/react-sdk@alpha @tanstack/react-query --save-exact
```
```bash yarn
yarn add @getpara/react-sdk@alpha @tanstack/react-query --exact
```
````bash pnpm
pnpm add @getpara/react-sdk@alpha @tanstack/react-query --save-exact
```bash bun
bun add @getpara/react-sdk@alpha @tanstack/react-query --exact
````
## Configure Providers
Create a providers component and wrap your application with it. Note the `"use client"` directive at the top - this is
required for Next.js App Router:
```jsx providers.tsx
"use client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ParaProvider } from "@getpara/react-sdk";
import "@getpara/react-sdk/styles.css";
const queryClient = new QueryClient();
export function Providers({
children,
}: Readonly<{
children: React.ReactNode,
}>) {
return (
{children}
);
}
```
If you're using a legacy API key (one without an environment prefix) you must provide a value to the
`paraClientConfig.environment`. You can retrieve your updated API key from the Para Developer Portal at
[https://developer.getpara.com/](https://developer.getpara.com/)
## Wrap Your App with Providers
Update your root layout to wrap your application with the Providers component:
```jsx app/layout.tsx
import { Providers } from "./providers";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
{children}
);
}
```
## Create a Connect Button
Now you can create a component that uses Para hooks to manage wallet connection:
```jsx connect-button.tsx
"use client";
import { useModal, useAccount, useWallet } from "@getpara/react-sdk";
export function ConnectButton() {
const { openModal } = useModal();
const { data: wallet } = useWallet();
const { isConnected } = useAccount();
return (
openModal()}>
{isConnected ? `Connected: ${wallet?.address?.slice(0, 6)}...${wallet?.address?.slice(-4)}` : "Connect Wallet"}
);
}
```
**Testing?** Use `BETA` testing credentials for fast development. Check out the to learn about test emails and phone numbers.
## Example
## Next Steps
Success you've set up Para with Next.js! Now you can expand your application with wallet connections, account
management, and more.
# Para with TanStack Start
Source: https://docs.getpara.com/v2/react/setup/tanstack-start
A guide to integrate Para SDK with TanStack Start while preserving server-side rendering capabilities.
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
This guide will walk you through integrating Para SDK with **TanStack Start** while preserving server-side rendering (SSR) capabilities.
TanStack Start is a full-stack React framework powered by TanStack Router. Para SDK uses styled-components internally which requires client-side only loading to work correctly with SSR.
## Prerequisites
Before starting, you'll need a Para API key which you can obtain from the Para Developer Portal. You can learn to create your account and get your API key from the Developer Portal.
## Installation
Install the Para React SDK and React Query:
```bash npm
npm install @getpara/react-sdk@alpha @tanstack/react-query @getpara/graz@alpha @cosmjs/cosmwasm-stargate @cosmjs/launchpad @cosmjs/proto-signing @cosmjs/stargate @cosmjs/tendermint-rpc @leapwallet/cosmos-social-login-capsule-provider long starknet wagmi viem @farcaster/mini-app-solana @farcaster/miniapp-sdk @farcaster/miniapp-wagmi-connector @solana-mobile/wallet-adapter-mobile @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-walletconnect @solana/web3.js --save-exact
```
```bash yarn
yarn add @getpara/react-sdk@alpha @tanstack/react-query @getpara/graz@alpha @cosmjs/cosmwasm-stargate @cosmjs/launchpad @cosmjs/proto-signing @cosmjs/stargate @cosmjs/tendermint-rpc @leapwallet/cosmos-social-login-capsule-provider long starknet wagmi viem @farcaster/mini-app-solana @farcaster/miniapp-sdk @farcaster/miniapp-wagmi-connector @solana-mobile/wallet-adapter-mobile @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-walletconnect @solana/web3.js --exact
```
````bash pnpm
pnpm add @getpara/react-sdk@alpha @tanstack/react-query @getpara/graz@alpha @cosmjs/cosmwasm-stargate @cosmjs/launchpad @cosmjs/proto-signing @cosmjs/stargate @cosmjs/tendermint-rpc @leapwallet/cosmos-social-login-capsule-provider long starknet wagmi viem @farcaster/mini-app-solana @farcaster/miniapp-sdk @farcaster/miniapp-wagmi-connector @solana-mobile/wallet-adapter-mobile @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-walletconnect @solana/web3.js --save-exact
```bash bun
bun add @getpara/react-sdk@alpha @tanstack/react-query @getpara/graz@alpha @cosmjs/cosmwasm-stargate @cosmjs/launchpad @cosmjs/proto-signing @cosmjs/stargate @cosmjs/tendermint-rpc @leapwallet/cosmos-social-login-capsule-provider long starknet wagmi viem @farcaster/mini-app-solana @farcaster/miniapp-sdk @farcaster/miniapp-wagmi-connector @solana-mobile/wallet-adapter-mobile @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-walletconnect @solana/web3.js --exact
````
## Setting Up Polyfills with TanStack Start
Since TanStack Start uses Vite under the hood, we need to set up polyfills for modules like crypto, buffer, etc. that Para SDK relies on. We only want to run these polyfills on the client, not on the server.
1. Install the Vite Node Polyfills plugin:
```bash npm
npm install vite-plugin-node-polyfills --save-dev
```
```bash yarn
yarn add vite-plugin-node-polyfills -D
```
```bash pnpm
pnpm add vite-plugin-node-polyfills -D
```
```bash bun
bun add -d vite-plugin-node-polyfills
```
2. Configure the polyfills in your `app.config.ts`:
```ts app.config.ts
import { defineConfig } from "@tanstack/react-start/config";
import tsConfigPaths from "vite-tsconfig-paths";
import { nodePolyfills } from "vite-plugin-node-polyfills";
export default defineConfig({
tsr: { appDirectory: "src" },
// Base configuration (applied to both client and server)
vite: {
plugins: [tsConfigPaths({ projects: ["./tsconfig.json"] })],
define: {
// This helps modules determine the execution environment
"process.browser": true,
},
},
// Client-specific configuration
routers: {
client: {
vite: {
// Apply node polyfills only on the client side
plugins: [nodePolyfills()],
},
},
},
});
```
## Setup Postinstall Script
Add the Para setup script to your `package.json`:
```json package.json
{
"scripts": {
"postinstall": "npx setup-para"
}
}
```
## Create a Client-Only Providers Component
Create a providers component using React.lazy and ClientOnly to ensure Para SDK only loads on the client:
```tsx src/components/Providers.tsx
import React from "react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ClientOnly } from "@tanstack/react-router";
const queryClient = new QueryClient();
// Lazy load ParaProvider to avoid SSR issues
const LazyParaProvider = React.lazy(() =>
import("@getpara/react-sdk").then((mod) => ({
default: mod.ParaProvider
}))
);
export default function Providers({ children }: React.PropsWithChildren) {
return (
{children}
);
}
```
If you're using a legacy API key (one without an environment prefix) you must provide a value to the `paraClientConfig.environment`. You can retrieve your updated API key from the Para Developer Portal at [https://developer.getpara.com/](https://developer.getpara.com/)
## Wrap Your App with Providers
Update your root component to wrap your application with the Providers component:
```tsx src/routes/__root.tsx
import Providers from "~/components/Providers";
import { Outlet } from "@tanstack/react-router";
export function RootComponent() {
return (
);
}
```
You can learn more about the `ParaProvider` and its definition in the .
## Create a Client-Only Connect Component
Create a component that uses Para SDK hooks, ensuring it's only rendered on the client:
```tsx src/components/ParaContainer.tsx
import { useModal, useAccount } from "@getpara/react-sdk";
export function ParaContainer() {
const { openConnectModal, openWalletModal } = useModal();
const account = useAccount();
return (
{account.isConnected && account.embedded.wallets?.length ? (
Connected: {account.embedded.wallets[0].address}
Manage Wallet
) : (
Connect Wallet
)}
);
}
```
You can learn more about the `useModal` and `useAccount` hooks in the .
Use it in your pages with ClientOnly wrapper:
```tsx src/routes/index.tsx
import React from "react";
import { createFileRoute, ClientOnly } from "@tanstack/react-router";
import "@getpara/react-sdk/styles.css";
// Lazy load Para container component
const LazyParaContainer = React.lazy(() =>
import("~/components/ParaContainer").then((mod) => ({
default: mod.ParaContainer,
}))
);
function Home() {
return (
Para Modal Example
Loading Para components...}>
);
}
export const Route = createFileRoute("/")({
component: Home,
});
```
The Para SDK uses styled-components internally which can cause issues during server-side rendering. By using `React.lazy` and `ClientOnly`, we ensure Para components are only evaluated in the browser environment where styled-components works correctly.
## Example
## Next Steps
Success you've set up Para with TanStack Start! Now you can expand your application with wallet connections, account management, and more.
# Para with React + Vite
Source: https://docs.getpara.com/v2/react/setup/vite
A guide to quickly integrate the Para Modal into your Vite-powered React application.
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
This guide will walk you through integrating Para SDK into your **Vite**-powered React application, providing seamless user authentication and wallet management.
## Prerequisites
Before starting, you'll need a Para API key which you can obtain from the Para Developer Portal. You can learn to create your account and get your API key from the Developer Portal.
## Installation
Install the Para React SDK, React Query, and required polyfills for Vite:
```bash npm
npm install @getpara/react-sdk@alpha @tanstack/react-query --save-exact && npm install vite-plugin-node-polyfills --save-dev
```
```bash yarn
yarn add @getpara/react-sdk@alpha @tanstack/react-query --exact && yarn add vite-plugin-node-polyfills -D
```
```bash pnpm
pnpm add @getpara/react-sdk@alpha @tanstack/react-query --save-exact && pnpm add vite-plugin-node-polyfills -D
```
```bash bun
bun add @getpara/react-sdk@alpha @tanstack/react-query --exact && bun add -d vite-plugin-node-polyfills
```
Then add the polyfill plugin to your `vite.config.js`:
```js vite.config.js
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { nodePolyfills } from "vite-plugin-node-polyfills";
export default defineConfig({
plugins: [react(), nodePolyfills()],
});
```
## Configure Providers
Create a providers component and wrap your application with it:
```jsx providers.jsx
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ParaProvider } from "@getpara/react-sdk";
import "@getpara/react-sdk/styles.css";
const queryClient = new QueryClient();
export function Providers({ children }) {
return (
{children}
);
}
```
If you're using a legacy API key (one without an environment prefix) you must provide a value to the `paraClientConfig.environment`. You can retrieve your updated API key from the Para Developer Portal at [https://developer.getpara.com/](https://developer.getpara.com/)
## Wrap Your App with Providers
Update your main app file:
```jsx src/App.jsx
import { Providers } from './providers';
function App() {
return (
{/* Your app content */}
);
}
export default App;
```
## Create a Connect Button
Now create a component that uses Para hooks to manage wallet connection:
```jsx ConnectButton.jsx
import { useModal, useAccount, useWallet } from "@getpara/react-sdk";
export function ConnectButton() {
const { openModal } = useModal();
const { data: wallet } = useWallet();
const { isConnected } = useAccount();
return (
openModal()}>
{isConnected
? `Connected: ${wallet?.address?.slice(0, 6)}...${wallet?.address?.slice(-4)}`
: "Connect Wallet"}
);
}
```
**Testing?** Use `BETA` testing credentials for fast development. Check out the to learn about test emails and phone numbers.
## Example
## Next Steps
Success you've set up Para with Vite! Now you can expand your application with wallet connections, account management, and more.
# Testing Your Integration
Source: https://docs.getpara.com/v2/react/testing-guide
Use test credentials to develop and test your Para integration without creating real users
## Overview
Para provides test credentials for the `BETA` environment to help you develop and test your integration without creating real user accounts. This guide explains how to use test accounts and manage your testing workflow effectively.
## Test Credentials
### Email Testing
For email-based authentication testing in the `BETA` environment:
* Use any email ending in `@test.getpara.com`
* Examples: `dev@test.getpara.com`, `test1@test.getpara.com`, `user123@test.getpara.com`
* **Any OTP code will work** for verification (e.g., `123456`, `000000`, `111111`)
* Perfect for testing email-based authentication flows
### Phone Number Testing
For SMS-based authentication testing in the BETA environment:
* Use US phone numbers (+1) in format: `(area code)-555-xxxx`
* Examples: `(425)-555-1234`, `(206)-555-9876`, `(310)-555-0001`
* **Any OTP code will work** for verification
* Ideal for testing phone-based authentication flows
## Important Testing Notes
These test credentials **only work in the BETA Environment**. They will not work in production. Make sure your Para SDK is configured for the BETA environment when using these credentials.
### User Limits
* Beta accounts are limited to **50 users**
* If you reach the 50 user limit, you will need to delete users to continue testing
* Regular cleanup helps you stay within limits during development
### Managing Test Users
Navigate to your [Para Developer Portal](https://developer.getpara.com) and log in with your developer credentials
Click on "Users" in the left sidebar. You'll be taken to a list of users for your API key where you can see the identifier and login method for each user.
Click on any user to open a drawer with user details. Inside the drawer, click "Delete User" to remove that specific user.
If you need to clear all test users at once, use the "Delete All Users" button available on the users page.
**Important:** Deleting users is only possible while in the BETA environment. In production, wallets are permanent and cannot be deleted.
## Troubleshooting
* Verify you're using the BETA environment
* Check that the email ends exactly with `@test.getpara.com`
* Ensure phone numbers follow the `(xxx)-555-xxxx` format
* Access the Developer Portal to delete unused test users
* Consider using a naming convention to identify old test accounts
* Set up automated cleanup in your test suite
* Confirm you're in BETA environment (not production)
* Any numeric OTP should work (e.g., "123456")
* Check for typos in the test credentials
## Next Steps
Get started with Para integration
Configure your developer portal
Manage user sessions effectively
# Para with Svelte + Vite
Source: https://docs.getpara.com/v2/svelte/setup/vite
A user-friendly guide to integrate the Para Modal (React-based) into your Svelte application powered by Vite.
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label}) => {
e.currentTarget.querySelector("#underline").style.height = "2px";
}} onMouseLeave={e => {
e.currentTarget.querySelector("#underline").style.height = "1px";
}}>
{label}
;
If you haven't already you can create a new Svelte project with Vite by following the .
Although mixing React and Svelte is unusual, we can do so via . If you prefer to build your own custom UI, you can also use `@getpara/web-sdk`@alpha directly. Reach out to use for help with custom UI integration.
## Prerequisites
To use Para, you need an API key. This key authenticates your requests to Para services and is essential for
integration.
Don't have an API key yet? Request access to the to create API keys, manage billing, teams, and more.
## Installing Dependencies & Peer Dependencies
First, install the Para React SDK and needed peer dependencies, plus React dependencies using your preferred package manager:
```bash npm
npm install @getpara/react-sdk@alpha react react-dom @tanstack/react-query @getpara/graz@alpha @cosmjs/cosmwasm-stargate @cosmjs/launchpad @cosmjs/proto-signing @cosmjs/stargate @cosmjs/tendermint-rpc @leapwallet/cosmos-social-login-capsule-provider long starknet wagmi viem @solana-mobile/wallet-adapter-mobile @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-walletconnect @solana/web3.js --save-exact
```
```bash yarn
yarn add @getpara/react-sdk@alpha react react-dom @tanstack/react-query @getpara/graz@alpha @cosmjs/cosmwasm-stargate @cosmjs/launchpad @cosmjs/proto-signing @cosmjs/stargate @cosmjs/tendermint-rpc @leapwallet/cosmos-social-login-capsule-provider long starknet wagmi viem @solana-mobile/wallet-adapter-mobile @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-walletconnect @solana/web3.js --exact
```
```bash pnpm
pnpm add @getpara/react-sdk@alpha react react-dom @tanstack/react-query @getpara/graz@alpha @cosmjs/cosmwasm-stargate @cosmjs/launchpad @cosmjs/proto-signing @cosmjs/stargate @cosmjs/tendermint-rpc @leapwallet/cosmos-social-login-capsule-provider long starknet wagmi viem @solana-mobile/wallet-adapter-mobile @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-walletconnect @solana/web3.js --save-exact
```
```bash bun
bun add @getpara/react-sdk@alpha react react-dom @tanstack/react-query @getpara/graz@alpha @cosmjs/cosmwasm-stargate @cosmjs/launchpad @cosmjs/proto-signing @cosmjs/stargate @cosmjs/tendermint-rpc @leapwallet/cosmos-social-login-capsule-provider long starknet wagmi viem @solana-mobile/wallet-adapter-mobile @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-walletconnect @solana/web3.js --exact
```
## Setting Up the Svelte Preprocessor and Vite Polyfills
### Svelte Preprocessor for React
You must configure your **Svelte** app to accept React components. For that, install and configure
`svelte-preprocess-react`:
```bash npm
npm install svelte-preprocess-react
```
```bash yarn
yarn add svelte-preprocess-react
```
```bash pnpm
pnpm add svelte-preprocess-react
```
```bash bun
bun add svelte-preprocess-react
```
Then add it to your `svelte.config.js`:
```js svelte.config.js
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
import preprocessReact from "svelte-preprocess-react/preprocessReact";
export default {
preprocess: [vitePreprocess(), preprocessReact()],
};
```
### Vite Polyfills
Like other React-based setups, you may need Node.js polyfills for features like `crypto`, `buffer`, and `stream`.
Install `vite-plugin-node-polyfills`:
```bash npm
npm install vite-plugin-node-polyfills --save-dev
```
```bash yarn
yarn add vite-plugin-node-polyfills -D
```
```bash pnpm
pnpm add vite-plugin-node-polyfills -D
```
```bash bun
bun add vite-plugin-node-polyfills
```
Then configure it in `vite.config.js` or `vite.config.ts`:
```ts vite.config.ts
import { defineConfig } from "vite";
import { svelte } from "@sveltejs/vite-plugin-svelte";
import { nodePolyfills } from "vite-plugin-node-polyfills";
export default defineConfig({
plugins: [svelte(), nodePolyfills()],
});
```
## Creating a QueryClient Instance
```ts client/queryClient.ts
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
export const queryClient = new QueryClient();
```
## Setting Up the Para SDK
Now that you've installed the necessary dependencies, let's set up the Para SDK in your Svelte application. This
involves creating a client instance and integrating the Para Modal.
### Creating a Para Client Instance
Much like in React or Vue, you'll need a Para client instance. Keep it in a dedicated file (e.g., `client/para.ts`):
```ts client/para.ts
import { ParaWeb } from "@getpara/react-sdk@alpha";
const PARA_API_KEY = import.meta.env.VITE_PARA_API_KEY;
export const para = new ParaWeb(PARA_API_KEY);
```
If you're using a legacy API key (one without an environment prefix) you must provide the `Environment` as the first argument to the `ParaWeb` constructor. You can retrieve your updated API key from the Para Developer Portal at [https://developer.getpara.com/](https://developer.getpara.com/)
### Integrating the Para Modal in Svelte
With `svelte-preprocess-react`, you can **directly** use React components in Svelte:
**Beta Testing Credentials** In the `BETA` Environment, you can use any email ending in `@test.getpara.com` (like
[dev@test.getpara.com](mailto:dev@test.getpara.com)) or US phone numbers (+1) in the format `(area code)-555-xxxx` (like (425)-555-1234). Any OTP
code will work for verification with these test credentials. These credentials are for beta testing only. You can
delete test users anytime in the beta developer console to free up user slots.
```svelte
isModalOpen = true}>
Open Para Modal
isModalOpen = false},
logo: Logo,
disableEmailLogin: false,
disablePhoneLogin: false,
authLayout: [AuthLayout.AUTH_FULL],
oAuthMethods: [
"APPLE",
"DISCORD",
"FACEBOOK",
"FARCASTER",
"GOOGLE",
"TWITTER",
],
onRampTestMode: true,
recoverySecretStepEnabled: true,
twoFactorAuthEnabled: false,
theme: {
foregroundColor: "#2D3648",
backgroundColor: "#FFFFFF",
accentColor: "#0066CC",
darkForegroundColor: "#E8EBF2",
darkBackgroundColor: "#1A1F2B",
darkAccentColor: "#4D9FFF",
mode: "light",
borderRadius: "none",
font: "Inter",
},
}}
externalWalletConfig={{
wallets: []
}}
/>
```
When you click **Open Para Modal**, the React-based Para Modal will appear inside your Svelte application.
### Customizing the Para Modal
Just like in React, you can provide any additional props to the `` component. For example, customizing modal
theming:
```svelte
```
For a full list of available `ParaModalProps`, refer to the customization guide:
## Examples
For an example of using Para SDK in a Svelte application, check out our Examples Hub repository:
## Troubleshooting
If you encounter issues during the integration or usage of the Para Modal in a Svelte-based app, here are some common
problems and their solutions:
# Para with Vue + Vite
Source: https://docs.getpara.com/v2/vue/setup/vite
A guide to integrate the Para Modal (React-based) into your Vue application powered by Vite.
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label}) => {
e.currentTarget.querySelector("#underline").style.height = "2px";
}} onMouseLeave={e => {
e.currentTarget.querySelector("#underline").style.height = "1px";
}}>
{label}
;
While mixing React with Vue isn't always considered best practice, it is entirely possible by bridging to the React
modal via a connector. If you prefer to build your own custom UI, you can also use `@getpara/web-sdk`@alpha directly. Reach out to use for help with custom UI integration.
## Prerequisites
To use Para, you need an API key. This key authenticates your requests to Para services and is essential for
integration.
Don't have an API key yet? Request access to the to create API keys, manage billing, teams, and more.
## Installing Dependencies & Peer Dependencies
First, install the Para React SDK and needed peer dependencies, plus React dependencies using your preferred package manager:
```bash npm
npm install @getpara/react-sdk@alpha react react-dom @tanstack/react-query @getpara/graz@alpha @cosmjs/cosmwasm-stargate @cosmjs/launchpad @cosmjs/proto-signing @cosmjs/stargate @cosmjs/tendermint-rpc @leapwallet/cosmos-social-login-capsule-provider long starknet wagmi viem @solana-mobile/wallet-adapter-mobile @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-walletconnect @solana/web3.js --save-exact
```
```bash yarn
yarn add @getpara/react-sdk@alpha react react-dom @tanstack/react-query @getpara/graz@alpha @cosmjs/cosmwasm-stargate @cosmjs/launchpad @cosmjs/proto-signing @cosmjs/stargate @cosmjs/tendermint-rpc @leapwallet/cosmos-social-login-capsule-provider long starknet wagmi viem @solana-mobile/wallet-adapter-mobile @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-walletconnect @solana/web3.js --exact
```
```bash pnpm
pnpm add @getpara/react-sdk@alpha react react-dom @tanstack/react-query @getpara/graz@alpha @cosmjs/cosmwasm-stargate @cosmjs/launchpad @cosmjs/proto-signing @cosmjs/stargate @cosmjs/tendermint-rpc @leapwallet/cosmos-social-login-capsule-provider long starknet wagmi viem @solana-mobile/wallet-adapter-mobile @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-walletconnect @solana/web3.js --save-exact
```
```bash bun
bun add @getpara/react-sdk@alpha react react-dom @tanstack/react-query @getpara/graz@alpha @cosmjs/cosmwasm-stargate @cosmjs/launchpad @cosmjs/proto-signing @cosmjs/stargate @cosmjs/tendermint-rpc @leapwallet/cosmos-social-login-capsule-provider long starknet wagmi viem @solana-mobile/wallet-adapter-mobile @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-walletconnect @solana/web3.js --exact
```
## Setting Up Polyfills
Like any React + Vite project that may rely on Node modules (`crypto`, `buffer`, `stream`), you'll likely need
polyfills:
```bash npm
npm install vite-plugin-node-polyfills
```
```bash yarn
yarn add vite-plugin-node-polyfills -D
```
```bash pnpm
pnpm add vite-plugin-node-polyfills -D
```
```bash bun
bun add vite-plugin-node-polyfills
```
Then, update your `vite.config.js` or `vite.config.ts`:
```js vite.config.js
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import react from "@vitejs/plugin-react"; // Needed for the React-based modal
import { nodePolyfills } from "vite-plugin-node-polyfills";
export default defineConfig({
plugins: [
vue(),
react(),
nodePolyfills({
protocolImports: true,
}),
],
});
```
## Setting Up the Para SDK
Now that you've installed the necessary dependencies, let's set up the Para SDK in your Vue project. This involves
creating a client instance and optionally configuring Next.js to transpile external modules if needed.
### Creating a Para Client Instance
Just like in React apps, you need a Para client instance. You can keep it in a dedicated file (e.g., `client/para.ts`):
```ts client/para.ts
import { ParaWeb } from "@getpara/react-sdk@alpha";
const PARA_API_KEY = import.meta.env.VITE_PARA_API_KEY;
export const para = new ParaWeb(PARA_API_KEY);
```
If you're using a legacy API key (one without an environment prefix) you must provide the `Environment` as the first argument to the `ParaWeb` constructor. You can retrieve your updated API key from the Para Developer Portal at [https://developer.getpara.com/](https://developer.getpara.com/)
### Building a Connector for the React Modal
To display the React-based Para Modal from within Vue, we'll create a component that mounts the React modal into a DOM
element. You can store this in a file such as `para-react-component.jsx`:
```jsx para-react-component.jsx
import React from "react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { AuthLayout, ParaProvider } from "@getpara/react-sdk@alpha";
import { para } from "./client/para";
import "@getpara/react-sdk/styles.css@alpha";
const queryClient = new QueryClient();
export function ParaReactComponent({ onClose, isOpen }) {
return (
{
onClose?.();
},
logo: "/para.svg",
disableEmailLogin: false,
disablePhoneLogin: false,
authLayout: [AuthLayout.AUTH_FULL],
oAuthMethods: [
"APPLE",
"DISCORD",
"FACEBOOK",
"FARCASTER",
"GOOGLE",
"TWITTER",
],
onRampTestMode: true,
recoverySecretStepEnabled: true,
twoFactorAuthEnabled: false,
theme: {
foregroundColor: "#2D3648",
backgroundColor: "#FFFFFF",
accentColor: "#0066CC",
darkForegroundColor: "#E8EBF2",
darkBackgroundColor: "#1A1F2B",
darkAccentColor: "#4D9FFF",
mode: "light",
borderRadius: "none",
font: "Inter",
},
}}
externalWalletConfig={{
wallets: [],
}}
/>
);
}
```
This connector creates a React root within a given DOM element and renders the Para Modal into it. It also provides a
few methods to open, close, and check the modal's state.
### Integrating in a Vue Component
Use Vue's lifecycle hooks to create and destroy the modal connector. Below is a simplified example (`index.vue`):
```vue index.vue
Para Modal Starter (Vue + Vite)
Open Para Modal
```
When you click the **Open Para Modal** button, the React-based Para Modal will appear within your Vue application.
**Beta Testing Credentials** In the `BETA` Environment, you can use any email ending in `@test.getpara.com` (like
[dev@test.getpara.com](mailto:dev@test.getpara.com)) or US phone numbers (+1) in the format `(area code)-555-xxxx` (like (425)-555-1234). Any OTP
code will work for verification with these test credentials. These credentials are for beta testing only. You can
delete test users anytime in the beta developer console to free up user slots.
### Customizing the Para Modal
All the usual customization props apply, just as in a React app:
```tsx
```
Add them to your `ParaReactComponent` as needed.
## Examples
For an example of a fully working Vue + Vite integration, check out our starter templates or example repositories:
## Troubleshooting
If you encounter issues during the integration or usage of the Para Modal in a Vue-based app, here are some common
problems and their solutions:
# Integrate Para Wallets with Eliza OS
Source: https://docs.getpara.com/v2/walkthroughs/Eliza
Build wallet-enabled AI agents using Para's infrastructure and Eliza OS framework
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Build wallet-enabled AI agents by integrating Para's wallet infrastructure with Eliza OS. Your agent will create and manage EVM wallets and send transactions across Ethereum-compatible chains.
## Prerequisites
You need these components before starting:
* Node.js 18+ and npm/pnpm/yarn/bun installed
* An active [Eliza OS](https://docs.elizaos.ai/) project
* Para API credentials (get them from the [Para Developer Portal](https://developer.getpara.com/))
## Installation and Setup
Choose your preferred package manager to install the [Para plugin](https://github.com/aipop-fun/plugin-para):
```bash
# npm
npm install @elizaos/plugin-para
# pnpm
pnpm add @elizaos/plugin-para
# yarn
yarn add @elizaos/plugin-para
# bun
bun add @elizaos/plugin-para
```
Create or update your `.env` file with Para credentials:
```env
# Para Configuration
PARA_API_KEY=your-para-api-key
PARA_ENV=production
# Optional: Chain-specific RPC URLs
ETH_RPC_URL=https://mainnet.infura.io/v3/your-key
POLYGON_RPC_URL=https://polygon-rpc.com
```
Register the Para plugin in your Eliza character configuration:
```typescript
// character.config.ts
import { paraPlugin } from '@elizaos/plugin-para';
export const characterConfig = {
name: "ParaAgent",
description: "An AI agent with wallet management capabilities",
plugins: [paraPlugin],
settings: {
secrets: {
PARA_API_KEY: process.env.PARA_API_KEY,
PARA_ENV: process.env.PARA_ENV || 'production'
}
}
};
```
Create your agent with Para capabilities:
```typescript
// index.ts
import { ElizaOS } from '@elizaos/core';
import { characterConfig } from './character.config';
async function main() {
const agent = new ElizaOS({
character: characterConfig,
runtime: {
// Additional runtime configuration
logLevel: 'info',
persistState: true
}
});
await agent.start();
console.log('🤖 Para-enabled agent is running!');
}
main().catch(console.error);
```
## Next Steps
# Integrating Para with thirdweb
Source: https://docs.getpara.com/v2/walkthroughs/Thirdweb
Learn how to integrate Para's embedded wallets with the thirdweb SDK to onboard users without seed phrases
Learn how to connect Para with thirdweb. This guide shows you how to integrate Para's embedded wallets with the thirdweb SDK to onboard users without seed phrases, while enabling full EVM and Solana compatibility, account abstraction, and seamless in-app payments.
## Prerequisites
Before proceeding, ensure your application has [the necessary setup for the Para SDK](https://developer.getpara.com/?ref=blog.thirdweb.com).
## Step 1: Create a thirdweb Project
To access a client for authentication and transactions, follow these steps:
1. Navigate to the [thirdweb Dashboard](https://thirdweb.com/dashboard?ref=blog.thirdweb.com).
2. Click on **Create a new project**.
3. Enter a project name (e.g., "My thirdweb project").
4. Configure allowed domains:
* Add your production domain (e.g., `mydomain.com`).
* Add `localhost:` for local development.
5. Click **Create** to generate your project.
6. Securely save your **Client ID** and **Secret Key**.
### Add your keys to .env.local
At the root of your project, create (or update) a `.env.local` file:
```bash
NEXT_PUBLIC_THIRDWEB_CLIENT_ID=your_thirdweb_client_id
NEXT_PUBLIC_PARA_API_KEY=your_para_api_key
```
## Step 2: Configure the thirdweb SDK
### Install Dependencies
Use either `yarn` or `npm` to install the required package:
```bash
yarn add thirdweb
# or
npm install thirdweb
```
### Set Up the Provider
```tsx
// app/providers.tsx (or _app.tsx)
"use client";
import { ReactNode } from "react";
import { ThirdwebProvider } from "thirdweb/react";
import { Environment, ParaProvider, ParaModal } from "@getpara/react-sdk";
export default function Providers({ children }: { children: ReactNode }) {
return (
{children}
);
}
```
## Step 3: Implement Login and Wallet Connection
### Import Required Dependencies
In your login page or main application file, include the necessary imports:
```tsx
"use client";
import { useEffect } from "react";
import { defineChain } from "thirdweb";
import { viemAdapter } from "thirdweb/adapters/viem";
import { createWalletAdapter } from "thirdweb";
import { useSetActiveWallet, useActiveWallet, ConnectButton, PayEmbed } from "thirdweb/react";
import { useViemClient, useViemAccount, useModal } from "@getpara/react-sdk";
import { client } from "@/lib/thirdwebClient";
```
**Initialize thirdweb client**
```tsx
const client = createThirdwebClient({
clientId: process.env.NEXT_PUBLIC_TEMPLATE_CLIENT_ID!,
});
// (Optional) choose your active chain the same way you do elsewhere
const chain = defineChain(1); // e.g., Ethereum mainnet, or your target EVM chain
```
### Handle Wallet Connection
```tsx
"use client";
import { useEffect } from "react";
import { defineChain } from "thirdweb";
import { viemAdapter } from "thirdweb/adapters/viem";
import { createWalletAdapter } from "thirdweb";
import { useSetActiveWallet, useActiveWallet, ConnectButton, PayEmbed } from "thirdweb/react";
import { useViemClient, useViemAccount } from "@getpara/react-sdk"; // Para hooks
import { client } from "@/lib/thirdwebClient"; // ← shared client
export function WalletBridge() {
const { viemClient } = useViemClient(); // Para-provided viem WalletClient
const { viemAccount } = useViemAccount(); // { address, status } etc.
const setActiveWallet = useSetActiveWallet();
const thirdwebWallet = useActiveWallet();
const isConnected = Boolean(viemAccount?.address);
// Bridge Para's viem wallet client into a thirdweb wallet
useEffect(() => {
let cancelled = false;
const setActive = async () => {
if (!viemClient || !viemAccount?.address) return;
// Determine current chain id from the Para viem client
const chainId =
(await viemClient.getChainId?.()) ??
viemClient.chain?.id ??
1; // fallback: Ethereum mainnet
const personalAccount = viemAdapter.walletClient.fromViem({
walletClient: viemClient as any,
});
const w = createWalletAdapter({
client,
adaptedAccount,
chain: defineChain(chainId),
onDisconnect: async () => {
// optional: any local cleanup you need
},
switchChain: async (next) => {
// If you support user-initiated chain switching, implement it here.
// Typically you'd re-create the adapter with the new chain or
// call your own chain-switch UX before re-bridging.
},
});
if (!cancelled) setActiveWallet(w);
};
setActive();
return () => {
cancelled = true;
};
}, [viemClient, viemAccount?.address, setActiveWallet]);
}
```
### Managing Wallet Disconnection
```tsx
// If the Para account goes away (user logs out / session expired),
// make sure thirdweb disconnects too so state stays in sync.
useEffect(() => {
const syncDisconnect = async () => {
if (thirdwebWallet && !viemAccount?.address) {
await thirdwebWallet.disconnect();
}
};
syncDisconnect();
}, [thirdwebWallet, viemAccount?.address]);
```
### Render UI Components
```tsx
return (
<>
{isConnected ? (
) : (
Connect with Para to share the wallet between both libraries!
)}
>
);
```
## Real-World Implementation
Teams like **Camp Network** are already using Para wallets with thirdweb Account Abstraction tooling to power seamless onboarding and in-app transactions. Para provides the **universal embedded wallet layer** (Distributed MPC, passkeys, and multi-chain support), while thirdweb's AA SDK gives Camp flexible **smart account features** like gas sponsorship, batched transactions, session keys.
The result: users log in once with Para and get a gasless and bundled transaction experience through thirdweb, without ever touching seed phrases or juggling multiple wallets.
## Next Steps
Learn more about Para's React SDK features and configuration options
Explore how Para integrates with Account Abstraction systems
# Integrate x402 with Para
Source: https://docs.getpara.com/v2/walkthroughs/X402
Enable micropayments over HTTP using Para's ViemAccount with Coinbase's x402 protocol
Para provides a standard ViemAccount that works seamlessly with x402's HTTP payment protocol. This guide shows you how to integrate Para wallets with x402 for stablecoin payments.
## Prerequisites
* Para SDK configured with API credentials
* Node.js 18+ or modern browser environment
* Basic understanding of Viem accounts
* x402 facilitator URL (default: `https://x402.org/facilitator`)
## Installation
### Install packages
Install the required packages:
```bash
npm install @getpara/viem-v2-integration@alpha viem@^2 @coinbase/x402 x402-express --save-exact
```
## Setup
```typescript
import Para, { Environment } from '@getpara/web-sdk';
const para = new Para(Environment.BETA, YOUR_API_KEY);
```
Para provides a standard ViemAccount that works with any Viem-compatible library:
```typescript
import { createParaAccount } from '@getpara/viem-v2-integration';
const viemAccount = await createParaAccount(para);
```
## Usage
### Client-Side Payments
```typescript
import { wrapFetchWithPayment } from '@coinbase/x402';
// Wrap fetch with x402 payments using Para's ViemAccount
const paymentFetch = wrapFetchWithPayment(fetch, viemAccount);
// Make payment-enabled requests
const response = await paymentFetch('https://api.example.com/premium');
const data = await response.json();
```
### React Hook Integration
```typescript
import { useAccount } from '@getpara/react-sdk';
import { createParaAccount } from '@getpara/viem-v2-integration';
import { wrapFetchWithPayment } from '@coinbase/x402';
function PaymentComponent() {
const { para } = useAccount();
const handlePayment = async () => {
const viemAccount = await createParaAccount(para);
const paymentFetch = wrapFetchWithPayment(fetch, viemAccount);
const response = await paymentFetch('/api/endpoint');
const data = await response.json();
console.log('Payment complete:', data);
};
return Pay with Para ;
}
```
### Server-Side Setup
Set up your Express server with x402 payment middleware:
```typescript
import express from 'express';
import { paymentMiddleware } from 'x402-express';
import { facilitator } from '@coinbase/x402';
const app = express();
```
Configure the middleware with your wallet address and pricing:
```typescript
app.use('/api/premium', paymentMiddleware(
'0xYourWalletAddress', // Your receiving wallet
{
'GET /api/premium': {
price: '$0.01',
network: 'base'
}
},
facilitator // or { url: 'https://x402.org/facilitator' } for testnet
));
```
Add your protected endpoint and start the server:
```typescript
app.get('/api/premium', (req, res) => {
res.json({ data: 'Premium content' });
});
app.listen(3000);
```
## Examples
### Autonomous Agent
Build an agent that makes autonomous payments:
```typescript
import Para, { Environment } from '@getpara/server-sdk';
import { createParaAccount } from '@getpara/viem-v2-integration';
import { wrapFetchWithPayment } from '@coinbase/x402';
class PaymentAgent {
private para: Para;
private viemAccount: any;
async initialize() {
this.para = new Para(Environment.BETA, process.env.PARA_API_KEY);
this.viemAccount = await createParaAccount(this.para);
}
async payForService(url: string, maxAmount: string) {
const paymentFetch = wrapFetchWithPayment(fetch, this.viemAccount, {
maxAmount
});
return await paymentFetch(url);
}
}
// Usage
const agent = new PaymentAgent();
await agent.initialize();
const response = await agent.payForService('https://api.example.com/premium', '0.10');
```
### Multi-Chain Payments
Use Para's multi-chain support with x402:
```typescript
import { createParaAccount } from '@getpara/viem-v2-integration';
import { http } from 'viem';
import { base, ethereum, polygon } from 'viem/chains';
// Create Para Viem client with multi-chain support
const paraClient = createParaAccount(para, {
chain: base, // Default chain
transport: http()
});
// Use with x402 - automatically handles chain switching
const paymentFetch = wrapFetchWithPayment(fetch, paraClient.account);
```
## Next Steps
Learn more about the x402 payment protocol
Explore Para's Viem integration in detail
# Integrate Aave v3 with Para
Source: https://docs.getpara.com/v2/walkthroughs/aave
Combine Para's wallet infrastructure with Aave's lending protocol to enable seamless borrowing, lending, and yield strategies
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
## Integrating Aave V3 with Para's Viem Accounts
Combine Para's viem account infrastructure with [Aave v3](https://docs-aave-git-feat-api-sdk-documentation-avaraxyz.vercel.app/docs/developers/aave-v3/overview) to enable seamless borrowing, lending, and yield strategies, all from a Para-powered wallet.
## What You Need
You need these components to integrate Aave V3 with Para:
* **Para SDK** for creating and managing wallets
* **Aave V3 SDK / ABI** for interacting with the protocol
* **EVM-compatible chain** such as Polygon, Optimism, or Arbitrum
## Step-by-Step Integration
1. Initialize Para (complete authentication before signing)
```
import { supply } from '@aave/client/actions';
import { sendWith } from '@aave/client/viem';
import { createParaViemClient, createParaAccount } from "@getpara/viem-v2-integration@alpha";
import { http } from 'viem';
import { mainnet } from 'viem/chains';
import {ParaWeb } from "@getpara/react-sdk";
// Initialize Para (complete authentication before signing)
const para = new ParaWeb('YOUR_API_KEY_HERE');
```
2. Create Para account
```
const account = await createParaAccount(para);
```
3. Create Para Viem wallet client for transactions
```
const wallet = createParaViemClient(para, {
account,
chain: mainnet,
transport: http(), // Or specify RPC URL: http('https://your-rpc-url')
});
const result = await supply(client, {
market: evmAddress('0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4e2'), // Aave V3 Pool address
amount: {
erc20: {
currency: evmAddress('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'), // USDC on Mainnet
value: '1000' // 1000 USDC
}
},
supplier: evmAddress('0xYourUserAddressHere'),
chainId: chainId(1), // Mainnet
})
.andThen(sendWith(wallet)) // Signs and sends via Para Viem wallet client
.andThen(client.waitForTransaction); // Waits for confirmation
```
## Why Combine Para and Aave
| Feature | Benefit |
| ------------ | ------------------------------------------- |
| Para wallets | Instant onboarding, MPC-secure, white-label |
| Aave V3 | Yield, borrow, leverage strategies |
Together, you can enable [fintech-grade](https://www.getpara.com/fintech) defi UX in your app without friction.
## Example Use Cases
Integrating Para and Aave enable these example use cases:
**1. Fintech App Integration**: Embed borrow and lend flows directly in your fintech or stablecoin application
**2. Stablecoin Vaults**: Run automated stablecoin vaults using Aave yield generation
**3. Treasury Management**: Automate treasury strategies from a Para wallet with programmable rules
# Alchemy: EIP-7702 vs Smart Wallet Accounts with Para
Source: https://docs.getpara.com/v2/walkthroughs/alchemy-eip7702-vs-smart-accounts
Learn the differences between EIP-7702 temporary account upgrades and traditional smart wallet accounts using Para and Alchemy
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
This walkthrough explores two approaches to account abstraction with Para and Alchemy: EIP-7702 temporary account upgrades versus traditional smart wallet accounts. Both approaches enable gas sponsorship and advanced transaction capabilities, but work differently under the hood.
## Understanding the Approaches
### Traditional Smart Wallet Accounts
Traditional smart wallet accounts involve:
1. **EOA as signer/owner** - Para wallet acts as the signer for a deployed smart contract
2. **Smart contract deployment** - A separate smart contract wallet is deployed on-chain
3. **Smart contract receives benefits** - Gas sponsorship goes to the smart contract, not the EOA
4. **Persistent deployment** - The smart contract remains deployed after use
### EIP-7702 Temporary Upgrades
EIP-7702 enables:
1. **EOA receives benefits directly** - Para wallet itself receives gas sponsorship and smart contract capabilities
2. **No permanent deployment** - Temporarily borrows bytecode from a pre-deployed smart contract
3. **EOA transformation** - The EOA itself becomes a smart account temporarily
4. **Simplified architecture** - No need to manage separate smart contract addresses
## Key Differences
| Feature | Smart Wallet Account | EIP-7702 |
| -------------------------- | ---------------------- | ----------------------------- |
| **Contract Deployment** | Required per user | Uses pre-deployed contract |
| **Gas Sponsorship Target** | Smart contract address | EOA address directly |
| **Transaction Complexity** | Higher (userOps) | Lower (standard transactions) |
| **Signature Recovery** | Expects 27/28 v-bytes | Expects 0/1 v-bytes |
| **Persistence** | Permanent deployment | Temporary upgrade |
## Para Wallet Integration
Para wallets work as EOAs (Externally Owned Accounts) that can sign for both approaches:
* **Active user sessions** - Authenticated users with live Para embedded wallets
* **Pregenerated wallets** - Server-side Para instances with loaded user shares
Since Para provides raw signing capabilities, it can facilitate signatures for both smart wallet accounts and EIP-7702 operations.
## Implementation: Smart Wallet Accounts
### Setup Para Client
```typescript
import { Para } from "@getpara/server-sdk";
import { createParaAccount, createParaViemClient } from "@getpara/viem";
// Initialize Para with pregenerated wallet
const para = new Para(process.env.PARA_API_KEY!);
// Load user share for pregenerated wallet
const userShare = await getUserShareFromDatabase(email);
await para.setUserShare(userShare);
// Create Para account with custom signing
const viemParaAccount = createParaAccount(para);
viemParaAccount.signMessage = async ({ message }) =>
customSignMessage(para, message);
```
```typescript
import { Para } from "@getpara/server-sdk";
import { createParaAccount, createParaViemClient } from "@getpara/viem";
// Initialize Para with active user session
const para = new Para(process.env.PARA_API_KEY!);
// Import existing user session
await para.importSession(userSession);
// Create Para account with custom signing
const viemParaAccount = createParaAccount(para);
viemParaAccount.signMessage = async ({ message }) =>
customSignMessage(para, message);
```
### Create Alchemy Modular Account Client
```typescript
import { customSignMessage } from "./signature-utils";
// Create Viem client with Para integration
const viemClient = createParaViemClient(para, {
account: viemParaAccount,
chain: arbitrumSepolia,
transport: http(rpcUrl)
});
// Create wallet client signer
const walletClientSigner = new WalletClientSigner(viemClient, "para");
// Create Alchemy modular account client
const alchemyClient = await createModularAccountAlchemyClient({
transport: alchemy({ rpcUrl: rpcUrl }),
chain: arbitrumSepolia,
signer: walletClientSigner,
policyId: alchemyGasPolicyId // For gas sponsorship
});
```
### Execute Smart Wallet Transactions
```typescript
// Prepare batch user operations
const uoCallData = await alchemyClient.buildUserOperation({
calls: [
{
target: "0x1234567890123456789012345678901234567890",
data: "0x",
value: parseEther("0.001")
}
]
});
// Send user operation
const { hash: uoHash } = await alchemyClient.sendUserOperation(uoCallData);
// Wait for confirmation
const txHash = await alchemyClient.waitForUserOperationTransaction({
hash: uoHash
});
console.log(`Smart wallet transaction: ${txHash}`);
```
## Implementation: EIP-7702
### Setup Para Client
```typescript
import { Para } from "@getpara/server-sdk";
import { createParaAccount, createParaViemClient } from "@getpara/viem";
// Initialize Para with pregenerated wallet
const para = new Para(process.env.PARA_API_KEY!);
// Load user share for pregenerated wallet
const userShare = await getUserShareFromDatabase(email);
await para.setUserShare(userShare);
// Create Para account with custom signing
const viemParaAccount = createParaAccount(para);
viemParaAccount.signMessage = async ({ message }) =>
customSignMessage(para, message);
```
```typescript
import { Para } from "@getpara/server-sdk";
import { createParaAccount, createParaViemClient } from "@getpara/viem";
// Initialize Para with active user session
const para = new Para(process.env.PARA_API_KEY!);
// Import existing user session
await para.importSession(userSession);
// Create Para account with custom signing
const viemParaAccount = createParaAccount(para);
viemParaAccount.signMessage = async ({ message }) =>
customSignMessage(para, message);
```
### Create EIP-7702 Client
```typescript
// Create Viem client
const viemClient = createParaViemClient(para, {
account: viemParaAccount,
chain: arbitrumSepolia,
transport: http(rpcUrl)
});
const walletClientSigner = new WalletClientSigner(viemClient, "para");
// Create EIP-7702 client - note the "mode" parameter
const alchemyClient = await createModularAccountV2Client({
mode: "7702", // This is the key difference
transport: alchemy({ rpcUrl: rpcUrl }),
chain: arbitrumSepolia,
signer: walletClientSigner,
policyId: alchemyGasPolicyId
});
```
### Execute EIP-7702 Transactions
```typescript
// EIP-7702 transactions are simpler
const txHash = await alchemyClient.sendTransaction({
calls: [
{
target: "0x1234567890123456789012345678901234567890",
data: "0x",
value: parseEther("0.001")
}
]
});
console.log(`EIP-7702 transaction: ${txHash}`);
```
## Signature Compatibility
Para's MPC signatures use 0/1 v-byte recovery, but smart wallet accounts expect 27/28. You need custom signing utilities:
### Custom Signature Utils
```typescript
// signature-utils.ts
const V_OFFSET_FOR_ETHEREUM = 27;
export async function customSignMessage(para: Para, message: string | Uint8Array) {
const messageToSign = typeof message === "string" ? message : toHex(message);
const signature = await para.signMessage(messageToSign);
// Parse signature components
const r = signature.slice(0, 64);
const s = signature.slice(64, 128);
let v = parseInt(signature.slice(128, 130), 16);
// Adjust v-byte for smart wallet compatibility
if (v < 27) {
v += V_OFFSET_FOR_ETHEREUM;
}
return `0x${r}${s}${v.toString(16).padStart(2, "0")}`;
}
export async function customSignAuthorization(para: Para, authorization: any) {
const signature = await para.signMessage(serializeAuthorization(authorization));
// Parse v-byte
const v = parseInt(signature.slice(128, 130), 16);
// EIP-7702 requires v-byte of 0 or 1
if (v !== 0 && v !== 1) {
throw new Error(`Invalid v value for EIP-7702: ${v}. Expected 0 or 1`);
}
return `0x${signature}`;
}
```
### Apply Custom Signing
```typescript
// Override Para account signing methods
viemParaAccount.signMessage = async ({ message }) =>
customSignMessage(para, message);
viemParaAccount.signTransaction = async (transaction) =>
customSignTransaction(para, transaction);
```
## Transaction Construction Best Practices
Para signs raw bytes without transaction validation. Ensure proper transaction construction:
### Type Safety
```typescript
// Ensure proper types before signing
const calls = [
{
target: getAddress("0x1234567890123456789012345678901234567890"), // Proper address format
data: "0x" as Hex, // Proper hex format
value: parseEther("0.001") // Proper bigint value
}
];
```
### Error Handling
```typescript
try {
const txHash = await alchemyClient.sendTransaction({ calls });
console.log(`Transaction successful: ${txHash}`);
} catch (error) {
if (error.message.includes("signature verification failed")) {
console.error("Signature issue - check v-byte adjustment");
} else if (error.message.includes("invalid transaction")) {
console.error("Transaction construction issue - check types and values");
}
throw error;
}
```
## Choosing the Right Approach
### Use Smart Wallet Accounts When:
* You need persistent smart contract functionality
* Your application requires complex access control
* You want to leverage established userOp infrastructure
* Gas sponsorship policies are account-specific
### Use EIP-7702 When:
* You want simpler transaction flows
* Gas sponsorship should go directly to EOAs
* You prefer avoiding permanent contract deployments
* Your use case fits temporary smart account capabilities
## Important Considerations
### Signature Recovery
* **Smart Wallet Accounts**: Expect 27/28 v-byte recovery (legacy Ethereum format)
* **EIP-7702**: Expects 0/1 v-byte recovery (modern format)
* **Para Default**: Produces 0/1 v-byte signatures (requires adjustment for smart wallets)
### Network Support
* EIP-7702 requires network support for the new transaction type
* Smart wallet accounts work on any EVM-compatible network
* Check Alchemy's documentation for current EIP-7702 network availability
### Gas Sponsorship
* Both approaches support Alchemy's gas sponsorship policies
* EIP-7702 sponsors the EOA directly
* Smart wallet accounts sponsor the smart contract address
## Additional Resources
For more detailed information about EIP-7702 implementation with Alchemy, see the [Alchemy Modular Account v2 EIP-7702 documentation](https://www.alchemy.com/docs/wallets/smart-contracts/modular-account-v2/using-7702).
## Next Steps
# Bulk Wallet Pregeneration for Twitter
Source: https://docs.getpara.com/v2/walkthroughs/bulk-pregeneration
Learn how to bulk pregenerate Para wallets for Twitter users and enable seamless wallet claiming
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Bulk pregeneration allows you to create Para wallets for multiple Twitter users ahead of time. Users can later claim these wallets by authenticating with their Twitter accounts, creating a seamless onboarding experience for airdrops, token distributions, or whitelist rewards.
## How Bulk Pregeneration Works
When you bulk pregenerate wallets:
1. **Generate wallets** for Twitter usernames using Para's server SDK
2. **Store user shares** securely on your backend
3. **Fund wallets** with tokens or NFTs for airdrops (optional)
4. **Users claim wallets** later by signing in with Twitter
5. **Para matches** the Twitter username to the pregenerated wallet
## Prerequisites
You need a Para API key and basic knowledge of Node.js/TypeScript development.
## Getting Twitter Usernames
You can obtain Twitter usernames for bulk pregeneration from various sources:
* **Database of pre-registered users** - Users who joined your whitelist or waitlist
* **Twitter API** - Programmatically fetch followers, mentions, or community members
* **CSV files** - Export from existing user databases or CRM systems
* **Contest participants** - Users who engaged with your Twitter campaigns
For this tutorial, we'll use a local CSV file as an example, but the core logic applies regardless of your data source.
## Server-Side Implementation
### Setup Para Server Client
First, create a Para server client to handle wallet generation:
```typescript lib/para-server.ts
import { Para } from "@getpara/server-sdk";
export function getParaServerClient() {
const apiKey = process.env.PARA_API_KEY;
if (!apiKey) {
throw new Error("PARA_API_KEY is required");
}
return new Para(apiKey);
}
```
### Create Bulk Generation API
Create an API endpoint to generate wallets for Twitter usernames:
```typescript api/wallet/generate/route.ts
import { getParaServerClient } from "@/lib/para-server";
import { NextResponse } from "next/server";
interface GenerateWalletRequest {
handle: string;
type: "TWITTER";
}
export async function POST(request: Request) {
try {
const { handle, type }: GenerateWalletRequest = await request.json();
if (!handle || type !== "TWITTER") {
return NextResponse.json({ error: "Invalid handle or type" }, { status: 400 });
}
const para = getParaServerClient();
const wallet = await para.createPregenWallet({
type: "EVM",
pregenId: { xUsername: handle.trim() }
});
const userShare = await para.getUserShare();
if (!wallet || !userShare) {
throw new Error("Failed to generate wallet");
}
await storeWalletData(handle.trim(), wallet, userShare);
return NextResponse.json({
success: true,
handle: handle.trim(),
address: wallet.address
});
} catch (error) {
console.error("Wallet generation error:", error);
return NextResponse.json({ error: "Generation failed" }, { status: 500 });
}
}
async function storeWalletData(handle: string, wallet: any, userShare: any) {
// Store wallet and user share in your database
// This is critical for users to claim their wallets later
}
```
### Batch Processing Implementation
For processing multiple handles efficiently:
```typescript hooks/use-batch-processor.ts
import { useState } from "react";
interface BatchResult {
handle: string;
success: boolean;
address?: string;
error?: string;
}
export function useBatchProcessor() {
const [processing, setProcessing] = useState(false);
const [results, setResults] = useState([]);
const [progress, setProgress] = useState(0);
const processBatch = async (handles: string[]) => {
setProcessing(true);
setResults([]);
setProgress(0);
const batchSize = 10;
const batches = [];
for (let i = 0; i < handles.length; i += batchSize) {
batches.push(handles.slice(i, i + batchSize));
}
const allResults: BatchResult[] = [];
for (let i = 0; i < batches.length; i++) {
const batch = batches[i];
const batchResults = await Promise.all(
batch.map(async (handle) => {
try {
const response = await fetch("/api/wallet/generate", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ handle, type: "TWITTER" })
});
const data = await response.json();
return {
handle,
success: data.success,
address: data.address,
error: data.error
};
} catch (error) {
return {
handle,
success: false,
error: "Network error"
};
}
})
);
allResults.push(...batchResults);
setResults([...allResults]);
setProgress(((i + 1) / batches.length) * 100);
// Rate limiting delay
if (i < batches.length - 1) {
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
setProcessing(false);
};
return {
processing,
results,
progress,
processBatch
};
}
```
## Alternative Data Sources
### From Database
You can fetch usernames directly from your database:
```typescript
// Example: Fetch whitelist users from database
async function getWhitelistUsers() {
const users = await db.users.findMany({
where: { whitelisted: true },
select: { twitterUsername: true }
});
return users.map(user => user.twitterUsername).filter(Boolean);
}
```
### From Twitter API
Programmatically fetch Twitter usernames:
```typescript
// Example: Get followers using Twitter API
async function getFollowers(userId: string) {
const response = await fetch(`https://api.twitter.com/2/users/${userId}/followers`, {
headers: {
'Authorization': `Bearer ${process.env.TWITTER_BEARER_TOKEN}`
}
});
const data = await response.json();
return data.data?.map((user: any) => user.username) || [];
}
```
### Example: CSV Processing
For this tutorial, we'll demonstrate with a CSV file containing Twitter handles:
```csv
handle,type
@username1,twitter
@username2,twitter
username3,twitter
```
The `@` symbol is optional and will be automatically handled. Headers are also optional.
## Frontend Considerations
While the UI implementation depends on your application's design system, consider these patterns:
* **Progress tracking** - Show real-time batch processing status
* **Error handling** - Display failed generations with retry options
* **Results export** - Allow downloading generation results
* **Batch size control** - Let users adjust processing batch sizes
The core logic remains the same regardless of your UI framework choice.
## Important Considerations
### Rate Limiting
Para's API has rate limits. Process handles in batches with delays:
```typescript
// Process 10 handles at a time with 1-second delays
const batchSize = 10;
const delay = 1000; // 1 second between batches
```
### Error Handling
Always implement retry logic for failed generations:
```typescript
const retryFailed = async (failedResults: BatchResult[]) => {
const failedHandles = failedResults
.filter(result => !result.success)
.map(result => result.handle);
// Retry processing
await processBatch(failedHandles);
};
```
### Data Storage
Store wallet data securely in your database:
* **Wallet addresses** for reference
* **User shares** for wallet claiming
* **Handle mappings** for Twitter username lookup
* **Generation timestamps** for tracking
## Testing Your Implementation
1. **Start with small batches** (5-10 handles)
2. **Use test Twitter handles** that you control
3. **Verify wallet generation** in Para Developer Portal
4. **Test claiming flow** with actual Twitter authentication
## Next Steps
# Chrome Extension Integration with Para
Source: https://docs.getpara.com/v2/walkthroughs/chrome-extension-integration
Learn how to build Chrome extensions with Para, including state persistence, background workers, and seamless user authentication
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Building Chrome extensions with Para requires special considerations for state persistence and user experience. This walkthrough covers how to implement Chrome storage overrides, background workers, and seamless authentication flows.
## Chrome Extension Challenges
Chrome extensions present unique challenges for web applications:
* **State resets** - Clicking outside a popup can close and reset the application state
* **Limited popup space** - Small popup windows aren't ideal for complex authentication flows
* **Background execution** - Background workers need access to authentication state
* **Storage limitations** - Standard localStorage/sessionStorage APIs work differently in extensions
## Solution Overview
Para addresses these challenges through:
1. **Storage overrides** - Custom storage implementations using Chrome extension APIs
2. **Singleton promise pattern** - Shared Para instance across popup and background
3. **Smart routing** - Background worker decides between popup vs tab based on auth state
4. **State persistence** - Authentication state survives popup closures
## Setup and Configuration
### Install Dependencies
```bash
npm install @getpara/react-sdk
```
### Create Chrome Storage Overrides
Create a storage implementation that uses Chrome extension storage APIs:
```typescript lib/chrome-storage.ts
// Chrome local storage overrides
export const localStorageGetItemOverride = async (key: string): Promise => {
try {
// Handle special cases
if (key === "guestWalletIds" || key === "pregenIds") {
return JSON.stringify({});
}
const result = await chrome.storage.local.get([key]);
return result[key] || null;
} catch (error) {
console.error("Local storage get error:", error);
return null;
}
};
export const localStorageSetItemOverride = async (key: string, value: string): Promise => {
try {
await chrome.storage.local.set({ [key]: value });
} catch (error) {
console.error("Local storage set error:", error);
}
};
export const localStorageRemoveItemOverride = async (key: string): Promise => {
try {
await chrome.storage.local.remove([key]);
} catch (error) {
console.error("Local storage remove error:", error);
}
};
// Chrome session storage overrides
export const sessionStorageGetItemOverride = async (key: string): Promise => {
try {
if (key === "guestWalletIds" || key === "pregenIds") {
return JSON.stringify({});
}
const result = await chrome.storage.session.get([key]);
return result[key] || null;
} catch (error) {
console.error("Session storage get error:", error);
return null;
}
};
export const sessionStorageSetItemOverride = async (key: string, value: string): Promise => {
try {
await chrome.storage.session.set({ [key]: value });
} catch (error) {
console.error("Session storage set error:", error);
}
};
export const sessionStorageRemoveItemOverride = async (key: string): Promise => {
try {
await chrome.storage.session.remove([key]);
} catch (error) {
console.error("Session storage remove error:", error);
}
};
// Clear storage with Para prefix
export const clearStorageOverride = async (): Promise => {
try {
// Get all keys from both storages
const [localKeys, sessionKeys] = await Promise.all([
chrome.storage.local.get(),
chrome.storage.session.get()
]);
// Filter keys with Para prefix
const paraLocalKeys = Object.keys(localKeys).filter(key => key.startsWith("@CAPSULE/"));
const paraSessionKeys = Object.keys(sessionKeys).filter(key => key.startsWith("@CAPSULE/"));
// Remove Para keys
await Promise.all([
paraLocalKeys.length > 0 ? chrome.storage.local.remove(paraLocalKeys) : Promise.resolve(),
paraSessionKeys.length > 0 ? chrome.storage.session.remove(paraSessionKeys) : Promise.resolve()
]);
} catch (error) {
console.error("Clear storage error:", error);
}
};
// Export all overrides as a single object
export const chromeStorageOverrides = {
localStorageGetItemOverride,
localStorageSetItemOverride,
localStorageRemoveItemOverride,
sessionStorageGetItemOverride,
sessionStorageSetItemOverride,
sessionStorageRemoveItemOverride,
clearStorageOverride
};
```
### Configure Para Client
Create a singleton Para client with Chrome storage overrides:
```typescript lib/para/client.ts
import { ParaWeb } from "@getpara/react-sdk";
import { chromeStorageOverrides } from "../chrome-storage";
const PARA_API_KEY = process.env.NEXT_PUBLIC_PARA_API_KEY || "your-api-key";
// Create Para instance with Chrome storage overrides
export const para = new ParaWeb(PARA_API_KEY, {
...chromeStorageOverrides,
useStorageOverrides: true,
});
// Export shared promise for initialization
export const paraReady = para.init();
```
### Background Worker Implementation
Create a background worker that manages authentication flows:
```typescript background.ts
import { para, paraReady } from "@/lib/para/client";
// Handle extension icon clicks
chrome.action.onClicked.addListener(async () => {
try {
// Wait for Para to be ready
await paraReady;
// Check authentication status
const isLoggedIn = await para.isFullyLoggedIn();
console.log("User authentication status:", isLoggedIn);
if (!isLoggedIn) {
// User not authenticated - open full tab for login
chrome.tabs.create({
url: chrome.runtime.getURL("index.html")
});
} else {
// User authenticated - open popup for quick actions
await chrome.action.setPopup({ popup: "index.html" });
await chrome.action.openPopup();
// Reset popup after opening (allows clicking icon again)
await chrome.action.setPopup({ popup: "" });
}
} catch (error) {
console.error("Authentication check failed:", error);
// Fallback to tab on error
chrome.tabs.create({
url: chrome.runtime.getURL("index.html")
});
}
});
// Optional: Handle installation
chrome.runtime.onInstalled.addListener(async () => {
console.log("Extension installed");
// Initialize Para on installation
try {
await paraReady;
console.log("Para initialized successfully");
} catch (error) {
console.error("Para initialization failed:", error);
}
});
```
## Manifest Configuration
Create a `manifest.json` file for your Chrome extension:
```json manifest.json
{
"manifest_version": 3,
"name": "Para Chrome Extension",
"version": "1.0",
"description": "Chrome extension with Para authentication",
"permissions": [
"storage",
"activeTab"
],
"background": {
"service_worker": "background.js",
"type": "module"
},
"action": {
"default_title": "Para Extension"
},
"content_security_policy": {
"extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self';"
},
"web_accessible_resources": [
{
"resources": ["index.html"],
"matches": [""]
}
]
}
```
## Application Setup
### Main Application Component
```typescript components/App.tsx
import { useEffect, useState } from "react";
import { para, paraReady } from "@/lib/para/client";
import { useAccount } from "@getpara/react-sdk";
export function App() {
const [isReady, setIsReady] = useState(false);
const { data: account } = useAccount();
useEffect(() => {
// Wait for Para initialization
paraReady.then(() => {
setIsReady(true);
}).catch((error) => {
console.error("Para initialization failed:", error);
setIsReady(true); // Show UI even on error
});
}, []);
if (!isReady) {
return (
);
}
return (
{account?.isConnected ? (
) : (
)}
);
}
function AuthenticatedView() {
const { data: account } = useAccount();
return (
Welcome Back!
Address: {account?.address}
para.logout()}
className="mt-4 px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600"
>
Logout
);
}
function LoginView() {
const handleLogin = async () => {
try {
await para.signUpOrLogin();
} catch (error) {
console.error("Login failed:", error);
}
};
return (
Para Chrome Extension
Sign in to get started
Sign In with Para
);
}
```
### Para Provider Setup
```typescript components/ParaProvider.tsx
import { ParaProvider as BaseParaProvider } from "@getpara/react-sdk";
import { para } from "@/lib/para/client";
interface ParaProviderProps {
children: React.ReactNode;
}
export function ParaProvider({ children }: ParaProviderProps) {
return (
{children}
);
}
```
## User Experience Patterns
### Smart Authentication Flow
The background worker implements smart routing based on authentication state:
```typescript
// Pseudocode for authentication flow decision
if (userNotAuthenticated) {
// Open full tab - more space for authentication
openTab("index.html");
} else {
// Open popup - quick access for authenticated users
openPopup("index.html");
}
```
### State Persistence
Para state persists across popup sessions:
```typescript
// User clicks extension icon
// -> Popup opens with preserved authentication state
// -> User interacts with popup
// -> User clicks outside, popup closes
// -> User clicks extension icon again
// -> Popup reopens with same state (no re-authentication needed)
```
### Error Handling
Implement robust error handling for extension-specific scenarios:
```typescript
const handleExtensionError = (error: Error) => {
console.error("Extension error:", error);
// Always fallback to tab on critical errors
chrome.tabs.create({
url: chrome.runtime.getURL("index.html")
});
};
```
## Building and Deployment
### Build Configuration
Configure your build tool (Webpack, Vite, etc.) for Chrome extension:
```javascript webpack.config.js
module.exports = {
entry: {
background: './src/background.ts',
content: './src/index.tsx'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
},
// ... other webpack configuration
};
```
### Development Testing
1. **Build your extension**:
```bash
npm run build
```
2. **Load in Chrome**:
* Open `chrome://extensions/`
* Enable "Developer mode"
* Click "Load unpacked"
* Select your `dist` folder
3. **Test authentication flows**:
* Click extension icon when logged out (should open tab)
* Complete authentication
* Click extension icon when logged in (should open popup)
### Production Considerations
* **Permissions**: Only request necessary permissions in manifest
* **CSP**: Configure Content Security Policy for WASM and external resources
* **Error reporting**: Implement error tracking for production
* **Performance**: Optimize background worker to minimize resource usage
## Advanced Features
### Tab Communication
Communicate between popup and tabs:
```typescript
// In popup
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
chrome.tabs.sendMessage(tabs[0].id!, {
type: "PARA_AUTH_STATUS",
isAuthenticated: true
});
});
// In content script
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === "PARA_AUTH_STATUS") {
// Handle authentication status update
updateUIBasedOnAuth(message.isAuthenticated);
}
});
```
### Context Menus
Add context menu integration:
```typescript
// In background.ts
chrome.contextMenus.create({
id: "para-action",
title: "Sign with Para",
contexts: ["selection"]
});
chrome.contextMenus.onClicked.addListener(async (info, tab) => {
if (info.menuItemId === "para-action") {
// Handle context menu action
await paraReady;
const isLoggedIn = await para.isFullyLoggedIn();
if (isLoggedIn) {
// Perform action with selected text
console.log("Selected text:", info.selectionText);
}
}
});
```
## Troubleshooting
### Common Issues
**Storage not persisting**:
* Ensure `useStorageOverrides: true` is set
* Check Chrome storage permissions in manifest
* Verify storage override functions are async
**Background worker not receiving state**:
* Confirm `paraReady` promise is properly awaited
* Check console for initialization errors
* Verify manifest background configuration
**Popup closing unexpectedly**:
* This is expected Chrome behavior
* Use tabs for complex flows
* Implement state persistence with storage overrides
## Next Steps
# EIP-712 Typed Data Signing with Para
Source: https://docs.getpara.com/v2/walkthroughs/eip712-typed-data-signing
Learn how to sign structured, typed data using EIP-712 standard with Para's Ethers integration
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
EIP-712 enables signing complex, structured data in a standardized way, providing better security and user experience compared to simple message signing. This walkthrough shows how to implement EIP-712 typed data signing using Para's Ethers integration.
## What is EIP-712?
EIP-712 is a standard for signing typed structured data, offering several advantages:
* **Structured data signing** - Sign complex objects with multiple fields and nested structures
* **Domain separation** - Prevents signature replay attacks across different applications or chains
* **Human-readable format** - Users can see exactly what they're signing in wallet interfaces
* **Type safety** - Ensures data conforms to expected structure before signing
## Common Use Cases
EIP-712 is commonly used for:
* **Meta-transactions** - Gasless transactions with relayer support
* **Permit signatures** - Token approvals without on-chain transactions
* **Attestations** - Cryptographically signed claims or certificates
* **Voting systems** - Off-chain voting with on-chain verification
* **Order signing** - DEX orders and marketplace listings
## Setup Requirements
You need an authenticated Para client and Ethers provider to implement EIP-712 signing.
### Install Dependencies
```bash
npm install @getpara/react-sdk @getpara/ethers-v6-integration ethers
```
### Create Ethers Provider Hook
```typescript hooks/useEthersProvider.ts
import { useMemo } from "react";
import { ethers } from "ethers";
const RPC_URL = process.env.NEXT_PUBLIC_RPC_URL ||
"https://ethereum-holesky-rpc.publicnode.com";
export function useEthersProvider() {
const provider = useMemo(() => {
return new ethers.JsonRpcProvider(RPC_URL);
}, []);
return { provider };
}
```
### Create Para Signer Hook
```typescript hooks/useParaSigner.ts
import { useState, useEffect } from "react";
import { ParaEthersSigner } from "@getpara/ethers-v6-integration";
import { useAccount, useClient } from "@getpara/react-sdk";
import { useEthersProvider } from "./useEthersProvider";
export function useParaSigner() {
const { data: account } = useAccount();
const client = useClient();
const { provider } = useEthersProvider();
const [signer, setSigner] = useState(null);
useEffect(() => {
if (account?.isConnected && provider && client) {
try {
const newSigner = new ParaEthersSigner(client, provider);
setSigner(newSigner);
} catch (error) {
console.error("Failed to initialize Para signer:", error);
setSigner(null);
}
} else {
setSigner(null);
}
}, [account?.isConnected, provider, client]);
return { signer, provider };
}
```
## EIP-712 Implementation
### Define Domain and Types
The domain separator provides context and prevents replay attacks:
```typescript
// Domain definition - provides context for the signature
const domain = {
name: "MyDApp", // Application name
version: "1", // Version of signing domain
chainId: 17000, // Network chain ID (Holesky testnet)
verifyingContract: "0x..." as Address // Contract that will verify signatures
};
// Types definition - structure of the data being signed
const types = {
TokenAttestation: [
{ name: "holder", type: "address" },
{ name: "balance", type: "string" },
{ name: "purpose", type: "string" },
{ name: "timestamp", type: "uint256" },
{ name: "nonce", type: "uint256" }
]
};
```
### Create Typed Data Structure
```typescript
interface TokenAttestation {
holder: string;
balance: string;
purpose: string;
timestamp: number;
nonce: number;
}
// Create the data object to sign
const attestation: TokenAttestation = {
holder: "0x742d35Cc6634C0532925a3b8D756e3C98d8a3a1B",
balance: "1000.5",
purpose: "Identity verification",
timestamp: Math.floor(Date.now() / 1000),
nonce: 1
};
```
### Sign Typed Data
```typescript
import { useParaSigner } from "./hooks/useParaSigner";
export function TypedDataSigning() {
const { signer } = useParaSigner();
const [signature, setSignature] = useState("");
const [isLoading, setIsLoading] = useState(false);
const signAttestation = async () => {
if (!signer) {
throw new Error("Signer not available");
}
setIsLoading(true);
try {
// Sign the typed data
const signature = await signer.signTypedData(domain, types, attestation);
setSignature(signature);
console.log("Signed attestation:", signature);
} catch (error) {
console.error("Signing failed:", error);
} finally {
setIsLoading(false);
}
};
return (
{isLoading ? "Signing..." : "Sign Attestation"}
{signature && (
Signature:
{signature}
)}
);
}
```
## Advanced Examples
### Permit Signature for Token Approvals
```typescript
// EIP-2612 Permit signature
const permitTypes = {
Permit: [
{ name: "owner", type: "address" },
{ name: "spender", type: "address" },
{ name: "value", type: "uint256" },
{ name: "nonce", type: "uint256" },
{ name: "deadline", type: "uint256" }
]
};
const permitData = {
owner: userAddress,
spender: spenderAddress,
value: ethers.parseUnits("100", 18),
nonce: await token.nonces(userAddress),
deadline: Math.floor(Date.now() / 1000) + 3600 // 1 hour
};
const permitSignature = await signer.signTypedData(
{
name: "MyToken",
version: "1",
chainId: 1,
verifyingContract: tokenAddress
},
permitTypes,
permitData
);
```
### Voting Signature
```typescript
const voteTypes = {
Vote: [
{ name: "proposalId", type: "uint256" },
{ name: "support", type: "bool" },
{ name: "voter", type: "address" },
{ name: "reason", type: "string" },
{ name: "timestamp", type: "uint256" }
]
};
const voteData = {
proposalId: 42,
support: true,
voter: userAddress,
reason: "I support this proposal",
timestamp: Math.floor(Date.now() / 1000)
};
const voteSignature = await signer.signTypedData(domain, voteTypes, voteData);
```
### Marketplace Order Signature
```typescript
const orderTypes = {
Order: [
{ name: "seller", type: "address" },
{ name: "buyer", type: "address" },
{ name: "tokenContract", type: "address" },
{ name: "tokenId", type: "uint256" },
{ name: "price", type: "uint256" },
{ name: "deadline", type: "uint256" },
{ name: "nonce", type: "uint256" }
]
};
const orderData = {
seller: userAddress,
buyer: "0x0000000000000000000000000000000000000000", // Any buyer
tokenContract: nftContractAddress,
tokenId: 123,
price: ethers.parseEther("1.5"),
deadline: Math.floor(Date.now() / 1000) + 86400, // 24 hours
nonce: 1
};
const orderSignature = await signer.signTypedData(domain, orderTypes, orderData);
```
## Signature Verification
### Client-Side Verification
```typescript
import { ethers } from "ethers";
async function verifySignature(
domain: any,
types: any,
data: any,
signature: string,
expectedSigner: string
) {
try {
const recoveredSigner = ethers.verifyTypedData(domain, types, data, signature);
return recoveredSigner.toLowerCase() === expectedSigner.toLowerCase();
} catch (error) {
console.error("Verification failed:", error);
return false;
}
}
// Usage
const isValid = await verifySignature(
domain,
types,
attestation,
signature,
userAddress
);
console.log("Signature valid:", isValid);
```
### Smart Contract Verification
```solidity
// Solidity contract for verifying EIP-712 signatures
contract AttestationVerifier {
bytes32 private constant ATTESTATION_TYPEHASH = keccak256(
"TokenAttestation(address holder,string balance,string purpose,uint256 timestamp,uint256 nonce)"
);
bytes32 private immutable DOMAIN_SEPARATOR;
constructor() {
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes("MyDApp")),
keccak256(bytes("1")),
block.chainid,
address(this)
)
);
}
function verifyAttestation(
TokenAttestation memory attestation,
uint8 v,
bytes32 r,
bytes32 s
) public view returns (address) {
bytes32 structHash = keccak256(
abi.encode(
ATTESTATION_TYPEHASH,
attestation.holder,
keccak256(bytes(attestation.balance)),
keccak256(bytes(attestation.purpose)),
attestation.timestamp,
attestation.nonce
)
);
bytes32 digest = keccak256(
abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, structHash)
);
return ecrecover(digest, v, r, s);
}
}
```
## Error Handling
### Common Issues and Solutions
```typescript
const signWithErrorHandling = async () => {
try {
const signature = await signer.signTypedData(domain, types, data);
return signature;
} catch (error) {
if (error.code === 'ACTION_REJECTED') {
console.log("User rejected the signing request");
} else if (error.message.includes('invalid domain')) {
console.error("Domain configuration error:", error);
} else if (error.message.includes('invalid types')) {
console.error("Types definition error:", error);
} else {
console.error("Unexpected signing error:", error);
}
throw error;
}
};
```
### Validation Before Signing
```typescript
function validateTypedData(domain: any, types: any, data: any) {
// Validate domain
if (!domain.name || !domain.version || !domain.chainId) {
throw new Error("Invalid domain: missing required fields");
}
// Validate types
if (!types || Object.keys(types).length === 0) {
throw new Error("Invalid types: empty or undefined");
}
// Validate data matches types
const primaryType = Object.keys(types)[0];
const typeFields = types[primaryType];
for (const field of typeFields) {
if (!(field.name in data)) {
throw new Error(`Missing required field: ${field.name}`);
}
}
return true;
}
```
## Best Practices
### Security Considerations
* **Validate all inputs** before signing
* **Use proper domain separation** to prevent replay attacks
* **Include nonces** to prevent signature reuse
* **Set reasonable deadlines** for time-sensitive signatures
* **Verify contract addresses** in domain separator
### Type Definition Guidelines
* **Use specific types** (uint256 instead of uint)
* **Order fields consistently** across your application
* **Document field purposes** for maintainability
* **Version your types** when making changes
### User Experience
* **Provide clear descriptions** of what users are signing
* **Show human-readable summaries** before signing
* **Handle rejection gracefully** with meaningful error messages
* **Cache signatures** when appropriate to avoid re-signing
## Next Steps
# Ethereum Transfers with Para
Source: https://docs.getpara.com/v2/walkthroughs/ethereum-transfers
Learn how to send ETH transactions using Para with both Ethers and Viem libraries
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
This walkthrough covers sending basic Ethereum transfers using Para with both Ethers v6 and Viem v2. You'll learn transaction construction, gas estimation, and signing patterns for each library.
## Prerequisites
You need an authenticated Para client and basic knowledge of Ethereum transactions.
## Core Dependencies
```bash
npm install @getpara/react-sdk @getpara/ethers-v6-integration ethers
```
```bash
npm install @getpara/react-sdk @getpara/viem viem
```
## Provider Setup
### RPC Configuration
```typescript
import { ethers } from "ethers";
const RPC_URL = process.env.NEXT_PUBLIC_HOLESKY_RPC_URL ||
"https://ethereum-holesky-rpc.publicnode.com";
// Create JSON RPC provider
const provider = new ethers.JsonRpcProvider(RPC_URL);
```
```typescript
import { createPublicClient, http } from "viem";
import { holesky } from "viem/chains";
const RPC_URL = process.env.NEXT_PUBLIC_HOLESKY_RPC_URL ||
"https://ethereum-holesky-rpc.publicnode.com";
// Create public client for read operations
const publicClient = createPublicClient({
chain: holesky,
transport: http(RPC_URL)
});
```
### Para Signer Setup
```typescript
import { ParaEthersSigner } from "@getpara/ethers-v6-integration";
import { useAccount, useClient } from "@getpara/react-sdk";
// Get Para client and account
const client = useClient();
const { data: account } = useAccount();
// Create Para Ethers signer
let signer: ParaEthersSigner | null = null;
if (account?.isConnected && provider && client) {
signer = new ParaEthersSigner(client, provider);
}
```
```typescript
import { createParaAccount, createParaViemClient } from "@getpara/viem";
import { useAccount, useClient } from "@getpara/react-sdk";
// Get Para client and account
const client = useClient();
const { data: account } = useAccount();
// Create Para Viem account and wallet client
let walletClient: any = null;
if (account?.isConnected && client) {
const viemAccount = createParaAccount(client);
walletClient = createParaViemClient(client, {
account: viemAccount,
chain: holesky,
transport: http(RPC_URL)
});
}
```
## Transaction Construction
### Basic Transaction Parameters
```typescript
import { parseEther, toBigInt } from "ethers";
const constructTransaction = async (
toAddress: string,
ethAmount: string,
userAddress: string
) => {
// Get transaction parameters
const nonce = await provider.getTransactionCount(userAddress);
const feeData = await provider.getFeeData();
const gasLimit = toBigInt(21000); // Standard ETH transfer gas
const value = parseEther(ethAmount);
// Construct transaction object
const transaction = {
to: toAddress,
value: value,
nonce: nonce,
gasLimit: gasLimit,
maxFeePerGas: feeData.maxFeePerGas,
maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
chainId: 17000, // Holesky chain ID
};
return transaction;
};
```
```typescript
import { parseEther, parseGwei } from "viem";
const constructTransaction = (
toAddress: `0x${string}`,
ethAmount: string,
userAddress: `0x${string}`
) => {
// Construct transaction object
const transaction = {
account: userAddress,
to: toAddress,
value: parseEther(ethAmount),
chain: holesky,
maxFeePerGas: parseGwei("100"), // Custom max fee
maxPriorityFeePerGas: parseGwei("3") // Custom priority fee
};
return transaction;
};
```
## Gas Estimation
### Estimate Transaction Cost
```typescript
import { formatEther } from "ethers";
const estimateTransactionCost = async (
userAddress: string,
ethAmount: string
) => {
// Get current balance
const balanceWei = await provider.getBalance(userAddress);
// Get fee data
const feeData = await provider.getFeeData();
const gasLimit = toBigInt(21000);
// Calculate max gas cost
const maxGasFee = gasLimit * (feeData.maxFeePerGas ?? toBigInt(0));
const amountWei = parseEther(ethAmount);
const totalCost = amountWei + maxGasFee;
return {
balance: formatEther(balanceWei),
amount: formatEther(amountWei),
estimatedGas: formatEther(maxGasFee),
totalCost: formatEther(totalCost),
hasSufficientBalance: totalCost <= balanceWei
};
};
```
```typescript
import { formatEther, parseEther } from "viem";
const estimateTransactionCost = async (
userAddress: `0x${string}`,
toAddress: `0x${string}`,
ethAmount: string
) => {
// Get current balance
const balance = await publicClient.getBalance({ address: userAddress });
const amountWei = parseEther(ethAmount);
// Estimate gas for the specific transaction
const estimatedGas = await publicClient.estimateGas({
account: userAddress,
to: toAddress,
value: amountWei
});
// Get current gas price
const gasPrice = await publicClient.getGasPrice();
const estimatedGasCost = estimatedGas * gasPrice;
const totalCost = amountWei + estimatedGasCost;
return {
balance: formatEther(balance),
amount: formatEther(amountWei),
estimatedGas: formatEther(estimatedGasCost),
totalCost: formatEther(totalCost),
hasSufficientBalance: totalCost <= balance
};
};
```
## Transaction Validation
### Balance and Parameter Checks
```typescript
const validateTransaction = async (
userAddress: string,
toAddress: string,
ethAmount: string
) => {
// Basic parameter validation
if (!ethers.isAddress(toAddress)) {
throw new Error("Invalid recipient address");
}
if (parseFloat(ethAmount) <= 0) {
throw new Error("Amount must be greater than 0");
}
// Check balance and gas
const estimation = await estimateTransactionCost(userAddress, ethAmount);
if (!estimation.hasSufficientBalance) {
throw new Error(
`Insufficient balance. Need ${estimation.totalCost} ETH, have ${estimation.balance} ETH`
);
}
return true;
};
```
```typescript
import { isAddress } from "viem";
const validateTransaction = async (
userAddress: `0x${string}`,
toAddress: string,
ethAmount: string
) => {
// Basic parameter validation
if (!isAddress(toAddress)) {
throw new Error("Invalid recipient address");
}
if (parseFloat(ethAmount) <= 0) {
throw new Error("Amount must be greater than 0");
}
// Check balance and gas
const estimation = await estimateTransactionCost(
userAddress,
toAddress as `0x${string}`,
ethAmount
);
if (!estimation.hasSufficientBalance) {
throw new Error(
`Insufficient balance. Need ${estimation.totalCost} ETH, have ${estimation.balance} ETH`
);
}
return true;
};
```
## Sending Transactions
### Execute Transfer
```typescript
const sendEthTransfer = async (
toAddress: string,
ethAmount: string,
userAddress: string
) => {
// Validate transaction
await validateTransaction(userAddress, toAddress, ethAmount);
// Construct transaction
const transaction = await constructTransaction(toAddress, ethAmount, userAddress);
// Send transaction using Para signer
const txResponse = await signer.sendTransaction(transaction);
console.log("Transaction sent:", txResponse.hash);
// Wait for confirmation
const receipt = await txResponse.wait();
console.log("Transaction confirmed:", receipt.hash);
console.log("Block number:", receipt.blockNumber);
console.log("Gas used:", receipt.gasUsed.toString());
return {
hash: receipt.hash,
blockNumber: receipt.blockNumber,
gasUsed: receipt.gasUsed.toString(),
status: receipt.status === 1 ? "success" : "failed"
};
};
```
```typescript
const sendEthTransfer = async (
toAddress: `0x${string}`,
ethAmount: string,
userAddress: `0x${string}`
) => {
// Validate transaction
await validateTransaction(userAddress, toAddress, ethAmount);
// Send transaction using Para wallet client
const hash = await walletClient.sendTransaction({
account: userAddress,
to: toAddress,
value: parseEther(ethAmount),
chain: holesky,
maxFeePerGas: parseGwei("100"),
maxPriorityFeePerGas: parseGwei("3")
});
console.log("Transaction sent:", hash);
// Wait for confirmation
const receipt = await publicClient.waitForTransactionReceipt({ hash });
console.log("Transaction confirmed:", receipt.transactionHash);
console.log("Block number:", receipt.blockNumber);
console.log("Gas used:", receipt.gasUsed.toString());
return {
hash: receipt.transactionHash,
blockNumber: receipt.blockNumber,
gasUsed: receipt.gasUsed.toString(),
status: receipt.status === "success" ? "success" : "failed"
};
};
```
## Complete Implementation Example
### Full Transfer Function
```typescript
import { ethers, parseEther, formatEther, toBigInt } from "ethers";
import { ParaEthersSigner } from "@getpara/ethers-v6-integration";
class EthersTransferService {
private provider: ethers.JsonRpcProvider;
private signer: ParaEthersSigner;
constructor(rpcUrl: string, paraClient: any) {
this.provider = new ethers.JsonRpcProvider(rpcUrl);
this.signer = new ParaEthersSigner(paraClient, this.provider);
}
async transfer(toAddress: string, ethAmount: string, fromAddress: string) {
try {
// Validate inputs
if (!ethers.isAddress(toAddress)) {
throw new Error("Invalid recipient address");
}
// Check balance
const balance = await this.provider.getBalance(fromAddress);
const amount = parseEther(ethAmount);
const feeData = await this.provider.getFeeData();
const gasLimit = toBigInt(21000);
const maxGasFee = gasLimit * (feeData.maxFeePerGas ?? toBigInt(0));
if (balance < amount + maxGasFee) {
throw new Error("Insufficient balance for transfer and gas");
}
// Construct and send transaction
const nonce = await this.provider.getTransactionCount(fromAddress);
const transaction = {
to: toAddress,
value: amount,
nonce: nonce,
gasLimit: gasLimit,
maxFeePerGas: feeData.maxFeePerGas,
maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
chainId: 17000
};
const txResponse = await this.signer.sendTransaction(transaction);
const receipt = await txResponse.wait();
return {
success: true,
hash: receipt.hash,
blockNumber: receipt.blockNumber,
gasUsed: receipt.gasUsed.toString()
};
} catch (error) {
console.error("Transfer failed:", error);
throw error;
}
}
}
```
```typescript
import {
createPublicClient,
createParaViemClient,
createParaAccount,
http,
parseEther,
formatEther,
parseGwei,
isAddress
} from "viem";
import { holesky } from "viem/chains";
class ViemTransferService {
private publicClient: any;
private walletClient: any;
constructor(rpcUrl: string, paraClient: any) {
this.publicClient = createPublicClient({
chain: holesky,
transport: http(rpcUrl)
});
const account = createParaAccount(paraClient);
this.walletClient = createParaViemClient(paraClient, {
account,
chain: holesky,
transport: http(rpcUrl)
});
}
async transfer(
toAddress: `0x${string}`,
ethAmount: string,
fromAddress: `0x${string}`
) {
try {
// Validate inputs
if (!isAddress(toAddress)) {
throw new Error("Invalid recipient address");
}
// Check balance and estimate gas
const balance = await this.publicClient.getBalance({ address: fromAddress });
const amount = parseEther(ethAmount);
const estimatedGas = await this.publicClient.estimateGas({
account: fromAddress,
to: toAddress,
value: amount
});
const gasPrice = await this.publicClient.getGasPrice();
const estimatedGasCost = estimatedGas * gasPrice;
if (balance < amount + estimatedGasCost) {
throw new Error("Insufficient balance for transfer and gas");
}
// Send transaction
const hash = await this.walletClient.sendTransaction({
account: fromAddress,
to: toAddress,
value: amount,
chain: holesky,
maxFeePerGas: parseGwei("100"),
maxPriorityFeePerGas: parseGwei("3")
});
const receipt = await this.publicClient.waitForTransactionReceipt({ hash });
return {
success: true,
hash: receipt.transactionHash,
blockNumber: receipt.blockNumber,
gasUsed: receipt.gasUsed.toString()
};
} catch (error) {
console.error("Transfer failed:", error);
throw error;
}
}
}
```
## Key Differences
### Library Comparison
| Feature | Ethers v6 | Viem v2 |
| ---------------------- | -------------------------- | ------------------------------------------ |
| **Provider Setup** | `JsonRpcProvider` | `createPublicClient` |
| **Wallet Client** | `ParaEthersSigner` | `createParaViemClient` |
| **Unit Parsing** | `parseEther()` | `parseEther()` |
| **Gas Estimation** | `getFeeData()` | `estimateGas()` + `getGasPrice()` |
| **Transaction Send** | `signer.sendTransaction()` | `walletClient.sendTransaction()` |
| **Receipt Waiting** | `txResponse.wait()` | `publicClient.waitForTransactionReceipt()` |
| **Address Validation** | `ethers.isAddress()` | `isAddress()` |
### Gas Strategy Differences
```typescript
// Ethers uses provider fee data
const feeData = await provider.getFeeData();
const transaction = {
maxFeePerGas: feeData.maxFeePerGas,
maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
};
```
```typescript
// Viem allows manual gas price setting
const transaction = {
maxFeePerGas: parseGwei("100"),
maxPriorityFeePerGas: parseGwei("3")
};
```
## Best Practices
### Transaction Safety
* **Always validate recipient addresses** before sending
* **Check balance including gas costs** before transaction construction
* **Use appropriate gas limits** (21000 for basic ETH transfers)
* **Handle network errors gracefully** with proper try/catch blocks
* **Wait for receipt confirmation** before considering transaction complete
### Gas Optimization
* **Monitor network conditions** for optimal gas pricing
* **Use EIP-1559 gas parameters** for better fee prediction
* **Estimate gas dynamically** rather than using static values
* **Consider gas limit buffers** for complex operations
### Error Handling
Common errors to handle:
* Invalid recipient addresses
* Insufficient balance
* Network connectivity issues
* Transaction reversion
* Nonce management conflicts
## Next Steps
# Para + M0 Integration
Source: https://docs.getpara.com/v2/walkthroughs/m0
Combine Para's embedded wallets with M0's programmable stablecoin infrastructure
Para's embedded wallets [provide seamless access to M0's programmable stablecoin infrastructure](https://blog.getpara.com/money-movement/). Build next-generation financial applications with custom digital dollars.
Learn about M0's stablecoin protocol
## Prerequisites
* Para API key configured
* Node.js 18+ environment
* Understanding of stablecoin mechanics
* [M0 contract addresses](https://docs.m0.org/home/overview/) for your network
## Installation
Install the required packages:
```bash
npm install @getpara/server-sdk@alpha @getpara/viem-v2-integration@alpha viem@^2
```
## Setup
Import the required Para SDK and Viem components:
```typescript
import { ParaServer } from "@getpara/server-sdk@alpha";
import { createParaViemClient, createParaAccount } from "@getpara/viem-integration@alpha";
import { http } from 'viem';
import { mainnet } from 'viem/chains';
```
Set up Para server instance:
```typescript
const para = new ParaServer(process.env.PARA_API_KEY);
```
Check for existing wallet or create new pregenerated wallet:
```typescript
const hasWallet = await para.hasPregenWallet({
pregenId: { email: 'user@example.com' },
});
let pregenWallet;
if (!hasWallet) {
pregenWallet = await para.createPregenWallet({
type: 'EVM',
pregenId: { email: "user@example.com" },
});
}
```
Set up the account and Viem client for M0 interactions:
```typescript
const account = await createParaAccount(para);
const client = createParaViemClient(para, {
account,
chain: mainnet,
transport: http(),
});
```
## Contract Configuration
### M0 Contract Addresses
```typescript
const M_ADDRESS = '0x866A2BF4E572CbcF37D5071A7a58503Bfb36be1b';
const WM_ADDRESS = '0x437cc33344a0B27A429f795ff6B469C72698B291';
```
### Contract ABIs
```typescript
const ERC20_ABI = [
{ name: 'approve', type: 'function', inputs: [{ name: 'spender', type: 'address' }, { name: 'amount', type: 'uint256' }], outputs: [{ type: 'bool' }] },
{ name: 'transfer', type: 'function', inputs: [{ name: 'recipient', type: 'address' }, { name: 'amount', type: 'uint256' }], outputs: [{ type: 'bool' }] }
];
const WM_ABI = [
{ name: 'wrap', type: 'function', inputs: [{ name: 'recipient', type: 'address' }, { name: 'amount', type: 'uint256' }], outputs: [{ type: 'uint240' }] },
{ name: 'unwrap', type: 'function', inputs: [{ name: 'recipient', type: 'address' }, { name: 'amount', type: 'uint256' }], outputs: [{ type: 'uint240' }] }
];
```
## Usage
### Wrapping \$M to \$wM
```typescript
async function wrapMToWM(amount) {
const approveHash = await client.writeContract({
address: M_ADDRESS,
abi: ERC20_ABI,
functionName: 'approve',
args: [WM_ADDRESS, amount]
});
console.log('Approve hash:', approveHash);
```
```typescript
const wrapHash = await client.writeContract({
address: WM_ADDRESS,
abi: WM_ABI,
functionName: 'wrap',
args: [account.address, amount]
});
console.log('Wrap hash:', wrapHash);
}
```
### Unwrapping \$wM to \$M
```typescript
async function unwrapWMToM(amount) {
const unwrapHash = await client.writeContract({
address: WM_ADDRESS,
abi: WM_ABI,
functionName: 'unwrap',
args: [account.address, amount]
});
console.log('Unwrap hash:', unwrapHash);
}
```
### Token Transfers
```typescript
async function transferToken(tokenAddress, recipient, amount) {
const transferHash = await client.writeContract({
address: tokenAddress,
abi: ERC20_ABI,
functionName: 'transfer',
args: [recipient, amount]
});
console.log('Transfer hash:', transferHash);
}
```
## Examples
### Basic Operations
```typescript
await wrapMToWM(1000000n);
await unwrapWMToM(1000000n);
await transferToken(M_ADDRESS, '0xRecipientAddress', 1000000n);
```
## Next Steps
Learn about M0's stablecoin protocol
Deep dive into wallet pregeneration
# Para SDK Walkthroughs
Source: https://docs.getpara.com/v2/walkthroughs/overview
Step-by-step guides for integrating Para's wallet infrastructure with popular platforms and protocols
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Explore comprehensive guides for integrating Para's wallet infrastructure with various platforms, protocols, and use cases. Each walkthrough provides complete code examples and implementation patterns.
## DeFi Protocol Integrations
## Technical Implementations
## Transaction Guides & Advanced Topics
# Solana SOL Transfers with Para
Source: https://docs.getpara.com/v2/walkthroughs/solana-transfers
Learn how to send SOL transactions using Para with Solana Web3.js, Solana Signers v2, and Coral Anchor libraries
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
This walkthrough covers sending basic SOL transfers using Para with three different Solana libraries: Solana Web3.js (legacy), Solana Signers v2 (modern), and Coral Anchor (smart contracts). Each approach has different patterns for transaction construction and signing.
## Prerequisites
You need an authenticated Para client and basic knowledge of Solana transactions.
## Core Dependencies
```bash
npm install @getpara/react-sdk @getpara/solana-web3-integration @solana/web3.js
```
```bash
npm install @getpara/react-sdk @getpara/solana-signers-v2-integration @solana/kit @solana/transactions @solana-program/system
```
```bash
npm install @getpara/react-sdk @getpara/solana-web3-integration @solana/web3.js @coral-xyz/anchor
```
## Connection Setup
### RPC Configuration
```typescript
import { Connection } from "@solana/web3.js";
const DEVNET_RPC_URL = "https://api.devnet.solana.com";
// Create Solana connection
const connection = new Connection(DEVNET_RPC_URL, "confirmed");
```
```typescript
import { createHttpTransport } from "@solana/rpc-spec";
import { createSolanaRpc } from "@solana/kit";
const DEVNET_RPC_URL = "https://api.devnet.solana.com";
// Create HTTP transport
const transport = createHttpTransport({ url: DEVNET_RPC_URL });
// Create Kit RPC client
const kitRpc = createSolanaRpc({ transport });
// Create Para RPC client
const paraRpc = createHttpTransport({ url: DEVNET_RPC_URL });
```
```typescript
import { Connection } from "@solana/web3.js";
import { AnchorProvider } from "@coral-xyz/anchor";
const DEVNET_RPC_URL = "https://api.devnet.solana.com";
// Create Solana connection
const connection = new Connection(DEVNET_RPC_URL, "confirmed");
```
### Para Signer Setup
```typescript
import { ParaSolanaWeb3Signer } from "@getpara/solana-web3-integration";
import { useAccount, useClient } from "@getpara/react-sdk";
// Get Para client and account
const client = useClient();
const { data: account } = useAccount();
// Create Para Solana signer
let signer: ParaSolanaWeb3Signer | null = null;
if (account?.isConnected && connection && client) {
signer = new ParaSolanaWeb3Signer(client, connection);
}
```
```typescript
import { createParaSolanaSigner } from "@getpara/solana-signers-v2-integration";
import { useAccount, useClient } from "@getpara/react-sdk";
// Get Para client and account
const client = useClient();
const { data: account } = useAccount();
// Create Para Solana signer
let signer: any = null;
if (account?.isConnected && paraRpc && client) {
signer = createParaSolanaSigner({
para: client,
rpc: paraRpc
});
}
```
```typescript
import { ParaSolanaWeb3Signer } from "@getpara/solana-web3-integration";
import { AnchorProvider } from "@coral-xyz/anchor";
import { useAccount, useClient } from "@getpara/react-sdk";
// Get Para client and account
const client = useClient();
const { data: account } = useAccount();
// Create Para Solana signer and Anchor provider
let anchorProvider: AnchorProvider | null = null;
if (account?.isConnected && connection && client) {
const signer = new ParaSolanaWeb3Signer(client, connection);
// Create wallet adapter for Anchor
const walletAdapter = {
publicKey: signer.sender,
signTransaction: async (tx: any) => await signer.signTransaction(tx),
signAllTransactions: async (txs: any[]) => await signer.signAllTransactions(txs)
};
anchorProvider = new AnchorProvider(connection, walletAdapter, {
commitment: "confirmed"
});
}
```
## Transaction Construction
### Basic SOL Transfer
```typescript
import {
Transaction,
SystemProgram,
PublicKey,
LAMPORTS_PER_SOL
} from "@solana/web3.js";
const constructTransaction = async (
toAddress: string,
solAmount: string,
fromPublicKey: PublicKey
) => {
const toPubKey = new PublicKey(toAddress);
const amountLamports = parseFloat(solAmount) * LAMPORTS_PER_SOL;
// Create transaction
const transaction = new Transaction();
// Add transfer instruction
transaction.add(
SystemProgram.transfer({
fromPubkey: fromPublicKey,
toPubkey: toPubKey,
lamports: BigInt(amountLamports)
})
);
// Set transaction parameters
const { blockhash } = await connection.getLatestBlockhash();
transaction.recentBlockhash = blockhash;
transaction.feePayer = fromPublicKey;
return transaction;
};
```
```typescript
import { pipe } from "@solana/transactions";
import {
getTransferSolInstruction,
lamports,
address
} from "@solana-program/system";
import {
appendTransactionMessageInstruction,
createTransactionMessage,
setTransactionMessageFeePayerSigner,
setTransactionMessageLifetimeUsingBlockhash
} from "@solana/transactions";
const constructTransaction = async (
toAddress: string,
solAmount: string,
signerAddress: any
) => {
// Get latest blockhash
const { value: latestBlockhash } = await kitRpc.getLatestBlockhash().send();
// Convert SOL to lamports
const amountLamports = BigInt(parseFloat(solAmount) * 1e9);
// Create transfer instruction
const transferInstruction = getTransferSolInstruction({
source: signerAddress,
destination: address(toAddress),
amount: lamports(amountLamports)
});
// Build transaction message
const transactionMessage = pipe(
createTransactionMessage({ version: 0 }),
tx => setTransactionMessageFeePayerSigner(signerAddress, tx),
tx => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash.blockhash, tx),
tx => appendTransactionMessageInstruction(transferInstruction, tx)
);
return transactionMessage;
};
```
```typescript
import {
Transaction,
SystemProgram,
PublicKey,
LAMPORTS_PER_SOL
} from "@solana/web3.js";
const constructTransaction = async (
toAddress: string,
solAmount: string,
walletPublicKey: PublicKey
) => {
const toPubKey = new PublicKey(toAddress);
const amountLamports = parseFloat(solAmount) * LAMPORTS_PER_SOL;
// Create transaction
const transaction = new Transaction();
// Add transfer instruction
transaction.add(
SystemProgram.transfer({
fromPubkey: walletPublicKey,
toPubkey: toPubKey,
lamports: BigInt(amountLamports)
})
);
// Set transaction parameters
const { blockhash } = await connection.getLatestBlockhash();
transaction.recentBlockhash = blockhash;
transaction.feePayer = walletPublicKey;
return transaction;
};
```
## Balance Validation
### Check Sufficient Balance
```typescript
const validateTransaction = async (
userPublicKey: PublicKey,
solAmount: string
) => {
// Get current balance
const balanceLamports = await connection.getBalance(userPublicKey);
// Calculate amount in lamports
const amountLamports = parseFloat(solAmount) * LAMPORTS_PER_SOL;
// Estimate transaction fee (5000 lamports is typical)
const estimatedFee = 5000;
const totalCost = amountLamports + estimatedFee;
if (totalCost > balanceLamports) {
throw new Error(
`Insufficient balance. Need ${totalCost / LAMPORTS_PER_SOL} SOL, have ${balanceLamports / LAMPORTS_PER_SOL} SOL`
);
}
return true;
};
```
```typescript
const validateTransaction = async (
signerAddress: any,
solAmount: string
) => {
// Get current balance
const { value: balance } = await kitRpc.getBalance(signerAddress).send();
// Calculate amount in lamports
const amountLamports = BigInt(parseFloat(solAmount) * 1e9);
// Estimate transaction fee
const estimatedFee = BigInt(5000);
const totalCost = amountLamports + estimatedFee;
if (totalCost > balance) {
throw new Error(
`Insufficient balance. Need ${Number(totalCost) / 1e9} SOL, have ${Number(balance) / 1e9} SOL`
);
}
return true;
};
```
```typescript
const validateTransaction = async (
walletPublicKey: PublicKey,
solAmount: string
) => {
// Get current balance
const balanceLamports = await connection.getBalance(walletPublicKey);
// Calculate amount in lamports
const amountLamports = parseFloat(solAmount) * LAMPORTS_PER_SOL;
// Estimate transaction fee
const estimatedFee = 5000;
const totalCost = amountLamports + estimatedFee;
if (totalCost > balanceLamports) {
throw new Error(
`Insufficient balance. Need ${totalCost / LAMPORTS_PER_SOL} SOL, have ${balanceLamports / LAMPORTS_PER_SOL} SOL`
);
}
return true;
};
```
## Sending Transactions
### Execute Transfer
```typescript
const sendSolTransfer = async (
toAddress: string,
solAmount: string,
fromPublicKey: PublicKey
) => {
// Validate transaction
await validateTransaction(fromPublicKey, solAmount);
// Construct transaction
const transaction = await constructTransaction(toAddress, solAmount, fromPublicKey);
// Send transaction using Para signer
const txSignature = await signer.sendTransaction(transaction);
console.log("Transaction sent:", txSignature);
// Wait for confirmation with polling
let receipt = null;
while (!receipt) {
receipt = await connection.getSignatureStatus(txSignature, {
searchTransactionHistory: true
});
if (receipt?.value?.confirmationStatus === "confirmed" ||
receipt?.value?.confirmationStatus === "finalized") {
break;
}
// Wait 500ms before next check
await new Promise(resolve => setTimeout(resolve, 500));
}
console.log("Transaction confirmed:", receipt);
return {
signature: txSignature,
status: receipt?.value?.confirmationStatus,
slot: receipt?.value?.slot
};
};
```
```typescript
import {
compileTransaction,
getBase64EncodedWireTransaction
} from "@solana/transactions";
const sendSolTransfer = async (
toAddress: string,
solAmount: string,
signerAddress: any
) => {
// Validate transaction
await validateTransaction(signerAddress, solAmount);
// Construct transaction message
const transactionMessage = await constructTransaction(toAddress, solAmount, signerAddress);
// Sign transaction
const [signedTransaction] = await signer.modifyAndSignTransactions([
compileTransaction(transactionMessage)
]);
// Serialize transaction
const serializedTransaction = getBase64EncodedWireTransaction(signedTransaction);
// Send transaction
const { value: signature } = await kitRpc.sendTransaction(
serializedTransaction,
{
encoding: "base64",
skipPreflight: false,
preflightCommitment: "confirmed"
}
).send();
console.log("Transaction sent:", signature);
// Wait for confirmation
const { value: statuses } = await kitRpc.getSignatureStatuses([signature]).send();
const status = statuses[0];
console.log("Transaction confirmed:", status);
return {
signature,
status: status?.confirmationStatus,
slot: status?.slot
};
};
```
```typescript
const sendSolTransfer = async (
toAddress: string,
solAmount: string,
walletPublicKey: PublicKey
) => {
// Validate transaction
await validateTransaction(walletPublicKey, solAmount);
// Construct transaction
const transaction = await constructTransaction(toAddress, solAmount, walletPublicKey);
// Send and confirm transaction using Anchor provider
const txSignature = await anchorProvider.sendAndConfirm(transaction);
console.log("Transaction sent and confirmed:", txSignature);
return {
signature: txSignature,
status: "confirmed"
};
};
```
## Complete Implementation Example
### Full Transfer Service
```typescript
import {
Connection,
Transaction,
SystemProgram,
PublicKey,
LAMPORTS_PER_SOL
} from "@solana/web3.js";
import { ParaSolanaWeb3Signer } from "@getpara/solana-web3-integration";
class SolanaWeb3TransferService {
private connection: Connection;
private signer: ParaSolanaWeb3Signer;
constructor(rpcUrl: string, paraClient: any) {
this.connection = new Connection(rpcUrl, "confirmed");
this.signer = new ParaSolanaWeb3Signer(paraClient, this.connection);
}
async transfer(toAddress: string, solAmount: string) {
try {
const fromPublicKey = this.signer.sender;
// Validate balance
const balanceLamports = await this.connection.getBalance(fromPublicKey);
const amountLamports = parseFloat(solAmount) * LAMPORTS_PER_SOL;
const estimatedFee = 5000;
if (balanceLamports < amountLamports + estimatedFee) {
throw new Error("Insufficient balance");
}
// Create transaction
const transaction = new Transaction().add(
SystemProgram.transfer({
fromPubkey: fromPublicKey,
toPubkey: new PublicKey(toAddress),
lamports: BigInt(amountLamports)
})
);
const { blockhash } = await this.connection.getLatestBlockhash();
transaction.recentBlockhash = blockhash;
transaction.feePayer = fromPublicKey;
// Send transaction
const signature = await this.signer.sendTransaction(transaction);
// Wait for confirmation
await this.connection.confirmTransaction(signature);
return { success: true, signature };
} catch (error) {
console.error("Transfer failed:", error);
throw error;
}
}
}
```
```typescript
import { pipe } from "@solana/transactions";
import { createSolanaRpc, createHttpTransport } from "@solana/kit";
import { getTransferSolInstruction, lamports, address } from "@solana-program/system";
import { createParaSolanaSigner } from "@getpara/solana-signers-v2-integration";
class SolanaSignersTransferService {
private kitRpc: any;
private signer: any;
constructor(rpcUrl: string, paraClient: any) {
const transport = createHttpTransport({ url: rpcUrl });
this.kitRpc = createSolanaRpc({ transport });
this.signer = createParaSolanaSigner({
para: paraClient,
rpc: createHttpTransport({ url: rpcUrl })
});
}
async transfer(toAddress: string, solAmount: string) {
try {
const signerAddress = this.signer.address;
// Validate balance
const { value: balance } = await this.kitRpc.getBalance(signerAddress).send();
const amountLamports = BigInt(parseFloat(solAmount) * 1e9);
const estimatedFee = BigInt(5000);
if (balance < amountLamports + estimatedFee) {
throw new Error("Insufficient balance");
}
// Get latest blockhash
const { value: latestBlockhash } = await this.kitRpc.getLatestBlockhash().send();
// Create transfer instruction
const transferInstruction = getTransferSolInstruction({
source: signerAddress,
destination: address(toAddress),
amount: lamports(amountLamports)
});
// Build and sign transaction
const transactionMessage = pipe(
createTransactionMessage({ version: 0 }),
tx => setTransactionMessageFeePayerSigner(signerAddress, tx),
tx => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash.blockhash, tx),
tx => appendTransactionMessageInstruction(transferInstruction, tx)
);
const [signedTransaction] = await this.signer.modifyAndSignTransactions([
compileTransaction(transactionMessage)
]);
// Send transaction
const serialized = getBase64EncodedWireTransaction(signedTransaction);
const { value: signature } = await this.kitRpc.sendTransaction(serialized).send();
return { success: true, signature };
} catch (error) {
console.error("Transfer failed:", error);
throw error;
}
}
}
```
```typescript
import {
Connection,
Transaction,
SystemProgram,
PublicKey,
LAMPORTS_PER_SOL
} from "@solana/web3.js";
import { AnchorProvider } from "@coral-xyz/anchor";
import { ParaSolanaWeb3Signer } from "@getpara/solana-web3-integration";
class AnchorTransferService {
private connection: Connection;
private anchorProvider: AnchorProvider;
constructor(rpcUrl: string, paraClient: any) {
this.connection = new Connection(rpcUrl, "confirmed");
const signer = new ParaSolanaWeb3Signer(paraClient, this.connection);
const walletAdapter = {
publicKey: signer.sender,
signTransaction: async (tx: any) => await signer.signTransaction(tx),
signAllTransactions: async (txs: any[]) => await signer.signAllTransactions(txs)
};
this.anchorProvider = new AnchorProvider(this.connection, walletAdapter, {
commitment: "confirmed"
});
}
async transfer(toAddress: string, solAmount: string) {
try {
const fromPublicKey = this.anchorProvider.wallet.publicKey;
// Validate balance
const balanceLamports = await this.connection.getBalance(fromPublicKey);
const amountLamports = parseFloat(solAmount) * LAMPORTS_PER_SOL;
const estimatedFee = 5000;
if (balanceLamports < amountLamports + estimatedFee) {
throw new Error("Insufficient balance");
}
// Create transaction
const transaction = new Transaction().add(
SystemProgram.transfer({
fromPubkey: fromPublicKey,
toPubkey: new PublicKey(toAddress),
lamports: BigInt(amountLamports)
})
);
const { blockhash } = await this.connection.getLatestBlockhash();
transaction.recentBlockhash = blockhash;
transaction.feePayer = fromPublicKey;
// Send and confirm transaction
const signature = await this.anchorProvider.sendAndConfirm(transaction);
return { success: true, signature };
} catch (error) {
console.error("Transfer failed:", error);
throw error;
}
}
}
```
## Key Differences
### Library Comparison
| Feature | Solana Web3.js | Solana Signers v2 | Coral Anchor |
| ------------------------ | -------------------------- | ------------------------------------ | --------------------------- |
| **Status** | Legacy | Modern/Recommended | Smart Contracts |
| **Transaction Type** | `Transaction` | `TransactionMessage` | `Transaction` |
| **Instruction Creation** | `SystemProgram.transfer()` | `getTransferSolInstruction()` | `SystemProgram.transfer()` |
| **Signing** | `signer.sendTransaction()` | `signer.modifyAndSignTransactions()` | `provider.sendAndConfirm()` |
| **Amount Format** | `BigInt(lamports)` | `lamports(bigint)` | `BigInt(lamports)` |
| **Confirmation** | Manual polling | Status check | Automatic |
### Transaction Construction Patterns
```typescript
// Legacy approach with Transaction class
const transaction = new Transaction();
transaction.add(SystemProgram.transfer({...}));
transaction.recentBlockhash = blockhash;
transaction.feePayer = publicKey;
```
```typescript
// Modern functional approach with pipes
const transactionMessage = pipe(
createTransactionMessage({ version: 0 }),
tx => setTransactionMessageFeePayerSigner(signer, tx),
tx => setTransactionMessageLifetimeUsingBlockhash(blockhash, tx),
tx => appendTransactionMessageInstruction(instruction, tx)
);
```
```typescript
// Anchor provider abstraction
const transaction = new Transaction();
transaction.add(SystemProgram.transfer({...}));
// Provider handles blockhash and fee payer automatically
const signature = await provider.sendAndConfirm(transaction);
```
## Best Practices
### Library Selection
* **Solana Web3.js**: Use for compatibility with existing projects, but consider migrating
* **Solana Signers v2**: Recommended for new projects, modern patterns, better performance
* **Coral Anchor**: Best for dApps interacting with Anchor-based smart contracts
### Transaction Safety
* **Always validate recipient addresses** using `PublicKey` constructor
* **Check balance including fees** before transaction construction
* **Use appropriate commitment levels** ("confirmed" for most cases)
* **Handle network errors gracefully** with proper retry logic
* **Monitor transaction confirmation** rather than assuming success
### Performance Optimization
* **Reuse connection instances** rather than creating new ones
* **Batch multiple transfers** when possible
* **Use appropriate RPC endpoints** for your use case
* **Monitor transaction fees** and adjust as needed
## Next Steps
# Flutter SDK API
Source: https://docs.getpara.com/v2/flutter/api/sdk
Complete API reference for Para Flutter SDK v2, including authentication, wallet management, and blockchain operations. Updated for 2.0.0-alpha with comprehensive multi-chain support and passkey authentication.
## Para Class
The `Para` class is the main entry point for the Para Flutter SDK, providing wallet operations, authentication, and blockchain interactions. The latest version includes passkey authentication, comprehensive multi-chain support, and deep linking capabilities.
### Constructor
Creates a new Para SDK instance using the v2 factory constructor.
Configuration object containing environment and API key.
Your app's deep link scheme (e.g., "yourapp").
```dart
final para = Para.fromConfig(
config: ParaConfig(
environment: Environment.beta,
apiKey: 'YOUR_API_KEY',
jsBridgeUri: Uri.parse('custom-bridge-url'), // Optional
relyingPartyId: 'custom.domain.com', // Optional
),
appScheme: 'yourapp',
);
```
### Authentication Methods
Initiates authentication flow for email or phone. Returns an `AuthState` indicating next steps.
Authentication object using `Auth.email()` or `Auth.phone()` helper methods.
```dart
// Email authentication
final authState = await para.initiateAuthFlow(
auth: Auth.email('user@example.com')
);
// Phone authentication
final authState = await para.initiateAuthFlow(
auth: Auth.phone('+1234567890')
);
```
Verifies the OTP code sent to email/phone during authentication.
The 6-digit OTP verification code.
```dart
final verifiedState = await para.verifyOtp(
otp: '123456'
);
```
Handles login for existing users with passkey authentication.
The auth state returned from `initiateAuthFlow()` for existing users.
```dart
final wallet = await para.handleLogin(
authState: authState,
);
```
Handles the complete signup flow for new users, including passkey creation and wallet setup.
The auth state returned from `verifyOtp()` for new users.
The signup method to use: `SignupMethod.passkey`.
```dart
final wallet = await para.handleSignup(
authState: authState,
method: SignupMethod.passkey,
);
```
Handles complete OAuth authentication flow using an external browser.
OAuth provider: `OAuthMethod.google`, `.twitter`, `.apple`, `.discord`, or `.facebook`.
Your app's deep link scheme for OAuth callback (e.g., 'yourapp').
```dart
final authState = await para.verifyOAuth(
provider: OAuthMethod.google,
appScheme: 'yourapp',
);
```
### Wallet Management
Creates a new wallet with enhanced multi-chain support. Returns a `ParaFuture` that can be cancelled.
The type of wallet to create: `WalletType.evm`, `.solana`, or `.cosmos` (default: `WalletType.evm`).
Whether to skip the distributed backup process.
```dart
final walletFuture = para.createWallet(
type: WalletType.evm,
skipDistribute: false,
);
final wallet = await walletFuture.future;
// Or cancel: await para.cancelOperationById(walletFuture.requestId);
```
Retrieves all wallets for the current user.
```dart
final walletsFuture = para.fetchWallets();
final wallets = await walletsFuture.future;
```
### Signing Operations
Signs a message with the specified wallet. Returns a cancellable `ParaFuture`.
The wallet ID to use for signing.
The message to sign, base64-encoded.
Optional timeout in milliseconds (default: 30000).
For Cosmos signing: The SignDoc as base64-encoded JSON. When provided, this method signs a Cosmos transaction instead of a generic message.
```dart
// Generic message signing
final signatureFuture = para.signMessage(
walletId: wallet.id,
messageBase64: base64Encode(utf8.encode('Hello, Para!')),
);
final signature = await signatureFuture.future;
// Cosmos transaction signing
final cosmosSignature = await para.signMessage(
walletId: cosmosWallet.id,
messageBase64: '', // Not used for Cosmos
cosmosSignDocBase64: base64Encode(utf8.encode(jsonEncode(signDoc))),
).future;
```
Signs an EVM transaction. Returns a cancellable `ParaFuture`.
This method is for EVM transactions only. For Solana, use `signMessage()` with the serialized transaction as `messageBase64`. For Cosmos, use `signMessage()` with `cosmosSignDocBase64`.
**EVM Transaction Return Value**: The `SuccessfulSignatureResult` contains the complete RLP-encoded transaction ready for broadcasting via the `signedTransaction` property.
**Solana/Cosmos Return Value**: For pre-serialized transactions, returns just the signature in `signedTransaction`. For constructed transactions, returns the complete signed transaction.
The wallet ID to use for signing.
RLP-encoded EVM transaction (base64).
Chain ID of the EVM network.
Optional timeout in milliseconds (default: 30000).
```dart
// EVM transaction signing
final signatureFuture = para.signTransaction(
walletId: evmWallet.id,
rlpEncodedTxBase64: base64Encode(rlpEncodedTx),
chainId: '1', // Ethereum mainnet
);
final signature = await signatureFuture.future;
```
Cancels an ongoing operation by its request ID.
The request ID from a `ParaFuture`.
```dart
final signatureFuture = para.signMessage(...);
// Cancel the operation
await para.cancelOperationById(signatureFuture.requestId);
```
### Session Management
Checks if there's an active user session.
```dart
final isActive = await para.isSessionActive().future;
```
Exports the current session as an encrypted string.
```dart
final sessionData = await para.exportSession().future;
// Save sessionData securely
```
Logs out the current user and clears session data.
```dart
await para.logout().future;
```
### Utility Methods
Gets the current user's authentication details.
```dart
final authDetails = await para.getCurrentUserAuthDetails().future;
```
Waits for an ongoing login operation to complete.
Optional function to check if operation is canceled.
Polling interval in milliseconds (default: 2000).
```dart
final result = await para.waitForLogin(
pollingIntervalMs: 1000,
).future;
```
Waits for wallet creation to complete after signup.
Optional function to check if operation is canceled.
Polling interval in milliseconds (default: 2000).
```dart
final result = await para.waitForWalletCreation(
pollingIntervalMs: 1000,
).future;
```
Formats a phone number for authentication.
The phone number to format.
The country code (e.g., '1' for US, '44' for UK).
```dart
final formatted = para.formatPhoneNumber('1234567890', '1');
// Returns: '+11234567890' (exact format depends on implementation)
```
Checks if the current user is using an external wallet.
```dart
final isExternal = await para.isUsingExternalWallet().future;
```
Clears local storage data.
Whether to keep the Paillier secret key (default: false).
```dart
await para.clearStorage(false).future;
```
Disposes of SDK resources. Call when the SDK is no longer needed.
```dart
para.dispose();
```
## Extension Methods
Para provides extension methods for cleaner authentication flows (requires importing extensions):
```dart
import 'package:para/src/auth_extensions.dart';
```
### ParaAuthExtensions
Initiates authentication and returns the current state using `Auth` helper class.
Authentication method: `Auth.email()` or `Auth.phone()`.
```dart
// Must import extensions
import 'package:para/src/auth_extensions.dart';
final authState = await para.initiateAuthFlow(
auth: Auth.email('user@example.com')
);
```
Presents a password authentication URL in a secure web view.
The password authentication URL.
Web authentication session for handling the flow.
## Types and Enums
### Environment
```dart
enum Environment {
dev, // Development environment
beta, // Beta environment
prod // Production environment
}
```
### Auth
```dart
class Auth {
static AuthEmail email(String email);
static AuthPhone phone(String phoneNumber);
}
```
### AuthState
```dart
class AuthState {
final AuthStage stage; // Current authentication stage
final String? userId; // User's unique identifier
final AuthIdentity auth; // Authentication identity details
final String? displayName; // User's display name
final String? pfpUrl; // Profile picture URL
final String? username; // Username
final Map? externalWallet; // External wallet info
final String? passkeyUrl; // URL for passkey authentication
final String? passkeyId; // Passkey identifier
final String? passwordUrl; // URL for password authentication
// Additional properties for specific auth flows
}
class AuthIdentity {
final String? email;
final String? phoneNumber;
final String? fid; // Farcaster ID
final String? telegramUserId;
// Other identity types
}
enum AuthStage {
verify, // Need to verify email/phone
login, // Existing user, proceed to login
signup // New user, proceed to signup
}
```
### SignupMethod
```dart
enum SignupMethod {
passkey, // Hardware-backed passkey
password // Password-based authentication
}
```
### OAuthMethod
```dart
enum OAuthMethod {
google,
twitter,
apple,
discord,
facebook
}
```
### WalletType
```dart
enum WalletType {
evm, // Ethereum and EVM-compatible chains
solana, // Solana blockchain
cosmos // Cosmos-based chains
}
```
### ParaFuture
```dart
class ParaFuture {
final Future future; // The actual future
final String requestId; // ID for cancellation
}
```
### Wallet
```dart
class Wallet {
final String id;
final String address;
final WalletType type;
final WalletScheme scheme;
final String? userId; // Associated user ID
final DateTime? createdAt; // Creation timestamp
final String? publicKey; // Wallet public key
final bool? isPregen; // Whether this is a pregenerated wallet
// Additional optional fields available
}
```
### SignatureResult
```dart
// Abstract base class
abstract class SignatureResult {}
// Successful signature
class SuccessfulSignatureResult extends SignatureResult {
final String signedTransaction; // For transactions: complete signed transaction ready for broadcasting
// For messages: just the signature
SuccessfulSignatureResult(this.signedTransaction);
/// Gets the transaction data ready for broadcasting.
String get transactionData => signedTransaction;
}
// Denied signature
class DeniedSignatureResult extends SignatureResult {
final String? pendingTransactionId;
DeniedSignatureResult(this.pendingTransactionId);
}
// Denied with URL
class DeniedSignatureResultWithUrl extends SignatureResult {
final String? pendingTransactionId;
final String url;
DeniedSignatureResultWithUrl({this.pendingTransactionId, required this.url});
}
```
# Mobile Examples
Source: https://docs.getpara.com/v2/flutter/examples
Explore Para's mobile integration examples for Flutter
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Para provides a minimal, focused Flutter example demonstrating clean integration patterns with our v2 SDK. Our example app serves as a reference implementation that you can adapt to your specific needs.
## Para Flutter Example
Explore our complete Flutter application showcasing Para v2 integration:
### What's Included
The Flutter example demonstrates essential Para v2 features with a focus on clean architecture:
**🔐 Authentication Methods:**
* Email and phone verification with passkeys
* OAuth social login (Google, Apple, Twitter, Discord, Facebook)
* Farcaster authentication
* External wallet connections (MetaMask, Phantom)
**💰 Wallet Management:**
* Multi-chain wallet creation (EVM, Solana, Cosmos)
* Session management and persistence
* Wallet import/export functionality
**⛓️ Blockchain Integration:**
* EVM transaction signing with web3dart
* Solana transaction signing with native SDK
* Cosmos transaction signing with SignDoc
* Message signing across all chains
**🛠️ Advanced Features:**
* Pregenerated wallet handling
* Error handling and retry logic
* Cross-platform passkey and biometric authentication
* Modern app architecture with launch screen
* Deep linking for auth callbacks
* New helper methods (handleLogin, handleSignup)
## Code Examples by Feature
### Authentication Flow Example
The Flutter example includes a complete authentication implementation:
```dart
// From: lib/examples/auth/email_auth_example.dart
Future authenticateWithEmail(String email) async {
final authState = await para.initiateAuthFlow(
auth: Auth.email(email)
);
switch (authState.stage) {
case AuthStage.verify:
// New user - show verification UI
showVerificationScreen();
break;
case AuthStage.login:
// Existing user - login with passkey
await para.handleLogin(
authState: authState,
webAuthenticationSession: webAuthSession,
);
break;
}
}
```
### Transaction Signing Examples
### Authentication Examples
## App Architecture
The example app features a modern architecture:
* **Launch Screen**: Professional splash screen during initialization
* **Auth Management**: Unified authentication flow using new helper methods
* **State Management**: Clean separation of concerns
* **Deep Link Handling**: Proper callback handling for external auth
## Getting Started with the Example
### Prerequisites
1. **Flutter SDK**: Version 3.1.3 or higher
2. **Device Setup**: iOS simulator or Android emulator with biometric support
3. **Para API Key**: Sign up at [developer.getpara.com](https://developer.getpara.com)
### Quick Start
```bash
# Clone the repository
git clone https://github.com/getpara/examples-hub.git
cd examples-hub/mobile/with-flutter
# Install dependencies
flutter pub get
# Configure your API key
# Edit lib/client/para.dart with your API key
# Run the example
flutter run
```
### Configuration
Update the Para configuration in `lib/client/para.dart`:
```dart
final para = Para.fromConfig(
config: ParaConfig(
environment: Environment.beta, // or Environment.prod
apiKey: 'YOUR_API_KEY_HERE',
),
appScheme: 'yourapp',
);
```
## E2E Testing
The Flutter example includes comprehensive end-to-end tests:
```bash
# Run E2E tests
cd test_e2e
dart run tool/setup.dart
dart run tool/run_tests.dart
```
The E2E tests cover:
* Email and phone authentication flows
* Wallet creation and management
* Transaction signing
* Error handling scenarios
## Need Something Specific?
Don't see an example for your use case? Para's team is eager to create new examples to help you integrate with different libraries, third-party features, or providers.
# Cosmos Integration
Source: https://docs.getpara.com/v2/flutter/guides/cosmos
Sign transactions for Cosmos chains using Para's unified wallet architecture
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
## Quick Start
```dart
import 'package:para/para.dart';
// Sign a Cosmos transaction
final para = Para(apiKey: 'your-api-key');
final wallet = (await para.fetchWallets()).firstWhere((w) => w.type == 'COSMOS');
final transaction = CosmosTransaction(
to: 'cosmos1recipient...',
amount: '1000000', // 1 ATOM in micro-units
chainId: 'theta-testnet-001', // Cosmos Hub testnet (use 'cosmoshub-4' for mainnet)
format: 'proto',
);
final result = await para.signTransaction(
walletId: wallet.id!,
transaction: transaction.toJson(),
chainId: 'theta-testnet-001',
);
print('Transaction signed: ${result.signedTransaction}');
```
## Common Operations
### Sign Transactions for Different Chains
```dart
// Sign ATOM transaction on Cosmos Hub testnet
final atomTx = CosmosTransaction(
to: 'cosmos1recipient...',
amount: '1000000', // 1 ATOM
denom: 'uatom',
chainId: 'theta-testnet-001', // Testnet
format: 'proto',
);
// Sign OSMO transaction on Osmosis testnet
final osmoTx = CosmosTransaction(
to: 'osmo1recipient...',
amount: '1000000', // 1 OSMO
denom: 'uosmo',
chainId: 'osmo-test-5', // Testnet
format: 'proto',
);
// Sign JUNO transaction on Juno mainnet
final junoTx = CosmosTransaction(
to: 'juno1recipient...',
amount: '1000000', // 1 JUNO
denom: 'ujuno',
chainId: 'juno-1',
format: 'proto',
);
```
### Sign Transaction
```dart
final transaction = CosmosTransaction(
to: 'cosmos1recipient...',
amount: '1000000', // 1 ATOM
denom: 'uatom',
memo: 'Transfer via Para',
chainId: 'theta-testnet-001', // Testnet
format: 'proto', // or 'amino' for legacy
);
final result = await para.signTransaction(
walletId: wallet.id!,
transaction: transaction.toJson(),
chainId: 'theta-testnet-001',
rpcUrl: 'https://rpc.sentry-01.theta-testnet.polypore.xyz',
);
// Cosmos returns: { signBytes, signDoc, format }
print('Signed: ${result.signedTransaction}');
```
### Check Balance
```dart
final balance = await para.getBalance(
walletId: wallet.id!,
rpcUrl: 'https://cosmos-rpc.publicnode.com',
chainPrefix: 'cosmos',
denom: 'uatom',
);
print('Balance: $balance uatom');
// Different chain
final osmoBalance = await para.getBalance(
walletId: wallet.id!,
rpcUrl: 'https://osmosis-rpc.publicnode.com',
chainPrefix: 'osmo',
denom: 'uosmo',
);
```
### Sign Message
```dart
final message = 'Hello, Cosmos!';
final result = await para.signMessage(
walletId: wallet.id!,
message: message,
);
print('Signature: ${result.signedTransaction}');
```
## Supported Networks
### Testnets
| Network | Chain ID | Prefix | Native Token | RPC URL |
| ---------------------- | ------------------- | -------- | ------------ | -------------------------------------------------- |
| **Cosmos Hub Testnet** | `theta-testnet-001` | `cosmos` | `uatom` | `https://rpc.sentry-01.theta-testnet.polypore.xyz` |
| **Osmosis Testnet** | `osmo-test-5` | `osmo` | `uosmo` | `https://rpc.osmotest5.osmosis.zone` |
### Mainnets
| Network | Chain ID | Prefix | Native Token | Decimals | RPC URL |
| -------------- | ---------------- | ---------- | ------------ | -------- | -------------------------------------- |
| **Cosmos Hub** | `cosmoshub-4` | `cosmos` | `uatom` | 6 | `https://cosmos-rpc.publicnode.com` |
| **Osmosis** | `osmosis-1` | `osmo` | `uosmo` | 6 | `https://osmosis-rpc.publicnode.com` |
| **Juno** | `juno-1` | `juno` | `ujuno` | 6 | `https://rpc-juno.itastakers.com` |
| **Stargaze** | `stargaze-1` | `stars` | `ustars` | 6 | `https://rpc.stargaze-apis.com` |
| **Akash** | `akashnet-2` | `akash` | `uakt` | 6 | `https://rpc.akash.forbole.com` |
| **Celestia** | `celestia` | `celestia` | `utia` | 6 | `https://rpc.celestia.pops.one` |
| **dYdX** | `dydx-mainnet-1` | `dydx` | `adydx` | 18 | `https://dydx-dao-api.polkachu.com` |
| **Injective** | `injective-1` | `inj` | `inj` | 18 | `https://injective-rpc.publicnode.com` |
## Complete Example
```dart
import 'package:flutter/material.dart';
import 'package:para/para.dart';
class CosmosWalletView extends StatefulWidget {
final Para para;
final Wallet wallet;
const CosmosWalletView({required this.para, required this.wallet});
@override
State createState() => _CosmosWalletViewState();
}
class _CosmosWalletViewState extends State {
String _selectedChain = 'theta-testnet-001';
bool _isLoading = false;
String? _result;
final chains = {
'theta-testnet-001': {'name': 'Cosmos Hub Testnet', 'rpc': 'https://rpc.sentry-01.theta-testnet.polypore.xyz', 'denom': 'uatom', 'prefix': 'cosmos'},
'osmo-test-5': {'name': 'Osmosis Testnet', 'rpc': 'https://rpc.osmotest5.osmosis.zone', 'denom': 'uosmo', 'prefix': 'osmo'},
};
@override
Widget build(BuildContext context) {
final chain = chains[_selectedChain]!;
return Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
DropdownButton(
value: _selectedChain,
items: chains.entries.map((e) =>
DropdownMenuItem(value: e.key, child: Text(e.value['name']!))
).toList(),
onChanged: (value) => setState(() => _selectedChain = value!),
),
SizedBox(height: 20),
Text(
widget.wallet.address ?? 'No address',
style: TextStyle(fontFamily: 'monospace', fontSize: 12),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: _isLoading ? null : _signTransaction,
child: Text(_isLoading ? 'Signing...' : 'Sign Transaction for ${chain['name']}'),
),
if (_result != null)
Padding(
padding: const EdgeInsets.only(top: 20),
child: Text(_result!, style: TextStyle(fontSize: 12)),
),
],
),
);
}
Future _signTransaction() async {
setState(() => _isLoading = true);
final chain = chains[_selectedChain]!;
try {
final transaction = CosmosTransaction(
to: '${chain['prefix']}1recipient...', // Uses chain prefix
amount: '1000000', // 1 token in micro-units
denom: chain['denom']!,
memo: 'Test transaction from Flutter',
chainId: _selectedChain,
format: 'proto',
);
final result = await widget.para.signTransaction(
walletId: widget.wallet.id!,
transaction: transaction.toJson(),
chainId: _selectedChain,
rpcUrl: chain['rpc']!,
);
setState(() => _result = 'Signed! Signature: ${result.signature}');
} catch (e) {
setState(() => _result = 'Error: $e');
} finally {
setState(() => _isLoading = false);
}
}
}
```
## Proto vs Amino Formats
```dart
// Modern Proto format (recommended)
final protoTx = CosmosTransaction(
to: 'cosmos1recipient...',
amount: '1000000',
format: 'proto',
chainId: 'cosmoshub-4',
);
// Legacy Amino format (compatibility)
final aminoTx = CosmosTransaction(
to: 'cosmos1recipient...',
amount: '1000000',
format: 'amino',
chainId: 'cosmoshub-4',
);
// Use convenience constructor
final simpleTx = CosmosTransaction(
to: 'cosmos1recipient...',
amount: '1000000',
denom: 'uatom',
chainId: 'theta-testnet-001',
);
```
# EVM Integration
Source: https://docs.getpara.com/v2/flutter/guides/evm
Transfer ETH and interact with EVM chains using Para's unified wallet architecture
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
## Quick Start
### Transfer
Para handles signing and broadcasting in one call:
```dart
import 'package:para/para.dart';
final para = Para(apiKey: 'your-api-key');
final wallet = (await para.fetchWallets()).firstWhere((w) => w.type == 'EVM');
// Send ETH - Para signs and broadcasts
final result = await para.transfer(
walletId: wallet.id!,
to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
amount: '1000000000000000', // 0.001 ETH in wei
chainId: '11155111', // Optional: Sepolia testnet (defaults to wallet's chain)
rpcUrl: null, // Optional: override default RPC
);
print('Transaction sent: ${result.hash}');
print('From: ${result.from}, To: ${result.to}');
print('Amount: ${result.amount}, Chain: ${result.chainId}');
```
### Advanced Control
Sign with Para, then broadcast yourself for custom gas/RPC settings:
```dart
// Step 1: Sign transaction with Para
final transaction = EVMTransaction(
to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
value: '1000000000000000',
gasLimit: '21000',
);
final result = await para.signTransaction(
walletId: wallet.id!,
transaction: transaction.toJson(),
chainId: '11155111', // Sepolia testnet
);
// Step 2: Broadcast using your preferred library (e.g., web3dart)
// The transactionData getter provides the complete signed transaction
// final txHash = await broadcastWithWeb3Dart(result.transactionData);
```
## Common Operations
### Send ETH
```dart
// Para handles everything - signing and broadcasting
final result = await para.transfer(
walletId: wallet.id!,
to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
amount: '1000000000000000', // 0.001 ETH in wei
chainId: '11155111', // Optional: Sepolia testnet
rpcUrl: null, // Optional: custom RPC URL
);
print('Transaction hash: ${result.hash}');
print('From: ${result.from}, To: ${result.to}, Chain: ${result.chainId}');
```
### Sign Transaction
```dart
final transaction = EVMTransaction(
to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
value: '1000000000000000',
gasLimit: '21000',
maxPriorityFeePerGas: '1000000000', // 1 Gwei
maxFeePerGas: '3000000000', // 3 Gwei
nonce: '0',
chainId: '11155111', // Sepolia
type: 2,
);
final result = await para.signTransaction(
walletId: wallet.id!,
transaction: transaction.toJson(),
chainId: '11155111',
);
// The transactionData getter returns the complete RLP-encoded transaction
// ready for broadcasting via eth_sendRawTransaction
print('Signed transaction: ${result.transactionData}');
// For backward compatibility, signature field still contains the raw signature
print('Raw signature: ${result.signedTransaction}');
```
### Check Balance
```dart
// Native ETH balance
final ethBalance = await para.getBalance(walletId: wallet.id!);
// ERC-20 token balance
final tokenBalance = await para.getBalance(
walletId: wallet.id!,
token: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
);
```
### Sign Message
```dart
final message = 'Hello, Ethereum!';
final result = await para.signMessage(
walletId: wallet.id!,
message: message,
);
print('Signature: ${result.signedTransaction}');
```
## Networks
### Testnets
| Network | Chain ID | Native Token | Default RPC |
| ------------------ | ---------- | ------------ | --------------------------------------------- |
| **Sepolia** | `11155111` | ETH | `https://ethereum-sepolia-rpc.publicnode.com` |
| **Polygon Mumbai** | `80001` | MATIC | `https://rpc-mumbai.maticvigil.com` |
| **Base Sepolia** | `84532` | ETH | `https://sepolia.base.org` |
### Mainnets
| Network | Chain ID | Native Token | Default RPC |
| ------------ | -------- | ------------ | ------------------------------ |
| **Ethereum** | `1` | ETH | `https://eth.llamarpc.com` |
| **Polygon** | `137` | MATIC | `https://polygon-rpc.com` |
| **Base** | `8453` | ETH | `https://mainnet.base.org` |
| **Arbitrum** | `42161` | ETH | `https://arb1.arbitrum.io/rpc` |
| **Optimism** | `10` | ETH | `https://mainnet.optimism.io` |
## Complete Example
```dart
import 'package:flutter/material.dart';
import 'package:para/para.dart';
class EVMWalletView extends StatefulWidget {
final Para para;
final Wallet wallet;
const EVMWalletView({required this.para, required this.wallet});
@override
State createState() => _EVMWalletViewState();
}
class _EVMWalletViewState extends State {
bool _isLoading = false;
String? _txHash;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Text(
widget.wallet.address ?? 'No address',
style: TextStyle(fontFamily: 'monospace', fontSize: 12),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: _isLoading ? null : _sendETH,
child: Text(_isLoading ? 'Sending...' : 'Send 0.001 ETH'),
),
if (_txHash != null)
Padding(
padding: const EdgeInsets.only(top: 20),
child: Text('Sent: $_txHash', style: TextStyle(fontSize: 12)),
),
],
),
);
}
Future _sendETH() async {
setState(() => _isLoading = true);
try {
final result = await widget.para.transfer(
walletId: widget.wallet.id!,
to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
amount: '1000000000000000',
chainId: '11155111', // Optional: Sepolia testnet
rpcUrl: null, // Optional: custom RPC
);
setState(() => _txHash = result.hash);
} catch (e) {
print('Error: $e');
} finally {
setState(() => _isLoading = false);
}
}
}
```
## Smart Contract Interaction
**Transaction Data**: For EVM transactions, `result.transactionData` returns the complete RLP-encoded signed transaction that's ready to broadcast via `eth_sendRawTransaction`. The `signature` field contains just the raw signature for backward compatibility.
```dart
// Call a contract function
final contractTransaction = EVMTransaction(
to: '0x123abc...', // Contract address
value: '0',
gasLimit: '150000',
maxPriorityFeePerGas: '1000000000',
maxFeePerGas: '3000000000',
nonce: '0',
chainId: '11155111', // Sepolia testnet
smartContractAbi: '''[{
"inputs": [{"name":"num","type":"uint256"}],
"name": "store",
"type": "function"
}]''',
smartContractFunctionName: 'store',
smartContractFunctionArgs: ['42'],
type: 2,
);
final result = await para.signTransaction(
walletId: wallet.id!,
transaction: contractTransaction.toJson(),
chainId: '11155111', // Sepolia testnet
);
// Use result.transactionData to get the complete signed transaction
print('Signed transaction: ${result.transactionData}');
```
### ERC20 Token Transfer
Transfer ERC20 tokens using the standard transfer function:
```dart
// Transfer USDC on Sepolia testnet
final usdcTransaction = EVMTransaction(
to: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238', // USDC contract on Sepolia
value: '0', // No ETH being sent, only tokens
gasLimit: '100000', // Higher gas limit for token transfers
maxPriorityFeePerGas: '1000000000', // 1 Gwei
maxFeePerGas: '3000000000', // 3 Gwei
nonce: '0',
chainId: '11155111', // Sepolia testnet
// ERC20 transfer function ABI
smartContractAbi: '''[{
"inputs": [
{"name": "to", "type": "address"},
{"name": "amount", "type": "uint256"}
],
"name": "transfer",
"outputs": [{"name": "", "type": "bool"}],
"type": "function"
}]''',
smartContractFunctionName: 'transfer',
smartContractFunctionArgs: [
'0x742d35Cc6634C0532925a3b844Bc454e4438f44e', // Recipient address
'100000', // 0.1 USDC (USDC has 6 decimals, so 100000 = 0.1 USDC)
],
type: 2, // EIP-1559 transaction
);
// Sign the token transfer transaction
final result = await para.signTransaction(
walletId: wallet.id!,
transaction: usdcTransaction.toJson(),
chainId: '11155111',
);
// The Flutter SDK sends the ABI and function parameters separately
// The bridge handles the encoding to create the proper transaction data
print('Token transfer signed: ${result.transactionData}');
// You can now broadcast this transaction using eth_sendRawTransaction
// or use Para's transfer method for automatic broadcasting
```
# External Wallets
Source: https://docs.getpara.com/v2/flutter/guides/external-wallets
Connect and authenticate users with external wallets like MetaMask and Phantom in Flutter.
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label}) => {
e.currentTarget.querySelector("#underline").style.height = "2px";
}} onMouseLeave={e => {
e.currentTarget.querySelector("#underline").style.height = "1px";
}}>
{label}
;
## Overview
Para v2 supports authentication with external wallets, allowing users to connect their existing MetaMask, Phantom, or other wallets to authenticate with your Flutter application. The Flutter SDK maintains blockchain packages (web3dart, solana\_web3) to provide direct access to external wallet functionality while integrating with Para's unified wallet architecture.
This guide covers how to implement external wallet authentication and interaction using Para's connector classes.
## Prerequisites
Before implementing external wallet support, ensure you have:
1. Para SDK set up in your Flutter project (see the [Setup Guide](/v2/flutter/setup))
2. Deep linking configured for your app
3. Target external wallet apps installed on the device
## Deep Link Configuration
External wallet authentication requires deep linking to redirect users back to your app after wallet interaction. Configure this in both iOS and Android.
### Android Configuration
Add an intent filter to your `android/app/src/main/AndroidManifest.xml`:
```xml
```
### iOS Configuration
Add your URL scheme to `ios/Runner/Info.plist`:
```xml
CFBundleURLTypes
CFBundleTypeRole
Editor
CFBundleURLSchemes
yourapp
```
## External Wallet Authentication
Para v2 provides a unified method for external wallet authentication:
```dart
import 'package:para/para.dart';
Future authenticateWithExternalWallet(
String externalAddress,
String walletType,
) async {
try {
// Login with external wallet address
await para.loginExternalWallet(
externalAddress: externalAddress,
type: walletType, // "EVM" or "SOLANA"
);
// Check if authentication was successful
final isActive = await para.isSessionActive().future;
if (isActive) {
final wallets = await para.fetchWallets().future;
print('Authenticated with ${wallets.length} wallets');
}
} catch (e) {
print('External wallet authentication failed: $e');
}
}
```
## Working with Specific Wallets
Para provides dedicated connectors for popular external wallets:
### MetaMask Integration
Para includes a MetaMask connector for EVM interactions:
```dart
import 'package:para/para.dart';
class MetaMaskService {
late ParaMetaMaskConnector _connector;
void initialize() {
_connector = ParaMetaMaskConnector(
para: para,
appUrl: 'https://yourapp.com',
appScheme: 'yourapp',
);
}
Future connectMetaMask() async {
try {
await _connector.connect();
print('MetaMask connected');
} catch (e) {
print('Failed to connect MetaMask: $e');
}
}
Future signMessage(String message) async {
if (_connector.accounts.isEmpty) {
throw Exception('No accounts connected');
}
final signature = await _connector.signMessage(
message,
_connector.accounts.first,
);
return signature;
}
Future sendTransaction({
required String toAddress,
required BigInt value,
}) async {
if (_connector.accounts.isEmpty) {
throw Exception('No accounts connected');
}
final transaction = Transaction(
from: EthereumAddress.fromHex(_connector.accounts.first),
to: EthereumAddress.fromHex(toAddress),
value: EtherAmount.inWei(value),
maxGas: 100000,
gasPrice: EtherAmount.inWei(BigInt.from(20000000000)), // 20 Gwei
);
final txHash = await _connector.sendTransaction(
transaction,
_connector.accounts.first,
);
return txHash;
}
}
```
### Phantom Integration
Para includes a Phantom connector for Solana interactions:
```dart
import 'package:para/para.dart';
import 'package:solana_web3/solana_web3.dart';
class PhantomService {
late ParaPhantomConnector _connector;
void initialize() {
_connector = ParaPhantomConnector(
para: para,
appUrl: 'https://yourapp.com',
appScheme: 'yourapp',
);
}
Future connectPhantom() async {
try {
await _connector.connect();
print('Phantom connected');
} catch (e) {
print('Failed to connect Phantom: $e');
}
}
Future signMessage(String message) async {
final signature = await _connector.signMessage(message);
return signature;
}
/// Sign a transaction using serialized transaction bytes
/// Returns: Base58 encoded signed transaction that must be sent to the network
Future signTransactionBytes(Uint8List transactionBytes) async {
final signedTxBase58 = await _connector.signTransactionBytes(transactionBytes);
return signedTxBase58;
}
}
```
## Example: Complete External Wallet Flow
Here's a complete example showing external wallet authentication and usage:
```dart
import 'package:flutter/material.dart';
import 'package:para/para.dart';
class ExternalWalletScreen extends StatefulWidget {
@override
_ExternalWalletScreenState createState() => _ExternalWalletScreenState();
}
class _ExternalWalletScreenState extends State {
ParaMetaMaskConnector? _metamaskConnector;
ParaPhantomConnector? _phantomConnector;
bool _isConnected = false;
@override
void initState() {
super.initState();
_initializeConnectors();
}
void _initializeConnectors() {
_metamaskConnector = ParaMetaMaskConnector(
para: para,
appUrl: 'https://yourapp.com',
appScheme: 'yourapp',
);
_phantomConnector = ParaPhantomConnector(
para: para,
appUrl: 'https://yourapp.com',
appScheme: 'yourapp',
);
}
Future _connectMetaMask() async {
try {
await _metamaskConnector!.connect();
setState(() => _isConnected = true);
// Check if Para session is active after connection
final isActive = await para.isSessionActive().future;
if (isActive) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('MetaMask connected and authenticated with Para!')),
);
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to connect MetaMask: $e')),
);
}
}
Future _connectPhantom() async {
try {
await _phantomConnector!.connect();
setState(() => _isConnected = true);
// Check if Para session is active after connection
final isActive = await para.isSessionActive().future;
if (isActive) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Phantom connected and authenticated with Para!')),
);
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to connect Phantom: $e')),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('External Wallets')),
body: Padding(
padding: EdgeInsets.all(16),
child: Column(
children: [
Text(
'Connect an external wallet to get started',
style: Theme.of(context).textTheme.headlineSmall,
),
SizedBox(height: 32),
// MetaMask Connection
ElevatedButton.icon(
onPressed: _connectMetaMask,
icon: Icon(Icons.account_balance_wallet),
label: Text('Connect MetaMask'),
style: ElevatedButton.styleFrom(
minimumSize: Size(double.infinity, 50),
),
),
SizedBox(height: 16),
// Phantom Connection
ElevatedButton.icon(
onPressed: _connectPhantom,
icon: Icon(Icons.account_balance_wallet),
label: Text('Connect Phantom'),
style: ElevatedButton.styleFrom(
minimumSize: Size(double.infinity, 50),
),
),
],
),
),
);
}
}
```
## Security Considerations
When working with external wallets:
1. **Validate Connections**: Always verify the wallet connection before performing operations
2. **Handle Errors Gracefully**: External wallet apps may not be installed or might reject connections
3. **User Experience**: Provide clear instructions for users on wallet installation and connection
4. **Permissions**: Ensure your app requests appropriate permissions for wallet interactions
5. **Deep Link Security**: Validate deep link callbacks to prevent malicious redirects
## Troubleshooting
Common issues and solutions:
### Connection Failures
```dart
Future connectWithRetry(VoidCallback connectFunction) async {
int retries = 3;
while (retries > 0) {
try {
await connectFunction();
return;
} catch (e) {
retries--;
if (retries == 0) {
throw Exception('Failed to connect after 3 attempts: $e');
}
await Future.delayed(Duration(seconds: 2));
}
}
}
```
### Phantom Transaction Errors
When working with Phantom, use the transaction helper for proper encoding:
```dart
import 'package:para/para.dart';
// Convert signed transaction for network submission
final signedTxBase64 = ParaPhantomTransactionHelper.signedTransactionToBase64(signedTxBase58);
// Send to Solana network
final signature = await solanaClient.rpcClient.sendTransaction(signedTxBase64);
```
### Wallet App Not Installed
```dart
Future isWalletInstalled(String walletScheme) async {
try {
return await canLaunchUrl(Uri.parse('$walletScheme://'));
} catch (e) {
return false;
}
}
Future openWalletInstallPage(String storeUrl) async {
if (await canLaunchUrl(Uri.parse(storeUrl))) {
await launchUrl(Uri.parse(storeUrl));
}
}
```
### Network Issues
Ensure you have the correct network selected in your external wallet:
* **Phantom**: Check that you're on the intended Solana network (mainnet-beta, devnet, testnet)
* **MetaMask**: Verify you're connected to the correct Ethereum network
* **Transactions**: Use testnet/devnet for development to avoid spending real funds
## Key Features
Para's Flutter SDK provides:
* **Unified Architecture**: External wallets integrate seamlessly with Para's unified wallet system
* **Direct Blockchain Access**: Uses web3dart for Ethereum and solana\_web3 for Solana interactions
* **Deep Link Support**: Handles wallet app redirections automatically
* **Transaction Helpers**: Utility classes for transaction encoding/decoding
* **Error Handling**: Comprehensive error handling for wallet interactions
⚠️ Important Notes
* External wallets use blockchain packages directly for maximum compatibility
* The Flutter SDK maintains these dependencies to support external wallet features
* Phantom's `signAndSendTransaction` method is deprecated - use `signTransactionBytes` instead
* Always validate wallet connections before performing operations
## Resources
For more information about external wallet integration:
# Wallet Pregeneration
Source: https://docs.getpara.com/v2/flutter/guides/pregen
Create and manage pregenerated wallets for users in Flutter applications
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
Para's Wallet Pregeneration feature allows you to create wallets for users before they authenticate, giving you control over when and how users claim ownership of their wallets. This is particularly powerful in mobile applications, where you can leverage device-specific storage capabilities for enhanced user experiences.
## Mobile-Specific Benefits
While pregeneration works the same across all Para SDKs, Flutter applications offer unique advantages:
Pregeneration is especially valuable for devices that may not have full WebAuthn support for passkeys. It allows you to create Para wallets for users on any device while managing the security of the wallet yourself.
## Creating Pregenerated Wallets
In Flutter, you can create pregenerated wallets of multiple types with a single method call:
```dart
import 'package:para/para.dart';
Future> createPregenWallets() async {
final pregenWalletsFuture = para.createPregenWalletPerType(
pregenId: {'EMAIL': 'user@example.com'}, // Map format for pregen ID
types: [WalletType.evm], // Optionally specify wallet types
);
final pregenWallets = await pregenWalletsFuture.future;
// Get the user share
final userShareFuture = para.getUserShare();
final userShare = await userShareFuture.future;
// Store user share securely (see storage options below)
return pregenWallets;
}
```
## Mobile Storage Options
In Flutter applications, you have several options for securely storing the user share:
```dart
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
final storage = FlutterSecureStorage();
// Store the user share
Future storeUserShare(String userShare) async {
try {
await storage.write(
key: 'para_user_share',
value: userShare,
);
} catch (e) {
// Handle error
}
}
// Retrieve the user share
Future retrieveUserShare() async {
try {
return await storage.read(key: 'para_user_share');
} catch (e) {
// Handle error
return null;
}
}
```
```dart
import 'package:encrypted_shared_preferences/encrypted_shared_preferences.dart';
final encryptedPrefs = EncryptedSharedPreferences();
// Store the user share
Future storeUserShare(String userShare) async {
try {
await encryptedPrefs.setString('para_user_share', userShare);
} catch (e) {
// Handle error
}
}
// Retrieve the user share
Future retrieveUserShare() async {
try {
return await encryptedPrefs.getString('para_user_share');
} catch (e) {
// Handle error
return null;
}
}
```
Whichever storage method you choose, ensure you implement proper security measures. The user share is critical for wallet access, and if lost, the wallet becomes permanently inaccessible.
## Using Pregenerated Wallets in Flutter Apps
Once you have created a pregenerated wallet and stored the user share, you can use it for signing operations:
```dart
import 'dart:convert';
import 'package:para/para.dart';
Future usePregenWallet(String walletId) async {
// Retrieve the user share from your secure storage
final userShare = await retrieveUserShare();
if (userShare == null) {
throw Exception("User share not found");
}
// Load the user share into the Para client
await para.setUserShare(userShare);
// Now you can perform signing operations
final messageBase64 = base64Encode(utf8.encode("Hello, World!"));
final signatureFuture = para.signMessage(
walletId: walletId,
messageBase64: messageBase64,
);
final signatureResult = await signatureFuture.future;
// The signature is in the signedTransaction property
return (signatureResult as SuccessfulSignatureResult).signedTransaction;
}
```
### Mobile-Specific Use Cases
Create wallets that are bound to a specific device by using device-specific identifiers combined with secure local storage. This approach is ideal for multi-device users who need different wallets for different devices.
```dart
import 'package:device_info_plus/device_info_plus.dart';
import 'package:para/para.dart';
Future> createDeviceWallet() async {
final deviceInfo = DeviceInfoPlugin();
String deviceId;
if (Platform.isAndroid) {
final androidInfo = await deviceInfo.androidInfo;
deviceId = androidInfo.id;
} else if (Platform.isIOS) {
final iosInfo = await deviceInfo.iosInfo;
deviceId = iosInfo.identifierForVendor ?? 'unknown';
} else {
deviceId = 'unknown';
}
final pregenWalletsFuture = para.createPregenWalletPerType(
pregenId: {'CUSTOM_ID': 'device-$deviceId'},
);
final pregenWallets = await pregenWalletsFuture.future;
// Store the user share in device-specific secure storage
final userShare = await para.getUserShare().future;
await storeUserShare(userShare);
return pregenWallets;
}
```
Seamlessly introduce blockchain functionality to your existing app users without requiring them to understand wallets or crypto.
```dart
import 'package:para/para.dart';
Future> createWalletForExistingUser(String userId) async {
final pregenIdentifier = "user-$userId";
try {
final pregenWalletsFuture = para.createPregenWalletPerType(
pregenId: {'CUSTOM_ID': pregenIdentifier},
);
final pregenWallets = await pregenWalletsFuture.future;
final userShare = await para.getUserShare().future;
await storeUserShare(userShare);
return pregenWallets;
} catch (e) {
// Handle errors
throw e;
}
}
```
## Claiming Pregenerated Wallets
When a user is ready to take ownership of their pregenerated wallet, they can claim it once they've authenticated with Para:
```dart
import 'package:para/para.dart';
Future claimWallet(Map pregenId) async {
// Ensure user is authenticated
if (!(await para.isSessionActive().future)) {
throw Exception("User must be authenticated to claim wallets");
}
// Retrieve and load the user share
final userShare = await retrieveUserShare();
if (userShare != null) {
await para.setUserShare(userShare);
}
// Claim the wallet with the pregen ID
final claimFuture = para.claimPregenWallets(
pregenId: pregenId, // e.g., {'EMAIL': 'user@example.com'}
);
final recoverySecret = await claimFuture.future;
// Optionally, clear the locally stored user share after claiming
// since Para now manages it through the user's authentication
await clearUserShare();
return recoverySecret;
}
```
After claiming, Para will manage the user share through the user's authentication methods. You can safely remove the user share from your local storage if you no longer need to access the wallet directly.
## Best Practices for Mobile
1. **Utilize Device Security**: Leverage biometric authentication (TouchID/FaceID) to protect access to locally stored user shares.
2. **Implement Device Sync**: For users with multiple devices, consider implementing your own synchronization mechanism for user shares across devices.
3. **Handle Offline States**: Mobile applications often work offline. Design your pregenerated wallet system to function properly even when connectivity is limited.
4. **Backup Strategies**: Provide users with options to back up their wallet data, especially for device-specific wallets that might not be associated with their Para account.
5. **Clear Security Boundaries**: Clearly communicate to users when they're using an app-managed wallet versus a personally-owned wallet.
## Related Resources
# Flutter Session Management
Source: https://docs.getpara.com/v2/flutter/guides/sessions
Guide to managing authentication sessions in Para for Flutter applications
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
Para provides a comprehensive set of methods for managing authentication sessions in Flutter applications. These sessions are crucial for secure transaction signing and other authenticated operations.
## Session Duration
The Para session length is `2 hours` by default, but can be configured to up to 30 days. To configure this parameter, please visit the Configuration section of the . A user signing a message or transaction extends the session by the duration of the session length.
## Managing Sessions
### Checking Session Status
Use `isSessionActive()` to verify whether a user's session is currently valid before performing authenticated operations.
```dart
Future isSessionActive()
```
In Flutter applications, it's especially important to check the session status before allowing users to access authenticated areas of your app due to the persistence of local storage between app launches.
Example usage:
```dart
import 'package:para/para.dart';
Future checkSession() async {
try {
final isActive = await para.isSessionActive().future;
if (!isActive) {
// First clear any existing data
await para.logout().future;
// Navigate to login screen
// Handle navigation according to your app's navigation strategy
} else {
// Session is valid, proceed with app flow
// Navigate to authenticated part of your app
}
} catch (e) {
// Handle error
}
}
```
### Refreshing Expired Sessions
When a session has expired, Para recommends initiating a full authentication flow rather than trying to refresh the session.
For Flutter applications, always call `logout()` before reinitiating authentication when a session has expired to ensure all stored data is properly cleared.
```dart
import 'package:para/para.dart';
Future handleSessionExpiration() async {
// When session expires, first clear storage
await para.logout().future;
// Then redirect to authentication screen
// Handle navigation according to your app's navigation strategy
}
```
## Exporting Sessions to Your Server
Use `exportSession()` when you need to transfer session state to your server for performing operations on behalf of the user.
```dart
String exportSession()
```
Example implementation:
```dart
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:para/para.dart';
Future> sendSessionToServer() async {
// Export session without signing capabilities
final sessionData = para.exportSession();
// Send to your server
try {
final response = await http.post(
Uri.parse('https://your-api.com/sessions'),
headers: {
'Content-Type': 'application/json',
},
body: jsonEncode({'session': sessionData}),
);
if (response.statusCode != 200) {
throw Exception('Failed to send session to server');
}
return jsonDecode(response.body);
} catch (e) {
// Handle error
throw e;
}
}
```
## Best Practices for Flutter
1. **Check Sessions on App Launch**: Verify session status when your app starts to determine if users need to reauthenticate.
```dart
import 'package:flutter/material.dart';
import 'package:para/para.dart';
// In your app's entry point or state initialization
@override
void initState() {
super.initState();
checkSessionOnLaunch();
}
Future checkSessionOnLaunch() async {
final isActive = await para.isSessionActive().future;
if (isActive) {
// Navigate to authenticated part of your app
} else {
await para.logout().future; // Clear any lingering data
// Navigate to login screen
}
}
```
2. **Handle App Lifecycle Changes**: Flutter apps can be backgrounded and foregrounded, which may affect session status.
```dart
import 'package:flutter/material.dart';
import 'package:para/para.dart';
class YourWidget extends StatefulWidget {
@override
_YourWidgetState createState() => _YourWidgetState();
}
class _YourWidgetState extends State with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
// App came to foreground, check session
checkSession();
}
}
Future checkSession() async {
final isActive = await para.isSessionActive().future;
if (!isActive) {
await para.logout().future;
// Navigate to login screen
}
}
@override
Widget build(BuildContext context) {
// Your widget implementation
return Container();
}
}
```
## Next Steps
Explore more advanced features and integrations with Para in Flutter:
# Social Login
Source: https://docs.getpara.com/v2/flutter/guides/social-login
Implementing social login with Para in Flutter applications
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Para supports social login authentication in Flutter applications, allowing users to sign in using popular providers like Google, Apple, Twitter, Discord, and Facebook. This guide explains how to implement social login in your Flutter app using Para's Flutter SDK v2.
The social login flow in mobile applications requires handling browser sessions and deeplinks to redirect users back to your app after successful authentication. Para's v2 API provides a streamlined flow that automatically handles both new and existing users.
## Prerequisites
Before implementing social login, ensure you have completed the basic Para setup for your Flutter application.
## Configuration
First, set up URL schemes to handle OAuth callbacks:
Add URL schemes to your `Info.plist` file to handle callbacks from authentication:
```xml
CFBundleURLTypes
CFBundleTypeRole
Editor
CFBundleURLSchemes
yourapp
```
In your `AndroidManifest.xml`, add the callback activity and URL scheme:
```xml
```
The URL scheme should match the `appScheme` parameter you used when initializing Para (e.g., `yourapp`).
## Implementation
### V2 OAuth Authentication
Para's v2 API provides a streamlined OAuth flow that handles both new and existing users:
```dart
import 'package:para/para.dart';
Future authenticateWithOAuth(OAuthMethod provider) async {
try {
// Handle OAuth flow - this manages the entire process
final authState = await para.verifyOAuth(
provider: provider,
appScheme: 'yourapp', // Your app's deep link scheme
);
// Handle the result based on auth stage
switch (authState.stage) {
case AuthStage.login:
// Existing user - proceed to login with passkey
final wallet = await para.handleLogin(
authState: authState,
);
print('User logged in: ${wallet.address}');
break;
case AuthStage.signup:
// New user - create wallet
final wallet = await para.handleSignup(
authState: authState,
method: SignupMethod.passkey,
);
print('New wallet created: ${wallet.address}');
break;
default:
print('Unexpected auth stage: ${authState.stage}');
}
} catch (e) {
print('OAuth authentication failed: $e');
}
}
```
### Individual OAuth Providers
```dart Google OAuth
Future loginWithGoogle() async {
await authenticateWithOAuth(OAuthMethod.google);
}
```
```dart Apple OAuth
Future loginWithApple() async {
await authenticateWithOAuth(OAuthMethod.apple);
}
```
```dart Twitter OAuth
Future loginWithTwitter() async {
await authenticateWithOAuth(OAuthMethod.twitter);
}
```
```dart Discord OAuth
Future loginWithDiscord() async {
await authenticateWithOAuth(OAuthMethod.discord);
}
```
```dart Facebook OAuth
Future loginWithFacebook() async {
await authenticateWithOAuth(OAuthMethod.facebook);
}
```
### Farcaster Authentication
Farcaster authentication follows a unique flow in V2:
```dart
Future authenticateWithFarcaster() async {
// Step 1: Get the Farcaster connect URI
final connectUri = await para.getFarcasterConnectUri().future;
// Step 2: Launch the URI (opens Farcaster app/website for user authorization)
if (await canLaunchUrl(Uri.parse(connectUri))) {
await launchUrl(Uri.parse(connectUri));
}
// Step 3: Poll for verification result
final authState = await para.verifyFarcaster().future;
// Step 4: Handle the authentication state
switch (authState.stage) {
case AuthStage.login:
// Existing user - open passkey URL and wait for login
if (authState.passkeyUrl != null) {
final webAuthSession = FlutterWebAuthSession(
callbackUrlScheme: 'yourapp',
);
await launchUrl(Uri.parse(authState.passkeyUrl!));
// Wait for login to complete
final loginResult = await para.waitForLogin().future;
print('Farcaster user logged in');
}
break;
case AuthStage.signup:
// New user - create wallet
if (authState.passkeyUrl != null) {
final webAuthSession = FlutterWebAuthSession(
callbackUrlScheme: 'yourapp',
);
await launchUrl(Uri.parse(authState.passkeyUrl!));
// Wait for wallet creation
final walletResult = await para.waitForWalletCreation().future;
print('New Farcaster wallet created');
}
break;
case AuthStage.verify:
// Should not occur for Farcaster
print('Unexpected verify stage for Farcaster');
break;
}
}
```
## Available OAuth Providers
Para supports the following OAuth providers:
| Provider | Enum Value | Description |
| -------- | ---------------------- | ------------------------------ |
| Google | `OAuthMethod.google` | Google authentication |
| Apple | `OAuthMethod.apple` | Apple Sign-In |
| Twitter | `OAuthMethod.twitter` | Twitter (X.com) authentication |
| Discord | `OAuthMethod.discord` | Discord authentication |
| Facebook | `OAuthMethod.facebook` | Facebook authentication |
## Complete Social Login Widget
Here's a complete example of a social login widget:
```dart
import 'package:flutter/material.dart';
import 'package:para/para.dart';
class SocialLoginWidget extends StatefulWidget {
@override
_SocialLoginWidgetState createState() => _SocialLoginWidgetState();
}
class _SocialLoginWidgetState extends State {
bool _isLoading = false;
Future _handleOAuthLogin(OAuthMethod provider) async {
if (_isLoading) return;
setState(() => _isLoading = true);
try {
// Use the unified OAuth flow for v2
final authState = await para.verifyOAuth(
provider: provider,
appScheme: 'yourapp',
);
// OAuth authentication handles both new and existing users
final isActive = await para.isSessionActive().future;
if (isActive) {
_navigateToHome();
return;
}
} catch (e) {
_showError('Authentication failed: $e');
} finally {
setState(() => _isLoading = false);
}
}
Future _handleFarcasterLogin() async {
if (_isLoading) return;
setState(() => _isLoading = true);
try {
// Step 1: Get the Farcaster connect URI
final connectUri = await para.getFarcasterConnectUri().future;
// Step 2: Launch the URI
if (await canLaunchUrl(Uri.parse(connectUri))) {
await launchUrl(Uri.parse(connectUri));
}
// Step 3: Poll for verification result
final authState = await para.verifyFarcaster().future;
// Step 4: Handle the authentication state
switch (authState.stage) {
case AuthStage.login:
case AuthStage.signup:
if (authState.passkeyUrl != null) {
await launchUrl(Uri.parse(authState.passkeyUrl!));
// Wait for completion
if (authState.stage == AuthStage.login) {
await para.waitForLogin().future;
} else {
await para.waitForWalletCreation().future;
}
}
break;
case AuthStage.verify:
// Should not occur for Farcaster
break;
}
_navigateToHome();
} catch (e) {
_showError('Farcaster authentication failed: $e');
} finally {
setState(() => _isLoading = false);
}
}
@override
Widget build(BuildContext context) {
return Column(
children: [
_SocialButton(
onPressed: () => _handleOAuthLogin(OAuthMethod.google),
icon: Icons.login,
label: 'Continue with Google',
isLoading: _isLoading,
),
SizedBox(height: 12),
_SocialButton(
onPressed: () => _handleOAuthLogin(OAuthMethod.apple),
icon: Icons.apple,
label: 'Continue with Apple',
isLoading: _isLoading,
),
SizedBox(height: 12),
_SocialButton(
onPressed: () => _handleOAuthLogin(OAuthMethod.twitter),
icon: Icons.alternate_email,
label: 'Continue with Twitter',
isLoading: _isLoading,
),
SizedBox(height: 12),
_SocialButton(
onPressed: () => _handleFarcasterLogin(),
icon: Icons.forum,
label: 'Continue with Farcaster',
isLoading: _isLoading,
),
],
);
}
void _navigateToHome() {
// Navigate to your app's main screen
Navigator.pushReplacementNamed(context, '/home');
}
void _showError(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(message)),
);
}
}
class _SocialButton extends StatelessWidget {
final VoidCallback onPressed;
final IconData icon;
final String label;
final bool isLoading;
const _SocialButton({
required this.onPressed,
required this.icon,
required this.label,
required this.isLoading,
});
@override
Widget build(BuildContext context) {
return SizedBox(
width: double.infinity,
child: ElevatedButton.icon(
onPressed: isLoading ? null : onPressed,
icon: isLoading
? SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(strokeWidth: 2),
)
: Icon(icon),
label: Text(label),
style: ElevatedButton.styleFrom(
padding: EdgeInsets.symmetric(vertical: 12),
),
),
);
}
}
```
## Session Management
Check if a user is already authenticated when your app starts:
```dart
Future checkAuthStatus() async {
final isActive = await para.isSessionActive().future;
if (isActive) {
// User is logged in
final authDetails = await para.getCurrentUserAuthDetails().future;
final wallets = await para.fetchWallets().future;
print('User is logged in with ${wallets.length} wallets');
// Navigate to main app
Navigator.pushReplacementNamed(context, '/home');
} else {
// Show login screen
Navigator.pushReplacementNamed(context, '/login');
}
}
```
Social login with Para still requires creating a native passkey to secure the user's wallets. After social authentication completes, Para associates a native passkey with the user's account. For returning users, the native passkey is used for authentication. The passkey is associated on a per-app basis, making authentication streamlined.
## Error Handling
Handle common OAuth errors:
```dart
Future handleOAuthWithErrorHandling(OAuthMethod provider) async {
try {
await authenticateWithOAuth(provider);
} catch (e) {
if (e.toString().contains('cancelled')) {
// User cancelled the OAuth flow
print('Authentication cancelled by user');
} else if (e.toString().contains('network')) {
// Network error
print('Network error during authentication');
} else {
// Other errors
print('Authentication error: $e');
}
}
}
```
## Examples
Explore our complete example implementations for social login with Para:
## Next Steps
After integrating Para, you can explore other features and integrations to enhance your Para experience.
# Solana Integration
Source: https://docs.getpara.com/v2/flutter/guides/solana
Sign Solana transactions using Para's unified wallet architecture
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
## Quick Start
```dart
import 'package:para/para.dart';
// Sign a Solana transaction
final para = Para(apiKey: 'your-api-key');
final wallet = (await para.fetchWallets()).firstWhere((w) => w.type == 'SOLANA');
final transaction = SolanaTransaction(
to: '9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM',
lamports: '1000000', // 0.001 SOL
feePayer: null, // Uses wallet as fee payer
recentBlockhash: null, // Fetched automatically with RPC URL
);
final result = await para.signTransaction(
walletId: wallet.id!,
transaction: transaction.toJson(),
chainId: null, // Not needed for Solana
rpcUrl: 'https://api.devnet.solana.com',
);
print('Transaction signed: ${result.signedTransaction}');
```
## Common Operations
### Sign Transaction
```dart
final transaction = SolanaTransaction(
to: '9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM',
lamports: '1000000', // 0.001 SOL
feePayer: null, // Uses wallet as fee payer
recentBlockhash: null, // Fetched automatically with RPC URL
);
final result = await para.signTransaction(
walletId: wallet.id!,
transaction: transaction.toJson(),
chainId: null, // Not needed for Solana
rpcUrl: 'https://api.devnet.solana.com',
);
print('Signed: ${result.signedTransaction}');
```
### Check Balance
```dart
final balance = await para.getBalance(
walletId: wallet.id!,
token: null, // Native SOL
rpcUrl: 'https://api.devnet.solana.com',
);
// Convert lamports to SOL
final lamports = double.parse(balance);
final sol = lamports / 1000000000;
print('Balance: ${sol.toStringAsFixed(4)} SOL');
```
### Sign Message
```dart
final message = 'Hello, Solana!';
final result = await para.signMessage(
walletId: wallet.id!,
message: message,
);
print('Signature: ${result.signedTransaction}');
```
## Networks
### Testnets
| Network | RPC URL | Native Token |
| ----------- | -------------------------------- | ------------ |
| **Devnet** | `https://api.devnet.solana.com` | SOL |
| **Testnet** | `https://api.testnet.solana.com` | SOL |
### Mainnet
| Network | RPC URL | Native Token | Network Type |
| ----------- | -------------------------------------------------- | ------------ | ------------ |
| **Mainnet** | `https://api.mainnet-beta.solana.com` | SOL | Production |
| **Alchemy** | `https://solana-mainnet.g.alchemy.com/v2/YOUR_KEY` | SOL | Production |
## Complete Example
```dart
import 'package:flutter/material.dart';
import 'package:para/para.dart';
class SolanaWalletView extends StatefulWidget {
final Para para;
final Wallet wallet;
const SolanaWalletView({required this.para, required this.wallet});
@override
State createState() => _SolanaWalletViewState();
}
class _SolanaWalletViewState extends State {
bool _isLoading = false;
String? _signature;
final String _rpcUrl = 'https://api.devnet.solana.com';
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Text(
widget.wallet.address ?? 'No address',
style: TextStyle(fontFamily: 'monospace', fontSize: 12),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: _isLoading ? null : _signTransaction,
child: Text(_isLoading ? 'Signing...' : 'Sign Transaction'),
),
if (_signature != null)
Padding(
padding: const EdgeInsets.only(top: 20),
child: Text('Signed: $_signature', style: TextStyle(fontSize: 12)),
),
],
),
);
}
Future _signTransaction() async {
setState(() => _isLoading = true);
try {
final transaction = SolanaTransaction(
to: '9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM',
lamports: '1000000', // 0.001 SOL
feePayer: null,
recentBlockhash: null,
);
final result = await widget.para.signTransaction(
walletId: widget.wallet.id!,
transaction: transaction.toJson(),
chainId: null, // Not needed for Solana
rpcUrl: _rpcUrl,
);
setState(() => _signature = result.signedTransaction);
} catch (e) {
print('Error: $e');
} finally {
setState(() => _isLoading = false);
}
}
}
```
## Advanced Transaction Options
```dart
// Transaction with memo
final transaction = SolanaTransaction(
to: '9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM',
lamports: '1000000',
memo: 'Payment for services',
);
// Transaction with custom blockhash
final transaction = SolanaTransaction(
to: '9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM',
lamports: '1000000',
recentBlockhash: 'custom_blockhash',
feePayer: wallet.address,
);
```
# Flutter SDK Overview
Source: https://docs.getpara.com/v2/flutter/overview
Para Flutter SDK documentation for cross-platform wallet integration
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Para Flutter SDK eliminates the complexity of blockchain integration by providing a unified interface for wallet creation, authentication, and multi-chain transactions across iOS and Android.
## Quick Start
```dart main.dart
// Initialize Para
final para = Para.fromConfig(
config: ParaConfig(
apiKey: 'YOUR_API_KEY',
environment: Environment.beta,
),
appScheme: 'yourapp',
);
// Authenticate user
final authState = await para.initiateAuthFlow(
auth: Auth.email('user@example.com')
);
// Handle login for existing user
if (authState.stage == AuthStage.login) {
await para.handleLogin(authState: authState);
}
```
## Sign Transactions
```dart transaction_handler.dart
// Get wallets
final wallets = await para.fetchWallets();
final evmWallet = wallets.firstWhere((w) => w.type == WalletType.evm);
final solanaWallet = wallets.firstWhere((w) => w.type == WalletType.solana);
// EVM transaction
final evmTransaction = {
'to': '0x742d35Cc6634C0532925a3b844Bc9e7595f6E2c0',
'value': '0x38d7ea4c68000', // 0.001 ETH in hex
'gas': '0x5208', // 21000 in hex
};
final evmResult = await para.signTransaction(
walletId: evmWallet.id,
transaction: evmTransaction,
chainId: '11155111', // Sepolia
rpcUrl: 'https://rpc.ankr.com/eth_sepolia',
);
// Solana message signing
final signature = await para.signMessage(
walletId: solanaWallet.id,
message: 'Hello, Solana!',
);
```
## Next Steps
# Setup
Source: https://docs.getpara.com/v2/flutter/setup
Step-by-step guide for integrating the Para Flutter SDK into your mobile application
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label}) => {
e.currentTarget.querySelector("#underline").style.height = "2px";
}} onMouseLeave={e => {
e.currentTarget.querySelector("#underline").style.height = "1px";
}}>
{label}
;
The Para Flutter SDK enables you to integrate secure wallet features including creation, passkey-based authentication, and transaction signing into your mobile applications. This guide covers all necessary steps from installation to implementing authentication flows.
## Prerequisites
To use Para, you need an API key. This key authenticates your requests to Para services and is essential for
integration.
Don't have an API key yet? Request access to the to create API keys, manage billing, teams, and more.
## Install the SDK
Start by installing the Para SDK:
```bash
flutter pub add para
```
## Configure URL Scheme
Configure your app's URL scheme for OAuth authentication flows. This enables OAuth providers to redirect back to your app after authentication.
1. In Xcode, select your project in the navigator
2. Select your app target
3. Go to the **Info** tab
4. Scroll down to **URL Types** and click **+** to add a new URL type
5. Fill in the fields:
* **URL Schemes**: Enter your scheme name (e.g., `yourapp`, `myflutterapp`)
* **Role**: Select **Editor**
* **Identifier**: Use your bundle identifier or a descriptive name
Make sure your URL scheme is unique to avoid conflicts with other apps. Use a scheme related to your app's bundle ID (e.g., `com.mycompany.myapp`) for uniqueness.
Configure URL scheme handling in your `android/app/src/main/AndroidManifest.xml` file:
1. Locate your MainActivity in the AndroidManifest.xml
2. Update your MainActivity with the complete configuration below:
```xml
```
**Android 12+ Requirement:** The `android:exported="true"` attribute is mandatory for apps targeting Android 12 (API 31) and higher when the activity has intent filters.
Replace `yourapp` with your actual app scheme. This scheme must match the `appScheme` parameter used in Para initialization. The `android:launchMode="singleTop"` prevents multiple instances of your app from being created when deep links are opened.
## Configure Associated Domains for Passkeys
To enable passkeys in your Flutter project, you need to configure both iOS and Android platforms:
To enable passkeys on iOS, you need to configure Associated Domains:
1. Open your Flutter project's iOS folder in Xcode
2. In Xcode, go to **Signing & Capabilities** for your app target
3. Click **+ Capability** and add **Associated Domains**
4. Add the following entries:
```
webcredentials:app.usecapsule.com
webcredentials:app.beta.usecapsule.com
```
5. Register your Team ID + Bundle ID with Para via the
Without properly registering your Team ID and Bundle ID with Para, passkey authentication flows will fail. Contact Para support if you encounter issues with passkey registration.
### Get SHA-256 Fingerprint
To get your SHA-256 fingerprint:
* For debug builds: `keytool -list -v -keystore ~/.android/debug.keystore`
* For release builds: `keytool -list -v -keystore `
Register your package name and SHA-256 fingerprint with Para via the
Without properly registering your package name and SHA-256 fingerprint with Para, passkey authentication flows will fail. Contact Para support if you encounter issues with passkey registration.
**Quick Testing Option**: You can use `com.getpara.example.flutter` as your package name for immediate testing. This package name is pre-registered and works with the SHA-256 certificate from the default debug.keystore, making it testable in debug mode for newly scaffolded Flutter apps.
### Fix Namespace Issue
For newer versions of Flutter, you need to add the following configuration block to your `android/build.gradle` file to resolve a namespace issue with the passkey dependency:
```gradle
subprojects {
afterEvaluate { project ->
if (project.hasProperty('android')) {
project.android {
if (namespace == null) {
namespace project.group
}
}
}
}
}
```
### Device Requirements
To ensure passkey functionality works correctly:
* Enable biometric or device unlock settings (fingerprint, face unlock, or PIN)
* Sign in to a Google account on the device (required for Google Play Services passkey management)
## Initialize Para
To use Para's features, you'll need to initialize a Para client instance that can be accessed throughout your app. This
client handles all interactions with Para's services, including authentication, wallet management, and transaction
signing.
Create a file (e.g., `lib/services/para_client.dart`) to initialize your Para client:
```dart lib/services/para_client.dart
import 'package:para/para.dart';
// Para Configuration
final config = ParaConfig(
apiKey: 'YOUR_PARA_API_KEY', // Get from: https://developer.getpara.com
environment: Environment.beta, // Use Environment.prod for production
);
// Initialize Para client instance using v2 factory constructor
final para = Para.fromConfig(
config: config,
appScheme: 'yourapp', // Your app's scheme (without ://)
);
```
You can access `para` from anywhere in your app by importing the file where you initialized it. This singleton pattern
ensures consistent state management across your application.
## Authenticate Users
Para provides a unified authentication experience that supports email, phone, and social login methods. The SDK automatically determines whether a user is new or existing and guides you through the appropriate flow.
**Beta Testing Credentials** In the `BETA` Environment, you can use any email ending in `@test.getpara.com` (like
[dev@test.getpara.com](mailto:dev@test.getpara.com)) or US phone numbers (+1) in the format `(area code)-555-xxxx` (like (425)-555-1234). Any OTP
code will work for verification with these test credentials. These credentials are for beta testing only. You can
delete test users anytime in the beta developer console to free up user slots.
### Build Your Authentication Flow
The recommended approach is to create a single authentication view that handles all authentication methods together. This provides users with all authentication options in one place.
Para supports authentication with both email addresses and phone numbers.
Initiate authentication with email or phone:
```dart lib/views/authentication_view.dart
// Determine if input is email or phone
final Auth auth;
if (userInput.contains('@')) {
auth = Auth.email(userInput);
} else {
auth = Auth.phone(userInput); // Include country code
}
// SDK call: Initiate authentication
final authState = await para.initiateAuthFlow(auth: auth);
// Handle the result based on stage
switch (authState.stage) {
case AuthStage.verify:
// New user - needs verification (see OTP handling step below)
break;
case AuthStage.login:
// Existing user - complete login
await para.handleLogin(
authState: authState,
);
break;
case AuthStage.signup:
// Handle signup after verification
break;
}
```
For new users who need verification, handle the OTP flow:
```dart lib/views/authentication_view.dart
// After user enters the verification code
final verificationCode = "123456"; // Get from user input
try {
// Submit verification code
final verifiedState = await para.verifyOtp(
otp: verificationCode
);
// Complete signup with passkey
await para.handleSignup(
authState: verifiedState,
signupMethod: SignupMethod.passkey,
);
// User is now signed up and authenticated
} catch (e) {
// Handle error
}
```
Social login is integrated directly into the unified authentication view. Users can authenticate with Google, Apple, or Discord.
Implement the social login handler:
```dart lib/views/authentication_view.dart
Future handleSocialLogin(OAuthMethod provider) async {
try {
await para.verifyOAuth(
provider: provider,
appScheme: 'yourapp',
);
// User successfully authenticated
final isActive = await para.isSessionActive().future;
if (isActive) {
// Navigate to main app
}
} catch (e) {
// Handle error
print('OAuth login failed: ${e.toString()}');
}
}
```
## Handle Returning Users
After initial setup, users can log in using their email or phone with the same authentication flow:
```dart lib/views/login_view.dart
// Login with email
final authState = await para.initiateAuthFlow(
auth: Auth.email(userEmail)
);
// Since the user exists, authState.stage will be AuthStage.login
if (authState.stage == AuthStage.login) {
await para.handleLogin(
authState: authState,
);
// User is now logged in
}
```
Alternatively, you can use direct passkey login if you know the user has set up passkeys:
```dart lib/views/login_view.dart
// Direct passkey login (will show all available passkeys if email/phone not provided)
await para.loginWithPasskey(
email: userEmail, // Optional - helps filter passkeys
phone: null
);
```
This will prompt the user for biometric verification before granting access to their wallets.
## Check Authentication Status
You can check if a user is already authenticated:
```dart lib/views/content_view.dart
final isLoggedIn = await para.isSessionActive().future;
if (isLoggedIn) {
// User is authenticated, proceed to main app flow
} else {
// Show login/signup UI
}
```
## Sign Out Users
To sign out a user and clear their session:
```dart lib/views/settings_view.dart
await para.logout().future;
```
## Create and Manage Wallets
After successful authentication, you can perform wallet operations:
```dart lib/views/wallet_view.dart
// Get all user wallets
await para.fetchWallets(); // Ensure we have the latest wallets
final wallets = await para.fetchWallets().future;
if (wallets.isEmpty) {
// No wallets, perhaps create one
final wallet = await para.createWallet(
type: WalletType.evm,
skipDistribute: false,
).future;
print('Created wallet: ${wallet.address}');
// Sign a simple message (SDK handles Base64 encoding internally)
final signature = await para.signMessage(
walletId: wallet.id,
messageBase64: base64Encode(utf8.encode('Hello, Para!')),
).future;
print('Signature: ${(signature as SuccessfulSignatureResult).signedTransaction}');
} else {
// Use existing wallet
final firstWallet = wallets.first;
// Sign a simple message (SDK handles Base64 encoding internally)
final signature = await para.signMessage(
walletId: firstWallet.id,
messageBase64: base64Encode(utf8.encode('Hello, Para!')),
).future;
print('Signature: ${(signature as SuccessfulSignatureResult).signedTransaction}');
}
```
For detailed transaction signing with specific blockchains (EVM, Solana, Cosmos), please refer to the respective blockchain integration guides.
## Example
For a complete implementation example, check out our Flutter SDK example app:
## Next Steps
After integrating Para into your Flutter app, you can explore other features and integrations to enhance your Para experience.
# Flutter Troubleshooting Guide
Source: https://docs.getpara.com/v2/flutter/troubleshooting
Common issues and solutions when integrating Para with Flutter applications
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
This guide addresses common issues you might encounter when integrating Para with your Flutter application. It provides
solutions and best practices to ensure a smooth integration.
Using an LLM (ChatGPT, Claude) or Coding Assistant (Cursor, Github Copilot)? Here are a few tips:
1. Include the for the most up-to-date help
2. Check out the for an interactive LLM using Para Examples Hub
## General Troubleshooting Steps
Before diving into specific issues, try these general troubleshooting steps:
1. **Clean the project and get dependencies**:
```bash
flutter clean
flutter pub get
```
2. **Update Flutter and dependencies**:
```bash
flutter upgrade
flutter pub upgrade
```
3. **Ensure Para package is up to date**: Check your `pubspec.yaml` file and update the Para package version if
necessary.
4. **Rebuild the project**:
```bash
flutter run
```
## Common Issues and Solutions
### 1. Package Not Found or Version Conflicts
**Problem**: Dart can't find the Para package or there are version conflicts with other dependencies.
**Solution**: Ensure your `pubspec.yaml` file is correctly configured:
```yaml
dependencies:
flutter:
sdk: flutter
para: ^latest_version
dependency_overrides:
# Add any necessary overrides here
```
After updating `pubspec.yaml`, run:
```bash
flutter pub get
```
### 2. Platform-Specific Setup Issues
**Problem**: Para features not working on specific platforms (iOS/Android).
**Solution**: Ensure platform-specific configurations are correct:
For iOS (`ios/Runner/Info.plist`):
```xml
CFBundleURLTypes
CFBundleURLSchemes
para
```
For Android (`android/app/build.gradle`):
```gradle
android {
defaultConfig {
...
minSdkVersion 21
}
}
```
### 3. V2 API Initialization Errors
**Problem**: Para v2 fails to initialize or throws errors on startup.
**Solution**: Ensure proper initialization with required `appScheme` parameter:
```dart
import 'package:para/para.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final para = Para.fromConfig(
config: ParaConfig(
environment: Environment.beta,
apiKey: 'YOUR_API_KEY',
),
appScheme: 'yourapp', // Required in v2!
);
runApp(MyApp(para: para));
}
```
**Common v2 Initialization Issues**:
* Missing `appScheme` parameter
* Incorrect environment configuration
* Invalid API key format
### 4. V2 API ParaFuture Handling Errors
**Problem**: Errors when handling `ParaFuture` operations in v2 API.
**Solution**: Ensure proper `ParaFuture` handling with cancellation support:
```dart
try {
final walletFuture = para.createWallet(
type: WalletType.evm,
skipDistribute: false,
);
// Handle the ParaFuture properly
final wallet = await walletFuture.future;
print('Wallet created: ${wallet.address}');
// Cancel if needed
// await para.cancelOperationById(walletFuture.requestId);
} catch (e) {
print('Error creating wallet: $e');
// Handle ParaBridgeException specifically
if (e is ParaBridgeException) {
print('Bridge error code: ${e.code}');
}
}
```
**Common v2 ParaFuture Issues**:
* Not awaiting the `.future` property
* Incorrect cancellation handling
* Missing error type checking for `ParaBridgeException`
### 5. UI Thread Blocking
**Problem**: Para operations blocking the UI thread.
**Solution**: Use `compute` function for heavy computations:
```dart
import 'package:flutter/foundation.dart';
Future createWalletAsync(Para para) async {
return compute(_createWallet, para);
}
Future _createWallet(Para para) async {
final walletFuture = para.createWallet(
type: WalletType.evm,
skipDistribute: false,
);
return await walletFuture.future;
}
// Usage
final wallet = await createWalletAsync(para);
```
### 6. Platform Channel Errors
**Problem**: Errors related to platform channel communication.
**Solution**: Ensure the latest version of Para Flutter plugin is used and platform-specific code is correctly
implemented. If issues persist, check the plugin's GitHub repository for any known issues or updates.
## V2-Specific Issues
### 7. Authentication Flow Errors
**Problem**: V2 authentication flow failing or returning unexpected states.
**Solution**: Follow the correct v2 authentication pattern:
```dart
// Correct v2 flow
final authState = await para.initiateAuthFlow(
auth: Auth.email('user@example.com')
);
switch (authState.stage) {
case AuthStage.verify:
// Handle verification
final verifiedState = await para.verifyOtp(
otp: code
);
if (verifiedState.stage == AuthStage.signup) {
final wallet = await para.handleSignup(
authState: verifiedState,
method: SignupMethod.passkey,
);
}
break;
case AuthStage.login:
// Handle login
final wallet = await para.handleLogin(
authState: authState,
);
break;
}
```
### 8. OAuth Integration Issues
**Problem**: OAuth flows failing or not redirecting properly.
**Solution**: Ensure deep link configuration matches OAuth setup:
```dart
// Correct OAuth flow
final authState = await para.verifyOAuth(
provider: OAuthMethod.google,
appScheme: 'yourapp', // Must match your URL scheme
);
```
### 9. Extension Methods Not Found
**Problem**: `initiateAuthFlow()` or other extension methods not available.
**Solution**: Import the auth extensions:
```dart
import 'package:para/para.dart';
import 'package:para/src/auth_extensions.dart'; // Required for extension methods
// Now you can use
final authState = await para.initiateAuthFlow(
auth: Auth.email('user@example.com')
);
```
## Best Practices for V2
1. **Use ParaFuture Properly**: Always await the `.future` property and handle cancellation where appropriate.
2. **Error Handling**: Implement robust error handling with specific exception types:
```dart
try {
// Para operation
} on ParaBridgeException catch (e) {
// Handle Para-specific errors
} catch (e) {
// Handle general errors
}
```
3. **Session Management**: Use v2 session methods for persistence:
```dart
final isActive = await para.isSessionActive().future;
if (!isActive) {
// Show login screen
}
```
4. **State Management**: Use proper state management for v2 authentication flows.
5. **Deep Link Security**: Validate deep link callbacks to prevent malicious redirects.
6. **Testing**: Write unit and integration tests for your Para v2 integration.
7. **Performance Monitoring**: Monitor `ParaFuture` operations for performance.
8. **Keep Updated**: Regularly update to the latest v2 API changes.
## Debugging Tips
1. **Enable Verbose Logging**: Enable verbose logging for Para operations to get more detailed information:
```dart
Para.fromConfig(
config: ParaConfig(
environment: Environment.beta,
apiKey: 'YOUR_API_KEY',
logLevel: ParaLogLevel.verbose,
),
appScheme: 'yourapp',
);
```
2. **Use Flutter DevTools**: Utilize Flutter DevTools for performance profiling and debugging.
3. **Platform-Specific Debugging**: For platform-specific issues, use Xcode for iOS and Android Studio for Android
debugging.
## Setup and Integration Issues
If you're having trouble initializing the Para SDK:
* Ensure you're providing the required `appScheme` parameter
* Verify that you're using the correct API key and environment
* Check that all necessary dependencies are installed properly
* Look for any Dart errors in your Flutter debug console
* Verify that your Flutter version is compatible with the Para SDK
If passkey creation, retrieval, or usage isn't working:
* Verify that you've set up associated domains correctly in your iOS project
* For Android, check that you've configured your `build.gradle` file with the namespace fix
* Make sure you've provided the correct SHA-256 fingerprint to the Para team for Android
* Ensure that biometric authentication is enabled on the test device
* For Android, confirm the test device has a Google account signed in
* Check that `WebAuthenticationSession` is properly configured
If you're experiencing authentication issues:
* Double-check that your API key is correct and properly set in your Para client initialization
* Verify you're using the correct environment (`beta` or `prod`) that matches your API key
* Ensure your account has the necessary permissions for the operations you're attempting
* Check that your deep link scheme matches what's configured in your app
* Verify the authentication flow is being followed correctly (verify → signup/login)
If you're migrating from V1 to V2:
* Replace `signUpOrLogIn()` with `initiateAuthFlow()`
* Replace `verifyNewAccount()` with `verifyOtp()`
* Replace `loginWithPasskey()` with `handleLogin()`
* Remove calls to `init()` - it no longer exists
* Update constructor to use `Para.fromConfig()` factory method
* Add the required `appScheme` parameter (now without ://callback suffix)
* Update wallet creation to use `handleSignup()` with `SignupMethod.passkey` or `.password`
By following these troubleshooting steps and best practices, you should be able to resolve most common issues when
integrating Para with your Flutter application.
### Integration Support
If you're experiencing issues that aren't resolved by our troubleshooting resources, please [contact our team](https://join.slack.com/t/para-community/shared_invite/zt-304keeulc-Oqs4eusCUAJEpE9DBwAqrg) for
assistance. To help us resolve your issue quickly, please include the following information in your request:
1
A detailed description of the problem you're encountering.
2
Any relevant error messages or logs.
3
Steps to reproduce the issue.
4
Details about your system or environment (e.g., device, operating system, software version).
Providing this information will enable our team to address your concerns more efficiently.
# React Native & Expo SDK
Source: https://docs.getpara.com/v2/react-native/api/sdk
Documentation for the Para SDK in React Native and Expo applications
## ParaMobile Class
The `ParaMobile` class represents a mobile implementation of the Para SDK, extending the `CorePara` class.
### Methods
Creates an instance of ParaMobile.
The environment to use (BETA or PROD).
The API key for authentication.
The relying party ID for WebAuthn.
Additional constructor options.
Verifies an email and returns the biometrics ID.
The verification code sent to the email.
The biometrics ID.
Verifies a phone number and returns the biometrics ID.
The verification code sent to the phone.
The biometrics ID.
Registers a passkey for the user.
The user's email or phone number.
The biometrics ID obtained from verification.
The Web Crypto API instance.
The type of identifier used.
The country calling code for phone numbers.
A promise that resolves when the passkey is registered.
Logs in the user using either email or phone number.
The user's email address.
The user's phone number.
The country calling code for phone numbers.
An array of user wallets.
If neither email nor both phone and countryCode are provided.
# Mobile Examples
Source: https://docs.getpara.com/v2/react-native/examples
Explore Para's mobile integration examples for React Native and Expo
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Para offers a collection of mobile examples to help you integrate our technology into your React Native and Expo applications. These examples demonstrate minimal implementation requirements with clean, focused code that you can easily adapt to your specific application needs.
## Para Mobile Examples
Browse our mobile examples showcasing Para integration with React Native and Expo:
## Need Something Specific?
Don't see an example for your use case? Para's team is eager to create new examples to help you integrate with different libraries, third-party features, or providers.
# Cosmos Support
Source: https://docs.getpara.com/v2/react-native/guides/cosmos
Using Cosmos libraries like CosmJS in React Native with Para's SDK
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Para's React Native SDK supports Cosmos blockchain interactions through compatible libraries like CosmJS. After authenticating a user with native passkeys in your React Native or Expo application, all Cosmos-related operations function identically to our web SDKs.
## Implementation and References
Once a user has successfully authenticated with the Para React Native SDK using native passkeys, you can immediately sign Cosmos transactions and messages, interact with different Cosmos chains (including Cosmos Hub, Osmosis, and Juno), connect with IBC-enabled networks, and perform staking, delegation, and other operations. The CosmJS library and related Cosmos SDK tools work identically to their web implementations when used with Para's React Native SDK.
## Key Considerations for Mobile
When implementing Cosmos functionality in React Native applications:
* Initialize the Para SDK with your project ID before attempting any Cosmos operations
* Complete the authentication flow with native passkeys
* Consider mobile-specific UI patterns for transaction approvals
* Test on physical devices to ensure proper integration with native security features
While the integration steps are nearly identical to web implementations, mobile devices offer enhanced security through hardware-backed passkeys.
# Custom Storage with MMKV
Source: https://docs.getpara.com/v2/react-native/guides/custom-storage
Configure Para client to use MMKV storage in React Native applications
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Para's React Native SDK uses AsyncStorage and Keychain Storage by default. However, you can configure Para to use MMKV for improved performance. This guide shows you how to implement a custom storage solution using the MMKV library.
## Installation
First, install the MMKV package:
```bash
npm install react-native-mmkv
# or
yarn add react-native-mmkv
```
## Implementation
Create your MMKV storage instance and configure Para to use it:
```typescript
import { MMKV } from 'react-native-mmkv';
import { ParaMobile } from '@getpara/react-native-wallet@alpha';
// Initialize MMKV storage instances
const storage = new MMKV({
id: 'para-storage'
});
// Initialize Para client with MMKV storage
const para = new ParaMobile(
"YOUR_API_KEY",
undefined,
{
// Custom storage overrides
localStorageGetItemOverride: async (key) => {
const value = storage.getString(key);
return value ?? null;
},
localStorageSetItemOverride: async (key, value) => {
storage.set(key, value);
},
sessionStorageGetItemOverride: async (key) => {
const value = storage.getString(key);
return value ?? null;
},
sessionStorageSetItemOverride: async (key, value) => {
storage.set(key, value);
},
sessionStorageRemoveItemOverride: async (key) => {
storage.delete(key);
},
clearStorageOverride: async () => {
storage.clearAll();
}
}
);
export { para };
```
The custom storage implementation must handle serialization and deserialization of JSON data. All values are stored as strings, so your implementation should handle converting values correctly.
# EVM Support
Source: https://docs.getpara.com/v2/react-native/guides/evm
Using EVM libraries like Ethers.js and Viem in React Native with Para's SDK
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Para's React Native SDK provides full support for EVM chains through popular libraries like Ethers.js and Viem. Once a user is authenticated using native passkeys in your React Native or Expo application, all EVM-related operations work the same way as in our web SDKs.
## Implementation and References
After authenticating with the Para React Native SDK using native passkeys, you can seamlessly sign transactions and messages, interact with smart contracts, connect to different EVM networks, and perform other EVM operations. Both Ethers.js and Viem libraries are fully compatible with Para's React Native SDK, working identically to their web counterparts.
## Key Considerations for Mobile
When implementing EVM functionality in React Native applications:
* Ensure you've properly initialized the Para SDK with your project ID
* Complete authentication with native passkeys before attempting any signing operations
* Consider mobile UI/UX design for transaction approval flows
* Test on actual devices to verify the signing experience
The underlying code for signing transactions and messages remains identical between web and mobile implementations.
# Password Authentication
Source: https://docs.getpara.com/v2/react-native/guides/passwords
Authenticate users with passwords in React Native and Expo applications
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
Para supports password-based authentication as an alternative to passkeys. When users choose password authentication, they are redirected to Para's secure web interface to create or enter their password.
## Implementation
```typescript
import InAppBrowser from 'react-native-inappbrowser-reborn';
// After email/phone verification, if authState has passwordUrl
if (authState.passwordUrl) {
const APP_SCHEME = 'your-app-scheme';
const APP_SCHEME_REDIRECT_URL = `${APP_SCHEME}://para`;
// Redirect to password creation/login
await InAppBrowser.openAuth(authState.passwordUrl, APP_SCHEME_REDIRECT_URL);
// For new users creating password
await para.waitForWalletCreation({});
// For existing users logging in
await para.waitForLogin({});
onSuccess();
}
```
```typescript
import { openAuthSessionAsync } from 'expo-web-browser';
// After email/phone verification, if authState has passwordUrl
if (authState.passwordUrl) {
const APP_SCHEME = 'your-app-scheme';
const APP_SCHEME_REDIRECT_URL = `${APP_SCHEME}://para`;
// Redirect to password creation/login
await openAuthSessionAsync(authState.passwordUrl, APP_SCHEME_REDIRECT_URL);
// For new users creating password
await para.waitForWalletCreation({});
// For existing users logging in
await para.waitForLogin({});
onSuccess();
}
```
# Wallet Pregeneration
Source: https://docs.getpara.com/v2/react-native/guides/pregen
Create and manage pregenerated wallets for users in React Native and Expo applications
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
Para's Wallet Pregeneration feature allows you to create wallets for users before they authenticate, giving you control over when and how users claim ownership of their wallets. This is particularly powerful in mobile applications, where you can leverage device-specific storage capabilities for enhanced user experiences.
## Mobile-Specific Benefits
While pregeneration works the same across all Para SDKs, React Native and Expo applications offer unique advantages:
Pregeneration is especially valuable for devices that may not have full WebAuthn support for passkeys. It allows you to create Para wallets for users on any device while managing the security of the wallet yourself.
## Creating a Pregenerated Wallet
### Check if a wallet exists
```typescript
import { para } from '../your-para-client';
async function checkPregenWallet() {
const hasWallet = await para.hasPregenWallet({
pregenId: { email: "user@example.com" },
});
return hasWallet;
}
```
### Create a pregenerated wallet
```typescript
import { para } from '../your-para-client';
import { WalletType } from '@getpara/react-native-wallet@alpha';
async function createPregenWallet() {
const pregenWallet = await para.createPregenWallet({
type: 'EVM',',
pregenId: {email: "user@example.com" },
});
console.log("Pregenerated Wallet ID:", pregenWallet.id);
return pregenWallet;
}
```
### Retrieve the user share
```typescript
import { para } from '../your-para-client';
async function getUserShare() {
const userShare = await para.getUserShare();
// Store this share securely
return userShare;
}
```
## Mobile Storage Options
In mobile applications, you have several options for securely storing the user share:
```typescript
import * as Keychain from 'react-native-keychain';
// Store the user share
async function storeUserShare(userShare) {
try {
await Keychain.setGenericPassword(
'para_user_share',
userShare,
{
service: 'com.yourapp.wallet',
accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED_THIS_DEVICE_ONLY
}
);
} catch (error) {
console.error("Error storing user share:", error);
}
}
// Retrieve the user share
async function retrieveUserShare() {
try {
const credentials = await Keychain.getGenericPassword({
service: 'com.yourapp.wallet'
});
if (credentials) {
return credentials.password;
}
return null;
} catch (error) {
console.error("Error retrieving user share:", error);
return null;
}
}
```
```typescript
import { MMKV } from 'react-native-mmkv';
// Initialize with encryption for better security
const storage = new MMKV({
id: 'wallet-storage',
encryptionKey: 'your-secure-encryption-key'
});
// Store the user share
function storeUserShare(userShare) {
storage.set('user_share', userShare);
}
// Retrieve the user share
function retrieveUserShare() {
return storage.getString('user_share');
}
```
Whichever storage method you choose, ensure you implement proper security measures. The user share is critical for wallet access, and if lost, the wallet becomes permanently inaccessible.
## Using Pregenerated Wallets in Mobile Apps
Once you have created a pregenerated wallet and stored the user share, you can use it for signing operations:
```typescript
import { para } from '../your-para-client';
async function usePregenWallet() {
// Retrieve the user share from your secure storage
const userShare = await retrieveUserShare();
if (!userShare) {
console.error("User share not found");
return;
}
// Load the user share into the Para client
await para.setUserShare(userShare);
// Now you can perform signing operations
const messageBase64 = btoa("Hello, World!");
const signature = await para.signMessage({
walletId: "your-wallet-id",
messageBase64,
});
return signature;
}
```
### Mobile-Specific Use Cases
Create wallets that are bound to a specific device by using device-specific identifiers combined with secure local storage. This approach is ideal for multi-device users who need different wallets for different devices.
```typescript
import DeviceInfo from 'react-native-device-info';
async function createDeviceWallet() {
const deviceId = await DeviceInfo.getUniqueId();
const pregenWallet = await para.createPregenWallet({
type: 'EVM',
pregenId: { customId: `device-${deviceId}` },
});
// Store the user share in device-specific secure storage
const userShare = await para.getUserShare();
await storeUserShare(userShare);
return pregenWallet;
}
```
For iOS App Clips or Android Instant Apps, create temporary wallets that enable limited blockchain functionality without requiring full app installation or user authentication.
```typescript
async function createTemporaryWallet() {
// Generate a random identifier for this session
const sessionId = Math.random().toString(36).substring(2, 15);
const pregenWallet = await para.createPregenWallet({
type: 'EVM',
pregenId: { customId: `temp-${sessionId}` },
});
const userShare = await para.getUserShare();
// Store in memory for this session only
// (could also use temporary secure storage)
sessionStorage.userShare = userShare;
return pregenWallet;
}
```
Seamlessly introduce blockchain functionality to your existing app users without requiring them to understand wallets or crypto.
```typescript
async function createWalletForExistingUser(userId) {
// Check if we already created a wallet for this user
const hasWallet = await para.hasPregenWallet({
pregenId: { customId: `user-${userId}` },
});
if (!hasWallet) {
const pregenWallet = await para.createPregenWallet({
type: 'EVM',
pregenId: { customId: `user-${userId}` },
});
const userShare = await para.getUserShare();
await storeUserShare(userShare);
return pregenWallet;
} else {
// Retrieve existing wallet info
const wallets = await para.getPregenWallets({
pregenId: { customId: `user-${userId}` },
});
return wallets[0];
}
}
```
## Claiming Pregenerated Wallets
When a user is ready to take ownership of their pregenerated wallet, they can claim it once they've authenticated with Para:
```typescript
import { para } from '../your-para-client';
async function claimWallet() {
// Ensure user is authenticated
if (!(await para.isFullyLoggedIn())) {
console.error("User must be authenticated to claim wallets");
return;
}
// Retrieve and load the user share
const userShare = await retrieveUserShare();
await para.setUserShare(userShare);
// Claim the wallet
const recoverySecret = await para.claimPregenWallets();
// Optionally, clear the locally stored user share after claiming
// since Para now manages it through the user's authentication
await clearUserShare();
return recoverySecret;
}
```
After claiming, Para will manage the user share through the user's authentication methods. You can safely remove the user share from your local storage if you no longer need to access the wallet directly.
## Best Practices for Mobile
1. **Utilize Device Security**: Leverage biometric authentication (TouchID/FaceID) to protect access to locally stored user shares.
2. **Implement Device Sync**: For users with multiple devices, consider implementing your own synchronization mechanism for user shares across devices.
3. **Handle Offline States**: Mobile applications often work offline. Design your pregenerated wallet system to function properly even when connectivity is limited.
4. **Backup Strategies**: Provide users with options to back up their wallet data, especially for device-specific wallets that might not be associated with their Para account.
5. **Clear Security Boundaries**: Clearly communicate to users when they're using an app-managed wallet versus a personally-owned wallet.
## Related Resources
# React Native Session Management
Source: https://docs.getpara.com/v2/react-native/guides/sessions
Guide to managing authentication sessions in Para for React Native applications
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
Para provides a comprehensive set of methods for managing authentication sessions in React Native applications. These sessions are crucial for secure transaction signing and other authenticated operations.
## Session Duration
The Para session length is `2 hours` by default, but can be configured to up to 30 days. To configure this parameter, please visit the Configuration section of the . A user signing a message or transaction extends the session by the duration of the session length.
## Managing Sessions
### Checking Session Status
Use `isSessionActive()` to verify whether a user's session is currently valid before performing authenticated operations.
```typescript
async isSessionActive(): Promise
```
In React Native applications, it's especially important to check the session status before allowing users to access authenticated areas of your app due to the persistence of local storage between app launches.
Example usage:
```typescript
import { para } from '../your-para-client';
async function checkSession() {
try {
const isActive = await para.isSessionActive();
if (!isActive) {
// First clear any existing data
await para.logout();
// Navigate to login screen
navigation.navigate('Login');
} else {
// Session is valid, proceed with app flow
navigation.navigate('Dashboard');
}
} catch (error) {
console.error("Session check failed:", error);
// Handle error
}
}
```
### Maintaining Active Sessions
Para provides the `keepSessionAlive()` method to extend an active session without requiring full reauthentication.
```typescript
async keepSessionAlive(): Promise
```
Example usage:
```typescript
import { para } from '../your-para-client';
async function extendSession() {
try {
const success = await para.keepSessionAlive();
if (!success) {
// Session could not be extended
// Clear storage and navigate to login
await para.logout();
navigation.navigate('Login');
}
} catch (error) {
console.error("Session maintenance failed:", error);
}
}
```
### Refreshing Expired Sessions
When a session has expired, Para recommends initiating a full authentication flow rather than trying to refresh the session.
For React Native applications, always call `logout()` before reinitiating authentication when a session has expired to ensure all stored data is properly cleared.
```typescript
import { para } from '../your-para-client';
async function handleSessionExpiration() {
// When session expires, first clear storage
await para.logout();
// Then redirect to authentication screen
navigation.navigate('Login');
}
```
## Exporting Sessions to Your Server
Use `exportSession()` when you need to transfer session state to your server for performing operations on behalf of the user.
```typescript
exportSession({ excludeSigners?: boolean }): string
```
If your server doesn't need to perform signing operations, use `{ excludeSigners: true }` when exporting sessions for enhanced security.
Example implementation:
```typescript
import { para } from '../your-para-client';
async function sendSessionToServer() {
// Export session without signing capabilities
const sessionData = para.exportSession({ excludeSigners: true });
// Send to your server
try {
const response = await fetch('https://your-api.com/sessions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ session: sessionData }),
});
if (!response.ok) {
throw new Error('Failed to send session to server');
}
return await response.json();
} catch (error) {
console.error('Error sending session to server:', error);
throw error;
}
}
```
## Best Practices for React Native
1. **Check Sessions on App Launch**: Verify session status when your app starts to determine if users need to reauthenticate.
```typescript
// In your app's entry point or navigation setup
useEffect(() => {
async function checkSessionOnLaunch() {
const isActive = await para.isSessionActive();
if (isActive) {
navigation.navigate('Dashboard');
} else {
await para.logout(); // Clear any lingering data
navigation.navigate('Login');
}
}
checkSessionOnLaunch();
}, []);
```
2. **Implement Automatic Session Extension**: For long app usage sessions, periodically call `keepSessionAlive()` to prevent unexpected session expirations.
```typescript
useEffect(() => {
const sessionInterval = setInterval(async () => {
try {
const isActive = await para.isSessionActive();
if (isActive) {
await para.keepSessionAlive();
} else {
// Session expired, handle accordingly
await para.logout();
navigation.navigate('Login');
}
} catch (error) {
console.error('Error maintaining session:', error);
}
}, 30 * 60 * 1000); // Check every 30 minutes
return () => clearInterval(sessionInterval);
}, []);
```
3. **Handle Background/Foreground State**: React Native apps can be backgrounded and foregrounded, which may affect session status.
```typescript
import { AppState } from 'react-native';
useEffect(() => {
const subscription = AppState.addEventListener('change', async (nextAppState) => {
if (nextAppState === 'active') {
// App came to foreground, check session
const isActive = await para.isSessionActive();
if (!isActive) {
await para.logout();
navigation.navigate('Login');
}
}
});
return () => {
subscription.remove();
};
}, []);
```
4. **Secure Storage Configuration**: For enhanced security, consider implementing a to manage sensitive session data.
## Next Steps:
Explore more advanced features and integrations with Para in Flutter:
# OAuth Authentication
Source: https://docs.getpara.com/v2/react-native/guides/social-login
Implementing OAuth login with Para in React Native and Expo applications
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Para supports OAuth authentication in React Native and Expo applications, allowing users to sign in using popular providers like Google, Discord, and Farcaster. This guide explains how to implement OAuth login in your mobile app using Para's React Native SDK.
The OAuth flow in mobile applications requires handling browser sessions and deeplinks to redirect users back to your app after successful authentication. Once the OAuth flow completes, Para uses the returned email to authenticate users through the standard email-based flow, creating or authenticating with a native passkey.
## Prerequisites
Before implementing OAuth authentication, ensure you have completed the basic Para setup for your React Native or Expo application.
## Implementation
### Installation
Install the In-App Browser package to handle OAuth redirects securely:
```bash
npm install react-native-inappbrowser-reborn
# or
yarn add react-native-inappbrowser-reborn
```
For iOS, add the following to your `Info.plist` to define your URL scheme:
```xml
CFBundleURLTypes
CFBundleURLSchemes
your-app-scheme
```
For Android, add your URL scheme to `AndroidManifest.xml`:
```xml
```
Both `react-native-inappbrowser-reborn` and `expo-web-browser` use secure browser implementations that leverage the device's native browser engine rather than a WebView. This provides stronger security protections, including shared security context with the device's browser, protection against common web vulnerabilities, and support for modern authentication methods.
### Implementing Authentication
```typescript Standard OAuth
import { para } from "../your-para-client";
import { OAuthMethod } from "@getpara/react-native-wallet@alpha";
import { InAppBrowser } from "react-native-inappbrowser-reborn";
const APP_SCHEME = "your-app-scheme";
const APP_SCHEME_REDIRECT_URL = `${APP_SCHEME}://para`;
async function handleOAuthLogin(provider: OAuthMethod) {
if (provider === OAuthMethod.FARCASTER) {
return handleFarcasterLogin();
}
const oauthUrl = await para.getOAuthUrl({
method: provider,
appScheme: APP_SCHEME,
});
await InAppBrowser.openAuth(oauthUrl, APP_SCHEME, {
ephemeralWebSession: false,
showTitle: false,
enableUrlBarHiding: true,
});
const verifiedAuthState = await para.verifyOAuth({
method: provider,
});
if (verifiedAuthState.stage === 'login') {
// Existing user - check if they use password or passkey
if (verifiedAuthState.passwordUrl) {
// User has password-based security
await InAppBrowser.openAuth(verifiedAuthState.passwordUrl, APP_SCHEME_REDIRECT_URL);
await para.waitForLogin({});
} else {
// User has passkey-based security
await para.loginWithPasskey();
}
onSuccess();
} else if (verifiedAuthState.stage === 'signup') {
// New user - register passkey directly or show security choice
await para.registerPasskey(verifiedAuthState);
onSuccess();
}
}
```
```typescript Farcaster Login
import { Linking } from "react-native";
import { para } from "../your-para-client";
async function handleFarcasterLogin() {
const farcasterUrl = await para.getFarcasterConnectURL();
await Linking.openURL(farcasterUrl);
const { userExists, username } = await para.waitForFarcasterStatus();
if (userExists) {
await para.login({ email: username! });
// Navigate to your authenticated screen
} else {
await para.registerPasskey({ email: username! });
// Navigate to your authenticated screen
}
}
```
### Installation
Install the Expo Web Browser package:
```bash
npx expo install expo-web-browser
```
Configure your app.json with the URL scheme:
```json
{
"expo": {
"scheme": "your-app-scheme",
"ios": {
"bundleIdentifier": "com.yourcompany.yourappname"
},
"android": {
"package": "com.yourcompany.yourappname"
}
}
}
```
After updating your app.json, run the following command to rebuild native iOS and Android files:
```bash
npx expo prebuild --clean
```
For Expo Router apps, create a `+native-intent.tsx` file in your project root to handle deeplinks:
```typescript
export function redirectSystemPath({ path, initial }: { path: string; initial: boolean }) {
if (path.includes("para?method=login") && !initial) {
return `/auth/your-oauth-screen-path`;
}
return path;
}
```
The browser packages used for OAuth share cookies, cache, and session data with the device's native browser. This means users already logged into OAuth providers in their device browser will stay logged in. If you encounter authentication issues, try clearing the cache and history in the device's native browser.
### Implementing Authentication
```typescript Standard OAuth
import { para } from "../your-para-client";
import { OAuthMethod } from "@getpara/react-native-wallet@alpha";
import { openAuthSessionAsync } from "expo-web-browser";
const APP_SCHEME = "your-app-scheme";
const APP_SCHEME_REDIRECT_URL = `${APP_SCHEME}://para`;
async function handleOAuthLogin(provider: OAuthMethod) {
if (provider === OAuthMethod.FARCASTER) {
return handleFarcasterLogin();
}
const oauthUrl = await para.getOAuthUrl({
method: provider,
appScheme: APP_SCHEME,
});
await openAuthSessionAsync(oauthUrl, APP_SCHEME, {
preferEphemeralSession: false,
});
const verifiedAuthState = await para.verifyOAuth({
method: provider,
});
if (verifiedAuthState.stage === 'login') {
// Existing user - check if they use password or passkey
if (verifiedAuthState.passwordUrl) {
// User has password-based security
await openAuthSessionAsync(verifiedAuthState.passwordUrl, APP_SCHEME_REDIRECT_URL);
await para.waitForLogin({});
} else {
// User has passkey-based security
await para.loginWithPasskey();
}
onSuccess();
} else if (verifiedAuthState.stage === 'signup') {
// New user - register passkey directly or show security choice
await para.registerPasskey(verifiedAuthState);
onSuccess();
}
}
```
```typescript Farcaster Login
import { openURL } from "expo-linking";
import { para } from "../your-para-client";
async function handleFarcasterLogin() {
const farcasterUrl = await para.getFarcasterConnectURL();
await openURL(farcasterUrl);
const { userExists, username } = await para.waitForFarcasterStatus();
if (userExists) {
await para.login({ email: username! });
// Navigate to your authenticated screen
} else {
await para.registerPasskey({ email: username! });
// Navigate to your authenticated screen
}
}
```
OAuth authentication with Para still requires creating a native passkey to secure the user's wallets. After OAuth completes, Para associates a native passkey with the user's account. For returning users, the native passkey is used for authentication. The passkey is associated on a per-app basis, making authentication streamlined, and users will only see passkey options they created for your specific app.
## Examples
Explore our complete example implementations for OAuth authentication with Para:
## Next Steps
After integrating Para, you can explore other features and integrations to enhance your Para experience.
# Solana Support in React Native
Source: https://docs.getpara.com/v2/react-native/guides/solana
Using Para with Solana Web3.js and Anchor in React Native applications
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Para's React Native SDK provides comprehensive support for Solana blockchain operations through libraries like Solana Web3.js and Anchor. After authenticating users with native passkeys in your React Native or Expo application, all Solana-related operations work exactly the same as in our web SDKs.
## Implementation and References
Once authentication is complete with the Para React Native SDK using native passkeys, you can immediately sign Solana transactions and messages, interact with Solana programs, connect to different Solana networks (mainnet, devnet, testnet), and leverage Solana Pay and other ecosystem tools. Both Solana Web3.js and Anchor framework work seamlessly with Para's React Native SDK, functioning identically to their web implementations.
## Key Considerations for Mobile
When implementing Solana functionality in React Native applications:
* Ensure proper initialization of the Para SDK with your project ID
* Complete authentication with native passkeys before attempting any signing operations
* Design mobile-friendly UI for transaction approval flows
* Test transaction signing on actual devices to verify the end-to-end experience
The underlying code for Solana transaction construction and signing remains identical between web and mobile implementations, making it easy to maintain consistency across platforms.
# Overview
Source: https://docs.getpara.com/v2/react-native/overview
An introduction to mobile integrations with Para
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Para supports modern mobile development frameworks, giving you the flexibility to implement our SDKs in your native mobile applications. Each integration guide provides step-by-step instructions tailored to specific mobile development environments.
## Getting Started with Mobile Integrations
## Blockchain Ecosystem Integrations
Para works seamlessly with major blockchain ecosystems in your mobile apps, allowing you to leverage Para's authentication alongside chain-specific libraries and development tools.
## Advanced Configuration
Customize Para's behavior and extend its functionality with these advanced configuration guides.
## Extended Authentication Options
Enhance your application's security and user experience with additional authentication methods.
# Expo
Source: https://docs.getpara.com/v2/react-native/setup/expo
Learn how to integrate the Para SDK with Expo projects.
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label}) => {
e.currentTarget.querySelector("#underline").style.height = "2px";
}} onMouseLeave={e => {
e.currentTarget.querySelector("#underline").style.height = "1px";
}}>
{label}
;
is a framework built on React Native that provides many out-of-the-box features, similar to NextJS for web but designed
for mobile development. Para provides a `@getpara/react-native-wallet`@alpha package that works seamlessly in both React Native bare and Expo workflows, utilizing the device's Native Passkeys for secure wallet management.
## Prerequisites
To use Para, you need an API key. This key authenticates your requests to Para services and is essential for
integration.
Don't have an API key yet? Request access to the to create API keys, manage billing, teams, and more.
To ensure passkey functionality works correctly:
* Enable biometric or device unlock settings (fingerprint, face unlock, or PIN)
* On Android sign in to a Google account on the device (required for Google Play Services passkey management)
## Dependency Installation
Install the required dependencies:
```bash npm
npm install @getpara/react-native-wallet@alpha @react-native-async-storage/async-storage react-native-keychain react-native-modpow react-native-passkey react-native-quick-base64 @craftzdog/react-native-buffer react-native-quick-crypto expo-linking expo-web-browser --save-exact
```
```bash yarn
yarn add @getpara/react-native-wallet@alpha @react-native-async-storage/async-storage react-native-keychain react-native-modpow react-native-passkey react-native-quick-base64 @craftzdog/react-native-buffer react-native-quick-crypto expo-linking expo-web-browser --exact
```
```bash pnpm
pnpm add @getpara/react-native-wallet@alpha @react-native-async-storage/async-storage react-native-keychain react-native-modpow react-native-passkey react-native-quick-base64 @craftzdog/react-native-buffer react-native-quick-crypto expo-linking expo-web-browser --save-exact
```
```bash bun
bun add @getpara/react-native-wallet@alpha @react-native-async-storage/async-storage react-native-keychain react-native-modpow react-native-passkey react-native-quick-base64 @craftzdog/react-native-buffer react-native-quick-crypto expo-linking expo-web-browser --exact
```
## Project Setup
To use the `@getpara/react-native-wallet`@alpha package in your Expo project, you will need to do some initial project setup.
For passkeys to work correctly we have to setup the for both iOS and Android. This ensures passkeys are bound to the domains they were created for.
Your apps must be registered with Para to link the passkey to the correct domain. You can find this configuration options
your under the 'Configuration' tab of the API key label as Native Passkey Configuration.
### Platform-Specific Configuration
Configure your `app.json` file to enable passkey functionality and secure communication:
```json app.json
{
"expo": {
"ios": {
"bundleIdentifier": "your.app.bundleIdentifier",
"associatedDomains": [
"webcredentials:app.beta.usecapsule.com?mode=developer",
"webcredentials:app.usecapsule.com"
]
}
}
}
```
**Important**: Your `teamId + bundleIdentifier` must be registered with the Para team to set up associated domains. For example, if your Team ID is `A1B2C3D4E5` and Bundle Identifier is `com.yourdomain.yourapp`, provide `A1B2C3D4E5.com.yourdomain.yourapp` to Para. This is required by Apple for passkey security. Allow up to 24 hours for domain propagation. You can find this setting in the Developer Portal under the 'Configuration' tab of the API key label as Native Passkey Configuration.
For Android setup in Expo, you'll need to configure your package name and provide your SHA-256 certificate fingerprint.
**Quick Testing Option**: You can use `com.getpara.example.expo` as your package name in `app.json` for immediate testing. This package name is pre-registered but only works with the default debug.keystore generated by Expo.
Configure your `app.json`:
```json app.json
{
"expo": {
"android": {
"package": "com.getpara.example.expo" // For testing
// or your actual package name for production
}
}
}
```
**Important**: Your SHA-256 certificate fingerprint must be registered with the Para team to set up associated domains. This is required by Google for passkey security. Allow up to 24 hours for domain propagation. You can find this setting in the Developer Portal under the 'Configuration' tab of the API key label as Native Passkey Configuration.
### Configure Metro Bundler
Create or update `metro.config.js` in your project with the following node module resolutions. This will ensure that any library that depends on global modules like `crypto` or `buffer` will be properly resolved in the Expo environment. For more details on Metro configuration, see the .
```javascript metro.config.js
const { getDefaultConfig } = require("expo/metro-config");
const config = getDefaultConfig(__dirname);
config.resolver.extraNodeModules = {
crypto: require.resolve("react-native-quick-crypto"),
buffer: require.resolve("@craftzdog/react-native-buffer"),
};
module.exports = config;
```
### Import Required Shims
Import the Para Wallet shim in your root layout file to ensure proper global module shimming. This ensures that the necessary modules are available globally in your application. Ensure this is the very first import in your root layout file.
```typescript app/_layout.tsx
import "@getpara/react-native-wallet/shim";
// ... rest of your imports and layout code
```
Alternatively, you can create a custom entry point to handle the shimming. This will ensure that the shim occurs before the Expo Router entry point.
Create `index.js` in your project root and add the following imports:
```javascript index.js
import "@getpara/react-native-wallet/shim";
import "expo-router/entry";
```
Update `package.json` to point to your new entry file:
```json package.json
{
"main": "index.js"
}
```
### Prebuild and Run
Since native modules are required, you'll need to use Expo Development Build to ensure that linking is successful. This means using the `expo prebuild` command to generate the necessary native code and then run your app using `expo run:ios` or `expo run:android`.
```bash
npx expo prebuild
npx expo run:ios
npx expo run:android
```
You **cannot** use Expo Go as it doesn't support native module linking. When running via `yarn start`, switch to development mode by pressing `s`, then `i` for iOS or `a` for Android.
## Using the Para SDK
The `@getpara/react-native-wallet`@alpha provides two main authentication methods: email-based and phone-based. Both flows utilize Native Passkeys for secure and seamless authentication.
On mobile Para doesn't provide a modal component. Instead you can create your own auth screens with either email, phone
number, or oauth using the available methods in the Para SDK.
### Setup the Para Client
First, set up the Para client singleton and initialize it in your app:
```typescript para.ts
import { ParaMobile } from "@getpara/react-native-wallet";
export const para = new ParaMobile(YOUR_API_KEY, undefined, {
disableWorkers: true,
});
```
Then initialize it in your app entry point:
```typescript app/_layout.tsx
import { para } from "../para";
import { useEffect } from "react";
export default function Layout() {
useEffect(() => {
const initPara = async () => {
await para.init();
};
initPara();
}, []);
// ... rest of your layout code
}
```
If you're using a legacy API key (one without an environment prefix) you must provide the `Environment` as the first argument to the `ParaMobile` constructor. You can retrieve your updated API key from the Para Developer Portal at [https://developer.getpara.com/](https://developer.getpara.com/)
**Beta Testing Credentials** In the `BETA` Environment, you can use any email ending in `@test.getpara.com` (like
[dev@test.getpara.com](mailto:dev@test.getpara.com)) or US phone numbers (+1) in the format `(area code)-555-xxxx` (like (425)-555-1234). Any OTP
code will work for verification with these test credentials. These credentials are for beta testing only. You can
delete test users anytime in the beta developer console to free up user slots.
### Authentication Methods
#### Sign Up or Log In with Email
Use the `signUpOrLogIn` method to handle both new user registration and existing user authentication:
```typescript
const handleContinue = async (email: string) => {
try {
const authState = await para.signUpOrLogIn({ auth: { email } });
if (authState?.stage === 'verify') {
// New user - show OTP verification
setShowOTP(true);
} else if (authState?.stage === 'login') {
// Existing user - proceed with passkey login
await para.loginWithPasskey();
}
} catch (error) {
// Handle error
}
};
const handleVerification = async (verificationCode: string) => {
try {
const authState = await para.verifyNewAccount({ verificationCode });
await para.registerPasskey(authState);
} catch (error) {
// Handle error
}
};
// Usage example:
await handleContinue("user@example.com");
// If verification is needed:
await handleVerification("123456");
```
#### Login Existing User with Email
For existing users, use the `signUpOrLogIn` method which will return a login stage, then use `loginWithPasskey`:
```typescript
const handleLogin = async (email: string) => {
try {
const authState = await para.signUpOrLogIn({ auth: { email } });
if (authState?.stage === 'login') {
await para.loginWithPasskey();
}
} catch (error) {
// Handle error
}
};
```
#### Sign Up or Log In with Phone Number
Use the `signUpOrLogIn` method to handle both new user registration and existing user authentication:
```typescript
const handleContinue = async (phone: string) => {
try {
const authState = await para.signUpOrLogIn({ auth: { phone } });
if (authState?.stage === 'verify') {
// New user - show OTP verification
setShowOTP(true);
} else if (authState?.stage === 'login') {
// Existing user - proceed with passkey login
await para.loginWithPasskey();
}
} catch (error) {
// Handle error
}
};
const handlePhoneVerification = async (verificationCode: string) => {
try {
const authState = await para.verifyNewAccount({ verificationCode });
await para.registerPasskey(authState);
} catch (error) {
// Handle error
}
};
// Resend verification code if needed
const resendPhoneVerificationCode = async () => {
await para.resendVerificationCode();
};
// Usage example:
await handleContinue("+1234567890");
// If verification is needed:
await handlePhoneVerification("123456");
```
#### Login Existing User with Phone
For existing users, use the `signUpOrLogIn` method which will return a login stage, then use `loginWithPasskey`:
```typescript
const handlePhoneLogin = async (phone: string) => {
try {
const authState = await para.signUpOrLogIn({ auth: { phone } });
if (authState?.stage === 'login') {
await para.loginWithPasskey();
}
} catch (error) {
// Handle error
}
};
```
#### Create a User with OAuth
OAuth authentication flow is coming soon. Please contact Para support for more information and early access.
By following these steps, you can implement a secure and user-friendly authentication system in your Expo application using the Para SDK.
## Examples
For practical implementations of the Para SDK in Expo environments, check out our GitHub repository:
## Troubleshooting
If you encounter issues during the integration or usage of the Para SDK in your Expo application, here are some common
problems and their solutions:
If you're having trouble initializing the Para SDK:
* Ensure that you've called `para.init()` after creating the Para instance.
* Verify that you're using the correct API key and environment.
* Check that all necessary dependencies are installed and linked properly.
* Look for any JavaScript errors in your Expo bundler console.
If you're seeing errors about missing native modules:
* Ensure you've run `expo prebuild` to generate native code.
* Run `expo run:ios` and `expo run:android` to rebuild your app after adding new native dependencies.
* Verify that your `app.json` file includes the necessary configurations for native modules.
If passkey creation, retrieval, or usage isn't working:
* Verify that you've set up associated domains correctly in your `app.json` file for both iOS and Android.
* Check that you've provided the correct SHA-256 fingerprint to the Para team for Android.
* Ensure your Expo SDK version is compatible with the Para SDK.
If you're seeing errors related to crypto functions:
* Ensure you've properly set up the `expo-crypto` and `react-native-quick-crypto` polyfills.
* Verify that your `metro.config.js` file is configured correctly to include the necessary Node.js core modules.
* Check that you've imported the shim file at the top of your root `index.js` or `App.js` file.
* Make sure you're using the latest version of Expo SDK that's compatible with the Para SDK.
If you're experiencing authentication issues:
* Double-check that your API key is correct and properly set in your environment variables.
* Verify you're using the correct environment (`BETA` or `PRODUCTION`) that matches your API key.
* Ensure your account has the necessary permissions for the operations you're attempting.
* Check your network requests for any failed API calls and examine the error messages.
* If using Expo Go, remember that some native features might not work; consider using a development build or EAS.
If you're encountering problems during the Expo build process:
* Ensure you're using a compatible Expo SDK version with all your dependencies.
* Run `expo doctor` to check for any configuration issues in your project.
* If using managed workflow, consider switching to bare workflow for full native module support.
* For EAS builds, check your `eas.json` configuration and ensure it's set up correctly for both iOS and Android.
For a more comprehensive list of solutions, including Expo-specific issues, visit our troubleshooting guide:
## Next Steps
After integrating Para, you can explore other features and integrations to enhance your Para experience.
# Bare Workflow
Source: https://docs.getpara.com/v2/react-native/setup/react-native
Learn how to integrate the Para SDK with React Native projects.
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label}) => {
e.currentTarget.querySelector("#underline").style.height = "2px";
}} onMouseLeave={e => {
e.currentTarget.querySelector("#underline").style.height = "1px";
}}>
{label}
;
The Para SDK for React Native allows you to easily integrate secure and scalable wallet functionalities into your mobile
applications, utilizing the device's Native Passkeys for secure wallet management. This guide covers the installation,
setup, and usage of the Para SDK.
## Prerequisites
To use Para, you need an API key. This key authenticates your requests to Para services and is essential for
integration.
Don't have an API key yet? Request access to the to create API keys, manage billing, teams, and more.
## Dependency Installation
Install the required packages for Para SDK integration:
```bash npm
npm install @getpara/react-native-wallet@alpha @react-native-async-storage/async-storage react-native-keychain react-native-modpow react-native-passkey react-native-quick-base64 @craftzdog/react-native-buffer react-native-quick-crypto react-native-config react-native-inappbrowser-reborn --save-exact
```
```bash yarn
yarn add @getpara/react-native-wallet@alpha @react-native-async-storage/async-storage react-native-keychain react-native-modpow react-native-passkey react-native-quick-base64 @craftzdog/react-native-buffer react-native-quick-crypto react-native-config react-native-inappbrowser-reborn --exact
```
```bash pnpm
pnpm add @getpara/react-native-wallet@alpha @react-native-async-storage/async-storage react-native-keychain react-native-modpow react-native-passkey react-native-quick-base64 @craftzdog/react-native-buffer react-native-quick-crypto react-native-config react-native-inappbrowser-reborn --save-exact
```
```bash bun
bun add @getpara/react-native-wallet@alpha @react-native-async-storage/async-storage react-native-keychain react-native-modpow react-native-passkey react-native-quick-base64 @craftzdog/react-native-buffer react-native-quick-crypto react-native-config react-native-inappbrowser-reborn --exact
```
## Project Setup
### Platform-Specific Configuration
In order for passkeys to work, you need to set up associated domains in your Xcode project linked to the Para domain.
#### Set Up Associated Domains
1. Open your project in Xcode
2. Select your target and go to "Signing & Capabilities"
3. Click "+ Capability" and add "Associated Domains"
4. Add the following domains:
* webcredentials:app.beta.usecapsule.com
* webcredentials:app.usecapsule.com
For additional information on associated domains, refer to the .
**Important**: Your `teamId + bundleIdentifier` must be registered with the Para team to set up associated domains. For example, if your Team ID is `A1B2C3D4E5` and Bundle Identifier is `com.yourdomain.yourapp`, provide `A1B2C3D4E5.com.yourdomain.yourapp` to Para. This is required by Apple for passkey security. **Note:** Allow up to 24 hours for domain propagation.
#### Install CocoaPods for native dependencies:
```bash
cd ios
bundle install
bundle exec pod install
cd ..
```
Remember to run `pod install` after adding new dependencies to your project.
#### Set Up Digital Asset Links
For Android setup, you need to provide your app's SHA-256 certificate fingerprint to Para.
**Quick Testing Option**: You can use `com.getpara.example.reactnative` as your package name for immediate testing. This package name is pre-registered and works with the SHA-256 certificate from the default debug.keystore.
To get your SHA-256 fingerprint:
* For debug builds: `keytool -list -v -keystore ~/.android/debug.keystore`
* For release builds: `keytool -list -v -keystore `
For production apps, you'll need to: 1. Upgrade your plan in the Developer Portal 2. Register your actual package name 3. Provide your app's SHA-256 fingerprint 4. Wait up to 24 hours for the Digital Asset Links to propagate
#### Device Requirements
To ensure passkey functionality works correctly:
* Enable biometric or device unlock settings (fingerprint, face unlock, or PIN)
* Sign in to a Google account on the device (required for Google Play Services passkey management)
### Configure Metro Bundler
Create or update `metro.config.js` in your project root:
```javascript metro.config.js
const { getDefaultConfig, mergeConfig } = require("@react-native/metro-config");
const config = {
resolver: {
extraNodeModules: {
crypto: require.resolve("react-native-quick-crypto"),
buffer: require.resolve("@craftzdog/react-native-buffer"),
},
},
};
module.exports = mergeConfig(getDefaultConfig(__dirname), config);
```
### Add Para Shim
Import the Para shim as the FIRST import in your application's entry file (typically `index.js`):
```javascript
import "@getpara/react-native-wallet/shim";
// Other imports...
```
**Important**: The shim import must come before any other imports to ensure required modules are available.
## Using the Para SDK
The Para SDK provides two main authentication methods: email-based and phone-based. Each method supports creating a new user and logging in an existing user. Both flows utilize Native Passkeys for secure and seamless authentication. Follow the steps below to implement these flows in your React Native application.
**Beta Testing Credentials** In the `BETA` Environment, you can use any email ending in `@test.getpara.com` (like
[dev@test.getpara.com](mailto:dev@test.getpara.com)) or US phone numbers (+1) in the format `(area code)-555-xxxx` (like (425)-555-1234). Any OTP
code will work for verification with these test credentials. These credentials are for beta testing only. You can
delete test users anytime in the beta developer console to free up user slots.
### Create New User with Email
This flow guides you through the process of registering a new user with email, verifying their email, and setting up their wallet.
#### Initialize Para Client
First, set up the Para client to enable SDK interactions:
```typescript
import { ParaMobile } from "@getpara/react-native-wallet";
const para = new ParaMobile(
YOUR_API_KEY,
undefined,
{ disableWorkers: true }
);
```
If you're using a legacy API key (one without an environment prefix) you must provide the `Environment` as the first argument to the `ParaMobile` constructor. You can retrieve your updated API key from the Para Developer Portal at [https://developer.getpara.com/](https://developer.getpara.com/)
#### Sign Up or Log In
Use the `signUpOrLogIn` method to handle both new user registration and existing user authentication:
```typescript
const handleContinue = async (email: string) => {
try {
const authState = await para.signUpOrLogIn({ auth: { email } });
if (authState?.stage === 'verify') {
// New user - show OTP verification
setShowOTP(true);
} else if (authState?.stage === 'login') {
// Existing user - proceed with passkey login
await para.loginWithPasskey();
}
} catch (error) {
// Handle error
}
};
```
#### Verify Email
Once the user receives the verification code, call the `verifyNewAccount` method to confirm their email:
```typescript
const handleVerifyEmail = async (verificationCode: string) => {
try {
const authState = await para.verifyNewAccount({ verificationCode });
return authState;
} catch (error) {
// Handle error
}
};
```
#### Register Passkey
Use the returned authState to register the user's passkey:
```typescript
const handleRegisterPasskey = async (authState: any) => {
try {
await para.registerPasskey(authState);
} catch (error) {
// Handle error
}
};
```
#### Complete New User Flow
Implement the full flow by combining all the previous steps:
```typescript
const handleNewUserFlow = async (email: string, verificationCode: string) => {
try {
// Step 1: Sign up or log in
const authState = await para.signUpOrLogIn({ auth: { email } });
if (authState?.stage === 'verify') {
// Step 2: Verify email
const verifiedAuthState = await para.verifyNewAccount({ verificationCode });
// Step 3: Register passkey
await para.registerPasskey(verifiedAuthState);
}
} catch (error) {
// Handle error
}
};
```
### Login Existing User with Email
This flow demonstrates how to authenticate an existing user using their email and passkey.
#### Login Existing User
For existing users, use the `signUpOrLogIn` method which will return a login stage, then use `loginWithPasskey`:
```typescript
const handleLogin = async (email: string) => {
try {
const authState = await para.signUpOrLogIn({ auth: { email } });
if (authState?.stage === 'login') {
await para.loginWithPasskey();
}
} catch (error) {
// Handle error
}
};
```
### Create New User with Phone
This flow guides you through the process of registering a new user with a phone number, verifying it, and setting up their wallet.
#### Initialize Para Client
First, set up the Para client to enable SDK interactions:
```typescript
import { ParaMobile } from "@getpara/react-native-wallet@alpha";
const para = new ParaMobile(
YOUR_API_KEY,
undefined,
{ disableWorkers: true }
);
```
If you're using a legacy API key (one without an environment prefix) you must provide the `Environment` as the first argument to the `ParaMobile` constructor. You can retrieve your updated API key from the Para Developer Portal at [https://developer.getpara.com/](https://developer.getpara.com/)
#### Sign Up or Log In
Use the `signUpOrLogIn` method to handle both new user registration and existing user authentication:
```typescript
const handleContinue = async (phone: string) => {
try {
const authState = await para.signUpOrLogIn({ auth: { phone } });
if (authState?.stage === 'verify') {
// New user - show OTP verification
setShowOTP(true);
} else if (authState?.stage === 'login') {
// Existing user - proceed with passkey login
await para.loginWithPasskey();
}
} catch (error) {
// Handle error
}
};
```
#### Verify Phone
Once the user receives the verification code, call the `verifyNewAccount` method to confirm their phone number:
```typescript
const handleVerifyPhone = async (verificationCode: string) => {
try {
const authState = await para.verifyNewAccount({ verificationCode });
return authState;
} catch (error) {
// Handle error
}
};
```
#### Register Passkey
Use the returned authState to register the user's passkey:
```typescript
const handleRegisterPasskey = async (authState: any) => {
try {
await para.registerPasskey(authState);
} catch (error) {
// Handle error
}
};
```
#### Complete Phone-based Flow
Here's an example of a complete phone-based authentication flow:
```typescript
const handleNewUserFlow = async (phone: string, verificationCode: string) => {
try {
// Step 1: Sign up or log in
const authState = await para.signUpOrLogIn({ auth: { phone } });
if (authState?.stage === 'verify') {
// Step 2: Verify phone
const verifiedAuthState = await para.verifyNewAccount({ verificationCode });
// Step 3: Register passkey
await para.registerPasskey(verifiedAuthState);
}
} catch (error) {
// Handle error
}
};
// Resend verification code if needed
const resendOTP = async () => {
await para.resendVerificationCode();
};
```
### Login Existing User with Phone
This flow demonstrates how to authenticate an existing user using their phone number and passkey.
#### Login Existing User
For existing users, use the `signUpOrLogIn` method which will return a login stage, then use `loginWithPasskey`:
```typescript
const handleLogin = async (phone: string) => {
try {
const authState = await para.signUpOrLogIn({ auth: { phone } });
if (authState?.stage === 'login') {
await para.loginWithPasskey();
}
} catch (error) {
// Handle error
}
};
```
By following these steps, you can implement a secure and user-friendly authentication system in your React Native application using the Para SDK, with support for both email and phone-based authentication methods.
## Wallet Management
After successful authentication, you must create wallets for the blockchain networks you want to use:
### Creating Wallets
```typescript
import { WalletType } from "@getpara/react-native-wallet";
// Create wallets for different blockchain types
await para.createWallet({type: WalletType.EVM, skipDistribute: false});
await para.createWallet({type: WalletType.SOLANA, skipDistribute: false});
await para.createWallet({type: WalletType.COSMOS, skipDistribute: false});
```
### Retrieving Wallet Information
```typescript
// Get existing wallets by type
const evmWallet = para.getWalletsByType(WalletType.EVM)[0];
const solanaWallet = para.getWalletsByType(WalletType.SOLANA)[0];
const cosmosWallet = para.getWalletsByType(WalletType.COSMOS)[0];
// Check if wallet exists and get address
if (evmWallet?.address) {
console.log('EVM Address:', evmWallet.address);
}
```
### Complete Integration Example
```typescript
const setupEVMWallet = async () => {
try {
// Check if EVM wallet exists, create if not
let wallet = para.getWalletsByType(WalletType.EVM)[0];
if (!wallet) {
await para.createWallet({type: WalletType.EVM, skipDistribute: false});
wallet = para.getWalletsByType(WalletType.EVM)[0];
}
// Now ready for EVM operations
return wallet?.address;
} catch (error) {
console.error('Wallet setup failed:', error);
}
};
```
**Important**: Wallet creation must be completed after authentication but before any blockchain operations (signing transactions, getting balances, etc.).
## Examples
For practical implementation of the Para SDK in React Native environments, check out our GitHub repository:
## Troubleshooting
If you encounter issues during the integration or usage of the Para SDK in your React Native application, here are some
common problems and their solutions:
If you're having trouble initializing the Para SDK:
* Ensure that you've called `para.init()` after creating the Para instance.
* Verify that you're using the correct API key and environment.
* Check that all necessary dependencies are installed and linked properly.
* Look for any JavaScript errors in your Metro bundler console.
If you're seeing errors about missing native modules: - Run `pod install` in the `ios` directory to ensure all
CocoaPods dependencies are installed. - For Android, make sure your `android/app/build.gradle` file includes the
necessary dependencies. - Rebuild your app after adding new native dependencies. - If using Expo, ensure you've run
`expo prebuild` to generate native code.
If passkey creation, retrieval, or usage isn't working: - Verify that you've set up associated domains correctly for
both iOS and Android. - For iOS, check that your `entitlements` file includes the necessary associated domains. - For
Android, ensure your `asset_statements` are correctly configured in your `AndroidManifest.xml`. - Make sure you've
provided the correct SHA-256 fingerprint to the Para team for Android. - Check for any permission-related errors in
your logs.
If you're seeing errors related to crypto functions: - Ensure you've properly set up the
`react-native-get-random-values` and `react-native-quick-crypto` polyfills. - Verify that your `metro.config.js` file
is configured correctly to include the necessary Node.js core modules. - Check that you've imported the shim file at
the top of your root `index.js` file.
If you're encountering blob URL creation errors during passkey operations:
* Ensure you're using `{ disableWorkers: true }` in the ParaMobile constructor
* Verify the Para SDK shim is imported first in your `index.js` file
* This error occurs when Web Workers are enabled in React Native environments
If you're experiencing authentication issues:
* Double-check that your API key is correct and properly set in your environment variables.
* Verify you're using the correct environment (`BETA` or `PRODUCTION`) that matches your API key.
* Ensure your account has the necessary permissions for the operations you're attempting.
* Check your network requests for any failed API calls and examine the error messages.
For a more comprehensive list of solutions, visit our troubleshooting guide:
## Next Steps
After integrating Para, you can explore other features and integrations to enhance your Para experience.
# React Native and Expo Troubleshooting
Source: https://docs.getpara.com/v2/react-native/troubleshooting
Resolving integration issues for Para in React Native and Expo environments
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
When incorporating Para into React Native or Expo applications, developers may face specific hurdles. This guide offers
solutions to common problems and provides best practices for a smooth integration process.
Using an LLM (ChatGPT, Claude) or Coding Assistant (Cursor, Github Copilot)? Here are a few tips:
1. Include the for the most up-to-date help
2. Check out the for an interactive LLM using Para Examples Hub
## General Troubleshooting Steps
Before addressing specific issues, try these general troubleshooting steps for both React Native and Expo projects:
```bash
# For React Native
rm -rf node_modules
npm cache clean --force
npm install
# For Expo
expo r -c
```
`bash expo prebuild --clean `
```bash
# For React Native
npx react-native run-ios
npx react-native run-android
# For Expo
expo run:ios
expo run:android
```
## Common Issues and Solutions
**Error**: Errors related to missing modules like `crypto`, `buffer`, or `stream`.
**Solution**: Update your `metro.config.js` to include necessary polyfills:
```javascript
const { getDefaultConfig, mergeConfig } = require("@react-native/metro-config");
const nodeLibs = require("node-libs-react-native");
const config = {
resolver: {
extraNodeModules: {
...nodeLibs,
crypto: require.resolve("react-native-quick-crypto"),
buffer: require.resolve("@craftzdog/react-native-buffer"),
},
},
};
module.exports = mergeConfig(getDefaultConfig(__dirname), config);
```
**Error**: Errors persist despite Metro configuration, often related to global objects.
**Solution**: Create a `shim.js` file at the root of your project and import it in your entry file.
For the complete `shim.js` setup, refer to the Polyfills and Shims section in the and setup guides.
**Error**: Errors related to `crypto.subtle` API or missing cryptographic functions.
**Solution**: Add the `PolyfillCrypto` component to your root `App` component.
````jsx
import PolyfillCrypto from "react-native-webview-crypto";
export default function App() {
return (
<>
{/* Your app components */}
>
);
}
**Error**: Passkey functionality not working. Errors related to `ASAuthorizationController` or `ASWebAuthenticationSession` on iOS and `CredenitalManager` on Android.
**Solution**:
Passkeys requires configuring both the iOS and Android environments with the Para associated domains and web credentials.
Please check Step one of the Project Setup section for the and setup guides for detailed instructions.
**Error**: Passkeys not functioning despite correct configuration.
**Solution**: Ensure your app's bundle identifier and team ID are registered with Para.
Contact Para support to associate your app correctly. Provide your app's bundle identifier and team ID. You can find your team ID in the Apple Developer portal.
**Error**: Native modules not working in Expo Go.
**Solution**: Para is reliant on native modules and will not work with Expo Go. Use Expo's build service to create a standalone app. You can do this by running `expo build:ios` or `expo build:android`. This will create the corresponding iOS or Android folders in your project and link the native modules correctly. Alternative use expo prebuild to create the native folders for both platforms.
**Error**: Native modules not linking correctly. Build errors related to missing pods. Build stalls at the linking stage.
**Solution**: iOS in React Native projects requires manual linking of pods. Ensure the pods are correctly linked by running `pod install` in the `ios` directory. Expo auto links the pods, but you can run `expo prebuild --clean` to ensure the pods are correctly linked.
```bash
cd ios
pod install
cd ..
npx react-native run-ios
````
**Error**: Errors retrieving stored items.
**Solution**: Ensure React Native Async Storage and Keychain are installed and linked. Additionally ensure that you run `para.init()` as it asynchronusly initializes the storage.
### Best Practices
1. Implement robust error handling for all Para operations.
2. Use secure storage methods for sensitive data.
3. Keep your project's native code up to date with the latest Para SDK requirements.
For comprehensive setup instructions and the most up-to-date integration guide, please refer to our and quick start guides.
### Integration Support
If you're experiencing issues that aren't resolved by our troubleshooting resources, please [contact our team](https://join.slack.com/t/para-community/shared_invite/zt-304keeulc-Oqs4eusCUAJEpE9DBwAqrg) for
assistance. To help us resolve your issue quickly, please include the following information in your request:
1
A detailed description of the problem you're encountering.
2
Any relevant error messages or logs.
3
Steps to reproduce the issue.
4
Details about your system or environment (e.g., device, operating system, software version).
Providing this information will enable our team to address your concerns more efficiently.
# Content Security Policy (CSP) Configuration
Source: https://docs.getpara.com/v2/react/guides/csp
Configure Content Security Policy for Para SDK in Next.js and Vite applications
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Para SDK works out of the box when your application doesn't have a Content Security Policy (CSP). However, if your application has implemented a CSP for security purposes, you'll need to add specific directives to ensure Para SDK functions properly. This guide covers how to configure CSP for both Next.js and Vite applications.
## Required CSP Directives
If your application has a CSP policy in place, you'll need to include the following directives for Para SDK:
```text CSP Directives
# Script sources (for SDK initialization)
script-src 'https://*.getpara.com' 'https://*.usecapsule.com';
# Worker sources (required for blob workers)
worker-src 'blob:' 'https://*.getpara.com' 'https://*.usecapsule.com';
# Connect sources (API calls and websockets)
connect-src 'https://*.getpara.com' 'https://*.usecapsule.com' 'wss://*.getpara.com' 'wss://*.usecapsule.com' 'https://*.ingest.sentry.io' 'https://*.ingest.us.sentry.io';
# Frame sources (for embedded content)
frame-src 'https://*.getpara.com' 'https://*.usecapsule.com';
```
No CSP configuration is needed if your application doesn't currently implement a Content Security Policy. These directives are only required when you have an existing CSP that would otherwise block Para SDK's functionality.
If you do have a CSP policy, the `'blob:'` directive in `worker-src` is critical for Para SDK to function properly. It allows the SDK to create and execute web workers from blob URLs.
## Next.js Configuration
The following configurations are only needed if your Next.js application already has a CSP policy that needs to be updated to support Para SDK.
### App Router
For Next.js App Router with existing CSP headers, update your `next.config.js`:
```javascript next.config.js
const nextConfig = {
async headers() {
return [
{
source: '/:path*',
headers: [
{
key: 'Content-Security-Policy',
value: [
"default-src 'self'",
"script-src 'self' 'unsafe-inline' 'unsafe-eval' https://*.getpara.com https://*.usecapsule.com",
"worker-src 'self' blob: https://*.getpara.com https://*.usecapsule.com",
"connect-src 'self' https://*.getpara.com https://*.usecapsule.com wss://*.getpara.com wss://*.usecapsule.com https://*.ingest.sentry.io https://*.ingest.us.sentry.io",
"frame-src 'self' https://*.getpara.com https://*.usecapsule.com",
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data: https:",
"font-src 'self' data:"
].join('; ')
}
]
}
]
}
}
module.exports = nextConfig
```
### Pages Router with Middleware
For more dynamic CSP configuration, use Next.js middleware:
```typescript middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const response = NextResponse.next()
const csp = [
"default-src 'self'",
"script-src 'self' 'unsafe-inline' 'unsafe-eval' https://*.getpara.com https://*.usecapsule.com",
"worker-src 'self' blob: https://*.getpara.com https://*.usecapsule.com",
"connect-src 'self' https://*.getpara.com https://*.usecapsule.com wss://*.getpara.com wss://*.usecapsule.com https://*.ingest.sentry.io https://*.ingest.us.sentry.io",
"frame-src 'self' https://*.getpara.com https://*.usecapsule.com",
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data: https:",
"font-src 'self' data:"
].join('; ')
response.headers.set('Content-Security-Policy', csp)
return response
}
export const config = {
matcher: '/:path*'
}
```
## Vite Configuration
The following configurations are only needed if your Vite application already has a CSP policy that needs to be updated to support Para SDK.
For Vite applications with existing CSP, you can use the `vite-plugin-csp` plugin:
```bash Installation
npm install -D vite-plugin-csp
```
```javascript vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import csp from 'vite-plugin-csp'
export default defineConfig({
plugins: [
react(),
csp({
policy: {
'default-src': ["'self'"],
'script-src': ["'self'", "'unsafe-inline'", "'unsafe-eval'", 'https://*.getpara.com', 'https://*.usecapsule.com'],
'worker-src': ["'self'", 'blob:', 'https://*.getpara.com', 'https://*.usecapsule.com'],
'connect-src': ["'self'", 'https://*.getpara.com', 'https://*.usecapsule.com', 'wss://*.getpara.com', 'wss://*.usecapsule.com', 'https://*.ingest.sentry.io', 'https://*.ingest.us.sentry.io'],
'frame-src': ["'self'", 'https://*.getpara.com', 'https://*.usecapsule.com'],
'style-src': ["'self'", "'unsafe-inline'"],
'img-src': ["'self'", 'data:', 'https:'],
'font-src': ["'self'", 'data:']
}
})
]
})
```
### Alternative: Meta Tag Configuration
If your Vite application uses a meta tag for CSP, update your `index.html`:
```html index.html
Your App
```
## Development vs Production
For development environments, you may need to add `'unsafe-eval'` to `script-src` for hot module replacement. Ensure this is removed in production builds.
### Development CSP
```javascript Development Configuration
const isDevelopment = process.env.NODE_ENV === 'development'
const cspDirectives = {
'script-src': [
"'self'",
"'unsafe-inline'",
isDevelopment && "'unsafe-eval'", // Only in development
'https://*.getpara.com',
'https://*.usecapsule.com'
].filter(Boolean)
}
```
## Next Steps
# Custom Authentication UI with Para Client
Source: https://docs.getpara.com/v2/react/guides/custom-ui-client
Build custom authentication UI using the Para client directly with custom React Query hooks for maximum control
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
This guide covers building custom authentication UI using the Para client directly with custom React Query hooks. This approach provides maximum control over authentication flow, caching strategies, and error handling.
For simplified state management with pre-built hooks, see the [React Hooks Approach](/v2/react/guides/custom-ui-hooks).
## Prerequisites
You must have a Para account set up with authentication methods enabled in your Developer Portal. Install the Web SDK:
```bash
npm install @getpara/web-sdk @tanstack/react-query
```
## Para Client Setup
First, create a Para client instance that you'll use throughout your application:
```tsx
import { ParaWeb } from "@getpara/web-sdk";
const PARA_API_KEY = process.env.NEXT_PUBLIC_PARA_API_KEY!;
export const para = new ParaWeb(PARA_API_KEY);
```
## Direct Client Methods
",
description: "Promise resolving to AuthState indicating next step in authentication flow"
}}
async={true}
since="2.0.0"
id="para-sign-up-or-log-in"
/>
",
description: "Promise resolving to AuthStateSignup with passkey/password URLs for account creation"
}}
async={true}
since="2.0.0"
id="para-verify-new-account"
/>
boolean",
optional: true,
description: "Function to check if login process should be canceled"
},
{
name: "onCancel",
type: "() => void",
optional: true,
description: "Callback function executed when login is canceled"
},
{
name: "onPoll",
type: "() => void",
optional: true,
description: "Callback function executed on each polling interval"
},
{
name: "skipSessionRefresh",
type: "boolean",
optional: true,
description: "Whether to skip automatic session refresh after login",
defaultValue: "false"
}
]}
returns={{
type: "Promise<{ needsWallet?: boolean; partnerId?: string }>",
description: "Promise resolving with information about whether wallet creation is needed"
}}
async={true}
since="2.0.0"
id="para-wait-for-login"
/>
",
description: "Promise resolving to tuple of created wallet and optional recovery secret"
}}
async={true}
since="2.0.0"
id="para-create-wallet"
/>
boolean",
optional: true,
description: "Function to check if signing should be canceled"
},
{
name: "onCancel",
type: "() => void",
optional: true,
description: "Callback function executed when signing is canceled"
},
{
name: "onPoll",
type: "() => void",
optional: true,
description: "Callback function executed on each polling interval"
}
]}
returns={{
type: "Promise",
description: "Promise resolving to signature result or transaction review URL"
}}
async={true}
since="2.0.0"
id="para-sign-message"
/>
",
description: "Object mapping wallet IDs to wallet objects"
}}
since="2.0.0"
id="para-get-wallets"
/>
",
description: "Promise resolving to true if user is fully logged in, false otherwise"
}}
async={true}
since="2.0.0"
id="para-is-fully-logged-in"
/>
",
description: "Promise that resolves when logout is complete"
}}
async={true}
since="2.0.0"
id="para-logout"
/>
## Custom Hook Implementation Examples
Here are examples of how to create custom hooks using the Para client directly with React Query:
### Authentication Hook
```tsx
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { para } from '@/lib/para/client';
import type { AuthState } from '@getpara/web-sdk';
interface SignUpOrLoginParams {
email?: string;
phoneNumber?: string;
countryCode?: string;
}
export const useParaAuth = () => {
const queryClient = useQueryClient();
const signUpOrLoginMutation = useMutation({
mutationFn: async ({ email, phoneNumber, countryCode }: SignUpOrLoginParams) => {
if (email) {
return await para.signUpOrLogIn({ auth: { email } });
} else if (phoneNumber && countryCode) {
const phone = `+${countryCode}${phoneNumber}` as `+${number}`;
return await para.signUpOrLogIn({ auth: { phone } });
}
throw new Error('Either email or phone number is required');
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['paraAccount'] });
},
});
const verifyAccountMutation = useMutation({
mutationFn: async ({ verificationCode }: { verificationCode: string }) => {
return await para.verifyNewAccount({ verificationCode });
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['paraAccount'] });
},
});
const waitForLoginMutation = useMutation({
mutationFn: async (params?: { isCanceled?: () => boolean }) => {
return await para.waitForLogin(params);
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['paraAccount'] });
},
});
const logoutMutation = useMutation({
mutationFn: async (params?: { clearPregenWallets?: boolean }) => {
return await para.logout(params);
},
onSuccess: () => {
queryClient.invalidateQueries();
},
});
return {
signUpOrLogin: signUpOrLoginMutation.mutate,
signUpOrLoginAsync: signUpOrLoginMutation.mutateAsync,
isSigningUpOrLoggingIn: signUpOrLoginMutation.isPending,
signUpOrLoginError: signUpOrLoginMutation.error,
verifyAccount: verifyAccountMutation.mutate,
verifyAccountAsync: verifyAccountMutation.mutateAsync,
isVerifyingAccount: verifyAccountMutation.isPending,
verifyAccountError: verifyAccountMutation.error,
waitForLogin: waitForLoginMutation.mutate,
waitForLoginAsync: waitForLoginMutation.mutateAsync,
isWaitingForLogin: waitForLoginMutation.isPending,
waitForLoginError: waitForLoginMutation.error,
logout: logoutMutation.mutate,
logoutAsync: logoutMutation.mutateAsync,
isLoggingOut: logoutMutation.isPending,
logoutError: logoutMutation.error,
};
};
```
### Account State Hook
```tsx
import { useQuery } from '@tanstack/react-query';
import { para } from '@/lib/para/client';
export const useParaAccount = () => {
const { data: isLoggedIn = false, isLoading: isCheckingLogin } = useQuery({
queryKey: ['paraAccount', 'isLoggedIn'],
queryFn: async () => {
return await para.isFullyLoggedIn();
},
refetchInterval: 2000,
});
const { data: wallets = {}, isLoading: isLoadingWallets } = useQuery({
queryKey: ['paraAccount', 'wallets'],
queryFn: async () => {
return para.getWallets();
},
enabled: isLoggedIn,
refetchInterval: 5000,
});
const walletsArray = Object.values(wallets);
const primaryWallet = walletsArray.find(wallet => wallet.type === 'EVM') || walletsArray[0];
return {
isConnected: isLoggedIn,
address: primaryWallet?.address,
isLoading: isCheckingLogin || isLoadingWallets,
wallets: walletsArray,
primaryWallet,
};
};
```
### Wallet Management Hook
```tsx
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { para } from '@/lib/para/client';
import type { TWalletType } from '@getpara/web-sdk';
interface CreateWalletParams {
type?: TWalletType;
skipDistribute?: boolean;
}
export const useParaWallet = () => {
const queryClient = useQueryClient();
const createWalletMutation = useMutation({
mutationFn: async ({ type = 'EVM', skipDistribute = false }: CreateWalletParams) => {
return await para.createWallet({ type, skipDistribute });
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['paraAccount', 'wallets'] });
},
});
return {
createWallet: createWalletMutation.mutate,
createWalletAsync: createWalletMutation.mutateAsync,
isCreatingWallet: createWalletMutation.isPending,
createWalletError: createWalletMutation.error,
createdWallet: createWalletMutation.data,
};
};
```
### Message Signing Hook
```tsx
import { useMutation } from '@tanstack/react-query';
import { para } from '@/lib/para/client';
interface SignMessageParams {
message: string;
walletId?: string;
timeoutMs?: number;
onPoll?: () => void;
onCancel?: () => void;
isCanceled?: () => boolean;
}
export const useParaSignMessage = () => {
const signMessageMutation = useMutation({
mutationFn: async ({
message,
walletId,
timeoutMs = 120000,
...pollParams
}: SignMessageParams) => {
let targetWalletId = walletId;
if (!targetWalletId) {
const wallets = para.getWallets();
const walletsArray = Object.values(wallets);
const primaryWallet = walletsArray.find(w => w.type === 'EVM') || walletsArray[0];
if (!primaryWallet) {
throw new Error('No wallet available for signing');
}
targetWalletId = primaryWallet.id;
}
const messageBase64 = btoa(message);
return await para.signMessage({
walletId: targetWalletId,
messageBase64,
timeoutMs,
...pollParams,
});
},
});
return {
signMessage: signMessageMutation.mutate,
signMessageAsync: signMessageMutation.mutateAsync,
isSigning: signMessageMutation.isPending,
signError: signMessageMutation.error,
signature: signMessageMutation.data,
};
};
```
## Advanced Custom Hook Examples
### OAuth Authentication Hook
```tsx
import { useMutation } from '@tanstack/react-query';
import { para } from '@/lib/para/client';
export const useParaOAuth = () => {
const oauthMutation = useMutation({
mutationFn: async ({
method,
onOAuthUrl,
onOAuthPopup,
isCanceled,
onCancel,
onPoll
}: {
method: 'GOOGLE' | 'APPLE' | 'FACEBOOK' | 'DISCORD' | 'X';
onOAuthUrl?: (url: string) => void;
onOAuthPopup?: (popup: Window) => void;
isCanceled?: () => boolean;
onCancel?: () => void;
onPoll?: () => void;
}) => {
return await para.verifyOAuth({
method,
onOAuthUrl,
onOAuthPopup,
isCanceled,
onCancel,
onPoll,
});
},
});
return {
authenticateWithOAuth: oauthMutation.mutate,
authenticateWithOAuthAsync: oauthMutation.mutateAsync,
isAuthenticating: oauthMutation.isPending,
authError: oauthMutation.error,
authResult: oauthMutation.data,
};
};
```
### Session Management Hook
```tsx
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { para } from '@/lib/para/client';
export const useParaSession = () => {
const queryClient = useQueryClient();
const { data: sessionInfo, isLoading: isLoadingSession } = useQuery({
queryKey: ['paraSession'],
queryFn: async () => {
const isLoggedIn = await para.isFullyLoggedIn();
if (!isLoggedIn) return null;
return {
isActive: true,
wallets: para.getWallets(),
timestamp: Date.now(),
};
},
refetchInterval: 30000, // Check session every 30 seconds
});
const refreshSessionMutation = useMutation({
mutationFn: async () => {
return await para.refreshSession?.() || true;
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['paraSession'] });
},
});
const keepAlive = () => {
if (sessionInfo?.isActive) {
refreshSessionMutation.mutate();
}
};
return {
sessionInfo,
isLoadingSession,
isSessionActive: !!sessionInfo?.isActive,
refreshSession: refreshSessionMutation.mutate,
isRefreshing: refreshSessionMutation.isPending,
keepAlive,
};
};
```
### Error Handling Hook
```tsx
import { useCallback } from 'react';
import { toast } from 'react-hot-toast';
export const useParaErrorHandler = () => {
const handleError = useCallback((error: Error, context?: string) => {
console.error(`Para Error ${context ? `(${context})` : ''}:`, error);
// Handle specific error types
if (error.message.includes('network')) {
toast.error('Network error. Please check your connection.');
} else if (error.message.includes('unauthorized')) {
toast.error('Authentication expired. Please log in again.');
} else if (error.message.includes('cancelled')) {
toast.error('Operation was cancelled.');
} else {
toast.error(error.message || 'An unexpected error occurred.');
}
}, []);
const withErrorHandling = useCallback((
fn: (...args: T) => Promise,
context?: string
) => {
return async (...args: T): Promise => {
try {
return await fn(...args);
} catch (error) {
handleError(error as Error, context);
return undefined;
}
};
}, [handleError]);
return { handleError, withErrorHandling };
};
```
## Benefits of Direct Client Approach
1. **Full Control**: Complete control over state management and caching strategies
2. **Custom Return Interfaces**: Design return interfaces that match your application's needs
3. **Enhanced Error Handling**: Add custom error processing and retry logic
4. **Flexible Polling**: Implement custom polling behavior for long-running operations
5. **Performance Optimization**: Optimize queries and mutations for your specific use case
## Trade-offs
1. **More Boilerplate**: Requires more code to implement the same functionality
2. **Manual Cache Management**: You need to handle cache invalidation manually
3. **Type Safety**: May need to define custom TypeScript interfaces
4. **Maintenance**: More code to maintain and update as the SDK evolves
## Best Practices
1. **Centralized Client**: Create a single Para client instance and share it across your app
2. **Query Key Consistency**: Use consistent query key patterns for cache management
3. **Error Boundaries**: Implement error boundaries to catch and handle errors gracefully
4. **Loading States**: Provide clear loading states for better user experience
5. **Cache Invalidation**: Invalidate relevant queries after mutations
6. **Type Safety**: Define proper TypeScript interfaces for your custom hooks
## Next Steps
# Custom Authentication UI with React Hooks
Source: https://docs.getpara.com/v2/react/guides/custom-ui-hooks
Build custom authentication UI using Para's React hooks for simplified state management
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
This guide covers building custom authentication UI using Para's React hooks from `@getpara/react-sdk@alpha`. This approach provides simplified state management and is recommended for most React applications.
For maximum control over authentication flow and custom React Query implementations, see the [Para Client Approach](/v2/react/guides/custom-ui-client).
## Prerequisites
You must have a Para account set up with authentication methods enabled in your Developer Portal. Install the React SDK:
```bash
npm install @getpara/react-sdk@alpha --save-exact
```
## Authentication States
There are three stages for an authenticating user and three corresponding `AuthState` types that are returned from various authentication methods:
| Stage | Meaning | Applicable Methods |
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| `'verify'` | The user has entered their email or phone number and been sent a confimation code via email or SMS. Alternatively, they have logged in via an external wallet and need to sign a message to verify their ownership of the wallet. | `signUpOrLogIn`, `loginExternalWallet` |
| `'signup'` | The user has verified their email, phone number, external wallet, or completed a third-party authentication and may now create a WebAuth passkey or password to secure their account. | `verifyNewAccount`, `verifyExternalWallet`, `verifyOAuth`, `verifyTelegram`, `verifyFarcaster` |
| `'login'` | The user has previously signed up and can now log in using their WebAuth passkey or password. | `signUpOrLogIn` , `loginExternalWallet` , `verifyOAuth` , `verifyTelegram`, `verifyFarcaster` |
### AuthState Type Definitions
## Authentication State Management
You will most likely want to track the `AuthState` within your app and update it with each method resolution. For example, you may want to store it in a dedicated context:
```tsx
import React from 'react';
import { AuthState } from '@getpara/react-sdk';
const AuthStateContext = React.createContext<[
AuthState | undefined,
React.Dispatch>
]>([undefined, () => {}]);
export function AuthStateProvider({ children }: React.PropsWithChildren) {
const [authState, setAuthState] = React.useState();
return {
{children}
};
}
export const useAuthState = () => React.useContext(AuthStateContext);
```
## Authentication Hooks
",
description: "React Query mutation result with mutate/mutateAsync functions and state"
}}
since="2.0.0"
id="use-sign-up-or-log-in"
/>
",
description: "React Query mutation result returning AuthStateSignup with passkey/password URLs"
}}
since="2.0.0"
id="use-verify-new-account"
/>
boolean",
optional: true,
description: "Function to check if login process should be canceled (e.g., popup closed)"
},
{
name: "onCancel",
type: "() => void",
optional: true,
description: "Callback function executed when login is canceled"
},
{
name: "onPoll",
type: "() => void",
optional: true,
description: "Callback function executed on each polling interval"
},
{
name: "skipSessionRefresh",
type: "boolean",
optional: true,
description: "Whether to skip automatic session refresh after login",
defaultValue: "false"
}
]}
returns={{
type: "UseMutationResult<{ needsWallet?: boolean; partnerId?: string }, Error, WaitForLoginParams>",
description: "React Query mutation result indicating if wallet creation is needed"
}}
since="2.0.0"
id="use-wait-for-login"
/>
boolean",
optional: true,
description: "Function to check if wallet creation should be canceled"
},
{
name: "onCancel",
type: "() => void",
optional: true,
description: "Callback function executed when wallet creation is canceled"
},
{
name: "onPoll",
type: "() => void",
optional: true,
description: "Callback function executed on each polling interval"
}
]}
returns={{
type: "UseMutationResult<{ wallets: Wallet[]; walletIds: CurrentWalletIds; recoverySecret?: string }, Error, WaitForWalletCreationParams>",
description: "React Query mutation result with created wallets and recovery information"
}}
since="2.0.0"
id="use-wait-for-wallet-creation"
/>
## Phone or Email Authentication
### Sign up or log in
To authenticate a user via email or phone number, use the `useSignUpOrLogIn` hook. This mutation will either fetch the user with the provided authentication method and return an `AuthStateLogin` object, or create a new user and return an `AuthStateVerify` object.
* If the user already exists, you will need to open either the `passkeyUrl` or `passwordUrl` in a new window or tab, then invoke the `useWaitForLogin` mutation. This hook will wait until the user has completed the login process in the new window and then perform any needed setup.
* If the user is new, you will then need to display a verification code input and later invoke the `useVerifyNewAccount` mutation.
```tsx
import { useSignUpOrLogIn } from "@getpara/react-sdk@alpha";
import { useAuthState } from '@/hooks';
function AuthInput() {
const { signUpOrLogIn, isLoading, isError } = useSignUpOrLogIn();
const [authState, setAuthState] = useAuthState();
const [authType, setAuthType] = useState<'email' | 'phone'>("email");
const onSubmit = (identifier: string) => {
signUpOrLogIn(
{
auth: authType === "email"
? { email: identifier }
: { phone: identifier as `+${number}` },
},
{
onSuccess: (authState) => {
setAuthState(authState);
switch (authState.stage) {
case "verify":
// Display verification code input
break;
case "login":
const { passkeyUrl, passwordUrl } = authState;
// Open a login URL in a new window or tab
break;
}
},
onError: (error) => {
// Handle error
},
}
);
};
// ...
}
```
### Verify new account
While in the `verify` stage, you will need to display an input for a six-digit code and a callback that invokes the `useVerifyNewAccount` hook. This will validate the one-time code and, if successful, will return an `AuthStateLogin` object. (The email or phone number previously entered is now stored, and will not need to be resupplied.)
```tsx
import { useVerifyNewAccount } from "@getpara/react-sdk@alpha";
import { useAuthState } from '@/hooks';
function VerifyOtp() {
const { verifyNewAccount, isLoading, isError } = useVerifyNewAccount();
const [_, setAuthState] = useAuthState();
const [verificationCode, setVerificationCode] = useState('');
const onSubmit = (verificationCode: string) => {
verifyNewAccount(
{ verificationCode },
{
onSuccess: (authState) => {
setAuthState(authState);
const { isPasskeySupported, passkeyUrl, passwordUrl } = authState;
// Update your UI and prepare to log in the user
},
onError: (error) => {
// Handle a mismatched code
},
}
);
};
// ...
}
```
### Resend verification code
You can present a button to resend the verification code to the user's email or phone in case they need a second one.
",
description: "React Query mutation result for resending verification code"
}}
since="2.0.0"
id="use-resend-verification-code"
/>
```tsx
import { useResendVerificationCode } from "@getpara/react-sdk@alpha";
function VerifyOtp() {
const { resendVerificationCode, isLoading, isError } = useResendVerificationCode();
const [isResent, setIsResent] = React.useState(false);
const timeout = useRef();
const onClickResend = () => {
resendVerificationCode(
undefined,
{
onSuccess: () => {
setIsResent(true);
timeout.current = setTimeout(() => {
setIsResent(false);
}, 3000)
},
onError: e => {
console.error(e);
}
}
);
}
// ...
}
```
### Sign up a new user
After verification is complete, you will receive an `AuthStateSignup` object. Depending on your configuration, the `AuthStateSignup` will contain a Para URL for creating a WebAuth biometric passkey, a Para URL for creating a new password, or both. For compatibility and security, you will most likely want to open these URLs in a new popup window, and then immediately invoke the `useWaitForWalletCreation` hook. This will wait for the user to complete signup and then create a new wallet for each wallet type you have configured in the Para Developer Portal. If you would like more control over the signup process, you can also call the `useWaitForSignup` hook, which will resolve after signup but bypass automatic wallet provisioning. To cancel the process in response to UI events, you can pass the `isCanceled` callback.
```tsx
import { useWaitForWalletCreation } from "@getpara/react-sdk@alpha";
import { useAuthState } from '@/hooks';
function Signup() {
const popupWindow = React.useRef(null);
const { waitForWalletCreation, isLoading, isError } = useWaitForWalletCreation();
const [authState, setAuthState] = useAuthState();
const onSelectSignupMethod = (chosenMethod: 'passkey' | 'password') => {
const popupUrl = chosenMethod === 'passkey' && authState.isPasskeySupported
? authState.passkeyUrl!
: authState.passwordUrl!
popupWindow.current = window.open(popupUrl, `ParaSignup_${chosenMethod}`);
waitForWalletCreation(
{
isCanceled: () => popupWindow.current?.closed,
},
{
onSuccess: () => {
// Handle successful signup and wallet provisioning
},
onError: (error) => {
// Handle a canceled signup
},
}
);
};
// ...
}
```
### Log in an existing user
Depending on your configuration, the `AuthStateLogin` will contain a Para URL for creating a WebAuth biometric passkey, a Para URL for creating a new password, or both. For compatibility and security, you will most likely want to open these URLs in a new popup window, and then immediately invoke the `useWaitForLogin` hook. This will wait for the user to complete the login process and resolve when it is finished. To cancel the process in response to UI events, you can pass the `isCanceled` callback.
```tsx
import { useWaitForLogin } from "@getpara/react-sdk@alpha";
import { useAuthState } from '@/hooks';
function Login() {
const popupWindow = React.useRef(null);
const { waitForLogin, isLoading, isError } = useWaitForLogin();
const [authState, setAuthState] = useAuthState();
const onSelectLoginMethod = (chosenMethod: 'passkey' | 'password') => {
const popupUrl = chosenMethod === 'passkey'
? authState.passkeyUrl!
: authState.passwordUrl!;
popupWindow.current = window.open(popupUrl, 'ParaLogin');
waitForLogin(
{
isCanceled: () => popupWindow.current?.closed,
},
{
onSuccess: (result) => {
const { needsWallet } = result;
if (needsWallet) {
// Create wallet(s) for the user if needed
} else {
// Set up signed-in UI
}
},
onError: (error) => {
// Handle a canceled login
},
}
);
};
// ...
}
```
## Third-Party Authentication Hooks
void",
required: true,
description: "A callback function that receives the OAuth URL to open in a popup window. Pass either this or `onOAuthPopup`."
},
{
name: "onOAuthPopup",
type: "(popup: Window) => void",
required: true,
description: "If supplied, a popup window will be opened to the OAuth URL. This callback will then be invoked with the `Window` object. Pass either this or `onOAuthUrl`."
},
{
name: "isCanceled",
type: "() => boolean",
optional: true,
description: "Function to check if OAuth process should be canceled"
},
{
name: "onCancel",
type: "() => void",
optional: true,
description: "Callback function executed when OAuth is canceled"
},
{
name: "onPoll",
type: "() => void",
optional: true,
description: "Callback function executed on each polling interval"
}
]}
returns={{
type: "UseMutationResult",
description: "React Query mutation result that returns either signup or login state"
}}
since="2.0.0"
id="use-verify-oauth"
/>
",
description: "React Query mutation result that returns either signup or login state"
}}
since="2.0.0"
id="use-verify-telegram"
/>
void",
required: true,
description: "Callback function that receives the Farcaster Connect URI to display as QR code"
},
{
name: "isCanceled",
type: "() => boolean",
optional: true,
description: "Function to check if Farcaster process should be canceled"
},
{
name: "onCancel",
type: "() => void",
optional: true,
description: "Callback function executed when Farcaster auth is canceled"
},
{
name: "onPoll",
type: "() => void",
optional: true,
description: "Callback function executed on each polling interval"
}
]}
returns={{
type: "UseMutationResult",
description: "React Query mutation result that returns either signup or login state"
}}
since="2.0.0"
id="use-verify-farcaster"
/>
### OAuth
Para supports OAuth 2.0 sign-ins via Google, Apple, Facebook, Discord, and X, provided the linked account has an email address set. Once a valid email account is fetched, the process is identical to that for email authentication, simply bypassing the one-time code verification step. To implement OAuth flow, use the `useVerifyOAuth` hook.
```tsx
import { type TOAuthMethod, useVerifyOAuth } from "@getpara/react-sdk@alpha";
import { useAuthState } from '@/hooks';
function OAuthLogin() {
const popupWindow = React.useRef(null);
const { verifyOAuth, isLoading, isError } = useVerifyOAuth();
const [authState, setAuthState] = useAuthState();
const onOAuthLogin = (method: TOAuthMethod) => {
verifyOAuth(
{
method,
onOAuthPopup: (oAuthPopup) => {
popupWindow.current = oAuthPopup;
},
isCanceled: () => popupWindow.current?.closed,
},
{
onSuccess: (authState) => {
setAuthState(authState);
switch (authState.stage) {
case 'signup':
// New user: refer to 'Sign up a new user'
break;
case 'login':
// Returning user: refer to 'Log in an existing user'
break;
};
},
onError: (error) => {
// Handle a canceled OAuth verification
},
}
);
};
// ...
}
```
### Telegram
To implement your own Telegram authentication flow, please refer to the [official documentation](https://core.telegram.org/widgets/login). Para uses the following bots to handle authentication requests:
| Environment | Username | Bot ID |
| ----------- | ----------------------------------------------------------- | ---------- |
| `BETA` | [@para\_oauth\_beta\_bot](https://t.me/para_oauth_beta_bot) | 7788006052 |
| `PROD` | [@para\_oauth\_bot](https://t.me/para_oauth_bot) | 7643995807 |
Once a Telegram authentication response is received, you can invoke the `useVerifyTelegram` hook to sign up or log in a user associated with the returned Telegram user ID. Users created via Telegram will *not* have an associated email address or phone number.
```tsx
import { useVerifyTelegram } from "@getpara/react-sdk@alpha";
import { useAuthState } from '@/hooks';
type TelegramAuthObject = {
auth_date: number;
first_name?: string;
hash: string;
id: number;
last_name?: string;
photo_url?: string;
username?: string;
};
function TelegramLogin() {
const popupWindow = React.useRef(null);
const { verifyTelegram, isLoading, isError } = useVerifyTelegram();
const [authState, setAuthState] = useAuthState();
const onTelegramResponse = (response: TelegramAuthObject) => {
verifyTelegram(
{ telegramAuthObject: response },
{
onSuccess: (authState) => {
setAuthState(authState);
switch (authState.stage) {
case 'signup':
// New user: refer to 'Sign up a new user'
break;
case 'login':
// Returning user: refer to 'Log in an existing user'
break;
};
},
onError: (error) => {
// Handle a failed Telegram verification
},
}
);
};
// ...
}
```
### Farcaster
Refer to the [official documentation](https://docs.farcaster.xyz/developers/siwf/) for information on Farcaster's SIWF (Sign In with Farcaster) feature.
To use this authentication method, use the `useVerifyFarcaster` hook. The hook will supply a Farcaster Connect URI, which should be displayed to your users as a QR code. Like with Telegram, users created via Farcaster will *not* have an associated email address or phone number.
```tsx
import { useVerifyFarcaster } from "@getpara/react-sdk@alpha";
import { useAuthState } from '@/hooks';
function FarcasterLogin() {
const { verifyFarcaster, isLoading, isError } = useVerifyFarcaster();
const [authState, setAuthState] = useAuthState();
const [farcasterConnectUri, setFarcasterConnectUri] = useState(null);
const isCanceled = React.useRef(false);
useEffect(() => {
isCanceled.current = !farcasterConnectUri;
}, [farcasterConnectUri]);
const onClickCancelButton = () => {
setFarcasterConnectUri(null);
}
const onClickFarcasterLoginButton = () => {
verifyFarcaster(
{
onConnectUri: connectUri => {
setFarcasterConnectUri(connectUri);
},
isCanceled: () => isCanceled.current,
},
{
onSuccess: (authState) => {
setAuthState(authState);
switch (authState.stage) {
case 'signup':
// New user: refer to 'Sign up a new user'
break;
case 'login':
// Returning user: refer to 'Log in an existing user'
break;
};
},
onError: (error) => {
// Handle a failed Telegram verification
},
}
);
};
// ...
}
```
## Two-Factor Authentication Hooks
",
description: "React Query mutation result with 2FA setup status and optional QR URI"
}}
since="2.0.0"
id="use-setup-2fa"
/>
",
description: "React Query mutation result for enabling 2FA"
}}
since="2.0.0"
id="use-enable-2fa"
/>
",
description: "React Query mutation result for 2FA verification"
}}
since="2.0.0"
id="use-verify-2fa"
/>
Para supports two-factor authentication via one-time codes in Google Authenticator or similar apps. To check a user's current 2FA status, use the `useSetup2fa` hook:
* If the user has already set up two-factor authentication, the `setup2fa` mutation will return `{ isSetup: true }`.
* If not, the mutation will return `{ isSetup: false, uri: string }`, where `uri` is a URI that can be scanned as a QR code by Authenticator or a similar app.
* When the user has entered the code from their authenticator app, you can use the `useEnable2fa` hook to activate 2FA for their account.
* Subsequently, you can use the `useVerify2fa` hook to verify the user's account by their one-time code.
```tsx Initial Setup
import { useSetup2fa } from '@getpara/react-sdk';
function Setup2fa() {
const { setup2fa, isPending } = useSetup2fa();
const [twoFAUri, setTwoFAUri] = useState(null);
const onClickSetup2fa = () => {
setup2fa(
undefined,
{
onSuccess: (result) => {
if (result.isSetup) {
// User has already set up 2FA
} else {
// Display QR code with result.uri
setTwoFAUri(result.uri);
}
},
onError: (error) => {
// Handle error
},
}
);
};
// ...
}
```
```tsx Enable 2FA
import { useEnable2fa } from '@getpara/react-sdk';
function Enable2fa() {
const { enable2fa, isPending } = useEnable2fa();
const [verificationCode, setVerificationCode] = useState('');
const onClickEnable2fa = () => {
enable2fa(
{ verificationCode },
{
onSuccess: () => {
// 2FA has been successfully enabled
},
onError: (error) => {
// Handle error
},
}
);
};
// ...
```
```tsx Verify 2FA
import { useVerify2fa } from '@getpara/react-sdk';
function Verify2fa() {
const { verify2fa, isPending } = useVerify2fa();
const [verificationCode, setVerificationCode] = useState('');
const onClickVerify2fa = () => {
verify2fa(
{ verificationCode },
{
onSuccess: () => {
// User has been successfully verified
},
onError: (error) => {
// Handle error
},
}
);
};
// ...
```
## Logout
",
description: "React Query mutation result for user logout"
}}
since="2.0.0"
id="use-logout-hook"
/>
To sign out the current user, use the `useLogout` hook. By default, signing out will preserve any pregenerated wallets (including guest login wallets) present in the device storage, some of which may not belong to the signed-in user. To clear all wallets, set the `clearPregenWallets` parameter to `true`.
```tsx
import { useLogout } from '@getpara/react-sdk';
function Account() {
const { logout, isPending } = useLogout();
const onClickLogout = () => {
logout(
undefined,
{
onSuccess: () => {
// Update UI to non-authenticated state
},
}
);
};
const onClickLogoutAndClearWallets = () => {
logout(
{ clearPregenWallets: true },
{
onSuccess: () => {
// Update UI to non-authenticated state
},
}
);
};
// ...
}
```
## Next Steps
# Balance Display
Source: https://docs.getpara.com/v2/react/guides/customization/balances
Learn how to configure and display balances in the Para Modal, including Aggregated and Custom Asset modes, and use the useProfileBalance hook for programmatic access.
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
The Para Modal provides comprehensive balance display capabilities, allowing users to view their wallet balances across multiple assets and networks. You can configure how balances are displayed and aggregated, and programmatically access balance data using the `useProfileBalance` hook.
## Balance Display Configuration
You can customize how balances are displayed and calculated through the `paraModalConfig.balances` property in your `ParaProvider` configuration. This setting will impact both the Para Modal's balance display and instances where you use the `useProfileBalance` hook.
Para supports two primary balance display modes, `AGGREGATED` and `CUSTOM_ASSET`.
### Defining Custom Networks and Assets
To include custom assets when fetching connected wallet balances, you will need to supply implementation metadata for each asset, including:
* Each asset must include basic metadata, including `name`, `symbol`, and `logoUrl` (optional).
* Each asset must include an `implementations` array for each network you wish to query for balances.
* Each implementation object must include:
* Price data:
* **For a fixed price:**
* Include a `price` object with the asset's price in the format `{ value: number; currency: 'USD' }`.
* **For a volatile price:**
* Include a `priceUrl` string. This endpoint must respond to GET requests with a JSON object with the asset's current price in the format `{ value: number; currency: 'USD' }`.
* Network information:
* **For a custom EVM network:**
* Include a `network` object specifying the network's `name`, `evmChainId`, and an `rpcUrl` where asset balances can be queried.
* **If the asset is the network's native token:**
* No additional configuration is needed.
* **If the asset is an ERC-20 token:**
* Include a `contractAddress` string.
* **For a standard EVM or Solana network:**
* Include a `network` string, matching one of the networks enumerated in the `TNetwork` type. For example, `'ETHEREUM'` or `'SOLANA'`.
* Include a `contractAddress` string.
Refer to the code snippets below for example configurations.
### Aggregated Mode (Default)
Aggregated Mode automatically aggregates balances across all detected chains and assets and displays them in USD value. If you supply additional assets and price data, these totals will be included in the calculation.
The aggregated total will include most commonly used assets across many networks. If you want to only include totals from your customized tokens, set `excludeStandardAssets` to `true`.
An example configuration with additional assets is below:
```tsx
',
// A price endpoint for the asset:
priceUrl: '',
implementations: [
// A custom EVM network where the asset is the native token:
{
network: {
name: 'Custom Chain',
evmChainId: '12345',
rpcUrl: '',
},
},
// A custom EVM network where the asset is an ERC-20 token:
{
network: {
name: 'Custom Chain',
evmChainId: '12345',
rpcUrl: '',
},
contractAddress: '0x...',
},
// An implementation of the token on Solana:
{
network: 'SOLANA',
contractAddress: 'Ep4r...',
},
],
},
{
name: 'Custom Stablecoin',
symbol: 'CSTABLE',
logoUrl: '',
// A fixed price for the asset
price: {
value: 1,
currency: 'USD',
},
networks: [
// A custom network where the asset is an ERC-20 token:
{
network: {
name: 'Custom Chain',
evmChainId: '12345',
rpcUrl: '',
},
contractAddress: '0x...',
},
],
},
]
}
}}
>
{children}
```
### Custom Asset Mode
In Custom Asset Mode, the Para Modal will only display balances of a chosen asset, with no fiat currency conversion. This is ideal for cases where your app uses a particular token that may not have price information available.
Like in Aggregated Mode, you will need to supply implementation metadata for the asset, including any custom network definitions so that its balances can be queried for the session's connected wallets. However, in this mode, you do not need to include a price object or a price URL.
```tsx
',
networks: [
// A custom network where the asset is the native token:
{
network: {
name: 'Custom Chain',
evmChainId: '12345',
rpcUrl: '',
},
},
// A known network where the asset is an ERC-20 token:
{
contractAddress: '0x...',
network: 'ETHEREUM',
}
],
},
},
}}
>
{children}
```
## useProfileBalance Hook
The `useProfileBalance` hook allows you to query the current aggregated or custom asset balance of all wallets in the current session.
Balances are normally cached on the server for five minutes. You can supply a `refetchTrigger` to the hook to manually refetch balances when desired, using a unique number or string.
```tsx
import { useProfileBalance } from "@getpara/react-sdk";
function BalanceDisplay() {
const [refetchTrigger, setRefetchTrigger] = useState(0);
const { data: profileBalance, isLoading, error } = useProfileBalance({
// Balances will be refetched whenever `refetchTrigger` changes
refetchTrigger,
});
if (isLoading) return Loading balances...
;
if (error) return Error loading balances: {error.message}
;
if (!profileBalance) return No balance data available
;
return (
Total Balance: ${profileBalance.value.value.toFixed(2)}
{profileBalance.wallets.map((wallet) => (
Wallet: {wallet.address}
{wallet.assets.map((asset) => (
{asset.symbol}: ${asset.balance}
(${asset.value.value.toFixed(2)})
))}
))}
setRefetchTrigger(prev => prev + 1)}>Refresh Balances
);
}
```
Depending on the display type, the `ProfileBalance` object returned by `useProfileBalance` has the following structure:
```tsx
{
value: {
value: 200,
currency: 'USD',
},
wallets: [
{
type: 'EVM',
address: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
value: {
value: 200,
currency: 'USD',
},
assets: [
{
metadata: {
internalId: 'ETHEREUM',
zerionId: 'eth',
name: 'Ethereum',
price: {
value: 4000,
currency: 'USD',
}
},
quantity: 0.03,
value: {
value: 120,
currency: 'USD',
},
networks: [
{
metadata: {
internalId: 'ETHEREUM',
zerionId: 'ethereum',
evmChainId: '1',
name: 'Ethereum',
},
quantity: 0.02,
value: {
value: 80,
currency: 'USD',
},
},
{
metadata: {
internalId: 'BASE',
zerionId: 'base',
evmChainId: '8453',
name: 'Base',
},
quantity: 0.01,
value: {
value: 40,
currency: 'USD',
},
}
]
},
{
metadata: {
internalId: 'USDC',
zerionId: 'usdc',
name: 'USD Coin',
price: {
value: 1,
currency: 'USD',
}
},
quantity: 80,
value: {
value: 80,
currency: 'USD',
},
networks: [
{
metadata: {
internalId: 'ETHEREUM',
zerionId: 'ethereum',
evmChainId: '1',
name: 'Ethereum',
},
quantity: 50,
value: {
value: 50,
currency: 'USD',
},
},
{
metadata: {
internalId: 'BASE',
zerionId: 'base',
evmChainId: '8453',
name: 'Base',
},
quantity: 20,
value: {
value: 20,
currency: 'USD',
},
},
{
metadata: {
internalId: 'SOLANA',
name: 'Solana',
},
quantity: 10,
value: {
value: 10,
currency: 'USD',
},
}
]
}
],
networks: [
{
metadata: {
internalId: 'ETHEREUM',
zerionId: 'ethereum',
evmChainId: '1',
name: 'Ethereum',
},
value: {
value: 130,
currency: 'USD',
},
assets: [
{
metadata: {
internalId: 'ETHEREUM',
zerionId: 'ethereum',
evmChainId: '1',
name: 'Ethereum',
},
quantity: 0.02,
value: {
value: 80,
currency: 'USD',
},
},
{
metadata: {
internalId: 'USDC',
zerionId: 'usdc',
name: 'USD Coin',
price: {
value: 1,
currency: 'USD',
},
},
quantity: 50,
value: {
value: 50,
currency: 'USD',
},
}
]
},
{
metadata: {
internalId: 'BASE',
zerionId: 'base',
evmChainId: '8453',
name: 'Base',
},
value: {
value: 60,
currency: 'USD',
},
assets: [
{
metadata: {
internalId: 'ETHEREUM',
zerionId: 'eth',
evmChainId: '1',
name: 'Ethereum',
},
quantity: 0.01,
value: {
value: 40,
currency: 'USD',
},
},
{
metadata: {
internalId: 'USDC',
zerionId: 'usdc',
name: 'USD Coin',
price: {
value: 1,
currency: 'USD',
},
},
quantity: 20,
value: {
value: 20,
currency: 'USD',
},
}
]
},
{
metadata: {
internalId: 'SOLANA',
name: 'Solana',
},
value: {
value: 10,
currency: 'USD',
},
assets: [
{
metadata: {
internalId: 'USDC',
zerionId: 'usdc',
name: 'USD Coin',
price: {
value: 1,
currency: 'USD',
},
},
quantity: 10,
value: {
value: 10,
currency: 'USD',
},
}
]
}
]
}
]
}
```
```tsx
{
wallets: [
{
type: 'EVM',
address: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
assets: [
{
metadata: {
name: 'Custom Asset',
symbol: 'CUSTOM',
customAssetId: 'custom_CUSTOM',
},
quantity: 1.5,
networks: [
{
metadata: {
internalId: 'ETHEREUM',
zerionId: 'ethereum',
name: 'Ethereum',
evmChainId: '1',
},
quantity: 1.0,
},
{
metadata: {
customNetworkId: 'custom_12345',
name: 'Custom Chain',
evmChainId: '12345',
},
quantity: 0.5,
}
]
}
],
networks: [
{
metadata: {
internalId: 'ETHEREUM',
zerionId: 'ethereum',
name: 'Ethereum',
evmChainId: '1',
},
assets: [
{
metadata: {
name: 'Custom Asset',
symbol: 'CUSTOM',
customAssetId: 'custom_CUSTOM',
},
quantity: 1.5,
}
]
},
{
metadata: {
customNetworkId: 'custom_12345',
name: 'Custom Chain',
evmChainId: '12345',
},
assets: [
{
metadata: {
name: 'Custom Asset',
symbol: 'CUSTOM',
customAssetId: 'custom_CUSTOM',
},
quantity: 0.5,
}
]
}
]
}
]
}
```
# Developer Portal Email Branding
Source: https://docs.getpara.com/v2/react/guides/customization/developer-portal-email-branding
Customize the appearance of Welcome and OTP emails with your brand.
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
Customize the visual appearance of Welcome and OTP emails sent to your users during authentication. These branding settings apply specifically to automated emails, not your Para modal interface. If you're looking to customize the modal appearance, refer to the .
## Brand Colors
Configure your brand colors to match your company's visual identity in all email communications.
### Color Settings
* **Foreground**: Primary brand color for buttons, links, and highlights
* **Background**: Background color for email content areas
* **Accent (Optional)**: Secondary color for borders and accents
- Use your primary brand color for the foreground to maintain consistency
- Ensure sufficient contrast between foreground and background colors
## Typography
Select fonts that align with your brand identity and ensure readability across email clients.
## Logo Assets
Upload your company's visual assets to personalize email headers and branding.
* **Icon**: 80px × 80px square format for email headers
* **Logo**: Maximum width 200px for email signatures and footers
* **Format**: PNG or SVG recommended for best quality
* **Background**: Transparent backgrounds work best
## Social Links
Add your company's social media and website links to email footers. These links will appear in all automated emails, providing users with easy access to your online presence.
### Available Links
* **Website URL**: Your company's main website
* **X/Twitter Profile**: Twitter or X profile link
* **LinkedIn Profile**: Company or founder LinkedIn page
* **GitHub Profile**: Company or project GitHub repository
## Email Impact
These branding settings specifically affect:
### Welcome Emails
* Sent to new users during initial registration
* Display your logo, brand colors, and company links
* Include verification links with your custom styling
### OTP Emails
* Sent during two-factor authentication
* Use your brand colors and typography
* Include your logo for brand recognition
Email branding settings do NOT affect your Para modal interface. For modal customization, see the .
## Next Steps
# Developer Portal Payment Integration
Source: https://docs.getpara.com/v2/react/guides/customization/developer-portal-payments
Configure payment providers and transaction features for crypto onramps and offramp.
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
Configure payment providers and transaction features to enable crypto buying, selling, and wallet funding for your users. These settings control which payment options appear in your Para integration.
These configurations will show up in the Para modal interface post user authentication. You can open t he `ParaModal` at anytime in your application to allow users to interact with these payment features.
## Buy Crypto Configuration
Enable and configure crypto purchasing options for your users.
### Enable Buy Crypto
Toggle the buy crypto feature to allow users to purchase cryptocurrency directly through your application.
### Asset Selection
Choose which cryptocurrencies users can purchase:
* **All Available Assets**: Enable all supported cryptocurrencies
* **Custom Selection**: Limit to specific assets that match your application's needs
### Default Asset Configuration
Set the default cryptocurrency and amount that pre-populates when users initiate a purchase:
1. **Select Asset**: Choose from your enabled cryptocurrency list
2. **Default Amount**: Set a suggested purchase amount (e.g., \$50.00)
3. **Status**: Enable or disable the default asset feature
## Crypto Withdrawal (Offramp)
Allow users to sell cryptocurrency for fiat currency.
## Payment Provider Configuration
Configure which payment providers appear in your application's onramp interface.
Click and drag to reorder payment providers. The order determines which provider appears first in the user interface.
### Available Providers
* **Stripe**: Credit/debit card payments with global support
* **Ramp**: Comprehensive fiat onramp with bank transfers and cards
* **Moonpay**: Multi-currency support with global payment methods
### Provider Priority
Payment providers display in the order shown. Users will see enabled providers as options when purchasing cryptocurrency, with the first enabled provider typically appearing as the default.
### Integration Requirements
Each payment provider requires separate integration setup:
1. **Stripe**: Requires Stripe account and API keys
2. **Ramp**: Requires Ramp partnership and configuration
3. **Moonpay**: Requires Moonpay API access and compliance approval
Ramp requires a Ramp production api key. Learn more at
## Receive Funds Feature
Enable wallet address display and QR code generation for receiving cryptocurrency. When enabled, users can receive funds directly into their wallets by sharing their wallet addresses or QR codes.
## Next Steps
# Developer Portal Security Settings
Source: https://docs.getpara.com/v2/react/guides/customization/developer-portal-security
Configure authentication methods, session management, and transaction permissions
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
Configure security settings to control user authentication methods, session duration, and transaction permissions. These settings balance security with user experience for your Para integration.
## Authentication Methods
Configure which authentication methods your users can use to access their wallets.
This configuration does not affect Mobile SDK frameworks. Mobile SDKs use native mobile passkeys with an option to use passwords via Webviews.
### Passkeys
Enable passkey authentication for enhanced security and user experience:
* **Biometric Authentication**: Fingerprint, Face ID, or Windows Hello
* **Hardware Security Keys**: FIDO2-compatible security keys
* **Platform Authenticators**: Built-in device authenticators
### Passwords
Configure traditional password authentication:
* **Password Requirements**: Set complexity requirements
* **Recovery Options**: Enable password reset functionality
* **Multi-Factor Authentication**: Optional additional security layer
### PINs
Enable simple PIN-based authentication for quick access:
* **4 Digit Codes:** Users can create a short numeric code, familiar from mobile banking and device unlock screens
– **Flexibility:** Allow PINs as the primary method or alongside passkey/passwords so users can choose whatever feels easiest
– **Legacy Devices:** Provides a lightweight option on devices that don't support passkeys
You can enable both passkeys and passwords to give users choice:
* **Passkeys Preferred**: Passkeys will be suggested first during registration
* **Fallback Support**: Users can choose passwords if passkeys aren't available
If you're creating a PWA we recommend using passwords so that the user stays within the installed app. Passkeys will open a new browser tab.
## Session Management
Control how long users stay authenticated before requiring re-authentication.
### Security Considerations
**Shorter Sessions (2 Hours - 1 Day):**
* Enhanced security for sensitive applications
* Reduced risk if device is compromised
* Better for shared or public devices
**Longer Sessions (1 Week - 1 Month):**
* Improved user experience with fewer logins
* Better for personal devices and trusted environments
* Consider implementing automatic session refresh
### Custom Session Length
For custom durations:
1. Select "Custom" option
2. Enter duration in minutes
3. Consider your application's specific security needs
4. Balance security with user experience
## Transaction Permissions
Configure how users confirm transactions and manage permissions.
### Transaction Pop-ups
Control whether users see confirmation dialogs for transactions:
* **Enabled**: Users manually confirm each transaction via popup
* **Disabled**: Transactions proceed without additional confirmation
By default, transaction pop-ups are disabled allow for faster transaction signing. We recommend adding careful transaction validation in your application logic to ensure users are aware of the transactions they are signing.
# Developer Portal Setup
Source: https://docs.getpara.com/v2/react/guides/customization/developer-portal-setup
Configure your Para integration through the developer portal with environment settings, network configuration, and domain management.
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
Configure your Para integration through the developer portal at . This portal allows you to manage your application's settings, including environment configurations, supported networks, and security options.
## Environment Configuration
Set up your development environment to match your application's framework and package manager preferences. This will provide you with tailored integration examples and installation commands or visit the for a general overview.
### Framework Selection
Choose your primary framework to receive tailored integration examples:
* **React**: For React applications and Next.js projects
* **Vue**: For Vue.js applications and Nuxt projects
* **Svelte**: For Svelte and SvelteKit applications
* **React Native**: For mobile applications
* **Flutter**: For cross-platform mobile development
### Package Manager
Select your preferred package manager for installation commands:
* **npm**: Default Node.js package manager
* **yarn**: Alternative package manager with workspace support
* **pnpm**: Fast, disk space efficient package manager
## Network Configuration
Configure which blockchain networks your application supports and require users to connect.
This will configure which wallet options are available during user authentication. Your app will receive wallets for each required network.
### Available Networks
* **Ethereum (EVM)**: Includes Ethereum Layer 2 networks
* **Solana**: Solana blockchain network
* **Cosmos**: Cosmos ecosystem networks
### Network Requirements
Toggle "Required" for networks where users must connect at least one wallet of that type during login. This ensures users have the necessary wallet connections for your application's functionality.
## Domain Security
Configure allowed origins to secure your API requests and prevent unauthorized access.
This prevents unauthorized domains from making API requests to your Para integration. Ideal for production environments.
### Origin URLs
Add your application's domains to the allowed origins list:
```
www.yourapp.com, app.yourapp.com, localhost:3000
```
### Security Best Practices
* Add only necessary domains to minimize attack surface
* Include all environments (development, staging, production)
* Separate multiple domains with commas
* Use HTTPS in production environments
## Email Configuration
Configure email settings for user verification and communication.
Configure the theming of emails sent to your users on the page.
### Verification URL
Set the redirect URL displayed in verification emails that users receive. This should point to your application where users complete the authentication process.
### Email Types
Choose which emails Para sends to your users:
* **Welcome Email Only**: Send only welcome emails to new users
* **Welcome Email + Backup Kit**: Include backup kit instructions for new wallets
* **No Email**: Disable all automated emails (except OTP emails)
## Next Steps
# Modal Customization
Source: https://docs.getpara.com/v2/react/guides/customization/modal
Learn how to customize the appearance of the Para modal to match your application's design.
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
The Para Modal provides extensive customization options through the `paraModalConfig` prop passed to the `ParaProvider`. You can customize everything from colors and themes to authentication flows and security features.
## Basic Setup
Pass the `paraModalConfig` object to your `ParaProvider` to customize the modal:
```tsx
{children}
```
## Configuration Options
A full list of available configuration options for the `paraModalConfig` prop available on the `ParaProvider` component:
void",
required: false,
description: "Callback fired when the modal step changes"
},
{
name: "onClose",
type: "() => void",
required: false,
description: "Callback fired when the modal is closed"
},
{
name: "loginTransitionOverride",
type: "(para: ParaWeb) => Promise",
required: false,
description: "Custom login transition logic"
},
{
name: "createWalletOverride",
type: "(para: ParaWeb) => Promise<{recoverySecret?: string; walletIds: CurrentWalletIds}>",
required: false,
description: "Custom wallet creation logic"
}
]}
/>
## Logo Configuration
```tsx
paraModalConfig={{
logo: "https://yourdomain.com/logo.png"
}}
```
For optimal display, use a logo image with dimensions of 372px × 160px.
## Authentication Options
### OAuth Methods
```tsx
paraModalConfig={{
oAuthMethods: ["GOOGLE", "TWITTER", "DISCORD", "APPLE"]
}}
```
Available OAuth providers:
* `GOOGLE` - Google OAuth
* `TWITTER` - Twitter/X OAuth
* `APPLE` - Apple OAuth
* `DISCORD` - Discord OAuth
* `FACEBOOK` - Facebook OAuth
* `FARCASTER` - Farcaster OAuth
* `TELEGRAM` - Telegram OAuth
### Email and Phone Login
```tsx
paraModalConfig={{
disableEmailLogin: false,
disablePhoneLogin: true, // Only allow email and OAuth
oAuthMethods: ["GOOGLE", "TWITTER"]
}}
```
### Default Authentication Identifier
```tsx
paraModalConfig={{
defaultAuthIdentifier: "user@example.com" // or "+15555555555"
}}
```
Phone numbers should be in international format: `+15555555555`
## Authentication Layout
```tsx
paraModalConfig={{
authLayout: ["AUTH:CONDENSED", "EXTERNAL:FULL"]
}}
```
Available layout options:
* `AUTH:FULL` - Full authentication component
* `AUTH:CONDENSED` - Condensed authentication component
* `EXTERNAL:FULL` - Full external wallet component
* `EXTERNAL:CONDENSED` - Condensed external wallet component
Use our to visualize different layout configurations before implementing them.
## Step Override
```tsx
paraModalConfig={{
currentStepOverride: "ACCOUNT_MAIN" // or "account_main"
}}
```
Authentication Steps:
* `AUTH_MAIN` - Main authentication options
* `AUTH_MORE` - Additional authentication methods
* `AWAITING_OAUTH` - OAuth authentication in progress
* `VERIFICATIONS` - Email/phone verification
Wallet Creation Steps:
* `BIOMETRIC_CREATION` - Biometric setup
* `PASSWORD_CREATION` - Password creation
* `SECRET` - Recovery secret display
* `AWAITING_WALLET_CREATION` - Wallet creation in progress
Account Management Steps:
* `ACCOUNT_MAIN` - Main account view
* `ACCOUNT_PROFILE` - Profile management
* `CHAIN_SWITCH` - Network selection
External Wallet Steps:
* `EX_WALLET_MORE` - External wallet options
* `EX_WALLET_SELECTED` - Selected external wallet
Funds Management Steps:
* `ADD_FUNDS_BUY` - Buy crypto interface
* `ADD_FUNDS_RECEIVE` - Receive crypto interface
* `ADD_FUNDS_WITHDRAW` - Withdraw crypto interface
Security Steps:
* `SETUP_2FA` - Two-factor authentication setup
* `VERIFY_2FA` - Two-factor authentication verification
Setting an invalid step or a step that requires previous steps to be completed may cause unexpected behavior. Ensure the step override makes sense in your authentication flow.
## Security Features
### Two-Factor Authentication
### Recovery Secret
```tsx
paraModalConfig={{
twoFactorAuthEnabled: true,
recoverySecretStepEnabled: true
}}
```
## Guest Mode
```tsx
paraModalConfig={{
isGuestModeEnabled: true
}}
```
## Theme Configuration
### Basic Theme Example
```tsx
paraModalConfig={{
theme: {
foregroundColor: "#333333",
backgroundColor: "#FFFFFF",
accentColor: "#007AFF",
mode: "light",
borderRadius: "md",
font: "Arial, sans-serif"
}
}}
```
### Advanced Theme with Custom Palette
```tsx
paraModalConfig={{
theme: {
foregroundColor: "#333333",
backgroundColor: "#FFFFFF",
accentColor: "#007AFF",
mode: "light",
customPalette: {
text: {
primary: "#333333",
secondary: "#666666",
subtle: "#999999",
inverted: "#FFFFFF",
error: "#FF3B30"
},
modal: {
surface: {
main: "#FFFFFF",
footer: "#F2F2F7"
},
border: "#E5E5EA"
},
button: {
primary: {
background: "#007AFF",
hover: "#0056CC",
text: "#FFFFFF"
}
}
}
}
}}
```
Set the `mode` correctly based on your background color to ensure all components remain visible and accessible.
You can use custom fonts by importing them in your global CSS and specifying the font family in the `font` property.
## Account Linking
```tsx
paraModalConfig={{
supportedAccountLinks: [
"EMAIL",
"PHONE",
"GOOGLE",
"TWITTER",
"EXTERNAL_WALLET"
]
}}
```
## Event Callbacks
### Modal Step Changes
void",
required: false,
description: "Callback fired when users navigate between modal steps"
}
]}
/>
### Modal Close
void",
required: false,
description: "Callback fired when the modal is closed"
}
]}
/>
```tsx
paraModalConfig={{
onModalStepChange: (stepInfo) => {
console.log('Modal step changed:', stepInfo);
},
onClose: () => {
console.log('Modal closed');
}
}}
```
## Password & PIN Screen Theme Limitations
Password and PIN authentication screens are rendered in an iframe and use the Developer Portal theme settings, not your `paraModalConfig.theme`. This means:
* Theme colors may differ between the modal and password screens if configurations don't match
* Dynamic theme changes at runtime won't affect the iframe
* You must configure matching themes in both your code and the Developer Portal for consistency
## Advanced Configuration
### Custom Modal Behavior
### On-Ramp Configuration
## Complete Example
Here's a comprehensive example showcasing multiple configuration options:
```tsx
{
console.log('Step changed:', stepInfo);
},
onClose: () => {
console.log('Modal closed');
}
}}
>
{children}
```
## Examples and Tools
Test your modal configuration with our interactive tools:
## Next Steps
Now that you've configured your Para modal, explore additional customization options:
# React Hooks
Source: https://docs.getpara.com/v2/react/guides/hooks
State management and SDK interactions using Para's React hooks
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Para's React hooks provide an intuitive way to manage wallet state, handle transactions, and interact with the Para SDK. These hooks are built on top of TanStack Query (React Query) for efficient data fetching and state management.
## Prerequisites
Before using Para's React hooks, ensure you have:
1. Set up the Para Modal in your application following one of our framework integration guides
2. Wrapped your application with the `ParaProvider`
3. Installed the required dependencies:
```bash
npm install @getpara/react-sdk@alpha @tanstack/react-query --save-exact
```
## Provider Setup
To use Para's React hooks, wrap your application with `ParaProvider`:
```tsx
import { ParaProvider, ParaModal } from "@getpara/react-sdk@alpha";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const queryClient = new QueryClient();
function App() {
return (
);
}
```
If you're using a legacy API key (one without an environment prefix) you must provide a value to the `paraClientConfig.environment`. You can retrieve your updated API key from the Para Developer Portal at [https://developer.getpara.com/](https://developer.getpara.com/)
## Quick Example
Here's a simple example using multiple hooks together:
```tsx
import { useAccount, useWallet, useSignMessage, useModal } from "@getpara/react-sdk@alpha";
function WalletComponent() {
const account = useAccount();
const { data: wallet } = useWallet();
const { signMessageAsync } = useSignMessage();
const { openModal } = useModal();
const handleSign = async () => {
if (!wallet) return;
const result = await signMessageAsync({
messageBase64: Buffer.from("Hello Para!").toString("base64"),
});
console.log("Signature:", result.signature);
};
return (
{account?.isConnected ? (
Sign Message
) : (
Connect Wallet
)}
);
}
```
## Hooks
#### Authentication
#### Wallet Operations
#### Session Management
#### Utility Hooks
Utility hooks provide access to core functionality without React Query:
# ParaProvider
Source: https://docs.getpara.com/v2/react/guides/hooks/para-provider
React context provider for Para SDK integration
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
The `ParaProvider` component wraps your React application to provide access to Para hooks and manage the SDK instance.
## Import
```tsx
import { ParaProvider } from "@getpara/react-sdk@alpha";
```
## Usage
```tsx
import { ParaProvider, ParaModal } from "@getpara/react-sdk@alpha";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const queryClient = new QueryClient();
function App() {
return (
);
}
```
## Advanced Usage
### With Event Callbacks
```tsx
function AppWithCallbacks() {
return (
{
console.log("User logged in:", event.detail.data);
navigate("/dashboard");
},
onLogout: (event) => {
console.log("User logged out");
clearUserData();
navigate("/");
},
onWalletCreated: (event) => {
console.log("New wallet:", event.detail.data);
toast.success("Wallet created successfully!");
},
onSignMessage: (event) => {
console.log("Message signed:", event.detail.data);
analytics.track("message_signed", {
walletType: event.detail.data.walletType
});
}
}}>
);
}
```
### With Custom Para Instance
This can be useful if you need to use the Para instance outside of the React tree, i.e. in the callbacks on the ParaProvider.
```tsx
function AppWithCustomClient() {
const paraClient = useMemo(() => {
return new ParaWeb("your-api-key", {
debugMode: true,
customHeaders: {
"X-Custom-Header": "value"
}
});
}, []);
return (
);
}
```
## Notes
* The `ParaProvider` must wrap any components that use Para hooks
* It requires `QueryClientProvider` from React Query as a parent
* The `ParaModal` component should be placed inside the provider
* Event callbacks receive events with a `detail` property containing `data` and optional `error`
* The provider automatically manages session keep-alive unless disabled
* All child components can access Para hooks without additional setup
# useAccount
Source: https://docs.getpara.com/v2/react/guides/hooks/use-account
Hook for retrieving the current embedded account and connected external wallets
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
The `useAccount` hook provides access to the current user's account state, including both embedded Para accounts and connected external wallets across EVM, Cosmos, and Solana chains.
## Import
```tsx
import { useAccount } from "@getpara/react-sdk@alpha";
```
## Usage
```tsx
function AccountInfo() {
const account = useAccount();
if (account.isLoading) return Loading account...
;
if (!account.isConnected) {
return Not connected
;
}
return (
Connection Type: {account.connectionType}
{account.embedded.isConnected && (
Embedded Account
User ID: {account.embedded.userId}
Auth Type: {account.embedded.authType}
Email: {account.embedded.email}
Wallets: {account.embedded.wallets?.length || 0}
)}
{account.external.connectedNetworks.length > 0 && (
External Wallets
Connected Networks: {account.external.connectedNetworks.join(', ')}
{account.external.evm.isConnected && (
EVM Address: {account.external.evm.address}
)}
{account.external.cosmos.isConnected && (
Cosmos Connected
)}
{account.external.solana.isConnected && (
Solana Public Key: {account.external.solana.publicKey?.toString()}
)}
)}
);
}
```
## Return Value Structure
The hook returns a `UseAccountReturn` object with the following properties:
### Top-Level Properties
* `isConnected: boolean` - Whether there is a wallet connected (either embedded, external or both)
* `isLoading: boolean` - Whether the account is currently loading
* `connectionType: 'embedded' | 'external' | 'both' | 'none'` - The type of connection for the account
* `'embedded'` - Only the embedded account is connected
* `'external'` - Only an external wallet is connected
* `'both'` - Both embedded and external wallets are connected
* `'none'` - No wallets are connected
### Embedded Account Properties
`embedded` object contains:
* `isConnected: boolean` - Whether the embedded Para account is connected
* `isGuestMode?: boolean` - Whether the user is in guest mode
* `userId?: string` - Unique identifier for the user
* `authType?: 'email' | 'phone' | 'farcaster' | 'telegram' | 'externalWallet'` - Authentication method used
* `email?: string` - User's email address (only if authType is 'email')
* `phone?: string` - User's phone number (only if authType is 'phone')
* `farcasterUsername?: string` - Farcaster username (only if authType is 'farcaster')
* `telegramUserId?: string` - Telegram user ID (only if authType is 'telegram')
* `externalWalletAddress?: string` - External wallet address (only if authType is 'externalWallet')
* `wallets?: Array` - Array of available wallets for the user
### External Wallet Properties
`external` object contains:
* `connectedNetworks: Array<'evm' | 'cosmos' | 'solana'>` - List of connected external networks
* `evm` - EVM wallet connection data (if connected)
* `isConnected: boolean`
* `address?: string`
* `addresses?: string[]`
* `chain?: Chain`
* `chainId?: number`
* `status: 'connected' | 'reconnecting' | 'connecting' | 'disconnected'`
* `cosmos` - Cosmos wallet connection data (if connected)
* `isConnected: boolean`
* Additional Cosmos-specific properties
* `solana` - Solana wallet adapter data (if connected)
* `isConnected: boolean`
* `isConnecting?: boolean`
* `publicKey?: PublicKey`
* `name?: string`
* `icon?: string`
## Examples
### Basic Connection Check
```tsx
function ConnectionStatus() {
const { isConnected, connectionType } = useAccount();
return (
Connected: {isConnected ? 'Yes' : 'No'}
Connection Type: {connectionType}
);
}
```
### Accessing Embedded Wallet Address
```tsx
function WalletAddress() {
const account = useAccount();
if (!account.isConnected || !account.embedded.wallets?.length) {
return No wallet connected
;
}
return (
Address: {account.embedded.wallets[0].address}
);
}
```
### Working with External Wallets
```tsx
function ExternalWalletInfo() {
const { external } = useAccount();
return (
{external.evm.isConnected && (
EVM Address: {external.evm.address}
)}
{external.cosmos.isConnected && (
Cosmos wallet connected
)}
{external.solana.isConnected && (
Solana: {external.solana.name}
)}
);
}
```
### Complete Connect Wallet Component
```tsx
function ConnectWallet() {
const { openConnectModal, openWalletModal } = useModal();
const account = useAccount();
if (account.isConnected && account.embedded.wallets?.length) {
return (
{account.embedded.wallets[0].address.slice(0, 6)}...{account.embedded.wallets[0].address.slice(-4)}
);
}
return (
Connect Wallet
);
}
```
## Notes
* The hook automatically refetches when the user's authentication state changes
* Use `isLoading` to show loading states while fetching account data
* The `embedded` account refers to Para's native wallet system
* External wallets are third-party wallets connected via standard wallet connectors
* When both embedded and external wallets are connected, `connectionType` will be `'both'`
# useClient
Source: https://docs.getpara.com/v2/react/guides/hooks/use-client
Hook for accessing the Para client instance
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
The `useClient` hook provides direct access to the Para client instance, allowing you to call any method available on the Para SDK.
## Import
```tsx
import { useClient } from "@getpara/react-sdk@alpha";
```
## Usage
```tsx
function ClientExample() {
const para = useClient();
const { data: wallet } = useWallet();
const getFormattedAddress = () => {
if (!para || !wallet) return "No wallet";
return para.getDisplayAddress(wallet.id, {
truncate: true,
addressType: wallet.type
});
};
const checkSessionStatus = async () => {
if (!para) return;
const isActive = await para.isSessionActive();
console.log("Session active:", isActive);
};
return (
Address: {getFormattedAddress()}
Check Session
);
}
```
## Parameters
This hook does not accept any parameters.
## Return Type
## Available Methods
When you have the Para client instance, you can access all SDK methods including:
* `getDisplayAddress()` - Format wallet addresses
* `isSessionActive()` - Check session status
* `exportSession()` - Export session for server-side use
* `findWallet()` - Find a specific wallet
* `getUserId()` - Get the current user ID
* And many more...
## Example: Advanced Usage
```tsx
function AdvancedClientUsage() {
const para = useClient();
const [sessionInfo, setSessionInfo] = useState("");
const exportCurrentSession = () => {
if (!para) return;
// Export session without signers for security
const session = para.exportSession({ excludeSigners: true });
setSessionInfo(session);
};
const checkUserDetails = async () => {
if (!para) return;
const userId = para.getUserId();
const authInfo = para.authInfo;
console.log("User ID:", userId);
console.log("Auth Info:", authInfo);
};
return (
Export Session
Check User Details
{sessionInfo &&
Session: {sessionInfo.substring(0, 50)}...
}
);
}
```
## Notes
* The client is undefined until the `ParaProvider` is fully initialized
* Always check if the client exists before using it
* The client instance is the same one passed to the `ParaProvider`
# useCosmjsAminoSigner
Source: https://docs.getpara.com/v2/react/guides/hooks/use-cosmjs-amino-signer
Hook for retrieving a Cosmjs Amino signer for a Para wallet
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
The `useCosmjsAminoSigner` hook provides a Cosmjs Amino signer for a Para wallet.
## Import
```tsx
import { useCosmjsAminoSigner } from "@getpara/react-sdk";
```
## Usage
```tsx
function CosmjsAminoSigner() {
const { aminoSigner, isLoading } = useCosmjsAminoSigner();
const handleSign = async () => {
if (!aminoSigner) {
return;
}
// Create a simple sign doc for the message
const signDoc = {
bodyBytes: new TextEncoder().encode(
JSON.stringify({
messages: [],
memo: "Test Message",
})
),
authInfoBytes: new Uint8Array(0),
chainId: "",
accountNumber: BigInt(0),
};
const result = await aminoSigner.signAmino(aminoSigner.address, signDoc);
console.log("Signature:", result.signature.signature);
};
if (isLoading) return Loading Cosmjs Amino signer...
;
return (
Address: {aminoSigner?.address}
Sign Message
);
}
```
## Return Type
The hook returns a `useCosmjsAminoSigner` object with the following properties:
# useCosmjsProtoSigner
Source: https://docs.getpara.com/v2/react/guides/hooks/use-cosmjs-proto-signer
Hook for retrieving a Cosmjs Proto signer for a Para wallet
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
The `useCosmjsProtoSigner` hook provides a Cosmjs Proto signer for a Para wallet.
## Import
```tsx
import { useCosmjsProtoSigner } from "@getpara/react-sdk";
```
## Usage
```tsx
function CosmjsProtoSigner() {
const { protoSigner, isLoading } = useCosmjsProtoSigner();
const handleSign = async () => {
if (!protoSigner) {
return;
}
// Create a simple sign doc for the message
const signDoc = {
bodyBytes: new TextEncoder().encode(
JSON.stringify({
messages: [],
memo: "Test Message",
})
),
authInfoBytes: new Uint8Array(0),
chainId: "",
accountNumber: BigInt(0),
};
const result = await protoSigner.signDirect(protoSigner.address, signDoc);
console.log("Signature:", result.signature.signature);
};
if (isLoading) return Loading Cosmjs Proto signer...
;
return (
Address: {protoSigner?.address}
Sign Message
);
}
```
## Return Type
The hook returns a `UseCosmjsProtoSignerReturn` object with the following properties:
# useCreateWallet
Source: https://docs.getpara.com/v2/react/guides/hooks/use-create-wallet
Hook for creating new wallets for the authenticated user
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
The `useCreateWallet` hook provides functionality to create new blockchain wallets for the authenticated user.
## Import
```tsx
import { useCreateWallet } from "@getpara/react-sdk@alpha";
```
## Usage
```tsx
function WalletCreator() {
const { createWallet, createWalletAsync, isPending, error } = useCreateWallet();
const { refetch: refetchAccount } = useAccount();
const handleCreateWallet = async () => {
try {
const result = await createWalletAsync({
wallets: [
{ type: "EVM" },
{ type: "SOLANA" }
]
});
console.log("Created wallets:", result.wallets);
await refetchAccount();
} catch (err) {
console.error("Failed to create wallets:", err);
}
};
return (
{isPending ? "Creating..." : "Create EVM & Solana Wallets"}
);
}
```
",
description: "React Query mutation result with createWallet/createWalletAsync functions, loading state, error information, and success data"
}}
async={true}
/>
## Parameters for createWallet/createWalletAsync
The mutation functions accept a `CreateWalletParams` object with the following structure:
```typescript
interface CreateWalletParams {
wallets: WalletCreationSpec[];
}
interface WalletCreationSpec {
type: 'EVM' | 'SOLANA' | 'COSMOS';
}
```
## Response Structure
When successful, the mutation returns a `CreateWalletResponse` object:
```typescript
interface CreateWalletResponse {
wallets: Wallet[];
}
interface Wallet {
id: string;
type: 'EVM' | 'SOLANA' | 'COSMOS';
address: string;
}
```
## Example: Conditional Wallet Creation
```tsx
function ConditionalWalletCreator() {
const { createWalletAsync } = useCreateWallet();
const { data: account } = useAccount();
const [walletType, setWalletType] = useState("EVM");
const createWalletIfNeeded = async () => {
if (!account?.isConnected) return;
const hasWalletType = account.wallets.some(w => w.type === walletType);
if (hasWalletType) {
console.log(`User already has ${walletType} wallet`);
return;
}
try {
const result = await createWalletAsync({
wallets: [{ type: walletType }]
});
console.log(`Created ${walletType} wallet:`, result.wallets[0]);
} catch (err) {
console.error("Wallet creation failed:", err);
}
};
return (
setWalletType(e.target.value as TWalletType)}
>
EVM
Solana
Cosmos
Create {walletType} Wallet
);
}
```
## Events
The wallet creation process triggers a `WalletCreatedEvent` that can be listened to via the `ParaProvider` callbacks:
```tsx
{
console.log("New wallet created:", event.detail);
}
}}
>
{/* Your app */}
```
## Notes
* This hook requires the user to be authenticated before creating wallets
* The hook automatically invalidates account queries on success to refresh wallet lists
* Multiple wallets can be created in a single mutation by passing multiple specifications
* Each wallet type (EVM, SOLANA, COSMOS) can only be created once per user
# useIssueJwt
Source: https://docs.getpara.com/v2/react/guides/hooks/use-issue-jwt
Hook for issuing JWT tokens for session verification
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
The `useIssueJwt` hook provides functionality to request Para JWT tokens that contain attestations for the user's ID, identity, and provisioned wallets.
## Import
```tsx
import { useIssueJwt } from "@getpara/react-sdk@alpha";
```
## Usage
```tsx
function JwtTokenManager() {
const { issueJwt, issueJwtAsync, isPending, error } = useIssueJwt();
const [tokenInfo, setTokenInfo] = useState<{ token: string; keyId: string } | null>(null);
const handleIssueToken = async () => {
try {
const result = await issueJwtAsync();
setTokenInfo({
token: result.token,
keyId: result.keyId
});
await sendTokenToBackend(result.token);
} catch (err) {
console.error("Failed to issue JWT:", err);
}
};
return (
{isPending ? "Issuing..." : "Issue JWT Token"}
);
}
```
",
description: "React Query mutation result with issueJwt/issueJwtAsync functions, loading state, error information, and JWT token data on success"
}}
async={true}
/>
# useKeepSessionAlive
Source: https://docs.getpara.com/v2/react/guides/hooks/use-keep-session-alive
Hook for maintaining active user sessions
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
The `useKeepSessionAlive` hook provides functionality to extend the current user session without requiring re-authentication.
## Import
```tsx
import { useKeepSessionAlive } from "@getpara/react-sdk@alpha";
```
## Usage
```tsx
function SessionManager() {
const { keepSessionAlive, keepSessionAliveAsync, isPending } = useKeepSessionAlive();
const [lastRefresh, setLastRefresh] = useState(null);
const handleKeepAlive = async () => {
try {
const success = await keepSessionAliveAsync();
if (success) {
setLastRefresh(new Date());
console.log("Session extended successfully");
}
} catch (err) {
console.error("Session extension error:", err);
}
};
return (
{isPending ? "Extending..." : "Extend Session"}
);
}
```
",
description: "React Query mutation result with keepSessionAlive/keepSessionAliveAsync functions, loading state, error information, and boolean success status"
}}
async={true}
/>
# useLogout
Source: https://docs.getpara.com/v2/react/guides/hooks/use-logout
Hook for logging out the current user
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
The `useLogout` hook provides functionality to log out the current user and optionally clear pregenerated wallets.
## Import
```tsx
import { useLogout } from "@getpara/react-sdk@alpha";
```
## Usage
```tsx
function LogoutButton() {
const { logout, logoutAsync, isPending } = useLogout();
const { data: account } = useAccount();
const handleLogout = async () => {
try {
await logoutAsync({
clearPregenWallets: false // Keep pregenerated wallets
});
console.log("Successfully logged out");
} catch (err) {
console.error("Logout failed:", err);
}
};
if (!account?.isConnected) {
return null;
}
return (
{isPending ? "Logging out..." : "Logout"}
);
}
```
",
description: "React Query mutation result with logout/logoutAsync functions, loading state, error information, and void return on success"
}}
async={true}
/>
# useModal
Source: https://docs.getpara.com/v2/react/guides/hooks/use-modal
Hook for controlling the Para modal
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
The `useModal` hook provides methods to control the Para modal's visibility. This is useful for programmatically opening the modal for authentication or wallet management.
## Import
```tsx
import { useModal } from "@getpara/react-sdk@alpha";
```
## Usage
```tsx
function ModalControl() {
const { isOpen, openModal, closeModal } = useModal();
const { data: account } = useAccount();
return (
{account?.isConnected ? "Manage Wallet" : "Connect Wallet"}
{isOpen && (
Modal is currently open
Close Modal
)}
);
}
```
## Parameters
This hook does not accept any parameters.
## Return Type
## Example: Conditional Modal Control
```tsx
function ConditionalModalExample() {
const { openModal } = useModal();
const { data: account } = useAccount();
const { data: wallet } = useWallet();
const handleAction = () => {
if (!account?.isConnected) {
// Open modal for authentication
openModal();
} else if (!wallet) {
// Open modal to select/create wallet
openModal();
} else {
// User is ready, perform action
console.log("Ready to perform action with wallet:", wallet.id);
}
};
return (
Perform Action
);
}
```
## Example: Auto-open on Mount
```tsx
function AutoOpenModal() {
const { openModal } = useModal();
const { data: account } = useAccount();
useEffect(() => {
// Automatically open modal if user is not connected
if (account && !account.isConnected) {
openModal();
}
}, [account, openModal]);
return Welcome to our app!
;
}
```
## Notes
* The modal component (` `) must be rendered within the `ParaProvider` for this hook to work
* Opening the modal when a user is not connected will show the authentication flow
* Opening the modal when a user is connected will show wallet management options
* The modal can be closed by the user clicking outside or using the close button
# useSignMessage
Source: https://docs.getpara.com/v2/react/guides/hooks/use-sign-message
Hook for signing messages with a wallet
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
The `useSignMessage` hook provides functionality to sign arbitrary messages with the user's wallet.
## Import
```tsx
import { useSignMessage } from "@getpara/react-sdk@alpha";
```
## Usage
```tsx
function MessageSigner() {
const { signMessage, signMessageAsync, isPending, error } = useSignMessage();
const [message, setMessage] = useState("");
const [signature, setSignature] = useState("");
const handleSign = async () => {
try {
const result = await signMessageAsync({
messageBase64: Buffer.from(message).toString("base64"),
});
if ("signature" in result) {
setSignature(result.signature);
}
} catch (err) {
console.error("Failed to sign message:", err);
}
};
return (
setMessage(e.target.value)}
placeholder="Enter message to sign"
/>
{isPending ? "Signing..." : "Sign Message"}
{signature &&
Signature: {signature}
}
);
}
```
",
description: "React Query mutation result with signMessage/signMessageAsync functions, loading state, error information, and signature data on success"
}}
async={true}
/>
# useSignTransaction
Source: https://docs.getpara.com/v2/react/guides/hooks/use-sign-transaction
Hook for signing blockchain transactions
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
The `useSignTransaction` hook provides functionality to sign blockchain transactions with the user's wallet.
## Import
```tsx
import { useSignTransaction } from "@getpara/react-sdk@alpha";
```
## Usage
```tsx
function TransactionSigner() {
const { signTransactionAsync, isPending, error } = useSignTransaction();
const handleSignTransaction = async () => {
try {
const tx = {
to: "0x742d35Cc6634C0532925a3b844Bc9e7595f6E123",
value: "0x2386f26fc10000", // 0.01 ETH in wei
gasLimit: "0x5208", // 21000
gasPrice: "0x09184e72a000", // 10000000000000
};
const rlpEncoded = encodeTransaction(tx); // Your encoding logic
const result = await signTransactionAsync({
rlpEncodedTxBase64: Buffer.from(rlpEncoded).toString("base64"),
});
if ("signature" in result) {
console.log("Transaction signed:", result.signature);
}
} catch (err) {
console.error("Failed to sign transaction:", err);
}
};
return (
{isPending ? "Signing..." : "Sign Transaction"}
);
}
```
",
description: "React Query mutation result with signTransaction/signTransactionAsync functions, loading state, error information, and signature data on success"
}}
async={true}
/>
# useSignUpOrLogIn
Source: https://docs.getpara.com/v2/react/guides/hooks/use-sign-up-or-login
Hook for initiating the authentication flow
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
The `useSignUpOrLogIn` hook initiates the authentication flow for new or existing users, handling both sign-up and login scenarios automatically.
## Import
```tsx
import { useSignUpOrLogIn } from "@getpara/react-sdk@alpha";
```
## Usage
```tsx
function AuthenticationFlow() {
const { signUpOrLogIn, signUpOrLogInAsync, isPending, error } = useSignUpOrLogIn();
const [email, setEmail] = useState("");
const handleAuth = async () => {
try {
const result = await signUpOrLogInAsync({
email,
isGuestMode: false
});
console.log("Authentication initiated:", result);
} catch (err) {
console.error("Authentication failed:", err);
}
};
return (
setEmail(e.target.value)}
placeholder="Enter your email"
/>
{isPending ? "Processing..." : "Sign Up / Log In"}
);
}
```
",
description: "React Query mutation result with signUpOrLogIn/signUpOrLogInAsync functions, loading state, error information, and authentication response data on success"
}}
async={true}
/>
# useSolanaSigner
Source: https://docs.getpara.com/v2/react/guides/hooks/use-solana-signer
Hook for retrieving a Solana signer for a Para wallet
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
The `useSolanaSigner` hook provides a Solana signer for a Para wallet.
## Import
```tsx
import { useSolanaSigner } from "@getpara/react-sdk";
import { createSolanaRpc } from "@solana/kit";
```
## Usage
```tsx
const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");
function SolanaSigner() {
const { solanaSigner, isLoading } = useSolanaSigner({ rpc });
const handleSign = async () => {
if (!solanaSigner) {
return;
}
// Convert message to bytes
const messageBytes = new Uint8Array(
getUtf8Encoder().encode("Test Message")
);
// Sign the message
const signatureResult = await solanaSigner.signMessages([
{ content: messageBytes, signatures: {} },
]);
// Get the signature
const signatureBytes = signatureResult[0][solanaSigner.address];
const signatureBase58 = bs58.encode(signatureBytes);
console.log("Signature:", signatureBase58);
};
if (isLoading) return Loading Solana signer...
;
return (
Address: {solanaSigner?.address}
Sign Message
);
}
```
## Return Type
The hook returns a `UseSolanaSignerReturn` object with the following properties:
# useVerifyNewAccount
Source: https://docs.getpara.com/v2/react/guides/hooks/use-verify-new-account
Hook for verifying new accounts with verification codes
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
The `useVerifyNewAccount` hook completes the account verification process after initiating authentication with email or phone number.
## Import
```tsx
import { useVerifyNewAccount } from "@getpara/react-sdk@alpha";
```
## Usage
```tsx
function VerificationFlow() {
const { verifyNewAccount, verifyNewAccountAsync, isPending, error } = useVerifyNewAccount();
const [verificationCode, setVerificationCode] = useState("");
const [identifier, setIdentifier] = useState(""); // email or phone
const handleVerification = async () => {
try {
const result = await verifyNewAccountAsync({
identifier,
verificationCode
});
console.log("Account verified successfully");
} catch (err) {
console.error("Verification failed:", err);
}
};
return (
setIdentifier(e.target.value)}
placeholder="Email or phone used for signup"
/>
setVerificationCode(e.target.value)}
placeholder="Enter verification code"
maxLength={6}
/>
{isPending ? "Verifying..." : "Verify Account"}
);
}
```
",
description: "React Query mutation result with verifyNewAccount/verifyNewAccountAsync functions, loading state, error information, and verification response data on success"
}}
async={true}
/>
# useViemAccount
Source: https://docs.getpara.com/v2/react/guides/hooks/use-viem-account
Hook for retrieving a Viem account for a Para wallet
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
The `useViemAccount` hook provides a Viem account for a Para wallet.
## Import
```tsx
import { useViemAccount } from "@getpara/react-sdk";
```
## Usage
```tsx
function ViemAccount() {
const { viemAccount, isLoading } = useViemAccount();
if (isLoading) return Loading viem account...
;
return (
Address: {viemAccount.address}
);
}
```
## Return Type
The hook returns a `UseViemAccountReturn` object with the following properties:
# useViemClient
Source: https://docs.getpara.com/v2/react/guides/hooks/use-viem-client
Hook for retrieving a Viem client for a Viem client for a Para wallet
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
The `useViemClient` hook provides a Viem account for a Para wallet.
## Import
```tsx
import { useViemClient } from "@getpara/react-sdk";
```
## Usage
```tsx
function ViemClient() {
const { viemClient, isLoading } = useViemClient({
walletClientConfig: {
chain: sepolia,
transport: http("https://ethereum-sepolia-rpc.publicnode.com"),
},
});
const handleSign = async () => {
if (!viemClient) {
return;
}
const signatureRes = await viemClient.signMessage({
message: "Test Message",
});
console.log("Signature:", signatureRes);
};
if (isLoading) return Loading viem client...
;
return (
Address: {viemClient?.address}
Sign Message
);
}
```
## Return Type
The hook returns a `UseViemClientReturn` object with the following properties:
# useWallet
Source: https://docs.getpara.com/v2/react/guides/hooks/use-wallet
Hook for retrieving the currently selected wallet
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
The `useWallet` hook provides access to the currently selected wallet's information.
## Import
```tsx
import { useWallet } from "@getpara/react-sdk@alpha";
```
## Usage
```tsx
function WalletInfo() {
const { data: wallet, isLoading, error } = useWallet();
const para = useClient();
if (isLoading) return Loading wallet...
;
if (error) return Error loading wallet
;
if (!wallet) {
return No wallet selected
;
}
return (
Wallet ID: {wallet.id}
Type: {wallet.type}
Address: {para.getDisplayAddress(wallet.id, {
truncate: true,
addressType: wallet.type
})}
Is External: {wallet.isExternal ? "Yes" : "No"}
);
}
```
",
description: "React Query result object containing wallet data when available, loading state, error information, and refetch function"
}}
async={true}
/>
# useWalletBalance
Source: https://docs.getpara.com/v2/react/guides/hooks/use-wallet-balance
Hook for retrieving the balance of the selected wallet
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
The `useWalletBalance` hook fetches the current balance of the selected wallet, supporting both Para-managed wallets and external wallets.
## Import
```tsx
import { useWalletBalance } from "@getpara/react-sdk@alpha";
```
## Usage
```tsx
function WalletBalance() {
const { data: balance, isLoading, error } = useWalletBalance();
if (isLoading) return Loading balance...
;
if (error) return Error loading balance
;
if (!balance) {
return No balance available
;
}
return (
);
}
```
",
optional: true,
description: "Optional parameters including custom RPC URL and wallet ID selection"
}
]}
returns={{
type: "UseQueryResult",
description: "React Query result object containing wallet balance as string, loading state, error information, and refetch function"
}}
async={true}
/>
# useWalletState
Source: https://docs.getpara.com/v2/react/guides/hooks/use-wallet-state
Hook for managing the currently selected wallet
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
The `useWalletState` hook provides methods to get and set the currently selected wallet, which is used as the default for signing operations.
## Import
```tsx
import { useWalletState } from "@getpara/react-sdk@alpha";
```
## Usage
```tsx
function WalletSelector() {
const { selectedWallet, setSelectedWallet, updateSelectedWallet } = useWalletState();
const { data: account } = useAccount();
const handleWalletChange = (walletId: string, walletType: TWalletType) => {
setSelectedWallet({ id: walletId, type: walletType });
};
return (
Current Wallet ID: {selectedWallet.id || "None"}
Current Wallet Type: {selectedWallet.type || "None"}
{account?.wallets.map((wallet) => (
handleWalletChange(wallet.id, wallet.type)}
style={{
fontWeight: selectedWallet.id === wallet.id ? "bold" : "normal"
}}
>
Select {wallet.type} Wallet
))}
);
}
```
# Reown AppKit Integration
Source: https://docs.getpara.com/v2/react/guides/reown-appkit
Integrate Para as the wallet provider in Reown AppKit
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Use Para as the exclusive wallet provider in (formerly WalletConnect Web3Modal). This integration provides a polished wallet connection UI with Para handling all authentication.
This guide uses Para as the only wallet option in AppKit. For a simpler integration with multiple wallets, see the external wallets guide.
## Prerequisites
Before integrating with Reown AppKit, ensure you have a Para account and project ID from Reown.
## Installation
Install Para's Wagmi integration and Reown AppKit:
```bash npm
npm install @getpara/wagmi-v2-integration@alpha @reown/appkit @reown/appkit-adapter-wagmi wagmi viem @tanstack/react-query --save-exact
```
```bash yarn
yarn add @getpara/wagmi-v2-integration@alpha @reown/appkit @reown/appkit-adapter-wagmi wagmi viem @tanstack/react-query --exact
```
```bash pnpm
pnpm add @getpara/wagmi-v2-integration@alpha @reown/appkit @reown/appkit-adapter-wagmi wagmi viem @tanstack/react-query --save-exact
```
```bash bun
bun add @getpara/wagmi-v2-integration@alpha @reown/appkit @reown/appkit-adapter-wagmi wagmi viem @tanstack/react-query --exact
```
## Configuration
Create the AppKit configuration with Para as the sole connector:
```typescript appkit.config.ts
import { createAppKit } from "@reown/appkit/react";
import { WagmiAdapter } from "@reown/appkit-adapter-wagmi";
import { paraConnector } from "@getpara/wagmi-v2-integration";
import { mainnet, polygon, arbitrum } from "@reown/appkit/networks";
import Para from "@getpara/web-sdk";
import { QueryClient } from "@tanstack/react-query";
// Initialize clients
const para = new Para("YOUR_PARA_API_KEY");
const queryClient = new QueryClient();
// Configure chains
const chains = [mainnet, polygon, arbitrum] as const;
// Create Para connector
const connector = paraConnector({
para,
chains: [...chains],
appName: "Your App Name"
});
// Setup Wagmi adapter
const wagmiAdapter = new WagmiAdapter({
networks: [...chains],
projectId: "YOUR_REOWN_PROJECT_ID",
connectors: [connector]
});
// Create AppKit instance
export const appKit = createAppKit({
adapters: [wagmiAdapter],
networks: [...chains],
projectId: "YOUR_REOWN_PROJECT_ID",
metadata: {
name: "Your App Name",
description: "Your app description",
url: "https://yourapp.com",
icons: ["https://yourapp.com/icon.png"]
},
features: {
analytics: true,
email: false, // Para handles auth
socials: false, // Para handles socials
},
allWallets: "HIDE" // Only show Para
});
export { wagmiAdapter };
```
## Provider Setup
Wrap your app with the necessary providers:
```tsx app.tsx
import { WagmiProvider } from "wagmi";
import { QueryClientProvider } from "@tanstack/react-query";
import { wagmiAdapter } from "./appkit.config";
const queryClient = new QueryClient();
function App() {
return (
{/* Your app */}
);
}
```
## Using AppKit
Open the connection modal using AppKit hooks:
```tsx connect-button.tsx
import { useAppKit } from "@reown/appkit/react";
function ConnectButton() {
const { open } = useAppKit();
return (
open()}>
Connect Wallet
);
}
```
## Configuration Options
Key configuration options for the Para + AppKit integration:
```typescript
const connector = paraConnector({
para, // Your Para instance
chains, // Supported chains
appName: "Your App Name", // Display name
queryClient, // TanStack Query client
oAuthMethods: ["GOOGLE", "TWITTER"], // Social login options
disableEmailLogin: false, // Enable email auth
disablePhoneLogin: false, // Enable phone auth
});
```
## Next Steps
# JWT Token Management
Source: https://docs.getpara.com/v2/react/guides/sessions-jwt
Issuing and verifying JWT tokens for Para session attestation
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
Once a user is signed in, you can request a Para JWT token. This token will provide attestations for the user's ID, their identity, and any wallets they have provisioned via your application.
## Requesting a JWT Token
You can request a JWT token using either the client method or the React hook. Both approaches return the token itself as well as the JWKS key ID (`kid`) for the keypair that signed it.
### Client Method
```typescript TypeScript
import { ParaWeb } from '@getpara/web-sdk';
const para = new ParaWeb('your-api-key');
const { token, keyId } = await para.issueJwt();
```
```tsx React Hook
import { useIssueJwt } from '@getpara/react-sdk';
function JwtTokenManager() {
const { issueJwt, issueJwtAsync, isPending, error } = useIssueJwt();
const [tokenInfo, setTokenInfo] = useState<{ token: string; keyId: string } | null>(null);
const handleIssueToken = async () => {
try {
const result = await issueJwtAsync();
setTokenInfo({
token: result.token,
keyId: result.keyId
});
await sendTokenToBackend(result.token);
} catch (err) {
console.error("Failed to issue JWT:", err);
}
};
return (
{isPending ? "Issuing..." : "Issue JWT Token"}
);
}
```
### React Hook
",
description: "React Query mutation result with issueJwt/issueJwtAsync functions, loading state, error information, and JWT token data on success"
}}
async={true}
/>
The token's expiry will be determined by your customized session length, or else will default to 30 minutes. Issuing a token, like most authenticated API operations, will also renew and extend the session for that duration.
## Token Structure
Depending on the user in question, a decoded token payload might resemble the following:
```json Email
{
"data": {
"userId": "d5358219-38d3-4650-91a8-e338131d1c5e",
"wallets": [
{
"id": "de4034f1-6b0f-4a98-87a5-e459db4d3a03",
"type": "EVM",
"address": "0x9dd3824f045c77bc369485e8f1dd6b452b6be617",
"publicKey": "0x0465434f76c8321f386856c44e735fd365a09d42c1da03489184b651c2052ea1c7b19c54722ed828458c1d271cc590b0818d8c7df423f71e92683f9e819095a8c6"
},
{
"id": "d70f64e4-266a-457e-9cea-eeb42341a975",
"type": "SOLANA",
"address": "EEp7DbBu5yvgf7Pr9W17cATPjCqUxY8K8R3dFbg53a3W",
"publicKey": ""
}
],
"email": "email@example.com",
"authType": "email",
"identifier": "email@example.com",
"oAuthMethod": "google" // or: undefined | "x" | "discord" | "facebook" | "apple"
},
"iat": 1745877709,
"exp": 1745879509,
"sub": "d5358219-38d3-4650-91a8-e338131d1c5e"
}
```
```json Phone
{
"data": {
"userId": "d5358219-38d3-4650-91a8-e338131d1c5e",
"wallets": [
{
"id": "de4034f1-6b0f-4a98-87a5-e459db4d3a03",
"type": "EVM",
"address": "0x9dd3824f045c77bc369485e8f1dd6b452b6be617",
"publicKey": "0x0465434f76c8321f386856c44e735fd365a09d42c1da03489184b651c2052ea1c7b19c54722ed828458c1d271cc590b0818d8c7df423f71e92683f9e819095a8c6"
},
{
"id": "d70f64e4-266a-457e-9cea-eeb42341a975",
"type": "SOLANA",
"address": "EEp7DbBu5yvgf7Pr9W17cATPjCqUxY8K8R3dFbg53a3W",
"publicKey": ""
}
],
"phone": "+13105551234",
"authType": "phone",
"identifier": "+13105551234"
},
"iat": 1745877709,
"exp": 1745879509,
"sub": "d5358219-38d3-4650-91a8-e338131d1c5e"
}
```
```json Telegram
{
"data": {
"userId": "d5358219-38d3-4650-91a8-e338131d1c5e",
"wallets": [
{
"id": "de4034f1-6b0f-4a98-87a5-e459db4d3a03",
"type": "EVM",
"address": "0x9dd3824f045c77bc369485e8f1dd6b452b6be617",
"publicKey": "0x0465434f76c8321f386856c44e735fd365a09d42c1da03489184b651c2052ea1c7b19c54722ed828458c1d271cc590b0818d8c7df423f71e92683f9e819095a8c6"
},
{
"id": "d70f64e4-266a-457e-9cea-eeb42341a975",
"type": "SOLANA",
"address": "EEp7DbBu5yvgf7Pr9W17cATPjCqUxY8K8R3dFbg53a3W",
"publicKey": ""
}
],
"telegramUserId": "1234567890",
"authType": "telegram",
"identifier": "1234567890"
},
"iat": 1745877709,
"exp": 1745879509,
"sub": "d5358219-38d3-4650-91a8-e338131d1c5e"
}
```
```json Farcaster
{
"data": {
"userId": "d5358219-38d3-4650-91a8-e338131d1c5e",
"wallets": [
{
"id": "de4034f1-6b0f-4a98-87a5-e459db4d3a03",
"type": "EVM",
"address": "0x9dd3824f045c77bc369485e8f1dd6b452b6be617",
"publicKey": "0x0465434f76c8321f386856c44e735fd365a09d42c1da03489184b651c2052ea1c7b19c54722ed828458c1d271cc590b0818d8c7df423f71e92683f9e819095a8c6"
},
{
"id": "d70f64e4-266a-457e-9cea-eeb42341a975",
"type": "SOLANA",
"address": "EEp7DbBu5yvgf7Pr9W17cATPjCqUxY8K8R3dFbg53a3W",
"publicKey": ""
}
],
"farcasterUsername": "FarcasterUsername",
"authType": "farcaster",
"identifier": "FarcasterUsername"
},
"iat": 1745877709,
"exp": 1745879509,
"sub": "d5358219-38d3-4650-91a8-e338131d1c5e"
}
```
```json External Wallet
{
"data": {
"userId": "d5358219-38d3-4650-91a8-e338131d1c5e",
"wallets": [
{
"id": "de4034f1-6b0f-4a98-87a5-e459db4d3a03",
"type": "EVM",
"address": "0x9dd3824f045c77bc369485e8f1dd6b452b6be617",
"publicKey": "0x0465434f76c8321f386856c44e735fd365a09d42c1da03489184b651c2052ea1c7b19c54722ed828458c1d271cc590b0818d8c7df423f71e92683f9e819095a8c6"
},
{
"id": "d70f64e4-266a-457e-9cea-eeb42341a975",
"type": "SOLANA",
"address": "EEp7DbBu5yvgf7Pr9W17cATPjCqUxY8K8R3dFbg53a3W",
"publicKey": ""
}
],
"externalWalletAddress": "0xaD6b78193b78e23F9aBBB675734f4a2B3559598D",
"authType": "externalWallet",
"identifier": "0xaD6b78193b78e23F9aBBB675734f4a2B3559598D",
"externalWallet": {
"address": "0xaD6b78193b78e23F9aBBB675734f4a2B3559598D",
"type": "EVM",
"provider": "MetaMask"
}
},
"iat": 1745877709,
"exp": 1745879509,
"sub": "d5358219-38d3-4650-91a8-e338131d1c5e"
}
```
## JWKS Verification
Para's JSON Web Keys Set (JWKS) file(s) are available at the following URLs:
| Environment | JWKS URL |
| ----------- | ------------------------------------------------------- |
| SANDBOX | `https://api.sandbox.getpara.com/.well-known/jwks.json` |
| BETA | `https://api.beta.getpara.com/.well-known/jwks.json` |
| PROD | `https://api.getpara.com/.well-known/jwks.json` |
## Best Practices
* **Session Verification**: For security-critical operations, verify JWT tokens on both client and server sides
* **Token Expiry**: Be aware that tokens expire based on your session configuration and plan accordingly
* **Secure Storage**: Never store JWT tokens in insecure locations like localStorage for sensitive applications
# Session Lifecycle
Source: https://docs.getpara.com/v2/react/guides/sessions-lifecycle
Managing the lifecycle of authentication sessions in Para
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
Learn how to check session status, maintain active sessions, and handle session expiration in Para web applications.
## Checking Session Status
Use `isSessionActive()` to verify whether a user's session is currently valid before performing authenticated operations.
",
description: "A promise that resolves to true if the session is currently valid and active"
}}
async={true}
/>
Example usage:
```typescript
const para = new Para(apiKey);
try {
const isActive = await para.isSessionActive();
if (!isActive) {
// Handle expired session
// See options below for session refresh
}
} catch (error) {
console.error("Session check failed:", error);
}
```
## Maintaining Active Sessions
Use `keepSessionAlive()` to extend an active session's validity without requiring full reauthentication.
",
description: "A promise that resolves to true if the session was successfully maintained, false otherwise"
}}
async={true}
/>
Example usage:
```typescript
const para = new Para(apiKey);
try {
const success = await para.keepSessionAlive();
if (!success) {
// Handle failed session maintenance
// Consider initiating a full authentication flow
}
} catch (error) {
console.error("Session maintenance failed:", error);
}
```
### Automatic Session Management with React
If you're using the React SDK and the `ParaProvider` component, you can leverage automatic session management:
```typescript
// The ParaProvider will automatically keep sessions alive by default
// To disable automatic session management
```
When using the ParaProvider component from the React SDK, it automatically keeps sessions alive in the background by calling `keepSessionAlive()` periodically. You can disable this behavior by setting the `disableAutoSessionKeepAlive` prop to `true` if you prefer to manage sessions manually.
## Refreshing Expired Sessions
Para provides the `refreshSession()` method when a session has expired.
",
description: "A promise that resolves to the refreshed session token"
}}
async={true}
/>
It's currently recommended to initiate a full authentication flow rather than using `refreshSession()` when sessions expire. The refresh flow is being improved in upcoming releases.
For most applications, when a session expires, it's better to guide users through a complete authentication process:
```typescript
const para = new Para(apiKey);
// When session expires, initiate a full authentication
if (!(await para.isSessionActive())) {
//route to authentication page
}
```
## Best Practices
* **Proactive Session Management**: Always check session status before operations that require authentication
* **Regular Session Extension**: For long user sessions, periodically call `keepSessionAlive()` or leverage the `ParaProvider` automatic session management
* **Graceful Expiration Handling**: Provide a smooth re-authentication flow when sessions expire instead of showing errors
# Session Transfer
Source: https://docs.getpara.com/v2/react/guides/sessions-transfer
Exporting Para sessions for server-side operations
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
Learn how to securely transfer session state from your client application to your server for performing operations on behalf of authenticated users.
## Exporting Sessions for Server-Side Operations
Use `exportSession()` when you need to transfer session state to your server for performing operations on behalf of the user.
By default, the exported session includes user signers which allow for server-side signing. If you don't need signing capabilities on your server, use the `excludeSigners` option to enhance security.
## Example Usage
Example client-side export:
```typescript
const para = new Para(apiKey);
// After user authentication
// Full session with signing capabilities
const fullSession = para.exportSession();
// OR
// Session without signing capabilities (recommended if signing not needed)
const secureSession = para.exportSession({ excludeSigners: true });
// Send to your server
```
## Importing Sessions
For cases where you need to import a previously exported session back into a Para client instance:
",
description: "A promise that resolves when the session has been successfully imported"
}}
async={true}
/>
```typescript
const para = new Para(apiKey);
// Import a previously exported session
await para.importSession(exportedSessionString);
// Session is now active and ready for operations
const isActive = await para.isSessionActive(); // Should return true
```
## Server-Side Implementation
To learn more about handling session on the server, check out the following guide:
## Best Practices
* **Security-First Approach**: When exporting sessions to servers, use `excludeSigners: true` unless server-side signing is explicitly needed
* **Secure Transmission**: Always use HTTPS when transmitting exported sessions to your server
* **Session Validation**: Verify the session validity on your server before performing any operations
# Wagmi Connector Integration
Source: https://docs.getpara.com/v2/react/guides/wagmi-connector
Use Para as a Wagmi connector to build custom wallet connection interfaces
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Build custom wallet connection interfaces using Para as a connector. This guide shows how to integrate Para alongside other wallet options in your own UI.
Para's `ParaModal` is built with Wagmi under the hood. We recommend using ParaModal directly for a complete authentication experience. Use this guide only if you need a custom wallet selection UI.
## Prerequisites
Before building a custom Wagmi connector, ensure you have Para configured in your application.
## Installation
Install the Para Wagmi integration:
```bash npm
npm install @getpara/wagmi-v2-integration@alpha @tanstack/react-query wagmi@^2 viem --save-exact
```
```bash yarn
yarn add @getpara/wagmi-v2-integration@alpha @tanstack/react-query wagmi@^2 viem --exact
```
```bash pnpm
pnpm add @getpara/wagmi-v2-integration@alpha @tanstack/react-query wagmi@^2 viem --save-exact
```
```bash bun
bun add @getpara/wagmi-v2-integration@alpha @tanstack/react-query wagmi@^2 viem --exact
```
## Basic Setup
Create a Wagmi config with Para as a connector option:
```typescript wagmi.config.ts
import { paraConnector } from "@getpara/wagmi-v2-integration";
import { createConfig, http } from "wagmi";
import { sepolia } from "wagmi/chains";
import Para from "@getpara/web-sdk";
// Initialize Para
const para = new Para("YOUR_PARA_API_KEY");
// Create Para connector
const connector = paraConnector({
para,
chains: [sepolia],
appName: "Your App Name"
});
// Configure Wagmi
export const config = createConfig({
chains: [sepolia],
connectors: [connector], // Add other connectors as needed
transports: {
[sepolia.id]: http("https://ethereum-sepolia-rpc.publicnode.com")
}
});
```
## Provider Setup
Wrap your app with the necessary providers:
```tsx app.tsx
import { WagmiProvider } from "wagmi";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { config } from "./wagmi.config";
const queryClient = new QueryClient();
function App() {
return (
{/* Your app */}
);
}
```
## Using the Connector
Connect with Para using Wagmi hooks:
```tsx connect-button.tsx
import { useConnect } from "wagmi";
function ConnectWithPara() {
const { connect, connectors } = useConnect();
// Find Para connector
const paraConnector = connectors.find(c => c.id === "para");
return (
connect({ connector: paraConnector })}>
Connect with Para
);
}
```
## Configuration Options
The Para connector supports these options:
```typescript
const connector = paraConnector({
para, // Your Para instance (required)
chains, // Supported chains array (required)
appName: "Your App", // Display name (required)
nameOverride: "Para", // Connector name override
idOverride: "para", // Connector ID override
});
```
## Next Steps
# Next.js
Source: https://docs.getpara.com/v2/react/troubleshooting/nextjs
Troubleshooting Para integration with Next.js applications
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
Integrating Para with Next.js can present unique challenges. This guide outlines common issues you might encounter and
provides effective solutions and best practices to ensure a seamless integration.
Using an LLM (ChatGPT, Claude) or Coding Assistant (Cursor, Github Copilot)? Here are a few tips:
1. Include the for the most up-to-date help
2. Check out the for an interactive LLM using Para Examples Hub
## General Troubleshooting Steps
Before diving into specific issues, try these general troubleshooting steps:
```bash
rm -rf .next
rm -rf node_modules
npm cache clean --force
```
`bash npm install `
```bash
npm update @getpara/web-sdk@alpha @getpara/react-sdk@alpha
```
## Common Issues and Solutions
**Problem**: Para is a client-side library and may cause issues with Server-Side Rendering (SSR) in Next.js.
**Solution**: Use dynamic imports to load Para components only on the client side.
```jsx
import dynamic from "next/dynamic";
const ParaComponent = dynamic(() => import("@getpara/react-sdk@alpha").then((mod) => mod.ParaComponent), {
ssr: false,
});
```
**Problem**: Next.js may not transpile Para packages by default, leading to build errors.
**Solution**: Add Para packages to the `transpilePackages` configuration in `next.config.js`:
```javascript
/** @type {import('next').NextConfig} */
const nextConfig = {
transpilePackages: [
"@getpara/web-sdk@alpha",
"@getpara/react-sdk@alpha",
// Add any other Para-related packages here
],
// ... other configurations
};
module.exports = nextConfig;
```
**Problem**: Para's CSS files may not load correctly in Next.js.
**Solution**: Import Para's CSS file in your `_app.js` or `_app.tsx` file:
```jsx
import "@getpara/react-sdk/dist/index.css@alpha";
function MyApp({ Component, pageProps }) {
return ;
}
export default MyApp;
```
**Problem**: Para API key not being recognized in the application.
**Solution**: Ensure you're setting the environment variable correctly in your `.env.local` file and prefixing it with `NEXT_PUBLIC_` for client-side access:
```
NEXT_PUBLIC_PARA_API_KEY=your_api_key_here
```
Then, use it in your code like this:
```javascript
const para = new Para(process.env.NEXT_PUBLIC_PARA_API_KEY);
```
**Problem**: Errors related to missing Node.js modules like `crypto` or `buffer`.
**Solution**: While not always necessary for Next.js, you may need to add polyfills. Update your `next.config.js`:
```javascript
/** @type {import('next').NextConfig} */
const nextConfig = {
// ... other configs
webpack: (config, { isServer }) => {
if (!isServer) {
config.resolve.fallback = {
...config.resolve.fallback,
crypto: require.resolve("crypto-browserify"),
stream: require.resolve("stream-browserify"),
buffer: require.resolve("buffer"),
};
}
return config;
},
};
module.exports = nextConfig;
```
### Best Practices
1. **Use the Latest Versions**: Always use the latest versions of Next.js and Para SDK to ensure compatibility and
access to the latest features.
2. **Client-Side Rendering for Para Components**: Whenever possible, render Para components on the client-side to avoid
SSR-related issues.
3. **Error Boundary**: Implement error boundaries to gracefully handle any runtime errors related to Para integration.
4. **Environment-Specific Configurations**: Use Next.js environment configurations to manage different settings for
development and production environments.
By following these troubleshooting steps and best practices, you should be able to resolve most common issues when
integrating Para with your Next.js application.
### Integration Support
If you're experiencing issues that aren't resolved by our troubleshooting resources, please [contact our team](https://join.slack.com/t/para-community/shared_invite/zt-304keeulc-Oqs4eusCUAJEpE9DBwAqrg) for
assistance. To help us resolve your issue quickly, please include the following information in your request:
1
A detailed description of the problem you're encountering.
2
Any relevant error messages or logs.
3
Steps to reproduce the issue.
4
Details about your system or environment (e.g., device, operating system, software version).
Providing this information will enable our team to address your concerns more efficiently.
# React with Vite
Source: https://docs.getpara.com/v2/react/troubleshooting/react-vite
Overcoming Para integration challenges in Vite-powered React applications
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
Vite's approach to building React applications can introduce unique considerations when integrating Para. This guide
addresses frequent issues and offers tailored solutions to ensure a successful implementation.
Using an LLM (ChatGPT, Claude) or Coding Assistant (Cursor, Github Copilot)? Here are a few tips:
1. Include the for the most up-to-date help
2. Check out the for an interactive LLM using Para Examples Hub
## General Troubleshooting Steps
Before diving into specific issues, try these general troubleshooting steps:
`bash rm -rf node_modules npm cache clean --force `
`bash npm install `
`bash npm update @getpara/react-sdk@alpha `
`bash npm run build `
## Common Issues and Solutions
**Problem**: Vite doesn't include Node.js polyfills by default, which can cause issues with packages that depend on Node.js built-ins like `buffer` or `crypto`.
**Solution**: Add the necessary polyfills using the `vite-plugin-node-polyfills` plugin. Adjust the configuration as needed for your specific requirements:
1. Install the plugin:
```bash
npm install --save-dev vite-plugin-node-polyfills
```
2. Update your `vite.config.js`:
```javascript
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { nodePolyfills } from "vite-plugin-node-polyfills";
export default defineConfig({
plugins: [
react(),
nodePolyfills({
include: ["buffer", "crypto", "stream", "util"],
}),
],
// ... other configurations
});
```
**Problem**: Environment variables not being recognized in your application.
**Solution**: Ensure you're prefixing your environment variables with `VITE_` and accessing them correctly:
1. In your `.env` file:
```
VITE_PARA_API_KEY=your_api_key_here
```
2. In your code:
```javascript
const para = new Para(import.meta.env.VITE_PARA_API_KEY);
```
**Problem**: Para's CSS files not loading correctly.
**Solution**: Import Para's CSS file in your main `App.jsx` or `index.jsx`:
```jsx
import "@getpara/react-sdk/dist/index.css@alpha";
function App() {
// Your app code
}
export default App;
```
### Best Practices
1. **Use the Latest Versions**: Always use the latest versions of Vite, React, and Para SDK to ensure compatibility and
access to the latest features.
2. **Error Handling**: Implement error boundaries to gracefully handle any runtime errors related to Para integration.
3. **Development vs Production**: Use environment-specific configurations to manage different settings for development
and production builds. Para provides environment-specific API keys.
By following these troubleshooting steps and best practices, you should be able to resolve most common issues when
integrating Para with your React application using Vite.
### Integration Support
If you're experiencing issues that aren't resolved by our troubleshooting resources, please [contact our team](https://join.slack.com/t/para-community/shared_invite/zt-304keeulc-Oqs4eusCUAJEpE9DBwAqrg) for
assistance. To help us resolve your issue quickly, please include the following information in your request:
1
A detailed description of the problem you're encountering.
2
Any relevant error messages or logs.
3
Steps to reproduce the issue.
4
Details about your system or environment (e.g., device, operating system, software version).
Providing this information will enable our team to address your concerns more efficiently.
# Svelte
Source: https://docs.getpara.com/v2/react/troubleshooting/svelte
Overcoming Para integration challenges in Svelte applications
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Using an LLM (ChatGPT, Claude) or Coding Assistant (Cursor, Github Copilot)? Here are a few tips:
1. Include the for the most up-to-date help
2. Check out the for an interactive LLM using Para Examples Hub
## General Troubleshooting Steps
Before diving into specific issues, try these general troubleshooting steps:
`bash rm -rf node_modules npm cache clean --force `
`bash npm install `
`bash npm update @getpara/react-sdk@alpha `
`bash npm run build `
Svelte applications require configuring some additional polyfills for svelte and react preprocessing. The following
example should cover these requirements.
## Adding Svelte and React + Vite Preprocessing
First, ensure `svelteKit` is installed and configured correctly within the project's `vite.config.ts` file.
```bash
npm i @sveltejs/kit
```
Then you'll need to add the appropriate preprocessing and adapter dependencies to the project's `svelte.config.ts` file.
```bash
npm i @sveltejs/vite-plugin-svelte @sveltejs/adapter-auto @svelte-preprocess @svelte-preprocess-react
```
Last, configure the `vite.config.js` and `svelte.config.js` project files to add preprocessing.
See the below code files for reference examples.
```javascript vite.config.js
import { sveltekit } from "@sveltejs/kit/vite";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [sveltekit()],
});
```
```javascript svelte.config.js
import adapter from "@sveltejs/adapter-auto";
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
import preprocessReact from "svelte-preprocess-react/preprocessReact";
/**
* This will add autocompletion if you're working with SvelteKit
*
* @type {import('@sveltejs/kit').Config}
*/
const config = {
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
// for more information about preprocessors
preprocess: [vitePreprocess(), preprocessReact()],
kit: {
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter(),
},
};
export default config;
```
For more info, including CommonJS style configs, please see the
## Example
Explore our example implementation of SvelteKit and Svelte with Vite:
### Best Practices
1. **Use the Latest Versions**: Always use the latest versions of Svelte, React, and Para SDK to ensure compatibility
and access to the latest features.
2. **Error Handling**: Implement error boundaries to gracefully handle any runtime errors related to Para integration.
3. **Development vs Production**: Use environment-specific configurations to manage different settings for development
and production builds. Para provides environment-specific API keys.
By following these troubleshooting steps and best practices, you should be able to resolve most common issues when
integrating Para with your React application using Vite.
### Integration Support
If you're experiencing issues that aren't resolved by our troubleshooting resources, please [contact our team](https://join.slack.com/t/para-community/shared_invite/zt-304keeulc-Oqs4eusCUAJEpE9DBwAqrg) for
assistance. To help us resolve your issue quickly, please include the following information in your request:
1
A detailed description of the problem you're encountering.
2
Any relevant error messages or logs.
3
Steps to reproduce the issue.
4
Details about your system or environment (e.g., device, operating system, software version).
Providing this information will enable our team to address your concerns more efficiently.
# TanStack Start Troubleshooting
Source: https://docs.getpara.com/v2/react/troubleshooting/tanstack-start
Overcoming Para integration challenges in TanStack Start applications
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
TanStack Start's server-side rendering (SSR) capabilities can introduce unique challenges when integrating Para SDK. This guide addresses frequent issues and offers tailored solutions to ensure a successful implementation.
Using an LLM (ChatGPT, Claude) or Coding Assistant (Cursor, Github Copilot)? Here are a few tips:
1. Include the for the most up-to-date help
2. Check out the for an interactive LLM using Para Examples Hub
## General Troubleshooting Steps
Before diving into specific issues, try these general troubleshooting steps:
```bash
rm -rf node_modules
npm cache clean --force
```
```bash
npm install
```
```bash
npm update @getpara/react-sdk
```
```bash
npm run build
```
## Common Issues and Solutions
**Problem**: Para API key environment variables not being recognized in your application.
**Solution**: Ensure you're using the correct prefix for environment variables in TanStack Start and accessing them properly:
1. In your `.env` file:
```
VITE_PARA_API_KEY=your_api_key_here
VITE_PARA_ENVIRONMENT=BETA
```
2. In your constants file:
```javascript
// src/constants.ts
export const API_KEY = import.meta.env.VITE_PARA_API_KEY || "";
export const ENVIRONMENT = import.meta.env.VITE_PARA_ENVIRONMENT || "BETA";
```
3. When using these in your ParaProvider:
```jsx
{children}
```
**Problem**: Missing or improperly configured Node.js polyfills causing errors like `crypto is not defined` or similar issues.
**Solution**: Configure the polyfills specifically for the client bundle only:
1. Install the plugin:
```bash
npm install --save-dev vite-plugin-node-polyfills
```
2. Update your `app.config.ts` to apply polyfills only to the client bundle:
```typescript
import { defineConfig } from "@tanstack/react-start/config";
import tsConfigPaths from "vite-tsconfig-paths";
import { nodePolyfills } from "vite-plugin-node-polyfills";
export default defineConfig({
tsr: { appDirectory: "src" },
// Base configuration (applied to both client and server)
vite: {
plugins: [tsConfigPaths({ projects: ["./tsconfig.json"] })],
define: {
// This helps modules determine the execution environment
"process.browser": true,
},
},
// Client-specific configuration
routers: {
client: {
vite: {
// Apply node polyfills ONLY on the client side
plugins: [nodePolyfills()],
},
},
},
});
```
**Important**: Do NOT configure nodePolyfills in the top-level vite plugins array, as this will apply the polyfills to the server bundle and can cause conflicts.
**Problem**: Browser-specific modules not being resolved correctly, leading to missing APIs or incorrect environment detection.
**Solution**: Add the `process.browser` definition to help modules determine the execution environment:
```typescript
// app.config.ts
export default defineConfig({
vite: {
define: {
"process.browser": true,
},
// other configurations...
},
// other configurations...
});
```
This setting is critical for ensuring that browser-specific code paths are correctly resolved during bundling.
**Problem**: Errors like `styled.div is not a function` or `Cannot read properties of undefined (reading 'div')` during server rendering.
**Solution**: Ensure Para components are only rendered on the client side by using both `React.lazy` for dynamic imports and `ClientOnly` from TanStack Router:
```jsx
import React from "react";
import { ClientOnly } from "@tanstack/react-router";
// Lazy load Para component to prevent server-side evaluation
const LazyParaProvider = React.lazy(() =>
import("@getpara/react-sdk").then((mod) => ({
default: mod.ParaProvider
}))
);
export function Providers({ children }) {
return (
{children}
);
}
```
The combination of `React.lazy` and `ClientOnly` ensures that Para components are not only rendered on the client side but also that the modules are not evaluated on the server.
**Problem**: Even with `ClientOnly`, you're still seeing styled-components errors during server rendering.
**Solution**: Module-level evaluation can still happen on the server even if the component isn't rendered. Make sure all Para imports are lazy loaded:
1. Don't import directly from Para SDK at the module level:
```jsx
// AVOID this at the top level:
import { ParaModal, useModal } from "@getpara/react-sdk";
```
2. Instead, create wrapper components for all Para components:
```jsx
// Create a component file like ParaContainer.tsx
export function ParaContainer() {
// Import and use Para components here
const { openModal } = useModal();
return (
<>
Open Para Modal
>
);
}
```
3. Then lazy load these wrapper components:
```jsx
const LazyParaContainer = React.lazy(() =>
import("~/components/ParaContainer").then((mod) => ({
default: mod.ParaContainer,
}))
);
function HomePage() {
return (
Loading...}>
);
}
```
**Problem**: The Para modal appears transparent or without proper styling.
**Solution**: Import Para's CSS file in your component:
```jsx
// In your main component or route file:
import "@getpara/react-sdk/styles.css";
// Then use Para components as usual
```
Ensure this import is included in the component that uses Para components or in a parent component that wraps them.
## Best Practices for TanStack Start Integration
1. **Client-Side Only Rendering**: Always use both `React.lazy` and `ClientOnly` for Para components to avoid SSR issues.
2. **Polyfill Strategy**: Configure node polyfills only for the client bundle using the `routers.client.vite.plugins` config.
3. **Environment Awareness**: Set `process.browser` to true to help modules determine the execution environment.
4. **Component Boundaries**: Clearly define boundaries between server and client components to prevent hydration mismatches.
5. **Error Handling**: Implement error boundaries to gracefully handle any runtime errors related to Para integration.
6. **Development vs Production**: Use environment-specific configurations to manage different settings for development and production builds.
By following these troubleshooting steps and best practices, you should be able to resolve most common issues when integrating Para with your TanStack Start application.
### Integration Support
If you're experiencing issues that aren't resolved by our troubleshooting resources, please [contact our team](https://join.slack.com/t/para-community/shared_invite/zt-304keeulc-Oqs4eusCUAJEpE9DBwAqrg) for
assistance. To help us resolve your issue quickly, please include the following information in your request:
1
A detailed description of the problem you're encountering.
2
Any relevant error messages or logs.
3
Steps to reproduce the issue.
4
Details about your system or environment (e.g., device, operating system, software version).
Providing this information will enable our team to address your concerns more efficiently.
# claimPregenWallets
Source: https://docs.getpara.com/v2/references/core/claimpregenwallets
Claims pregenerated wallets for the user
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# clearStorage
Source: https://docs.getpara.com/v2/references/core/clearstorage
Clears the specified storage type
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# createGuestWallets
Source: https://docs.getpara.com/v2/references/core/createguestwallets
Creates guest wallets
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# createPregenWallet
Source: https://docs.getpara.com/v2/references/core/createpregenwallet
Creates a pregenerated wallet of a specific type
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# createPregenWalletPerType
Source: https://docs.getpara.com/v2/references/core/createpregenwalletpertype
Creates pregenerated wallets for specified types
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# createWallet
Source: https://docs.getpara.com/v2/references/core/createwallet
Creates a new wallet
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
",
typeLink: "/v2/references/types/twallettype",
optional: true
},
{
name: "skipDistribute",
type: "boolean",
optional: true,
description: "If `true`, skip distributing the new wallet shares."
}
]}
returns={{
type: "[Wallet, string | undefined]",
typeLink: "/v2/references/types/wallet",
description: "The created wallet and optional recovery secret."
}}
/>
# createWalletPerType
Source: https://docs.getpara.com/v2/references/core/createwalletpertype
Creates wallets for specified types
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
[]",
typeLink: "/v2/references/types/twallettype",
optional: true,
description: "Array of the wallet types to create."
},
{
name: "skipDistribute",
type: "boolean",
optional: true,
description: "If `true`, skip distributing the new wallets shares."
}
]}
returns={{
type: "{ wallets: Wallet[]; walletIds: CurrentWalletIds; recoverySecret?: string; }",
typeLink: "/v2/references/types/wallet",
description: "Created wallets, their IDs, and optional recovery secret."
}}
/>
# distributeNewWalletShare
Source: https://docs.getpara.com/v2/references/core/distributenewwalletshare
Distributes a new wallet share
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# enable2fa
Source: https://docs.getpara.com/v2/references/core/enable2fa
Enables two-factor authentication using the provided code
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# exportSession
Source: https://docs.getpara.com/v2/references/core/exportsession
Exports the current session data
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# fetchWallets
Source: https://docs.getpara.com/v2/references/core/fetchwallets
Fetches wallet entities from the server
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# getAuthInfo
Source: https://docs.getpara.com/v2/references/core/getauthinfo
Retrieves the current authentication information for the user
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# getFarcasterConnectUri
Source: https://docs.getpara.com/v2/references/core/getfarcasterconnecturi
Generates a Farcaster connect URI for authentication
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# API Reference
Source: https://docs.getpara.com/v2/references/overview
Complete reference documentation for Para SDK methods, hooks, and types
## What You'll Find Here
This section contains comprehensive API reference documentation for the Para SDK. It's organized into three main categories to help you quickly find what you need:
### Core Methods
Direct SDK methods for authentication, wallet management, and blockchain operations. These are the fundamental building blocks for integrating Para into any JavaScript/TypeScript application.
### React Hooks
React-specific hooks that provide a declarative interface for Para functionality. These hooks handle state management, caching, and lifecycle concerns automatically, making it easy to build React applications with Para.
### Types & Interfaces
TypeScript type definitions and interfaces used throughout the SDK. Understanding these types will help you write type-safe code and better understand the data structures returned by Para methods.
## Quick Navigation Tips
* All items within each category are organized alphabetically for easy discovery
* Each reference includes detailed parameter descriptions, return types, and usage examples
* Type definitions link to their corresponding documentation for deeper understanding
* Hook documentation shows both TypeScript interfaces and practical implementation patterns
## Need Help?
If you're just getting started, we recommend checking out the [Getting Started](/v2/getting-started) guide first to understand the basics before diving into the API reference.
For implementation examples and best practices, visit our [Examples](/v2/walkthroughs/overview) section.
# Server Examples
Source: https://docs.getpara.com/v2/server/examples
Explore Para's server-side integration examples across Node.js, Bun, and Deno
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Para offers a collection of server-side examples to help you integrate our technology across different JavaScript runtime environments. Our examples-hub repository includes server implementations that showcase how to use Para in Node.js, Bun, and Deno environments.
Each example demonstrates how to perform blockchain operations server-side using both pregenerated wallets and imported client sessions. These standalone examples focus on specific Para SDKs or features, providing minimal implementation requirements that you can easily adapt to your specific application needs.
## Runtime Environments
Browse our server examples showcasing Para integration across different JavaScript runtimes:
## Need Something Specific?
Don't see an example for your server-side use case? Para's team is eager to create new examples to help you integrate with different libraries, runtime environments, or blockchain ecosystems. Reach out to our support team for assistance.
# Account Abstraction
Source: https://docs.getpara.com/v2/server/guides/account-abstraction
Implement ERC-4337 Account Abstraction with Para Server SDK
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Account Abstraction (AA) enables powerful smart contract wallet functionality like batched transactions, gas sponsorship, and advanced access controls. Para Server SDK supports integration with leading AA providers, allowing you to implement these capabilities in server-side environments.
When using Account Abstraction with Para, your Para wallet acts as the EOA (Externally Owned Account) signer that controls the smart contract wallet. The AA provider deploys and manages the smart contract wallet on-chain, while Para handles the secure signing required for authorizing transactions.
Server-side AA implementation functions identically to client-side implementation, with the additional requirement of signature byte adjustment for contract verification.
## Understanding Signature Adjustment
Account Abstraction providers use on-chain signature verification within their smart contracts. Para's 2/2 MPC wallet produces non-deterministic signatures where the last byte (`v` recovery byte) may need adjustment for proper on-chain verification.
**Critical**: Para signatures may require adjustment of the last byte for compatibility with AA providers. Without this adjustment, transactions might fail at the network level despite signature success.
## Implementation Steps
Let's break down the process of implementing Account Abstraction on the server into manageable steps:
### 1. Set Up Para Server Client
First, initialize the Para Server SDK and authenticate with an imported session:
```typescript
import { Para as ParaServer } from "@getpara/server-sdk@alpha";
// Initialize Para Server SDK
const para = new ParaServer("YOUR_API_KEY");
// Import a client session
await para.importSession(session);
```
If you need more details on setup please refer tot he .
### 2. Create a Viem Client
Next, use Para's Viem integration to create a Viem client:
```typescript
import { createParaAccount, createParaViemClient } from "@getpara/viem-integration@alpha";
import { http } from "viem/transport";
import { arbitrumSepolia } from "viem/chains";
// Create a Para account for Viem
const viemParaAccount = createParaAccount(para);
// Initialize the Viem client
const viemClient = createParaViemClient(para, {
account: viemParaAccount,
chain: arbitrumSepolia,
transport: http("YOUR_RPC_URL"),
});
```
### 3. Implement Signature Adjustment
Create a helper function to properly adjust the signature byte for on-chain verification:
```typescript
import { hashMessage, type Hash, type SignableMessage } from "viem";
function hexStringToBase64(hexString) {
return Buffer.from(hexString, "hex").toString("base64");
}
// Custom sign message function with signature byte adjustment
async function customSignMessage(para, message) {
// Get the first wallet from Para client
const wallet = para.wallets ? Object.values(para.wallets)[0] : null;
if (!wallet) {
throw new Error("Para wallet not available for signing.");
}
// Hash and convert the message
const hashedMessage = hashMessage(message);
const messagePayload = hashedMessage.startsWith("0x") ? hashedMessage.substring(2) : hashedMessage;
const messageBase64 = hexStringToBase64(messagePayload);
// Sign with Para
const res = await para.signMessage({
walletId: wallet.id,
messageBase64: messageBase64,
});
if (!("signature" in res)) {
throw new Error("Signature failed");
}
// Adjust the signature's 'v' value for on-chain verification
let signature = res.signature;
const vHex = signature.slice(-2);
const v = parseInt(vHex, 16);
if (!isNaN(v) && v < 27) {
const adjustedVHex = (v + 27).toString(16).padStart(2, "0");
signature = signature.slice(0, -2) + adjustedVHex;
}
return `0x${signature}`;
}
```
As mentioned earlier, this function adjusts the last byte of the signature to ensure compatibility with on-chain verification. This is crucial for successful transaction execution when working with Account Abstraction providers.
### 4. Override Viem Client's Sign Function
Apply the custom signing function to the Viem client:
```typescript
// Override sign message function with custom implementation
viemClient.signMessage = async ({ message }) => customSignMessage(para, message);
```
### 5. Create the AA Provider Client
Finally, create the Account Abstraction client using your preferred provider. Here's an example with Alchemy:
```typescript
import { WalletClientSigner } from "@alchemy/aa-core";
import { createModularAccountAlchemyClient } from "@alchemy/aa-alchemy";
// Create Alchemy AA client with the customized Viem client
const walletClientSigner = new WalletClientSigner(viemClient, "para");
const alchemyClient = await createModularAccountAlchemyClient({
apiKey: "YOUR_ALCHEMY_API_KEY",
chain: arbitrumSepolia,
signer: walletClientSigner,
gasManagerConfig: {
policyId: "YOUR_ALCHEMY_GAS_POLICY_ID", // Optional: For gas sponsorship
},
});
```
## Using the AA Smart Wallet
Once your AA client is set up, you can perform transactions through the smart contract wallet:
### Get Smart Wallet Address
First, retrieve the smart wallet address (this is different from your Para wallet address):
```typescript
// Get the smart wallet address
const smartWalletAddress = await alchemyClient.getAddress();
console.log("Smart Wallet Address:", smartWalletAddress);
```
Be aware that funds should be sent to the smart wallet address (returned by `getAddress()`) rather than the Para wallet address. The smart wallet is the entity that holds funds and executes transactions on-chain.
### Send Transactions
Execute transactions through the smart wallet:
```typescript
import { parseEther } from "viem";
// Send a simple transfer
const txHash = await alchemyClient.sendTransaction({
to: "0xRecipientAddress",
value: parseEther("0.01"),
data: "0x", // Optional for simple transfers
});
console.log("Transaction Hash:", txHash);
```
### Execute Contract Interactions
Interact with smart contracts through your AA wallet:
```typescript
// Interact with a smart contract
const tokenContract = "0xTokenContractAddress";
const data = "0x..." // Encoded contract function call
const contractTxHash = await alchemyClient.sendTransaction({
to: tokenContract,
data: data,
});
```
## Supported AA Providers
Para integrates with several leading Account Abstraction providers:
## Troubleshooting
If transactions fail despite successful signing, check that the signature byte adjustment is working correctly. The most common issue is that the 'v' byte isn't properly adjusted for on-chain verification.
First-time use of an AA wallet requires contract deployment, which can be more expensive and complex. Ensure you have sufficient funds in the EOA (Para wallet) for this initial deployment.
If using gas sponsorship, verify your policy ID and settings in the AA provider's dashboard. Also check that the transaction meets the policy requirements (value limits, allowed functions, etc.).
## Best Practices
1. **Always adjust signatures**: Implement the signature adjustment function to ensure compatibility with on-chain verification.
2. **Test thoroughly**: Before deploying to production, test your AA implementation in a test environment with minimal funds.
3. **Handle errors gracefully**: Implement proper error handling for signature failures and transaction rejections.
4. **Monitor gas costs**: Be aware of the additional gas costs associated with AA transactions, especially for contract deployments.
5. **Secure session management**: Follow secure practices for managing Para sessions in server environments.
6. **Consider gas sponsorship**: Many AA providers offer gas sponsorship, which can improve user experience by eliminating gas fees.
## Learn More
For more detailed information on Account Abstraction concepts and implementation, refer to our web documentation:
## Examples
Explore our server-side Account Abstraction examples:
# Cosmos Integration
Source: https://docs.getpara.com/v2/server/guides/cosmos
Use Para Server SDK with Cosmos-based blockchains
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Para Server SDK seamlessly integrates with Cosmos-based blockchains through the CosmJS library. Once you've set up and authenticated your Para Server client, the Cosmos integration works identically to the client-side implementation.
Before using this integration, ensure you've completed the server setup by importing a client session or creating a pregenerated wallet. See the for details.
## Installation
Install the required dependencies for Cosmos integration:
```bash
npm install @getpara/cosmjs-v0-integration@alpha @cosmjs/stargate @cosmjs/proto-signing @cosmjs/amino @cosmjs/encoding --save-exact
```
## Implementation
The Para integration with CosmJS provides a custom signer that works with Stargate Client:
```typescript
import { Para as ParaServer } from "@getpara/server-sdk@alpha";
import { ParaProtoSigner } from "@getpara/cosmjs-v0-integration@alpha";
import { SigningStargateClient } from "@cosmjs/stargate";
// Para server client (already authenticated)
const paraServer = new ParaServer("YOUR_API_KEY");
// Create the Para Cosmos Signer
const signer = new ParaProtoSigner(paraServer, "cosmos");
// Connect to the Cosmos network
const rpcUrl = "https://rpc.cosmos.network"; // Replace with your preferred RPC endpoint
const client = await SigningStargateClient.connectWithSigner(rpcUrl, signer);
// Get the wallet address
const address = await signer.getAddress();
console.log(`Wallet address: ${address}`);
// Get account balance
const balance = await client.getBalance(address, "uatom");
console.log(`Balance: ${balance.amount} ${balance.denom}`);
// Send tokens
const recipient = "cosmos1recipient";
const amount = {
denom: "uatom",
amount: "100000", // 0.1 ATOM (uatom is microatom, 1 ATOM = 1,000,000 uatom)
};
const result = await client.sendTokens(
address,
recipient,
[amount],
{
amount: [{ denom: "uatom", amount: "5000" }],
gas: "200000",
}
);
console.log(`Transaction hash: ${result.transactionHash}`);
```
## Chain Support
The Para Cosmos integration supports various Cosmos-based chains. You can specify the chain when creating the signer:
```typescript
// For Cosmos Hub
const cosmosSigner = new ParaProtoSigner(paraServer, "cosmos");
// For Osmosis
const osmosisSigner = new ParaProtoSigner(paraServer, "osmosis");
// For other supported chains
const otherChainSigner = new ParaProtoSigner(paraServer, "chainName");
```
## Best Practices
* Use appropriate gas settings for different types of transactions
* Implement proper error handling for network failures
* Consider retry logic for RPC endpoints
* Always verify transaction details before sending
## Learn More
For detailed examples of using Para with Cosmos, including chain-specific operations and advanced transaction types, refer to our web documentation:
## Examples
Explore our server-side Cosmos integration examples:
# EVM Integration
Source: https://docs.getpara.com/v2/server/guides/evm
Use Para Server SDK with Ethereum and EVM-compatible chains
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Para Server SDK provides seamless integration with Ethereum Virtual Machine (EVM) compatible chains through popular libraries like Ethers.js and Viem. Once you've set up and authenticated your Para Server client, the EVM integration works identically to the client-side implementation.
Before using these integrations, ensure you've completed the server setup by importing a client session or creating a pregenerated wallet. See the for details.
## Installation
Install the required dependencies for your preferred EVM library:
```bash Ethers.js
npm install @getpara/ethers-v6-integration@alpha ethers --save-exact
```
```bash Viem
npm install @getpara/viem-integration@alpha viem --save-exact
```
## Implementation
### Ethers.js Integration
The Para Ethers Signer acts as a drop-in replacement for standard Ethers signers:
```typescript
import { Para as ParaServer } from "@getpara/server-sdk@alpha";
import { ParaEthersSigner } from "@getpara/ethers-v6-integration@alpha";
import { ethers } from "ethers";
// Para server client (already authenticated)
const paraServer = new ParaServer("YOUR_API_KEY");
// Set up the provider with your RPC URL
const provider = new ethers.JsonRpcProvider("YOUR_RPC_URL");
// Create the Para Ethers Signer
const signer = new ParaEthersSigner(paraServer, provider);
// Now you can use the signer with any Ethers.js operations
const balance = await provider.getBalance(await signer.getAddress());
console.log(`Balance: ${ethers.formatEther(balance)} ETH`);
// Sign a message
const signature = await signer.signMessage("Hello from Para Server!");
// Send a transaction
const tx = await signer.sendTransaction({
to: "0xRecipientAddress",
value: ethers.parseEther("0.001")
});
```
### Viem Integration
Para's Viem integration provides a custom Viem client compatible with all Viem operations:
```typescript
import { Para as ParaServer } from "@getpara/server-sdk@alpha";
import { createParaAccount, createParaViemClient } from "@getpara/viem-integration@alpha";
import { http } from "viem";
import { sepolia } from "viem/chains";
// Para server client (already authenticated)
const paraServer = new ParaServer("YOUR_API_KEY");
// Create a Para Account
const account = await createParaAccount(paraServer);
// Create the Para Viem WalletClient
const walletClient = createParaViemClient(paraServer, {
account: account,
chain: sepolia,
transport: http("https://ethereum-sepolia-rpc.publicnode.com"),
});
// Now you can use the walletClient with any Viem operations
const hash = await walletClient.sendTransaction({
to: "0xRecipientAddress",
value: 1000000000000000n // 0.001 ETH
});
```
## Best Practices
* Use environment variables for API keys and RPC URLs
* Implement proper error handling for network failures
* Consider gas price management for production applications
* Cache network calls where appropriate to reduce RPC usage
## Learn More
For detailed examples of using Para with EVM chains, including smart contract interactions, ERC-20 transfers, and more, refer to our web documentation:
## Examples
Explore our server-side EVM integration examples:
# Wallet Pregeneration
Source: https://docs.getpara.com/v2/server/guides/pregen
Create and manage server-side pregenerated wallets using Para's Server SDK
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Pregenerated wallets are a powerful feature of Para that enable server-side wallet creation without requiring user authentication. This approach allows your application to perform blockchain operations autonomously, making it ideal for agent-based systems, automated workflows, and backend services.
The pregeneration flow works by creating a wallet associated with an identifier of your choice (email, phone, username, or custom ID). Para then provides you with the user share of the 2/2 MPC key, which you must securely store on your server until it's either claimed by a user or used for signing operations.
## Key Benefits
* **Authentication-free operations**: Create and use wallets without requiring user authentication
* **Autonomous agents**: Provide blockchain capabilities to AI agents or automated systems
* **User pre-provisioning**: Create wallets for existing user bases before they interact with your application
* **Server-side signing**: Perform blockchain operations entirely from your backend
## Creating a Pregenerated Wallet
```typescript Node.js
import { Para as ParaServer, WalletType } from "@getpara/server-sdk@alpha";
// Initialize the Para Server SDK
const paraServer = new ParaServer("YOUR_API_KEY");
// Check if a wallet already exists for this identifier
const hasWallet = await paraServer.hasPregenWallet({
pregenId: { email: "user@example.com" },
});
// Create a pregenerated wallet if needed
if (!hasWallet) {
const pregenWallet = await paraServer.createPregenWallet({
type: 'EVM', // or 'SOLANA', 'COSMOS'
pregenId: { email: "user@example.com" },
});
// Now use the pregenerated wallet
}
```
```typescript Bun
import { Para as ParaServer, WalletType } from "@getpara/server-sdk@alpha";
// Initialize the Para Server SDK with WebSockets disabled for Bun
const paraServer = new ParaServer("YOUR_API_KEY", {
disableWebSockets: true
});
// Check if a wallet already exists for this identifier
const hasWallet = await paraServer.hasPregenWallet({
pregenId: { email: "user@example.com" },
});
// Create a pregenerated wallet if needed
if (!hasWallet) {
const pregenWallet = await paraServer.createPregenWallet({
type: 'EVM', // or 'SOLANA', 'COSMOS'
pregenId: { email: "user@example.com" },
});
// Now use the pregenerated wallet
}
```
```typescript Deno
import { Para as ParaServer, WalletType } from "@getpara/server-sdk@alpha";
// Initialize the Para Server SDK with WebSockets disabled for Deno
const paraServer = new ParaServer("YOUR_API_KEY", {
disableWebSockets: true
});
// Check if a wallet already exists for this identifier
const hasWallet = await paraServer.hasPregenWallet({
pregenId: { email: "user@example.com" },
});
// Create a pregenerated wallet if needed
if (!hasWallet) {
const pregenWallet = await paraServer.createPregenWallet({
type: WalletType.EVM, // or WalletType.SOLANA, WalletType.COSMOS
pregenId: { email: "user@example.com" },
});
// Now use the pregenerated wallet
}
```
### Method Parameters
The type of wallet to create (`'EVM'`, `'SOLANA'`, or `'COSMOS'`).
The identifier for the new wallet. The `pregenId` must be an object of the form:
```typescript
| { email: string; }
| { phone: `+${number}`; }
| { farcasterUsername: string; }
| { telegramUserId: string; }
| { discordUsername: string; }
| { xUsername: string; }
| { customId: string; }
```
The identifier can be an email or phone number, a third-party user ID (for Farcaster, Telegram, Discord, or X), or a custom ID relevant to your application. Choose an identifier that works best for your application architecture.
## Securing the User Share
After creating a pregenerated wallet, you must securely store the user share. This component is critical for the wallet's operation and security.
```typescript
// Retrieve the user share for the pregenerated wallet
const userShare = await paraServer.getUserShare();
// Store this user share securely in your database
// NEVER store this in plain text - always encrypt it!
```
You must securely store this user share in your backend, associated with the user's identifier. If this share is lost, the wallet becomes permanently inaccessible.
### Secure Storage Best Practices
We strongly recommend implementing robust encryption for user shares both in transit and at rest. Consider using a high-entropy encryption key with AES-GCM encryption. Do not store encryption keys in the same database as the encrypted data.
Para offers pre-launch security reviews for teams in the Growth tier or above. Reach out to the Para team for assistance with your implementation!
### Storage Security Recommendations
* **Encrypt** user shares in-transit and at-rest
* Implement **access controls** for your share database
* Maintain regular **database backups** to prevent data loss
* Create **disaster recovery** processes for compromise scenarios
* Have a **key rotation** plan in case of security incidents
* Complete **security fire drills** before launching
## Using a Pregenerated Wallet
To use a pregenerated wallet for blockchain operations, you need to:
1. Retrieve the encrypted user share from your database
2. Decrypt the user share
3. Load it into your Para client instance
```typescript
// Retrieve and decrypt the user share from your database
const encryptedUserShare = await database.getUserShare(walletId);
const userShare = decryptUserShare(encryptedUserShare);
// Load the user share into the Para client
await paraServer.setUserShare(userShare);
```
When implementing `setUserShare` in API routes or serverless functions, it's critical to create a new Para client instance for each request. This prevents different users' shares from conflicting with each other. Creating a new Para client has minimal overhead and won't impact request performance.
### Signing Operations
Once the user share is loaded, you can test the wallet functionality by signing a message. However, for production use, we recommend using the blockchain library integrations described in the next section.
```typescript
// Test signing a message
const messageBase64 = Buffer.from("Hello, World!").toString('base64');
const signature = await paraServer.signMessage({
walletId,
messageBase64,
});
```
### Using with Blockchain Libraries
Pregenerated wallets work seamlessly with all blockchain integration libraries. Here are some examples:
## Wallet Claiming Flow
Claiming pregenerated wallets must be done client-side with the Para Client SDK. The Server SDK does not support the key rotation operations required for wallet claiming.
For applications that need to transfer ownership of pregenerated wallets to users, you'll need to implement a client-side claiming flow. This process involves:
1. Securely transferring the user share from your server to the client
2. Loading the share into the client-side Para instance
3. Using the client SDK to claim the wallet
For a comprehensive guide on implementing the claiming flow, refer to our web documentation:
## Core Pregeneration Methods
Create a new pregenerated wallet for an identifier
Check if a pregenerated wallet exists for an identifier
Retrieve pregenerated wallets for a given identifier
Get the user share that must be securely stored
Load a previously stored user share
Update the identifier of a pregenerated wallet
## Use Cases
Pregenerated wallets enable autonomous AI agents to perform blockchain operations. For example, an AI trading agent could analyze market conditions and execute trades using its own wallet, without requiring human intervention or authentication.
Create automation systems that perform recurring blockchain operations on predetermined schedules. For instance, a DeFi yield harvesting service could automatically collect and reinvest yields at optimal times using pregenerated wallets.
Create wallets for your existing user base before they engage with blockchain features. When users are ready to interact with these features, they can claim ownership of their pregenerated wallet through a seamless onboarding process.
Build backend services that perform blockchain operations on behalf of users or systems. For example, a gas fee management service could optimize transaction timing based on network conditions without requiring user input.
Maintain consistent wallet identities across different platforms by using the same pregenerated wallets. This allows users to have a unified experience regardless of which platform they're using to access your service.
## Best Practices
* **Choose appropriate identifiers** that align with your application architecture
* **Implement robust encryption** for user share storage
* **Create backup systems** to prevent data loss
* **Use a separate database** for user share storage with enhanced security
* **Monitor for suspicious activity** in your pregenerated wallet systems
* **Implement rate-limiting** to prevent abuse of wallet creation
* **Document your recovery procedures** for security incidents
* **Consider multi-region replication** for high-availability systems
## Example Implementation
Here's a reference example demonstrating the creation and secure storage of pregenerated wallets:
## Community Showcase
Check out some novel use cases of pregenerated wallets created by our community:
# Session Management
Source: https://docs.getpara.com/v2/server/guides/sessions
Manage client sessions in server-side environments with Para Server SDK
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Para's Server SDK enables you to import and manage client-side sessions within your server environment. This allows your server to perform authenticated blockchain operations on behalf of users without requiring them to re-authenticate. The server can also validate existing client sessions using either the Para client or dedicated verification endpoints.
## Importing Client Sessions
To use a client session on your server, you need to:
1. Export the session from the client-side Para instance
2. Transfer the session to your server securely
3. Import the session into your server-side Para instance
### Client-Side Session Export
First, have your client-side application export the active session:
```typescript
// Client-side
const para = new Para("YOUR_API_KEY");
// Export the current session
const serializedSession = await para.exportSession();
// Send this to your server endpoint
await fetch("/api/import-session", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ session: serializedSession }),
});
```
If signing on the server isn't required, you can pass `{ excludeSigners: true }` as an argument to `exportSession` to remove the signer data from the exported wallets, enhancing security:
```typescript
const serializedSession = await para.exportSession({ excludeSigners: true });
```
### Server-Side Session Import
On your server, import the session into a Para Server SDK instance:
```typescript
import { Para as ParaServer } from "@getpara/server-sdk@alpha";
// Initialize the Para Server SDK
const paraServer = new ParaServer("YOUR_API_KEY");
app.post("/api/import-session", async (req, res) => {
try {
// Import the session from the client
await paraServer.importSession(req.body.session);
// Now you can use the paraServer instance for authenticated operations
// ...
res.status(200).json({ success: true });
} catch (error) {
res.status(500).json({ error: "Failed to import session" });
}
});
```
Create a new Para client instance for each request when handling multiple users. This prevents session conflicts between different users' requests and ensures security isolation.
## Session Validation
You can validate sessions on the server side to ensure they're still active before performing operations.
### Using the Para Client
```typescript
import { Para as ParaServer } from "@getpara/server-sdk@alpha";
const paraServer = new ParaServer("YOUR_API_KEY");
app.post("/api/authenticated-action", async (req, res) => {
try {
// Import the session
await paraServer.importSession(req.body.session);
// Check if the session is still active
const isActive = await paraServer.isSessionActive();
if (!isActive) {
return res.status(401).json({ error: "Session expired" });
}
// Proceed with authenticated operations
// ...
res.status(200).json({ success: true });
} catch (error) {
res.status(500).json({ error: "Operation failed" });
}
});
```
### Using JWT Authentication
Once a user is signed in, you can request a Para JWT token. This token will provide attestations for the user's ID, their identity, and any wallets they have provisioned via your application.
To request a token, use the `issueJwt` method. The method returns the token itself as well as the JWKS key ID (`kid`) for the keypair that signed it.
```typescript
const paraServer = new ParaServer('your-api-key');
const { token, keyId } = await paraServer.issueJwt();
```
The token's expiry will be determined by your customized session length, or else will default to 30 minutes. Issuing a token, like most authenticated API operations, will also renew and extend the session for that duration.
Depending on the user in question, a decoded token payload might resemble the following:
```json Email
{
"data": {
"userId": "d5358219-38d3-4650-91a8-e338131d1c5e",
"wallets": [
{
"id": "de4034f1-6b0f-4a98-87a5-e459db4d3a03",
"type": "EVM",
"address": "0x9dd3824f045c77bc369485e8f1dd6b452b6be617",
"publicKey": "0x0465434f76c8321f386856c44e735fd365a09d42c1da03489184b651c2052ea1c7b19c54722ed828458c1d271cc590b0818d8c7df423f71e92683f9e819095a8c6"
},
{
"id": "d70f64e4-266a-457e-9cea-eeb42341a975",
"type": "SOLANA",
"address": "EEp7DbBu5yvgf7Pr9W17cATPjCqUxY8K8R3dFbg53a3W",
"publicKey": ""
}
],
"email": "email@example.com",
"authType": "email",
"identifier": "email@example.com",
"oAuthMethod": "google" // or: undefined | "x" | "discord" | "facebook" | "apple"
},
"iat": 1745877709,
"exp": 1745879509,
"sub": "d5358219-38d3-4650-91a8-e338131d1c5e"
}
```
```json Phone
{
"data": {
"userId": "d5358219-38d3-4650-91a8-e338131d1c5e",
"wallets": [
{
"id": "de4034f1-6b0f-4a98-87a5-e459db4d3a03",
"type": "EVM",
"address": "0x9dd3824f045c77bc369485e8f1dd6b452b6be617",
"publicKey": "0x0465434f76c8321f386856c44e735fd365a09d42c1da03489184b651c2052ea1c7b19c54722ed828458c1d271cc590b0818d8c7df423f71e92683f9e819095a8c6"
},
{
"id": "d70f64e4-266a-457e-9cea-eeb42341a975",
"type": "SOLANA",
"address": "EEp7DbBu5yvgf7Pr9W17cATPjCqUxY8K8R3dFbg53a3W",
"publicKey": ""
}
],
"phone": "+13105551234",
"authType": "phone",
"identifier": "+13105551234"
},
"iat": 1745877709,
"exp": 1745879509,
"sub": "d5358219-38d3-4650-91a8-e338131d1c5e"
}
```
```json Telegram
{
"data": {
"userId": "d5358219-38d3-4650-91a8-e338131d1c5e",
"wallets": [
{
"id": "de4034f1-6b0f-4a98-87a5-e459db4d3a03",
"type": "EVM",
"address": "0x9dd3824f045c77bc369485e8f1dd6b452b6be617",
"publicKey": "0x0465434f76c8321f386856c44e735fd365a09d42c1da03489184b651c2052ea1c7b19c54722ed828458c1d271cc590b0818d8c7df423f71e92683f9e819095a8c6"
},
{
"id": "d70f64e4-266a-457e-9cea-eeb42341a975",
"type": "SOLANA",
"address": "EEp7DbBu5yvgf7Pr9W17cATPjCqUxY8K8R3dFbg53a3W",
"publicKey": ""
}
],
"telegramUserId": "1234567890",
"authType": "telegram",
"identifier": "1234567890"
},
"iat": 1745877709,
"exp": 1745879509,
"sub": "d5358219-38d3-4650-91a8-e338131d1c5e"
}
```
```json Farcaster
{
"data": {
"userId": "d5358219-38d3-4650-91a8-e338131d1c5e",
"wallets": [
{
"id": "de4034f1-6b0f-4a98-87a5-e459db4d3a03",
"type": "EVM",
"address": "0x9dd3824f045c77bc369485e8f1dd6b452b6be617",
"publicKey": "0x0465434f76c8321f386856c44e735fd365a09d42c1da03489184b651c2052ea1c7b19c54722ed828458c1d271cc590b0818d8c7df423f71e92683f9e819095a8c6"
},
{
"id": "d70f64e4-266a-457e-9cea-eeb42341a975",
"type": "SOLANA",
"address": "EEp7DbBu5yvgf7Pr9W17cATPjCqUxY8K8R3dFbg53a3W",
"publicKey": ""
}
],
"farcasterUsername": "FarcasterUsername",
"authType": "farcaster",
"identifier": "FarcasterUsername"
},
"iat": 1745877709,
"exp": 1745879509,
"sub": "d5358219-38d3-4650-91a8-e338131d1c5e"
}
```
```json External Wallet
{
"data": {
"userId": "d5358219-38d3-4650-91a8-e338131d1c5e",
"wallets": [
{
"id": "de4034f1-6b0f-4a98-87a5-e459db4d3a03",
"type": "EVM",
"address": "0x9dd3824f045c77bc369485e8f1dd6b452b6be617",
"publicKey": "0x0465434f76c8321f386856c44e735fd365a09d42c1da03489184b651c2052ea1c7b19c54722ed828458c1d271cc590b0818d8c7df423f71e92683f9e819095a8c6"
},
{
"id": "d70f64e4-266a-457e-9cea-eeb42341a975",
"type": "SOLANA",
"address": "EEp7DbBu5yvgf7Pr9W17cATPjCqUxY8K8R3dFbg53a3W",
"publicKey": ""
}
],
"externalWalletAddress": "0xaD6b78193b78e23F9aBBB675734f4a2B3559598D",
"authType": "externalWallet",
"identifier": "0xaD6b78193b78e23F9aBBB675734f4a2B3559598D",
"externalWallet": {
"address": "0xaD6b78193b78e23F9aBBB675734f4a2B3559598D",
"type": "EVM",
"provider": "MetaMask"
}
},
"iat": 1745877709,
"exp": 1745879509,
"sub": "d5358219-38d3-4650-91a8-e338131d1c5e"
}
```
Para's JSON Web Keys Set (JWKS) file(s) are available at the following URLs:
| Environment | JWKS URL |
| ----------- | ------------------------------------------------------- |
| SANDBOX | `https://api.sandbox.getpara.com/.well-known/jwks.json` |
| BETA | `https://api.beta.getpara.com/.well-known/jwks.json` |
| PROD | `https://api.getpara.com/.well-known/jwks.json` |
### Using Verification Tokens
For non-Node.js servers or scenarios where you only need to validate a session without importing it, Para provides dedicated verification endpoints:
```typescript
// Client-side: Get a verification token
const verificationToken = await para.getVerificationToken();
// Send to your server
await fetch("/api/verify-session", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ verificationToken }),
});
```
On your server, verify the token against Para's API.
Use your Secret API Key from the Developer Portal to authenticate requests to the verification endpoints. This key is different from the public-facing API Key used in the Para client.
```typescript Node.js
// Server-side verification
app.post("/api/verify-session", async (req, res) => {
const { verificationToken } = req.body;
if (!verificationToken) {
return res.status(400).json({ error: "Missing verification token" });
}
// Set the correct URL based on your environment
const verifyUrl = "https://api.beta.getpara.com/sessions/verify";
try {
const response = await fetch(verifyUrl, {
method: "POST",
headers: {
"content-type": "application/json",
"x-external-api-key": "YOUR_SECRET_API_KEY"
},
body: JSON.stringify({ verificationToken }),
});
if (response.status === 403) {
return res.status(403).json({ error: "Session expired" });
}
const userData = await response.json();
// userData contains { authType, identifier }
// Proceed with authenticated operations
res.status(200).json({ userData });
} catch (error) {
res.status(500).json({ error: "Verification failed" });
}
});
```
```python Python
from flask import Flask, request, jsonify
import requests
app = Flask(__name__)
@app.route('/api/verify-session', methods=['POST'])
def verify_session():
data = request.get_json()
verification_token = data.get("verificationToken")
if not verification_token:
return jsonify({"error": "Missing verification token"}), 400
# Set the correct URL based on your environment
verify_url = "https://api.beta.getpara.com/sessions/verify"
response = requests.post(
url=verify_url,
json={"verificationToken": verification_token},
headers={
"content-type": "application/json",
"x-external-api-key": "YOUR_API_KEY"
}
)
if response.status_code == 403:
return jsonify({"error": "Session expired"}), 403
user_data = response.json()
# user_data contains { authType, identifier }
# Proceed with authenticated operations
return jsonify({"userData": user_data})
if __name__ == '__main__':
app.run(debug=True)
```
The verification endpoints are environment-specific:
| Environment | Verification URL |
| ----------- | ------------------------------------------------- |
| SANDBOX | `https://api.sandbox.getpara.com/sessions/verify` |
| BETA | `https://api.beta.getpara.com/sessions/verify` |
| PROD | `https://api.getpara.com/sessions/verify` |
The verification response will contain the authentication type, identifier, and optionally the OAuth method used:
```typescript
{
authType: "email" | "phone" | "farcaster" | "telegram" | "externalWallet";
identifier: string;
oAuthMethod?: "google" | "x" | "discord" | "facebook" | "apple";
}
```
## Session Management
### Maintaining Session Validity
To extend the validity of an imported session, you can use the `keepSessionAlive` method:
```typescript
try {
const success = await paraServer.keepSessionAlive();
if (!success) {
// Session couldn't be extended
// The client may need to re-authenticate
}
} catch (error) {
console.error("Failed to maintain session:", error);
}
```
You can configure session duration (up to 30 days) in the . This affects how long sessions remain valid without explicit extension.
### Best Practices
1. **Create new Para instances per request**: Initialize a fresh Para Server SDK instance for each request to prevent session conflicts between users.
2. **Secure session transport**: Always use HTTPS and consider additional encryption when transferring sessions between client and server.
3. **Exclude signers when possible**: Use `{ excludeSigners: true }` when exporting sessions if server-side signing isn't needed.
4. **Validate before operations**: Always check if a session is active before performing blockchain operations.
5. **Handle expiration gracefully**: Implement proper error handling for expired sessions, guiding users to re-authenticate when necessary.
6. **Consider session verification tokens**: For simple authentication checks without full session import, use verification tokens.
7. **Set appropriate session duration**: Configure session length in the developer portal based on your security requirements.
## Verifying Wallet Ownership
To verify that a wallet address matches one of your users' embedded wallets, you can send a request to one of the following endpoints:
| Environment | URL |
| ----------- | ------------------------------------------------ |
| SANDBOX | `https://api.sandbox.getpara.com/wallets/verify` |
| BETA | `https://api.beta.getpara.com/wallets/verify` |
| PROD | `https://api.getpara.com/wallets/verify` |
Use your Secret API Key from the Developer Portal to authenticate requests to this endpoint. This key is different from the public-facing API Key used in the Para client.
Pass the address for the wallet in the POST request body:
```typescript Node.js
// Server-side verification
app.post("/api/verify-wallet", async (req, res) => {
const { address } = req.body;
if (!address) {
return res.status(400).json({ error: "Missing address" });
}
// Set the correct URL based on your environment
const verifyUrl = "https://api.beta.getpara.com/wallets/verify";
try {
const response = await fetch(verifyUrl, {
method: "POST",
headers: {
"content-type": "application/json",
"x-external-api-key": "YOUR_SECRET_API_KEY"
},
body: JSON.stringify({ address }),
});
// No matching wallet found
if (response.status === 404) {
return res.status(404).json({ error: `Wallet not found with address: ${address}` });
}
const { walletId } = await response.json();
// Return the matched wallet ID:
res.status(200).json({ walletId });
} catch (error) {
res.status(500).json({ error: "Verification failed" });
}
});
```
## Learn More
For more information about client-side session management and authentication, refer to our web documentation:
## Examples
To learn more about using sessions on the server, check out this example. Each example route will have both pregen and session based routes for you to test with.
# Solana Integration
Source: https://docs.getpara.com/v2/server/guides/solana
Use Para Server SDK with Solana blockchain
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Para Server SDK provides seamless integration with Solana blockchain through both Solana Web3.js and Anchor frameworks. Once you've set up and authenticated your Para Server client, the Solana integration works identically to the client-side implementation.
Before using these integrations, ensure you've completed the server setup by importing a client session or creating a pregenerated wallet. See the for details.
## Installation
Install the required dependencies for your preferred Solana library:
```bash Solana Web3.js
npm install @getpara/solana-web3.js-v1-integration@alpha @solana/web3.js --save-exact
```
```bash Anchor
npm install @getpara/solana-web3.js-v1-integration@alpha @solana/web3.js @coral-xyz/anchor --save-exact
```
## Implementation
### Solana Web3.js Integration
The Para Solana Web3 Signer works seamlessly with the Solana Web3.js library:
```typescript
import { Para as ParaServer } from "@getpara/server-sdk@alpha";
import { ParaSolanaWeb3Signer } from "@getpara/solana-web3.js-v1-integration@alpha";
import { Connection, clusterApiUrl, SystemProgram, LAMPORTS_PER_SOL, PublicKey } from "@solana/web3.js";
// Para server client (already authenticated)
const paraServer = new ParaServer("YOUR_API_KEY");
// Set up Solana connection
const solanaConnection = new Connection(clusterApiUrl("testnet"));
// Create the Para Solana Signer
const solanaSigner = new ParaSolanaWeb3Signer(paraServer, solanaConnection);
// Get the wallet address
const walletAddress = solanaSigner.sender.toBase58();
console.log(`Wallet address: ${walletAddress}`);
// Create and send a transaction
const transaction = await solanaSigner.createTransaction({
instructions: [
SystemProgram.transfer({
fromPubkey: solanaSigner.sender,
toPubkey: new PublicKey("RecipientPublicKeyHere"),
lamports: 0.01 * LAMPORTS_PER_SOL,
}),
],
});
const signature = await solanaSigner.sendTransaction(transaction);
console.log(`Transaction signature: ${signature}`);
```
### Anchor Integration
Para can be used with Anchor by creating an Anchor-compatible wallet wrapper:
```typescript
import { Para as ParaServer } from "@getpara/server-sdk@alpha";
import { ParaSolanaWeb3Signer } from "@getpara/solana-web3.js-v1-integration@alpha";
import { Connection, clusterApiUrl, Transaction, VersionedTransaction } from "@solana/web3.js";
import * as anchor from "@coral-xyz/anchor";
// Para server client (already authenticated)
const paraServer = new ParaServer("YOUR_API_KEY");
// Set up Solana connection
const solanaConnection = new Connection(clusterApiUrl("testnet"));
const solanaSigner = new ParaSolanaWeb3Signer(paraServer, solanaConnection);
// Create an Anchor-compatible wallet
const anchorWallet = {
publicKey: solanaSigner.sender,
signTransaction: async (tx: T): Promise => {
return await solanaSigner.signTransaction(tx);
},
signAllTransactions: async (txs: T[]): Promise => {
return await Promise.all(txs.map((tx) => solanaSigner.signTransaction(tx)));
},
};
// Create the Anchor provider
const provider = new anchor.AnchorProvider(
solanaConnection,
anchorWallet,
{ commitment: "confirmed" }
);
// Now you can use this provider with any Anchor program
const program = new anchor.Program(
YOUR_IDL,
"PROGRAM_ID_HERE",
provider
);
// Interact with your program
await program.methods
.yourProgramMethod()
.accounts({
// Your accounts here
})
.rpc();
```
## Best Practices
* Use higher commitment levels (`confirmed` or `finalized`) for critical transactions
* Implement proper error handling for network failures
* Consider retry logic for Solana RPC endpoints, which can occasionally be unreliable
* Cache account data where appropriate to reduce RPC usage
## Learn More
For detailed examples of using Para with Solana, including SPL token transfers, NFT interactions, and more, refer to our web documentation:
## Examples
Explore our server-side Solana integration examples:
# Para Server SDK
Source: https://docs.getpara.com/v2/server/overview
An introduction to server-side integrations with Para
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Para's Server SDK enables you to perform blockchain operations on the server-side across Node.js, Bun, and Deno environments. The server SDK shares the same core functionality as the web SDK, with authentication being the primary difference.
## Getting Started
## Blockchain Ecosystem Support
Para works seamlessly with major blockchain ecosystems on the server-side, allowing you to leverage Para's authentication alongside chain-specific libraries:
## Authentication Options
Para offers two authentication methods for server-side applications:
## Resources
# Server Setup
Source: https://docs.getpara.com/v2/server/setup
Install and configure the Para Server SDK across Node.js, Bun, and Deno environments
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
The Para Server SDK enables secure server-side blockchain operations across different JavaScript runtime environments.
With nearly identical functionality to client-side implementations, the server SDK allows you to perform signing
operations server-side by either importing client-side sessions or using pregenerated wallets.
## Installation
Install the Para Server SDK in your preferred JavaScript runtime environment:
```bash npm
npm install @getpara/server-sdk@alpha --save-exact
```
```bash yarn
yarn add @getpara/server-sdk@alpha --exact
```
```bash pnpm
pnpm add @getpara/server-sdk@alpha --save-exact
```
```bash bun
bun add @getpara/server-sdk@alpha --exact
```
```bash deno
deno install npm:@getpara/server-sdk@alpha
```
## Initialization
Initialize the Para Server SDK with your API key. The initialization process varies slightly depending on your runtime
environment:
```typescript Node.js
import { Para as ParaServer } from "@getpara/server-sdk@alpha";
// Standard initialization for Node.js
const paraServer = new ParaServer("YOUR_API_KEY");
```
```typescript Bun
import { Para as ParaServer } from "@getpara/server-sdk@alpha";
// Bun requires disabling WebSockets
const paraServer = new ParaServer("YOUR_API_KEY", {
disableWebSockets: true
});
```
```typescript Deno
import { Para as ParaServer } from "@getpara/server-sdk@alpha";
// Deno requires disabling WebSockets
const paraServer = new ParaServer("YOUR_API_KEY", {
disableWebSockets: true,
});
```
If you're using a legacy API key (one without an environment prefix) you must provide the `Environment` as the first argument to the `ParaServer` constructor. You can retrieve your updated API key from the Para Developer Portal at [https://developer.getpara.com/](https://developer.getpara.com/)
## Authentication Methods
After initializing the Para Server SDK, you need to authenticate it before performing any operations. The server SDK
supports two authentication methods:
### Option 1: Importing Client Sessions
Import an active session from your client application to create a server-side replica that can perform the same
operations.
First, in your client application, export the active session to get a serialized string:
```typescript
// Client-side
const serializedSession = await para.exportSession();
// Send this string to your server endpoint
```
This serialiazed sessions tring can then be sent to your server via an API endpoint or any other secure method.
If signing on the server isn't required, you can pass `{ excludeSigners: true }` as an argument to `exportSession` to remove the signer data from the exported wallets:`await para.exportSession({ excludeSigners: true });` before sending it to your server.
Then, on your server, import the serialized session to create a functional server-side client:
```typescript
// Server-side
await paraServer.importSession(serializedSession);
```
With a session no loaded into the para server instance, you can now perform all operations that the Para Server SDK supports.
### Option 2: Using Pregenerated Wallets
Generate and use deterministic wallets server-side without requiring client-side authentication. This pregen wallet will load the para server instance with a wallet that can be used for all operations that the Para Server SDK supports.
```typescript
import { WalletType } from "@getpara/server-sdk@alpha";
await paraServer.createPregenWallet({
type: 'EVM', // or 'SOLANA', 'COSMOS'
pregenId: { email: "user@example.com" },
});
```
When using pregenerated wallets, you'll need to manage the user share of the wallet and store it securely.
Learn more about pregen wallets and their usage on the server in our pregen wallets guide.
## Examples
Explore our example implementations of the Para Server SDK across different runtime environments:
## Troubleshooting
If you encounter issues while setting up the Para Server SDK, check out our troubleshooting guide:
## Next Steps
Once your Para Server SDK is set up and authenticated, you can start performing blockchain operations. The server SDK
provides the same functionality as the client SDK, allowing you to:
# Swift SDK API Reference
Source: https://docs.getpara.com/v2/swift/api/sdk
Comprehensive API reference for the Para Swift SDK (v2.0.0 Alpha)
The Para Swift SDK provides a comprehensive toolkit for integrating non-custodial wallet functionality, passkey-based authentication, and blockchain interactions into your native iOS applications.
## ParaManager Class
The `ParaManager` class is the central component for managing user authentication, wallet operations, and session state.
### Properties
An array of `Wallet` objects currently associated with the authenticated user. This list is updated after operations like `fetchWallets()` or `createWallet()`.
The current session state of the Para SDK (e.g., `.unknown`, `.inactive`, `.active`, `.activeLoggedIn`).
The environment configuration for the Para SDK (e.g., `.beta`, `.prod`).
The API key used for authenticating with Para services.
Indicates if the `ParaManager` and its underlying WebView are initialized and ready to process requests.
### Initialization
Initializes a new `ParaManager` instance.
The Para environment to use (e.g., `.beta`, `.prod`).
Your Para API key.
Optional. Your app's custom URL scheme (e.g., "yourapp\://"). Defaults to the app's bundle identifier. Used for OAuth and other redirection flows.
### Authentication Methods
Starts the authentication (signup or login) process for a user with the specified email or phone number.
The authentication identifier: `.email(String)` for email or `.phone(String)` for a full phone number (e.g., "+15551234567").
An `AuthState` object indicating the next step in the flow (e.g., `.verify` for new users, `.login` for existing users).
Submits the verification code (OTP) received by the user via email or SMS.
The verification code entered by the user.
An `AuthState` object, typically with `stage == .signup`, indicating the user is verified and needs to choose a signup method (passkey or password).
Requests a new verification code to be sent to the user's email or phone.
Checks if a specific signup method (passkey or password) is available based on the current `AuthState`.
The signup method to check (e.g., `.passkey`).
The current `AuthState` (should have `stage == .signup`).
`true` if the method is available, `false` otherwise.
Completes the signup process for a new, verified user using the chosen method (passkey or password). This typically includes creating a passkey/password and the first wallet.
The current `AuthState` (must have `stage == .signup`).
The chosen signup method (`.passkey` or `.password`).
An `ASAuthorizationController` instance for handling Passkey UI operations.
A `WebAuthenticationSession` conforming object for handling web-based authentication (e.g., password setup).
Checks if a specific login method (passkey or password) is available for an existing user.
The login method to check (e.g., `.passkey`).
The current `AuthState` (should have `stage == .login`).
`true` if the method is available, `false` otherwise.
Logs in an existing user, automatically determining and using the preferred available method (passkey or password).
The current `AuthState` (must have `stage == .login`).
An `ASAuthorizationController` instance for Passkey UI.
A `WebAuthenticationSession` for web-based login (e.g., password).
Logs in a user directly using their passkey.
An `ASAuthorizationController` instance for Passkey UI.
Optional. The user's email if known, to help filter passkeys.
Optional. The user's full phone number if known, to help filter passkeys. If both email and phone are nil, the system prompts for any available passkey.
Generates and registers a new passkey for the user. Typically called during signup when `authState.stage == .signup` and `SignupMethod.passkey` is chosen.
The user's identifier (email or full phone number).
The `passkeyId` obtained from `AuthState.passkeyId` when `authState.stage == .signup`.
An `ASAuthorizationController` instance for Passkey UI.
Presents a web URL (typically for password setup/login) using a web authentication session.
The URL to present (e.g., `authState.passwordUrl`).
A `WebAuthenticationSession` conforming object.
The callback URL if authentication was successful via direct callback, or nil on failure/cancellation.
Initiates and handles the entire OAuth flow with the specified provider (e.g., Google, Apple, Discord).
This includes user authentication with the provider, Para account lookup/creation, and passkey setup if it's a new Para user.
The OAuth provider to use (e.g., `.google`).
A `WebAuthenticationSession` for handling the OAuth web flow.
An `ASAuthorizationController` for potential passkey setup.
Returns nothing on success. Throws ParaError or other authentication-related errors on failure.
Logs into Para using an externally managed wallet (e.g., MetaMask).
Information about the external wallet, including its address and type.
### Session Management Methods
Checks if there is an active session and the user is fully authenticated (e.g., passkey/password set up).
`true` if the user is fully logged in, `false` otherwise.
Checks if there is any active session with Para, even if the user is not fully logged in (e.g., pending verification).
`true` if there is any active session, `false` otherwise.
Exports the current session for backup or transfer purposes.
The session data as a string that can be saved and restored later.
Logs out the current user and clears all session data.
Gets the current user's persisted authentication details.
The current user's authentication state, or nil if no user is authenticated. The 'stage' will be set to 'login' for active sessions.
Manually checks and updates the current session state. This method waits for the Para WebView to be ready and updates the session state accordingly.
### Wallet Management Methods
Retrieves all wallets associated with the current user.
An array of `Wallet` objects associated with the user.
Creates a new wallet for the authenticated user. This method initiates wallet creation and refreshes the internal `wallets` list. Observe the `paraManager.wallets` property for the new wallet.
The type of wallet to create (e.g., `.evm`, `.solana`, `.cosmos`).
Whether to skip the distributable key generation step.
Retrieves the email of the currently authenticated user, if available and the session was initiated with an email.
The user's email address.
(Advanced) Distributes a new share for an existing wallet.
The ID of the wallet.
The user share to distribute.
Gets the balance for any wallet type. This unified method works with all wallet types (EVM, Solana, Cosmos).
The ID of the wallet.
Optional token identifier (contract address for EVM, mint address for Solana, etc.).
Optional RPC URL (recommended for Solana and Cosmos to avoid 403/CORS issues).
Optional bech32 prefix for Cosmos (e.g., "juno", "stars").
Optional denom for Cosmos balances (e.g., "ujuno", "ustars").
The balance as a string (format depends on the chain).
Synchronizes required wallets by creating any missing non-optional wallet types. This should be called after successful authentication for new users.
Array of newly created wallets, if any.
### Transfer Methods
Transfers tokens using an EVM wallet. This method builds, signs, and broadcasts the transaction in one call.
The ID of the EVM wallet to use for the transfer.
The recipient address.
The amount to send in wei (smallest unit).
Optional. The chain ID for the EVM network. If not provided, uses the wallet's default chain.
Optional. Custom RPC URL for the transaction. If not provided, uses the default RPC for the chain.
A TransferResult object containing transaction details.
This method is only available for EVM wallets. Solana and Cosmos wallets must use signing methods only.
### Signing Methods
Signs an arbitrary message using the specified wallet.
The ID of the wallet to use for signing.
The raw message string to sign. The SDK will Base64-encode this string before signing.
Optional. Timeout for the signing operation in milliseconds.
A SignatureResult object containing the signature and metadata.
Signs a transaction object using the specified wallet. The method accepts any Encodable transaction type (EVMTransaction, SolanaTransaction, CosmosTransaction) and handles chain-specific formatting internally.
The ID of the wallet to use for signing.
The transaction object to sign. Can be EVMTransaction, SolanaTransaction, or CosmosTransaction.
Optional. Timeout for the signing operation in milliseconds.
A SignatureResult containing the signed transaction. For EVM, this includes the complete RLP-encoded transaction in `signedTransaction`. For Solana/Cosmos, if only a signature is available (e.g., pre-serialized transactions), it's provided in `signedTransaction`. Use `result.transactionData` (computed property) to get the value for broadcasting.
For EVM transactions, the returned `SignatureResult` contains the complete RLP-encoded transaction ready for broadcasting via `eth_sendRawTransaction`.
Signs an RLP-encoded EVM transaction string using the private key of the specified wallet. This method is maintained for backward compatibility.
The ID of the EVM wallet to use for signing.
The RLP-encoded transaction as a hex string. The SDK will Base64-encode this string.
The chain ID of the EVM network.
Optional. Timeout for the signing operation in milliseconds.
The resulting transaction signature as a hex string.
### Two-Factor Authentication (2FA) Methods
Initiates the setup process for 2FA.
Returns `.alreadySetup` if 2FA is already configured, or `.needsSetup(uri: String)` containing the URI to be displayed in an authenticator app (e.g., as a QR code).
Enables 2FA for the user after they have scanned the URI and entered the code from their authenticator app.
The 2FA code from the user's authenticator app.
## MetaMaskConnector Class
The `MetaMaskConnector` class enables integration with MetaMask wallet for external wallet operations and authentication.
### Properties
Indicates whether the connector is currently connected to MetaMask.
Array of connected MetaMask account addresses.
The current chain ID from MetaMask (e.g., "0x1" for Ethereum mainnet, "0xaa36a7" for Sepolia).
### Initialization
Initializes a new `MetaMaskConnector` instance.
The ParaManager instance.
Your app's URL scheme for deep link callbacks.
Configuration object containing app metadata.
### Methods
Processes incoming deep link URLs from MetaMask responses.
The incoming URL to process.
Initiates connection to MetaMask and requests account access. This method is `async throws`. Upon successful connection, the `accounts`, `chainId`, and `isConnected` properties of the `MetaMaskConnector` instance are updated. `ParaManager.loginExternalWallet` is also called internally.
Requests MetaMask to sign a message with the specified account.
The message string to be signed.
The account address to use for signing.
The resulting signature from MetaMask.
Sends a transaction through MetaMask using the specified account.
The transaction object or dictionary containing transaction parameters.
The account address to use for the transaction.
The transaction hash returned by MetaMask.
## Error Types
The main error type for Para SDK operations.
An error occurred while executing JavaScript bridge code.
The JavaScript bridge did not respond in time.
A general error occurred.
Feature not implemented yet.
Errors specific to MetaMask connector operations.
Another MetaMask operation is already in progress.
Failed to construct a valid URL for MetaMask communication.
Received an invalid or unexpected response from MetaMask.
An error reported by the MetaMask app itself (e.g., user rejection code 4001).
MetaMask app is not installed on the device.
Errors specific to CosmosTransaction operations.
Invalid address format.
Invalid amount format.
Invalid denomination.
Invalid chain prefix.
Transaction encoding failed.
Errors related to authorization handling in external wallet operations.
Invalid response received from authorization process.
Authorization was cancelled by the user.
### CosmosChain
Supported Cosmos chains with testnet configurations.
Cosmos Hub network with chain ID "provider", prefix "cosmos" and default denom "uatom" (testnet).
Osmosis network with chain ID "osmo-test-5", prefix "osmo" and default denom "uosmo" (testnet).
Juno network with chain ID "uni-6", prefix "juno" and default denom "ujuno" (testnet).
Stargaze network with chain ID "elgafar-1", prefix "stars" and default denom "ustars" (testnet).
The chain ID for this network.
The bech32 prefix for this chain.
Default denomination for this chain.
Default RPC URL for this chain's testnet.
### CosmosSigningMethod
Signing method for Cosmos transactions.
Legacy Amino JSON signing method for backward compatibility.
Modern Proto/Direct binary signing method (recommended - more efficient).
### CosmosTransaction
A struct representing a Cosmos transaction with messages, fees, and metadata.
The transaction messages.
Transaction fee.
Optional memo.
Preferred signing method (defaults to proto).
Convenience initializer for creating token transfer transactions.
### CosmosSignResponse
Response from a Cosmos transaction signing operation.
The signature information.
The signed document.
### CosmosCoin
Represents a coin amount in Cosmos with denomination and amount.
The token denomination (e.g., "uatom").
The amount as a string in the smallest unit.
Creates a new coin with string amount.
Creates a new coin with UInt64 amount.
### CosmosFee
Represents transaction fees in Cosmos.
Array of fee coins.
Gas limit as a string.
Creates a fee with array of coins.
Convenience initializer for simple fee.
## Type Definitions
### SignatureResult
Result of a message or transaction signing operation.
For transaction signing: Contains the complete signed transaction ready for broadcasting (RLP-encoded for EVM, serialized for other chains).
For message signing: Contains just the signature.
Note: The bridge returns `signature` for messages and `signedTransaction` for transactions, but Swift SDK normalizes both to `signedTransaction` for consistency.
Computed property that returns the signed transaction data for broadcasting.
The ID of the wallet that performed the signing.
The wallet type that signed (e.g., "evm", "solana", "cosmos").
### AuthState
Authentication state returned by authentication operations.
The stage of authentication (`.verify`, `.signup`, `.login`).
The Para userId for the currently authenticating user.
Email address if using email auth.
Phone number if using phone auth.
Display name for the authenticating user.
Profile picture URL for the authenticating user.
Username for the authenticating user.
URL for passkey authentication.
ID for the passkey.
URL for passkey authentication on a known device.
URL for password authentication.
Biometric hints for the user's devices.
### TransferResult
Result returned from a successful EVM transfer operation.
The transaction hash on the blockchain.
The sender address.
The recipient address.
The amount transferred in wei (smallest unit).
The chain ID where the transaction was broadcast.
### Auth
Authentication type for initiateAuthFlow method.
Email-based authentication.
Phone-based authentication with full phone number including country code.
### OAuthProvider
Supported OAuth provider types for authentication.
Google authentication provider.
Discord authentication provider.
Apple authentication provider.
### SignupMethod & LoginMethod
The possible methods for signup when the stage is .signup.
Passkey-based signup.
Password-based signup.
The possible methods for login when the stage is .login.
Passkey-based login.
Password-based login.
Passkey login on a known device.
### Wallet
Represents a wallet associated with a Para user account.
Unique identifier for the wallet.
The type of wallet (e.g., `.evm`, `.solana`, `.cosmos`).
Primary public address of the wallet.
Secondary address (e.g., Cosmos bech32 address for Cosmos wallets).
Public key of the wallet.
Scheme used by the wallet.
Timestamp when the wallet was created.
### WalletType
Supported wallet types for Para wallets.
Ethereum Virtual Machine compatible wallet (Ethereum, Polygon, etc.).
Solana blockchain wallet.
Cosmos ecosystem wallet supporting bech32 addresses.
### MetaMaskConfig
Configuration object for MetaMask connector initialization.
The name of your application as displayed in MetaMask.
Your application's identifier (typically the bundle identifier).
The API version to use (e.g., "1.0").
# Mobile Examples
Source: https://docs.getpara.com/v2/swift/examples
Explore Para's mobile integration examples for Swift
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Para offers a comprehensive Swift example to help you integrate our technology into your iOS applications. Our example repository demonstrates minimal implementation requirements with clean, focused code that you can easily adapt to your specific application needs.
## Para Swift Example
Explore our Swift example showcasing Para integration with various features:
The Swift example demonstrates:
* Native iOS passkey authentication
* Face ID and Touch ID integration
* Wallet creation and management
* Transaction signing across multiple chains
* Session management
* Integration with Apple's Secure Enclave
* iCloud Sharechain support
## Need Something Specific?
Don't see an example for your use case? Para's team is eager to create new examples to help you integrate with different libraries, third-party features, or providers.
# Cosmos Integration
Source: https://docs.getpara.com/v2/swift/guides/cosmos
Sign transactions for Cosmos chains using Para's unified wallet architecture
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
## Quick Start
```swift
import ParaSwift
// Sign a Cosmos transaction
let paraManager = ParaManager(apiKey: "your-api-key")
let wallet = (try await paraManager.fetchWallets()).first { $0.type == .cosmos }!
let transaction = CosmosTransaction(
to: "cosmos1recipient...",
amount: "1000000", // 1 ATOM in micro-units
chainId: "theta-testnet-001", // Cosmos Hub testnet (use "cosmoshub-4" for mainnet)
format: "proto"
)
let result = try await paraManager.signTransaction(
walletId: wallet.id,
transaction: transaction,
chainId: "theta-testnet-001"
)
print("Transaction signed: \(result.signedTransaction)")
```
## Common Operations
### Sign Transactions for Different Chains
```swift
// Sign ATOM transaction on Cosmos Hub testnet
let atomTx = CosmosTransaction(
to: "cosmos1recipient...",
amount: "1000000", // 1 ATOM
denom: "uatom",
chainId: "theta-testnet-001", // Testnet
format: "proto"
)
// Sign OSMO transaction on Osmosis testnet
let osmoTx = CosmosTransaction(
to: "osmo1recipient...",
amount: "1000000", // 1 OSMO
denom: "uosmo",
chainId: "osmo-test-5", // Testnet
format: "proto"
)
// Sign JUNO transaction on Juno mainnet
let junoTx = CosmosTransaction(
to: "juno1recipient...",
amount: "1000000", // 1 JUNO
denom: "ujuno",
chainId: "juno-1",
format: "proto"
)
```
### Sign Transaction
```swift
let transaction = CosmosTransaction(
to: "cosmos1recipient...",
amount: "1000000", // 1 ATOM
denom: "uatom",
memo: "Transfer via Para",
chainId: "theta-testnet-001", // Testnet
format: "proto" // or "amino" for legacy
)
let result = try await paraManager.signTransaction(
walletId: wallet.id,
transaction: transaction,
chainId: "theta-testnet-001",
rpcUrl: "https://rpc.sentry-01.theta-testnet.polypore.xyz"
)
// Cosmos returns: { signBytes, signDoc, format }
print("Signed: \(result.signedTransaction)")
```
### Get Wallet Address
```swift
// Get the Cosmos wallet address for a specific chain
let wallet = (try await paraManager.fetchWallets()).first { $0.type == .cosmos }!
let address = wallet.address // Returns the primary address
print("Cosmos address: \(address ?? "No address")")
```
### Check Balance
```swift
// Native token balance
let balance = try await paraManager.getBalance(
walletId: wallet.id,
rpcUrl: "https://cosmos-rpc.publicnode.com",
chainPrefix: "cosmos" // Important: specify chain prefix for address derivation
)
print("Balance: \(balance) uatom")
// Different chain
let osmoBalance = try await paraManager.getBalance(
walletId: wallet.id,
rpcUrl: "https://osmosis-rpc.publicnode.com",
chainPrefix: "osmo" // Different prefix for Osmosis
)
print("Balance: \(osmoBalance) uosmo")
```
### Sign Message
```swift
let message = "Hello, Cosmos!"
let result = try await paraManager.signMessage(
walletId: wallet.id,
message: message
)
print("Signature: \(result.signedTransaction)")
```
## Supported Networks
### Testnets
| Network | Chain ID | Prefix | Native Token | RPC URL |
| ---------------------- | ------------------- | -------- | ------------ | -------------------------------------------------- |
| **Cosmos Hub Testnet** | `theta-testnet-001` | `cosmos` | `uatom` | `https://rpc.sentry-01.theta-testnet.polypore.xyz` |
| **Osmosis Testnet** | `osmo-test-5` | `osmo` | `uosmo` | `https://rpc.osmotest5.osmosis.zone` |
### Mainnets
| Network | Chain ID | Prefix | Native Token | Decimals | RPC URL |
| -------------- | ---------------- | ---------- | ------------ | -------- | -------------------------------------- |
| **Cosmos Hub** | `cosmoshub-4` | `cosmos` | `uatom` | 6 | `https://cosmos-rpc.publicnode.com` |
| **Osmosis** | `osmosis-1` | `osmo` | `uosmo` | 6 | `https://osmosis-rpc.publicnode.com` |
| **Juno** | `juno-1` | `juno` | `ujuno` | 6 | `https://rpc-juno.itastakers.com` |
| **Stargaze** | `stargaze-1` | `stars` | `ustars` | 6 | `https://rpc.stargaze-apis.com` |
| **Akash** | `akashnet-2` | `akash` | `uakt` | 6 | `https://rpc.akash.forbole.com` |
| **Celestia** | `celestia` | `celestia` | `utia` | 6 | `https://rpc.celestia.pops.one` |
| **dYdX** | `dydx-mainnet-1` | `dydx` | `adydx` | 18 | `https://dydx-dao-api.polkachu.com` |
| **Injective** | `injective-1` | `inj` | `inj` | 18 | `https://injective-rpc.publicnode.com` |
## Complete Example
```swift
import SwiftUI
import ParaSwift
struct CosmosWalletView: View {
@EnvironmentObject var paraManager: ParaManager
@State private var selectedChain = "theta-testnet-001"
@State private var isLoading = false
@State private var result: String?
let wallet: Wallet
let chains = [
"theta-testnet-001": ("Cosmos Hub Testnet", "https://rpc.sentry-01.theta-testnet.polypore.xyz", "uatom", "cosmos"),
"osmo-test-5": ("Osmosis Testnet", "https://rpc.osmotest5.osmosis.zone", "uosmo", "osmo")
]
var body: some View {
VStack(spacing: 20) {
Picker("Chain", selection: $selectedChain) {
ForEach(chains.keys.sorted(), id: \.self) { chainId in
Text(chains[chainId]!.0).tag(chainId)
}
}
.pickerStyle(.segmented)
Text(wallet.address ?? "No address")
.font(.system(.caption, design: .monospaced))
Button(action: signTransaction) {
Text(isLoading ? "Signing..." : "Sign Transaction for \(chains[selectedChain]!.0)")
}
.disabled(isLoading)
if let result = result {
Text(result)
.font(.caption)
}
}
.padding()
}
private func signTransaction() {
isLoading = true
Task {
do {
let chainInfo = chains[selectedChain]!
let transaction = CosmosTransaction(
to: "\(chainInfo.3)1recipient...", // Uses chain prefix
amount: "1000000", // 1 token in micro-units
denom: chainInfo.2,
memo: "Test transaction from Swift",
chainId: selectedChain,
format: "proto"
)
let txResult = try await paraManager.signTransaction(
walletId: wallet.id,
transaction: transaction,
chainId: selectedChain,
rpcUrl: chainInfo.1
)
result = "Signed! Signature: \(txResult.signedTransaction)"
} catch {
result = "Error: \(error)"
}
isLoading = false
}
}
}
```
## Proto vs Amino Formats
```swift
// Modern Proto format (recommended)
let protoTx = CosmosTransaction(
to: "cosmos1recipient...",
amount: "1000000",
denom: "uatom",
format: "proto",
chainId: "theta-testnet-001" // Testnet
)
// Legacy Amino format (compatibility)
let aminoTx = CosmosTransaction(
to: "cosmos1recipient...",
amount: "1000000",
denom: "uatom",
format: "amino",
chainId: "theta-testnet-001" // Testnet
)
// Use convenience constructor
let simpleTx = CosmosTransaction(
to: "cosmos1recipient...",
amount: "1000000",
denom: "uatom",
chainId: "theta-testnet-001"
)
```
# EVM Integration
Source: https://docs.getpara.com/v2/swift/guides/evm
Transfer ETH and interact with EVM chains using Para's unified wallet architecture
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
## Quick Start
### Transfer
Para handles signing and broadcasting in one call:
```swift
import ParaSwift
let paraManager = ParaManager(apiKey: "your-api-key")
let wallet = (try await paraManager.fetchWallets()).first { $0.type == .evm }!
// Send ETH - Para signs and broadcasts
let result = try await paraManager.transfer(
walletId: wallet.id,
to: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
amount: "1000000000000000", // 0.001 ETH in wei
chainId: "11155111", // Optional: Sepolia testnet (defaults to wallet's chain)
rpcUrl: nil // Optional: override default RPC
)
print("Transaction sent: \(result.hash)")
print("From: \(result.from), To: \(result.to)")
print("Amount: \(result.amount), Chain: \(result.chainId)")
```
### Advanced Control
Sign with Para, then broadcast yourself for custom gas/RPC settings:
```swift
import ParaSwift
import BigInt
// Step 1: Sign transaction with Para
let transaction = EVMTransaction(
to: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
value: BigUInt("1000000000000000")!,
gasLimit: BigUInt("21000")!
)
let result = try await paraManager.signTransaction(
walletId: wallet.id,
transaction: transaction,
chainId: "11155111" // Sepolia testnet
)
// Step 2: Broadcast using your preferred method (e.g., web3.swift)
// The transactionData property provides the complete signed transaction
// let txHash = try await broadcastWithWeb3Swift(result.transactionData)
```
## Common Operations
### Send ETH
```swift
// Para handles everything - signing and broadcasting
let result = try await paraManager.transfer(
walletId: wallet.id,
to: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
amount: "1000000000000000", // 0.001 ETH in wei
chainId: "11155111", // Optional: Sepolia testnet
rpcUrl: nil // Optional: custom RPC URL
)
print("Transaction hash: \(result.hash)")
print("From: \(result.from), To: \(result.to), Chain: \(result.chainId)")
```
### Sign Transaction
```swift
import BigInt
let transaction = EVMTransaction(
to: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
value: BigUInt("1000000000000000")!,
gasLimit: BigUInt("21000")!,
maxPriorityFeePerGas: BigUInt("1000000000")!,
maxFeePerGas: BigUInt("3000000000")!,
nonce: BigUInt("0")!,
chainId: BigUInt("11155111")!, // Sepolia
type: 2
)
let result = try await paraManager.signTransaction(
walletId: wallet.id,
transaction: transaction,
chainId: "11155111"
)
// The transactionData property returns the complete RLP-encoded transaction
// ready for broadcasting via eth_sendRawTransaction
print("Signed transaction: \(result.transactionData)")
// For backward compatibility, signature field still contains the raw signature
print("Raw signature: \(result.signedTransaction)")
```
### Check Balance
```swift
// Native ETH balance
let ethBalance = try await paraManager.getBalance(walletId: wallet.id)
// ERC-20 token balance
let tokenBalance = try await paraManager.getBalance(
walletId: wallet.id,
token: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" // USDC
)
```
### Sign Message
```swift
let message = "Hello, Ethereum!"
let result = try await paraManager.signMessage(
walletId: wallet.id,
message: message
)
print("Signature: \(result.signedTransaction)")
```
## Networks
### Testnets
| Network | Chain ID | Native Token | Default RPC |
| ------------------ | ---------- | ------------ | --------------------------------------------- |
| **Sepolia** | `11155111` | ETH | `https://ethereum-sepolia-rpc.publicnode.com` |
| **Polygon Mumbai** | `80001` | MATIC | `https://rpc-mumbai.maticvigil.com` |
| **Base Sepolia** | `84532` | ETH | `https://sepolia.base.org` |
### Mainnets
| Network | Chain ID | Native Token | Default RPC |
| ------------ | -------- | ------------ | ------------------------------ |
| **Ethereum** | `1` | ETH | `https://eth.llamarpc.com` |
| **Polygon** | `137` | MATIC | `https://polygon-rpc.com` |
| **Base** | `8453` | ETH | `https://mainnet.base.org` |
| **Arbitrum** | `42161` | ETH | `https://arb1.arbitrum.io/rpc` |
| **Optimism** | `10` | ETH | `https://mainnet.optimism.io` |
## Complete Example
```swift
import SwiftUI
import ParaSwift
import BigInt
struct EVMWalletView: View {
@EnvironmentObject var paraManager: ParaManager
@State private var isLoading = false
@State private var txHash: String?
let wallet: Wallet
var body: some View {
VStack(spacing: 20) {
Text(wallet.address ?? "No address")
.font(.system(.caption, design: .monospaced))
Button(action: sendETH) {
Text(isLoading ? "Sending..." : "Send 0.001 ETH")
}
.disabled(isLoading)
if let txHash = txHash {
Text("Sent: \(txHash)")
.font(.caption)
}
}
.padding()
}
private func sendETH() {
isLoading = true
Task {
do {
let result = try await paraManager.transfer(
walletId: wallet.id,
to: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
amount: "1000000000000000",
chainId: "11155111", // Optional: Sepolia testnet
rpcUrl: nil // Optional: custom RPC
)
txHash = result.hash
} catch {
print("Error: \(error)")
}
isLoading = false
}
}
}
```
## Smart Contract Interaction
**Transaction Data**: For EVM transactions, `result.transactionData` returns the complete RLP-encoded signed transaction that's ready to broadcast via `eth_sendRawTransaction`. The `signature` field contains just the raw signature for backward compatibility.
```swift
// Call a contract function
let contractTransaction = EVMTransaction(
to: "0x123abc...", // Contract address
value: BigUInt(0),
gasLimit: BigUInt("150000")!,
maxPriorityFeePerGas: BigUInt("1000000000")!,
maxFeePerGas: BigUInt("3000000000")!,
nonce: BigUInt("0")!,
chainId: BigUInt("11155111")!, // Sepolia testnet
smartContractAbi: """
[{
"inputs": [{"name":"num","type":"uint256"}],
"name": "store",
"type": "function"
}]
""",
smartContractFunctionName: "store",
smartContractFunctionArgs: ["42"],
type: 2
)
let result = try await paraManager.signTransaction(
walletId: wallet.id,
transaction: contractTransaction,
chainId: "11155111" // Sepolia testnet
)
// Use result.transactionData to get the complete signed transaction
print("Signed transaction: \(result.transactionData)")
```
### ERC20 Token Transfer
```swift
// Transfer USDC on Sepolia testnet
let usdcTransaction = EVMTransaction(
to: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", // USDC contract on Sepolia
value: BigUInt(0), // No ETH value for token transfer
gasLimit: BigUInt("100000")!, // Higher gas limit for token transfers
maxPriorityFeePerGas: BigUInt("1000000000")!,
maxFeePerGas: BigUInt("3000000000")!,
nonce: BigUInt("0")!,
chainId: BigUInt("11155111")!, // Sepolia testnet
smartContractAbi: """
[{
"inputs": [
{"name": "recipient", "type": "address"},
{"name": "amount", "type": "uint256"}
],
"name": "transfer",
"outputs": [{"name": "", "type": "bool"}],
"type": "function"
}]
""",
smartContractFunctionName: "transfer",
smartContractFunctionArgs: [
"0xcb53FD7529d257D40618992993c5F863f5d86572", // Recipient address
"100000" // 0.1 USDC (6 decimals, so 100000 = 0.1)
],
type: 2
)
// Sign the transaction - Para bridge handles ABI encoding
let result = try await paraManager.signTransaction(
walletId: wallet.id,
transaction: usdcTransaction,
chainId: "11155111"
)
// The signed transaction is ready to broadcast
// Para encodes the function call data using the provided ABI
print("Signed ERC20 transfer: \(result.transactionData)")
// You can broadcast using your preferred method
// The transaction will transfer 0.1 USDC to the recipient
```
# External Wallets
Source: https://docs.getpara.com/v2/swift/guides/external-wallets
Instructions for using external wallets with the ParaSwift SDK.
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label}) => {
e.currentTarget.querySelector("#underline").style.height = "2px";
}} onMouseLeave={e => {
e.currentTarget.querySelector("#underline").style.height = "1px";
}}>
{label}
;
## Overview
This guide outlines how to integrate and use external cryptocurrency wallets with the ParaSwift SDK. With the unified wallet architecture, the Swift SDK has removed all blockchain-specific dependencies and now provides a streamlined approach to external wallet connectivity.
The SDK supports external wallets like MetaMask through deep-linking protocols and provides built-in authentication and transaction signing capabilities. You can also use external wallet addresses to authenticate with Para.
**Unified Wallet Architecture:** The Swift SDK v2 has removed all blockchain-specific packages (web3swift, solana-swift, etc.) and now uses only BigInt for handling blockchain values. This provides a cleaner, more maintainable architecture while still supporting all necessary external wallet operations.
The SDK now has minimal dependencies:
* **BigInt**: For handling large blockchain numbers (Wei, gas values, etc.)
* **PhoneNumberKit**: For phone number validation in authentication flows
## Deep Linking
The ParaSwift SDK communicates with other apps via deep linking. To enable deep linking for your application, you'll need to configure your app appropriately.
### Configure URL Schemes
First, you need to configure your app to handle custom URL schemes:
1. Open your app's Info.plist file
2. Add a new entry for `LSApplicationQueriesSchemes` as an array
3. Add the URL schemes of supported wallets as strings to this array
```xml
LSApplicationQueriesSchemes
metamask
```
### Configure URL Types
Next, you need to set up URL Types to handle callbacks from external wallets:
1. In Xcode, select your app target
2. Go to "Info" tab
3. Expand "URL Types"
4. Click the "+" button to add a new URL Type
5. Set the "Identifier" to your app's bundle identifier
6. Set the "URL Schemes" to a unique identifier for your app
**Important:** You must use a unique URL scheme to avoid conflicts with other apps. We recommend using reverse-domain notation like `com.yourcompany.yourapp`.
In our examples we use `paraswift`, but you **must replace this** with your own unique scheme:
```xml
CFBundleURLTypes
CFBundleURLSchemes
com.yourcompany.yourapp
```
## MetaMask Connector
### Setup
Create and initialize the MetaMask connector with your app's configuration:
```swift
import ParaSwift
// Create MetaMask configuration
let appScheme = "com.yourcompany.yourapp" // Replace with your unique scheme
let metaMaskConfig = MetaMaskConfig(
appName: "Your App Name",
appId: appScheme,
apiVersion: "1.0"
)
// Initialize the connector
let metaMaskConnector = MetaMaskConnector(
para: paraManager,
appUrl: "https://\(appScheme)",
config: metaMaskConfig
)
```
### Handle Deep Links
Handle incoming deep links from MetaMask by adding a URL handler in your SwiftUI app:
```swift
@main
struct YourApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL { url in
// Handle MetaMask deep links with URL validation
if url.scheme == "yourapp", url.host == "mmsdk" {
MetaMaskConnector.handleDeepLink(url)
}
}
}
}
}
```
The deep link handling has been simplified to use a static method. You no longer need to maintain a MetaMaskConnector instance at the app level just for handling deep links.
### Connecting
To connect to MetaMask and retrieve the user's accounts:
```swift
do {
try await metaMaskConnector.connect()
// MetaMask will automatically attempt Para authentication after connection
// Access connected accounts via metaMaskConnector.accounts
} catch {
// Handle connection error
}
```
**Automatic Authentication:** The MetaMask connector automatically attempts to authenticate with Para after a successful connection. This streamlines the user experience by reducing the number of manual steps required.
### Sign Message
To request a signature for a message from MetaMask:
```swift
guard let account = metaMaskConnector.accounts.first else { return }
do {
let signature = try await metaMaskConnector.signMessage(
"Message to sign! Hello World",
account: account
)
// Use the signature
} catch {
// Handle signing error
}
```
### Send Transaction
To send a transaction through MetaMask using the EVMTransaction model:
```swift
import BigInt
guard let account = metaMaskConnector.accounts.first else { return }
do {
// Convert 0.001 ETH to wei (1 ETH = 10^18 wei)
let valueInWei = BigUInt("1000000000000000")! // 0.001 ETH in wei
let gasLimit = BigUInt(100000)
let transaction = EVMTransaction(
to: "0x13158486860B81Dee9e43Dd0391e61c2F82B577F",
value: valueInWei,
gasLimit: gasLimit
)
let txHash = try await metaMaskConnector.sendTransaction(transaction, account: account)
// Transaction sent successfully, use txHash
} catch {
// Handle transaction error
}
```
### Alternative: Raw Transaction Format
You can also use a raw transaction dictionary format:
```swift
guard let account = metaMaskConnector.accounts.first else { return }
let transaction: [String: String] = [
"from": account,
"to": "0x13158486860B81Dee9e43Dd0391e61c2F82B577F",
"value": "0x38D7EA4C68000", // 0.001 ETH in wei (hex)
"gasLimit": "0x186A0" // 100000 in hex
]
do {
let txHash = try await metaMaskConnector.sendTransaction(
transaction,
account: account
)
// Transaction sent successfully
} catch {
// Handle transaction error
}
```
### Properties
The MetaMask connector provides several useful properties:
```swift
// Check if connected to MetaMask
let isConnected = metaMaskConnector.isConnected
// Get list of connected accounts
let accounts = metaMaskConnector.accounts
// Get current chain ID (e.g., "0x1" for Ethereum mainnet)
let chainId = metaMaskConnector.chainId
```
### Supported Networks
The MetaMask connector works with any EVM-compatible network that MetaMask supports. Common networks include:
| Network | Chain ID | Description |
| ---------------- | ---------- | --------------------- |
| Ethereum Mainnet | `0x1` | Main Ethereum network |
| Sepolia Testnet | `0xaa36a7` | Ethereum test network |
| Polygon | `0x89` | Polygon mainnet |
| Arbitrum One | `0xa4b1` | Arbitrum Layer 2 |
| Base | `0x2105` | Base Layer 2 |
## Working with BigUInt Values
Since the Swift SDK now uses BigInt for handling blockchain values, here are some utility patterns for working with Ether and Wei conversions:
```swift
import BigInt
// Convert Ether to Wei (multiply by 10^18)
func etherToWei(_ ether: String) -> BigUInt? {
guard let etherDecimal = Decimal(string: ether) else { return nil }
let weiDecimal = etherDecimal * pow(10, 18)
return BigUInt(weiDecimal.description.components(separatedBy: ".").first ?? "")
}
// Convert Wei to Ether (divide by 10^18)
func weiToEther(_ wei: BigUInt) -> String {
let weiDecimal = Decimal(string: wei.description) ?? 0
let etherDecimal = weiDecimal / pow(10, 18)
return etherDecimal.description
}
// Usage examples
let oneEthInWei = etherToWei("1.0")! // 1000000000000000000
let halfEthInWei = etherToWei("0.5")! // 500000000000000000
let pointZeroOneEthInWei = etherToWei("0.01")! // 10000000000000000
// Convert back to Ether
let ethAmount = weiToEther(BigUInt("1000000000000000000")!) // "1"
```
These utility functions help you convert between human-readable Ether amounts and the Wei values required by the blockchain. Always validate decimal inputs to prevent runtime crashes.
## Advanced Configuration
### Customizing MetaMask Connection
You can customize various aspects of the MetaMask connection by modifying the MetaMaskConfig:
```swift
let metaMaskConfig = MetaMaskConfig(
appName: "Your App Name",
appId: bundleId,
apiVersion: "1.0"
)
```
### Working with Different Networks
MetaMask supports multiple networks. You can check the current network and adjust your app's behavior accordingly:
```swift
switch metaMaskConnector.chainId {
case "0x1":
// Ethereum Mainnet
case "0x5":
// Goerli Testnet
case "0x89":
// Polygon
default:
// Other network
}
```
## External Wallet Authentication with Para
Para supports authentication using external wallets like MetaMask. This allows users to log into Para using their existing wallet credentials.
### Using External Wallet for Para Login
After connecting to MetaMask, you can use the wallet address to authenticate with Para:
```swift
// First, connect to MetaMask
try await metaMaskConnector.connect()
// Get the first connected account
guard let account = metaMaskConnector.accounts.first else {
throw ParaError.error("No MetaMask accounts found")
}
// Create external wallet info for Para authentication
let externalWallet = ExternalWalletInfo(
address: account,
type: .evm,
provider: "metamask",
isConnectionOnly: false // Set to false for full authentication
)
// Login to Para using the external wallet
try await paraManager.loginExternalWallet(wallet: externalWallet)
// User is now logged into Para with their MetaMask wallet
```
### Complete External Wallet Login Example
Here's a complete example showing external wallet authentication:
```swift
import SwiftUI
import ParaSwift
struct ExternalWalletLoginView: View {
@EnvironmentObject var paraManager: ParaManager
@EnvironmentObject var appRootManager: AppRootManager
@StateObject private var metaMaskConnector: MetaMaskConnector
@State private var isConnecting = false
@State private var errorMessage: String?
init(paraManager: ParaManager) {
let config = MetaMaskConfig(
appName: "Your App",
appId: "com.yourcompany.yourapp", // Use your unique app scheme
apiVersion: "1.0"
)
_metaMaskConnector = StateObject(wrappedValue: MetaMaskConnector(
para: paraManager,
appUrl: "https://com.yourcompany.yourapp", // Use your unique app scheme
config: config
))
}
var body: some View {
VStack(spacing: 20) {
Image("metamask")
.resizable()
.frame(width: 80, height: 80)
Text("Connect with MetaMask")
.font(.title2)
.fontWeight(.semibold)
Text("Use your existing MetaMask wallet to log into Para")
.font(.body)
.foregroundColor(.secondary)
.multilineTextAlignment(.center)
if let errorMessage = errorMessage {
Text(errorMessage)
.foregroundColor(.red)
.font(.caption)
.padding()
.background(Color.red.opacity(0.1))
.cornerRadius(8)
}
Button {
connectAndLogin()
} label: {
if isConnecting {
ProgressView()
.tint(.white)
} else {
Text("Connect MetaMask")
.fontWeight(.semibold)
}
}
.frame(maxWidth: .infinity)
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
.disabled(isConnecting)
}
.padding()
.navigationTitle("External Wallet")
}
private func connectAndLogin() {
isConnecting = true
errorMessage = nil
Task {
do {
// Connect to MetaMask
try await metaMaskConnector.connect()
// Get the first account
guard let account = metaMaskConnector.accounts.first else {
throw ParaError.error("No MetaMask accounts found")
}
// Create external wallet info
let externalWallet = ExternalWalletInfo(
address: account,
type: .evm,
provider: "metamask",
isConnectionOnly: false // Set to false for full authentication
)
// Login to Para using external wallet
try await paraManager.loginExternalWallet(wallet: externalWallet)
// Navigate to home on success
appRootManager.currentRoot = .home
} catch {
errorMessage = error.localizedDescription
}
isConnecting = false
}
}
}
```
# Wallet Pregeneration & Claiming
Source: https://docs.getpara.com/v2/swift/guides/pregen
Pregenerate and claim wallets in your Swift applications (Coming Soon)
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
**Coming Soon**: Wallet pregeneration and claiming functionality for Swift applications is currently in development and will be available soon. Reach out to us at if you'd like to get early access.
Para will soon provide support for wallet pregeneration and claiming in Swift applications, allowing you to create blockchain wallets for users before they complete authentication.
# Swift Session Management
Source: https://docs.getpara.com/v2/swift/guides/sessions
Guide to managing authentication sessions in Para for Swift applications
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
Para Swift SDK provides robust session management, automatically tracking authentication states and ensuring secure, seamless interactions. Effective session management is critical for security, usability, and reliability of your application.
## Session States
Para manages sessions using the `ParaSessionState` enum:
* `unknown`: Initial state before the status is determined.
* `inactive`: SDK initialized but no active session.
* `active`: Session is active but user not fully logged in.
* `activeLoggedIn`: User is fully logged in with an active session.
### Observing Session States
Utilize SwiftUI's Combine or other state management tools to observe changes:
```swift
@StateObject private var paraManager: ParaManager
.onChange(of: paraManager.sessionState) { newState in
switch newState {
case .activeLoggedIn:
print("User authenticated")
case .inactive:
print("Session inactive")
default:
print("Session state: \(newState)")
}
}
```
## Session Duration
The Para session length is `2 hours` by default, but can be configured to up to 30 days. To configure this parameter, please visit the Configuration section of the . A user signing a message or transaction extends the session by the duration of the session length.
## Key Session Methods
* `isSessionActive() async throws -> Bool`: Checks if the session is currently valid before performing authenticated operations.
* `isFullyLoggedIn() async throws -> Bool`: Checks if the user is fully logged in with an active session.
* `exportSession() async throws -> String`: Exports session state as a string that can be used for advanced integration scenarios.
* `logout() async throws`: Clears the current session, removes all website data from the WebView, and resets the session state to inactive.
## Maintaining Active Sessions
For long-running applications, check session status before performing sensitive operations:
```swift
func performSensitiveOperation() {
Task {
do {
if try await paraManager.isSessionActive() {
// Proceed with sensitive operation
try await signTransaction(...)
} else {
// Handle session expiration - redirect to login
navigateToLogin()
}
} catch {
await MainActor.run {
isLoggedIn = false
}
}
}
}
```
## Refreshing Expired Sessions
When a session has expired, Para recommends initiating a full authentication flow rather than trying to refresh the session.
For Swift applications, always call `logout()` before reinitiating authentication when a session has expired to ensure all stored data is properly cleared.
```swift
import ParaSwift
func handleSessionExpiration() async {
do {
// When session expires, first clear storage
try await paraManager.logout()
// Then redirect to authentication screen
await MainActor.run {
// Navigate to authentication screen
}
} catch {
// Handle error
}
}
```
## Background Security
Clear sensitive data when app goes to background by logging out:
```swift
class AppDelegate: NSObject, UIApplicationDelegate {
func applicationDidEnterBackground(_ application: UIApplication) {
Task {
try? await paraManager.logout()
}
}
}
```
## Exporting Sessions to Your Server
In some advanced scenarios, you may need to export the session state:
```swift
func sendSessionToServer() async throws {
do {
// Export session without signing capabilities
let sessionString = try await paraManager.exportSession()
// Create URL request
var request = URLRequest(url: URL(string: "https://your-api.com/sessions")!)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
// Create request body
let body: [String: Any] = ["session": sessionString]
request.httpBody = try JSONSerialization.data(withJSONObject: body)
// Send request
let (_, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
throw URLError(.badServerResponse)
}
// Handle success
} catch {
// Handle error
throw error
}
}
```
## Best Practices
### Check Sessions on App Launch
Verify session status when your app starts to determine if users need to reauthenticate:
```swift
import SwiftUI
import ParaSwift
class AppStartupManager: ObservableObject {
@Published var isLoggedIn = false
let paraManager: ParaManager
init(paraManager: ParaManager) {
self.paraManager = paraManager
checkSessionOnLaunch()
}
func checkSessionOnLaunch() {
Task {
do {
let isActive = try await paraManager.isSessionActive()
await MainActor.run {
if isActive {
// User is logged in
isLoggedIn = true
} else {
// Session not active, clear any lingering data
Task {
try? await paraManager.logout()
}
isLoggedIn = false
}
}
} catch {
await MainActor.run {
isLoggedIn = false
}
}
}
}
}
```
### Handle App Lifecycle Changes
Swift apps can be backgrounded and foregrounded, which may affect session status:
```swift
import SwiftUI
import ParaSwift
class LifecycleManager: ObservableObject {
let paraManager: ParaManager
init(paraManager: ParaManager) {
self.paraManager = paraManager
// Register for foreground notifications
NotificationCenter.default.addObserver(
self,
selector: #selector(appMovedToForeground),
name: UIApplication.willEnterForegroundNotification,
object: nil
)
}
@objc func appMovedToForeground() {
// App came to foreground, check session
checkSession()
}
func checkSession() {
Task {
let isActive = try? await paraManager.isSessionActive()
if isActive != true {
try? await paraManager.logout()
await MainActor.run {
// Navigate to login screen
}
}
}
}
deinit {
NotificationCenter.default.removeObserver(self)
}
}
```
## Next Steps
Explore more advanced features and integrations with Para in Swift:
# Social Login
Source: https://docs.getpara.com/v2/swift/guides/social-login
Instructions for implementing social login with the ParaSwift SDK.
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label}) => {
e.currentTarget.querySelector("#underline").style.height = "2px";
}} onMouseLeave={e => {
e.currentTarget.querySelector("#underline").style.height = "1px";
}}>
{label}
;
## Overview
Social login (OAuth) is integrated directly into Para's unified authentication experience. This guide covers how to implement social login alongside email and phone authentication in a single, streamlined interface. Para supports Google, Apple, and Discord as OAuth providers.
## Prerequisites
## Prerequisites
To use Para, you need an API key. This key authenticates your requests to Para services and is essential for
integration.
Don't have an API key yet? Request access to the to create API keys, manage billing, teams, and more.
You must have the ParaSwift SDK installed and configured in your project. If you haven't done this yet, please refer to our .
## Unified Authentication Approach
Para's recommended approach is to integrate social login directly into your main authentication view alongside email and phone options. This provides users with all authentication methods in one place.
### Environment Setup
Ensure your authentication view has access to the required environment values:
```swift
@Environment(\.webAuthenticationSession) private var webAuthenticationSession
@Environment(\.authorizationController) private var authorizationController
```
## Implementing Social Login
### Integration with Unified Auth View
Social login should be integrated alongside email and phone authentication in your main authentication view. Here's a basic example:
```swift
import SwiftUI
import ParaSwift
import AuthenticationServices
struct AuthView: View {
@EnvironmentObject var paraManager: ParaManager
@Environment(\.webAuthenticationSession) private var webAuthenticationSession
@Environment(\.authorizationController) private var authorizationController
@State private var emailOrPhone = ""
var body: some View {
VStack(spacing: 20) {
// Email/Phone input
TextField("Email or phone number", text: $emailOrPhone)
.textFieldStyle(RoundedBorderTextFieldStyle())
Button("Continue") {
handleEmailPhoneAuth()
}
.buttonStyle(.borderedProminent)
// Divider
Text("or")
.foregroundColor(.gray)
// Social login buttons
Button("Continue with Google") {
handleSocialLogin(.google)
}
Button("Continue with Apple") {
handleSocialLogin(.apple)
}
Button("Continue with Discord") {
handleSocialLogin(.discord)
}
}
.padding()
}
}
```
### Handling Social Login
Implement the social login handler that manages the OAuth flow:
```swift
private func handleSocialLogin(_ provider: OAuthProvider) {
Task {
do {
try await paraManager.handleOAuth(
provider: provider,
webAuthenticationSession: webAuthenticationSession,
authorizationController: authorizationController
)
// OAuth flow completed successfully
// User is now logged in and wallets are available
print("User authenticated successfully")
// Navigate to authenticated area of your app
} catch {
// Handle OAuth error
print("OAuth error: \(error.localizedDescription)")
}
}
}
```
The `handleOAuth` method:
* Authenticates the user with the OAuth provider
* Checks if a Para account exists for the user
* For new users: creates a Para account and sets up a passkey automatically
* For existing users: logs them in directly
* Returns nothing on success, throws errors on failure
### Creating Social Login Buttons
Create buttons for each OAuth provider:
```swift
// Google Login
Button("Continue with Google") {
handleSocialLogin(.google)
}
// Apple Login
Button("Continue with Apple") {
handleSocialLogin(.apple)
}
// Discord Login
Button("Continue with Discord") {
handleSocialLogin(.discord)
}
```
## Available OAuth Providers
The ParaSwift SDK supports the following OAuth providers:
* Google (`.google`)
* Apple (`.apple`)
* Discord (`.discord`)
## Key Points
* Social login is handled through the `handleOAuth` method
* The method manages the complete OAuth flow including user authentication, Para account creation/lookup, and passkey setup for new users
* For existing users, it logs them in directly
* The SDK supports Google, Apple, and Discord as OAuth providers
* Social login should be integrated with email/phone authentication for a unified experience
## Next Steps
After implementing social login, you might want to:
1. for new users
2. for session management
3. as an additional security layer
# Solana Integration
Source: https://docs.getpara.com/v2/swift/guides/solana
Sign Solana transactions using Para's unified wallet architecture
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
## Quick Start
```swift
import ParaSwift
// Sign a Solana transaction
let paraManager = ParaManager(apiKey: "your-api-key")
let wallet = (try await paraManager.fetchWallets()).first { $0.type == .solana }!
let transaction = try SolanaTransaction(
to: "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM",
lamports: UInt64(1_000_000), // 0.001 SOL
feePayer: nil, // Uses wallet as fee payer
recentBlockhash: nil // Fetched automatically with RPC URL
)
let result = try await paraManager.signTransaction(
walletId: wallet.id,
transaction: transaction,
chainId: nil, // Not needed for Solana
rpcUrl: "https://api.devnet.solana.com"
)
print("Transaction signed: \(result.signedTransaction)")
```
## Common Operations
### Sign Transaction
```swift
let transaction = try SolanaTransaction(
to: "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM",
lamports: UInt64(1_000_000), // 0.001 SOL
feePayer: nil, // Uses wallet as fee payer
recentBlockhash: nil // Fetched automatically with RPC URL
)
let result = try await paraManager.signTransaction(
walletId: wallet.id,
transaction: transaction,
chainId: nil, // Not needed for Solana
rpcUrl: "https://api.devnet.solana.com"
)
print("Signed: \(result.signedTransaction)")
```
### Check Balance
```swift
let balance = try await paraManager.getBalance(
walletId: wallet.id,
token: nil, // Native SOL
rpcUrl: "https://api.devnet.solana.com"
)
// Convert lamports to SOL
let lamports = Double(balance) ?? 0
let sol = lamports / 1_000_000_000
print("Balance: \(String(format: "%.4f", sol)) SOL")
```
### Sign Message
```swift
let message = "Hello, Solana!"
let result = try await paraManager.signMessage(
walletId: wallet.id,
message: message
)
print("Signature: \(result.signedTransaction)")
```
## Networks
### Testnets
| Network | RPC URL | Native Token |
| ----------- | -------------------------------- | ------------ |
| **Devnet** | `https://api.devnet.solana.com` | SOL |
| **Testnet** | `https://api.testnet.solana.com` | SOL |
### Mainnets
| Network | RPC URL | Native Token | Network Type |
| ----------- | -------------------------------------------------- | ------------ | ------------ |
| **Mainnet** | `https://api.mainnet-beta.solana.com` | SOL | Production |
| **Alchemy** | `https://solana-mainnet.g.alchemy.com/v2/YOUR_KEY` | SOL | Production |
## Complete Example
```swift
import SwiftUI
import ParaSwift
struct SolanaWalletView: View {
@EnvironmentObject var paraManager: ParaManager
@State private var isLoading = false
@State private var signature: String?
let wallet: Wallet
private let rpcUrl = "https://api.devnet.solana.com"
var body: some View {
VStack(spacing: 20) {
Text(wallet.address ?? "No address")
.font(.system(.caption, design: .monospaced))
Button(action: signTransaction) {
Text(isLoading ? "Signing..." : "Sign Transaction")
}
.disabled(isLoading)
if let signature = signature {
Text("Signed: \(signature)")
.font(.caption)
}
}
.padding()
}
private func signTransaction() {
isLoading = true
Task {
do {
let transaction = try SolanaTransaction(
to: "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM",
lamports: 1_000_000, // 0.001 SOL
feePayer: nil,
recentBlockhash: nil
)
let result = try await paraManager.signTransaction(
walletId: wallet.id,
transaction: transaction,
chainId: nil, // Not needed for Solana
rpcUrl: rpcUrl
)
signature = result.signedTransaction
} catch {
print("Error: \(error)")
}
isLoading = false
}
}
}
```
## Advanced Transaction Options
```swift
// Transaction with compute budget
let transaction = try SolanaTransaction(
to: "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM",
lamports: UInt64(1_000_000),
computeUnitLimit: UInt32(200_000), // Set compute budget
computeUnitPrice: UInt64(1_000) // Set priority fee
)
// Transaction with custom blockhash
let transaction = try SolanaTransaction(
to: "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM",
lamports: UInt64(1_000_000),
recentBlockhash: "custom_blockhash",
feePayer: wallet.address
)
```
## Pre-Serialized Transactions
Sign base64-encoded Solana transactions from dApps or backend services.
```swift
let base64Transaction = "AQABA8GlkLb8bd/L6i5/YftGpxyig/iBvof2eNEF9WPF2o0Z..."
let result = try await paraManager.signSolanaSerializedTransaction(
walletId: wallet.id,
base64Tx: base64Transaction
)
```
### Use Cases
```swift
// From dApp
let serializedTx = dApp.getSerializedTransaction()
let signature = try await paraManager.signSolanaSerializedTransaction(
walletId: wallet.id,
base64Tx: serializedTx
)
// From backend
let preparedTx = await backend.prepareTransaction()
let result = try await paraManager.signSolanaSerializedTransaction(
walletId: wallet.id,
base64Tx: preparedTx.serialized
)
```
Accepts base64-encoded bytes from `transaction.serializeMessage()` or compatible Solana SDKs.
# Swift SDK Overview
Source: https://docs.getpara.com/v2/swift/overview
Para Swift SDK documentation for iOS wallet integration
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
Para Swift SDK eliminates the complexity of blockchain integration by providing a unified interface for wallet creation, authentication, and multi-chain transactions in iOS applications.
## Quick Start
```swift ViewController.swift
// Initialize Para
let paraManager = ParaManager(
environment: .beta,
apiKey: "YOUR_API_KEY",
appScheme: "yourapp"
)
// Authenticate user
let authState = try await paraManager.initiateAuthFlow(auth: .email("user@example.com"))
// Handle login for existing user
if case .login = authState.stage {
try await paraManager.handleLogin(
authState: authState,
authorizationController: authorizationController,
webAuthenticationSession: webAuthenticationSession
)
}
```
## Sign Transactions
```swift TransactionHandler.swift
// Get wallet
let wallets = try await paraManager.fetchWallets()
let evmWallet = wallets.first { $0.type == .evm }!
let solanaWallet = wallets.first { $0.type == .solana }!
// EVM transaction
let transaction = EVMTransaction(
to: "0x742d35Cc6634C0532925a3b844Bc9e7595f6E2c0",
value: BigUInt("1000000000000000")!, // 0.001 ETH in wei
gasLimit: BigUInt("21000")!
)
let result = try await paraManager.signTransaction(
walletId: evmWallet.id,
transaction: transaction,
chainId: "11155111", // Sepolia
rpcUrl: "https://sepolia.infura.io/v3/YOUR_API_KEY"
)
// Solana message signing
let signature = try await paraManager.signMessage(
walletId: solanaWallet.id,
message: "Hello, Solana!"
)
```
## Next Steps
# Setup
Source: https://docs.getpara.com/v2/swift/setup
Step-by-step guide for integrating the Para Swift SDK into your iOS application
export const Card = ({imgUrl, title, description, href, horizontal = false, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
const baseImageUrl = "https://mintlify.s3-us-west-1.amazonaws.com/getpara";
const handleClick = e => {
e.preventDefault();
if (newTab) {
window.open(href, '_blank', 'noopener,noreferrer');
} else {
window.location.href = href;
}
};
return ;
};
export const Link = ({href, label}) => {
e.currentTarget.querySelector("#underline").style.height = "2px";
}} onMouseLeave={e => {
e.currentTarget.querySelector("#underline").style.height = "1px";
}}>
{label}
;
The Para Swift SDK enables you to integrate secure wallet features including creation, passkey-based authentication, and transaction signing into your iOS applications. This guide covers all necessary steps from installation to implementing authentication flows.
## Prerequisites
To use Para, you need an API key. This key authenticates your requests to Para services and is essential for
integration.
Don't have an API key yet? Request access to the to create API keys, manage billing, teams, and more.
## Install the SDK
1. In your Xcode project, go to **File > Add Packages** or (in your target) **Frameworks, Libraries, and Embedded Content** and click **+**.
2. Enter `https://github.com/getpara/swift-sdk`
3. Select **Branch** and enter `2.0.0-alpha`
4. Add the package to your app target and click **Add Package**.
The Para Swift SDK automatically includes the following dependencies:
* **BigInt**: For handling large numbers in blockchain operations
* **PhoneNumberKit**: For phone number validation and formatting
These dependencies will be automatically resolved by Swift Package Manager.
To enable passkeys on iOS, you need to configure Associated Domains:
1. In Xcode, go to **Signing & Capabilities** for your app target
2. Click **+ Capability** and add **Associated Domains**
3. Add the following entries:
```
webcredentials:app.usecapsule.com
webcredentials:app.beta.usecapsule.com
```
4. Register your Team ID + Bundle ID with Para via the
Without properly registering your Team ID and Bundle ID with Para, passkey authentication flows will fail. Contact Para support if you encounter issues with passkey registration.
## Configure URL Scheme
Before initializing Para, you need to configure your app's URL scheme for deep linking. This is required for the `appScheme` parameter and enables OAuth authentication flows.
1. In Xcode, select your project in the navigator
2. Select your app target
3. Go to the **Info** tab
4. Scroll down to **URL Types** and click **+** to add a new URL type
5. Fill in the fields:
* **URL Schemes**: Enter your scheme name (e.g., `paraswift`, `yourapp`)
* **Role**: Select **Editor**
## Initialize Para
To use Para's features, you'll need to initialize a Para manager that can be accessed throughout your app. This manager handles all interactions with Para's services, including authentication, wallet management, and transaction signing.
Below is an example of initializing the SDK in a SwiftUI application:
```swift App.swift
import SwiftUI
import ParaSwift
@main
struct ExampleApp: App {
@StateObject private var paraManager: ParaManager
init() {
// Initialize Para manager
_paraManager = StateObject(wrappedValue: ParaManager(
environment: .beta, // Use .prod for production
apiKey: "YOUR_API_KEY_HERE", // Get from: https://developer.getpara.com
appScheme: "yourapp" // Your app's URL scheme for deep linking
))
}
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(paraManager)
}
}
}
```
The `appScheme` parameter must match the URL scheme you configured in your Info.plist. This enables deep linking for external wallet integrations like MetaMask and OAuth authentication flows.
## Authenticate Users
Para provides a unified authentication experience that supports email, phone, and social login methods. The SDK automatically determines whether a user is new or existing and guides you through the appropriate flow.
**Beta Testing Credentials** In the `BETA` Environment, you can use any email ending in `@test.getpara.com` (like
[dev@test.getpara.com](mailto:dev@test.getpara.com)) or US phone numbers (+1) in the format `(area code)-555-xxxx` (like (425)-555-1234). Any OTP
code will work for verification with these test credentials. These credentials are for beta testing only. You can
delete test users anytime in the beta developer console to free up user slots.
### Build Your Authentication Flow
The recommended approach is to create a single authentication view that handles all authentication methods together. This provides users with all authentication options in one place.
Para supports authentication with both email addresses and phone numbers.
Initiate authentication with email or phone:
```swift AuthenticationView.swift
// Initialize authentication controllers
@Environment(\.authorizationController) private var authorizationController
@Environment(\.webAuthenticationSession) private var webAuthenticationSession
// Determine if input is email or phone
let auth: Auth
if userInput.contains("@") {
auth = .email(userInput)
} else {
auth = .phone(userInput) // Include country code
}
// SDK call: Initiate authentication
let authState = try await paraManager.initiateAuthFlow(auth: auth)
// Handle the result based on stage
switch authState.stage {
case .verify:
// New user - needs verification (see OTP handling step below)
case .login:
// Existing user - complete login
try await paraManager.handleLogin(
authState: authState,
authorizationController: authorizationController,
webAuthenticationSession: webAuthenticationSession
)
case .signup:
// Handle signup after verification
}
```
For new users who need verification, handle the OTP flow:
```swift AuthenticationView.swift
// After user enters the verification code
let verificationCode = "123456" // Get from user input
do {
// Submit verification code
let verifiedState = try await paraManager.handleVerificationCode(
verificationCode: verificationCode
)
// Complete signup with passkey
try await paraManager.handleSignup(
authState: verifiedState,
method: .passkey,
authorizationController: authorizationController,
webAuthenticationSession: webAuthenticationSession
)
// User is now signed up and authenticated
} catch {
// Handle error
}
```
Social login is integrated directly into the unified authentication view. Users can authenticate with Google, Apple, or Discord.
Implement the social login handler:
```swift AuthenticationView.swift
private func handleSocialLogin(_ provider: OAuthProvider) {
Task {
do {
try await paraManager.handleOAuth(
provider: provider,
webAuthenticationSession: webAuthenticationSession,
authorizationController: authorizationController
)
// User successfully authenticated
appRootManager.setAuthenticated(true)
} catch {
// Handle error
print("OAuth login failed: \(error.localizedDescription)")
}
}
}
```
## Handle Returning Users
After initial setup, users can log in using their email or phone with the same authentication flow:
```swift LoginView.swift
// Login with email
let authState = try await paraManager.initiateAuthFlow(auth: .email(userEmail))
// Since the user exists, authState.stage will be .login
if authState.stage == .login {
try await paraManager.handleLogin(
authState: authState,
authorizationController: authorizationController,
webAuthenticationSession: webAuthenticationSession
)
// User is now logged in
}
```
Alternatively, you can use direct passkey login if you know the user has set up passkeys:
```swift LoginView.swift
// Direct passkey login (will show all available passkeys if email/phone not provided)
try await paraManager.loginWithPasskey(
authorizationController: authorizationController,
email: userEmail, // Optional - helps filter passkeys
phone: nil
)
```
This will prompt the user for Face ID or Touch ID verification before granting access to their wallets.
## Check Authentication Status
You can check if a user is already authenticated:
```swift ContentView.swift
let isLoggedIn = await paraManager.isFullyLoggedIn()
if isLoggedIn {
// User is authenticated, proceed to main app flow
} else {
// Show login/signup UI
}
```
## Sign Out Users
To sign out a user and clear their session:
```swift SettingsView.swift
try await paraManager.logout()
```
## Create and Manage Wallets
After successful authentication, you can perform wallet operations:
```swift WalletView.swift
// Get all user wallets
try await paraManager.fetchWallets() // Ensure we have the latest wallets
if paraManager.wallets.isEmpty {
// No wallets, perhaps create one
try await paraManager.createWallet(type: .evm, skipDistributable: false)
// paraManager.wallets is updated internally
guard let firstWallet = paraManager.wallets.first else {
print("Failed to create or find a wallet.")
return
}
// Sign a simple message (SDK handles Base64 encoding internally)
let signature = try await paraManager.signMessage(
walletId: firstWallet.id,
message: "Hello, Para!"
)
print("Signature: \(signature)")
} else {
// Use existing wallet
guard let firstWallet = paraManager.wallets.first else { return }
// Sign a simple message (SDK handles Base64 encoding internally)
let signature = try await paraManager.signMessage(
walletId: firstWallet.id,
message: "Hello, Para!"
)
print("Signature: \(signature)")
}
```
For detailed transaction signing with specific blockchains (EVM, Solana, Cosmos), please refer to the respective blockchain integration guides.
## Example
For a complete implementation example, check out our Swift SDK example app:
## Next Steps
After integrating Para into your Swift app, you can explore other features and integrations to enhance your Para experience.
# Troubleshooting
Source: https://docs.getpara.com/v2/swift/troubleshooting
Solutions for common issues with the Para Swift SDK integration
export const Link = ({href, label, newTab = false}) => {
const [isHovered, setIsHovered] = useState(false);
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
{label}
;
};
This guide helps you identify and resolve common issues encountered while integrating the Para Swift SDK into your iOS application.
Using an LLM (ChatGPT, Claude) or Coding Assistant (Cursor, Github Copilot)? Here are a few tips:
1. Include the for the most up-to-date help
2. Check out the for an interactive LLM using Para Examples Hub
## General Troubleshooting Steps
Before diving into specific issues, try these basic troubleshooting steps:
In Xcode, go to **Product → Clean Build Folder** (Option + Shift + Command + K).
For Swift Package Manager: **File → Packages → Update to Latest Package Versions**
For CocoaPods: Run `pod update` in your terminal.
Ensure you are using the latest Para SDK compatible with your minimum deployment target (iOS 13.0+).
Confirm your API key, Associated Domains, custom URL scheme, Team ID, and Bundle ID are correctly configured.
## Common Issues and Solutions
### Authentication Issues
**Error:** `ParaError.bridgeError` or system authentication errors
**Solution:** Verify Associated Domains, Team ID, Bundle ID, and domain setup.
```swift
do {
try await paraManager.generatePasskey(
identifier: email,
biometricsId: biometricsId,
authorizationController: authorizationController
)
} catch let error as ParaError {
print("Para error occurred: \(error.description)")
} catch let error as ASAuthorizationError {
print("Authentication error: \(error.localizedDescription)")
}
```
**Solution:** Confirm biometric setup on the device and check permissions in app settings.
Make sure your app includes the necessary privacy descriptions in Info.plist:
* `NSFaceIDUsageDescription` for Face ID
* Proper permission handling for biometric authentication
**Error:** `ASAuthorizationError.canceled` or similar system errors
**Solution:** Catch authentication cancellation errors and offer a retry option to the user. This error occurs when the user cancels a biometric prompt.
```swift
do {
try await paraManager.loginWithPasskey(authorizationController: authorizationController)
} catch let error as ASAuthorizationError where error.code == .canceled {
print("User canceled authentication")
}
```
**Solution:** Verify:
* Correct environment settings (BETA/prod)
* Proper user input (valid email/phone format)
* Active network connection
* You haven't hit rate limits for verification attempts
### Transaction Signing Issues
**Error:** `ParaError.bridgeError` or `ParaError.error`
**Solution:** Verify transaction parameters, proper encoding (Base64), and integration with web3 libraries.
```swift
do {
let result = try await paraManager.signTransaction(
walletId: walletId,
transaction: transaction
)
} catch let error as ParaError {
print("Transaction signing failed: \(error.description)")
}
```
**Error:** Transaction signing failures
**Solution:** Handle signing errors appropriately:
```swift
do {
let result = try await paraManager.signTransaction(
walletId: wallet.id,
transaction: transaction
)
print("Signed transaction: \(result.signedTransaction)")
} catch ParaError.bridgeError(let message) {
print("Signing failed: \(message)")
} catch {
print("Unexpected error: \(error)")
}
```
**Solution:**
* Ensure wallet balance covers gas fees
* Verify correct gas parameters
* Use reliable web3 libraries for estimates
* Consider implementing fallback gas values
### Network Issues
**Error:** `ParaError.bridgeError` or `ParaError.bridgeTimeoutError`
**Solution:** Check network connectivity, implement retry logic, and use network monitoring tools.
```swift
do {
try await paraManager.createWallet(type: .evm, skipDistributable: false)
} catch ParaError.bridgeTimeoutError {
print("Bridge operation timed out. Check connectivity and try again.")
} catch ParaError.bridgeError(let message) {
print("Bridge error occurred: \(message)")
}
```
**Error:** `ParaError.bridgeTimeoutError`
**Solution:**
* Implement timeout handling using Swift concurrency features
* Provide retry options for users
* Display loading indicators during network operations
* Consider implementing exponential backoff for retries
### External Wallet Issues
**Error:** `MetaMaskError` or `ParaError.bridgeError`
**Solution:** Check MetaMask installation and connection flow.
```swift
do {
try await metaMaskConnector.connect()
} catch let error as MetaMaskError {
print("MetaMask error: \(error.localizedDescription)")
} catch let error as ParaError {
print("Para error during MetaMask connection: \(error.description)")
}
```
**Solution:** Confirm wallet address and type are correct for external wallet login.
```swift
do {
let walletInfo = ExternalWalletInfo(
address: walletAddress,
type: .evm,
provider: "metamask"
)
try await paraManager.loginExternalWallet(wallet: walletInfo)
} catch let error as ParaError {
print("External wallet login failed: \(error.description)")
}
```
**Solution:**
* Verify URL schemes in `Info.plist`
* Confirm deep-link handling in AppDelegate or SceneDelegate
* Test with simple deep links to isolate the issue
* Check if the external wallet app is properly installed
## Best Practices
## Development Tools
Enable debug mode in the Para SDK (if available) to get more detailed logging information.
Utilize network debugging tools like Charles Proxy or Xcode's network debugger to inspect API calls.
Leverage Xcode's built-in debugging features:
* Set breakpoints at critical points
* Inspect variables and state
* Use the console for logging
### Setup and Integration Issues
If you're having trouble initializing the Para SDK:
* Ensure you're providing the required `appScheme` parameter
* Verify that you're using the correct API key and environment
* Check that all necessary dependencies are installed properly
* Look for any Swift compiler errors in your Xcode console
* Verify that your minimum deployment target is iOS 13.0 or higher
If passkey creation, retrieval, or usage isn't working:
* Verify that you've set up Associated Domains correctly in your Xcode project
* Make sure you've registered your Team ID + Bundle ID with Para via the Developer Portal
* Ensure that biometric authentication is enabled on the test device
* Check that `AuthorizationController` is properly configured
* Verify Face ID/Touch ID permissions are properly set in Info.plist
* Check for `ASAuthorizationError.canceled` when users cancel the biometric prompt
If you're experiencing authentication issues:
* Double-check that your API key is correct and properly set in your Para manager initialization
* Verify you're using the correct environment (`beta` or `prod`) that matches your API key
* Ensure your account has the necessary permissions for the operations you're attempting
* Check that your URL scheme matches what's configured in your Info.plist
* Verify the authentication flow is being followed correctly (verify → signup/login)
If OAuth callbacks or deep links aren't functioning:
* Verify your URL scheme is correctly configured in Info.plist
* Check that `onOpenURL` modifier is properly implemented
* Ensure the `appScheme` parameter matches your URL scheme exactly
* Test with a simple deep link first to isolate the issue
* Make sure your app is handling the URL in the main app file
## Getting Help
If you're still experiencing issues after trying the solutions above, you can get additional help:
*
* Contact Para Support via or [Slack](https://join.slack.com/t/para-community/shared_invite/zt-304keeulc-Oqs4eusCUAJEpE9DBwAqrg)
* When reporting issues, include:
* Detailed error messages
* Steps to reproduce the issue
* Device and iOS version details
* Para SDK version
# getLinkedAccounts
Source: https://docs.getpara.com/v2/references/core/getlinkedaccounts
Retrieves linked accounts for the user
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# getOAuthUrl
Source: https://docs.getpara.com/v2/references/core/getoauthurl
Generates an OAuth URL for third-party authentication
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
",
typeLink: "/v2/references/types/toauthmethod",
required: true,
description: "The third-party OAuth service."
},
{
name: "appScheme",
type: "string",
optional: true,
description: "The app scheme to redirect to after OAuth is complete."
},
{
name: "sessionLookupId",
type: "string",
optional: true
}
]}
returns={{
type: "string",
description: "The OAuth URL."
}}
/>
# getPregenWallets
Source: https://docs.getpara.com/v2/references/core/getpregenwallets
Retrieves pregenerated wallets
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# getUserShare
Source: https://docs.getpara.com/v2/references/core/getusershare
Retrieves the user's share
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# getVerificationToken
Source: https://docs.getpara.com/v2/references/core/getverificationtoken
Retrieves a verification token
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# getWalletBalance
Source: https://docs.getpara.com/v2/references/core/getwalletbalance
Retrieves the balance for a wallet
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# getWallets
Source: https://docs.getpara.com/v2/references/core/getwallets
Retrieves all wallets for the user
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
",
typeLink: "/v2/references/types/wallet",
description: "A record of wallets keyed by ID."
}}
/>
# getWalletsByType
Source: https://docs.getpara.com/v2/references/core/getwalletsbytype
Retrieves wallets of a specific type
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# hasPregenWallet
Source: https://docs.getpara.com/v2/references/core/haspregenwallet
Checks if a pregenerated wallet exists for the given ID
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# importSession
Source: https://docs.getpara.com/v2/references/core/importsession
Imports session data
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# initiateOnRampTransaction
Source: https://docs.getpara.com/v2/references/core/initiateonramptransaction
Initiates an on-ramp transaction
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# isFullyLoggedIn
Source: https://docs.getpara.com/v2/references/core/isfullyloggedin
Checks if the user is fully logged in
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# isSessionActive
Source: https://docs.getpara.com/v2/references/core/issessionactive
Checks if the current session is active
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# issueJwt
Source: https://docs.getpara.com/v2/references/core/issuejwt
Issues a JWT token
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# keepSessionAlive
Source: https://docs.getpara.com/v2/references/core/keepsessionalive
Keeps the current session alive
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# loginExternalWallet
Source: https://docs.getpara.com/v2/references/core/loginexternalwallet
Initiates login using an external wallet
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# logout
Source: https://docs.getpara.com/v2/references/core/logout
Logs out the current user
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# refreshSession
Source: https://docs.getpara.com/v2/references/core/refreshsession
Refreshes the current session
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# refreshShare
Source: https://docs.getpara.com/v2/references/core/refreshshare
Refreshes a wallet share
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# resendVerificationCode
Source: https://docs.getpara.com/v2/references/core/resendverificationcode
Resends a verification code for signup, login, or account linking
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# setup2fa
Source: https://docs.getpara.com/v2/references/core/setup2fa
Sets up two-factor authentication for the user
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# setUserShare
Source: https://docs.getpara.com/v2/references/core/setusershare
Sets the user's share
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# signMessage
Source: https://docs.getpara.com/v2/references/core/signmessage
Signs a message using the specified wallet
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
boolean",
optional: true,
description: "A callback that returns a boolean, indicating whether the signing operation should be cancelled."
}
]}
returns={{
type: "FullSignatureRes",
typeLink: "/v2/references/types/fullsignatureres",
description: "The signing result."
}}
/>
# signTransaction
Source: https://docs.getpara.com/v2/references/core/signtransaction
Signs a transaction using the specified wallet
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
boolean",
optional: true,
description: "A callback that returns a boolean, indicating whether the signing operation should be cancelled."
}
]}
returns={{
type: "FullSignatureRes",
typeLink: "/v2/references/types/fullsignatureres",
description: "The signing result."
}}
/>
# signUpOrLogIn
Source: https://docs.getpara.com/v2/references/core/signuporlogin
Initiates signup or login for a user based on the provided authentication details
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# updatePregenWalletIdentifier
Source: https://docs.getpara.com/v2/references/core/updatepregenwalletidentifier
Updates the identifier for a pregenerated wallet
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# verify2fa
Source: https://docs.getpara.com/v2/references/core/verify2fa
Verifies two-factor authentication
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# verifyExternalWallet
Source: https://docs.getpara.com/v2/references/core/verifyexternalwallet
Verifies an external wallet for authentication
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# verifyFarcaster
Source: https://docs.getpara.com/v2/references/core/verifyfarcaster
Verifies Farcaster authentication
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
boolean",
optional: true,
description: "A function returning a boolean, indicating whether the Farcaster login process should be cancelled."
},
{
name: "onConnectUri",
type: "(uri: string) => void",
optional: true,
description: "A callback function that will be invoked with the Farcaster Connect URI when it is available. You will need to display the URI as a QR code."
}
]}
returns={{
type: "OAuthResponse",
typeLink: "/v2/references/types/oauthresponse",
description: "The Farcaster verification response."
}}
/>
# verifyNewAccount
Source: https://docs.getpara.com/v2/references/core/verifynewaccount
Verifies a new account using the provided verification code
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# verifyOAuth
Source: https://docs.getpara.com/v2/references/core/verifyoauth
Verifies OAuth authentication
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
",
typeLink: "/v2/references/types/toauthmethod",
required: true,
description: "The third-party OAuth service."
},
{
name: "isCanceled",
type: "() => boolean",
optional: true,
description: "A function returning a boolean, indicating whether the OAuth process should be cancelled."
},
{
name: "onOAuthUrl",
type: "(url: string) => void",
optional: true,
description: "A callback function that will be invoked with the OAuth URL when it is available."
},
{
name: "onOAuthPopup",
type: "(popup: Window) => void",
optional: true,
description: "A callback function that will be invoked with the OAuth popup window when it is available."
}
]}
returns={{
type: "OAuthResponse",
typeLink: "/v2/references/types/oauthresponse",
description: "The OAuth verification response."
}}
/>
# verifyTelegram
Source: https://docs.getpara.com/v2/references/core/verifytelegram
Verifies Telegram authentication
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# waitForLogin
Source: https://docs.getpara.com/v2/references/core/waitforlogin
Polls and waits for the login process to complete
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
boolean",
optional: true,
description: "A function returning a boolean, indicating whether the login process should be cancelled."
}
]}
returns={{
type: "{ needsWallet?: boolean; partnerId?: string; }",
description: "Object indicating if the user needs a wallet and the partner ID."
}}
/>
# waitForSignup
Source: https://docs.getpara.com/v2/references/core/waitforsignup
Polls and waits for the signup process to complete
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
boolean",
optional: true,
description: "A function returning a boolean, indicating whether the signup process should be cancelled."
}
]}
returns={{
type: "true",
description: "True if signup completes successfully."
}}
/>
# waitForWalletCreation
Source: https://docs.getpara.com/v2/references/core/waitforwalletcreation
Polls and waits for wallet creation to complete
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
boolean",
optional: true,
description: "A function returning a boolean, indicating whether wallet creation should be cancelled."
}
]}
returns={{
type: "{ walletIds: CurrentWalletIds; recoverySecret?: string; }",
typeLink: "/v2/references/types/currentwalletids",
description: "The IDs of the newly created wallets and optional recovery secret."
}}
/>
# ParaProvider
Source: https://docs.getpara.com/v2/references/hooks/ParaProvider
React context provider component that wraps your application to provide access to Para hooks
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
",
typeLink: "/v2/references/types/externalwalletconfig",
optional: true,
description: "Configuration for connecting external wallets."
},
{
name: "children",
type: "ReactNode",
required: true,
description: "Your app's components that will use Para hooks."
}
]}
returns={{
type: "JSX.Element",
description: "The provider component wrapping your app."
}}
async={false}
/>
# useAccount
Source: https://docs.getpara.com/v2/references/hooks/useAccount
React Query hook for retrieving the current embedded account and connected external wallets
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# useAccountLinkInProgress
Source: https://docs.getpara.com/v2/references/hooks/useAccountLinkInProgress
Hook for returning the account linking status of the user
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# useClaimPregenWallets
Source: https://docs.getpara.com/v2/references/hooks/useClaimPregenWallets
React hook for claiming pregenerated wallets
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, claimPregenWalletsAsync: (params: { pregenId?: PregenAuth }) => string | undefined, data: string | undefined }",
description: "Functions to claim wallets (sync/async) and the claim result."
}}
/>
# useClient
Source: https://docs.getpara.com/v2/references/hooks/useClient
Hook for retrieving the Para client instance
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# useCosmjsAminoSigner
Source: https://docs.getpara.com/v2/references/hooks/useCosmjsAminoSigner
Hook to retrieve a CosmJS Amino signer for Para Cosmos wallets
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# useCosmjsProtoSigner
Source: https://docs.getpara.com/v2/references/hooks/useCosmjsProtoSigner
Hook to retrieve a CosmJS Proto signer for Para Cosmos wallets
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# useCreateGuestWallets
Source: https://docs.getpara.com/v2/references/hooks/useCreateGuestWallets
React hook for creating guest wallets
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, createGuestWalletsAsync: () => Wallet[], data: Wallet[] | undefined }",
description: "Functions to create guest wallets (sync/async) and the created wallets.",
typeLink: "/v2/references/types/wallet"
}}
/>
# useCreatePregenWallet
Source: https://docs.getpara.com/v2/references/hooks/useCreatePregenWallet
React hook for creating pregenerated wallets
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, createPregenWalletAsync: (params: { type: TWalletType, pregenId: PregenAuth }) => Wallet, data: Wallet | undefined }",
description: "An object with functions to create a pregenerated wallet and the resulting data.",
typeLink: "/v2/references/types/wallet"
}}
/>
# useCreatePregenWalletPerType
Source: https://docs.getpara.com/v2/references/hooks/useCreatePregenWalletPerType
React hook for creating pregenerated wallets per type
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, createPregenWalletPerTypeAsync: (params: { types?: TWalletType[], pregenId: PregenAuth }) => Wallet[], data: Wallet[] | undefined }",
description: "An object with functions to create pregenerated wallets per type and the resulting data.",
typeLink: "/v2/references/types/wallet"
}}
/>
# useCreateWallet
Source: https://docs.getpara.com/v2/references/hooks/useCreateWallet
React hook for creating wallets
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
",
optional: true,
description: "The wallet type to create (e.g., 'EVM').",
typeLink: "/v2/references/types/twallettype"
},
{
name: "skipDistribute",
type: "boolean",
optional: true,
description: "If true, skips wallet distribution."
}
]}
returns={{
type: "{ createWallet: (params?: { type?: Uppercase, skipDistribute?: boolean }) => void, createWalletAsync: (params?: { type?: Uppercase, skipDistribute?: boolean }) => [Wallet, string | undefined], data: [Wallet, string | undefined] | undefined }",
description: "An object with functions to create a wallet and the resulting data.",
typeLink: "/v2/references/types/wallet"
}}
/>
# useCreateWalletPerType
Source: https://docs.getpara.com/v2/references/hooks/useCreateWalletPerType
React hook for creating wallets per type
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
[]", optional: true },
{ name: "skipDistribute", type: "boolean", optional: true }
]}
returns={{
type: "{ createWalletPerType: (params?: { types?: Uppercase[], skipDistribute?: boolean }) => void, createWalletPerTypeAsync: (params?: { types?: Uppercase[], skipDistribute?: boolean }) => { wallets: Wallet[], walletIds: CurrentWalletIds, recoverySecret?: string }, data: { wallets: Wallet[], walletIds: CurrentWalletIds, recoverySecret?: string } | undefined }",
description: "An object with functions to create wallets per type and the resulting data.",
typeLink: "/v2/references/types/currentwalletids"
}}
/>
# useEnable2fa
Source: https://docs.getpara.com/v2/references/hooks/useEnable2fa
React hook to enable two-factor authentication (2FA)
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, enable2faAsync: (params: { verificationCode: string }) => void, data: void | undefined }", description: "An object with functions to enable 2FA and the resulting data." }}
async={true}
/>
# useHasPregenWallet
Source: https://docs.getpara.com/v2/references/hooks/useHasPregenWallet
React hook for checking if a pregenerated wallet exists
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, hasPregenWalletAsync: (params: { pregenId: PregenAuth }) => boolean, data: boolean | undefined }", description: "Functions to check existence (sync/async) and the result." }}
async={true}
/>
# useIsFullyLoggedIn
Source: https://docs.getpara.com/v2/references/hooks/useIsFullyLoggedIn
Hook for returning whether the user is fully logged in with Para
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# useIssueJwt
Source: https://docs.getpara.com/v2/references/hooks/useIssueJwt
React hook for issuing a JWT token
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, issueJwtAsync: (params?: { keyIndex?: number }) => { token: string, keyId: string }, data: { token: string, keyId: string } | undefined }", description: "An object with functions to issue a JWT and the resulting data." }}
async={true}
/>
# useKeepSessionAlive
Source: https://docs.getpara.com/v2/references/hooks/useKeepSessionAlive
React hook for keeping the session alive
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, keepSessionAliveAsync: () => boolean, data: boolean | undefined }", description: "An object with functions to keep the session alive and the resulting data." }} async={true} />
# null
Source: https://docs.getpara.com/v2/references/hooks/useLinkAccount
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
Promise, error: string | null, status: MutationStatus, isPending: boolean, isError: boolean, isIdle: boolean, isSuccess: boolean }", description: "Functions and status for account linking." }} async={true} />
# useLinkedAccounts
Source: https://docs.getpara.com/v2/references/hooks/useLinkedAccounts
Hook for returning the linked accounts of the user
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
", optional: true, description: "Options for querying linked accounts." }
]}
returns={{
type: "LinkedAccounts & { userId: string } | undefined",
description: "An object containing the linked accounts data.",
typeLink: "/v2/references/types/linkedaccounts"
}}
/>
# null
Source: https://docs.getpara.com/v2/references/hooks/useLoginExternalWallet
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, loginExternalWalletAsync: (params: { portalTheme?: Theme, useShortUrls?: boolean, externalWallet: ExternalWalletInfo | ExternalWalletInfo[] }) => AuthStateVerifyOrLogin, data: AuthStateVerifyOrLogin | undefined }", description: "An object with functions to log in with an external wallet and the resulting data." }}
async={true}
/>
# useLogout
Source: https://docs.getpara.com/v2/references/hooks/useLogout
React hook for logging out
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, logoutAsync: (params?: { clearPregenWallets?: boolean }) => void, data: void | undefined }", description: "An object with functions to log out and the resulting data." }}
async={true}
/>
# null
Source: https://docs.getpara.com/v2/references/hooks/useModal
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, closeModal: () => void }", description: "Modal state and functions to open/close it." }} />
# null
Source: https://docs.getpara.com/v2/references/hooks/useParaStatus
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# null
Source: https://docs.getpara.com/v2/references/hooks/useResendVerificationCode
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, resendVerificationCodeAsync: (params?: { type?: 'SIGNUP' | 'LINK_ACCOUNT' | 'LOGIN' }) => void, data: void | undefined }", description: "An object with functions to resend verification code and the resulting data." }}
async={true}
/>
# null
Source: https://docs.getpara.com/v2/references/hooks/useSetup2fa
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, setup2faAsync: () => Setup2faResponse, data: Setup2faResponse | undefined }", description: "An object with functions to set up 2FA and the resulting data." }} async={true} />
# null
Source: https://docs.getpara.com/v2/references/hooks/useSignMessage
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, signMessageAsync: (params: { message: string, wallet?: CurrentWalletIds['embedded'] | CurrentWalletIds['external'], waitForTransaction?: boolean }) => FullSignatureRes, data: FullSignatureRes | undefined }", description: "An object with functions to sign a message and the resulting data." }}
async={true}
/>
# null
Source: https://docs.getpara.com/v2/references/hooks/useSignTransaction
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, signTransactionAsync: (params: { transaction: any, network?: string | number, wallet?: CurrentWalletIds['embedded'] | CurrentWalletIds['external'], waitForTransaction?: boolean }) => FullSignatureRes, data: FullSignatureRes | undefined }", description: "An object with functions to sign a transaction and the resulting data." }}
async={true}
/>
# null
Source: https://docs.getpara.com/v2/references/hooks/useSignUpOrLogIn
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, signUpOrLogInAsync: (params: { identifier: string, chainType?: string, channelType?: AuthMethod, authType?: EnabledFlow, provider?: TOAuthMethod, useShortUrls?: boolean, providerRedirectUrl?: string }) => AuthStateLogin | ServerAuthStateVerify, data: AuthStateLogin | ServerAuthStateVerify | undefined }", description: "An object with functions to sign up or log in and the resulting data." }}
async={true}
/>
# null
Source: https://docs.getpara.com/v2/references/hooks/useSolanaSigner
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
", required: true, description: "Solana RPC client." }
]}
returns={{ type: "{ solanaSigner: SignerWalletAdapter | null, isLoading: boolean }", description: "The Solana signer (or null) and loading status." }}
/>
# null
Source: https://docs.getpara.com/v2/references/hooks/useUpdatePregenWalletIdentifier
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, updatePregenWalletIdentifierAsync: (params: { identifier: string, pregenId: PregenAuth }) => void, data: void | undefined }", description: "An object with functions to update pregenerated wallet identifier and the resulting data." }}
async={true}
/>
# null
Source: https://docs.getpara.com/v2/references/hooks/useVerify2fa
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, verify2faAsync: (params: { verificationCode: string }) => { initiatedAt?: Date, status?: RecoveryStatus, userId: string, wallets: Pick[] }, data: { initiatedAt?: Date, status?: RecoveryStatus, userId: string, wallets: Pick[] } | undefined }", description: "Verification result including user ID and wallets." }}
async={true}
/>
# null
Source: https://docs.getpara.com/v2/references/hooks/useVerifyExternalWallet
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, verifyExternalWalletAsync: (params: { signature: string, message?: string, externalWallet: ExternalWalletInfo | ExternalWalletInfo[] }) => AuthStateSignup | AuthStateLogin, data: AuthStateSignup | AuthStateLogin | undefined }", description: "An object with functions to verify external wallet and the resulting data." }}
async={true}
/>
# null
Source: https://docs.getpara.com/v2/references/hooks/useVerifyFarcaster
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, verifyFarcasterAsync: (params?: { message?: string, signature?: string, channelToken?: string }) => AuthStateSignupOrLogin, data: AuthStateSignupOrLogin | undefined }", description: "An object with functions to verify Farcaster authentication and the resulting data." }}
async={true}
/>
# null
Source: https://docs.getpara.com/v2/references/hooks/useVerifyNewAccount
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, verifyNewAccountAsync: (params: { type: TLinkedAccountType, authMethod: AuthMethod, authMethodDetails: string }) => { username?: string, linkedAccounts: LinkedAccounts, userId: string }, data: { username?: string, linkedAccounts: LinkedAccounts, userId: string } | undefined }", description: "An object with functions to verify a new account and the resulting data." }}
async={true}
/>
# null
Source: https://docs.getpara.com/v2/references/hooks/useVerifyOAuth
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, verifyOAuthAsync: (params: { signature: string, nonce?: string, message?: string, redirectUriHostname?: string }) => AuthStateSignupOrLogin, data: AuthStateSignupOrLogin | undefined }", description: "An object with functions to verify OAuth and the resulting data." }}
async={true}
/>
# null
Source: https://docs.getpara.com/v2/references/hooks/useVerifyTelegram
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, verifyTelegramAsync: (params: { telegramAuthResponse: TelegramAuthResponse, redirectUriHostname?: string }) => AuthStateSignupOrLogin, data: AuthStateSignupOrLogin | undefined }", description: "An object with functions to verify Telegram authentication and the resulting data." }}
async={true}
/>
# null
Source: https://docs.getpara.com/v2/references/hooks/useViemAccount
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# null
Source: https://docs.getpara.com/v2/references/hooks/useViemClient
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
", required: true, description: "Configuration for the Viem wallet client, excluding the account." }
]}
returns={{ type: "{ viemClient: WalletClient | null, isLoading: boolean }", description: "The Viem client (or null) and loading status." }}
/>
# null
Source: https://docs.getpara.com/v2/references/hooks/useWaitForLogin
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, waitForLoginAsync: (params?: { timeout?: number }) => { needsWallet?: boolean, partnerId?: string }, data: { needsWallet?: boolean, partnerId?: string } | undefined }", description: "An object with functions to wait for login and the resulting data." }}
async={true}
/>
# null
Source: https://docs.getpara.com/v2/references/hooks/useWaitForSignup
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, waitForSignupAsync: (params?: { timeout?: number }) => true, data: true | undefined }", description: "An object with functions to wait for signup and the resulting data." }}
async={true}
/>
# null
Source: https://docs.getpara.com/v2/references/hooks/useWaitForWalletCreation
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, waitForWalletCreationAsync: (params?: { timeout?: number }) => { walletIds: CurrentWalletIds, recoverySecret?: string }, data: { walletIds: CurrentWalletIds, recoverySecret?: string } | undefined }", description: "An object with functions to wait for wallet creation and the resulting data." }}
async={true}
/>
# useWallet
Source: https://docs.getpara.com/v2/references/hooks/useWallet
Hook for retrieving the selected wallet
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
| null | undefined",
description: "The selected wallet details (without signer), or null if none.",
typeLink: "/v2/references/types/wallet"
}}
/>
# useWalletBalance
Source: https://docs.getpara.com/v2/references/hooks/useWalletBalance
Hook for retrieving a wallet balance
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
", optional: true, description: "Optional parameters for wallet balance query." }
]}
returns={{ type: "string | null | undefined", description: "The wallet balance as a string, or null if unavailable." }}
/>
# null
Source: https://docs.getpara.com/v2/references/hooks/useWalletState
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void, updateSelectedWallet: () => void }", description: "Object for managing the selected wallet state and actions." }} />
# AccountLinkError
Source: https://docs.getpara.com/v2/references/types/accountlinkerror
Error types for account linking
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# AccountLinkInProgress
Source: https://docs.getpara.com/v2/references/types/accountlinkinprogress
Represents an in-progress account link
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# AuthMethod
Source: https://docs.getpara.com/v2/references/types/authmethod
Authentication methods
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# AuthState
Source: https://docs.getpara.com/v2/references/types/authstate
Union of authentication states: verify, login, or signup
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# AuthStateSignup
Source: https://docs.getpara.com/v2/references/types/authstatesignup
The authentication state for signup
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# AuthStateSignupOrLogin
Source: https://docs.getpara.com/v2/references/types/authstatesignuporlogin
Union type for signup or login authentication states
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# AuthStateVerify
Source: https://docs.getpara.com/v2/references/types/authstateverify
The authentication state for verification
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# AuthStateVerifyOrLogin
Source: https://docs.getpara.com/v2/references/types/authstateverifyorlogin
Union type for verify or login authentication states
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# AuthType
Source: https://docs.getpara.com/v2/references/types/authtype
Union of authentication types
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# BackupKitEmailProps
Source: https://docs.getpara.com/v2/references/types/backupkitemailprops
Properties for backup kit emails
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# BorderRadius
Source: https://docs.getpara.com/v2/references/types/borderradius
Border radius options for themes
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# Callbacks
Source: https://docs.getpara.com/v2/references/types/callbacks
Event callbacks for Para SDK events
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void",
optional: true
},
{
name: "onLogin",
type: "(event: LoginEvent) => void",
optional: true
},
{
name: "onAccountSetup",
type: "(event: AccountSetupEvent) => void",
optional: true
},
{
name: "onAccountCreation",
type: "(event: AccountCreationEvent) => void",
optional: true
},
{
name: "onSignMessage",
type: "(event: SignMessageEvent) => void",
optional: true
},
{
name: "onSignTransaction",
type: "(event: SignTransactionEvent) => void",
optional: true
},
{
name: "onExternalWalletChange",
type: "(event: ExternalWalletChangeEvent) => void",
optional: true
},
{
name: "onWalletsChange",
type: "(event: WalletsChangeEvent) => void",
optional: true
},
{
name: "onWalletCreated",
type: "(event: WalletCreatedEvent) => void",
optional: true
},
{
name: "onPregenWalletClaimed",
type: "(event: PregenWalletClaimedEvent) => void",
optional: true
},
{
name: "onGuestWalletsCreated",
type: "(event: GuestWalletsCreatedEvent) => void",
optional: true
}
]}
/>
# ConstructorOpts
Source: https://docs.getpara.com/v2/references/types/constructoropts
Options for SDK constructor
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
Promise",
optional: true
},
{
name: "localStorageSetItemOverride",
type: "(key: string, value: string) => Promise",
optional: true
},
{
name: "sessionStorageGetItemOverride",
type: "(key: string) => Promise",
optional: true
},
{
name: "sessionStorageSetItemOverride",
type: "(key: string, value: string) => Promise",
optional: true
},
{
name: "sessionStorageRemoveItemOverride",
type: "(key: string) => Promise",
optional: true
},
{
name: "clearStorageOverride",
type: "() => Promise",
optional: true
},
{
name: "portalBackgroundColor",
type: "string",
optional: true,
description: "Hex color to use in the portal for the background color. Deprecated: use portalTheme instead."
},
{
name: "portalPrimaryButtonColor",
type: "string",
optional: true,
description: "Hex color to use in the portal for the primary button. Deprecated: use portalTheme instead."
},
{
name: "portalTextColor",
type: "string",
optional: true,
description: "Hex text color to use in the portal. Deprecated: use portalTheme instead."
},
{
name: "portalPrimaryButtonTextColor",
type: "string",
optional: true,
description: "Hex color to use in the portal for the primary button text. Deprecated: use portalTheme instead."
},
{
name: "portalTheme",
type: "Theme",
typeLink: "/v2/references/types/theme",
optional: true,
description: "Theme to use for the portal. Deprecated: configure theming through the developer portal."
},
{
name: "useDKLSForCreation",
type: "boolean",
optional: true
},
{
name: "disableWebSockets",
type: "boolean",
optional: true
},
{
name: "wasmOverride",
type: "ArrayBuffer",
optional: true
},
{
name: "emailTheme",
type: "EmailTheme",
typeLink: "/v2/references/types/emailtheme",
optional: true,
description: "Base theme for the emails sent from this Para instance. Default: dark. Deprecated: configure theming through the developer portal."
},
{
name: "emailPrimaryColor",
type: "string",
optional: true,
description: "Hex color to use as the primary color in the emails. Default: #FE452B. Deprecated: configure theming through the developer portal."
},
{
name: "linkedinUrl",
type: "string",
optional: true,
description: "Linkedin URL to link to in the emails. Deprecated: configure this through the developer portal."
},
{
name: "githubUrl",
type: "string",
optional: true,
description: "Github URL to link to in the emails. Deprecated: configure this through the developer portal."
},
{
name: "xUrl",
type: "string",
optional: true,
description: "X (Twitter) URL to link to in the emails. Deprecated: configure this through the developer portal."
},
{
name: "supportUrl",
type: "string",
optional: true,
description: "Support URL to link to in the emails. Deprecated: homepageUrl will be used for this, configure it through the developer portal."
},
{
name: "homepageUrl",
type: "string",
optional: true,
description: "URL for your home landing page. Deprecated: configure this through the developer portal."
},
{
name: "useSessionStorage",
type: "boolean",
optional: true,
description: "If `true`, the SDK will use the device's temporary session storage instead of saving user and wallet data to local storage."
},
{
name: "portalPartnerId",
type: "string",
optional: true,
description: "Partner ID set in the Para Portal to track analytics for legacy SDK versions."
},
{
name: "fetchPregenWalletsOverride",
type: "(opts: { pregenId: PregenAuth }) => Promise<{ userShare?: string }>",
optional: true,
description: "An optional function that fetches the pregenerated wallets for a given identifier so a user can claim them on account creation."
}
]}
/>
# CoreAuthInfo
Source: https://docs.getpara.com/v2/references/types/coreauthinfo
Core authentication information
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# Ctx
Source: https://docs.getpara.com/v2/references/types/ctx
Context configuration for the SDK
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# CurrentWalletIds
Source: https://docs.getpara.com/v2/references/types/currentwalletids
Partial record of wallet IDs by type
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
>",
typeLink: "/v2/references/types/twallettype"
}}
/>
# EmailTheme
Source: https://docs.getpara.com/v2/references/types/emailtheme
Themes for emails
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# EmbeddedWalletType
Source: https://docs.getpara.com/v2/references/types/embeddedwallettype
Type for embedded wallets
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# EnabledFlow
Source: https://docs.getpara.com/v2/references/types/enabledflow
Enabled flows for on-ramp configurations
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# Environment
Source: https://docs.getpara.com/v2/references/types/environment
Available environments for the SDK
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# ExternalWalletConfig
Source: https://docs.getpara.com/v2/references/types/externalwalletconfig
Configuration for external wallets
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
, 'appName' | 'appDescription' | 'appUrl' | 'appIcon' | 'projectId'>, wagmiProviderProps?: ParaWagmiProviderProps }",
optional: true,
description: "Config for the EVM external wallets connector using Wagmi."
},
{
name: "cosmosConnector",
type: "{ config: ParaCosmosProviderConfigNoWallets, grazProviderProps?: ParaGrazProviderProps }",
optional: true,
description: "Config for the Cosmos external wallets connector using Graz."
},
{
name: "solanaConnector",
type: "{ config: Omit & Pick, 'appIdentity'> }",
optional: true,
description: "Config for the Solana external wallets connector using @solana/wallet-adapter-react."
},
{
name: "walletConnect",
type: "{ projectId: string }",
optional: true,
description: "Config for any connectors that use Wallet Connect."
},
{
name: "wallets",
type: "TExternalWallet[]",
typeLink: "/v2/references/types/texternalwallet",
optional: true,
description: "Which external wallets to show and in what order they should be displayed."
},
{
name: "createLinkedEmbeddedForExternalWallets",
type: "TExternalWallet[] | 'ALL'",
typeLink: "/v2/references/types/texternalwallet",
optional: true,
description: "Array of external wallets that will also include linked embedded wallets. Also includes a wallet verification step."
},
{
name: "includeWalletVerification",
type: "boolean",
optional: true,
description: "Whether or not to validate a signature from the connected external wallet and create a Para session."
},
{
name: "connectionOnly",
type: "boolean",
optional: true,
description: "Whether or not to treat external wallets as connections only, skipping all Para functionality."
}
]}
/>
# ExternalWalletInfo
Source: https://docs.getpara.com/v2/references/types/externalwalletinfo
Information for an external wallet
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# ExternalWalletType
Source: https://docs.getpara.com/v2/references/types/externalwallettype
Type for external wallets
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# FullSignatureRes
Source: https://docs.getpara.com/v2/references/types/fullsignatureres
Full result of a signing operation
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# GetWalletBalanceResponse
Source: https://docs.getpara.com/v2/references/types/getwalletbalanceresponse
Response type for wallet balance
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# IssueJwtResponse
Source: https://docs.getpara.com/v2/references/types/issuejwtresponse
Response for issuing a JWT
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# LinkedAccounts
Source: https://docs.getpara.com/v2/references/types/linkedaccounts
Structure for primary and linked accounts
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# Network
Source: https://docs.getpara.com/v2/references/types/network
Supported networks
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# OAuthResponse
Source: https://docs.getpara.com/v2/references/types/oauthresponse
Response type for OAuth verification
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# OnRampAsset
Source: https://docs.getpara.com/v2/references/types/onrampasset
Supported on-ramp assets
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# OnRampProvider
Source: https://docs.getpara.com/v2/references/types/onrampprovider
On-ramp providers
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# OnRampPurchase
Source: https://docs.getpara.com/v2/references/types/onramppurchase
Details of an on-ramp purchase
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# OnRampPurchaseCreateParams
Source: https://docs.getpara.com/v2/references/types/onramppurchasecreateparams
Parameters for creating an on-ramp purchase
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# OnRampPurchaseStatus
Source: https://docs.getpara.com/v2/references/types/onramppurchasestatus
Statuses for on-ramp purchases
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# OnRampPurchaseType
Source: https://docs.getpara.com/v2/references/types/onramppurchasetype
Types of on-ramp purchases
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# ParaEvent
Source: https://docs.getpara.com/v2/references/types/paraevent
Events emitted by the Para SDK
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# ParaModalProps
Source: https://docs.getpara.com/v2/references/types/paramodalprops
Props for the Para modal
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void",
optional: true,
description: "Called when the modal step changes."
},
{
name: "onClose",
type: "() => void",
optional: true,
description: "Called when the modal is closed."
},
{
name: "isGuestModeEnabled",
type: "boolean",
optional: true,
description: "Whether to enable guest login. A guest user will be provisioned embedded wallets that they will then claim upon signing up through your app."
},
{
name: "loginTransitionOverride",
type: "(para: ParaWeb) => Promise",
optional: true
},
{
name: "createWalletOverride",
type: "(para: ParaWeb) => Promise<{ recoverySecret?: string, walletIds: CurrentWalletIds }>",
typeLink: "/v2/references/types/currentwalletids",
optional: true
},
{
name: "supportedAccountLinks",
type: "SupportedAccountLinks",
typeLink: "/v2/references/types/supportedaccountlinks",
optional: true,
description: "Which external accounts or wallets to allow your users to link to their accounts. Defaults to your Developer Portal configuration or to all available account types."
}
]}
/>
# ParaProviderConfig
Source: https://docs.getpara.com/v2/references/types/paraproviderconfig
Configuration for the ParaProvider
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# PartnerEntity
Source: https://docs.getpara.com/v2/references/types/partnerentity
Details for a partner entity
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# PollParams
Source: https://docs.getpara.com/v2/references/types/pollparams
Parameters for polling operations
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
void",
optional: true,
description: "A callback function that will be invoked on each method poll."
},
{
name: "onCancel",
type: "() => void",
optional: true,
description: "A callback function that will be invoked if the method call is canceled."
}
]}
/>
# PregenAuth
Source: https://docs.getpara.com/v2/references/types/pregenauth
Authentication type for pregen identifiers
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
",
typeLink: "/v2/references/types/auth"
}}
/>
# Setup2faResponse
Source: https://docs.getpara.com/v2/references/types/setup2faresponse
Response for setting up 2FA
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# StorageType
Source: https://docs.getpara.com/v2/references/types/storagetype
Types of storage
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# SuccessfulSignatureRes
Source: https://docs.getpara.com/v2/references/types/successfulsignatureres
Successful signature result
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# SupportedAccountLinks
Source: https://docs.getpara.com/v2/references/types/supportedaccountlinks
Supported account link types
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# SupportedWalletTypes
Source: https://docs.getpara.com/v2/references/types/supportedwallettypes
Array of supported wallet types with optional flag
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# TelegramAuthResponse
Source: https://docs.getpara.com/v2/references/types/telegramauthresponse
Response from Telegram authentication
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# TExternalWallet
Source: https://docs.getpara.com/v2/references/types/texternalwallet
External wallet provider types
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# Theme
Source: https://docs.getpara.com/v2/references/types/theme
Theme configuration for the portal
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# TLinkedAccountType
Source: https://docs.getpara.com/v2/references/types/tlinkedaccounttype
Types of linked accounts
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# TOAuthMethod
Source: https://docs.getpara.com/v2/references/types/toauthmethod
OAuth method types
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# TPregenIdentifierType
Source: https://docs.getpara.com/v2/references/types/tpregenidentifiertype
Types of pregen identifiers
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# TWalletScheme
Source: https://docs.getpara.com/v2/references/types/twalletscheme
Wallet scheme types
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# TWalletType
Source: https://docs.getpara.com/v2/references/types/twallettype
Wallet type union
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# VerifiedAuth
Source: https://docs.getpara.com/v2/references/types/verifiedauth
Verified authentication details
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
",
typeLink: "/v2/references/types/auth"
}}
/>
# Verify2faResponse
Source: https://docs.getpara.com/v2/references/types/verify2faresponse
Response for verifying 2FA
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
[]",
typeLink: "/v2/references/types/wallet",
required: true,
description: "The wallets protected by this 2FA instance."
}
]}
/>
# Wallet
Source: https://docs.getpara.com/v2/references/types/wallet
Represents a wallet entity
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# WalletEntity
Source: https://docs.getpara.com/v2/references/types/walletentity
Server-side wallet entity
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};
# WalletFilters
Source: https://docs.getpara.com/v2/references/types/walletfilters
Filters for selecting wallets
export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
const [isHovered, setIsHovered] = useState(false);
const [isCopied, setIsCopied] = useState(false);
const [hoveredParam, setHoveredParam] = useState(null);
const [hoveredReturn, setHoveredReturn] = useState(false);
const parseMethodName = fullName => {
const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
if (match) {
return {
name: match[1],
openParen: match[2],
params: match[3],
closeParen: match[4]
};
}
return {
name: fullName,
openParen: '',
params: '',
closeParen: ''
};
};
const methodParts = parseMethodName(name);
const handleCopy = e => {
e.stopPropagation();
navigator.clipboard.writeText(name);
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
};
return setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
!preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
{async &&
async
}
{isStatic &&
static
}
{tag &&
{tag}
}
{methodParts.name}
{methodParts.openParen}
{methodParts.params}
{methodParts.closeParen}
{deprecated &&
⚠ Deprecated
}
{since &&
Since v{since}
}
{description}
{isCopied ?
:
}
{!preventCollapse &&
{isExpanded ?
:
}
}
{parameters.length > 0 &&
Parameters
({parameters.length})
{parameters.map((param, index) =>
setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
{param.name}
:
{param.typeLink ?
{param.type}
:
{param.type}
}
{param.required &&
Required
}
{param.optional &&
Optional
}
{param.description &&
{param.description}
}
{param.defaultValue !== undefined &&
Default: {param.defaultValue}
}
)}
}
{returns &&
0 ? 'mt-6' : 'pt-6'}`}>
Returns
setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
{returns.description &&
{returns.description}
}
}
;
};