From a05865e57ce9aac4958a20e2a8ad7722b9597ed1 Mon Sep 17 00:00:00 2001 From: rabi-siddique Date: Tue, 30 Apr 2024 21:44:42 +0500 Subject: [PATCH] feat: add handlers for incrementing and decrementing balances --- project.ts | 21 ++++++ src/mappings/constants.ts | 17 +++-- src/mappings/events/balances.ts | 68 +++++++++++------- src/mappings/mappingHandlers.ts | 120 +++++++++++++++++++++++++++++--- 4 files changed, 184 insertions(+), 42 deletions(-) diff --git a/project.ts b/project.ts index 14507895..9d7a20fa 100644 --- a/project.ts +++ b/project.ts @@ -94,6 +94,27 @@ const project: CosmosProject = { type: "transfer", }, }, + { + handler: "handleBalanceDecrementEvent", + kind: CosmosHandlerKind.Event, + filter: { + type: "transfer", + }, + }, + { + handler: "handleBalanceIncrementEvent", + kind: CosmosHandlerKind.Event, + filter: { + type: "coin_received", + }, + }, + { + handler: "handleBalanceDecrementEvent", + kind: CosmosHandlerKind.Event, + filter: { + type: "coin_spent", + }, + }, ], }, }, diff --git a/src/mappings/constants.ts b/src/mappings/constants.ts index 6fab244b..b21fc736 100644 --- a/src/mappings/constants.ts +++ b/src/mappings/constants.ts @@ -24,11 +24,18 @@ export const VAULT_STATES = { LIQUIDATED: "liquidated" } -export const TRANSACTION_FIELDS = { - RECIPIENT: 'recipient', - SENDER: 'sender', - AMOUNT: 'amount' -} +export const BALANCE_FIELDS = { + coinbase: 'minter', + commission: 'validator', + proposer_reward: 'validator', + message: 'sender', + rewards: 'validator', + coin_received: 'receiver', + coin_spent: 'spender', + transfer_recipient: 'recipient', + transfer_sender: 'sender', + amount: 'amount', +}; export const VALUE_KEY = b64encode("value"); export const STORE_KEY = b64encode("store"); diff --git a/src/mappings/events/balances.ts b/src/mappings/events/balances.ts index 595ae4b3..cd4cf12f 100644 --- a/src/mappings/events/balances.ts +++ b/src/mappings/events/balances.ts @@ -38,9 +38,10 @@ export const balancesEventKit = () => { return decodedData; } - async function addressExists(address: string): Promise { + async function isAddressInUse(address: string): Promise { const balance = await Balances.getByAddress(address); - if (balance?.length === 0) { + + if (!balance || balance.length === 0) { return false; } return true; @@ -50,55 +51,70 @@ export const balancesEventKit = () => { const newBalance = new Balances(address); newBalance.address = address; newBalance.balance = BigInt(0); - newBalance.denom = ''; + newBalance.denom = 'ubld'; await newBalance.save(); logger.info(`Created new entry for address: ${address}`); } - async function updateBalances( - senderAddress: string, - recipientAddress: string, + async function incrementBalance( + address: string, amount: bigint ): Promise { - const senderBalances = await Balances.getByAddress(senderAddress); - const recipientBalances = await Balances.getByAddress(recipientAddress); + const balances = await Balances.getByAddress(address); - if (!senderBalances || senderBalances.length === 0) { - logger.error(`Sender balance not found for address: ${senderAddress}`); + if (!balances || balances.length === 0) { + logger.error(`Balance not found for address: ${address}`); return; } - if (!recipientBalances || recipientBalances.length === 0) { - logger.error( - `Recipient balance not found for address: ${recipientAddress}` - ); + const balance = balances[0]; + const currentBalance = balance.balance ?? BigInt(0); + balance.balance = currentBalance + amount; + + await balance.save(); + logger.info( + `Incremented balance for ${address} by ${amount}. New balance: ${balance.balance}` + ); + } + + async function decrementBalance( + address: string, + amount: bigint + ): Promise { + const balances = await Balances.getByAddress(address); + + if (!balances || balances.length === 0) { + logger.error(`Balance not found for address: ${address}`); return; } - const senderBalance = senderBalances[0]; - const recipientBalance = recipientBalances[0]; - - const senderCurrentBalance = senderBalance.balance ?? BigInt(0); - const recipientCurrentBalance = recipientBalance.balance ?? BigInt(0); + const balance = balances[0]; + const currentBalance = balance.balance ?? BigInt(0); + const newBalance = currentBalance - amount; - senderBalance.balance = senderCurrentBalance - amount; - recipientBalance.balance = recipientCurrentBalance + amount; + if (newBalance < 0) { + logger.error( + `Transaction failed: Attempt to decrement ${amount} would result in a negative balance. Current balance: ${currentBalance}.` + ); + return; + } - await senderBalance.save(); - await recipientBalance.save(); + balance.balance = newBalance; + await balance.save(); logger.info( - `Updated balances: Sender ${senderAddress} balance: ${senderBalance.balance}, Recipient ${recipientAddress} balance: ${recipientBalance.balance}` + `Decremented balance for ${address} by ${amount}. New balance: ${balance.balance}` ); } return { getAttributeValue, decodeEvent, - addressExists, + isAddressInUse, createBalancesEntry, - updateBalances, + incrementBalance, + decrementBalance, }; }; diff --git a/src/mappings/mappingHandlers.ts b/src/mappings/mappingHandlers.ts index 9c6d096a..2e2e119a 100644 --- a/src/mappings/mappingHandlers.ts +++ b/src/mappings/mappingHandlers.ts @@ -37,7 +37,7 @@ import { STORE_NAME_KEY, SUBKEY_KEY, UNPROVED_VALUE_KEY, - TRANSACTION_FIELDS + BALANCE_FIELDS } from "./constants"; import { psmEventKit } from "./events/psm"; import { boardAuxEventKit } from "./events/boardAux"; @@ -169,27 +169,30 @@ export async function handleStateChangeEvent(cosmosEvent: CosmosEvent): Promise< export async function handleTransferEvent( cosmosEvent: CosmosEvent ): Promise { - const { event, block } = cosmosEvent; + const { event } = cosmosEvent; if (event.type != EVENT_TYPES.TRANSFER) { logger.warn('Not valid transfer event.'); return; } + logger.info('Captured a TRANSFER event'); + const balancesKit = balancesEventKit(); const decodedData: DecodedEvent = balancesKit.decodeEvent(cosmosEvent); + logger.info(`Decoded transaction data ${JSON.stringify(decodedData)}`); const recipientAddress = balancesKit.getAttributeValue( decodedData, - TRANSACTION_FIELDS.RECIPIENT + BALANCE_FIELDS.transfer_recipient ); const senderAddress = balancesKit.getAttributeValue( decodedData, - TRANSACTION_FIELDS.SENDER + BALANCE_FIELDS.transfer_sender ); const transactionAmount = balancesKit.getAttributeValue( decodedData, - TRANSACTION_FIELDS.AMOUNT + BALANCE_FIELDS.amount ); if (!recipientAddress) { @@ -208,8 +211,8 @@ export async function handleTransferEvent( } const [recipientEntryExists, senderEntryExists] = await Promise.all([ - balancesKit.addressExists(recipientAddress), - balancesKit.addressExists(senderAddress), + balancesKit.isAddressInUse(recipientAddress), + balancesKit.isAddressInUse(senderAddress), ]); if (!recipientEntryExists) { @@ -220,9 +223,104 @@ export async function handleTransferEvent( await balancesKit.createBalancesEntry(senderAddress); } - balancesKit.updateBalances( - senderAddress, - recipientAddress, - BigInt(transactionAmount.slice(0, -4)) + await Promise.all([ + balancesKit.decrementBalance( + senderAddress, + BigInt(transactionAmount.slice(0, -4)) + ), + balancesKit.incrementBalance( + recipientAddress, + BigInt(transactionAmount.slice(0, -4)) + ), + ]); +} + +export async function handleBalanceIncrementEvent( + cosmosEvent: CosmosEvent +): Promise { + const { event } = cosmosEvent; + + if (![EVENT_TYPES.COIN_RECEIVED].includes(event.type)) { + logger.warn(`${event.type} is not valid balance increment event.`); + return; + } + + logger.info(`Captured ${event.type} event`); + + const balancesKit = balancesEventKit(); + const decodedData: DecodedEvent = balancesKit.decodeEvent(cosmosEvent); + logger.info(`Decoded transaction data ${JSON.stringify(decodedData)}`); + + const address = balancesKit.getAttributeValue( + decodedData, + BALANCE_FIELDS[event.type as keyof typeof BALANCE_FIELDS] ); + + const transactionAmount = balancesKit.getAttributeValue( + decodedData, + BALANCE_FIELDS.amount + ); + + if (!address) { + logger.error('Address is missing or invalid.'); + return; + } + + if (!transactionAmount) { + logger.error('Transaction amount is missing or invalid.'); + return; + } + + const entryExists = balancesKit.isAddressInUse(address); + + if (!entryExists) { + await balancesKit.createBalancesEntry(address); + } + + balancesKit.incrementBalance(address, BigInt(transactionAmount.slice(0, -4))); } + +export async function handleBalanceDecrementEvent( + cosmosEvent: CosmosEvent +): Promise { + const { event } = cosmosEvent; + + if (![EVENT_TYPES.COIN_SPENT].includes(event.type)) { + logger.warn(`${event.type} is not valid balance decrement event.`); + return; + } + + logger.info(`Captured ${event.type} event`); + + const balancesKit = balancesEventKit(); + const decodedData: DecodedEvent = balancesKit.decodeEvent(cosmosEvent); + logger.info(`Decoded transaction data ${JSON.stringify(decodedData)}`); + + const address = balancesKit.getAttributeValue( + decodedData, + BALANCE_FIELDS[event.type as keyof typeof BALANCE_FIELDS] + ); + + const transactionAmount = balancesKit.getAttributeValue( + decodedData, + BALANCE_FIELDS.amount + ); + + if (!address) { + logger.error('Address is missing or invalid.'); + return; + } + + if (!transactionAmount) { + logger.error('Transaction amount is missing or invalid.'); + return; + } + + const entryExists = balancesKit.isAddressInUse(address); + + if (!entryExists) { + await balancesKit.createBalancesEntry(address); + } + + balancesKit.decrementBalance(address, BigInt(transactionAmount.slice(0, -4))); +} \ No newline at end of file