Skip to content

Commit 8fbae39

Browse files
committed
feat: yield+ domain model and pure utilities
1 parent 9f54af2 commit 8fbae39

20 files changed

Lines changed: 5181 additions & 0 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@venusprotocol/evm": patch
3+
---
4+
5+
add Yield+ domain models and pure utilities for position formatting, leverage calculations, and chart candle conversion
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
import type { YieldPlusPosition } from 'types';
2+
import { convertTokensToMantissa } from 'utilities';
3+
import { formatToYieldPlusPosition } from 'utilities/formatToYieldPlusPosition';
4+
import fakeAddress, { altAddress } from './address';
5+
import { poolData } from './pools';
6+
7+
type ApiYieldPlusPosition = {
8+
pnl: {
9+
realizedPnlShortAssetMantissa: string;
10+
realizedPnlUsd: string;
11+
unrealizedPnlShortAssetMantissa: string;
12+
unrealizedPnlUsd: string;
13+
unrealizedPnlPercentage: string;
14+
entryRatio: string;
15+
currentRatio: string;
16+
closeEventsWithPnlData: unknown[];
17+
totalShortOpenedMantissa: string;
18+
totalLongReceivedMantissa: string;
19+
};
20+
positionAccountAddress: string;
21+
accountAddress: string;
22+
longVTokenAddress: string;
23+
shortVTokenAddress: string;
24+
chainId: string;
25+
isActive: boolean;
26+
cycleId: string;
27+
dsaVTokenAddress: string;
28+
effectiveLeverageRatio: string;
29+
capitalUtilization: {
30+
suppliedPrincipalMantissa: string;
31+
capitalUtilizedMantissa: string;
32+
withdrawableCapitalMantissa: string;
33+
};
34+
};
35+
36+
const pool = poolData[0];
37+
const xvsAsset = pool.assets[0];
38+
const usdcAsset = pool.assets[1];
39+
const usdtAsset = pool.assets[2];
40+
const busdAsset = pool.assets[3];
41+
42+
export const apiYieldPlusPositions: ApiYieldPlusPosition[] = [
43+
{
44+
pnl: {
45+
realizedPnlShortAssetMantissa: '0',
46+
realizedPnlUsd: '0',
47+
unrealizedPnlShortAssetMantissa: '0',
48+
unrealizedPnlUsd: '0',
49+
unrealizedPnlPercentage: '0',
50+
entryRatio: '1',
51+
currentRatio: '1',
52+
closeEventsWithPnlData: [],
53+
totalShortOpenedMantissa: '0',
54+
totalLongReceivedMantissa: '0',
55+
},
56+
positionAccountAddress: fakeAddress,
57+
accountAddress: fakeAddress,
58+
longVTokenAddress: usdtAsset.vToken.address,
59+
shortVTokenAddress: busdAsset.vToken.address,
60+
chainId: String(busdAsset.vToken.underlyingToken.chainId),
61+
isActive: true,
62+
cycleId: '1',
63+
dsaVTokenAddress: xvsAsset.vToken.address,
64+
effectiveLeverageRatio: '2',
65+
capitalUtilization: {
66+
suppliedPrincipalMantissa: convertTokensToMantissa({
67+
value: xvsAsset.userSupplyBalanceTokens,
68+
token: xvsAsset.vToken.underlyingToken,
69+
}).toFixed(),
70+
capitalUtilizedMantissa: '0',
71+
withdrawableCapitalMantissa: '0',
72+
},
73+
},
74+
{
75+
positionAccountAddress: altAddress,
76+
accountAddress: altAddress,
77+
dsaVTokenAddress: usdcAsset.vToken.address,
78+
longVTokenAddress: usdtAsset.vToken.address,
79+
shortVTokenAddress: busdAsset.vToken.address,
80+
chainId: String(busdAsset.vToken.underlyingToken.chainId),
81+
isActive: true,
82+
cycleId: '1',
83+
effectiveLeverageRatio: '3',
84+
pnl: {
85+
realizedPnlShortAssetMantissa: '0',
86+
realizedPnlUsd: '0',
87+
unrealizedPnlShortAssetMantissa: '0',
88+
unrealizedPnlUsd: '1.5',
89+
unrealizedPnlPercentage: '1.2',
90+
entryRatio: '1.1',
91+
currentRatio: '1.1',
92+
closeEventsWithPnlData: [],
93+
totalShortOpenedMantissa: '0',
94+
totalLongReceivedMantissa: '0',
95+
},
96+
capitalUtilization: {
97+
suppliedPrincipalMantissa: convertTokensToMantissa({
98+
value: usdcAsset.userSupplyBalanceTokens,
99+
token: usdcAsset.vToken.underlyingToken,
100+
}).toFixed(),
101+
capitalUtilizedMantissa: '0',
102+
withdrawableCapitalMantissa: '0',
103+
},
104+
},
105+
{
106+
positionAccountAddress: altAddress,
107+
accountAddress: altAddress,
108+
dsaVTokenAddress: usdcAsset.vToken.address,
109+
longVTokenAddress: usdcAsset.vToken.address,
110+
shortVTokenAddress: usdtAsset.vToken.address,
111+
chainId: String(usdtAsset.vToken.underlyingToken.chainId),
112+
isActive: true,
113+
cycleId: '1',
114+
effectiveLeverageRatio: '1.5',
115+
pnl: {
116+
realizedPnlShortAssetMantissa: '0',
117+
realizedPnlUsd: '0',
118+
unrealizedPnlShortAssetMantissa: '0',
119+
unrealizedPnlUsd: '-0.5',
120+
unrealizedPnlPercentage: '-0.4',
121+
entryRatio: '0.95',
122+
currentRatio: '0.95',
123+
closeEventsWithPnlData: [],
124+
totalShortOpenedMantissa: '0',
125+
totalLongReceivedMantissa: '0',
126+
},
127+
capitalUtilization: {
128+
suppliedPrincipalMantissa: convertTokensToMantissa({
129+
value: usdcAsset.userSupplyBalanceTokens,
130+
token: usdcAsset.vToken.underlyingToken,
131+
}).toFixed(),
132+
capitalUtilizedMantissa: '0',
133+
withdrawableCapitalMantissa: '0',
134+
},
135+
},
136+
];
137+
138+
export const yieldPlusPositions: YieldPlusPosition[] = [
139+
formatToYieldPlusPosition({
140+
pool,
141+
chainId: busdAsset.vToken.underlyingToken.chainId,
142+
positionAccountAddress: fakeAddress,
143+
dsaVTokenAddress: xvsAsset.vToken.address,
144+
dsaBalanceMantissa: convertTokensToMantissa({
145+
value: xvsAsset.userSupplyBalanceTokens,
146+
token: xvsAsset.vToken.underlyingToken,
147+
}),
148+
longVTokenAddress: usdtAsset.vToken.address,
149+
shortVTokenAddress: busdAsset.vToken.address,
150+
leverageFactor: 2,
151+
unrealizedPnlCents: 0,
152+
unrealizedPnlPercentage: 0,
153+
})!,
154+
formatToYieldPlusPosition({
155+
pool,
156+
chainId: busdAsset.vToken.underlyingToken.chainId,
157+
positionAccountAddress: altAddress,
158+
dsaVTokenAddress: usdcAsset.vToken.address,
159+
dsaBalanceMantissa: convertTokensToMantissa({
160+
value: usdcAsset.userSupplyBalanceTokens,
161+
token: usdcAsset.vToken.underlyingToken,
162+
}),
163+
longVTokenAddress: usdtAsset.vToken.address,
164+
shortVTokenAddress: busdAsset.vToken.address,
165+
leverageFactor: 3,
166+
unrealizedPnlCents: 150,
167+
unrealizedPnlPercentage: 1.2,
168+
})!,
169+
formatToYieldPlusPosition({
170+
pool,
171+
chainId: usdtAsset.vToken.underlyingToken.chainId,
172+
positionAccountAddress: altAddress,
173+
dsaVTokenAddress: usdcAsset.vToken.address,
174+
dsaBalanceMantissa: convertTokensToMantissa({
175+
value: usdcAsset.userSupplyBalanceTokens,
176+
token: usdcAsset.vToken.underlyingToken,
177+
}),
178+
longVTokenAddress: usdcAsset.vToken.address,
179+
shortVTokenAddress: usdtAsset.vToken.address,
180+
leverageFactor: 1.5,
181+
unrealizedPnlCents: -50,
182+
unrealizedPnlPercentage: -0.4,
183+
})!,
184+
];

apps/evm/src/libs/translations/translations/en.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2189,5 +2189,10 @@
21892189
"submitButton": "Withdraw"
21902190
},
21912191
"withdrawTabTitle": "Withdraw"
2192+
},
2193+
"yieldPlus": {
2194+
"operationForm": {
2195+
"invalidLiquidationPrice": "N/A"
2196+
}
21922197
}
21932198
}

apps/evm/src/libs/translations/translations/ja.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2188,5 +2188,10 @@
21882188
"submitButton": "引き出す"
21892189
},
21902190
"withdrawTabTitle": "引き出す"
2191+
},
2192+
"yieldPlus": {
2193+
"operationForm": {
2194+
"invalidLiquidationPrice": "該当なし"
2195+
}
21912196
}
21922197
}

apps/evm/src/libs/translations/translations/th.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2188,5 +2188,10 @@
21882188
"submitButton": "ถอน"
21892189
},
21902190
"withdrawTabTitle": "ถอน"
2191+
},
2192+
"yieldPlus": {
2193+
"operationForm": {
2194+
"invalidLiquidationPrice": "ไม่มี"
2195+
}
21912196
}
21922197
}

apps/evm/src/libs/translations/translations/tr.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2189,5 +2189,10 @@
21892189
"submitButton": "Çek"
21902190
},
21912191
"withdrawTabTitle": "Çek"
2192+
},
2193+
"yieldPlus": {
2194+
"operationForm": {
2195+
"invalidLiquidationPrice": "Yok"
2196+
}
21922197
}
21932198
}

apps/evm/src/libs/translations/translations/vi.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2188,5 +2188,10 @@
21882188
"submitButton": "Rút"
21892189
},
21902190
"withdrawTabTitle": "Rút"
2191+
},
2192+
"yieldPlus": {
2193+
"operationForm": {
2194+
"invalidLiquidationPrice": "Không áp dụng"
2195+
}
21912196
}
21922197
}

apps/evm/src/libs/translations/translations/zh-Hans.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2188,5 +2188,10 @@
21882188
"submitButton": "取款"
21892189
},
21902190
"withdrawTabTitle": "取款"
2191+
},
2192+
"yieldPlus": {
2193+
"operationForm": {
2194+
"invalidLiquidationPrice": "不适用"
2195+
}
21912196
}
21922197
}

apps/evm/src/libs/translations/translations/zh-Hant.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2188,5 +2188,10 @@
21882188
"submitButton": "提取"
21892189
},
21902190
"withdrawTabTitle": "提取"
2191+
},
2192+
"yieldPlus": {
2193+
"operationForm": {
2194+
"invalidLiquidationPrice": "不適用"
2195+
}
21912196
}
21922197
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { calculateMaxLeverageFactor } from '..';
2+
3+
describe('calculateMaxLeverageFactor', () => {
4+
it('returns the leverage factor derived from the collateral factors and close tolerance', () => {
5+
const result = calculateMaxLeverageFactor({
6+
dsaTokenCollateralFactor: 0.5,
7+
longTokenCollateralFactor: 0.8,
8+
proportionalCloseTolerancePercentage: 2,
9+
});
10+
11+
expect(result).toMatchInlineSnapshot('2.31');
12+
});
13+
14+
it('rounds down to two decimal places', () => {
15+
const result = calculateMaxLeverageFactor({
16+
dsaTokenCollateralFactor: 0.1,
17+
longTokenCollateralFactor: 0.7,
18+
proportionalCloseTolerancePercentage: 0,
19+
});
20+
21+
expect(result).toMatchInlineSnapshot('0.33');
22+
});
23+
24+
it('reduces the maximum leverage when proportional close tolerance increases', () => {
25+
const lowToleranceResult = calculateMaxLeverageFactor({
26+
dsaTokenCollateralFactor: 0.5,
27+
longTokenCollateralFactor: 0.8,
28+
proportionalCloseTolerancePercentage: 2,
29+
});
30+
const highToleranceResult = calculateMaxLeverageFactor({
31+
dsaTokenCollateralFactor: 0.5,
32+
longTokenCollateralFactor: 0.8,
33+
proportionalCloseTolerancePercentage: 10,
34+
});
35+
36+
expect(lowToleranceResult).toMatchInlineSnapshot('2.31');
37+
expect(highToleranceResult).toMatchInlineSnapshot('1.78');
38+
});
39+
});

0 commit comments

Comments
 (0)