@crossmint/wallet-sdk
v0.0.9-alpha.1
Published
An SDK for Crossmint Smart Contract wallets on EVM.
Downloads
18
Readme
Crossmint SDK
Crossmint SDK is a library that provides a simple and convenient interface for interacting with various blockchain accounts. This library enables developers to create and manage abstract wallets, send transactions, sign messages, and interact with smart contracts.
📋 Table of Contents
📥 Installation
npm install --save @crossmint/wallet-sdk
🌐 Connect
To initialize the Crossmint API object and connect using a Signer object, you only need the following code:
Using Signer:
import { getOrCreateWalletSigner, APIClient } from "@crossmint/wallet-sdk";
import { Signer } from "ethers";
const apiClient: APIClient; // Provide your implementation of APIClient
const signer: Signer; // Get signer object from ethers.js
const userEmail: string; // Provide the user's email address
const jsonRpcProviderConnection: string; // RPC Provider URL or chainId
// Create an initialized instance of the AbstractWallet
const wallet = await getOrCreateWalletSigner(apiClient, signer, userEmail, jsonRpcProviderConnection);
Using Web3Auth:
import { getOrCreateWalletWeb3Auth, APIClient } from "@crossmint/wallet-sdk";
import { Signer } from "ethers";
import { Blockchain, NetworkType } from '@crossmint/wallet-sdk/lib/utils/blockchainUtils';
const apiClient: APIClient; // Provide your implementation of APIClient
const web3authOptions: {
chain: Blockchain | number; //("ethereum" | "goerli" | "polygon" | "mumbai" | "optimism" | "optimism_goerli" | "arbitrum" | "arbitrum_goerli" | "base" | "base_goerli") or chainId
network: NetworkType; // Network Type ("mainnet" | "testnet" | "cyan" | "development" | "aqua")
rpcTargetUri: string; // RPC target URL. Example: "https://rpc-mumbai.maticvigil.com".
clientId: string; // Web3Auth Client ID. You can get it from your W3A Project dashboard https://dashboard.web3auth.io/home/web3auth
displayName: string; // Display Name for the chain
blockExplorer: string; // Blockchain's explorer URL. (eg: https://etherscan.io)
ticker: string; // Default currency ticker of the network (e.g: ETH)
tickerName: string; // Name for currency ticker (e.g: Ethereum)
loginProvider: LoginProviders; //("google" | "facebook" | "reddit" | "discord" | "twitch" | "apple" | "line" | "github" | "kakao" | "linkedin" | "twitter" | "weibo" | "wechat" | "email_passwordless" | "sms_passwordless" | "jwt")
email?: string; // Email address for 'email_passwordless' login.
};
// Create an initialized instance of the AbstractWallet
const wallet = await getOrCreateWalletWeb3Auth(apiClient, web3authOptions);
To connect, you will need to implement an APIClient
, which will interact with your backend server to call the necessary Crossmint APIs.
🔌 APIClient
In order for the SDK to work, we need to make a few API calls to Crossmint servers.
API keys (x-project-id
and x-client-secret
) are highly sensitive and cannot be included in requests coming from a front-end client, otherwise are easily susceptible to sniffing.
Because of this, these API calls need to be made from your own servers.
You will need to provide an implementation of APIClient
that uses your own authentication system to perform calls from the front-end SDK to your back-end, subsequently calling the Crossmint APIs.
An example APIClient
may look like this:
import { StoreAbstractWalletInput, TransferInput } from "crossmint";
class MyAPIClient implements APIClient {
private baseUri = "https://example.api.com/api";
private jwtToken: string;
constructor(jwtToken: string) {
this.jwtToken = jwtToken;
}
async getSessionKey(address: string) {
const url = `${this.baseUri}/v2-alpha1/wallets/sessionkey`;
const options = {
method: "POST",
headers: {
Authorization: `Bearer ${this.jwtToken}`,
},
body: JSON.stringify({ address }),
};
const res = await fetch(url, options);
return res.json();
}
async storeAbstractWallet(input: StoreAbstractWalletInput) {
const url = `${this.baseUri}/v2-alpha1/wallets`;
const options = {
method: "POST",
headers: {
Authorization: `Bearer ${this.jwtToken}`,
},
body: JSON.stringify(input),
};
const res = await fetch(url, options);
return res.json();
}
}
And on your backend, you'll pass on these calls to the Crossmint API and return the result. An example in next.js may look like:
// getSessionKey
export default apiHandler(async (req: NextApiRequest, res: NextApiResponse) => {
const { address, chain } = req.body;
const url = `https://example.api.com/api/v2-alpha1/wallets/sessionkey`;
const options = {
method: "POST",
headers: {
accept: "application/json",
"content-type": "application/json",
"x-project-id": process.env.CROSSMINT_PROJECT_ID,
"x-client-secret": process.env.CROSSMINT_CLIENT_SECRET,
},
body: JSON.stringify({ address, chain }),
};
const response = await fetch(url, options);
const data = await response.json();
res.status(200).json(data);
});
⚙️ Functionalities
The wallet created with getOrCreateWallet
is an instance of AbstractWallet
.
You can do the following with the AbstractWallet
:
- Send transactions
- Estimate gas
- Connect to a provider
- Get the wallet's address
- Sign messages
- Sign typed data
- Approve plugins
- Sign transactions
- Execute batch transactions
- Execute delegate calls
- List all assets associated with the wallet
- Transfer all assets associated with the wallet
For example:
const balance = await wallet.getBalance();
const signerAddress = wallet.address!;
const signedMsg = await wallet.signMessage(message);
const receipt = await wallet.sendTransaction(transaction);
In addition, AbstractWallet
provides the following specific methods:
const isValid = await wallet.verifyMessage(message, signature);
This method allows you to verify the signer of a message. message
is the original message that was signed, and signature
is the signed message. The method returns a boolean indicating whether the signature is valid or not.
🔐 Authentication & Firebase
Firebase Authentication State Check
The checkAuthState
function monitors changes in a user's Firebase authentication state. When the user is authenticated, the function fetches the user's JWT token. If the user is not authenticated, the function resolves with undefined
.
For its implementation:
import { firebaseAuth, onAuthStateChanged } from "firebase/app"; // Ensure you have the right imports based on your Firebase setup.
export const checkAuthState = (): Promise<string | undefined> => {
return new Promise((resolve, reject) => {
const auth = firebaseAuth();
onAuthStateChanged(auth, async user => {
try {
if (user) {
const jwt = await user.getIdToken(true);
resolve(jwt);
} else {
resolve(undefined);
}
} catch (error) {
reject(error);
}
});
});
};
🤝 Contributing
We welcome contributions from the community! To contribute, please fork this repository and submit a pull request.
📝 License
This project is licensed under the MIT License.