Skip to content

Commit

Permalink
Add fee transactions report
Browse files Browse the repository at this point in the history
  • Loading branch information
sophialittlejohn committed Dec 4, 2024
1 parent c26a47f commit ebaf007
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 29 deletions.
14 changes: 14 additions & 0 deletions src/Reports/Processor.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { expect } from 'chai'
import { processor } from './Processor.js'
import { mockPoolSnapshots } from '../tests/mocks/mockPoolSnapshots.js'
import { mockFeeTransactions } from '../tests/mocks/mockPoolFeeTransactions.js'
import { mockTrancheSnapshots } from '../tests/mocks/mockTrancheSnapshots.js'
import { mockPoolFeeSnapshots } from '../tests/mocks/mockPoolFeeSnapshot.js'
import { mockPoolMetadata } from '../tests/mocks/mockPoolMetadata.js'
Expand Down Expand Up @@ -510,6 +511,19 @@ describe('Processor', () => {
}
})
})

describe('fee transactions processor', () => {
it('should return empty array when no transactions found', () => {
expect(processor.feeTransactions({ poolFeeTransactions: [] })).to.deep.equal([])
})
it('should process fee transactions correctly', () => {
const result = processor.feeTransactions({ poolFeeTransactions: mockFeeTransactions })
expect(result).to.have.lengthOf(2)
})
// TODO: add tests for filtering by transaction type
// find mapping for transaction type
})

describe('applyGrouping', () => {
const applyGrouping = processor['applyGrouping']
const mockData = [
Expand Down
51 changes: 35 additions & 16 deletions src/Reports/Processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import {
AssetTransactionReport,
AssetTransactionsData,
AssetTransactionReportFilter,
FeeTransactionsData,
FeeTransactionReportFilter,
FeeTransactionReport,
} from './types.js'

export class Processor {
Expand Down Expand Up @@ -212,41 +215,57 @@ export class Processor {

assetTransactions(data: AssetTransactionsData, filter?: AssetTransactionReportFilter): AssetTransactionReport[] {
return data.assetTransactions
.filter((day) => {
.filter((tx) => {
if (!filter?.transactionType || filter.transactionType === 'all') {
return true
}
if (filter.transactionType === 'created') {
return day.type === 'CREATED'
return tx.type === 'CREATED'
}
if (filter.transactionType === 'financed') {
return day.type === 'BORROWED'
return tx.type === 'BORROWED'
}
if (filter.transactionType === 'repaid') {
return day.type === 'REPAID'
return tx.type === 'REPAID'
}
if (filter.transactionType === 'priced') {
return day.type === 'PRICED'
return tx.type === 'PRICED'
}
if (filter.transactionType === 'closed') {
return day.type === 'CLOSED'
return tx.type === 'CLOSED'
}
if (filter.transactionType === 'cashTransfer') {
return day.type === 'CASH_TRANSFER'
return tx.type === 'CASH_TRANSFER'
}
return true
})
.filter((day) => {
return !filter?.assetId || filter.assetId === day.asset.id.split('-')[1]
.filter((tx) => {
return !filter?.assetId || filter.assetId === tx.asset.id.split('-')[1]
})
.map((day) => ({
.map((tx) => ({
type: 'assetTransactions',
timestamp: day.timestamp.toISOString(),
assetId: day.asset.id,
epoch: day.epochId,
transactionType: day.type,
amount: day.amount,
transactionHash: day.hash,
timestamp: tx.timestamp.toISOString(),
assetId: tx.asset.id,
epoch: tx.epochId,
transactionType: tx.type,
amount: tx.amount,
transactionHash: tx.hash,
}))
}

feeTransactions(data: FeeTransactionsData, filter?: FeeTransactionReportFilter): FeeTransactionReport[] {
return data.poolFeeTransactions
.filter((tx) => {
if (!filter?.transactionType || filter.transactionType === 'all') {
return true
}
return filter.transactionType === tx.type
})
.map((tx) => ({
type: 'feeTransactions',
timestamp: tx.timestamp,
feeId: tx.feeId,
amount: tx.amount,
}))
}

Expand Down
17 changes: 17 additions & 0 deletions src/Reports/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ import {
trancheSnapshotsPostProcess,
trancheSnapshotsQuery,
} from '../queries/trancheSnapshots.js'
import {
poolFeeTransactionQuery,
poolFeeTransactionPostProcess,
PoolFeeTransactionFilter,
} from '../queries/poolFeeTransactions.js'
import { combineLatest } from 'rxjs'
import { processor } from './Processor.js'

Expand Down Expand Up @@ -116,6 +121,10 @@ export class Reports extends Entity {
...dateFilter,
poolId: { equalTo: this.pool.id },
})
const poolFeeTransactions$ = this.poolFeeTransactionsQuery({
...dateFilter,
poolFee: { poolId: { equalTo: this.pool.id } },
})

switch (type) {
case 'balanceSheet':
Expand Down Expand Up @@ -147,6 +156,10 @@ export class Reports extends Entity {
return combineLatest([assetTransactions$, metadata$]).pipe(
map(([assetTransactions]) => processor.assetTransactions({ assetTransactions }, filter) as T[])
)
case 'feeTransactions':
return combineLatest([poolFeeTransactions$]).pipe(
map(([poolFeeTransactions]) => processor.feeTransactions({ poolFeeTransactions }, filter) as T[])
)
default:
throw new Error(`Unsupported report type: ${type}`)
}
Expand Down Expand Up @@ -176,4 +189,8 @@ export class Reports extends Entity {
assetTransactionsQuery(filter?: AssetTransactionFilter) {
return this._root._queryIndexer(assetTransactionsQuery, { filter }, assetTransactionsPostProcess)
}

poolFeeTransactionsQuery(filter?: PoolFeeTransactionFilter) {
return this._root._queryIndexer(poolFeeTransactionQuery, { filter }, poolFeeTransactionPostProcess)
}
}
21 changes: 21 additions & 0 deletions src/Reports/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AssetTransaction, AssetTransactionType } from '../queries/assetTransactions.js'
import { InvestorTransaction, SubqueryInvestorTransactionType } from '../queries/investorTransactions.js'
import { PoolFeeSnapshotsByDate } from '../queries/poolFeeSnapshots.js'
import { PoolFeeTransaction } from '../queries/poolFeeTransactions.js'
import { PoolSnapshot } from '../queries/poolSnapshots.js'
import { TrancheSnapshotsByDate } from '../queries/trancheSnapshots.js'
import { PoolMetadata } from '../types/poolMetadata.js'
Expand Down Expand Up @@ -172,3 +173,23 @@ export type AssetTransactionReportFilter = {
assetId?: string
transactionType?: 'created' | 'financed' | 'repaid' | 'priced' | 'closed' | 'cashTransfer' | 'all'
}

/**
* Fee transactions types
*/
export type FeeTransactionsData = {
poolFeeTransactions: PoolFeeTransaction[]
}

export type FeeTransactionReport = {
type: 'feeTransactions'
timestamp: string
feeId: string
amount: Currency
}

export type FeeTransactionReportFilter = {
from?: string
to?: string
transactionType?: 'directChargeMade' | 'directChargeCanceled' | 'accrued' | 'paid' | 'all'
}
26 changes: 13 additions & 13 deletions src/queries/assetTransactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,22 +105,22 @@ type SubqueryAssetTransactions = {

export const assetTransactionsPostProcess = (data: SubqueryAssetTransactions): AssetTransaction[] => {
return (
data.assetTransactions.nodes.map((day) => {
const decimals = day.pool.currency.decimals
data.assetTransactions.nodes.map((tx) => {
const decimals = tx.pool.currency.decimals
return {
...day,
settlementPrice: day.settlementPrice ? new Price(day.settlementPrice) : null,
amount: new Currency(day?.amount ?? 0n, decimals),
principalAmount: day.principalAmount ? new Currency(day.principalAmount, decimals) : undefined,
interestAmount: day.interestAmount ? new Currency(day.interestAmount, decimals) : undefined,
realizedProfitFifo: day.realizedProfitFifo ? new Currency(day.realizedProfitFifo, decimals) : undefined,
sumRealizedProfitFifo: day.asset.sumRealizedProfitFifo
? new Currency(day.asset.sumRealizedProfitFifo, decimals)
...tx,
settlementPrice: tx.settlementPrice ? new Price(tx.settlementPrice) : null,
amount: new Currency(tx?.amount ?? 0n, decimals),
principalAmount: tx.principalAmount ? new Currency(tx.principalAmount, decimals) : undefined,
interestAmount: tx.interestAmount ? new Currency(tx.interestAmount, decimals) : undefined,
realizedProfitFifo: tx.realizedProfitFifo ? new Currency(tx.realizedProfitFifo, decimals) : undefined,
sumRealizedProfitFifo: tx.asset.sumRealizedProfitFifo
? new Currency(tx.asset.sumRealizedProfitFifo, decimals)
: undefined,
unrealizedProfitAtMarketPrice: day.asset.unrealizedProfitAtMarketPrice
? new Currency(day.asset.unrealizedProfitAtMarketPrice, decimals)
unrealizedProfitAtMarketPrice: tx.asset.unrealizedProfitAtMarketPrice
? new Currency(tx.asset.unrealizedProfitAtMarketPrice, decimals)
: undefined,
timestamp: new Date(`${day.timestamp}+00:00`),
timestamp: new Date(`${tx.timestamp}+00:00`),
}
}) || ([] satisfies AssetTransaction[])
)
Expand Down
72 changes: 72 additions & 0 deletions src/queries/poolFeeTransactions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Currency } from '../utils/BigInt.js'

export type PoolFeeTransactionFilter = Partial<
Record<keyof SubqueryPoolFeeTransaction['poolFeeTransactions']['nodes'][0], any>
>

export type PoolFeeTransaction = {
feeId: string
type: string
timestamp: string
blockNumber: string
epochNumber: number
amount: Currency
}

export type SubqueryPoolFeeTransaction = {
poolFeeTransactions: {
nodes: {
id: string
type: string
timestamp: string
blockNumber: string
epochNumber: number
amount: string
poolFee: {
feeId: string
pool: {
currency: {
decimals: number
}
}
}
}[]
}
}

export function poolFeeTransactionPostProcess(data: SubqueryPoolFeeTransaction): PoolFeeTransaction[] {
return data.poolFeeTransactions.nodes.map((tx) => ({
feeId: tx.id,
type: tx.type,
timestamp: tx.timestamp,
blockNumber: tx.blockNumber,
epochNumber: tx.epochNumber,
amount: new Currency(tx.amount, tx.poolFee.pool.currency.decimals),
}))
}

export const poolFeeTransactionQuery = `
query($filter: PoolFeeTransactionFilter) {
poolFeeTransactions(
orderBy: TIMESTAMP_ASC,
filter: $filter
) {
nodes {
id
type
timestamp
blockNumber
epochNumber
amount
poolFee {
feeId
pool {
currency {
decimals
}
}
}
}
}
}
`
20 changes: 20 additions & 0 deletions src/tests/mocks/mockPoolFeeTransactions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Currency } from '../../utils/BigInt.js'

export const mockFeeTransactions = [
{
feeId: 'fee-1',
type: 'ACCRUED',
timestamp: '2024-01-01T00:00:00Z',
blockNumber: '1',
epochNumber: 1,
amount: new Currency(1000000n, 6),
},
{
feeId: 'fee-2',
type: 'PAID',
timestamp: '2024-01-02T00:00:00Z',
blockNumber: '2',
epochNumber: 2,
amount: new Currency(2000000n, 6),
},
]

0 comments on commit ebaf007

Please sign in to comment.