编写一个Solana链的Hello world合约并从前端调用

2,111 阅读1分钟

合约部分

这里我们使用Solana Playground编写、部署合约。

创建项目

编写合约逻辑

删除lib.rs文件中自带的内容。粘贴以下代码。

// 引入依赖
use solana_program::{
    account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, msg, pubkey::Pubkey,
};

// 程序入口
entrypoint!(process_instruction);

pub fn process_instruction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    instruction_data: &[u8],
) -> ProgramResult {
    // 打印
    msg!("Hello, world!");

    Ok(())
}

连接钱包

需要确保连接的钱包中有足以支付部署合约的gas数量的sol。

部署合约

部署合约后出现Program ID即可视为部署成功。

前端调用

前端部分基于Next.js编写。

钱包连接

使用Solana官方库进行钱包连接。在组件树外层包裹下列WalletContextProvider组件。

import { FC, ReactNode, useMemo } from "react"
import {
  ConnectionProvider,
  WalletProvider,
} from "@solana/wallet-adapter-react"
import { WalletModalProvider } from "@solana/wallet-adapter-react-ui"
import * as web3 from "@solana/web3.js"
import * as walletAdapterWallets from "@solana/wallet-adapter-wallets"
require("@solana/wallet-adapter-react-ui/styles.css")

const WalletContextProvider: FC<{ children: ReactNode }> = ({ children }) => {
  const endpoint = web3.clusterApiUrl("devnet")
  const wallets = useMemo(() => {
    return [
      new walletAdapterWallets.PhantomWalletAdapter(),
      new walletAdapterWallets.SolflareWalletAdapter(),
    ]
  }, [])

  return (
    <ConnectionProvider endpoint={endpoint}>
      <WalletProvider wallets={wallets} autoConnect={true}>
        <WalletModalProvider>{children}</WalletModalProvider>
      </WalletProvider>
    </ConnectionProvider>
  )
}

export default WalletContextProvider

调用合约

调用合约的页面的代码如下。

import {
  Connection,
  PublicKey,
  Signer,
  Transaction,
  TransactionInstruction,
  TransactionSignature,
  clusterApiUrl,
} from "@solana/web3.js"
import { Button } from "@chakra-ui/react"
import { useWallet } from "@solana/wallet-adapter-react"

let programId = new PublicKey("你的Program ID")

let connection = new Connection(clusterApiUrl("devnet"))

const Hello = () => {
  const { wallet } = useWallet()

  async function sayHello(): Promise<TransactionSignature> {
    const transaction = new Transaction()

    const instruction = new TransactionInstruction({
      keys: [],
      programId,
    })

    transaction.add(instruction)

    const transactionSignature = await wallet.adapter.sendTransaction(
      transaction,
      connection
    )

    return transactionSignature
  }

  return (
    <div>
      <Button
        onClick={() => {
          sayHello()
        }}
        >
        Say hello
      </Button>
    </div>
  )
}

export default Hello

调用合约之前要确保帐户中有足够支付gas的sol。

查看调用结果

调用合约成功后,可以在区块浏览器查看这笔交易的记录以及合约的打印输出,如下图。