@centrifuge/sdk 0.55.2 → 0.55.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/entities/BalanceSheet.js +3 -3
- package/dist/entities/BalanceSheet.js.map +1 -1
- package/dist/entities/IndexerQueries/assetSnapshots.d.ts +69 -0
- package/dist/entities/IndexerQueries/assetSnapshots.d.ts.map +1 -0
- package/dist/entities/IndexerQueries/assetSnapshots.js +91 -0
- package/dist/entities/IndexerQueries/assetSnapshots.js.map +1 -0
- package/dist/entities/IndexerQueries/assetTransactions.d.ts +93 -0
- package/dist/entities/IndexerQueries/assetTransactions.d.ts.map +1 -0
- package/dist/entities/IndexerQueries/assetTransactions.js +75 -0
- package/dist/entities/IndexerQueries/assetTransactions.js.map +1 -0
- package/dist/entities/IndexerQueries/epochs.d.ts +45 -0
- package/dist/entities/IndexerQueries/epochs.d.ts.map +1 -0
- package/dist/entities/IndexerQueries/epochs.js +51 -0
- package/dist/entities/IndexerQueries/epochs.js.map +1 -0
- package/dist/entities/IndexerQueries/index.d.ts +40 -0
- package/dist/entities/IndexerQueries/index.d.ts.map +1 -0
- package/dist/entities/IndexerQueries/index.js +45 -0
- package/dist/entities/IndexerQueries/index.js.map +1 -0
- package/dist/entities/IndexerQueries/investorTransactions.d.ts +50 -0
- package/dist/entities/IndexerQueries/investorTransactions.d.ts.map +1 -0
- package/dist/entities/IndexerQueries/investorTransactions.js +55 -0
- package/dist/entities/IndexerQueries/investorTransactions.js.map +1 -0
- package/dist/entities/IndexerQueries/poolFeeSnapshots.d.ts +48 -0
- package/dist/entities/IndexerQueries/poolFeeSnapshots.d.ts.map +1 -0
- package/dist/entities/IndexerQueries/poolFeeSnapshots.js +62 -0
- package/dist/entities/IndexerQueries/poolFeeSnapshots.js.map +1 -0
- package/dist/entities/IndexerQueries/poolFeeTransactions.d.ts +34 -0
- package/dist/entities/IndexerQueries/poolFeeTransactions.d.ts.map +1 -0
- package/dist/entities/IndexerQueries/poolFeeTransactions.js +37 -0
- package/dist/entities/IndexerQueries/poolFeeTransactions.js.map +1 -0
- package/dist/entities/IndexerQueries/poolSnapshots.d.ts +79 -0
- package/dist/entities/IndexerQueries/poolSnapshots.d.ts.map +1 -0
- package/dist/entities/IndexerQueries/poolSnapshots.js +112 -0
- package/dist/entities/IndexerQueries/poolSnapshots.js.map +1 -0
- package/dist/entities/IndexerQueries/trancheCurrencyBalance.d.ts +76 -0
- package/dist/entities/IndexerQueries/trancheCurrencyBalance.d.ts.map +1 -0
- package/dist/entities/IndexerQueries/trancheCurrencyBalance.js +63 -0
- package/dist/entities/IndexerQueries/trancheCurrencyBalance.js.map +1 -0
- package/dist/entities/IndexerQueries/trancheSnapshots.d.ts +70 -0
- package/dist/entities/IndexerQueries/trancheSnapshots.d.ts.map +1 -0
- package/dist/entities/IndexerQueries/trancheSnapshots.js +76 -0
- package/dist/entities/IndexerQueries/trancheSnapshots.js.map +1 -0
- package/dist/entities/Reports/Processor.d.ts +46 -0
- package/dist/entities/Reports/Processor.d.ts.map +1 -0
- package/dist/entities/Reports/Processor.js +471 -0
- package/dist/entities/Reports/Processor.js.map +1 -0
- package/dist/entities/Reports/Processor.test.d.ts +2 -0
- package/dist/entities/Reports/Processor.test.d.ts.map +1 -0
- package/dist/entities/Reports/Processor.test.js +767 -0
- package/dist/entities/Reports/Processor.test.js.map +1 -0
- package/dist/entities/Reports/Reports.test.d.ts +2 -0
- package/dist/entities/Reports/Reports.test.d.ts.map +1 -0
- package/dist/entities/Reports/Reports.test.js +559 -0
- package/dist/entities/Reports/Reports.test.js.map +1 -0
- package/dist/entities/Reports/index.d.ts +21 -0
- package/dist/entities/Reports/index.d.ts.map +1 -0
- package/dist/entities/Reports/index.js +144 -0
- package/dist/entities/Reports/index.js.map +1 -0
- package/dist/tests/mocks/mockAssetSnapshots.d.ts +3 -0
- package/dist/tests/mocks/mockAssetSnapshots.d.ts.map +1 -0
- package/dist/tests/mocks/mockAssetSnapshots.js +56 -0
- package/dist/tests/mocks/mockAssetSnapshots.js.map +1 -0
- package/dist/tests/mocks/mockAssetTransactions.d.ts +3 -0
- package/dist/tests/mocks/mockAssetTransactions.d.ts.map +1 -0
- package/dist/tests/mocks/mockAssetTransactions.js +86 -0
- package/dist/tests/mocks/mockAssetTransactions.js.map +1 -0
- package/dist/tests/mocks/mockEpochs.d.ts +3 -0
- package/dist/tests/mocks/mockEpochs.d.ts.map +1 -0
- package/dist/tests/mocks/mockEpochs.js +26 -0
- package/dist/tests/mocks/mockEpochs.js.map +1 -0
- package/dist/tests/mocks/mockInvestorCurrencyBalance.d.ts +3 -0
- package/dist/tests/mocks/mockInvestorCurrencyBalance.d.ts.map +1 -0
- package/dist/tests/mocks/mockInvestorCurrencyBalance.js +29 -0
- package/dist/tests/mocks/mockInvestorCurrencyBalance.js.map +1 -0
- package/dist/tests/mocks/mockInvestorTransactions.d.ts +3 -0
- package/dist/tests/mocks/mockInvestorTransactions.d.ts.map +1 -0
- package/dist/tests/mocks/mockInvestorTransactions.js +35 -0
- package/dist/tests/mocks/mockInvestorTransactions.js.map +1 -0
- package/dist/tests/mocks/mockPoolFeeSnapshot.d.ts +3 -0
- package/dist/tests/mocks/mockPoolFeeSnapshot.d.ts.map +1 -0
- package/dist/tests/mocks/mockPoolFeeSnapshot.js +68 -0
- package/dist/tests/mocks/mockPoolFeeSnapshot.js.map +1 -0
- package/dist/tests/mocks/mockPoolFeeTransactions.d.ts +11 -0
- package/dist/tests/mocks/mockPoolFeeTransactions.d.ts.map +1 -0
- package/dist/tests/mocks/mockPoolFeeTransactions.js +20 -0
- package/dist/tests/mocks/mockPoolFeeTransactions.js.map +1 -0
- package/dist/tests/mocks/mockPoolSnapshots.d.ts +3 -0
- package/dist/tests/mocks/mockPoolSnapshots.d.ts.map +1 -0
- package/dist/tests/mocks/mockPoolSnapshots.js +66 -0
- package/dist/tests/mocks/mockPoolSnapshots.js.map +1 -0
- package/dist/tests/mocks/mockTrancheSnapshots.d.ts +3 -0
- package/dist/tests/mocks/mockTrancheSnapshots.d.ts.map +1 -0
- package/dist/tests/mocks/mockTrancheSnapshots.js +112 -0
- package/dist/tests/mocks/mockTrancheSnapshots.js.map +1 -0
- package/dist/types/reports.d.ts +336 -0
- package/dist/types/reports.d.ts.map +1 -0
- package/dist/types/reports.js +2 -0
- package/dist/types/reports.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,767 @@
|
|
|
1
|
+
import { expect } from 'chai';
|
|
2
|
+
import { mockAssetSnapshots } from '../../tests/mocks/mockAssetSnapshots.js';
|
|
3
|
+
import { mockAssetTransactions } from '../../tests/mocks/mockAssetTransactions.js';
|
|
4
|
+
import { mockEpochs } from '../../tests/mocks/mockEpochs.js';
|
|
5
|
+
import { mockInvestorCurrencyBalances } from '../../tests/mocks/mockInvestorCurrencyBalance.js';
|
|
6
|
+
import { mockInvestorTransactions } from '../../tests/mocks/mockInvestorTransactions.js';
|
|
7
|
+
import { mockPoolFeeSnapshots } from '../../tests/mocks/mockPoolFeeSnapshot.js';
|
|
8
|
+
import { mockFeeTransactions } from '../../tests/mocks/mockPoolFeeTransactions.js';
|
|
9
|
+
import { mockPoolMetadata } from '../../tests/mocks/mockPoolMetadata.js';
|
|
10
|
+
import { mockPoolSnapshots } from '../../tests/mocks/mockPoolSnapshots.js';
|
|
11
|
+
import { mockTrancheSnapshots } from '../../tests/mocks/mockTrancheSnapshots.js';
|
|
12
|
+
import { Balance, Price } from '../../utils/BigInt.js';
|
|
13
|
+
import { processor } from './Processor.js';
|
|
14
|
+
describe('Processor', () => {
|
|
15
|
+
describe('balanceSheet processor', () => {
|
|
16
|
+
it('should return empty array when no pool snapshots found', () => {
|
|
17
|
+
expect(processor.balanceSheet({
|
|
18
|
+
poolSnapshots: [],
|
|
19
|
+
trancheSnapshots: {},
|
|
20
|
+
})).to.deep.equal([]);
|
|
21
|
+
});
|
|
22
|
+
it('should process pool and tranche data correctly', () => {
|
|
23
|
+
const result = processor.balanceSheet({
|
|
24
|
+
poolSnapshots: mockPoolSnapshots,
|
|
25
|
+
trancheSnapshots: mockTrancheSnapshots,
|
|
26
|
+
});
|
|
27
|
+
expect(result).to.have.lengthOf(2);
|
|
28
|
+
const report = result[0];
|
|
29
|
+
expect(report.timestamp).to.equal('2024-01-01T12:00:00Z');
|
|
30
|
+
expect(report.assetValuation.toBigInt()).to.equal(0n);
|
|
31
|
+
expect(report.onchainReserve.toBigInt()).to.equal(0n);
|
|
32
|
+
expect(report.offchainCash.toBigInt()).to.equal(0n);
|
|
33
|
+
expect(report.accruedFees.toBigInt()).to.equal(0n);
|
|
34
|
+
expect(report.netAssetValue.toBigInt()).to.equal(0n);
|
|
35
|
+
expect(report.tranches.length).to.equal(2);
|
|
36
|
+
const seniorTranche = report.tranches.find((t) => t.tokenId === 'senior');
|
|
37
|
+
const juniorTranche = report.tranches.find((t) => t.tokenId === 'junior');
|
|
38
|
+
expect(seniorTranche?.tokenPrice.toBigInt()).to.equal(1000000000000000000n);
|
|
39
|
+
expect(juniorTranche?.tokenPrice.toBigInt()).to.equal(1120000000000000000n);
|
|
40
|
+
expect(report.totalCapital?.toBigInt()).to.equal(0n);
|
|
41
|
+
});
|
|
42
|
+
it('should group data by day when specified', () => {
|
|
43
|
+
const result = processor.balanceSheet({
|
|
44
|
+
poolSnapshots: mockPoolSnapshots,
|
|
45
|
+
trancheSnapshots: mockTrancheSnapshots,
|
|
46
|
+
}, { groupBy: 'day' });
|
|
47
|
+
expect(result).to.have.lengthOf(2);
|
|
48
|
+
expect(result?.[0]?.timestamp.slice(0, 10)).to.equal('2024-01-01');
|
|
49
|
+
expect(result?.[1]?.timestamp.slice(0, 10)).to.equal('2024-01-02');
|
|
50
|
+
});
|
|
51
|
+
it('should group data by month when specified', () => {
|
|
52
|
+
const result = processor.balanceSheet({
|
|
53
|
+
poolSnapshots: mockPoolSnapshots,
|
|
54
|
+
trancheSnapshots: mockTrancheSnapshots,
|
|
55
|
+
}, { groupBy: 'month' });
|
|
56
|
+
expect(result).to.have.lengthOf(1);
|
|
57
|
+
expect(result?.[0]?.timestamp.slice(0, 10)).to.equal('2024-01-02');
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
describe('cashflow processor', () => {
|
|
61
|
+
const mockCashflowPoolSnapshots = [
|
|
62
|
+
{
|
|
63
|
+
...mockPoolSnapshots[0],
|
|
64
|
+
id: 'pool-10',
|
|
65
|
+
timestamp: '2024-01-01T12:00:00Z',
|
|
66
|
+
sumPrincipalRepaidAmountByPeriod: Balance.fromFloat(1, 6), // 1.0
|
|
67
|
+
sumInterestRepaidAmountByPeriod: Balance.fromFloat(0.05, 6), // 0.05
|
|
68
|
+
sumBorrowedAmountByPeriod: Balance.fromFloat(2, 6), // 2.0
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
...mockPoolSnapshots[0],
|
|
72
|
+
id: 'pool-11',
|
|
73
|
+
timestamp: '2024-01-01T18:00:00Z', // Same day, different time
|
|
74
|
+
sumPrincipalRepaidAmountByPeriod: Balance.fromFloat(0.5, 6), // 0.5
|
|
75
|
+
sumInterestRepaidAmountByPeriod: Balance.fromFloat(0.025, 6), // 0.025
|
|
76
|
+
sumBorrowedAmountByPeriod: Balance.fromFloat(1, 6), // 1.0
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
...mockPoolSnapshots[0],
|
|
80
|
+
id: 'pool-12',
|
|
81
|
+
timestamp: '2024-01-02T12:00:00Z', // Next day
|
|
82
|
+
sumPrincipalRepaidAmountByPeriod: Balance.fromFloat(2, 6), // 2.0
|
|
83
|
+
sumInterestRepaidAmountByPeriod: Balance.fromFloat(0.1, 6), // 0.1
|
|
84
|
+
sumBorrowedAmountByPeriod: Balance.fromFloat(4, 6), // 4.0
|
|
85
|
+
},
|
|
86
|
+
];
|
|
87
|
+
const mockCashflowFeeSnapshots = {
|
|
88
|
+
'2024-01-01': [
|
|
89
|
+
{
|
|
90
|
+
...mockPoolFeeSnapshots['2024-01-01']?.[0],
|
|
91
|
+
poolFee: { name: 'serviceFee' },
|
|
92
|
+
sumPaidAmountByPeriod: new Balance(1000000n, 6), // 1.0
|
|
93
|
+
sumAccruedAmountByPeriod: new Balance(500000n, 6), // 0.5
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
...mockPoolFeeSnapshots['2024-01-01']?.[1],
|
|
97
|
+
poolFee: { name: 'adminFee' },
|
|
98
|
+
sumPaidAmountByPeriod: new Balance(2000000n, 6), // 2.0
|
|
99
|
+
sumAccruedAmountByPeriod: new Balance(1000000n, 6), // 1.0
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
'2024-01-02': [
|
|
103
|
+
{
|
|
104
|
+
...mockPoolFeeSnapshots['2024-01-02']?.[0],
|
|
105
|
+
poolFee: { name: 'serviceFee' },
|
|
106
|
+
sumPaidAmountByPeriod: new Balance(3000000n, 6), // 3.0
|
|
107
|
+
sumAccruedAmountByPeriod: new Balance(1500000n, 6), // 1.5
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
...mockPoolFeeSnapshots['2024-01-02']?.[1],
|
|
111
|
+
poolFee: { name: 'adminFee' },
|
|
112
|
+
sumPaidAmountByPeriod: new Balance(4000000n, 6), // 4.0
|
|
113
|
+
sumAccruedAmountByPeriod: new Balance(2000000n, 6), // 2.0
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
};
|
|
117
|
+
it('should return empty array when no snapshots found', () => {
|
|
118
|
+
expect(processor.cashflow({ poolSnapshots: [], poolFeeSnapshots: {}, metadata: undefined })).to.deep.equal([]);
|
|
119
|
+
});
|
|
120
|
+
it('should throw an error if no metadata is passed', () => {
|
|
121
|
+
let thrown = false;
|
|
122
|
+
try {
|
|
123
|
+
processor.cashflow({
|
|
124
|
+
poolSnapshots: mockPoolSnapshots,
|
|
125
|
+
poolFeeSnapshots: mockPoolFeeSnapshots,
|
|
126
|
+
metadata: undefined,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
thrown = true;
|
|
131
|
+
}
|
|
132
|
+
expect(thrown).to.be.true;
|
|
133
|
+
});
|
|
134
|
+
it('should aggregate values correctly when grouping by day', () => {
|
|
135
|
+
const result = processor.cashflow({
|
|
136
|
+
poolSnapshots: mockCashflowPoolSnapshots,
|
|
137
|
+
poolFeeSnapshots: mockCashflowFeeSnapshots,
|
|
138
|
+
metadata: mockPoolMetadata,
|
|
139
|
+
}, { groupBy: 'day' });
|
|
140
|
+
expect(result).to.have.lengthOf(2);
|
|
141
|
+
const jan1 = result[0];
|
|
142
|
+
expect(jan1?.timestamp.slice(0, 10)).to.equal('2024-01-01');
|
|
143
|
+
expect(jan1?.principalPayments.toFloat()).to.equal(1.5); // 1.0 + 0.5
|
|
144
|
+
expect(jan1?.interestPayments.toFloat()).to.equal(0.075); // 0.05 + 0.025
|
|
145
|
+
expect(jan1?.subtype === 'privateCredit' ? jan1?.assetFinancing?.toFloat() : jan1?.assetPurchases?.toFloat()).to.equal(3); // 2.0 + 1.0
|
|
146
|
+
expect(jan1?.fees.length).to.equal(2);
|
|
147
|
+
expect(jan1?.fees[0]?.name).to.equal('serviceFee');
|
|
148
|
+
expect(jan1?.fees[1]?.name).to.equal('adminFee');
|
|
149
|
+
expect(jan1?.fees[0]?.amount.toFloat()).to.equal(1);
|
|
150
|
+
expect(jan1?.fees[1]?.amount.toFloat()).to.equal(2);
|
|
151
|
+
expect(jan1?.fees[0]?.timestamp.slice(0, 10)).to.equal('2024-01-01');
|
|
152
|
+
expect(jan1?.fees[1]?.timestamp.slice(0, 10)).to.equal('2024-01-01');
|
|
153
|
+
const jan2 = result[1];
|
|
154
|
+
expect(jan2?.timestamp.slice(0, 10)).to.equal('2024-01-02');
|
|
155
|
+
expect(jan2?.principalPayments.toFloat()).to.equal(2); // 2.0
|
|
156
|
+
expect(jan2?.interestPayments.toFloat()).to.equal(0.1); // 0.1
|
|
157
|
+
expect(jan2?.subtype === 'privateCredit' ? jan2?.assetFinancing?.toFloat() : jan2?.assetPurchases?.toFloat()).to.equal(4); // 4.0
|
|
158
|
+
expect(jan2?.fees.length).to.equal(2);
|
|
159
|
+
expect(jan2?.fees[0]?.name).to.equal('serviceFee');
|
|
160
|
+
expect(jan2?.fees[1]?.name).to.equal('adminFee');
|
|
161
|
+
expect(jan2?.fees[0]?.amount.toFloat()).to.equal(3);
|
|
162
|
+
expect(jan2?.fees[1]?.amount.toFloat()).to.equal(4);
|
|
163
|
+
expect(jan2?.fees[0]?.timestamp.slice(0, 10)).to.equal('2024-01-02');
|
|
164
|
+
expect(jan2?.fees[1]?.timestamp.slice(0, 10)).to.equal('2024-01-02');
|
|
165
|
+
});
|
|
166
|
+
it('should aggregate values correctly when grouping by month', () => {
|
|
167
|
+
const result = processor.cashflow({
|
|
168
|
+
poolSnapshots: mockCashflowPoolSnapshots,
|
|
169
|
+
poolFeeSnapshots: mockCashflowFeeSnapshots,
|
|
170
|
+
metadata: mockPoolMetadata,
|
|
171
|
+
}, { groupBy: 'month' });
|
|
172
|
+
expect(result).to.have.lengthOf(1);
|
|
173
|
+
const january = result[0];
|
|
174
|
+
expect(january?.timestamp.slice(0, 10)).to.equal('2024-01-02'); // Grouping by month returns the last day of the period
|
|
175
|
+
expect(january?.principalPayments.toFloat()).to.equal(3.5); // 1.0 + 0.5 + 2.0
|
|
176
|
+
expect(january?.interestPayments.toFloat()).to.equal(0.175); // 0.05 + 0.025 + 0.1
|
|
177
|
+
expect(january?.subtype === 'privateCredit' ? january?.assetFinancing?.toFloat() : january?.assetPurchases?.toFloat()).to.equal(7); // 2.0 + 1.0 + 4.0
|
|
178
|
+
expect(january?.fees.length).to.equal(2);
|
|
179
|
+
expect(january?.fees[0]?.name).to.equal('serviceFee');
|
|
180
|
+
expect(january?.fees[1]?.name).to.equal('adminFee');
|
|
181
|
+
// fees are NOT aggregated by period
|
|
182
|
+
expect(january?.fees[0]?.amount.toFloat()).to.equal(3);
|
|
183
|
+
expect(january?.fees[1]?.amount.toFloat()).to.equal(4);
|
|
184
|
+
});
|
|
185
|
+
it('should return realizedPL if pool is public credit', () => {
|
|
186
|
+
const result = processor.cashflow({
|
|
187
|
+
poolSnapshots: mockCashflowPoolSnapshots,
|
|
188
|
+
poolFeeSnapshots: mockCashflowFeeSnapshots,
|
|
189
|
+
metadata: {
|
|
190
|
+
...mockPoolMetadata,
|
|
191
|
+
pool: { ...mockPoolMetadata.pool, asset: { ...mockPoolMetadata.pool.asset, class: 'Public credit' } },
|
|
192
|
+
},
|
|
193
|
+
}, { groupBy: 'day' });
|
|
194
|
+
expect(result?.[0]).to.have.property('realizedPL');
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
describe('profit and loss processor', () => {
|
|
198
|
+
const mockPLPoolSnapshots = [
|
|
199
|
+
{
|
|
200
|
+
...mockPoolSnapshots[0],
|
|
201
|
+
id: 'pool-10',
|
|
202
|
+
timestamp: '2024-01-01T12:00:00Z',
|
|
203
|
+
sumInterestRepaidAmountByPeriod: Balance.fromFloat(0.05, 6), // 0.05
|
|
204
|
+
sumInterestAccruedByPeriod: Balance.fromFloat(0.1, 6), // 0.1
|
|
205
|
+
sumDebtWrittenOffByPeriod: Balance.fromFloat(0.02, 6), // 0.02
|
|
206
|
+
sumUnscheduledRepaidAmountByPeriod: Balance.fromFloat(0.01, 6), // 0.01
|
|
207
|
+
sumUnrealizedProfitByPeriod: Balance.fromFloat(0.15, 6), // 0.15
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
...mockPoolSnapshots[1],
|
|
211
|
+
id: 'pool-11',
|
|
212
|
+
timestamp: '2024-01-02T12:00:00Z',
|
|
213
|
+
sumInterestRepaidAmountByPeriod: Balance.fromFloat(0.1, 6),
|
|
214
|
+
sumInterestAccruedByPeriod: Balance.fromFloat(0.2, 6),
|
|
215
|
+
sumDebtWrittenOffByPeriod: Balance.fromFloat(0.03, 6),
|
|
216
|
+
sumUnscheduledRepaidAmountByPeriod: Balance.fromFloat(0.02, 6),
|
|
217
|
+
sumUnrealizedProfitByPeriod: Balance.fromFloat(0.25, 6),
|
|
218
|
+
},
|
|
219
|
+
];
|
|
220
|
+
const mockPLFeeSnapshots = {
|
|
221
|
+
'2024-01-01': [
|
|
222
|
+
{
|
|
223
|
+
poolFee: { name: 'serviceFee' },
|
|
224
|
+
sumAccruedAmountByPeriod: Balance.fromFloat(0.01, 6),
|
|
225
|
+
sumChargedAmountByPeriod: Balance.fromFloat(0.02, 6),
|
|
226
|
+
timestamp: '2024-01-01T12:00:00Z',
|
|
227
|
+
poolFeeId: 'pool-fee-1',
|
|
228
|
+
},
|
|
229
|
+
],
|
|
230
|
+
'2024-01-02': [
|
|
231
|
+
{
|
|
232
|
+
poolFee: { name: 'serviceFee' },
|
|
233
|
+
sumAccruedAmountByPeriod: Balance.fromFloat(0.02, 6),
|
|
234
|
+
sumChargedAmountByPeriod: Balance.fromFloat(0.03, 6),
|
|
235
|
+
timestamp: '2024-01-02T12:00:00Z',
|
|
236
|
+
poolFeeId: 'pool-fee-2',
|
|
237
|
+
},
|
|
238
|
+
],
|
|
239
|
+
};
|
|
240
|
+
it('should return empty array when no snapshots found', () => {
|
|
241
|
+
expect(processor.profitAndLoss({ poolSnapshots: [], poolFeeSnapshots: {}, metadata: undefined })).to.deep.equal([]);
|
|
242
|
+
});
|
|
243
|
+
it('should handle undefined metadata', () => {
|
|
244
|
+
let thrown = false;
|
|
245
|
+
try {
|
|
246
|
+
processor.profitAndLoss({
|
|
247
|
+
poolSnapshots: mockPLPoolSnapshots,
|
|
248
|
+
poolFeeSnapshots: mockPLFeeSnapshots,
|
|
249
|
+
metadata: undefined,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
catch {
|
|
253
|
+
thrown = true;
|
|
254
|
+
}
|
|
255
|
+
expect(thrown).to.be.true;
|
|
256
|
+
});
|
|
257
|
+
it('should process private credit pool data correctly', () => {
|
|
258
|
+
const result = processor.profitAndLoss({
|
|
259
|
+
poolSnapshots: mockPLPoolSnapshots,
|
|
260
|
+
poolFeeSnapshots: mockPLFeeSnapshots,
|
|
261
|
+
metadata: mockPoolMetadata, // defaults to private credit
|
|
262
|
+
});
|
|
263
|
+
expect(result).to.have.lengthOf(2);
|
|
264
|
+
const firstDay = result[0];
|
|
265
|
+
expect(firstDay?.subtype).to.equal('privateCredit');
|
|
266
|
+
expect(firstDay).to.have.property('interestAccrued');
|
|
267
|
+
expect(firstDay).to.have.property('assetWriteOffs');
|
|
268
|
+
expect(firstDay?.interestAccrued.toFloat()).to.equal(0.1);
|
|
269
|
+
expect(firstDay?.assetWriteOffs.toFloat()).to.equal(0.02);
|
|
270
|
+
expect(firstDay?.interestPayments.toFloat()).to.equal(0.05);
|
|
271
|
+
expect(firstDay?.otherPayments.toFloat()).to.equal(0.01);
|
|
272
|
+
expect(firstDay?.profitAndLossFromAsset.toFloat()).to.equal(0.16); // 0.05 + 0.1 + 0.02 - 0.01
|
|
273
|
+
});
|
|
274
|
+
it('should process public credit pool correctly', () => {
|
|
275
|
+
const result = processor.profitAndLoss({
|
|
276
|
+
poolSnapshots: mockPLPoolSnapshots,
|
|
277
|
+
poolFeeSnapshots: mockPLFeeSnapshots,
|
|
278
|
+
metadata: {
|
|
279
|
+
...mockPoolMetadata,
|
|
280
|
+
pool: {
|
|
281
|
+
...mockPoolMetadata.pool,
|
|
282
|
+
asset: { ...mockPoolMetadata.pool.asset, class: 'Public credit' },
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
});
|
|
286
|
+
expect(result).to.have.lengthOf(2);
|
|
287
|
+
const firstDay = result[0];
|
|
288
|
+
expect(firstDay?.subtype).to.equal('publicCredit');
|
|
289
|
+
expect(firstDay?.profitAndLossFromAsset.toFloat()).to.equal(0.15); // unrealized profit
|
|
290
|
+
expect(firstDay?.interestPayments.toFloat()).to.equal(0.05);
|
|
291
|
+
expect(firstDay?.otherPayments.toFloat()).to.equal(0.01);
|
|
292
|
+
expect(firstDay).to.have.property('totalIncome');
|
|
293
|
+
expect(firstDay?.totalIncome.toFloat()).to.equal(0.21); // 0.15 + 0.05 + 0.01
|
|
294
|
+
});
|
|
295
|
+
it('should aggregate values correctly when grouping by month', () => {
|
|
296
|
+
const result = processor.profitAndLoss({
|
|
297
|
+
poolSnapshots: mockPLPoolSnapshots,
|
|
298
|
+
poolFeeSnapshots: mockPLFeeSnapshots,
|
|
299
|
+
metadata: mockPoolMetadata,
|
|
300
|
+
}, { groupBy: 'month' });
|
|
301
|
+
expect(result).to.have.lengthOf(1);
|
|
302
|
+
const january = result[0];
|
|
303
|
+
expect(january?.timestamp.slice(0, 10)).to.equal('2024-01-02');
|
|
304
|
+
expect(january?.interestPayments.toFloat()).to.equal(0.15); // 0.05 + 0.1
|
|
305
|
+
expect(january?.otherPayments.toFloat()).to.equal(0.03); // 0.01 + 0.02
|
|
306
|
+
});
|
|
307
|
+
it('should make sure timestamp for pool state and pool fee match', () => {
|
|
308
|
+
const result = processor.profitAndLoss({
|
|
309
|
+
poolSnapshots: mockPLPoolSnapshots,
|
|
310
|
+
poolFeeSnapshots: mockPLFeeSnapshots,
|
|
311
|
+
metadata: mockPoolMetadata,
|
|
312
|
+
});
|
|
313
|
+
expect(result[0]?.timestamp.slice(0, 10)).to.equal('2024-01-01');
|
|
314
|
+
expect(result[0]?.fees?.[0]?.timestamp.slice(0, 10)).to.equal('2024-01-01');
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
describe('investor transactions processor', () => {
|
|
318
|
+
it('should return empty array when no transactions found', () => {
|
|
319
|
+
expect(processor.investorTransactions({ investorTransactions: [] })).to.deep.equal([]);
|
|
320
|
+
});
|
|
321
|
+
it('should process investor transactions correctly without filters', () => {
|
|
322
|
+
const result = processor.investorTransactions({
|
|
323
|
+
investorTransactions: mockInvestorTransactions,
|
|
324
|
+
});
|
|
325
|
+
expect(result).to.have.lengthOf(2);
|
|
326
|
+
const firstTx = result[0];
|
|
327
|
+
expect(firstTx?.timestamp.slice(0, 10)).to.equal('2024-01-01');
|
|
328
|
+
expect(firstTx?.chainId).to.equal(1);
|
|
329
|
+
expect(firstTx?.account).to.equal('0x123a');
|
|
330
|
+
expect(firstTx?.epoch).to.equal('1');
|
|
331
|
+
expect(firstTx?.transactionType).to.equal('INVEST_ORDER_UPDATE');
|
|
332
|
+
expect(firstTx?.currencyAmount.toFloat()).to.equal(1.0);
|
|
333
|
+
expect(firstTx?.trancheTokenAmount.toFloat()).to.equal(0.9);
|
|
334
|
+
expect(firstTx?.price.toString()).to.equal('1100000000000000000');
|
|
335
|
+
expect(firstTx?.transactionHash).to.equal('0xabc');
|
|
336
|
+
});
|
|
337
|
+
it('should filter by tokenId', () => {
|
|
338
|
+
const mockInvestorTransactionsWithJunior = [
|
|
339
|
+
...mockInvestorTransactions,
|
|
340
|
+
{
|
|
341
|
+
...mockInvestorTransactions[0],
|
|
342
|
+
trancheId: 'junior',
|
|
343
|
+
},
|
|
344
|
+
];
|
|
345
|
+
const result = processor.investorTransactions({
|
|
346
|
+
investorTransactions: mockInvestorTransactionsWithJunior,
|
|
347
|
+
}, { tokenId: 'senior' });
|
|
348
|
+
expect(result).to.have.lengthOf(2);
|
|
349
|
+
expect(result[0]?.trancheTokenId).to.equal('senior');
|
|
350
|
+
});
|
|
351
|
+
it('should filter by address', () => {
|
|
352
|
+
const result = processor.investorTransactions({
|
|
353
|
+
investorTransactions: mockInvestorTransactions,
|
|
354
|
+
}, { address: '0x123a' });
|
|
355
|
+
expect(result).to.have.lengthOf(1);
|
|
356
|
+
expect(result[0]?.account).to.equal('0x123a');
|
|
357
|
+
});
|
|
358
|
+
it('should filter by network', () => {
|
|
359
|
+
const mockInvestorTransactionsWithNetwork = [
|
|
360
|
+
...mockInvestorTransactions,
|
|
361
|
+
{
|
|
362
|
+
...mockInvestorTransactions[0],
|
|
363
|
+
chainId: 2,
|
|
364
|
+
},
|
|
365
|
+
];
|
|
366
|
+
const result = processor.investorTransactions({
|
|
367
|
+
investorTransactions: mockInvestorTransactionsWithNetwork,
|
|
368
|
+
}, { network: 2 });
|
|
369
|
+
expect(result).to.have.lengthOf(1);
|
|
370
|
+
expect(result[0]?.chainId).to.equal(2);
|
|
371
|
+
});
|
|
372
|
+
it('should filter by all networks', () => {
|
|
373
|
+
const result = processor.investorTransactions({
|
|
374
|
+
investorTransactions: mockInvestorTransactions,
|
|
375
|
+
}, { network: 'all' });
|
|
376
|
+
expect(result).to.have.lengthOf(2);
|
|
377
|
+
});
|
|
378
|
+
it('should filter by centrifuge network', () => {
|
|
379
|
+
const mockInvestorTransactionsWithCentrifuge = [
|
|
380
|
+
...mockInvestorTransactions,
|
|
381
|
+
{
|
|
382
|
+
...mockInvestorTransactions[0],
|
|
383
|
+
chainId: 'centrifuge',
|
|
384
|
+
},
|
|
385
|
+
];
|
|
386
|
+
const result = processor.investorTransactions({
|
|
387
|
+
investorTransactions: mockInvestorTransactionsWithCentrifuge,
|
|
388
|
+
}, { network: 'centrifuge' });
|
|
389
|
+
expect(result).to.have.lengthOf(1);
|
|
390
|
+
expect(result[0]?.chainId).to.equal('centrifuge');
|
|
391
|
+
});
|
|
392
|
+
it('should filter by transaction type', () => {
|
|
393
|
+
const result = processor.investorTransactions({
|
|
394
|
+
investorTransactions: mockInvestorTransactions,
|
|
395
|
+
}, { transactionType: 'orders' });
|
|
396
|
+
expect(result).to.have.lengthOf(1);
|
|
397
|
+
expect(result[0]?.transactionType).to.equal('INVEST_ORDER_UPDATE');
|
|
398
|
+
});
|
|
399
|
+
it('should filter by network and transaction type', () => {
|
|
400
|
+
const mockInvestorTransactionsWithNetworkAndOrders = [
|
|
401
|
+
...mockInvestorTransactions,
|
|
402
|
+
{
|
|
403
|
+
...mockInvestorTransactions[0],
|
|
404
|
+
chainId: 2,
|
|
405
|
+
},
|
|
406
|
+
];
|
|
407
|
+
const result = processor.investorTransactions({
|
|
408
|
+
investorTransactions: mockInvestorTransactionsWithNetworkAndOrders,
|
|
409
|
+
}, { network: 1, transactionType: 'orders' });
|
|
410
|
+
expect(result).to.have.lengthOf(1);
|
|
411
|
+
expect(result[0]?.chainId).to.equal(1);
|
|
412
|
+
expect(result[0]?.transactionType).to.equal('INVEST_ORDER_UPDATE');
|
|
413
|
+
});
|
|
414
|
+
it('should return an empty array when no filters match', () => {
|
|
415
|
+
const result = processor.investorTransactions({
|
|
416
|
+
investorTransactions: mockInvestorTransactions,
|
|
417
|
+
}, { network: 2, transactionType: 'executions' });
|
|
418
|
+
expect(result).to.deep.equal([]);
|
|
419
|
+
});
|
|
420
|
+
});
|
|
421
|
+
describe('asset transactions processor', () => {
|
|
422
|
+
it('should return empty array when no transactions found', () => {
|
|
423
|
+
expect(processor.assetTransactions({ assetTransactions: [] })).to.deep.equal([]);
|
|
424
|
+
});
|
|
425
|
+
it('should process asset transactions correctly without filters', () => {
|
|
426
|
+
const result = processor.assetTransactions({
|
|
427
|
+
assetTransactions: mockAssetTransactions,
|
|
428
|
+
});
|
|
429
|
+
expect(result).to.have.lengthOf(3);
|
|
430
|
+
});
|
|
431
|
+
it('should filter by assetId', () => {
|
|
432
|
+
const result = processor.assetTransactions({
|
|
433
|
+
assetTransactions: mockAssetTransactions,
|
|
434
|
+
}, { assetId: '1' });
|
|
435
|
+
expect(result).to.have.lengthOf(2);
|
|
436
|
+
});
|
|
437
|
+
it('should filter by transaction type', () => {
|
|
438
|
+
const types = [
|
|
439
|
+
{ type: 'created', expected: 0 },
|
|
440
|
+
{ type: 'financed', expected: 1 },
|
|
441
|
+
{ type: 'repaid', expected: 1 },
|
|
442
|
+
{ type: 'priced', expected: 0 },
|
|
443
|
+
{ type: 'closed', expected: 0 },
|
|
444
|
+
{ type: 'cashTransfer', expected: 1 },
|
|
445
|
+
];
|
|
446
|
+
for (const { type, expected } of types) {
|
|
447
|
+
const result = processor.assetTransactions({
|
|
448
|
+
assetTransactions: mockAssetTransactions,
|
|
449
|
+
}, { transactionType: type });
|
|
450
|
+
expect(result).to.have.lengthOf(expected);
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
it('should make sure all the fields exist', () => {
|
|
454
|
+
const result = processor.assetTransactions({ assetTransactions: mockAssetTransactions });
|
|
455
|
+
expect(result).to.have.lengthOf(3);
|
|
456
|
+
expect(result[0]).to.have.property('type');
|
|
457
|
+
expect(result[0]).to.have.property('timestamp');
|
|
458
|
+
expect(result[0]).to.have.property('assetId');
|
|
459
|
+
expect(result[0]).to.have.property('transactionType');
|
|
460
|
+
expect(result[0]).to.have.property('amount');
|
|
461
|
+
expect(result[0]).to.have.property('epoch');
|
|
462
|
+
expect(result[0]).to.have.property('transactionHash');
|
|
463
|
+
expect(result[0]).to.have.property('fromAsset'); // optional
|
|
464
|
+
expect(result[1]).to.have.property('toAsset'); // optional
|
|
465
|
+
});
|
|
466
|
+
});
|
|
467
|
+
describe('fee transactions processor', () => {
|
|
468
|
+
it('should return empty array when no transactions found', () => {
|
|
469
|
+
expect(processor.feeTransactions({ poolFeeTransactions: [] })).to.deep.equal([]);
|
|
470
|
+
});
|
|
471
|
+
it('should process fee transactions correctly', () => {
|
|
472
|
+
const result = processor.feeTransactions({ poolFeeTransactions: mockFeeTransactions });
|
|
473
|
+
expect(result).to.have.lengthOf(2);
|
|
474
|
+
});
|
|
475
|
+
it('should filter by transaction type all', () => {
|
|
476
|
+
const result = processor.feeTransactions({ poolFeeTransactions: mockFeeTransactions }, { transactionType: 'all' });
|
|
477
|
+
expect(result).to.have.lengthOf(2);
|
|
478
|
+
});
|
|
479
|
+
it('should filter by transaction type accrued', () => {
|
|
480
|
+
const result = processor.feeTransactions({ poolFeeTransactions: mockFeeTransactions }, { transactionType: 'accrued' });
|
|
481
|
+
expect(result).to.have.lengthOf(1);
|
|
482
|
+
});
|
|
483
|
+
it('should filter by transaction type paid', () => {
|
|
484
|
+
const result = processor.feeTransactions({ poolFeeTransactions: mockFeeTransactions }, { transactionType: 'paid' });
|
|
485
|
+
expect(result).to.have.lengthOf(1);
|
|
486
|
+
});
|
|
487
|
+
it('should return an empty array when no filters match', () => {
|
|
488
|
+
const result = processor.feeTransactions({ poolFeeTransactions: mockFeeTransactions }, { transactionType: 'directChargeMade' });
|
|
489
|
+
expect(result).to.deep.equal([]);
|
|
490
|
+
});
|
|
491
|
+
});
|
|
492
|
+
describe('token price processor', () => {
|
|
493
|
+
it('should return empty array when no snapshots found', () => {
|
|
494
|
+
expect(processor.tokenPrice({ trancheSnapshots: {} })).to.deep.equal([]);
|
|
495
|
+
});
|
|
496
|
+
it('should process token price correctly', () => {
|
|
497
|
+
const result = processor.tokenPrice({ trancheSnapshots: mockTrancheSnapshots });
|
|
498
|
+
expect(result).to.have.lengthOf(2);
|
|
499
|
+
expect(result[0]?.tranches[0]?.price?.toDecimal().toString()).to.equal('1');
|
|
500
|
+
expect(result[0]?.tranches[0]?.id).to.equal('senior');
|
|
501
|
+
});
|
|
502
|
+
it('should group by month', () => {
|
|
503
|
+
const result = processor.tokenPrice({ trancheSnapshots: mockTrancheSnapshots }, { groupBy: 'month' });
|
|
504
|
+
expect(result).to.have.lengthOf(1);
|
|
505
|
+
});
|
|
506
|
+
it('should make sure all fields are present', () => {
|
|
507
|
+
const result = processor.tokenPrice({ trancheSnapshots: mockTrancheSnapshots }, { groupBy: 'day' });
|
|
508
|
+
expect(result).to.have.lengthOf(2);
|
|
509
|
+
expect(result[0]).to.have.property('tranches');
|
|
510
|
+
expect(result[0]).to.have.property('timestamp');
|
|
511
|
+
expect(result[0]?.tranches[0]).to.have.property('id');
|
|
512
|
+
expect(result[0]?.tranches[0]).to.have.property('yieldMTD');
|
|
513
|
+
expect(result[0]?.tranches[0]).to.have.property('yieldQTD');
|
|
514
|
+
expect(result[0]?.tranches[0]).to.have.property('yieldYTD');
|
|
515
|
+
expect(result[0]?.tranches[0]).to.have.property('yield7daysAnnualized');
|
|
516
|
+
expect(result[0]?.tranches[0]).to.have.property('yield30daysAnnualized');
|
|
517
|
+
expect(result[0]?.tranches[0]).to.have.property('yield90daysAnnualized');
|
|
518
|
+
expect(result[0]?.tranches[0]).to.have.property('timestamp');
|
|
519
|
+
expect(result[0]?.tranches[0]).to.have.property('supply');
|
|
520
|
+
expect(result[0]?.tranches[0]).to.have.property('price');
|
|
521
|
+
});
|
|
522
|
+
});
|
|
523
|
+
describe('asset list processor', () => {
|
|
524
|
+
it('should return empty array when no snapshots found', () => {
|
|
525
|
+
expect(processor.assetList({ assetSnapshots: [], metadata: undefined })).to.deep.equal([]);
|
|
526
|
+
});
|
|
527
|
+
it('should throw an error if no metadata is passed', () => {
|
|
528
|
+
let thrown = false;
|
|
529
|
+
try {
|
|
530
|
+
processor.assetList({ assetSnapshots: mockAssetSnapshots, metadata: undefined });
|
|
531
|
+
}
|
|
532
|
+
catch {
|
|
533
|
+
thrown = true;
|
|
534
|
+
}
|
|
535
|
+
expect(thrown).to.be.true;
|
|
536
|
+
});
|
|
537
|
+
it('should process asset list correctly', () => {
|
|
538
|
+
const result = processor.assetList({ assetSnapshots: mockAssetSnapshots, metadata: mockPoolMetadata });
|
|
539
|
+
expect(result).to.have.lengthOf(2);
|
|
540
|
+
});
|
|
541
|
+
it('should filter by status ongoing', () => {
|
|
542
|
+
const result = processor.assetList({ assetSnapshots: mockAssetSnapshots, metadata: mockPoolMetadata }, { status: 'ongoing' });
|
|
543
|
+
expect(result).to.have.lengthOf(2);
|
|
544
|
+
});
|
|
545
|
+
it('should filter by status repaid', () => {
|
|
546
|
+
const result = processor.assetList({ assetSnapshots: mockAssetSnapshots, metadata: mockPoolMetadata }, { status: 'repaid' });
|
|
547
|
+
expect(result).to.have.lengthOf(0);
|
|
548
|
+
});
|
|
549
|
+
it('should filter by status overdue', () => {
|
|
550
|
+
const mockAssetSnapshotsOverdue = [
|
|
551
|
+
...mockAssetSnapshots,
|
|
552
|
+
{ ...mockAssetSnapshots[0], actualMaturityDate: '2023-01-01' },
|
|
553
|
+
];
|
|
554
|
+
const result = processor.assetList({ assetSnapshots: mockAssetSnapshotsOverdue, metadata: mockPoolMetadata }, { status: 'overdue' });
|
|
555
|
+
expect(result).to.have.lengthOf(1);
|
|
556
|
+
});
|
|
557
|
+
it('should return the correct data for private credit pools', () => {
|
|
558
|
+
const result = processor.assetList({ assetSnapshots: mockAssetSnapshots, metadata: mockPoolMetadata }, { status: 'ongoing' });
|
|
559
|
+
expect(result).to.have.lengthOf(2);
|
|
560
|
+
expect(result?.[0]).to.have.property('outstandingPrincipal');
|
|
561
|
+
expect(result?.[0]).to.have.property('outstandingInterest');
|
|
562
|
+
expect(result?.[0]).to.have.property('repaidPrincipal');
|
|
563
|
+
expect(result?.[0]).to.have.property('repaidInterest');
|
|
564
|
+
expect(result?.[0]).to.have.property('repaidUnscheduled');
|
|
565
|
+
expect(result?.[0]).to.have.property('originationDate');
|
|
566
|
+
expect(result?.[0]).to.have.property('maturityDate');
|
|
567
|
+
expect(result?.[0]).to.have.property('valuationMethod');
|
|
568
|
+
expect(result?.[0]).to.have.property('advanceRate');
|
|
569
|
+
expect(result?.[0]).to.have.property('collateralValue');
|
|
570
|
+
expect(result?.[0]).to.have.property('probabilityOfDefault');
|
|
571
|
+
expect(result?.[0]).to.have.property('lossGivenDefault');
|
|
572
|
+
expect(result?.[0]).to.have.property('discountRate');
|
|
573
|
+
expect(result?.[0]).to.have.property('name');
|
|
574
|
+
});
|
|
575
|
+
it('should return the correct data for public credit pools', () => {
|
|
576
|
+
const result = processor.assetList({
|
|
577
|
+
assetSnapshots: mockAssetSnapshots,
|
|
578
|
+
metadata: {
|
|
579
|
+
...mockPoolMetadata,
|
|
580
|
+
pool: { ...mockPoolMetadata.pool, asset: { ...mockPoolMetadata.pool.asset, class: 'Public credit' } },
|
|
581
|
+
},
|
|
582
|
+
}, { status: 'ongoing' });
|
|
583
|
+
expect(result).to.have.lengthOf(2);
|
|
584
|
+
expect(result?.[0]).to.have.property('faceValue');
|
|
585
|
+
expect(result?.[0]).to.have.property('outstandingQuantity');
|
|
586
|
+
expect(result?.[0]).to.have.property('currentPrice');
|
|
587
|
+
expect(result?.[0]).to.have.property('unrealizedProfit');
|
|
588
|
+
expect(result?.[0]).to.have.property('realizedProfit');
|
|
589
|
+
expect(result?.[0]).to.have.property('name');
|
|
590
|
+
});
|
|
591
|
+
});
|
|
592
|
+
describe('investor list processor', () => {
|
|
593
|
+
it('should return empty array when no balances found', () => {
|
|
594
|
+
expect(processor.investorList({ trancheCurrencyBalance: [] })).to.deep.equal([]);
|
|
595
|
+
});
|
|
596
|
+
it('should filter by network', () => {
|
|
597
|
+
const result = processor.investorList({ trancheCurrencyBalance: mockInvestorCurrencyBalances }, { network: 1 });
|
|
598
|
+
expect(result).to.have.lengthOf(1);
|
|
599
|
+
});
|
|
600
|
+
it('should filter by centrifuge network', () => {
|
|
601
|
+
const result = processor.investorList({ trancheCurrencyBalance: mockInvestorCurrencyBalances }, { network: 'centrifuge' });
|
|
602
|
+
expect(result).to.have.lengthOf(1);
|
|
603
|
+
});
|
|
604
|
+
it('should filter by address', () => {
|
|
605
|
+
const result = processor.investorList({ trancheCurrencyBalance: mockInvestorCurrencyBalances }, { address: '0x123' });
|
|
606
|
+
expect(result).to.have.lengthOf(1);
|
|
607
|
+
});
|
|
608
|
+
it('should filter by trancheId', () => {
|
|
609
|
+
const result = processor.investorList({ trancheCurrencyBalance: mockInvestorCurrencyBalances }, { trancheId: 'tranche-1' });
|
|
610
|
+
expect(result).to.have.lengthOf(2);
|
|
611
|
+
const result2 = processor.investorList({ trancheCurrencyBalance: mockInvestorCurrencyBalances }, { trancheId: 'tranche-2' });
|
|
612
|
+
expect(result2).to.have.lengthOf(0);
|
|
613
|
+
});
|
|
614
|
+
it('should make sure all the fields exist', () => {
|
|
615
|
+
const result = processor.investorList({ trancheCurrencyBalance: mockInvestorCurrencyBalances });
|
|
616
|
+
expect(result).to.have.lengthOf(2);
|
|
617
|
+
expect(result[0]).to.have.property('type');
|
|
618
|
+
expect(result[0]).to.have.property('chainId');
|
|
619
|
+
expect(result[0]).to.have.property('accountId');
|
|
620
|
+
expect(result[0]).to.have.property('evmAddress');
|
|
621
|
+
expect(result[0]).to.have.property('position');
|
|
622
|
+
expect(result[0]).to.have.property('poolPercentage');
|
|
623
|
+
expect(result[0]).to.have.property('pendingInvest');
|
|
624
|
+
expect(result[0]).to.have.property('pendingRedeem');
|
|
625
|
+
expect(result[0]).to.have.property('trancheId');
|
|
626
|
+
});
|
|
627
|
+
});
|
|
628
|
+
describe('orders list processor', () => {
|
|
629
|
+
it('should return empty array when no epochs found', () => {
|
|
630
|
+
expect(processor.ordersList({ poolEpochs: [] })).to.deep.equal([]);
|
|
631
|
+
});
|
|
632
|
+
it('should process orders list correctly', () => {
|
|
633
|
+
const result = processor.ordersList({ poolEpochs: mockEpochs });
|
|
634
|
+
expect(result).to.have.lengthOf(2);
|
|
635
|
+
expect(result[0]?.epoch).to.equal('1');
|
|
636
|
+
expect(result[0]?.netAssetValue.toString()).to.equal(Balance.fromFloat(1000, 6).toString());
|
|
637
|
+
expect(result[0]?.navPerShare.toString()).to.equal(new Price(1000000000000000000n).toString());
|
|
638
|
+
expect(result[0]?.lockedInvestments.toString()).to.equal(Balance.fromFloat(1000, 6).toString());
|
|
639
|
+
expect(result[0]?.lockedRedemptions.toString()).to.equal(Balance.fromFloat(100, 6).toString());
|
|
640
|
+
expect(result[0]?.executedInvestments.toString()).to.equal(Balance.fromFloat(900, 6).toString());
|
|
641
|
+
expect(result[0]?.executedRedemptions.toString()).to.equal(Balance.fromFloat(90, 6).toString());
|
|
642
|
+
expect(result[0]?.paidFees.toString()).to.equal(Balance.fromFloat(100, 6).toString());
|
|
643
|
+
});
|
|
644
|
+
});
|
|
645
|
+
describe('asset time series processor', () => {
|
|
646
|
+
it('should return empty array when no snapshots found', () => {
|
|
647
|
+
expect(processor.assetTimeSeries({ assetSnapshots: [] })).to.deep.equal([]);
|
|
648
|
+
});
|
|
649
|
+
it('should process asset time series correctly', () => {
|
|
650
|
+
const result = processor.assetTimeSeries({ assetSnapshots: mockAssetSnapshots });
|
|
651
|
+
expect(result).to.have.lengthOf(2);
|
|
652
|
+
expect(result[0]?.assetId).to.equal('1');
|
|
653
|
+
expect(result[0]?.currentPrice.toString()).to.equal(Balance.fromFloat(1, 6).toString());
|
|
654
|
+
});
|
|
655
|
+
});
|
|
656
|
+
describe('applyGrouping', () => {
|
|
657
|
+
const applyGrouping = processor['applyGrouping'];
|
|
658
|
+
const mockData = [
|
|
659
|
+
{ a: Balance.fromFloat(10, 6), timestamp: '2024-01-01' },
|
|
660
|
+
{ a: Balance.fromFloat(20, 6), timestamp: '2024-01-01' },
|
|
661
|
+
];
|
|
662
|
+
it('should return empty array when no items found', () => {
|
|
663
|
+
expect(applyGrouping([], 'day', 'sum')).to.deep.equal([]);
|
|
664
|
+
});
|
|
665
|
+
it('should return items by day when no grouping is specified', () => {
|
|
666
|
+
const latest = applyGrouping(mockData, undefined, 'latest');
|
|
667
|
+
expect(latest).to.deep.equal([{ a: Balance.fromFloat(20, 6), timestamp: '2024-01-01' }]);
|
|
668
|
+
const summed = applyGrouping(mockData, undefined, 'sum');
|
|
669
|
+
expect(summed).to.deep.equal([{ a: Balance.fromFloat(30, 6), timestamp: '2024-01-01' }]);
|
|
670
|
+
});
|
|
671
|
+
it('should return latest item when strategy is latest', () => {
|
|
672
|
+
const grouped = applyGrouping(mockData, 'day', 'latest');
|
|
673
|
+
expect(grouped).to.deep.equal([{ a: Balance.fromFloat(20, 6), timestamp: '2024-01-01' }]);
|
|
674
|
+
});
|
|
675
|
+
it('should aggregate values when strategy is sum', () => {
|
|
676
|
+
const grouped = applyGrouping(mockData, 'day', 'sum');
|
|
677
|
+
expect(grouped).to.deep.equal([{ a: Balance.fromFloat(30, 6), timestamp: '2024-01-01' }]);
|
|
678
|
+
});
|
|
679
|
+
it('should return latest item when strategy is latest and no grouping is specified', () => {
|
|
680
|
+
const grouped = applyGrouping(mockData, undefined, 'latest');
|
|
681
|
+
expect(grouped).to.deep.equal([{ a: Balance.fromFloat(20, 6), timestamp: '2024-01-01' }]);
|
|
682
|
+
});
|
|
683
|
+
it('should aggregate values when strategy is sum and no grouping is specified', () => {
|
|
684
|
+
const grouped = applyGrouping(mockData, undefined, 'sum');
|
|
685
|
+
expect(grouped).to.deep.equal([{ a: Balance.fromFloat(30, 6), timestamp: '2024-01-01' }]);
|
|
686
|
+
});
|
|
687
|
+
it('should return latest item when strategy is latest and grouping is month', () => {
|
|
688
|
+
const extendedMockData = [...mockData, { a: Balance.fromFloat(30, 6), timestamp: '2024-02-01' }];
|
|
689
|
+
const grouped = applyGrouping(extendedMockData, 'month', 'latest');
|
|
690
|
+
const expected = [
|
|
691
|
+
{ a: Balance.fromFloat(20, 6), timestamp: '2024-01-01' },
|
|
692
|
+
{ a: Balance.fromFloat(30, 6), timestamp: '2024-02-01' },
|
|
693
|
+
];
|
|
694
|
+
expect(grouped).to.deep.equal(expected);
|
|
695
|
+
});
|
|
696
|
+
it('should aggregate values when strategy is sum and grouping is month (Token)', () => {
|
|
697
|
+
const extendedMockData = [
|
|
698
|
+
{ a: Balance.fromFloat(10, 6), timestamp: '2024-01-01' },
|
|
699
|
+
{ a: Balance.fromFloat(20, 6), timestamp: '2024-01-02' },
|
|
700
|
+
{ a: Balance.fromFloat(30, 6), timestamp: '2024-02-01' },
|
|
701
|
+
];
|
|
702
|
+
const grouped = applyGrouping(extendedMockData, 'month', 'sum');
|
|
703
|
+
const expected = [
|
|
704
|
+
{ a: Balance.fromFloat(30, 6), timestamp: '2024-01-02' },
|
|
705
|
+
{ a: Balance.fromFloat(30, 6), timestamp: '2024-02-01' },
|
|
706
|
+
];
|
|
707
|
+
expect(grouped).to.deep.equal(expected);
|
|
708
|
+
});
|
|
709
|
+
it('should aggregate values when strategy is sum and grouping is month (Price)', () => {
|
|
710
|
+
const extendedMockData = [
|
|
711
|
+
{ a: Price.fromFloat(10), timestamp: '2024-01-01' },
|
|
712
|
+
{ a: Price.fromFloat(20), timestamp: '2024-01-02' },
|
|
713
|
+
{ a: Price.fromFloat(30), timestamp: '2024-02-01' },
|
|
714
|
+
];
|
|
715
|
+
const grouped = applyGrouping(extendedMockData, 'month', 'sum');
|
|
716
|
+
const expected = [
|
|
717
|
+
{ a: Price.fromFloat(30), timestamp: '2024-01-02' },
|
|
718
|
+
{ a: Price.fromFloat(30), timestamp: '2024-02-01' },
|
|
719
|
+
];
|
|
720
|
+
expect(grouped).to.deep.equal(expected);
|
|
721
|
+
});
|
|
722
|
+
it('should only aggregate top-level Currency values and use last value for nested objects', () => {
|
|
723
|
+
const items = [
|
|
724
|
+
{
|
|
725
|
+
timestamp: '2024-01-01T12:00:00Z',
|
|
726
|
+
topLevelAmount: Balance.fromFloat(1, 6), // should be summed
|
|
727
|
+
nested: {
|
|
728
|
+
amount: Balance.fromFloat(1, 6), // should take last value
|
|
729
|
+
description: 'first',
|
|
730
|
+
},
|
|
731
|
+
fees: [
|
|
732
|
+
{
|
|
733
|
+
amount: Balance.fromFloat(0.5, 6), // should take last value
|
|
734
|
+
name: 'fee1',
|
|
735
|
+
},
|
|
736
|
+
],
|
|
737
|
+
},
|
|
738
|
+
{
|
|
739
|
+
timestamp: '2024-01-01T18:00:00Z',
|
|
740
|
+
topLevelAmount: Balance.fromFloat(2, 6),
|
|
741
|
+
nested: {
|
|
742
|
+
amount: Balance.fromFloat(3, 6),
|
|
743
|
+
description: 'second',
|
|
744
|
+
},
|
|
745
|
+
fees: [
|
|
746
|
+
{
|
|
747
|
+
amount: Balance.fromFloat(0.7, 6),
|
|
748
|
+
name: 'fee1',
|
|
749
|
+
},
|
|
750
|
+
],
|
|
751
|
+
},
|
|
752
|
+
];
|
|
753
|
+
const result = processor['applyGrouping'](items, 'day', 'sum');
|
|
754
|
+
expect(result).to.have.lengthOf(1);
|
|
755
|
+
const aggregated = result[0];
|
|
756
|
+
// Top level Currency should be summed
|
|
757
|
+
expect(aggregated?.topLevelAmount.toFloat()).to.equal(3); // 1 + 2
|
|
758
|
+
// Nested Currency should be from last item
|
|
759
|
+
expect(aggregated?.nested?.amount.toFloat()).to.equal(3); // last value only
|
|
760
|
+
expect(aggregated?.nested?.description).to.equal('second');
|
|
761
|
+
// Array of objects with Currency should be from last item
|
|
762
|
+
expect(aggregated?.fees[0]?.amount.toFloat()).to.equal(0.7);
|
|
763
|
+
expect(aggregated?.fees[0]?.name).to.equal('fee1');
|
|
764
|
+
});
|
|
765
|
+
});
|
|
766
|
+
});
|
|
767
|
+
//# sourceMappingURL=Processor.test.js.map
|