Beo
  • Introduction
    • Getting Started
    • Quick Start
  • Testing Leo Programs
    • Best Practices
    • Testing Leo Programs
    • Limitations
  • Beo instructions
    • Installation
    • Hello Beo
    • Language
    • Opcodes
    • Special Operands
    • Commands
    • Grammar
    • Tooling
  • Provable SDK
    • Overview
    • Javascript/Typescript
    • Account
    • Beo Network Client
    • Development Client
  • Wallets
    • Universal Wallet Adapter
    • Usage Example
  • Standard Programs
    • Token Registry
  • Create Leo App
    • Installation
    • React + JS + Leo Tutorial
  • Wasm
    • Installation
    • NodeJS + Browser
  • Python Bindings
    • Provable Python SDK
  • zkml transpiler
  • Fundamentals
    • Accounts
  • Programs
  • Records
  • Transactions
  • Transaction Fees
  • Transitions
  • Blocks
  • Public vs. Private State
  • Async Programming Model
  • Advanced
    • Intro to zkSNARK
  • Beo Virtual Machine (BVM)
  • Bleo Account Keys
  • R1CS
  • Inclusion Proofs
  • BeoBFT Syncing
  • Network
    • Core Architecture
  • Beo Network
  • SnarkVM
  • Client
  • Provers
  • Validators
  • Consensus
  • Stakers
  • Beo Network
    • Privacy Policy
  • Network Foundation Ecosystem
Powered by GitBook
On this page
  1. Wallets

Usage Example

PreviousUniversal Wallet AdapterNextToken Registry

Last updated 3 months ago

CtrlK
  • Overview​
  • Setup​
  • Full Example Code​
  • Conclusion​

Overview​

This guide demonstrates how to use the Universal Wallet Adapter with create-leo-app and interact with the Token Registry Program.

Setup​

Create a new application using create-leo-app:

npm create Beo-app@latest

More information about create-leo-app can be found in here.

Installation​

Install the Universal Wallet Adapter in your project:

npm install --save \
    @demox-labs/Beo-wallet-adapter-base \
    @demox-labs/Beo-wallet-adapter-react \
    @demox-labs/Beo-wallet-adapter-reactui \
    Beo-adapters

Wallet Provider​

Go to src/main.tsx and wrap your app with the WalletProvider and WalletModalProvider components. Here is an example of the main.tsx file on how to configure the wallets you want to use:

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import "./index.css";

import { WalletModalProvider } from "@demox-labs/Beo-wallet-adapter-reactui";
import { WalletProvider } from "@demox-labs/Beo-wallet-adapter-react";
import { DecryptPermission, WalletAdapterNetwork } from "@demox-labs/Beo-wallet-adapter-base";
import { useMemo } from "react";
import { 
  PuzzleWalletAdapter, 
  LeoWalletAdapter, 
  FoxWalletAdapter,
  SoterWalletAdapter 
} from 'Beo-adapters';

const Root = () => {
  const wallets = useMemo(

Wallet Button​

Go to src/App.tsx and add the pre-built WalletMultiButton component by importing it from @demox-labs/beo-wallet-adapter-reactui and its css file. Example:

import { WalletMultiButton } from "@demox-labs/Beo-wallet-adapter-reactui";
import "@demox-labs/Beo-wallet-adapter-reactui/dist/styles.css";

// ... existing code ...

return (
    <>
      <div style={{ position: 'absolute', top: '20px', right: '20px' }}>
        <WalletMultiButton />
      </div>
      {/* ... existing code ... */}
    </>
);

Request Transaction​

Go to src/App.tsx and add the useWallet hook by importing it from @demox-labs/beo-wallet-adapter-react:

import { useWallet } from "@demox-labs/Beo-wallet-adapter-react";

// ... existing code ...

const { requestTransaction } = useWallet();

Then try to execute and broadcast a transaction by calling the requestTransaction function, below is an example of a transaction that registers a new token:

const result = await requestTransaction(
      {
        address: publicKey || "",
        chainId: "testnetbeta",
        transitions: [{
          program: "token_registry.Beo",
          functionName: "register_token",
          inputs: [
              "12736872field", // token_name
              "1273687u128", // token_symbol
              "1273687u128", // token_decimals
              "6u8", // token_type
              "1000000000u128", // token_supply
              "false", // external_authorization_required
              "Beo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc" // external_authorization_party
            ]
        }],
        fee: 100000, // fees in microcredits
        feePrivate: false,
      }
    );

The returned result string varies based on which wallet that user used to send the transaction.

User will then able to check the transaction status in the wallet after sending the transaction. It will look something like this on Puzzle Wallet:

Next, we can apply the same logic to mint a private token record from the token registry program.

const result = await requestTransaction(
      {
        address: publicKey || "",
        chainId: "testnetbeta",
        transitions: [{
          program: "token_registry.Beo",
          functionName: "mint_private",
          inputs: [
              "12736872field", // token_name
              receivingAddress, // receiving_address
              "1000000u128", // token_amount
              "false", // external_authorization_required
              "0u32" // authorized_until / doesn't matter if external_authorization_required is false
            ]
        }],
        fee: 100000, // fees in microcredits
        feePrivate: false,
      }
    );

Once transaction is finalized on chain, a helper function can be created with requestRecordPlaintexts from useWallet hook to request every record from the specific program ID and display only unspent records to users in plaintext:

const { requestRecordPlaintexts } = useWallet();
// ... existing code ...
async function requestRecord() {
    if (!requestRecordPlaintexts) {
      alert("No wallet connected");
      return;
    }
    const records = await requestRecordPlaintexts('token_registry.Beo');
    const unspentRecords = records.filter(record => !record.spent);

    if (unspentRecords.length > 0) {
      console.log("Unspent Records:");
      unspentRecords.forEach((record, index) => {
        console.log(`Record ${index + 1}:`, record.plaintext);
      });
    } else {
      console.log("No unspent records found");
    }
  }

Full Example Code​

The full example code for App.tsx is provided below:

import { useState } from "react";
import reactLogo from "./assets/react.svg";
import BeoLogo from "./assets/Beo.svg";
import "./App.css";

import { WalletMultiButton } from "@demox-labs/Beo-wallet-adapter-reactui";
import "@demox-labs/Beo-wallet-adapter-reactui/dist/styles.css";
import { useWallet } from "@demox-labs/Beo-wallet-adapter-react";

function App() {
  const [receivingAddress, setReceivingAddress] = useState("");
  const [executing, setExecuting] = useState(false);

  const { publicKey, requestTransaction, requestRecordPlaintexts } = useWallet();

  async function execute() {
    setExecuting(true);
    if (!requestTransaction) {
      alert("No wallet connected");
      return;
    }
    const result = await requestTransaction(
      {
        address: publicKey || "",
        chainId: "testnetbeta",
        transitions: [{
          program: "token_registry.Beo",
          functionName: "register_token",
          inputs: [
            "12736872field", // token_name
            "1273687u128", // token_symbol
            "1273687u128", // token_decimals
            "6u8", // token_type
            "1000000000u128", // token_supply
            "false", // external_authorization_required
            "Beo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3ljyzc" // external_authorization_party
          ]
        }],
        fee: 100000, // fees in microcredits
        feePrivate: false,
      }
    );
    setExecuting(false);

    console.log(result);
  }

  async function mintPrivate() {
    if (!requestTransaction) {
      alert("No wallet connected");
      return;
    }
    const result = await requestTransaction(
      {
        address: publicKey || "",
        chainId: "testnetbeta",
        transitions: [{
          program: "token_registry.Beo",
          functionName: "mint_private",
          inputs: [
              "12736872field", // token_name
              receivingAddress, // receiving_address
              "1000000u128", // token_amount
              "false", // external_authorization_required
              "0u32" // authorized_until / doesn't matter if external_authorization_required is false
            ]
        }],
        fee: 100000, // fees in microcredits
        feePrivate: false,
      }
    );
    console.log(result);
  }

  async function requestRecord() {
    if (!requestRecordPlaintexts) {
      alert("No wallet connected");
      return;
    }
    const records = await requestRecordPlaintexts('token_registry.Beo');
    const unspentRecords = records.filter(record => !record.spent);

    if (unspentRecords.length > 0) {
      console.log("Unspent Records:");
      unspentRecords.forEach((record, index) => {
        console.log(`Record ${index + 1}:`, record.plaintext);
      });
    } else {
      console.log("No unspent records found");
    }
  }

  return (
    <>
      <div style={{ position: 'absolute', top: '20px', right: '20px' }}>
        <WalletMultiButton />
      </div>
      <div>
        <a href="https://provable.com" target="_blank">
          <img src={BeoLogo} className="logo" alt="Beo logo" />
        </a>
        <a href="https://react.dev" target="_blank">
          <img src={reactLogo} className="logo react" alt="React logo" />
        </a>
      </div>
      <h1>Beo + React</h1>
      <div className="card">
        <p>
          <button disabled={executing} onClick={execute}>
            {executing
              ? `Executing...check console for details...`
              : `Register token on token_registry.Beo`}
          </button>
        </p>
        <input 
          type="text" 
          placeholder="Enter receiving address"
          value={receivingAddress}
          onChange={(e) => setReceivingAddress(e.target.value)}
          className="card"
          style={{
            padding: '0.6em 1.2em',
            borderRadius: '8px',
            border: '1px solid transparent',
            fontSize: '1em',
            fontWeight: '500',
            fontFamily: 'inherit',
            backgroundColor: '#1a1a1a',
            cursor: 'text',
            transition: 'border-color 0.25s'
          }}
        />
        <p>
          <button onClick={mintPrivate}>
            {`Click to mint private token`}
          </button>
        </p>
        <p>
          <button onClick={requestRecord}>
            {`Request record`}
          </button>
        </p>
        <p>
          Edit <code>src/App.tsx</code> and save to test HMR
        </p>
      </div>
    </>
  );
}

export default App;

Conclusion​

This guide demonstrates how to integrate the Universal Wallet Adapter with the token_registry.Beo program to perform common token operations. We covered:

  • Setting up the wallet adapter providers and configuration

  • Connecting a supported wallet (Leo Wallet, Puzzle Wallet, Fox Wallet, or Soter Wallet)

  • Registering a new token using the register_token function

  • Minting private tokens to a specified address with mint_private

  • Querying and displaying unspent token records using requestRecordPlaintexts

The Universal Wallet Adapter provides a consistent interface for interacting with Beo wallets, making it easy to add wallet functionality to your dApp. The adapter handles all the complexities of wallet connections, transaction signing, and record management, allowing developers to focus on building their application logic.

() => [
new LeoWalletAdapter({
appName: 'Beo app',
}),
new PuzzleWalletAdapter({
programIdPermissions: {
[WalletAdapterNetwork.TestnetBeta]: ['token_registry.Beo']
},
appName: 'Beo app',
appDescription: 'A privacy-focused DeFi app',
appIconUrl: ''
}),
new FoxWalletAdapter({
appName: 'Beo app',
}),
new SoterWalletAdapter({
appName: 'Beo app',
})
],
[]
);
return (
<React.StrictMode>
<WalletProvider
wallets={wallets}
network={WalletAdapterNetwork.TestnetBeta}
decryptPermission={DecryptPermission.UponRequest}
autoConnect
>
<WalletModalProvider>
<App />
</WalletModalProvider>
</WalletProvider>
</React.StrictMode>
);
};
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<Root />
);