Handy snippet to announce a transaction and wait until this is confirmed.
When announcing a transaction in NIS1, you had to wait to get the response from the node. Symbol works differently: when a transaction is announced, the REST API server will always return an OK. As a result, the developer does not have to wait until the server returns a response, being able to make more responsive apps. However, now is the developer’s responsibility to check the status of the transaction and ensure it is confirmed.
The negative aspect of announcing transactions asynchronously is that it adds unnecessary complexity to small projects.
The Symbol SDK TransactionService
aims to solve this problem by providing a function that waits for the confirmation or rejection of the transaction.
Complete sending mosaics and messages between two accounts guide.
Create a new account.
Load the account with enough symbol.xym
to pay for transaction fees.
Alice is developing an app to send 10 cat.currency
to Bob and wants to know if the transaction has reached the network before sending Bob an email.
Create a new .ts
file. Then, define and sign a TransferTransaction.
// replace with recipient address
const rawRecipientAddress = 'TB6Q5E-YACWBP-CXKGIL-I6XWCH-DRFLTB-KUK34I-YJQ';
const recipientAddress = Address.createFromRawAddress(rawRecipientAddress);
// replace with network type
const networkType = NetworkType.TEST_NET;
// replace with symbol.xym id
const networkCurrencyMosaicId = new MosaicId('5E62990DCAC5BE8A');
// replace with network currency divisibility
const networkCurrencyDivisibility = 6;
const transferTransaction = TransferTransaction.create(
Deadline.create(epochAdjustment),
recipientAddress,
[
new Mosaic(
networkCurrencyMosaicId,
UInt64.fromUint(10 * Math.pow(10, networkCurrencyDivisibility)),
),
],
EmptyMessage,
networkType,
UInt64.fromUint(2000000),
);
// replace with sender private key
const privateKey =
'1111111111111111111111111111111111111111111111111111111111111111';
const account = Account.createFromPrivateKey(privateKey, networkType);
// replace with meta.networkGenerationHash (nodeUrl + '/node/info')
const networkGenerationHash =
'1DFB2FAA9E7F054168B0C5FCB84F4DEB62CC2B4D317D861F3168D161F54EA78B';
const signedTransaction = account.sign(
transferTransaction,
networkGenerationHash,
);
// replace with recipient address
const rawRecipientAddress = 'TB6Q5E-YACWBP-CXKGIL-I6XWCH-DRFLTB-KUK34I-YJQ';
const recipientAddress = symbol_sdk_1.Address.createFromRawAddress(
rawRecipientAddress,
);
// replace with network type
const networkType = symbol_sdk_1.NetworkType.TEST_NET;
// replace with symbol.xym id
const networkCurrencyMosaicId = new symbol_sdk_1.MosaicId('5E62990DCAC5BE8A');
// replace with network currency divisibility
const networkCurrencyDivisibility = 6;
const transferTransaction = symbol_sdk_1.TransferTransaction.create(
symbol_sdk_1.Deadline.create(epochAdjustment),
recipientAddress,
[
new symbol_sdk_1.Mosaic(
networkCurrencyMosaicId,
symbol_sdk_1.UInt64.fromUint(
10 * Math.pow(10, networkCurrencyDivisibility),
),
),
],
symbol_sdk_1.EmptyMessage,
networkType,
symbol_sdk_1.UInt64.fromUint(2000000),
);
// replace with sender private key
const privateKey =
'1111111111111111111111111111111111111111111111111111111111111111';
const account = symbol_sdk_1.Account.createFromPrivateKey(
privateKey,
networkType,
);
// replace with meta.networkGenerationHash (nodeUrl + '/node/info')
const networkGenerationHash =
'1DFB2FAA9E7F054168B0C5FCB84F4DEB62CC2B4D317D861F3168D161F54EA78B';
const signedTransaction = account.sign(
transferTransaction,
networkGenerationHash,
);
Once signed, announce the transaction using TransactionService.announce
instead of TransactionHttp.announce
.
const nodeUrl = 'NODE_URL';
const repositoryFactory = new RepositoryFactoryHttp(nodeUrl);
const receiptHttp = repositoryFactory.createReceiptRepository();
const transactionHttp = repositoryFactory.createTransactionRepository();
const listener = repositoryFactory.createListener();
const transactionService = new TransactionService(transactionHttp, receiptHttp);
listener.open().then(() => {
merge(
transactionService.announce(signedTransaction, listener),
listener.status(account.address).pipe(
filter((error) => error.hash === signedTransaction.hash),
tap((error) => {
throw new Error(error.code);
}),
),
).subscribe(
(transaction) => {
console.log(transaction);
// TODO: send email to recipient
listener.close();
},
(err) => console.error(err),
);
});
const nodeUrl = 'NODE_URL';
const repositoryFactory = new symbol_sdk_1.RepositoryFactoryHttp(nodeUrl);
const receiptHttp = repositoryFactory.createReceiptRepository();
const transactionHttp = repositoryFactory.createTransactionRepository();
const listener = repositoryFactory.createListener();
const transactionService = new symbol_sdk_1.TransactionService(
transactionHttp,
receiptHttp,
);
listener.open().then(() => {
rxjs_1
.merge(
transactionService.announce(signedTransaction, listener),
listener.status(account.address).pipe(
operators_1.filter((error) => error.hash === signedTransaction.hash),
operators_1.tap((error) => {
throw new Error(error.code);
}),
),
)
.subscribe(
(transaction) => {
console.log(transaction);
// TODO: send email to recipient
listener.close();
},
(err) => console.error(err),
);
});
Note
The function TransactionService.announce()
will respond successfully if the transaction reaches the network and does not have validation errors. You might still need to wait for several confirmations before executing additional actions.