小试牛刀-walletconnect二维码及交互

本文涉及的产品
应用实时监控服务-应用监控,每月50GB免费额度
任务调度 XXL-JOB 版免费试用,400 元额度,开发版规格
Serverless 应用引擎免费试用套餐包,4320000 CU,有效期3个月
简介: 最近在使用walletconnect协议和typescript语言实现相关交互功能,在此对从walletconnet协议二维码生成、连接后发送交易事务、签名事务、签名任意信息的处理进行记录,加深对walletconnect的理解,熟悉对其组件的使用,同时希望帮助到有实现相关功能的朋友。

 目录

1.编写目的

2.实现功能

3.功能详解

依赖组件

3.1 二维码生成

3.1.1 初始化SignClient

3.1.2 创建会话空间获取WC协议uri

3.1.3 生成二维码供用户扫描

3.1.4 等待扫描

3.2 发送交易事务

3.2.1 创建交易事务

3.2.2 向用户发送交易事务

3.3 签名事务

3.3.1 接收签名事务并验证

3.3.2 发送签名并发送到链上

3.4 签名任意数据并验证


Welcome to Code Block's blog

本篇文章主要介绍了

[walletconnect二维码及交互]

❤博主广交技术好友,喜欢文章的可以关注一下❤

1.编写目的

      最近在使用walletconnect协议和typescript语言实现相关交互功能,在此对从walletconnet协议二维码生成连接后发送交易事务签名事务签名任意信息的处理进行记录,加深对walletconnect的理解,熟悉对其组件的使用,同时希望帮助到有实现相关功能的朋友。

2.实现功能

  1. 二维码生成:生成wc:协议二维码供用户扫码连接.
  2. 发送交易事务:向用户发送Transaction以供用户签名.
  3. 签名事务:用户签名后将transaction提交的链上.
  4. 签名任意信息:用户对任意信息签名,同时可以完成对签名信息的验证.

3.功能详解

依赖组件

名称 版本 作用

@solana/web3.js

1.95.2

链上相关操作:生成交易事务,提交事务到链上

@walletconnect/sign-client

2.14.0

walletconnect协议相关操作:生成二维码、发送事务

solana/spl-token

0.4.8

SPL代币事务操作:生成SPL代币事务

qrcode

1.5.3

生成二维码

注:这里的链是SOL链,其它链用法类似.SPL代币即除主要代币之外的代币.

3.1 二维码生成

3.1.1 初始化SignClient

       SignClient作为与用户wallet交互的主要实现类,在开始时要进行初始化,初始化要使用参数分别是metadataprojectId,metadata是项目相关信息,这些信息会在连接时进行展示.projectId是在walletconnect官网申请的项目ID.代码如下:

const metadata={
  //项目名称
  name: 'BoggyGame',
  //项目解释
  description: 'BoggyGame Bot',
  //项目官网
  url: 'https://www.boggycoin.com',
  //项目图片
  icons: [
    "https://i.postimg.cc/sftPCk3M/photo-2024-07-12-14-12-43.jpg"
  ]
}
//项目ID
const projectId="0176e783e7c5b0713450333ff866c2d6"

image.gif

       然后就可以对SignClient进行初始化,为保证性能,这里SignClient使用单例,代码如下:

async function getSignClient() {
  if (!signClient) {
    signClient = await SignClient.init({
      projectId: projectId, // 替换为你的项目ID
      metadata: metadata
    });
  }
  return signClient;
}

image.gif

3.1.2 创建会话空间获取WC协议uri

       使用signClient进行和中继器的对等连接配对(实际为websocket链接),并获取订阅的主题(topic),然后将会话空间数据上传到对应的主题,即可获取uri和等待授权方法,实现代码如下:

export async function initWalletConnect(onApproval: (approval: any) => void):Promise<String|undefined> {
    const signClient = await getSignClient()
    // 创建对等连接获取主题
    const {topic} = await signClient.core.pairing.create()
    // 发送命名空间,获取uri和等待授权的函数
    const { uri,approval } = await signClient.connect({
      pairingTopic: topic,
       //空间方法
      requiredNamespaces: {
        solana: {
          methods: [
            "solana_signTransaction",
            "solana_signMessage",
          ],
          chains: [
            "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"
          ],
          events: []
        }
      }
    })
    // 调用回调函数处理 approval
    if (approval) {
        onApproval(approval);
    }
    
    return uri;
}

image.gif

       这里存在两个方法solana_signTransactionsolana_signMessage方法,分别是签名交易事务和签名消息,空间内未定义的方法将无法调用.onApproval: (approval: any)用于接收外部传输的监听方法,方便在外部获取approval.

3.1.3 生成二维码供用户扫描

       生成二维码可以使用qrcode库,直接将uri的连接字符串生成为二维码,代码如下:

import QRCode from 'qrcode';
export async function generateQR(data: string): Promise<any> {
    const qrBuffer = await QRCode.toBuffer(data, {
        width: 300,  //宽度和高度
        margin: 4    //边框距离
    });
    return qrBuffer;
}

image.gif

3.1.4 等待扫描

       可以使用await approval()方法实现等待扫描授权,授权完成会获得当前连接session,同时可以获得当前连接的account,实现代码如下:

//等待扫码后授权
    const session=await approval();
    //获取链接的账号
    const account=session.namespaces.solana.accounts[0].split(':')[2];
    //打印账号
    console.log(account)

image.gif

3.2 发送交易事务

3.2.1 创建交易事务

       创建交易事务时需要用到@solana/web3.js库,这里我们创建一个转移SPL代币事务,我们需要两个地址(即发送方和接收方),同时因为是Solana链,所以需要获取这两个账户实际的AssociatedToken地址(即实际存储SPL代币的账户地址),同时需要代币的Mint地址和合约地址以及发送的数量,同时为加快交易的速度,需要设置UnitPriceUnitLimit(即增加一些交易费用来保证用户交易速度),实现代码如下:

export async function getTransaction(    
    senderPublicKey: string, 
    drawPublicKey: string,
    tokenAmount: number):Promise<Transaction> {
    //发送方公钥
    const senderPubkey = new PublicKey(senderPublicKey); 
    //接收方公钥
    const drawPubkey = new PublicKey(drawPublicKey);
    //代币MINT地址
    const tokenMintAddress = BOGGY_TOKEN_MINT;  
    //获取发送方AssociatedToken账户
    const sourceTokenAccount = await getAssociatedTokenAddress(tokenMintAddress,senderPubkey); //获取ACT账户
     //获取接收方AssociatedToke账户
    const destTokenAccount = await     getAssociatedTokenAddress(tokenMintAddress,drawPubkey);  
    //创建转移数据
    const transferInstruction = createTransferInstruction( 
        sourceTokenAccount,
        destTokenAccount,
        senderPubkey,
        tokenAmount * 1e9,
        [],
        TOKEN_PROGRAM_ID
    );
    // 创建 compute unit price 指令,提高交易速度
    const computeUnitPriceInstruction = ComputeBudgetProgram.setComputeUnitPrice({
        microLamports: 7500,
    });
    const computeUnitLimitInstruction=ComputeBudgetProgram.setComputeUnitLimit({
        units:200000
    })
    //创建事务并添加上面的三个交易数据信息
    const transaction=new Transaction().add(computeUnitPriceInstruction,computeUnitLimitInstruction,transferInstruction)
    //设置最新的区块hash
    transaction.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
    //设置交易费用由发送方支出
    transaction.feePayer=senderPubkey;
    
    return transaction;
}

image.gif

3.2.2 向用户发送交易事务

       通过SignClient.request方法可以向用户发送(通过中继器转发)交易事务,并等待用户的签名,实现代码如下:

const transaction=await getTransaction(
        发送方地址,接收方地址,代币数量
    )
    const result = await signClient!.request<{ signature: string }>({
        chainId:'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
        topic: session!.topic,
        request: {
        method: "solana_signTransaction",
        params: {
            //付款方地址
            feePayer: transaction.feePayer!.toBase58(),
            //最近区块链hash
            recentBlockhash: transaction.recentBlockhash,
            //transaction中数据遍历封装
            instructions: transaction.instructions.map((i) => ({
            //合约ID
            programId: i.programId.toBase58(),
            //数据
            data: Array.from(i.data),
            //发送方和接收方
            keys: i.keys.map((k) => ({
                isSigner: k.isSigner,
                isWritable: k.isWritable,
                pubkey: k.pubkey.toBase58(),
            })),
            })),
        },
        },
    });

image.gif

       这里因为transaction没有直接转换为walletconnect通信格式的方法,所以需要将transaction中的数据取出重新封装,当然也可以直接封装为walletconnet通信数据格式使用.

3.3 签名事务

3.3.1 接收签名事务并验证

       用户签名数据后,即可获得签名后的Signature值,这里需要对返回后的Signature验证是否有效,然后添加到签名到transaction中,实现代码如下:

//添加签名
transaction.addSignature(
     //签名方即发送方
     transaction.feePayer,
     //获取到的签名信息
     Buffer.from(bs58.decode(result.signature))
    );
//验证签名是否有效
const valid = transaction.verifySignatures();

image.gif

3.3.2 发送签名并发送到链上

       直接使用sendRawTransaction方法,将数据发送到链上,返回的txId值应该和用户的签名值相同,实现代码如下:

export async function sendTransaction(transaction:Transaction){
    const txId =await connection.sendRawTransaction(transaction.serialize())
    return txId;
}

image.gif

3.4 签名任意数据并验证

       可以使用签名完成任意数据的认证,这种认证主要用于用户登录的确认,如让用户签名一段随机信息,签名有效则可以认为用户完成登录,从而完成用户wallet网站登录,实现代码如下:

const response=await signClient.request({
         topic:session.topic,
         //链ID
         chainId:'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
         request:{
             method: 'solana_signMessage',
             params: {
                //随机字符串 
message:"37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7",
                 pubkey: 链接后用户地址
             }
         }
     })

image.gif

签名后可以使用公钥对签名后的数据进行验证,代码如下:

async function verifyMessageSignature(message: string, signature: string, userPublicKeyBase58: string) {
    try {
        const connection = new Connection(clusterApiUrl('devnet'), 'confirmed');
        
        // 将 Base58 格式的用户公钥转换为 PublicKey 对象
        const userPublicKey = new PublicKey(userPublicKeyBase58);
        // 将签名数据从 Base58 格式解码为 Uint8Array
        const signatureBytes = bs58.decode(signature);
        // 将消息字符串转换为 Uint8Array
        const messageBytes = new TextEncoder().encode(message);
        // 使用 PublicKey 对象和消息数据来验证签名
        const isSignatureValid = await connection.verifySignature(
            messageBytes,
            signatureBytes,
            userPublicKey
        );
        return isSignatureValid;
    } catch (error) {
        console.error('Error verifying signature:', error);
        return false;
    }
}

image.gif

区块链内容感兴趣可以查看我的专栏:小试牛刀-区块链

感谢您的关注和收藏!!!!!!

image.gif 编辑

目录
相关文章
AWS-EC2多弹性ip配置
AWS-EC2多弹性ip配置
1155 0
AWS-EC2多弹性ip配置
|
2月前
|
人工智能 数据挖掘 Linux
Centos安装Python3.7(亲测可用)
本指南详细介绍了在基于Linux(以CentOS系统为例,使用yum包管理器)的系统上安装Python 3.7版本的完整流程。Python是一种广泛使用的高级编程语言,在各种领域如软件开发、数据分析、人工智能和区块链开发等都有着重要的应用。
262 2
|
SQL 关系型数据库 PostgreSQL
把PostgreSQL的表导入SQLite
把PostgreSQL的表导入SQLite
239 0
|
2月前
|
区块链 数据安全/隐私保护 Python
小试牛刀-区块链WalletConnect协议数据解密
最近在学习如何使用Wallet Connect,查阅官方文档后,发现并没有太多的中文参考资料,英文直译读起来也有一些偏差,所以这边直接采用网页Demo的方式,对WC协议有了一定了解.在此进行记录,同时希望帮助到有实现相关功能的朋友.
119 4
|
2月前
|
存储 Java API
小试牛刀-SpringBoot集成SOL链
java工程师:如何在java/springboot中使用solana区块链呢?不用担心,现在solanaj来了!
63 1
|
小程序
微信小程序文件上传无响应解决方法
微信小程序文件上传无响应解决方法
1607 0
|
2月前
|
机器学习/深度学习 算法 Java
Java实现林火蔓延路径算法
记录正在进行的森林防火项目中林火蔓延功能,本篇文章可以较好的实现森林防火蔓延,但还存在很多不足,如:很多参数只能使用默认值,所以蔓延范围仅供参考。(如果底层设备获取的数据充足,那当我没说)。注:因林火蔓延涉及因素太多,如静可燃物载量、矿质阻尼系数等存在估值,所以得出的结果仅供参考。
36 4
|
2月前
|
API 区块链
小试牛刀-SOL链swap程序
本篇文章是为了记录自己通过jupiter swap Api接口实现简单的自动化的swap交换程序的过程,记录相关步骤方便查阅,同时希望可以帮助到有实现相关功能的朋友.
47 1
|
2月前
|
存储 Rust IDE
小试牛刀-Solana合约账户详解
开发语言上,Solana合约使用Rust为主要开发语言,其次是Solana合约并不像其它链那样将数据直接存到合约里,而是使用了更加独立的账户来代币转移和存储数据。按功能可以分为以下账户
77 0
|
2月前
|
存储 前端开发 测试技术
小试牛刀-区块链代币锁仓合约实战
记录一下自己在开发代币合约中的过程,加深自己对合约功能的理解,在后续的学习过程中可以进行资料查阅,以及帮助有这方面开发要求或想学习的朋友进行更方便的入门。
61 1

热门文章

最新文章