Tạo Các Transaction
To construct & process transactions you will need our API JavaScript library: 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
( [click here] for supported arguments)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
- Clone repository transaction-examples bằng cách chạy:
git clone https://github.com/near-examples/transaction-examples.git
- Follow setup instructions
Imports
Trong file send-tokens-easy.js
chúng ta sử dụng hai dependency:
- Thư viện API JavaScript của NEAR
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 NEARKeyPair
- 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 Transactionutils
- đượ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 sender
và receiver
, 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).
- Để làm điều này bạn sẽ dùng method
parseNearAmount()
củanear-api-js
(nằm tạiutils/format
)
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ạynear 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
- Trong dev tools của browser...
// 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
- Clone repository transaction-examples bằng cách chạy:
git clone https://github.com/near-examples/transaction-examples.git
- Follow setup instructions
Imports
Trong file send-tokens-deconstructed.js
chúng ta sử dụng ba dependency:
- Thư viện API JavaScript của NEAR
js-sha256
(giải thuật hash mã hóa)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 sender
và receiver
, 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).
- Để làm điều này bạn sẽ dùng method
parseNearAmount()
củanear-api-js
(nằm tạiutils/format
)
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ạynear 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
- Trong dev tools của browser...
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 objectkeyPair
để sign các transaction.
const privateKey = process.env.SENDER_PRIVATE_KEY;
const keyPair = nearAPI.KeyPair.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
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
anddata
.
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 variablekeyPair
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,
signerId
vàreceiverId
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
- Hiện tại, có tám loại
Action
được hỗ trợ. [see here] - Trong ví dụ này, chúng ta sử dụng
Transfer
- Action transfer này có thể được tạo bằng cách sử dụng object
nearAPI
đã được import vàamount Ⓝ đã được format được tạo ra trước đó.
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 trongnearAPI
.
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 methodcreateTransaction()
để 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.
const serializedTx = nearAPI.utils.serialize.serialize(
nearAPI.transactions.SCHEMA.Transaction,
transaction
);
- Hash transaction đã được serialize sử dụng giải thuật hash mã hóa
sha256
.
const serializedTxHash = new Uint8Array(sha256.sha256.array(serializedTx));
- Tạo một signature với
keyPair
.
const signature = keyPair.sign(serializedTxHash);
- 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 trongnear
.
// 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 undertransaction
/Transaction Results
. - Hơn nữa, bạn có thể tạo một link trong JS bằng cách sử dụng
networkId
vàresult.transaction.hash
.
const prefix = (networkId === "testnet") ? "testnet." : "";
const transactionLink = `https://${prefix}nearblocks.io/txns/${result.transaction.hash}`;
Happy Coding! 🚀