Solana Provider

After setting up your wallet, you can have access to the Solana provider:

// react
const { providers } = useTomo()
const { solanaProvider } = providers;

// pure js
const solanaProvider = window.tomo_sol

Get Solana Address

the Solana address from the wallet state or provider. In React framework:

// get address from wallet state
const { walletState } = useTomo()
const solanaAddress = walletState.solanaAddress

// or get address from provider
const { providers } = useTomo()
const solanaAddress = await providers.solanaProvider.getAddress()

Or Pure JS:

/** pure js */
import { getWalletState } from '@tomo-inc/tomo-web-sdk';
// get from wallet state
const walletState = getWalletState()
const solanaAddress = walletState.solanaAddress

// or get from provider
const solanaAddress = await window.tomo_sol.getAddress()

Provider Functions

providers.solanaProvider exposes three functions for sending requests to the user's wallet:

Signing a Message

It uses the Solana provider to sign a plain text offchain message, which returns the signature of the given message with the message header.

import bs58 from 'bs58'

// interface
signMessage(message: Uint8Array): Promise<Uint8Array>;

// example
const res = await solanaProvider.signMessage(new TextEncoder().encode('hello world'))
console.log('res:', bs58.encode(res))
// res:6EpGiRj6UMPWKZSNQoPsrpDxN9Mw25PmAtrWkD2V6wLZ5HLePPcwJV9DB3aCCeD2eEfW56NzuEkfXJHu2rgwhL7wweJeKJwrU7CoTvndykUPGkaM1mJb7N25NeyeUq7NBEFCNVt3LWPvDvVBmUMU88Vo6jTTjC4jPYnVsfZDrodsEx9

Sign Transaction

Given a transaction in the format of Transaction from @solana/web3.js you can use signTransactionmethod to get the signed transaction in hex value if the user approves the request.

// interface
signTransaction<T extends Transaction>(transaction: T): Promise<Transaction>;

// example, see next session for definition of createSolTx
const transaction = await createSolTx(from, to, amount);
const res = await solanaProvider.signTransaction(transaction)

Send Transaction

You can also send the transaction directly through this sendTransaction method. The return value is the transaction signature if signed and sent correctly.

// interface
type TransactionSignature = string;
sendTransaction<T extends Transaction>(transaction: T, connection?: Connection): Promise<TransactionSignature>;


// example, see next session for definition of createSolTx
const connection = getConnection()
const transaction = await createSolTx(from, to, amount, mintAddress)
const signature = await solanaProvider.sendTransaction(transaction, connection)

Example

We provide an example of a SOL transfer transaction as follows:

React

import {
  Connection,
  PublicKey,
  SystemProgram,
  Transaction
} from '@solana/web3.js'

import {
  createAssociatedTokenAccountInstruction,
  createTransferInstruction,
  getAccount,
  getAssociatedTokenAddress,
  TOKEN_PROGRAM_ID,
  TokenAccountNotFoundError,
  TokenInvalidAccountOwnerError
} from '@solana/spl-token'
import BigNumber from 'bignumber.js'
import { TomoContextProvider, useTomo } from '@tomo-inc/tomo-web-sdk'
import '@tomo-inc/tomo-web-sdk/style.css'

const solEndpoint = 'Your rpc endpoint'
const CLIENT_ID = 'Your client id'

// Get Sol Connection
function getConnection() {
  const connection = new Connection(solEndpoint, 'recent')
  return connection
}

// Get Sol Connection
let connection: Connection
function getConnection() {
  if (!connection) {
    connection = new Connection(solEndpoint, 'recent')
  }
  return connection
}

// create transaction
async function createSolTx(
  fromAddress: string,
  toAddress: string,
  amount: number,
  mintAddress?: string
) {
  try {
    const connection = getConnection()
    const tx = new Transaction()
    const fromPublicKey = new PublicKey(fromAddress)
    const toPublicKey = new PublicKey(toAddress)

    if (!tx.feePayer) {
      tx.feePayer = fromPublicKey
    }

    if (mintAddress) {
      const tokenPublicKey = new PublicKey(mintAddress)
      const fromTokenPubKey = await getAssociatedTokenAddress(
        tokenPublicKey,
        new PublicKey(fromAddress)
      )
      const toTokenPubKey = await getAssociatedTokenAddress(
        tokenPublicKey,
        new PublicKey(toAddress)
      )

      tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash

      let account: any
      try {
        account = await getAccount(connection, toTokenPubKey)
      } catch (error: unknown) {
        if (
          error instanceof TokenAccountNotFoundError ||
          error instanceof TokenInvalidAccountOwnerError
        ) {
          try {
            tx.add(
              createAssociatedTokenAccountInstruction(
                fromPublicKey,
                toTokenPubKey,
                toPublicKey,
                tokenPublicKey
              )
            )
          } catch (error: unknown) {}
        } else {
          throw error
        }
      }
      console.log('account', account)

      tx.add(
        createTransferInstruction(
          fromTokenPubKey,
          toTokenPubKey,
          fromPublicKey,
          amount,
          [],
          TOKEN_PROGRAM_ID
        )
      )
    } else {
      tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash
      tx.add(
        SystemProgram.transfer({
          fromPubkey: fromPublicKey,
          toPubkey: toPublicKey,
          lamports: amount
        })
      )
    }
    return tx
  } catch (e) {
    return null
  }
}

enum Theme {
  Light = 'light',
  Dark = 'dark'
}

export default function SOLDemo() {
  return (
    <TomoContextProvider
      theme={Theme.Light}
      chainTypes={['solana']}
      clientId={CLIENT_ID}
    >
      <App />
    </TomoContextProvider>
  )
}
function App() {
  const { providers, walletState, openConnectModal } = useTomo()
  const { solanaProvider } = providers

  return (
    <div style={{ display: 'flex', gap: '10px' }}>
      <button onClick={openConnectModal}>openConnectModal</button>
      <br />
      <button
        onClick={async () => {
          const from = walletState.solanaAddress || ''
          const to = 'xxx'
          const decimals = 9
          const amount = Number(new BigNumber(0.00001).shiftedBy(decimals))
          const transaction = await createSolTx(from, to, amount)

          if (!transaction) throw new Error('Failed to create transaction')

          const res = await solanaProvider.signTransaction(transaction)
          console.log('sign transaction res:', res)

          // continue to send transaction
          // const tx = await solanaProvider.sendTransaction(res)
          // console.log('send transaction res:', tx)
        }}
      >
        sign sol transaction
      </button>
      <br />
      <button
        onClick={async () => {
          const from = walletState.solanaAddress || ''
          const to = 'xxxx'
          const usdtMintAddress = 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB'
          const decimals = 6
          const amount = Number(new BigNumber(0.00001).shiftedBy(decimals))
          const transaction = await createSolTx(from, to, amount, usdtMintAddress)
          if (!transaction) throw new Error('Failed to create transaction')

          const connection = getConnection()
          const res = await solanaProvider.sendTransaction(transaction, connection)
          console.log('send token transaction res:', res)
        }}
      >
        send spl token transaction
      </button>
    </div>
  )
}

Pure JavaScript

import {
  Connection,
  PublicKey,
  SystemProgram,
  Transaction
} from '@solana/web3.js'

import {
  createAssociatedTokenAccountInstruction,
  createTransferInstruction,
  getAccount,
  getAssociatedTokenAddress,
  TOKEN_PROGRAM_ID,
  TokenAccountNotFoundError,
  TokenInvalidAccountOwnerError
} from '@solana/spl-token'
import BigNumber from 'bignumber.js'
import { CLIENT_ID } from 'constant'
import { initTomoModal } from '@tomo-inc/tomo-web-sdk'
import '@tomo-inc/tomo-web-sdk/style.css'

const solEndpoint = 'Your rpc endpoint'
const CLIENT_ID = 'Your client id'

// Get Sol Connection
function getConnection() {
  const connection = new Connection(solEndpoint, 'recent')
  return connection
}

// Get Sol Connection
let connection: Connection
function getConnection() {
  if (!connection) {
    connection = new Connection(solEndpoint, 'recent')
  }
  return connection
}


// create transaction
async function createSolTx(
  fromAddress: string,
  toAddress: string,
  amount: number,
  mintAddress?: string
) {
  // ...
}

enum Theme {
  Light = 'light',
  Dark = 'dark'
}
initTomoModal({
  onConnect: (param) => {
    console.log('onConnect', param)
  },
  theme: Theme.Light,
  clientId: CLIENT_ID,
  chainTypes: ['solana']
})
export default function SOLPureDemo() {
  return (
    <div style={{ display: 'flex', gap: '10px' }}>
      <button
        onClick={() => {
          window.openTomoConnectModal?.()
        }}
      >
        openTomoConnectModal
      </button>

      <button
        onClick={async () => {
          const solanaProvider = window.tomo_sol
          if (!solanaProvider) return
          const solanaAddress = await solanaProvider?.getAddress()
          const from = solanaAddress || ''
          const to = 'xxxx'
          const decimals = 9
          const amount = Number(new BigNumber(0.000001).shiftedBy(decimals))
          const transaction = await createSolTx(from, to, amount)

          if (!transaction) throw new Error('Failed to create transaction')

          const res = await solanaProvider.signTransaction(transaction)
          console.log('sign transaction res:', res)
        }}
      >
        sign sol transaction
      </button>

      <button
        onClick={async () => {
          const solanaProvider = window.tomo_sol
          if (!solanaProvider) return
          const solanaAddress = await solanaProvider?.getAddress()
          const from = solanaAddress || ''
          const to = 'xxxx'
          const usdtMintAddress = 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB'
          const decimals = 6
          const amount = Number(new BigNumber(0.000001).shiftedBy(decimals))
          const transaction = await createSolTx(from, to, amount, usdtMintAddress)
          if (!transaction) throw new Error('Failed to create transaction')

          const connection = getConnection()
          const res = await solanaProvider.sendTransaction(transaction, connection)
          console.log('send token transaction res:', res)
        }}
      >
        send spl token transaction
      </button>
    </div>
  )
}

Last updated