小试牛刀-区块链Solana多签账户

devtools/2024/10/10 22:43:47/

目录

1.什么是多签账户

2.多签账户的特点

2.1 多个签名者

2.2 最小签名要求

2.3 常见应用场景

3.多签账户实现

3.1 账户的创建

3.1.1 创建新账户

3.1.2 获取创建和初始账户事务

3.1.3 账户的签名

3.2 代币转移操作


Welcome to Code Block's blog

本篇文章主要介绍了

[小试牛刀-Solana多签账户]
❤博主广交技术好友,喜欢文章的可以关注一下❤

1.什么是多签账户

        在 Solana 区块链中,多签账户(Multisig Account)是一种智能合约账户,允许多个签名者共同管理和控制账户上的资产或操作。这种机制增强了账户的安全性和灵活性,特别适用于需要多个权限共同批准的操作场景,如资产管理、资金转移、或项目治理。                               

2.多签账户的特点

2.1 多个签名者

        多签账户通常指定多个签名者(即一组公钥),这些签名者可以是个人账户、智能合约账户或其他实体。

        每个签名者都有权批准账户的操作,但只有在达到预定义的签名数量时,操作才会生效。

2.2 最小签名要求

        多签账户设置了最小签名数(M)的要求,即在 N 个签名者中,至少需要 M 个签名才能执行账户的任何操作。

        这种机制通常被称为 M-of-N 签名方案,例如 2-of-3 签名意味着需要三个人中的两个人签署才能批准操作。

2.3 常见应用场景

        项目治理:在去中心化自治组织(DAO)中,使用多签账户来管理资金或项目决策。

        资产托管:增加资金管理的安全性,避免单一账户被攻击或失控。

        合作项目:需要多个合作方共同控制账户,确保所有操作都有多个利益相关方的同意。

3.多签账户实现

3.1 账户的创建

3.1.1 创建新账户

        首先创建一个新的账户,作为要创建多签账户,同时需要其公钥和私钥参与签名,实现代码如下:

function generateSolanaWalletNacl(): { publicKey: string, privateKey: string } {const keyPair = nacl.sign.keyPair();const publicKeyBase58 = bs58.encode(Buffer.from(keyPair.publicKey)).toString();const privateKeyBase58 = bs58.encode(Buffer.from(keyPair.secretKey)).toString();return { publicKey: publicKeyBase58, privateKey: privateKeyBase58 };
}

3.1.2 获取创建和初始账户事务

        这里multisigPubKey为上面创建的新账户的公钥,payer我们使用另一个账户(已有或创建)的公钥,保证payer中存在可以创建账户的费用,然后获取创建和初始化事务,代码如下:

export async function createMultisigAccount(payer:string,multisigPubKey:PublicKey): Promise<Transaction> {const fromPubkey =new PublicKey(payer);//签名者列表const signers = [fromPubkey,multisigPubKey];// 获取多签账户所需的最小余额以免租金const lamports = await getMinimumBalanceForRentExemptMultisig(connection);// 创建多签账户的指令const createAccountInstruction = SystemProgram.createAccount({//这个账户的拥有者fromPubkey: fromPubkey,//多签账户公钥newAccountPubkey: multisigPubKey,//免租金最小金额lamports,space: 355, // 多签账户的空间大小//属于的程序地址,这里使用SPL程序programId: TOKEN_PROGRAM_ID,});// 初始化多签账户的指令const initializeMultisigInstruction = createInitializeMultisigInstruction(//多签账户multisigPubKey,//签名者列表signers,//最小签名数量,这里是2requiredSigners,//属于的程序地址,这里使用SPL程序TOKEN_PROGRAM_ID);//创建transaction并添加创建和初始化指令const transaction = new Transaction().add(createAccountInstruction,initializeMultisigInstruction);//最近的区块hashtransaction.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;//付费者为拥有者transaction.feePayer=fromPubkey;console.log("签名者:"+signers)console.log("multisigPubKey:"+multisigPubKey)return transaction;
}

3.1.3 账户的签名

        账户创建时需要签名者列表中的用户分别对transaction进行签名,(是对同一transaction进行签名),如果是拥有者公私钥在本地,可以将公私钥生成Keypair,可使用以下方式签名:

const signer1=Keypair.generate()
const signer2=Keypair.generate()
//签名者1和签名者2 的keypair
transaction.sign(signer1,signer2)

        但若是外部签名,如walletconnect连接的钱包用户作为签名者,则需要使用以下方式进行签名(重点):

首先,获取本地公私钥的签名,注意这里并没有对transaction进行签名,只是获取签名:

export async function getLocalSign(transaction:Transaction,signer:Keypair){const signature = nacl.sign.detached(transaction.serializeMessage(), signer.secretKey);return signature;
}

然后,walletconnet用户连接钱包对创建和初始化账户事务签名后,会获取到一个signature,将这个signature和本地公私钥获取的signature添加到transaction中,代码如下:

    //钱包签名const result =await sendWcTransaction(signClient,session,transaction);//本地签名const signature = nacl.sign.detached(transaction.serializeMessage(), bs58.decode(privateKey));transaction.addSignature(transaction.feePayer,//这里返回的是字符串,所以需要转换Buffer.from(bs58.decode(result.signature)))//<>!transaction.addSignature(multisigPubKey,//本地获取的是uint8array,无需转换Buffer.from(signature))

为保证签名的有效性,需要先验证签名,验证方式如下:

    //验证签名const valid = transaction.verifySignatures();if (!valid){//验证未通过则不进行操作,或打印return ;}

验证通过后,就可以通过以下代码将要进行的创建事务提交到链上:

export async function sendTransaction(transaction:Transaction){try{const txId =await connection.sendRawTransaction(transaction.serialize())return txId;}catch(error){console.error('Exception occurred:', error);return 'error';}
}

链上截图:

可以看到这里创建并初始化了一个Multisig账户,即多签账户,并且Signers有两个地址,这样就完成了多签账户的创建.              

3.2 代币转移操作

        多签账户操作的转移和创建类似,同样需要两个或多个账户对transaction进行签名,获取transaction返回的[transaction,senderKeypair]分别是事务和本地的keyPair,方便后续签名使用,代码如下:

export async function getMultisigTransferTransaction(ownerPublicKey:string,senderPublicKey: string,privateKey: string,drawPublicKey: string,tokenAmount: number,drawData: string
): Promise<[Transaction,Keypair]> {const ownerPubKey = new PublicKey(ownerPublicKey);const senderPubkey = new PublicKey(senderPublicKey);const drawPubkey = new PublicKey(drawPublicKey);const tokenMintAddress = BOGGY_TOKEN_MINT;const senderKeypair = Keypair.fromSecretKey(Uint8Array.from(bs58.decode(privateKey)));try {const sourceTokenAccount = await getAssociatedTokenAddress(tokenMintAddress,senderPubkey);const destTokenAccount = await getAssociatedTokenAddress(tokenMintAddress,drawPubkey);const transferInstruction = createTransferInstruction(sourceTokenAccount,destTokenAccount,senderPubkey,tokenAmount * 1e9,[senderPubkey,ownerPubKey],TOKEN_PROGRAM_ID);// 构造 Memo 指令const memoInstruction = new TransactionInstruction({keys: [{ pubkey: ownerPubKey,  isSigner: true , isWritable:false },{ pubkey: senderPubkey, isSigner: true, isWritable: false }],programId: MEMO_PROGRAM_ID,data: Buffer.from(drawData,'utf-8')});// 创建 compute unit price 指令,提高交易速度const computeUnitPriceInstruction = ComputeBudgetProgram.setComputeUnitPrice({microLamports: 7500,});const computeUnitLimitInstruction=ComputeBudgetProgram.setComputeUnitLimit({units:200000})const transaction = new Transaction().add(computeUnitPriceInstruction,computeUnitLimitInstruction,transferInstruction,memoInstruction);transaction.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;transaction.feePayer = ownerPubKey;return [transaction,senderKeypair];} catch (error) {console.error('Exception occurred:', error);}
}

签名和发送的步骤和创建时签名是一样的,这里就不重复写了.

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

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


http://www.ppmy.cn/devtools/91697.html

相关文章

使用 Streamlit 和 Python 构建 Web 应用程序

一.介绍 在本文中&#xff0c;我们将探讨如何使用 Streamlit 构建一个简单的 Web 应用程序。Streamlit 是一个功能强大的 Python 库&#xff0c;允许开发人员快速轻松地创建交互式 Web 应用程序。Streamlit 旨在让 Python 开发人员尽可能轻松地创建 Web 应用程序。以下是一些主…

Linux上安装MySQL(glibc8.0版)、mysql管理和安全用户角色权限

目录 一、安装及配置mysql 1.下载 2.环境准备 3.解压 4.配置 1.创建用户 2.创建一个文件 3.修改权限 4.初始化数据库 5.判断是否初始化成功 6.设置ssl安全加密连接 7.其他配置 8.环境路径配置 5.启动服务 ​二、mysql管理 1.连接数据库 2.设置密码 3.修改登录…

【K8S】为什么需要Kubernetes?

文章目录 1 什么是Kubernetes&#xff1f;2 三种常见的应用部署方式2.1 传统部署2.2 虚拟化部署2.3 容器化部署 3 Kubernetes的特点写在最后 1 什么是Kubernetes&#xff1f; Kubernetes是 一个开源的&#xff0c;用于管理云平台中多个主机上的容器化应用&#xff0c;Kubernet…

为什么不用postman做自动化

面试的时候被问到&#xff1a;为什么不用postman做自动化 打开postman&#xff0c;看到用例集管理、API 管理、环境管理这三个功能&#xff0c;用户体验感算得上品牌等级了 为什么不用呢&#xff0c;文心一言给了一些答案 不适合大规模自动化测试&#xff1a;Postman 主要是为…

【ML】异常检测、二分类问题

【ML】异常检测、二分类问题 1. 异常检测、二分类问题1.1 异常检测&#xff08;Anomaly Detection&#xff09;1.2 二分类问题&#xff08;Binary Classification&#xff09;1.3 异常检测与二分类问题的对比1.4 总结 2. 模型额训练与评估3. 为什么会出现比较高的误识别&#x…

Adobe Substance 3D Sampler v4.2.2.3719 解锁版下载安装教程(3D材质管理软件)

前言 Substance 3D Sampler简称“Sa”是一款由Adobe新推出的3D真实材质贴图制作软件。允许用户通过调整和混合现有材料&#xff0c;或通过扫描&#xff08;单个或多个图像&#xff09;中提取新材料来创建和迭代材料集合&#xff0c;从而轻松将真实的图片转换为具有真实感的表面…

.net SqlSugarHelper

NuGet安装&#xff1a; SqlSugarCore using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace Namespace {public class SqlSugarHelper{public string _connectionString Custom…

【C++】—— 类与对象(四)

【C】—— 类与对象&#xff08;四&#xff09; 6、赋值运算符重载6.1、运算符重载6.1.1、基础知识6.1.2、调用方法6.1.3、前置 与 后置 的重载6.1.4、注意事项6.1.5、<< 和 >> 运算符重载6.1.5.1、<< 和 >> 基础6.1.5.2、日期类 operator<< 的实…