From b70740e81e7c22d41d195587fcf4764ede258040 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 | 74 ++++++++++++++++++++++++++- src/mappings/constants.ts | 22 ++++++-- src/mappings/events/balances.ts | 68 ++++++++++++++----------- src/mappings/mappingHandlers.ts | 89 +++++++++++++++++++++++++++++---- 4 files changed, 207 insertions(+), 46 deletions(-) diff --git a/project.ts b/project.ts index 14507895..f1474b09 100644 --- a/project.ts +++ b/project.ts @@ -87,6 +87,35 @@ const project: CosmosProject = { type: "state_change", }, }, + // Bank Events + { + handler: "handleBalanceEvent", + kind: CosmosHandlerKind.Event, + filter: { + type: "coinbase", + }, + }, + { + handler: "handleBalanceEvent", + kind: CosmosHandlerKind.Event, + filter: { + type: "coin_received", + }, + }, + { + handler: "handleBalanceEvent", + kind: CosmosHandlerKind.Event, + filter: { + type: "coin_spent", + }, + }, + { + handler: "handleBalanceEvent", + kind: CosmosHandlerKind.Event, + filter: { + type: "burn", + }, + }, { handler: "handleTransferEvent", kind: CosmosHandlerKind.Event, @@ -94,6 +123,49 @@ const project: CosmosProject = { type: "transfer", }, }, + { + handler: "handleBalanceEvent", + kind: CosmosHandlerKind.Event, + filter: { + type: "burn", + }, + }, + // Distribution Events + { + handler: "handleBalanceEvent", + kind: CosmosHandlerKind.Event, + filter: { + type: "rewards", + }, + }, + { + handler: "handleBalanceEvent", + kind: CosmosHandlerKind.Event, + filter: { + type: "commission", + }, + }, + { + handler: "handleBalanceEvent", + kind: CosmosHandlerKind.Event, + filter: { + type: "proposer_reward", + }, + }, + { + handler: "handleBalanceEvent", + kind: CosmosHandlerKind.Event, + filter: { + type: "withdraw_rewards", + }, + }, + { + handler: "handleBalanceEvent", + kind: CosmosHandlerKind.Event, + filter: { + type: "withdraw_rewards", + }, + }, ], }, }, @@ -101,4 +173,4 @@ const project: CosmosProject = { }; // Must set default to the project instance -export default project; +export default project; \ No newline at end of file diff --git a/src/mappings/constants.ts b/src/mappings/constants.ts index 6fab244b..0c43486c 100644 --- a/src/mappings/constants.ts +++ b/src/mappings/constants.ts @@ -24,11 +24,23 @@ export const VAULT_STATES = { LIQUIDATED: "liquidated" } -export const TRANSACTION_FIELDS = { - RECIPIENT: 'recipient', - SENDER: 'sender', - AMOUNT: 'amount' -} +export const BALANCE_FIELDS = { + amount: 'amount', + // Bank Events + coinbase: 'minter', + coin_received: 'receiver', + coin_spent: 'spender', + transfer_recipient: 'recipient', + transfer_sender: 'sender', + burn: "burner", + // Distribution Events + rewards: 'validator', + commission: 'validator', + proposer_reward: 'validator', + withdraw_rewards: 'validator', + withdraw_commission: 'validator', + +}; 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..2dfbc888 100644 --- a/src/mappings/events/balances.ts +++ b/src/mappings/events/balances.ts @@ -11,6 +11,11 @@ export interface DecodedEvent { type: string; attributes: Attribute[]; } + +export enum Operation { + Increment = "increment", + Decrement = "decrement", +} export const balancesEventKit = () => { function getAttributeValue(decodedData: DecodedEvent, key: string) { const attribute = decodedData.attributes.find((attr) => attr.key === key); @@ -40,7 +45,8 @@ export const balancesEventKit = () => { async function addressExists(address: string): Promise { const balance = await Balances.getByAddress(address); - if (balance?.length === 0) { + + if (!balance || balance.length === 0) { return false; } return true; @@ -50,48 +56,50 @@ 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, - amount: bigint + async function updateBalance( + address: string, + amount: bigint, + operation: Operation ): 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); + let newBalance: bigint; + + if (operation === Operation.Increment) { + newBalance = currentBalance + amount; + balance.balance = newBalance; + logger.info( + `Incremented balance for ${address} by ${amount}. New balance: ${balance.balance}` + ); + } else if (operation === Operation.Decrement) { + newBalance = currentBalance - amount; + if (newBalance < 0) { + logger.error( + `Attempt to decrement ${amount} would result in a negative balance. Current balance: ${currentBalance}.` + ); + return; + } + balance.balance = newBalance; + logger.info( + `Decremented balance for ${address} by ${amount}. New balance: ${balance.balance}` ); - return; } - const senderBalance = senderBalances[0]; - const recipientBalance = recipientBalances[0]; - - const senderCurrentBalance = senderBalance.balance ?? BigInt(0); - const recipientCurrentBalance = recipientBalance.balance ?? BigInt(0); - - senderBalance.balance = senderCurrentBalance - amount; - recipientBalance.balance = recipientCurrentBalance + amount; - - await senderBalance.save(); - await recipientBalance.save(); - - logger.info( - `Updated balances: Sender ${senderAddress} balance: ${senderBalance.balance}, Recipient ${recipientAddress} balance: ${recipientBalance.balance}` - ); + await balance.save(); } return { @@ -99,6 +107,6 @@ export const balancesEventKit = () => { decodeEvent, addressExists, createBalancesEntry, - updateBalances, + updateBalance, }; }; diff --git a/src/mappings/mappingHandlers.ts b/src/mappings/mappingHandlers.ts index 9c6d096a..ae105b08 100644 --- a/src/mappings/mappingHandlers.ts +++ b/src/mappings/mappingHandlers.ts @@ -37,14 +37,14 @@ 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"; import { priceFeedEventKit } from "./events/priceFeed"; import { vaultsEventKit } from "./events/vaults"; import { reservesEventKit } from "./events/reserves"; -import { DecodedEvent, balancesEventKit } from "./events/balances"; +import { DecodedEvent, Operation, balancesEventKit } from "./events/balances"; // @ts-ignore BigInt.prototype.toJSON = function () { @@ -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('Event:TRANSFER'); + 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) { @@ -220,9 +223,75 @@ export async function handleTransferEvent( await balancesKit.createBalancesEntry(senderAddress); } - balancesKit.updateBalances( - senderAddress, - recipientAddress, - BigInt(transactionAmount.slice(0, -4)) + const adjustedAmount = BigInt(Math.round(Number(transactionAmount.slice(0, -4)))); + + await Promise.all([ + balancesKit.updateBalance(senderAddress, adjustedAmount, Operation.Decrement), + balancesKit.updateBalance(recipientAddress, adjustedAmount, Operation.Increment), + ]); +} + +export async function handleBalanceEvent( + cosmosEvent: CosmosEvent +): Promise { + const { event } = cosmosEvent; + + const incrementEventTypes = [ + EVENT_TYPES.COMMISSION, + EVENT_TYPES.REWARDS, + EVENT_TYPES.PROPOSER_REWARD, + EVENT_TYPES.COIN_RECEIVED, + EVENT_TYPES.COINBASE, + ]; + + const decrementEventTypes = [ + EVENT_TYPES.COIN_SPENT, + EVENT_TYPES.BURN, + ]; + + let operation: Operation | null = null; + + if (incrementEventTypes.includes(event.type)) { + operation = Operation.Increment; + } else if (decrementEventTypes.includes(event.type)) { + operation = Operation.Decrement; + } else { + logger.warn(`${event.type} is not a valid balance event.`); + return; + } + + logger.info(`Event:${event.type}`); + + 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 = await balancesKit.addressExists(address); + + if (!entryExists) { + await balancesKit.createBalancesEntry(address); + } + + const amount = BigInt(Math.round(Number(transactionAmount.slice(0, -4)))); + await balancesKit.updateBalance(address, amount, operation); }