Skip to main content

Sending Serialized Transactions

note

This guide is for sending serialized transactions that are signed by the user's wallet (usually on the client side). If you want to send transactions signed by the project's shadow signer, refer to the Sending Serialized Transactions (Shadow Signer) guide.

Intro

In most cases when you interact with the Edge Client to perform actions like creating a user, mining resources, or sending characters on missions, you will receive a JSON object containing the last valid block height, the block hash, and the serialized transaction.

The serialized transaction is sent in response so developers can get it signed by the proper authority before sending it to the blockchain. Here's a step by step guide.

1. Setup your application

In order to use Solana wallets, you'll setup your frontend like this.

Install the necessary dependencies.


npm install @solana/wallet-adapter-react @solana/wallet-adapter-base @solana/wallet-adapter-react-ui @solana/web3.js

You'll setup your application like this. (This is a basic example, you can customize it as needed)


import { useMemo } from "react";
import {
ConnectionProvider,
WalletProvider,
} from "@solana/wallet-adapter-react";
import { WalletAdapterNetwork } from "@solana/wallet-adapter-base";
import {
WalletModalProvider,
WalletMultiButton,
} from "@solana/wallet-adapter-react-ui";
import { clusterApiUrl } from "@solana/web3.js";
import "./App.css";

// Default styles that can be overridden by your app
import "@solana/wallet-adapter-react-ui/styles.css";

function App() {
// The network can be set to 'devnet', 'testnet', or 'mainnet-beta'.
const network = WalletAdapterNetwork.Devnet;
// You can also provide a custom RPC endpoint.
const endpoint = useMemo(() => clusterApiUrl(network), [network]);

const wallets = useMemo(
() => [
// if desired, manually define specific/custom wallets here (normally not required)
// otherwise, the wallet-adapter will auto detect the wallets a user's browser has available
],
[network],
);

return (
<ConnectionProvider endpoint={endpoint}>
<WalletProvider wallets={wallets} autoConnect>
<WalletModalProvider>
<WalletMultiButton />
<h1>Hello Solana</h1>
</WalletModalProvider>
</WalletProvider>
</ConnectionProvider>
);
}

export default App;

2. Sign the transaction

Once you have the serialized transaction, you can sign it using the Solana wallet.

The useWallet hook from @solana/wallet-adapter-react can be used to get the user's wallet (if the wallet is connected).


import { useWallet } from "@solana/wallet-adapter-react";

const wallet = useWallet();

Once you have the user's wallet, sign the transactions and proceed to the next step.

Here's an example snippet of how we're signing the transactions in one of our own projects.


import * as web3 from "@solana/web3.js";
import { WalletContextState } from "@solana/wallet-adapter-react";
import base58 from "bs58";

const connection = new Connection("RPC_URL");

export async function sendTxns(
wallet: WalletContextState,
transactions: Transactions,
) {
const blockhash = (await connection.getRecentBlockhash()).blockhash;
const allTxns = transactions!.transactions.map((txStr) => {
let tn = web3.VersionedTransaction.deserialize(base58.decode(txStr));
tn.message.recentBlockhash = blockhash;
return tn;
});
const txs = await wallet
.signAllTransactions(allTxns)
.then((txs) => {
return txs.map((tx) => base58.encode(tx.serialize()));
})
.catch((e) => {
console.error("Failed to sign transactions: ", e);
throw new Error(e);
});

// Query the Edge Client to send the transactions (see next step)
}


3. Send the transaction

Once the transaction is signed, you can execute it on the blockchain by querying the Edge Client like this.


query SendBulkTransactions($txs: [Bytes!]!, $blockhash: String!, $lastValidBlockHeight: Int!, $options: SendBulkTransactionsOptions) {
sendBulkTransactions(txs: $txs, blockhash: $blockhash, lastValidBlockHeight: $lastValidBlockHeight, options: $options) {
error
signature
status
}
}

Set the variables like this:


{
"txs": [
"<serialized transaction 1>",
"<serialized transaction 2>"
],
"blockhash": "<blockhash>",
"lastValidBlockHeight": <last valid block height>,
"options": {
"commitment": "processed",
"skipPreflight": false
}
}