⛓️Solana
Follow these steps for a turnkey implementation of Civic Pass on Solana and SVM chains
Overview
Frontend integration using the React library to trigger pass issuance and check pass state in your app
Backend integration using the Typescript library to check for a valid Civic Pass server-side
On-Chain integration to check for a valid Civic Pass during smart contract program execution
Frontend Integration
Civic provides two React libraries to manage the issuance and status of your users' Civic Passes directly from your front-end.
The first one is a UI modal that overlays your existing UI, keeping your users within your experience. This modal will walk the user through the verification process.
The second one is an Identity Button to display user's Pass Status, ie. active, expired, revoked, and then trigger the verification process through the UI modal.
Install the React component
Install the Civic Gateway library for your chain.
Next, import and configure the GatewayProvider
component.
The GatewayProvider is a React component that enables your dApp frontend to:
access all available information of your user's Civic Pass
trigger the issuance and refresh of a new Civic Pass
The required configuration properties vary slightly depending on the chain.
Implementation
Children wrapped by this GatewayProvider
will have access to the connected wallet's Civic Pass. This is where you want to add the Identity Button and any of the gated features in your app.
We suggest placing the <GatewayProvider>
as high up in the component tree as possible, to ensure you have access to the Civic Pass state throughout your dApp.
Configuration Parameters
The configuration parameters of the Gateway Provider vary slightly depending on the blockchain.
Property
Description
Type
wallet
An object representing the user's wallet. This may be undefined
if a wallet hasn't been connected to the dApp yet.
{
publicKey, signTransaction
}
(see definitions below)
wallet.publicKey
The user wallet's public key.
PublicKey
from @solana/web3.js
wallet.signTransaction
A function that asks the user's wallet to sign a transaction.
(transaction: Transaction) => Promise<Transaction>
where Transaction
is from @solana/web3.js
gatekeeperNetwork
The address of the Gatekeeper Network for which your Civic Passes are issued. To get started you can use the address of the CAPTCHA Verification: ignREusXmGrscGNUesoU9mxfds9AiYTezUKex2PsZV6
. In the Available Networks page you can request access to the more advanced networks.
PublicKey
from @solana/web3.js
connection
A Solana connection to any Solana network. The recommended commitment level is confirmed
.
Connection
from @solana/web3.js
cluster
The Solana network to use (i.e. devnet
, mainnet-beta
, testnet)
. This defaults to mainnet-beta
, so should be set if a different connection endpoint.
string
Advanced Configuration
Client options
You can specify some options that affect the display behavior of the Civic modal that the user interacts with:
Property
Description
Type
autoShowModal
Whether the Civic modal should appear automatically if the Civic Pass token state changes.
true | false
logLevel
The log level.
debug | info | warn | error
disableAutoRestartOnValidationFailure
[Optional] When set to true, prevents the flow to automatically restart on user validation failure (USER_INFORMATION_REJECTED). Defaults to false.
true | false
Usage example:
Paying for your customers' transactions
If your users do not have crypto wallets, you can subsidize the cost of their passes, including the transaction cost, by signing and sending the transactions yourself.
To do this:
Set the
payer
field on the front-endCreate a back-end service to sign and send the transaction
Call that back-end service from the front-end via the
handleTransaction
callback.
Ensure you verify the source of the transaction before signing! Signing arbitrary transactions from an unsecured front-end can lead to loss of funds
For more details, see here: Docs & Sample Code
Broadcasting transactions via Civic
In the default mode of operation, the transaction required to issue or refresh the Civic Pass will be signed, but not broadcasted, by Civic. The user is responsible for broadcasting the transaction, including any fees. This flow is handled transparently by the Gateway Provider, which also communicates any fees to the user via the Civic Pass modal.
Some Passes support an alternative mode such as having the Civic backend broadcast the transaction. If the Pass Network you are using supports this, you can set the gatekeeperSendsTransaction
property to true
to turn it on.
Property
Description
Type
gatekeeperSendsTransaction
Civic will send the transaction to the blockchain on behalf of the user. Defaults to false
.
true | false
forceRequireRefresh
Setting this flag forces the user to refresh their active pass when set, even if the pass is not expired. Defaults to false
.
true | false
Interact with a Civic Pass
You can also use the provided Identity Button reference implementation to handle everything described in this section.
Now that you have initialized the GatewayProvider context, you can use the included useGateway
hook to:
trigger the issuance of a new Civic Pass modal
access the state of the Civic Pass
Trigger the issuance of a Civic Pass
Calling the function requestGatewayToken
opens the modal dialog, which guides the user through the flow of collecting and verifying their information. The information collected varies depending on the configured Gatekeeper Network.
For example, this is the initial screen your users will see when issuing a Civic Liveness Pass:
Even if the user already has a Civic Pass, the modal supports being triggered for any possible pass status and will always display the correct screen that corresponds with that Civic Pass status.
If the the user already has a Civic Pass, triggering the modal again via requestGatewayToken
displays the following screen:
Access the status of the Civic Pass
All children of the GatewayProvider have access to the user's Civic Pass status via the useGateway function.
The gatewayStatus
indicates the overall status of the Civic Pass and should be displayed in your dApp either via custom UI or by integrating the Civic Identity Button included with the library.
The gatewayToken represents the on-chain structure of the Civic Pass. This will is only defined if the Civic Pass is ACTIVE.
If the token does not exist or is in a inactive state (e.g. frozen), this variable will be undefined
. The dApp should disable certain parts of the UI when gatewayToken is undefined
to prevent dApp usage. This only complements the on-chain check and does not replace it.
Add the Identity Button
For convenience and less code, simply drop the Identity Button widget into your UI.
It will handle both displaying the user's Civic Pass status and triggering the issuance flow for new users, all without them ever leaving your dApp.
Identity Button Specifications
The Identity button changes appearance with text and icons to indicate when the user needs to take action. It can be clicked by the user at any point in the process.
Simple Implementation
The initial click on the button by a user initiates the Civic Pass modal which will guide the user through the process of issuing their Civic Pass. If a Civic Pass already exists for the connected wallet, the UI will update to show the 'Active' status.
Once the user has gone through the issuance flow via the Civic Pass modal, any subsequent click will launch the Civic Pass iframe with a screen describing the current status of the process.
Property
Description
Values
mode
The default setting of the button is dark. We also provide a light mode
.
DARK | LIGHT
animation
The button provides a neat animation on hover. The default value is dark mode
true | false
Edit Pass Status UI
To expose the status of the user's Civic Pass in your UI, add the Identity Button component (also included in the Gateway library), by placing it inside the <GatewayProvider>
context you created in the previous step.
Beyond just displaying the Civic Pass status, users can also start the issuance of their Pass if they do not already have one. The Pass Status UI will update to display the correct Civic Pass status.
Civic Pass Status
Gateway Status
The gatewayStatus
indicates the overall status of the Civic Pass.
Before Issuance
Even before a Civic Pass has been issued on-chain, the Gateway Provider gives you a set of status values that you can display in our UI to keep your users informed.
Status
Description
Behavior when requestGatewayToken
is triggered
UNKNOWN
No user wallet is connected or no gatekeeper network set.
None
CHECKING
Checking whether a Pass exists for the connected wallet.
None
NOT_REQUESTED
The wallet is connected but no Pass has been requested yet.
Opens the Civic Pass modal dialog and initiates the token request flow.
COLLECTING_USER_INFORMATION
The required user information is being collected. Depending on the Network configured, this ranges from a simple CAPTCHA to full KYC.
Opens the Civic Pass modal dialog and resumes the collection of the required information.
VALIDATING_USER_INFORMATION
The user's identity information has been collected successfully and is being verified.
This status is only available when KYC is in progress and only when the user has chosen to do KYC via on their browser. I.e. not relevant for the Ignite Pass that is used with CandyMachine v2.
Opens the Civic Pass modal dialog with a user-friendly explanation of the status.
USER_INFORMATION_VALIDATED
The user's identity has been validated. This status is only available when KYC is in progress and only when the user has chosen to do KYC via on their browser. I.e. not relevant for the Ignite Pass that is used with CandyMachine v2.
Opens the Civic Pass modal dialog and asks the user to re-authenticate so that the request process can proceed.
USER_INFORMATION_REJECTED
The user's identity verification request has been rejected. This status is only available when KYC is in progress and only when the user has chosen to do KYC via on their browser. I.e. not relevant for the Ignite Pass that is used with CandyMachine v2.
Opens the Civic Pass modal displaying the reasons for the rejection.
CONFIRM_WALLET_TRANSACTION
The user needs to confirm wallet ownership on their wallet.
Opens the Civic Pass modal dialog with a user-friendly explanation of the status.
IN_REVIEW
The Civic Pass has been requested and the Gatekeeper is reviewing the request.
Opens the Civic Pass modal dialog with a user-friendly explanation of the status.
After Issuance
After a Civic has been issued on-chain, the following status values may apply.
Status
Description
Behavior when requestGatewayToken
is triggered
ACTIVE
The Civic Pass is Active. The user can trade.
Opens the Civic Pass modal dialog with a user-friendly explanation of the status.
EXPIRED
The Civic Pass has expired. Depending on the Gatekeeper Network configured, an IP check and/or proof of wallet ownership are required to refresh it.
Proof of wallet ownership is automatically initiated.
FROZEN
The Pass has been frozen, for example because the user connected from a blocked IP.
Opens the Civic Pass modal dialog with a user-friendly explanation of the status.
REVOKED
The Pass has been revoked, for example because the user connected from a banned IP.
Opens the Civic Pass modal dialog with a user-friendly explanation of the status.
Error Handling
Issuing a Civic Pass might fail because the user did not fulfill the constraints of the configured Gatekeeper Network or, seldomly, because of an unexpected technical error.
Status
Description
Behavior when requestGatewayToken
is triggered
LOCATION_NOT_SUPPORTED
The user's location is not currently supported.
Opens the Civic Pass modal dialog with a user-friendly explanation of the status.
ERROR
There was an unexpected error requesting a Civic Pass.
Opens the Civic Pass modal dialog and the user can restart the process.
REJECTED
The token requests has been rejected by the Gatekeeper.
Opens the Civic Pass modal dialog with a user-friendly explanation of the status.
Civic Pass Structure
The gatewayToken represents the on-chain structure of the Civic Pass. This will only be defined if the Civic Pass is active.
Property
Description
Type
gatekeeperNetwork
The key of the Gatekeeper Network for which the token was issued.
PublicKey
issuingGatekeeper
The key of the issuing Gatekeeper.
PublicKey
state
The on-chain token status.
State { "ACTIVE", "REVOKED", "FROZEN" }
expiryTime
The timestamp at which the on-chain token expires.
number
Backend Integration
While the react library is the easiest way to integrate Civic Pass on a frontend, there are many reasons why you may need to check the pass state on your backend. Here are a few ways to do this.
Using the API
Custom Pass holders can use the API to manage their passes. See here for details.
Using the Backend Library
The @civic/solana-gateway-ts library provides a TypeScript interface for checking pass statuses directly against the blockchain
Installation
Install the civic library and the solana web3 dependency:
Usage
You will need the following things to get started:
Check the status of your user's pass using findGatewayToken
.
Optionally, a 'revoked' flag can be passed to allow retrieval of all, even revoked, tokens.
Subscribing to Events
The library also supports subscribing to events:
On-Chain Integration
Civic's on-chain integration allows developers to leverage smart contracts to verify user identities and ensure compliance with specific criteria. This section provides an overview of deploying and managing smart contracts on various chains and example use cases.
The general idea here is: You have an instruction that should only be callable by someone with a particular type of Civic Pass. For example, a uniqueness pass check on an airdrop, or an over-18 pass check on a purchase.
Your Solana program requires two pieces of information:
The network key - provided by Civic on sign-up to Civic Pass. Typically stored inside a State account that represents an instance of your program.
The user's pass - provided as one of the accounts in the instruction you wish to gate
Anchor Integration
When using the widely-used Anchor library, you can use a Civic anchor template to achieve this gating behavior.
First, import the dependencies
Then gate your instructions like below:
For more details on implementation best practices, check out this gated airdrop example.
Non-Anchor Integration
You can use Civic's provided libraries tailored to each blockchain's programming model for a straightforward integration. Import the solana_gateway
Rust crate from crates.io as follows:
In your instruction code, call: Gateway::verify_gateway_token_account_info
For your program to be able to call the integration library, the following parameters must be passed as inputs to your dApp's transaction:
user_wallet
: The wallet account for the dApp user. A Civic Pass must have already been issued to this wallet.pass
: The address of the Civic Pass. This address can be accessed in the dApp through theuseGateway
hook on the Civic UI Component once the user has passed verification.network_key
: The network key on which the Civic Pass has been issued.
Error handling
If something goes wrong or the token it invalid, the Gateway call will return a GatewayError
. The possible values can be seen in error.rs. For error cases, the dApp smart contract should reject the transaction.
User PII Retrieval
For certain Civic Pass types where the user has to supply a document or email address, such evidence items will be made available to you for approval or rejection prior to pass issuance.
As the user reaches the end of the Civic Pass data collection flow, including authorizing the collection of their PII, they will land on a screen informing them that their request is in "partner review". This serves as the interjection point where you will be able to view, inspect and decide on the outcome of the pass issuance request.
Retrieving PII Evidence
The Gatekeeper Context will communicate a new presentation request ID when the user reaches the end of the data collection flow. See here for more detail on the use of GatewayProvider
and useGateway
.
pendingRequests?.presentationRequestId
will be the identifier referred to by REQUEST_ID in the snippets below.
High-level overview
Retrieve an access token from the Civic auth endpoint
Retrieve PII for a specific request ID from the Civic Pass Partner API
Inspect the user-provided evidence and decide it it meets the requirements
Mark the request ID as pass or fail
1. Retrieve an access token
During onboarding you will be supplied a token URL, client ID and client secret. Use these to retrieve an access token.
Request
Response
2. Retrieve PII
Use the access token from step 1 to retrieve the evidence items for a specific request.
Request
Response
3. Inspect PII evidence and decide on an outcome (only for client-owned pass networks)
In the response from 2 will be an email, data items extracted from the scanned document, as well as an array containing urls for images of the captured document front and, optionally, back. Use the URL from the array to retrieve the specific image.
Request
4. Mark the request as pass or fail (only for client-owned pass networks)
After inspecting the user-provided data and images in step 3, inform Civic that the pass should issued or rejected. Civic expects a status of either partner-pass
or partner-fail
Request
3rd Party Integrations
Solana Token Extensions
Permissioned Tokens On the Solana Blockchain
Solana Token Extensions is a feature-rich platform for building permissioned tokens on Solana. Token Extensions can be used with Civic Pass to provide a powerful, flexible, and simple mechanism for adding identity verification to a Token Extensions token using the Civic Transfer Hook. Example use-cases are real-world assets and Sybil-resistance.
For details on setting up your token, see the details in the transfer hook repository or contact us.
Realms DAO Governance Plugin
Realms is the DAO governance platform on Solana, using the spl-governance program. Civic Pass can be added to a DAO on Realms using the "plugin" system.
When using the Realms UI, no coding is required to integrate Civic Pass into your DAO. Simply follow the steps in the Realms docs page.
See section below for Civic Pass verifications available via the Realms UI. To add a pass not included in the UI dropdown, choose "Other" and enter the address manually.
Quick Reference: If you are looking for the "Community Voter Weight Add-in" to enter into the DAO Parameters, it is GgathUhdrCWRHowoRKACjgWhYHfxCEdBi5ViqYN6HVxk
Step-by-Step Tutorial: Setting up a DAO on Realms and protecting it with Civic Pass
Metaplex Candy Machine v3
We are fully integrated into MetaPlex's Candy Machine v3 protocol to enable mint protection using Candy Guard. Permissioning with Civic Pass & Candy Guard allows you to verify minters in real-time, evaluating every request to mint by your criteria, including:
conducting a bot check using CAPTCHA
checking for liveness and uniqueness
checking for a minimum age
checking buyers from locations you want to allow
checking ID documents
You can use our reference implementation UI template using Candy Machine V3 with integrated Civic Pass ->
We recommend using the latest sugar command line tool to create your mint.
Creating a protected mint using Sugar CLI
In Candy Machine v3 creation of the token guard is separate from the mint.
install sugar: currently sugar support for Candy Machine needs to be downloaded here
Create your mint (with Candy Machine v3 the mint and the token guard are created separately). Follow the prompts on the CLI:
Copy
A config.json should have been created. Edit this file and add a 'guards' section (see the section below for alternative networks):
Copy
Create the guard for your mint:
Copy
The script should run successfully and you should see output like below:
Copy
For detailed configuration instructions on how to configure and deploy your mint, please refer to MetaPlex's Sugar repository.
Code Examples and Demos
For practical implementation, refer to the code examples below, which demonstrate how to use Civic's libraries for Solana and SVM chains. These examples can be extended to incorporate composability with passes:
Last updated