NEAR Guest Wallet Widget
Increase user engagement with this React component that sets up a NEAR guest wallet for your visitors on their first load.
Give your visitors a frictionless experience on performing on-chain transactions and using smart-contracts without the need of their own wallet. Perfect for beginners and for new product launches! 👌

Creating the Guest Wallet
This code needs to be executed on the server-side of your application, since creating new NEAR sub-accounts require you to provide the private keys of a parent account.
The clue is to return a JSON object that mimics the Wallet Selector localStorage
format so that it would pick the expected guest-wallet when a user enters.
If the new account will interact with an NEP141 fungible token, you'll need to register the account and transfer the minimum NEAR to activate the account with the source NEP141 contract.
import { v4 as uuidv4 } from "uuid";
import { KeyPair } from "near-api-js/lib/utils/key_pair";
import { NextApiRequest, NextApiResponse } from "next";
import * as nearAPI from "near-api-js";
import { BN } from "bn.js";
import logger from "providers/logger";
import near from "providers/near";
import { FungibleTokenContract } from "providers/near/contracts/fungible-token/contract";
import pulse from "providers/pulse";
export default async function Fn(_request: NextApiRequest, response: NextApiResponse) {
try {
logger.info(`creating Prompt Wars guest account`);
const accountId = near.getConfig().guestWalletId;
const connection = await near.getPrivateKeyConnection(process.env.NEAR_OWNER_PRIVATE_KEY, accountId);
const account = await connection.account(accountId);
const id = `guest-${uuidv4().slice(0, 5)}.${accountId}`;
const pk = KeyPair.fromRandom("ed25519");
const publicKey = pk.getPublicKey();
logger.info(publicKey.toString(), id, accountId);
await account.createAccount(id, publicKey, new BN(nearAPI.utils.format.parseNearAmount("0.2") as string));
await FungibleTokenContract.register(pulse.getDefaultCollateralToken().accountId, id);
await FungibleTokenContract.staticFtTransferCall(pulse.getDefaultCollateralToken().accountId, "50000", id);
response.status(200).json({
promptwars_wallet_auth_key: { accountId: id, allKeys: [publicKey.toString()] },
[`near-api-js:keystore:${id}:${near.getConfig().networkId}`]: pk.toString(),
"near-wallet-selector:contract": { contractId: near.getConfig().factoryWalletId },
});
} catch (error) {
logger.error(error);
response.status(500).json({ error: (error as Error).message });
}
}
Create a Guest Wallet Selector Module
When you setup the NEAR Wallet Selector modules, you'll want to insert your own instance of a guest-wallet module so that you have control on the ID and the way it connects your guest user.
See Calling the API Endpoint for full implementation.
const walletSelector = await setupWalletSelector({
network,
modules: [
setupGuestWallet(), <== custom module here
setupNearWallet(),
setupMyNearWallet(),
setupNearFi(),
setupHereWallet(),
setupMathWallet(),
setupSender(),
setupNightly(),
setupMeteorWallet(),
setupLedger(),
setupCoin98Wallet(),
],
});
Calling the API endpoint
The next step is to GET the endpoint JSON object and parse it to set the localStorage properties, see line 188+ and how it waits for selector
to exist first. Then call initGuestConnection
to initialize a new NEAR Wallet Connection.
This new Wallet connection will be stored in the WalletStateContextController, so that it can be used in your components:
useEffect(() => {
if (!selector) {
return;
}
(async () => {
try {
if (ls.get("near_app_wallet_auth_key") !== null) {
console.log(`existing non-guest wallet connected`);
return;
}
walletStateContext.setActions((prev) => ({
...prev,
isGettingGuestWallet: true,
}));
const walletAuthKey = ls.get<{
accountId: string;
allKeys: Array<string>;
}>("promptwars_wallet_auth_key");
if (walletAuthKey !== null && /^guest-/i.test(walletAuthKey?.accountId)) {
initGuestConnection(walletAuthKey.accountId);
return;
}
const response = await fetch(routes.api.promptWars.createGuestAccount());
const result = await response.json();
ls.set("near-wallet-selector:selectedWalletId", JSON.stringify("guest-wallet"));
ls.set("near-wallet-selector:recentlySignedInWallets", JSON.stringify(["guest-wallet"]));
ls.set(Object.keys(result)[0], result[Object.keys(result)[0]]);
ls.set(Object.keys(result)[1], result[Object.keys(result)[1]]);
ls.set(Object.keys(result)[2], result[Object.keys(result)[2]]);
console.log(result);
const { accountId } = result.promptwars_wallet_auth_key;
initGuestConnection(accountId);
} catch (error) {
console.log(error);
walletStateContext.setActions((prev) => ({
...prev,
isGettingGuestWallet: false,
}));
}
})();
}, [selector]);
Using the Guest Wallet Connection Instance
Now that a React context state has a wallet instance, you can use it to display values on a widget component.
See WalletStateContextController.tsx to learn how to use this React context pattern.
{wallet.isConnected ? (
Last updated