工具类
VeChain SDK 提供了一系列工具类来处理区块链开发中常见的数据类型。本文档介绍最常用的几个工具类。
Address(地址)
Address 类用于处理 VeChain 地址,提供地址验证、格式化和转换功能。
基本用法
ts
import { Address } from '@vechain/sdk-core';
// 从字符串创建地址
const address = Address.of('0x7567d83b7b8d80addcb281a71d54fc7b3364ffed');
// 获取地址字符串
console.log(address.toString()); // '0x7567d83b7b8d80addcb281a71d54fc7b3364ffed'
// 获取校验和格式地址
console.log(address.toChecksum()); // '0x7567D83b7b8d80ADDCb281A71d54Fc7B3364ffed'地址验证
ts
// 验证地址格式
try {
const address = Address.of('0x7567d83b...');
console.log('地址有效');
} catch (error) {
console.log('地址无效:', error.message);
}
// 检查地址是否有效(不抛出异常)
function isValidAddress(addr: string): boolean {
try {
Address.of(addr);
return true;
} catch {
return false;
}
}
console.log(isValidAddress('0x7567d83b7b8d80addcb281a71d54fc7b3364ffed')); // true
console.log(isValidAddress('invalid')); // false地址格式化
VeChain 支持 EIP-55 校验和地址格式,可以检测地址输入错误。
ts
const address = Address.of('0x7567d83b7b8d80addcb281a71d54fc7b3364ffed');
// 小写格式
console.log(address.toString());
// '0x7567d83b7b8d80addcb281a71d54fc7b3364ffed'
// 校验和格式(推荐)
console.log(address.toChecksum());
// '0x7567D83b7b8d80ADDCb281A71d54Fc7B3364ffed'特殊地址
VeChain 有一些内置的系统合约地址。
ts
// VTHO 代币合约
const VTHO_ADDRESS = '0x0000000000000000000000000000456E65726779';
// Authority 合约
const AUTHORITY_ADDRESS = '0x0000000000000000000000417574686F72697479';
// Energy 合约(VTHO)
const ENERGY_ADDRESS = Address.of('0x0000000000000000000000000000456E65726779');实用函数
ts
// 比较两个地址是否相同
function isSameAddress(addr1: string, addr2: string): boolean {
return Address.of(addr1).toString().toLowerCase() ===
Address.of(addr2).toString().toLowerCase();
}
// 地址缩写显示
function shortenAddress(addr: string): string {
const address = Address.of(addr).toString();
return `${address.slice(0, 6)}...${address.slice(-4)}`;
}
console.log(shortenAddress('0x7567d83b7b8d80addcb281a71d54fc7b3364ffed'));
// '0x7567...ffed'HexUInt(十六进制无符号整数)
HexUInt 用于处理十六进制数据,特别是私钥、哈希值等。
基本用法
ts
import { HexUInt } from '@vechain/sdk-core';
// 从十六进制字符串创建
const hex1 = HexUInt.of('0x1234abcd');
// 从数字创建
const hex2 = HexUInt.of(123456);
// 从 Buffer 创建
const buffer = Buffer.from('1234abcd', 'hex');
const hex3 = HexUInt.of(buffer);私钥处理
私钥通常使用 HexUInt 来表示。
ts
import { HexUInt, Transaction } from '@vechain/sdk-core';
// 私钥字符串
const privateKeyStr = '0xea5383ac1f9e625220039a4afac6a7f868bf1ad4f48ce3a1dd78bd214ee4ace5';
// 转换为字节数组用于签名
const privateKeyBytes = HexUInt.of(privateKeyStr).bytes;
// 签名交易
const signedTx = Transaction.of(txBody).sign(privateKeyBytes);数据转换
ts
const hex = HexUInt.of('0x1234abcd');
// 转换为字符串
console.log(hex.toString()); // '0x1234abcd'
// 转换为字节数组
console.log(hex.bytes); // Uint8Array [18, 52, 171, 205]
// 转换为数字
console.log(hex.toNumber()); // 305441741
// 转换为 BigInt
console.log(hex.toBigInt()); // 305441741n哈希处理
ts
import { HexUInt, blake2b256 } from '@vechain/sdk-core';
// 计算数据的哈希
const data = 'Hello VeChain';
const hash = blake2b256(data);
// 处理哈希值
const hashHex = HexUInt.of(hash);
console.log('哈希:', hashHex.toString());编码和解码
ts
import { HexUInt, abi } from '@vechain/sdk-core';
// ABI 编码参数
const encoded = abi.encodeParameter('uint256', '1000000000000000000');
const encodedHex = HexUInt.of(encoded);
console.log('编码后:', encodedHex.toString());Hex(通用十六进制工具)
Hex 提供了更通用的十六进制数据处理功能。
基本用法
ts
import { Hex } from '@vechain/sdk-core';
// 从各种格式创建
const hex1 = Hex.of('0x1234'); // 从字符串
const hex2 = Hex.of(Buffer.from([0x12, 0x34])); // 从 Buffer
const hex3 = Hex.of(new Uint8Array([0x12, 0x34])); // 从 Uint8Array字符串和字节转换
ts
// 字符串 → 十六进制
const text = 'Hello';
const textHex = Hex.of(Buffer.from(text, 'utf8'));
console.log(textHex.toString()); // '0x48656c6c6f'
// 十六进制 → 字符串
const hex = Hex.of('0x48656c6c6f');
const decoded = Buffer.from(hex.bytes).toString('utf8');
console.log(decoded); // 'Hello'拼接十六进制数据
ts
const hex1 = Hex.of('0x1234');
const hex2 = Hex.of('0xabcd');
// 拼接
const combined = Hex.of(
Buffer.concat([
Buffer.from(hex1.bytes),
Buffer.from(hex2.bytes)
])
);
console.log(combined.toString()); // '0x1234abcd'VET 和 VTHO
VET 和 VTHO 类用于处理 VeChain 的原生代币。
VET(VeChain Token)
ts
import { VET } from '@vechain/sdk-core';
// 从 VET 单位创建
const vet1 = VET.of(1); // 1 VET
const vet2 = VET.of(10.5); // 10.5 VET
const vet3 = VET.of('100'); // 100 VET
// 从 Wei 单位创建
const vetFromWei = VET.of('1000000000000000000'); // 1 VET = 10^18 Wei
// 转换为 Wei 字符串
console.log(VET.of(1).toString());
// '1000000000000000000'
// 转换为 VET 数值
console.log(VET.of('1000000000000000000').toVET());
// 1VTHO(VeThor Token)
ts
import { VTHO } from '@vechain/sdk-core';
// 从 VTHO 单位创建
const vtho1 = VTHO.of(100); // 100 VTHO
const vtho2 = VTHO.of(50.5); // 50.5 VTHO
// 从 Wei 单位创建
const vthoFromWei = VTHO.of('100000000000000000000'); // 100 VTHO
// 转换
console.log(VTHO.of(100).toString());
// '100000000000000000000'单位转换
ts
// VET 单位转换
const vetAmount = 1.5; // 1.5 VET
const weiAmount = VET.of(vetAmount).toString(); // '1500000000000000000'
// Wei 转 VET
const wei = '1500000000000000000';
const vet = parseFloat(wei) / 1e18; // 1.5
// 或使用 BigInt
const vetBigInt = BigInt(wei) / BigInt(1e18); // 1n实用函数
ts
// 格式化显示 VET
function formatVET(wei: string | bigint): string {
const vet = Number(wei) / 1e18;
return `${vet.toFixed(4)} VET`;
}
console.log(formatVET('1500000000000000000')); // '1.5000 VET'
// 格式化显示 VTHO
function formatVTHO(wei: string | bigint): string {
const vtho = Number(wei) / 1e18;
return `${vtho.toFixed(2)} VTHO`;
}
console.log(formatVTHO('100000000000000000000')); // '100.00 VTHO'ThorId
ThorId 用于处理区块哈希、交易哈希等 32 字节的标识符。
基本用法
ts
import { ThorId } from '@vechain/sdk-core';
// 从字符串创建
const txId = ThorId.of('0x9c8cf4f5d1b5f5c8e6d7b8a9f0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9');
// 从数字创建(用于存储槽位置)
const storagePosition = ThorId.of(1);
// 转换为字符串
console.log(txId.toString());交易和区块 ID
ts
// 交易 ID
const txId = ThorId.of(
'0x9c8cf4f5d1b5f5c8e6d7b8a9f0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9'
);
// 区块 ID
const blockId = ThorId.of(
'0x000f4240fa8c7c5b5f5c8e6d7b8a9f0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7'
);
// 从区块 ID 提取区块号
const blockNumber = parseInt(blockId.toString().slice(0, 10), 16);
console.log('区块号:', blockNumber);Bloom Filter
Bloom Filter 用于高效检查事件是否可能存在于区块中。
基本用法
ts
import { BloomFilter } from '@vechain/sdk-core';
// 创建 Bloom Filter
const bloom = BloomFilter.of('0x...');
// 检查是否包含某个元素
const topic = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';
if (bloom.contains(topic)) {
console.log('可能包含该事件');
} else {
console.log('肯定不包含该事件');
}实战示例
示例 1: 地址簿管理
ts
import { Address } from '@vechain/sdk-core';
class AddressBook {
private addresses: Map<string, string> = new Map();
// 添加地址
add(name: string, address: string): void {
// 验证并格式化地址
const addr = Address.of(address);
this.addresses.set(name, addr.toChecksum());
}
// 获取地址
get(name: string): string | undefined {
return this.addresses.get(name);
}
// 检查地址是否存在
has(address: string): boolean {
const addr = Address.of(address).toChecksum();
return Array.from(this.addresses.values()).includes(addr);
}
// 获取地址的名称
getName(address: string): string | undefined {
const addr = Address.of(address).toChecksum();
for (const [name, savedAddr] of this.addresses.entries()) {
if (savedAddr === addr) return name;
}
return undefined;
}
}
// 使用
const book = new AddressBook();
book.add('Alice', '0x7567d83b7b8d80addcb281a71d54fc7b3364ffed');
book.add('Bob', '0x9e7911de289c3c856ce7f421034f66b6cde49c39');
console.log(book.get('Alice'));
// '0x7567D83b7b8d80ADDCb281A71d54Fc7B3364ffed'示例 2: 金额计算器
ts
import { VET, VTHO } from '@vechain/sdk-core';
class AmountCalculator {
// VET 转换
static vetToWei(vet: number): string {
return VET.of(vet).toString();
}
static weiToVet(wei: string): number {
return Number(wei) / 1e18;
}
// VTHO 转换
static vthoToWei(vtho: number): string {
return VTHO.of(vtho).toString();
}
static weiToVtho(wei: string): number {
return Number(wei) / 1e18;
}
// 格式化显示
static formatVET(wei: string, decimals: number = 4): string {
const vet = this.weiToVet(wei);
return `${vet.toFixed(decimals)} VET`;
}
static formatVTHO(wei: string, decimals: number = 2): string {
const vtho = this.weiToVtho(wei);
return `${vtho.toFixed(decimals)} VTHO`;
}
}
// 使用
console.log(AmountCalculator.vetToWei(1.5));
// '1500000000000000000'
console.log(AmountCalculator.formatVET('1500000000000000000'));
// '1.5000 VET'
console.log(AmountCalculator.formatVTHO('100000000000000000000'));
// '100.00 VTHO'示例 3: 私钥管理
ts
import { HexUInt } from '@vechain/sdk-core';
import * as crypto from 'crypto';
class KeyManager {
// 生成随机私钥
static generatePrivateKey(): string {
const randomBytes = crypto.randomBytes(32);
return HexUInt.of(randomBytes).toString();
}
// 验证私钥格式
static isValidPrivateKey(key: string): boolean {
try {
const keyBytes = HexUInt.of(key).bytes;
return keyBytes.length === 32;
} catch {
return false;
}
}
// 私钥掩码显示(安全)
static maskPrivateKey(key: string): string {
if (!this.isValidPrivateKey(key)) return 'Invalid';
return `${key.slice(0, 6)}...${key.slice(-4)}`;
}
}
// 使用
const privateKey = KeyManager.generatePrivateKey();
console.log('生成的私钥:', KeyManager.maskPrivateKey(privateKey));
// '0xea53...ace5'
console.log('私钥有效:', KeyManager.isValidPrivateKey(privateKey));
// true示例 4: 交易哈希工具
ts
import { ThorId, HexUInt } from '@vechain/sdk-core';
class TransactionUtils {
// 验证交易 ID 格式
static isValidTxId(txId: string): boolean {
try {
const id = ThorId.of(txId);
return id.toString().length === 66; // '0x' + 64 个字符
} catch {
return false;
}
}
// 交易 ID 缩写
static shortenTxId(txId: string): string {
const id = ThorId.of(txId).toString();
return `${id.slice(0, 10)}...${id.slice(-8)}`;
}
// 生成交易链接(区块浏览器)
static getExplorerUrl(txId: string, network: 'mainnet' | 'testnet' = 'testnet'): string {
const id = ThorId.of(txId).toString();
const baseUrl = network === 'mainnet'
? 'https://explore.vechain.org'
: 'https://explore-testnet.vechain.org';
return `${baseUrl}/transactions/${id}`;
}
}
// 使用
const txId = '0x9c8cf4f5d1b5f5c8e6d7b8a9f0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9';
console.log('交易 ID 有效:', TransactionUtils.isValidTxId(txId));
// true
console.log('缩写:', TransactionUtils.shortenTxId(txId));
// '0x9c8cf4f5...f6a7b8c9'
console.log('浏览器链接:', TransactionUtils.getExplorerUrl(txId));
// 'https://explore-testnet.vechain.org/transactions/0x9c8cf4...'最佳实践
1. 地址处理
ts
// ✅ 使用 Address 类进行验证
try {
const address = Address.of(userInput);
// 使用校验和格式存储
saveAddress(address.toChecksum());
} catch (error) {
showError('地址格式无效');
}
// ❌ 直接使用字符串
saveAddress(userInput); // 可能包含无效地址2. 金额处理
ts
// ✅ 使用 VET/VTHO 类
const amount = VET.of(1.5);
const clause = Clause.transferVET(address, amount);
// ❌ 手动计算 Wei
const weiAmount = '1500000000000000000'; // 容易数错 03. 私钥安全
ts
// ✅ 永远不要在日志中输出完整私钥
console.log('私钥:', KeyManager.maskPrivateKey(privateKey));
// ❌ 直接输出私钥(危险)
console.log('私钥:', privateKey);4. 数据验证
ts
// ✅ 验证数据格式
function processAddress(addr: string) {
try {
const address = Address.of(addr);
// 继续处理
} catch (error) {
throw new Error('无效的地址格式');
}
}
// ❌ 不验证直接使用
function processAddress(addr: string) {
// 直接使用,可能导致错误
const clause = { to: addr, value: '0', data: '0x' };
}