This is a minimal React application for demonstrating the Snickerdoodle web-native analytics package. It is meant to be an example guide for adding Snickerdoodle analytics to your own React-based dApp.
This example repo specifically uses RainbowKit in conjunction with Wagmi for establishing a connection with a user's wallet. However, Snickerdoodle analytics is unopinionated in regards to the wallet connection technology. It can easily be used with other technologies like WalletConnect or simply use the window.ethereum
object available on most browser extension-based wallet applications.
If you want to run this project locally or make your own modification, see DEV.md
.
You'll need to add @snickerdoodlelabs/web-integration
to your dependency list:
yarn add @snickerdoodlelabs/web-integration
or if you are using NPM:
npm install @snickerdoodlelabs/web-integration
Snickerdoodle's web analytics package can fetch web3 data from multiple API providers (for redundancy and robustness). Checkout .example.env.local
for a template environment variable file. Snickerdoodle recommends that you provide your own web3 API keys if you have hundreds of thousands of users or more so that indexer requests are not throttled. You will use these environment variables in your application.
If you choose to provide your own API keys, put them into an object which will be used as an input for step 3. The Typescript interface IConfigOverrides defines this type if you are using TS. In this full running example, we are using
environnement variables that are referenced with process.env
. You project may be configured to reference environment variables in a different fashion.
const webIntegrationConfig = {
primaryInfuraKey: process.env.REACT_APP_INFURA_API_KEY!,
ankrApiKey: process.env.REACT_APP_ANKR_API_KEY!,
covalentApiKey: process.env.REACT_APP_COVALENT_API_KEY!,
poapApiKey: process.env.REACT_APP_POAP_API_KEY!,
};
Note: You do not need to specify your own API keys. Snickerdoodle's web-integration
analytics package comes with default API keys. The default keys may be rate limited, however, and this may affect your performance. Snickerdoodle recommends all integrators acquire their own keys before deploying to production. If you choose to rely on the default API keys set your config object to {}
:
const webIntegrationConfig = {};
You must import SnickerdoodleWebIntegration
into your application:
import { SnickerdoodleWebIntegration } from '@snickerdoodlelabs/web-integration';
Additionally, if you choose one of the signature-based authentication methods in step 4, you must also import some objects:
import { EVMAccountAddress, Signature, EChain } from "@snickerdoodlelabs/objects";
Note You do not need to import from @snickerdoodlelabs/objects
if you simply use the default initialization method described in section 4.
Snickerdoodle analytics offers 3 equivalent methods to authenticate a user's wallet against their decentralized user profile:
- A Snickerdoodle-managed EIP-191 (personal sign) prompt
- An application-managed EIP-191 (personal sign)) prompt
- An application-managed EIP-712 (sign typed data) prompt
If your dApp does not already ask a user for a login signature, allowing the Snickerdoodle analytics package to prompt the user for a simple login signature
is likely the simplest route. See the LetSnickerdoodleSign()
component. The relevant code block is the following:
const webIntegration = new SnickerdoodleWebIntegration(webIntegrationConfig, ethersSigner);
webIntegration.initialize();
Note: The ethersSigner
object is assumed to be a V5 Ethers signer object. If you are using wagmi
to manage signature requests, you'll probably need to
add ethers.ts
to you project and import it in an appropriate location;
If your dApp is already prompting the user to perform a simple signature of a login message, you can use the result of that operation to authenticate the user's
wallet against their decentralized profile. See the AskToSimpleSign()
component. The relevant code block is the following:
const webIntegration = new SnickerdoodleWebIntegration(webIntegrationConfig,);
webIntegration.initialize().andThen((proxy) => {
return proxy.account.addAccountWithExternalSignature(
EVMAccountAddress(address),
myMessage,
Signature(data),
EChain.EthereumMainnet, // you can set this to an appropriate network for your app
);
}).mapErr((err) => {console.log(err);});
Important
When calling new
on the SnickerdooodleWebIntegration
object, leave the second argument empty, otherwise the end user will be prompted with a Snickerdoodle login message.
If you dApp is already prompting the user to perform a signature of a typed data payload that is EIP-712 compatible, you can use the result of that operation to authenticate the user's wallet against their decentralized user profile. See the AskToSignTypedData()
component. The relevant code block is the following:
const webIntegration = new SnickerdoodleWebIntegration(webIntegrationConfig,);
webIntegration.initialize().andThen((proxy) => {
return proxy.account.addAccountWithExternalTypedDataSignature(
EVMAccountAddress(address),
domain,
types,
message,
Signature(data),
EChain.EthereumMainnet, // you can set this to an appropriate network for your app
);
}).mapErr((err) => {
console.log(err);
});
Important
When calling new
on the SnickerdooodleWebIntegration
object, leave the second argument empty, otherwise the end user will be prompted with a Snickerdoodle login message.
You must add a single TXT Record to your application's DNS Records so that the analytics package will trigger the user agreement popup when a new user connects their wallet to your dApp. See our official documentation for more info.
Snickerdoodle offers support for non-EVM chains through the addAccountWithExternalSignature
method as described in section 4. For example, if you are integrating this package into a Solana application, you can
activate the analytics package by passing a Solana signature in a similar fashion:
import { SolanaAccountAddress, Signature, EChain } from "@snickerdoodlelabs/objects";
const webIntegration = new SnickerdoodleWebIntegration(webIntegrationConfig,);
webIntegration.initialize().andThen((proxy) => {
return proxy.account.addAccountWithExternalSignature(
SolanaAccountAddress(address),
myMessage,
Signature(data),
EChain.Solana, // Solana's chain id is -1 by convention in Snickerdoodle's enum type
);
}).mapErr((err) => {console.log(err);});