交易构建与签名
Polkadot 交易(Transaction)是网络操作的基本单位,包括转账、智能合约调用、治理投票等。本指南将介绍如何构建、签名和提交交易。
交易概述
Polkadot 交易也称为外部交易(Extrinsic),具有以下特点:
- 需要账户签名
- 包含 nonce 和费用信息
- 支持多种操作类型
- 具有权重限制
连接网络
创建 API 实例
const { ApiPromise, WsProvider } = require('@polkadot/api');
async function connectToNetwork() {
// 连接到 clover 网络
const wsProvider = new WsProvider('wss://api.clover.finance');
// 创建 API 实例
const api = await ApiPromise.create({ provider: wsProvider });
console.log('Connected to network');
return api;
}
等待网络就绪
const api = await connectToNetwork();
// 等待网络就绪
await api.isReady;
// 获取网络信息
const [chain, nodeName, nodeVersion] = await Promise.all([
api.rpc.system.chain(),
api.rpc.system.name(),
api.rpc.system.version()
]);
console.log(`Connected to chain ${chain} using ${nodeName} v${nodeVersion}`);
基本转账交易
构建转账交易
const { Keyring } = require('@polkadot/keyring');
const { formatBalance } = require('@polkadot/util');
async function createTransfer(api, from, to, amount) {
// 设置余额显示格式
formatBalance.setDefaults({
unit: 'CLV', // Westend 测试网代币
decimals: 12
});
// 构建转账调用
const transfer = api.tx.balances.transfer(to, amount);
console.log(`Transfer ${formatBalance(amount)} from ${from} to ${to}`);
return transfer;
}
签名并发送交易
async function signAndSend(api, transfer, signer) {
try {
// 签名并发送交易
const txHash = await transfer.signAndSend(signer, ({ status, events }) => {
if (status.isInBlock) {
console.log(`Transaction included in block ${status.asInBlock}`);
} else if (status.isFinalized) {
console.log(`Transaction finalized in block ${status.asFinalized}`);
// 处理事件
events.forEach(({ event: { data, method, section } }) => {
console.log(`${section}.${method}:`, data.toString());
});
}
});
console.log(`Transaction hash: ${txHash}`);
return txHash;
} catch (error) {
console.error('Transaction failed:', error);
throw error;
}
}
交易参数
获取账户信息
async function getAccountInfo(api, address) {
// 获取账户信息
const { nonce, data: balance } = await api.query.system.account(address);
console.log(`Account: ${address}`);
console.log(`Nonce: ${nonce}`);
console.log(`Free balance: ${formatBalance(balance.free)}`);
console.log(`Reserved balance: ${formatBalance(balance.reserved)}`);
console.log(`Frozen balance: ${formatBalance(balance.frozen)}`);
return { nonce, balance };
}
设置交易参数
async function setTransactionParams(api, transfer, signer) {
// 获取当前 nonce
const { nonce } = await api.query.system.account(signer.address);
// 设置交易参数
const tx = transfer.sign(signer, {
nonce: nonce,
tip: 0, // 小费
era: 0 // 交易有效期
});
return tx;
}
高级交易功能
批量交易
async function createBatchTransfer(api, from, recipients, amounts) {
// 创建批量转账调用
const calls = recipients.map((recipient, index) =>
api.tx.balances.transfer(recipient, amounts[index])
);
// 构建批量交易
const batch = api.tx.utility.batch(calls);
console.log(`Batch transfer to ${recipients.length} recipients`);
return batch;
}
条件交易
async function createConditionalTransfer(api, from, to, amount, condition) {
// 创建条件转账
const transfer = api.tx.balances.transfer(to, amount);
// 添加条件
const conditional = api.tx.utility.if(condition, transfer);
return conditional;
}
交易状态监控
监听交易状态
async function monitorTransaction(api, txHash) {
console.log(`Monitoring transaction: ${txHash}`);
// 获取交易状态
const status = await api.rpc.author.pendingExtrinsics();
console.log('Pending extrinsics:', status.length);
// 监听区块事件
await api.rpc.chain.subscribeNewHeads((header) => {
console.log(`New block: ${header.number}`);
});
}
获取交易详情
async function getTransactionDetails(api, txHash) {
try {
// 获取交易信息
const tx = await api.rpc.author.pendingExtrinsics();
// 查找特定交易
const targetTx = tx.find(t => t.hash.eq(txHash));
if (targetTx) {
console.log('Transaction found in pending extrinsics');
console.log('Method:', targetTx.method.toHuman());
console.log('Signer:', targetTx.signer.toString());
} else {
console.log('Transaction not found in pending extrinsics');
}
} catch (error) {
console.error('Error getting transaction details:', error);
}
}
完整示例
const { ApiPromise, WsProvider, Keyring } = require('@polkadot/api');
const { formatBalance } = require('@polkadot/util');
async function transferExample() {
// 连接到网络
const wsProvider = new WsProvider('wss://api.clover.finance');
const api = await ApiPromise.create({ provider: wsProvider });
// 等待网络就绪
await api.isReady;
// 设置余额格式
formatBalance.setDefaults({
unit: 'CLV',
decimals: 12
});
// 创建密钥环
const keyring = new Keyring({ ss58Format: 42, type: 'sr25519' });
const alice = keyring.addFromUri('//Alice');
const bob = keyring.addFromUri('//Bob');
console.log('Alice address:', alice.address);
console.log('Bob address:', bob.address);
// 获取账户信息
const aliceInfo = await api.query.system.account(alice.address);
console.log('Alice balance:', formatBalance(aliceInfo.data.free));
// 创建转账交易
const amount = 1000000000000; // 1 WND
const transfer = api.tx.balances.transfer(bob.address, amount);
console.log(`Transferring ${formatBalance(amount)} from Alice to Bob`);
// 签名并发送交易
const txHash = await transfer.signAndSend(alice, ({ status, events }) => {
if (status.isInBlock) {
console.log(`Transaction included in block ${status.asInBlock}`);
} else if (status.isFinalized) {
console.log(`Transaction finalized in block ${status.asFinalized}`);
events.forEach(({ event: { data, method, section } }) => {
if (section === 'balances' && method === 'Transfer') {
console.log(`Transfer event: ${data.toString()}`);
}
});
}
});
console.log(`Transaction hash: ${txHash}`);
// 等待交易确认
await new Promise(resolve => setTimeout(resolve, 5000));
// 检查新余额
const newAliceInfo = await api.query.system.account(alice.address);
const bobInfo = await api.query.system.account(bob.address);
console.log('New Alice balance:', formatBalance(newAliceInfo.data.free));
console.log('New Bob balance:', formatBalance(bobInfo.data.free));
// 断开连接
await api.disconnect();
}
transferExample().catch(console.error);
最佳实践
- 错误处理: 始终处理交易失败的情况
- 状态监控: 监控交易状态直到最终确认
- 费用估算: 考虑网络费用和权重限制
- nonce 管理: 正确管理账户 nonce
- 网络选择: 在测试网上测试后再在主网使用
常见问题
Q: 如何估算交易费用?
A: 使用 api.tx.balances.transfer().paymentInfo()
获取费用信息。
Q: 交易失败怎么办?
A: 检查余额、nonce、网络状态和交易参数。
Q: 如何提高交易成功率?
A: 设置合理的小费,在网络拥堵时避免发送交易。
Q: 支持哪些交易类型?
A: 支持转账、智能合约调用、治理投票、质押等操作。