文章目录
- 1. 配置wasm
- 2. 钱包地址创建
- 3. KAS转账&余额查询
- 4. KRC-20 处理
- 5. 使用demo
1. 配置wasm
下载wasm地址:https://kaspa.aspectron.org/nightly/downloads/
在项目根目录下添加wasm目录, 将下载的wasm文件中web目录下kaspa和kaspa-dev文件家复制到项目wasm下
2. 钱包地址创建
import { EventEmitter } from 'events';
import {
kaspaToSompi,
type IPaymentOutput,
createTransactions,
PrivateKey,
UtxoProcessor,
UtxoContext,
RpcClient
} from "../wasm/kaspa-dev";
class TransactionSender extends EventEmitter {
private networkId: string;
private privateKey: PrivateKey;
private processor: UtxoProcessor;
private context: UtxoContext;
private rpc: RpcClient;
constructor(networkId: string, privKey: PrivateKey, rpc: RpcClient) {
super();
this.networkId = networkId;
this.privateKey = privKey;
this.processor = new UtxoProcessor({ rpc, networkId });
this.rpc = this.processor.rpc;
this.context = new UtxoContext({ processor: this.processor });
this.registerProcessor();
}
async transferFunds(address: string, amount: string): Promise<string> {
const payments: IPaymentOutput[] = [{
address: address,
amount: kaspaToSompi(amount)!
}];
return await this.send(payments);
}
private async send(outputs: IPaymentOutput[]): Promise<string> {
const { transactions, summary } = await createTransactions({
entries: this.context,
outputs,
changeAddress: this.privateKey.toPublicKey().toAddress(this.networkId).toString(),
priorityFee: kaspaToSompi("0.02")
});
for (let i = 0; i < transactions.length; i++) {
await this.submitTransaction(transactions[i]);
}
return summary.finalTransactionId;
}
private async submitTransaction(transaction: any) {
transaction.sign([this.privateKey]);
await transaction.submit(this.rpc);
}
private registerProcessor() {
this.processor.addEventListener("utxo-proc-start", async () => {
await this.context.clear();
await this.context.trackAddresses([this.privateKey.toPublicKey().toAddress(this.networkId).toString()]);
});
this.processor.start();
}
}
export default TransactionSender;
3. KAS转账&余额查询
import {
RpcClient,
Encoding,
Resolver,
PrivateKey,
IGetServerInfoResponse,
type IPaymentOutput,
kaspaToSompi,
createTransactions,
IGetBalanceByAddressResponse
} from "../wasm/kaspa-dev";
import {IGetBalanceByAddressRequest, UtxoEntryReference} from "../wasm/kaspa";
class Sender {
public client: RpcClient;
private network: string;
constructor(network: string = 'testnet-10') {
this.network = network;
this.client = new RpcClient({
resolver: new Resolver(),
encoding: Encoding.Borsh,
networkId: network
});
}
public async connect() {
await this.client.connect();
}
public async disconnect() {
await this.client.disconnect();
}
public async getServerInfo(): Promise<IGetServerInfoResponse> {
return await this.client.getServerInfo()
}
public async transfer(fromPrivateKey: string, address: string, amount: string): Promise<string> {
try {
const privateKey = new PrivateKey(fromPrivateKey);
const sourceAddress = privateKey.toKeypair().toAddress(this.network);
let {entries} = (await this.client.getUtxosByAddresses([sourceAddress]));
const payments: IPaymentOutput[] = [{
address: address,
amount: kaspaToSompi(amount)!
}];
return await this.send(privateKey, entries, payments);
} catch (error) {
return error
}
}
private async send(privateKey: PrivateKey, entries: UtxoEntryReference[], outputs: IPaymentOutput[]): Promise<string> {
const { transactions, summary } = await createTransactions({
entries: entries,
outputs,
changeAddress: privateKey.toPublicKey().toAddress(this.network).toString(),
priorityFee: kaspaToSompi("0"),
networkId: this.network
});
for (const transaction of transactions) {
transaction.sign([privateKey]);
await transaction.submit(this.client);
}
return summary.finalTransactionId;
}
// Method to get the balance of the address
public async getBalance(address: string): Promise<IGetBalanceByAddressResponse> {
const balanceRequest: IGetBalanceByAddressRequest = {
address: address,
};
return this.client.getBalanceByAddress(balanceRequest);
}
}
export default Sender;
4. KRC-20 处理
import {
RpcClient, Encoding, Resolver, ScriptBuilder, Opcodes, PrivateKey,
addressFromScriptPublicKey, createTransactions, kaspaToSompi, createTransaction, calculateTransactionFee
} from "../wasm/kaspa";
const u64MaxValue = 18446744073709551615;
const baseKasToP2SHAddress = "1.3";
export interface KRC20Data {
p: "krc-20";
op: 'mint' | 'deploy' | 'transfer';
tick: string;
to?: string;
amt?: string;
max?: string;
lim?: string;
dec?: "8";
pre?: string;
}
class KRC20 {
public client: RpcClient;
private network: string;
constructor(network: string = 'testnet-10') {
this.network = network;
this.client = new RpcClient({
resolver: new Resolver(),
encoding: Encoding.Borsh,
networkId: network
});
}
public async connect() {
await this.client.connect();
}
public async disconnect() {
await this.client.disconnect();
}
public async mint(_privateKey: string, data: KRC20Data) {
return this.send(_privateKey, data)
}
public async deploy(_privateKey: string, data: KRC20Data) {
return this.send(_privateKey, data)
}
public async transfer(_privateKey: string, data: KRC20Data) {
return this.send(_privateKey, data)
}
public async send(_privateKey: string, data: KRC20Data) {
const privateKey = new PrivateKey(_privateKey);
const publicKey = privateKey.toPublicKey();
const address = publicKey.toAddress(this.network);
const script = new ScriptBuilder()
.addData(privateKey.toPublicKey().toXOnlyPublicKey().toString())
.addOp(Opcodes.OpCheckSig)
.addOp(Opcodes.OpFalse)
.addOp(Opcodes.OpIf)
.addData(Buffer.from("kasplex"))
.addI64(0n)
.addData(Buffer.from(JSON.stringify(data, null, 0)))
.addOp(Opcodes.OpEndIf);
let scriptPublicKey = script.createPayToScriptHashScript()
const P2SHAddress = addressFromScriptPublicKey(scriptPublicKey, this.network)!;
try {
const {entries} = await this.client.getUtxosByAddresses({addresses: [address.toString()]});
const {transactions, summary} = await createTransactions({
priorityEntries: [],
entries,
outputs: [{
address: P2SHAddress.toString(),
amount: kaspaToSompi(baseKasToP2SHAddress)!
}],
changeAddress: address.toString(),
priorityFee: kaspaToSompi("0"),
networkId: this.network
});
for (const transaction of transactions) {
transaction.sign([privateKey]);
await transaction.submit(this.client);
}
const hash = summary.finalTransactionId
console.log(`summary finalTransactionId transaction on: ${hash}`, 'INFO');
var revealEntries = [{
"address": P2SHAddress.toString(),
"amount":kaspaToSompi(baseKasToP2SHAddress)!,
"outpoint":{
"transactionId":hash,
"index":0
},
"scriptPublicKey":"0000" + scriptPublicKey.script,
"blockDaaScore":u64MaxValue,
"isCoinbase":false
}];
var fee = kaspaToSompi(this.getFee(data.op))!.valueOf()
let tx = createTransaction(revealEntries, [], kaspaToSompi("0")!)
fee = fee + calculateTransactionFee(this.network, tx).valueOf()
return await this.sendRevealTransaction(privateKey, address, revealEntries, script, fee)
} catch (error) {
return error
}
}
// Helper function to determine the KASPA amount based on the operation type
private getFee(optype): string {
switch (optype) {
case 'deploy':
return "1000";
case 'mint':
return "1";
case 'transfer':
return "1";
default:
return "2"; // Default to "2" if the operation is unknown
}
}
public async sendRevealTransaction(privateKey, address, revealEntries, script, fee) {
const { transactions, summary } = await createTransactions({
priorityEntries: revealEntries,
entries: revealEntries,
outputs: [],
changeAddress: address.toString(),
priorityFee: fee,
networkId: this.network
});
for (const transaction of transactions) {
transaction.sign([privateKey], false);
const ourOutput = transaction.transaction.inputs.findIndex((input) => input.signatureScript === '');
if (ourOutput !== -1) {
const signature = await transaction.createInputSignature(ourOutput, privateKey);
transaction.fillInput(ourOutput, script.encodePayToScriptHashSignatureScript(signature));
}
await transaction.submit(this.client);
}
return summary.finalTransactionId
}
}
export default KRC20;
5. 使用demo
import Rpc from "./src/transaction";
import KRC20 from "./src/script";
// -------------------------------------- server information --------------------------------------
// let rpc = new Rpc()
// await rpc.connect()
// let serverInfo = await rpc.getServerInfo()
// console.log("serverInfo;",serverInfo)
// if (!serverInfo.isSynced || !serverInfo.hasUtxoIndex) {
// await rpc.disconnect();
// process.exit(1);
// }
// -------------------------------------- KAS balance--------------------------------------
// let rpc = new Rpc()
// await rpc.connect()
// let address = "kaspatest:*******"
// let balance = await rpc.getBalance(address)
// console.log("balance:", balance)
// -------------------------------------- transfer KAS --------------------------------------
// let rpc = new Rpc()
// await rpc.connect()
// let privateKey = "****"
// let address = "kaspatest:****"
// let amount = "1"
// let txhash = await rpc.transfer(privateKey, address, amount)
// console.log("txhash;",txhash)
// -------------------------------------- mint --------------------------------------
let privateKey = "*****"
let krc20 = new KRC20()
await krc20.connect()
var mintdata = {
p: "krc-20",
op: 'mint',
tick: "****"
}
let txid = await krc20.mint(privateKey, mintdata)
console.log("txsh", txid)
// -------------------------------------- transfer --------------------------------------
// let krc20 = new KRC20()
// let privateKey = "****"
// await krc20.connect()
// var transferdata = {
// p: "krc-20",
// op: 'transfer',
// tick: "SNOWDN",
// to: "kaspatest:****",
// amt: "1000000000",
// }
// let txid = await krc20.transfer(privateKey, transferdata)
// console.log("txsh", txid)
// -------------------------------------- deploy --------------------------------------
// let krc20 = new KRC20()
// await krc20.connect()
// var deploydata = {
// p: "krc-20",
// op: 'deploy',
// tick: "JEMES1",
// to: "kaspatest:*****",
// amt: "1000000000",
// max: "1000000000000000",
// lim: "1000000000",
// dec: "8",
// pre: "1000000000000000",
// }
// let txid = await krc20.deploy(privateKey, deploydata)
// console.log("txsh", txid)
process.exit(1);