Solana钱包开发小记

2022-3-3

Solana 钱包开发

这段时间,也不止Filecoin的钱包开发,还有Solana的钱包开发。

这里就不展开所有的代码讲了。有问题的可以自己联系我。

这里主要说一下功能的主要实现。

Solana根据助记词生成私钥和地址

一开始我也是看文档发现,生成私钥和地址,只需要

const bs58 = require("bs58")
const nacl = require("tweetnacl") // nacl
const bip39 = require('bip39');
const seed = bip39.mnemonicToSeedSync(mnemonic)
const keyPair = nacl.sign.keyPair.fromSeed(seed.slice(0, 32));
// 得到私钥和地址
// privateKey = bs58.encode(keyPair.secretKey)
// address = bs58.encode(keyPair.publicKey)

但是看过我上一篇filecoin文章的知道,一个助记词可以派生出很多的地址。有时候它的默认派生路径的地址不是我们想要的,这时候,我们就需要知道solana的具体network_path_code的数字了,找到自己想要的path。example:"m/44'/501'/0'/0'","m/44'/501'/0'/1'",甚至"m/44'/501'/0'/0'/0'"

const bs58 = require("bs58")
const bip39 = require('bip39');
const nacl = require("tweetnacl") // nacl
const ed25519 = require('ed25519-hd-key')
// 这里就直接取第一个地址,solana的network_path_code为501
// 举例,我们这边取的派生地址使用“m/44'/501'/0'/0'”,你也可以使用其他的派生路径
// phantom 默认就是使用的“m/44'/501'/0'/0'”
const derivePath = "m/44'/501'/0'/0'"
// 先根据助记词获取seed
const seed = bip39.mnemonicToSeedSync(mnemonic)
const derivedSeed = ed25519.derivePath(derivePath, seed.toString('hex')).key
// 得到私钥和地址
// privateKey = bs58.encode(nacl.sign.keyPair.fromSeed(derivedSeed).secretKey)
// address = bs58.encode(nacl.sign.keyPair.fromSeed(derivedSeed).publicKey)

solana的publicKeyaddress其实就是bs58(base58)的decodeencode之间的转换,同理privateKeysecretKey也是一样的。

privateKey = bs58.encode(secretKey)
address = bs58.encode(publicKey)

Solana 发送交易

关于solana如何发送交易,这里主要还是使用了solana官方提供的js的sdk,这里仅供参考。因为自己实现的是插件钱包,所以并未对客户端发送交易这块进行实际测试。

npm install — save @solana/web3.js

然后我们建立于solana链的连接 和 Airdrop some tokens

const web3 = require('@solana/web3.js');
// 主网 mainnet-beta 测试网 devnet
const connection = new web3.Connection( web3.clusterApiUrl('devnet'), 'confirmed');

let balanace = await connection.getBalance(fromWallet.publicKey)

const fromAirdropSignature = await connection.requestAirdrop(
  fromWallet.publicKey,
  web3.LAMPORTS_PER_SOL, //A lamport has a value of 0.000000001 SOL.
);

// Wait for airdrop confirmation
await connection.confirmTransaction(fromAirdropSignature);

接下来,我们直接调用交易api

var transaction = new web3.Transaction().add(
  web3.SystemProgram.transfer({
    fromPubkey: fromWallet.publicKey,
    toPubkey: toWallet.publicKey,
    lamports: 1, // number of SOL to send
  }),
)

// Sign transaction, broadcast, and confirm
transaction.feePayer = fromWallet.publicKey;
let blockhashObj = await connection.getRecentBlockhash();
transaction.recentBlockhash = await blockhashObj.blockhash;

// provider 其实就是我们作为钱包提供给客户端进行签名的
let signed = await provider.signTransaction(transaction)
let signature = await connection.sendRawTransaction(signed.serialize());
await connection.confirmTransaction(signature);

Solana 如何用私钥给交易签名

既然是钱包开发,我们肯定是要走完整个交易流程的,接下来,我们就来看看如何给sol的sdk提供交易签名服务。

由上文可知,我们需要提供一个provider.signTransaction的一个方法,来给交易对象transaction进行一个签名。

这里是如果密钥不在我们这,交给第三方进行签名的代码:

// 如果是交给第三方去签名,这里我们就需要对transaction 进行一个bs58的encode
// example
const signTransaction = (transaction) => {
  const message = bs58.encode(transaction.serializeMessage())
  /**
  	这里就是交给第三方对message进行签名,然后返回给我们
  	不理解signature内容的可以看下面我们自己签名的代码来查看具体的签名逻辑
  	return signature
  **/
  const signature = bs58.decode(signature);
  const publicKey = fromWallet.publicKey; // 不是address,是publicKey
  transaction.addSignature(publicKey, signature);
  return transaction
}

但如果是我们有密钥,我们自己来签名:

const signMessage = (message) => {
    const privateKey = '2m2VFti.......'
    return bs58.encode(nacl.sign.detached(bs58.decode(message), bs58.decode(privateKey)))
}
const signTransaction = (transaction) => {
  const message = bs58.encode(transaction.serializeMessage())
  const signature = bs58.decode(signMessage(message));
  /** 
  // 或者直接一点
  // const signature = nacl.sign.detached(transaction.serializeMessage(), fromWallet.secretKey)
  // 不知道secretKey 的可以看上文
  **/
  
  const publicKey = fromWallet.publicKey; // 不是address,是publicKey
  transaction.addSignature(publicKey, signature);
  return transaction
}

OK,这样我们就可以对transaction签名并返回了。

其实不止signTransaction,还有一个signAllTransactions,参数是transactions,是transaction的一个数组形式。

同理,对每一个transaction进行签名,并返回一个数组。

结束,Over!

遇到问题了? 可以直接联系我

评论区