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
- Clone repository transaction-examples bằng cách chạy:
git clone https://github.com/near-examples/transaction-examples.git
- Follow setup instructions
Import
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
Các Account & 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";
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).
- Để 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");
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ạ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
. - 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
- 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);
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
- Clone repository transaction-examples bằng cách chạy:
git clone https://github.com/near-examples/transaction-examples.git
- Follow setup instructions
Các Import
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();
Các Account & 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";
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).
- Để 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");
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ạ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
. - 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
- 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.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
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ợ. [xem thêm tại đây] - 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()
.
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 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
);
- 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,
}),
});
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 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"),
]);
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ủatransaction
/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
networkId
vàresult.transaction.hash
.
const transactionLink = `https://explorer.${networkId}.near.org/transactions/${result.transaction.hash}`;
Happy Coding! 🚀