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 -- Tạo transaction

Cài đặt

  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

Import

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

Các Account & 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";

Format Các Token Amount

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");

Tạo 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.
  • Nếu bạn đã tạo account bằng cách dùng NEAR Wallet, key của bạn sẽ được tìm thấy trong Local Storage của browser của bạn.
    • 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);

Cài đặt một kết nối tới 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 được dùng để kết nối tới NEAR
const config = {
networkId,
keyStore,
nodeUrl: `https://rpc.${networkId}.near.org`,
walletUrl: `https://wallet.${networkId}.near.org`,
helperUrl: `https://helper.${networkId}.near.org`,
explorerUrl: `https://explorer.${networkId}.near.org`,
};

// kết nối tới 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.

Tạo, Sign, & Gửi 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. Tạo một variable result thì không cần thiết ngoài việc kiểm tra chi tiết response và thậm chí tạo một link tới NEAR Explorer để có một GUI để xem chi tiết của transaction.


LOW LEVEL -- Tạo một Transaction

Cài đặt

  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

Các Import

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();

Các Account & 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";

Format Các Khoản Tiền Token

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");

Cài đặt một kết nối tới 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`
);

Các Access Key

Để 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.
  • Nếu bạn đã tạo account bằng cách dùng NEAR Wallet, key của bạn sẽ được tìm thấy trong Local Storage của browser của bạn.
    • 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);

Các yêu cầu của Transaction

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().


Khởi Tạo 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,
}),
});

Gửi 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"),
]);

Các Kết Quả của Transaction

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]

  • Để xem transaction trong NEAR Explorer, nhập vào hash nằm dưới cùng của transaction / Các Kết Quả của Transaction.
  • 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 transactionLink = `https://explorer.${networkId}.near.org/transactions/${result.transaction.hash}`;

Happy Coding! 🚀