Skip to content

Instantly share code, notes, and snippets.

@KaffinPX
Created July 21, 2022 14:35
Show Gist options
  • Save KaffinPX/354a5df82c3fc8a740125c21254dd3f1 to your computer and use it in GitHub Desktop.
Save KaffinPX/354a5df82c3fc8a740125c21254dd3f1 to your computer and use it in GitHub Desktop.
Kaspa transaction listener implementation in JS
const knownBlocks = new Map()
const knownTransactionsByBlock = {}
const waitingTransactions = {}
class extendedTransaction {
constructor(transaction) {
this.transaction = transaction
this.confirmations = 0
this.acceptingBlockHash = null
}
}
this.kaspa.subscribe('notifyBlockAddedRequest', {}, (data) => {
knownBlocks.set(data.block.verboseData.hash, data.block)
data.block.transactions.forEach(transaction => {
let isRelated = false
transaction.outputs.forEach(utxo => {
if (this.listeningAddrs.has(utxo.verboseData.scriptPublicKeyAddress)) { isRelated = true }
})
if (!isRelated) return
waitingTransactions[transaction.verboseData.transactionId] = new extendedTransaction(transaction)
})
})
this.kaspa.subscribe("notifyVirtualSelectedParentChainChangedRequest", { "includeAcceptedTransactionIds": true }, (data) => {
data.removedChainBlockHashes.forEach(removedBlockHash => {
knownTransactionsByBlock[removedBlockHash]?.forEach(transaction => {
waitingTransactions[transaction].acceptingBlockHash = null
})
delete knownTransactionsByBlock[removedBlockHash]
})
data.acceptedTransactionIds.forEach(acceptedTransactionIds => {
knownTransactionsByBlock[acceptedTransactionIds.acceptingBlockHash] = []
acceptedTransactionIds.acceptedTransactionIds.forEach(transactionId => {
if (typeof waitingTransactions[transactionId] === 'undefined') return
waitingTransactions[transactionId].acceptingBlockHash = acceptedTransactionIds.acceptingBlockHash
knownTransactionsByBlock[acceptedTransactionIds.acceptingBlockHash].push(transactionId)
})
})
const virtualParentHash = data.addedChainBlockHashes.slice(-1)[0]
const virtualParent = knownBlocks.get(virtualParentHash)
if (typeof virtualParent === 'undefined') return
const virtualParentBlueScore = virtualParent.verboseData.blueScore
for (const [key, value] of Object.entries(knownTransactionsByBlock)) {
var acceptingBlockHash = key
var transactions = value
var acceptingBlock = knownBlocks.get(acceptingBlockHash)
transactions.forEach(transaction => {
waitingTransactions[transaction].confirmations = virtualParentBlueScore - acceptingBlock.verboseData.blueScore + 1
if (waitingTransactions[transaction].confirmations >= this.config.deposit.networkConfirmations) {
knownTransactionsByBlock[key] = knownTransactionsByBlock[key].filter(tx => tx !== transaction)
waitingTransactions[transaction].transaction.outputs.forEach(output => {
if (!this.listeningAddrs.has(output.verboseData.scriptPublicKeyAddress)) return
this.emit('deposit', {
hash: waitingTransactions[transaction].transaction.verboseData.transactionId,
walletAddress: this.dbProvider.get('kaspaAccounts', output.verboseData.scriptPublicKeyAddress),
tokenId: this.config.tokenIds[0],
amount: output.amount
})
})
delete waitingTransactions[transaction]
}
})
}
})
@KaffinPX
Copy link
Author

Note: Has a memory leak

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment