Nhảy đến nội dung chính

Tạo Các Transaction

Để tạo & xử lý các transaction bạn sẽ cần đến thư viện API JavaScript của chúng tôi: near-api-js. Có rất nhiều cách để tạo các transaction nhưng trong ví dụ này chúng tôi sẽ chỉ cho bạn hai cách để tạo một transaction đơn giản để transfer token.

  • HIGH LEVEL - Cách dễ dàng nhất để tạo một transaction
  • LOW LEVEL - thực hiện chính xác những gì transaction ở trên đang làm, nhưng sẽ đi vào chi tiết từng bước cụ thể của toàn bộ quy trình cho những ai quan tâm

Về cốt lõi, tất cả các transaction yêu cầu những phần sau:

  • signerId (account ID của người khởi tạo transaction)
  • signerPublicKey
  • receiverId (account ID của người nhận transaction)
  • nonceForPublicKey (mỗi lần key được sử dụng, giá trị nonce này sẽ được tăng lên 1)
  • actions ( [bấm vào đây] để biết về những argument được hỗ trợ)
  • blockHash (hash của block hiện tại (trong vòng 24 giờ) để chứng minh transaction đó vừa được tạo)

See Transaction Class for a more in depth outline.


HIGH LEVEL -- Create a transaction

Setup

  1. Clone repository transaction-examples bằng cách chạy:
git clone https://github.com/near-examples/transaction-examples.git
  1. Follow setup instructions

Imports

Trong file send-tokens-easy.js chúng ta sử dụng hai dependency:

  1. Thư viện API JavaScript của NEAR
  2. dotenv (dùng để load những environment variable cho private key)
const nearAPI = require("near-api-js");
const { connect, KeyPair, keyStores, utils } = nearAPI;
require("dotenv").config();

Dòng thứ hai ở trên phân giải môt vài tiện ích trong nearAPI, mà bạn sẽ sử dụng chúng để thao tác với blockchain.

  • connect - truyền vào các variable thiết lập để tạo kết nối tới NEAR
  • KeyPair - tạo một keyPair từ private key mà bạn sẽ đưa vào trong một file .env
  • keyStores - lưu trữ keyPair mà bạn sẽ tạo từ private key và dùng nó để sign các Transaction
  • utils - được dùng để format các khoản tiền trong NEAR

Accounts & Network

Tiếp theo, bạn sẽ cần điền accountId của senderreceiver, cũng như là networkId (betanet, testnet, hoặc mainnet).

const sender = "sender.testnet";
const receiver = "receiver.testnet";
const networkId = "testnet";

Formatting Token Amounts

Khi gửi các NEAR token (Ⓝ) trong một transaction, khoản tiền này cần được chuyền thành Yocto Ⓝ hay (10^-24).

const amount = nearAPI.utils.format.parseNearAmount("1.5");

Create a Key Store

In order to sign transactions you will need to create a "Key Store" that will hold a full access key to sign your transactions. Có một vài cách để hoàn tất việc này, nhưng trong ví dụ này chúng ta sẽ sử dụng private key đã được lưu trong file .env trong project của bạn, hoặc một environment variable được export toàn cục.

  • Nếu bạn đã tạo account bằng cách dùng near-cli hoặc đã chạy near login trong terminal của bạn, thì private key của bạn có thể được tìm thấy trong file .json nằm tại /HOME/.near-credentials.
  • If you created an account using NEAR Wallet, your key will be found in your browser's Local Storage.
    • Trong dev tools của browser... Application >> Storage >> Local Storage
// thiết lập một object keyStore trống trong memory bằng near-api-js
const keyStore = new keyStores.InMemoryKeyStore();
// tạo một keyPair từ private key được cung cấp trong file .env của bạn
const keyPair = KeyPair.fromString(process.env.SENDER_PRIVATE_KEY);
// thêm key bạn vừa tạo vào keyStore của bạn, nó có thể giữ nhiều key (phải nằm trong một async function)
await keyStore.setKey(networkId, sender, keyPair);

Setting up a connection to NEAR

Bây giờ tạo một kết nối tới NEAR sử dụng một configuration object, nó sẽ chứa networkId đã được cài đặt trước đó cũng như keyStore của bạn.

// configuration used to connect to NEAR
const prefix = (networkId === "testnet") ? "testnet" : "www";

const config = {
networkId,
keyStore,
nodeUrl: `https://rpc.${networkId}.near.org`,
walletUrl: `https://wallet.${networkId}.near.org`,
helperUrl: `https://helper.${networkId}.near.org`,
explorerUrl: `https://${prefix}.nearblocks.io`,
};

// connect to NEAR! :)
const near = await connect(config);
// tạo một object NEAR account
const senderAccount = await near.account(sender);

Bạn sẽ báo cho dòng cuối sử dụng kết nối tới NEAR của bạn để tạo một object senderAccount mà bạn sẽ dùng để thực hiện một transaction.

Create, Sign, & Send Transaction

Bây giờ bạn đã cài đặt mọi thứ, khởi tạo transaction bằng chỉ bằng một dòng code.

const result = await senderAccount.sendMoney(receiver, amount);

Command đơn giản này sẽ khởi tạo, sign, và gửi một transaction về việc transfer token trên NEAR blockchain. There is no need to create a result variable aside from inspecting the response details from your transaction and even create a link to NearBlocks Explorer to view a GUI version of the transaction details.


LOW LEVEL -- Create a Transaction

Setup

  1. Clone repository transaction-examples bằng cách chạy:
git clone https://github.com/near-examples/transaction-examples.git
  1. Follow setup instructions

Imports

Trong file send-tokens-deconstructed.js chúng ta sử dụng ba dependency:

  1. Thư viện API JavaScript của NEAR
  2. js-sha256 (giải thuật hash mã hóa)
  3. dotenv (dùng để load các environment variable)
const nearAPI = require("near-api-js");
const sha256 = require("js-sha256");
require("dotenv").config();

Accounts & Network

Tiếp theo, bạn sẽ cần điền accountId của senderreceiver, cũng như là networkId (betanet, testnet, hoặc mainnet).

const sender = "sender.testnet";
const receiver = "receiver.testnet";
const networkId = "testnet";

Formatting Token Amounts

Khi gửi các NEAR token (Ⓝ) trong một transaction, khoản tiền này cần được chuyền thành Yocto Ⓝ hay (10^-24).

const amount = nearAPI.utils.format.parseNearAmount("1.5");

Setting up a connection to NEAR

Trong ví dụ này, chúng ta sẽ tạo một NEAR RPC provider, nó sẽ cho phép chúng ta tương tác với chain thông qua các RPC endpoint.

const provider = new nearAPI.providers.JsonRpcProvider(
`https://rpc.${networkId}.near.org`
);

Access Keys

Để sign một transaction để gửi NEAR Ⓝ, chúng ta cần một FullAccess key vào account của người gửi.

  • Nếu bạn đã tạo account bằng cách dùng near-cli hoặc đã chạy near login trong terminal của bạn, thì private key của bạn có thể được tìm thấy trong file .json nằm tại /HOME/.near-credentials.
  • If you created an account using NEAR Wallet, your key will be found in your browser's Local Storage.
    • Trong dev tools của browser... Application >> Storage >> Local Storage

Một khi bạn có quyền truy cập vào private key của account người gửi, tạo một environment variable SENDER_PRIVATE_KEY hoặc hard code nó trong một string như trong dòng 18 của file send-tokens.js.

  • Với privateKey này, chúng ta có thể khởi tạo một object keyPair để sign các transaction.
const privateKey = process.env.SENDER_PRIVATE_KEY;
const keyPair = nearAPI.utils.key_pair.KeyPairEd25519.fromString(privateKey);

Transaction Requirements

Như đã nêu ở trên, tất cả các transaction yêu cầu sáu phần sau:

  1. signerId
  2. signerPublicKey
  3. receiverId
  4. nonceForPublicKey
  5. actions
  6. blockHash

1 signerId

  • signerId là một account ID của người khởi tạo transaction.
  • Giá trị này được truyền vào dưới dạng một string (ví dụ: 'example.testnet' hoặc 'bob.near')

2 signerPublicKey

  • signerPublicKey được yêu cầu dưới dạng một object với hai cặp key value: keyType and data.
PublicKey = {
keyType: 0,
data: Uint8Array(32)[
(190,
150,
152,
145,
232,
248,
128,
151,
167,
165,
128,
46,
20,
231,
103,
142,
39,
56,
152,
46,
135,
1,
161,
180,
94,
212,
195,
201,
73,
190,
70,
242)
],
};
  • Điều này có thể được khởi tạo bằng cách gọi method getPublicKey() sử dụng variable keyPair mà chúng ta đã cài đặt trước đó.
const publicKey = keyPair.getPublicKey();

3 receiverId

  • receiverId là account ID của người nhận transaction.
  • Giá trị này được truyền vào dưới dạng một string (ví dụ: 'example.testnet' hoặc 'bob.near')
  • Trong một số trường hợp nhất định, signerIdreceiverId có thể là cùng một account.

4 nonceForPublicKey

  • Một số duy nhất hoặc một giá trị nonce được yêu cầu cho mỗi transaction, được sign bởi một access key.
  • Để đảm bảo chỉ một số duy nhất được tạo ra cho mỗi transaction, giá trị nonce hiện tại phải được query và sau đó tăng lên 1.
  • Giá trị nonce hiện tại có thể nhận được bằng cách sử dụng variable provider mà chúng ta đã tạo trước đó.
const accessKey = await provider.query(
`access_key/${sender}/${publicKey.toString()}`,
""
);
  • bây giờ chúng ta có thể tạo một số duy nhất cho transaction của chúng ta bằng cách tăng giá trị nonce hiện tại.
const nonce = ++accessKey.nonce;

5 actions

const actions = [nearAPI.transactions.transfer(amount)];

[bấm vào đây] để xem source của method transfer().

6 blockHash

  • Mỗi transaction yêu cầu một hash của block hiện tại (trong 24 giờ) để chứng mình rằng transaction này vừa được tạo.
  • Hash phải được chuyển thành một byte array bằng các dùng method base_decode nằm trong nearAPI.
const recentBlockHash = nearAPI.utils.serialize.base_decode(
accessKey.block_hash
);

[bấm vào đây] để view source của method base_decode().


Constructing the Transaction

Bây giờ, chúng ta có thể tạo transaction bằng tất cả các tham số yêu cầu ở trên.

  • Sử dụng nearAPI, chúng ta call method createTransaction() để thực hiện công việc này.
const transaction = nearAPI.transactions.createTransaction(
sender,
publicKey,
receiver,
nonce,
actions,
recentBlockHash
);

[bấm vào đây] để xem source code của class Transaction


Sign Transaction

Bây giờ transaction đã được tạo ra, chúng ta sign nó trước khi gửi nó đến NEAR blockchain. Ở tầng thấp nhất, có bốn bước cho quá trình này.

  1. Sử dụng nearAPI, chúng ta call method serialize() để serialize transaction bằng Borsh.
const serializedTx = nearAPI.utils.serialize.serialize(
nearAPI.transactions.SCHEMA,
transaction
);
  1. Hash transaction đã được serialize sử dụng giải thuật hash mã hóa sha256.
const serializedTxHash = new Uint8Array(sha256.sha256.array(serializedTx));
  1. Tạo một signature với keyPair.
const signature = keyPair.sign(serializedTxHash);
  1. Tạo một transaction đã sign bằng cách sử dụng class SignedTransaction của near-api-js.
const signedTransaction = new nearAPI.transactions.SignedTransaction({
transaction,
signature: new nearAPI.transactions.Signature({
keyType: transaction.publicKey.keyType,
data: signature.signature,
}),
});

Send Transaction

Bước cuối cùng là encode và gửi transaction này.

  • Đầu tiên chúng ta serialize transaction bằng Borsh, và lưu kết quả trong variable signedSerializedTx. (bắt buộc với tất cả các transaction)
  • Sau đó chúng ta gửi transaction thông qua một RPC call sử dụng method sendJsonRpc() nằm trong near.
// encode transaction bằng Borsh serialize (bắt buộc với tất cả các transaction)
const signedSerializedTx = signedTransaction.encode();
// gửi transaction tới NEAR blockchain thông qua JSON RPC call và ghi lại kết quả
const result = await provider.sendJsonRpc("broadcast_tx_commit", [
Buffer.from(signedSerializedTx).toString("base64"),
]);

Transaction Results

Các kết quả chi tiết của transction được trả về dưới dạng sau:

{
status: { SuccessValue: '' },
transaction: {
signer_id: 'sender.testnet',
public_key: 'ed25519:8RazSLHvzj4TBSKGUo5appP7wVeqZNQYjP9hvhF4ZKS2',
nonce: 57,
receiver_id: 'receiver.testnet',
actions: [ [Object] ],
signature: 'ed25519:2sK53w6hybSxX7qWShXz6xKnjnYRUW7Co3evEaaggNW6pGSCNPvx7urY4akwnzAbxZGwsKjx8dcVm73qbitntJjz',
hash: 'EgGzB73eFxCwZRGcEyCKedLjvvgxhDXcUtq21SqAh79j'
},
transaction_outcome: {
proof: [ [Object] ],
block_hash: 'J6cFDzAFkuknHMCEYW2uPQXDvCfSndkJmADVEWJbtTwV',
id: 'EgGzB73eFxCwZRGcEyCKedLjvvgxhDXcUtq21SqAh79j',
outcome: {
logs: [],
receipt_ids: [Array],
gas_burnt: 223182562500,
tokens_burnt: '22318256250000000000',
executor_id: 'sender.testnet',
status: [Object]
}
},
receipts_outcome: [
{
proof: [Array],
block_hash: 'FSS7UzTpMr4mUm6aw8MmzP6Q7wnQs35VS8vYm1R461dM',
id: '3LjBxe2jq1s7XEPrYxihp4rPVdyHAbYfkcdJjUEVijhJ',
outcome: [Object]
},
{
proof: [Array],
block_hash: '4XBio5dM5UGYjJgzZjgckfVgMZ9uKGbTkt8zZi5webxw',
id: 'AXFA4kwiYfruKQ4LkD1qZA8P7HoAvtFwGqwQYdWtWNaW',
outcome: [Object]
}
]
}
Transaction Results: {
signer_id: 'sender.testnet',
public_key: 'ed25519:8RazSLHvzj4TBSKGUo5appP7wVeqZNQYjP9hvhF4ZKS2',
nonce: 57,
receiver_id: 'receiver.testnet',
actions: [ { Transfer: [Object] } ],
signature: 'ed25519:2sK53w6hybSxX7qWShXz6xKnjnYRUW7Co3evEaaggNW6pGSCNPvx7urY4akwnzAbxZGwsKjx8dcVm73qbitntJjz',
hash: 'EgGzB73eFxCwZRGcEyCKedLjvvgxhDXcUtq21SqAh79j'
}

Để biết thêm thông tin chi tiết của các transaction receipt [bấm vào đây]

  • To view the transaction in NearBlocks Explorer, enter the hash located under transaction / Transaction Results.
  • Hơn nữa, bạn có thể tạo một link trong JS bằng cách sử dụng networkIdresult.transaction.hash.
const prefix = (networkId === "testnet") ? "testnet." : "";
const transactionLink = `https://${prefix}nearblocks.io/txns/${result.transaction.hash}`;

Happy Coding! 🚀