跳转至

秘籍

原文:https://docs.elrond.com/sdk-and-tools/erdjs/erdjs-cookbook

本页将引导您完成使用erdj处理常见任务的过程。

重要

这本秘籍利用了erdjs 10。为了从erdjs 9.x迁移到erdjs 10,请遵循迁移指南

创建网络提供商

创建 API 提供程序:

import { ApiNetworkProvider } from "@elrondnetwork/erdjs-network-providers";

let networkProvider = new ApiNetworkProvider("https://devnet-api.elrond.com"); 

创建代理提供程序:

import { ProxyNetworkProvider } from "@elrondnetwork/erdjs-network-providers";

let networkProvider = new ProxyNetworkProvider("https://devnet-gateway.elrond.com"); 
重要

仅使用@elrondnetwork/erdjs-network-providers 中的类作为起点。随着你的 dApp 成熟,确保你切换到使用你自己的网络提供商,根据你的需求定制(无论是从默认的衍生还是从头编写一个新的),直接与Elrond API(或网关)交互。

关于这个话题,请看扩展 erdjs

抓取网络参数

let networkConfig = await networkProvider.getNetworkConfig();
console.log(networkConfig.MinGasPrice);
console.log(networkConfig.ChainID); 

处理账目

同步账户对象

下面的代码片段(从网络)获取账户的随机数余额,并更新账户的本地表示。

let addressOfAlice = new Address("erd1...");
let alice = new Account(addressOfAlice);
let aliceOnNetwork = await networkProvider.getAccount(addressOfAlice);
alice.update(aliceOnNetwork);

console.log(alice.nonce);
console.log(alice.balance); 

本地管理发送方随机数

当发送一批交易时,您通常必须首先从网络获取账户随机数(见上文),然后在本地管理它(例如,在签署和广播交易时增加):

alice.incrementNonce(); 

或者,您也可以使用:

transaction.setNonce(alice.getNonceThenIncrement()); 

如需进一步参考,请参见随机数管理

准备支付对象

重要

erdjs 9x 中,使用类BalanceBalanceBuilder准备支付。在 erdjs 10 中,我们使用TokenPayment

用于 EGLD 转账TokenPayment对象(价值变动):

let firstPayment = TokenPayment.egldFromAmount("1.5");
let secondPayment = TokenPayment.egldFromBigInteger("1500000000000000000");
console.log(firstPayment.valueOf(), secondPayment.valueOf());
console.log(firstPayment.toPrettyString(), secondPayment.toPrettyString()); 

用于转移可替换的代币的TokenPayment对象:

let identifier = "FOO-123456";
let numDecimals = 2;
let firstPayment = TokenPayment.fungibleFromAmount(identifier, "1.5", numDecimals);
let secondPayment = TokenPayment.fungibleFromBigInteger(identifier, "4000", numDecimals);

console.log(firstPayment.toString()); // Will output: 150.
console.log(firstPayment.toPrettyString()); // Will output: 1.50 FOO-123456.
console.log(secondPayment.toString()); // Will output: 4000.
console.log(secondPayment.toPrettyString()); // Will output: 40.00 FOO-123456. 

用于转移半可替代代币的TokenPayment对象:

let nonce = 3;
let quantity = 50;
let payment = TokenPayment.semiFungible(identifier, nonce, quantity); 

用于转移不可替代的代币的TokenPayment对象(数量不需要为 NFTs 指定,因为代币只是同类代币中的一种):

let nonce = 7;
let payment = TokenPayment.nonFungible(identifier, nonce); 

用于传送元 esdt 代币的TokenPayment对象:

let payment = TokenPayment.metaEsdtFromAmount(identifier, nonce, "0.1", numDecimals); 

广播交易

准备简单的交易

let tx = new Transaction({
    data: new TransactionPayload("helloWorld"),
    gasLimit: 70000,
    receiver: new Address("erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx"),
    value: TokenPayment.egldFromAmount(1),
    chainID: "D"
}); 

使用网络提供商广播

let txHash = await networkProvider.sendTransaction(tx); 

请注意,在广播交易之前,需要对其进行签名。签名可以使用签名提供程序来实现。

重要

注意,出于各种目的,我们建议使用 dapp-core 而不是自己集成签名供应商。

广播使用axios

let data = tx.toSendable();
let url = "https://devnet-api.elrond.com/transactions";
let response = await axios.post(url, data, {
    headers: {
        "Content-Type": "application/json",
    },
});
let txHash = response.data.txHash; 

等待交易完成

let watcher = new TransactionWatcher(networkProvider);
let transactionOnNetwork = await watcher.awaitCompleted(tx); 

如果只有txHash可用,则:

let transactionOnNetwork = await watcher.awaitCompleted({ getHash: () => txHash });
console.log(transactionOnNetwork); 

为了等待多个交易:

await Promise.all([watcher.awaitCompleted(tx1), watcher.awaitCompleted(tx2), watcher.awaitCompleted(tx3)]); 

对于不同的等待策略,也可参见扩展 erdjs

代币转账

单 ESDT 转移

let payment = TokenPayment.fungibleFromAmount("COUNTER-8b028f", "100.00", 0);
let data = new ESDTTransferPayloadBuilder()
    .setPayment(payment)
    .build();

transactions.push(new Transaction({
    nonce: 7,
    receiver: new Address("erd1..."),
    data: data,
    gasLimit: 50000 + 1500 * data.length() + 300000,
    chainID: "D"
})); 

单 NFT 转移

let payment = TokenPayment.nonFungible("ERDJS-38f249", 1);
let payload = new ESDTNFTTransferPayloadBuilder()
    .setPayment(payment)
    .setDestination(new Address("erd1..."))
    .build();

transactions.push(new Transaction({
    nonce: 7,
    // Same as sender address!
    receiver: new Address("erd1..."),
    data: data,
    gasLimit: 50000 + 1500 * data.length() + 1000000,
    chainID: "D"
})); 

单 SFT 转移

let payment = TokenPayment.semiFungible("SEMI-9efd0f", 1, 5);
let payload = new ESDTNFTTransferPayloadBuilder()
    .setPayment(payment)
    .setDestination(new Address("erd1..."))
    .build();

transactions.push(new Transaction({
    nonce: 7,
    // Same as sender address!
    receiver: new Address("erd1..."),
    data: data,
    gasLimit: 50000 + 1500 * data.length() + 1000000,
    chainID: "D"
})); 

多 ESDT / NFT 转移

let paymentOne = TokenPayment.nonFungible("ERDJS-38f249", 1);
let paymentTwo = TokenPayment.fungibleFromAmount("BAR-c80d29", "10.00", 18);
let payments = [paymentOne, paymentTwo];
let payload = new MultiESDTNFTTransferPayloadBuilder()
    .setPayments(payments)
    .setDestination(new Address("erd1..."))
    .build();

transactions.push(new Transaction({
    nonce: 7,
    // Same as sender address!
    receiver: new Address("erd1..."),
    data: data,
    gasLimit: 50000 + 1500 * data.length() + 1000000 * payments.length,
    chainID: "D"
})); 

合约部署

从文件中加载字节码

import { Code } from "@elrondnetwork/erdjs";
import { promises } from "fs";

let buffer: Buffer = await promises.readFile(file);
let code = Code.fromBuffer(buffer); 

从 URL 加载字节码

import axios, { AxiosResponse } from "axios";

let response: AxiosResponse<ArrayBuffer> = await axios.get("https://.../myContract.wasm", {
    responseType: "arraybuffer",
    transformResponse: [],
    headers: {
        "Accept": "application/wasm"
    }
});

let buffer = Buffer.from(response.data);
let code = Code.fromBuffer(buffer); 

执行合约部署

创建一个SmartContract对象:

let contract = new SmartContract(); 

准备部署交易:

let transaction = contract.deploy({
 code: code,
 codeMetadata: new CodeMetadata(/* set the parameters accordingly */),
 initArguments: [/* set the initial arguments, if any */],
 gasLimit: 20000000,
 chainID: "D"
}); 

然后,设置交易随机数。

请注意,帐户随机数必须事先同步。此外,在本地增加部署者的 nonce(可选)。

transaction.setNonce(deployer.getNonceThenIncrement()); 

然后使用您选择的钱包/签名提供商对交易进行签名。签署后,您通常会计算合约地址(确定性可计算),如下所示:

let contractAddress = SmartContract.computeAddress(transaction.getSender(), transaction.getNonce()); 

为了广播交易并等待其完成,请使用网络提供商和交易监视器:

await networkProvider.sendTransaction(transaction);
let transactionOnNetwork = await new TransactionWatcher(networkProvider).awaitCompleted(transaction); 

最后,解析结果:

let { returnCode } = new ResultsParser().parseUntypedOutcome(transactionOnNetwork); 

ABI

从文件中加载 ABI

import { AbiRegistry } from "@elrondnetwork/erdjs";
import { promises } from "fs";

let jsonContent: string = await promises.readFile("myAbi.json", { encoding: "utf8" });
let json = JSON.parse(jsonContent);
let abiRegistry = AbiRegistry.create(json);
let abi = new SmartContractAbi(abiRegistry, ["MyContract"]); ... let contract = new SmartContract({ address: new Address("erd1..."), abi: abi }); 

从一个网址加载 ABI

import axios, { AxiosResponse } from "axios";

let response: AxiosResponse = await axios.get("https://.../myAbi.json");
let abiRegistry = AbiRegistry.create(response.data);
let abi = new SmartContractAbi(abiRegistry, ["MyContract"]); ... let contract = new SmartContract({ address: new Address("erd1..."), abi: abi }); 

合约查询

当 ABI 不在时

let contractAddress = new Address("erd1qqq...");
let contract = new SmartContract({ address: contractAddress });
let addressOfAlice = new Address("erd1...");

let query = contract.createQuery({
    func: new ContractFunction("getClaimableRewards"),
    args: [new AddressValue(addressOfAlice)],
    caller: new Address("erd1...")
});

let queryResponse = await networkProvider.queryContract(query);
let bundle = resultsParser.parseUntypedQueryResponse(queryResponse);
console.log(bundle.returnCode);
console.log(bundle.returnMessage);
console.log(bundle.values); 

使用Interaction,当 ABI 不可用时

let func = new ContractFunction("getClaimableRewards");
let args = [new AddressValue(addressOfAlice)];
let query = new Interaction(contract, func, args)
    .withQuerent(new Address("erd1..."))
    .buildQuery();

let queryResponse = await networkProvider.queryContract(query); 

然后,如上解析响应。

当 ABI 可用

let query = contract.createQuery({
    func: new ContractFunction("getClaimableRewards"),
    args: [new AddressValue(addressOfAlice)],
    caller: new Address("erd1...")
});

let queryResponse = await networkProvider.queryContract(query);
let endpointDefinition = contract.getEndpoint("getClaimableRewards");
let { firstValue, secondValue, returnCode } = resultsParser.parseQueryResponse(queryResponse, endpointDefinition); 

使用Interaction,当 ABI 可用

准备交互,检查它,然后构建查询:

let interaction = <Interaction>contract.methods.getLotteryInfo(["myLottery]);
let query = interaction.check().buildQuery(); 

然后,运行查询并解析结果:

let queryResponse = await networkProvider.queryContract(query);
let endpointDefinition = interaction.getEndpoint();
let { firstValue, secondValue, returnCode } = resultsParser.parseQueryResponse(queryResponse, endpointDefinition); 

根据上下文,重新解释(投射)结果:

let firstValueAsStruct = <Struct>firstValue;
return firstValueAsStruct; 

合约交互

当 ABI 不在时

let contractAddress = new Address("erd1qqq...");
let contract = new SmartContract({ address: contractAddress });
let addressOfCarol = new Address("erd1...");

let tx = contract.call({
    func: new ContractFunction("transferToken"),
    gasLimit: 5000000,
    args: [new AddressValue(addressOfCarol), new U64Value(1000)],
    chainID: "D"
});

tx.setNonce(alice.nonce); 

然后,签名,广播tx并等待其完成。

使用Interaction,当 ABI 不可用时

let contract = new SmartContract({ address: contractAddress });
let dummyFunction = new ContractFunction("dummy");
let args = [new U32Value(100)];
let interaction = new Interaction(contract, dummyFunction, args);

let tx = interaction
    .withNonce(7)
    .withValue(TokenPayment.egldFromAmount(1))
    .withGasLimit(20000000)
    .withChainID("D")
    .buildTransaction(); 

然后,签名,广播tx并等待其完成。

使用Interaction,当 ABI 可用

let contract = new SmartContract({ address: contractAddress, abi: abi });
let tx = contract.methods.dummy([new U32Value(100)])
    .withNonce(7)
    .withValue(TokenPayment.egldFromAmount(1))
    .withGasLimit(20000000)
    .withChainID("D")
    .buildTransaction(); 

传送&执行

给定一个交互:

let interaction = contract.methods.doStuff([]); 

也可以将代币传输应用于智能合约调用。

对于一次性付款,请执行以下操作:

// Fungible token
interaction.withSingleESDTTransfer(TokenPayment.fungibleFromAmount("FOO-6ce17b", "1.5", 18));

// Non-fungible token
interaction.withSingleESDTNFTTransfer(TokenPayment.nonFungible("ERDJS-38f249", 1)); 

对于多次付款:

interaction.withMultiESDTNFTTransfer([
    TokenPayment.fungibleFromAmount("FOO-6ce17b", "1.5", 18)
    TokenPayment.nonFungible("ERDJS-38f249", 1)
]); 

解析合约结果

重要

当默认ResultsParser行为不当时,请在 GitHub 上打开一个问题,并且也提供尽可能多的关于不可解析结果的细节(例如,如果可能的话提供交易对象的转储——确保删除任何敏感信息)。

当 ABI 不在时

let resultsParser = new ResultsParser();
let transactionOnNetwork = await networkProvider.getTransaction(txHash);
let { returnCode, returnMessage, values } = resultsParser.parseUntypedOutcome(transactionOnNetwork, endpointDefinition); 

当 ABI 可用

let resultsParser = new ResultsParser();
let transactionOnNetwork = await networkProvider.getTransaction(txHash);
let { returnCode } = resultsParser.parseOutcome(transactionOnNetwork, endpointDefinition); 

endpointDefinition可以从Interaction对象中获得,如果在上下文中可用的话:

let endpointDefinition = interaction.getEndpoint(); 

或者,endpointDefinition可以从SmartContract对象中获得:

let endpointDefinition = smartContract.getEndpoint("myFunction"); 

要定制默认解析器,请参见扩展 erdjs

解码交易元数据

利用transaction-decoder

为了从交易有效负载中解码元数据(函数、参数、传输),请执行以下操作:

import { TransactionDecoder, TransactionMetadata } from "@elrondnetwork/transaction-decoder";

let transactionOnNetwork = await networkProvider.getTransaction(txHash);

let metadata = new TransactionDecoder().getTransactionMetadata({
    sender: transactionOnNetwork.sender.bech32(),
    receiver: transactionOnNetwork.receiver.bech32(),
    data: transactionOnNetwork.data.toString("base64"),
    value: transactionOnNetwork.value.toString(),
    type: transactionOnNetwork.type
}); 

利用erdjs 9xesdtHelpersscArgumentsParser

erdjs 10esdtHelpersscArgumentsParser类已经被移除,取而代之的是@ elrond network/transaction-decoder(见上)。

但是,您仍然可以在以下位置找到以前的实现:



回到顶部