Transactions (a.k.a. extrinsics) are uniquely identified by block hash + their index. See also https://wiki.polkadot.network/docs/build-protocol-info#unique-identifiers-for-extrinsics
consttxId= { blockHash:BLOCK_HASH, index:EXTRINSIC_INDEX,};const { ApiPromise,WsProvider } =require('@polkadot/api');constprovider=newWsProvider('<WS_ENDPOINT>');constapi=awaitApiPromise.create({ provider });constapiAt=awaitapi.at(txId.blockHash);constallEvents=awaitapiAt.query.system.events();consttxEvents=allEvents.filter(({ phase }) =>phase.isApplyExtrinsic &&phase.asApplyExtrinsic.eq(txId.index));constsuccessEvent=txEvents.find(({ event }) =>api.events.system.ExtrinsicSuccess.is(event));constfailureEvent=txEvents.find(({ event }) =>api.events.system.ExtrinsicFailed.is(event));if (successEvent) {consttransferEvents=txEvents.filter(({ event }) =>api.events.assets.Transferred.is(event));transferEvents.forEach(({ event }) => {const [assetId,fromAccount,toAccount,amount] =event.data;if (assetId ==1) {console.log(`Transfer of ${amount} grains of LLM from ${fromAccount} to ${toAccount}`); } });} else {const [dispatchError,dispatchInfo] =failureEvent.event.data;let errorInfo;// decode the errorif (dispatchError.isModule) {// for module errors, we have the section indexed, lookup// (For specific known errors, we can also do a check against the// api.errors.<module>.<ErrorName>.is(dispatchError.asModule) guard)constdecoded=api.registry.findMetaError(dispatchError.asModule); errorInfo =`${decoded.section}.${decoded.name}`; } else {// Other, CannotLookup, BadOrigin, no extra info errorInfo =dispatchError.toString(); }console.log(`ExtrinsicFailed:: ${errorInfo}`);}
Optionally, for token transfers, you can use the "assets.transfer" method and then provide the id of the asset you want to transfer. An example transfer for LLM (LLM=1).
const { ApiPromise,WsProvider } =require('@polkadot/api');const { Keyring } =require("@polkadot/api");constprovider=newWsProvider('<WS_ENDPOINT>');constapi=awaitApiPromise.create({ provider });constkeyring=newKeyring({ type:'sr25519' });constsender=keyring.addFromUri('<SENDER-ACCOUNT-PRIVATE-KEY>');// The following value 1 is the ID token of LLM.consttransferExtrinsic=api.tx.assets.transfer(1,'<ACCOUNT_TO>','<AMOUNT>');consttxHash=awaittransferExtrinsic.signAndSend(sender);
See also https://polkadot.js.org/docs/api/cookbook/tx/#how-do-i-get-the-decoded-enum-for-an-extrinsicfailed-event for example on how to see if tx succeeded.