zo-sdk 0.1.21 → 0.1.23
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/abstract/BaseDataAPI.d.cts +2 -2
- package/dist/abstract/BaseDataAPI.d.cts.map +1 -1
- package/dist/abstract/BaseDataAPI.d.mts +2 -2
- package/dist/abstract/BaseDataAPI.d.mts.map +1 -1
- package/dist/consts/deployments-zbtcvc-mainnet.json +180 -0
- package/dist/consts/index.cjs +27 -20
- package/dist/consts/index.cjs.map +1 -1
- package/dist/consts/index.d.cts +5 -17
- package/dist/consts/index.d.cts.map +1 -1
- package/dist/consts/index.d.mts +5 -17
- package/dist/consts/index.d.mts.map +1 -1
- package/dist/consts/index.mjs +26 -19
- package/dist/consts/index.mjs.map +1 -1
- package/dist/factory/SDKFactory.cjs +36 -0
- package/dist/factory/SDKFactory.cjs.map +1 -1
- package/dist/factory/SDKFactory.d.cts +11 -1
- package/dist/factory/SDKFactory.d.cts.map +1 -1
- package/dist/factory/SDKFactory.d.mts +11 -1
- package/dist/factory/SDKFactory.d.mts.map +1 -1
- package/dist/factory/SDKFactory.mjs +36 -0
- package/dist/factory/SDKFactory.mjs.map +1 -1
- package/dist/implementations/SLPDataAPI.cjs +54 -32
- package/dist/implementations/SLPDataAPI.cjs.map +1 -1
- package/dist/implementations/SLPDataAPI.d.cts +2 -2
- package/dist/implementations/SLPDataAPI.d.cts.map +1 -1
- package/dist/implementations/SLPDataAPI.d.mts +2 -2
- package/dist/implementations/SLPDataAPI.d.mts.map +1 -1
- package/dist/implementations/SLPDataAPI.mjs +54 -32
- package/dist/implementations/SLPDataAPI.mjs.map +1 -1
- package/dist/implementations/USDZAPI.cjs +1 -1
- package/dist/implementations/USDZAPI.cjs.map +1 -1
- package/dist/implementations/USDZAPI.d.cts +1 -1
- package/dist/implementations/USDZAPI.d.cts.map +1 -1
- package/dist/implementations/USDZAPI.d.mts +1 -1
- package/dist/implementations/USDZAPI.d.mts.map +1 -1
- package/dist/implementations/USDZAPI.mjs +1 -1
- package/dist/implementations/USDZAPI.mjs.map +1 -1
- package/dist/implementations/ZBTCVCAPI.cjs +984 -0
- package/dist/implementations/ZBTCVCAPI.cjs.map +1 -0
- package/dist/implementations/ZBTCVCAPI.d.cts +133 -0
- package/dist/implementations/ZBTCVCAPI.d.cts.map +1 -0
- package/dist/implementations/ZBTCVCAPI.d.mts +133 -0
- package/dist/implementations/ZBTCVCAPI.d.mts.map +1 -0
- package/dist/implementations/ZBTCVCAPI.mjs +980 -0
- package/dist/implementations/ZBTCVCAPI.mjs.map +1 -0
- package/dist/implementations/ZBTCVCDataAPI.cjs +824 -0
- package/dist/implementations/ZBTCVCDataAPI.cjs.map +1 -0
- package/dist/implementations/ZBTCVCDataAPI.d.cts +94 -0
- package/dist/implementations/ZBTCVCDataAPI.d.cts.map +1 -0
- package/dist/implementations/ZBTCVCDataAPI.d.mts +94 -0
- package/dist/implementations/ZBTCVCDataAPI.d.mts.map +1 -0
- package/dist/implementations/ZBTCVCDataAPI.mjs +820 -0
- package/dist/implementations/ZBTCVCDataAPI.mjs.map +1 -0
- package/dist/implementations/index.cjs +5 -1
- package/dist/implementations/index.cjs.map +1 -1
- package/dist/implementations/index.d.cts +2 -0
- package/dist/implementations/index.d.cts.map +1 -1
- package/dist/implementations/index.d.mts +2 -0
- package/dist/implementations/index.d.mts.map +1 -1
- package/dist/implementations/index.mjs +2 -0
- package/dist/implementations/index.mjs.map +1 -1
- package/dist/interfaces/base.d.cts +2 -2
- package/dist/interfaces/base.d.cts.map +1 -1
- package/dist/interfaces/base.d.mts +2 -2
- package/dist/interfaces/base.d.mts.map +1 -1
- package/dist/interfaces/index.cjs +2 -0
- package/dist/interfaces/index.cjs.map +1 -1
- package/dist/interfaces/index.d.cts +2 -0
- package/dist/interfaces/index.d.cts.map +1 -1
- package/dist/interfaces/index.d.mts +2 -0
- package/dist/interfaces/index.d.mts.map +1 -1
- package/dist/interfaces/index.mjs +2 -0
- package/dist/interfaces/index.mjs.map +1 -1
- package/dist/interfaces/zbtcvc.cjs +7 -0
- package/dist/interfaces/zbtcvc.cjs.map +1 -0
- package/dist/interfaces/zbtcvc.d.cts +64 -0
- package/dist/interfaces/zbtcvc.d.cts.map +1 -0
- package/dist/interfaces/zbtcvc.d.mts +64 -0
- package/dist/interfaces/zbtcvc.d.mts.map +1 -0
- package/dist/interfaces/zbtcvc.mjs +6 -0
- package/dist/interfaces/zbtcvc.mjs.map +1 -0
- package/package.json +8 -8
- package/src/abstract/BaseDataAPI.ts +2 -2
- package/src/consts/deployments-zbtcvc-mainnet.json +180 -0
- package/src/consts/index.ts +28 -35
- package/src/factory/SDKFactory.ts +50 -0
- package/src/implementations/SLPDataAPI.ts +71 -41
- package/src/implementations/USDZAPI.ts +1 -1
- package/src/implementations/ZBTCVCAPI.ts +1453 -0
- package/src/implementations/ZBTCVCDataAPI.ts +985 -0
- package/src/implementations/index.ts +2 -0
- package/src/interfaces/base.ts +2 -2
- package/src/interfaces/index.ts +8 -0
- package/src/interfaces/zbtcvc.ts +115 -0
|
@@ -0,0 +1,824 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* eslint-disable no-await-in-loop */
|
|
3
|
+
/**
|
|
4
|
+
* ZBTCVC DataAPI implementation
|
|
5
|
+
* Implements ZBTCVC-specific data access methods
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.ZBTCVCDataAPI = void 0;
|
|
9
|
+
const utils_1 = require("@mysten/sui/utils");
|
|
10
|
+
const abstract_1 = require("../abstract/index.cjs");
|
|
11
|
+
const consts_1 = require("../consts/index.cjs");
|
|
12
|
+
const utils_2 = require("../utils.cjs");
|
|
13
|
+
class ZBTCVCDataAPI extends abstract_1.BaseDataAPI {
|
|
14
|
+
constructor(network, provider, apiEndpoint, connectionURL) {
|
|
15
|
+
super(network, provider, apiEndpoint, connectionURL, consts_1.LPToken.ZBTCVC);
|
|
16
|
+
}
|
|
17
|
+
async getStaked(owner) {
|
|
18
|
+
let rawCredentialsData = [];
|
|
19
|
+
let queryNextPage = true;
|
|
20
|
+
let queryCursor;
|
|
21
|
+
const limit = 50;
|
|
22
|
+
while (queryNextPage) {
|
|
23
|
+
const { data, hasNextPage, nextCursor } = await this.provider.getOwnedObjects({
|
|
24
|
+
owner,
|
|
25
|
+
filter: {
|
|
26
|
+
MoveModule: {
|
|
27
|
+
package: this.consts.zoStaking.package,
|
|
28
|
+
module: 'pool',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
options: {
|
|
32
|
+
showType: true,
|
|
33
|
+
showContent: true,
|
|
34
|
+
},
|
|
35
|
+
cursor: queryCursor,
|
|
36
|
+
limit,
|
|
37
|
+
});
|
|
38
|
+
queryNextPage = hasNextPage;
|
|
39
|
+
queryCursor = nextCursor;
|
|
40
|
+
if (!data)
|
|
41
|
+
break;
|
|
42
|
+
rawCredentialsData = [...rawCredentialsData, ...data];
|
|
43
|
+
}
|
|
44
|
+
const pool = await this.getStakePool();
|
|
45
|
+
const credentials = rawCredentialsData.map((item) => ZBTCVCDataAPI.parseCredential(item, pool));
|
|
46
|
+
return {
|
|
47
|
+
credentials,
|
|
48
|
+
amount: credentials.reduce((acc, cur) => acc + cur.amount, BigInt(0)),
|
|
49
|
+
claimable: credentials.reduce((acc, cur) => acc + cur.claimable, BigInt(0)),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
async getStakePool() {
|
|
53
|
+
const raw = await this.provider.getObject({
|
|
54
|
+
id: this.consts.zoStaking.pools[0],
|
|
55
|
+
options: {
|
|
56
|
+
showContent: true,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
return ZBTCVCDataAPI.parseStakePool(raw);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Creates vaults valuation for ZBTCVC
|
|
63
|
+
*/
|
|
64
|
+
valuateVaults(tx) {
|
|
65
|
+
const vaultsValuation = tx.moveCall({
|
|
66
|
+
target: `${this.consts.zoCore.upgradedPackage}::market::create_vaults_valuation`,
|
|
67
|
+
typeArguments: [`${this.consts.zoCore.package}::zbtcvc::ZBTCVC`],
|
|
68
|
+
arguments: [
|
|
69
|
+
tx.object(utils_1.SUI_CLOCK_OBJECT_ID),
|
|
70
|
+
tx.object(this.consts.zoCore.market),
|
|
71
|
+
],
|
|
72
|
+
});
|
|
73
|
+
for (const key of Object.keys(this.consts.zoCore.vaults)) {
|
|
74
|
+
const vault = this.consts.zoCore.vaults[key];
|
|
75
|
+
tx.moveCall({
|
|
76
|
+
target: `${this.consts.zoCore.upgradedPackage}::market::valuate_vault`,
|
|
77
|
+
typeArguments: [
|
|
78
|
+
`${this.consts.zoCore.package}::zbtcvc::ZBTCVC`,
|
|
79
|
+
this.consts.coins[key].module,
|
|
80
|
+
],
|
|
81
|
+
arguments: [
|
|
82
|
+
tx.object(this.consts.zoCore.market),
|
|
83
|
+
tx.object(vault.reservingFeeModel),
|
|
84
|
+
tx.object(this.consts.pythFeeder.feeder[key]),
|
|
85
|
+
vaultsValuation,
|
|
86
|
+
],
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return vaultsValuation;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Creates symbols valuation for ZBTCVC
|
|
93
|
+
*/
|
|
94
|
+
valuateSymbols(tx) {
|
|
95
|
+
const symbolsValuation = tx.moveCall({
|
|
96
|
+
target: `${this.consts.zoCore.upgradedPackage}::market::create_symbols_valuation`,
|
|
97
|
+
typeArguments: [`${this.consts.zoCore.package}::zbtcvc::ZBTCVC`],
|
|
98
|
+
arguments: [
|
|
99
|
+
tx.object(utils_1.SUI_CLOCK_OBJECT_ID),
|
|
100
|
+
tx.object(this.consts.zoCore.market),
|
|
101
|
+
],
|
|
102
|
+
});
|
|
103
|
+
for (const key of Object.keys(this.consts.zoCore.symbols)) {
|
|
104
|
+
const [direction, token] = (0, utils_2.parseSymbolKey)(key);
|
|
105
|
+
const symbol = this.consts.zoCore.symbols[key];
|
|
106
|
+
tx.moveCall({
|
|
107
|
+
target: `${this.consts.zoCore.upgradedPackage}::market::valuate_symbol`,
|
|
108
|
+
typeArguments: [
|
|
109
|
+
`${this.consts.zoCore.package}::zbtcvc::ZBTCVC`,
|
|
110
|
+
this.consts.coins[token].module,
|
|
111
|
+
`${this.consts.zoCore.package}::market::${direction.toUpperCase()}`,
|
|
112
|
+
],
|
|
113
|
+
arguments: [
|
|
114
|
+
tx.object(this.consts.zoCore.market),
|
|
115
|
+
tx.object(symbol.fundingFeeModel),
|
|
116
|
+
tx.object(this.consts.pythFeeder.feeder[token]),
|
|
117
|
+
symbolsValuation,
|
|
118
|
+
],
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return symbolsValuation;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Creates both vaults and symbols valuation
|
|
125
|
+
*/
|
|
126
|
+
valuate(tx) {
|
|
127
|
+
const vaultsValuation = this.valuateVaults(tx);
|
|
128
|
+
const symbolsValuation = this.valuateSymbols(tx);
|
|
129
|
+
return { vaultsValuation, symbolsValuation };
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Valuates the ZBTCVC market
|
|
133
|
+
*/
|
|
134
|
+
async valuateMarket() {
|
|
135
|
+
const marketInfo = await this.getMarketInfo();
|
|
136
|
+
const days = 7;
|
|
137
|
+
const fee = await this.getPastFee(days);
|
|
138
|
+
let zbtcvcPrice = 0;
|
|
139
|
+
let value = 0;
|
|
140
|
+
const vaultPromises = Object.keys(this.consts.zoCore.vaults).map(async (vault) => {
|
|
141
|
+
const vaultInfo = await this.getVaultInfo(vault);
|
|
142
|
+
const reservingFeeDelta = ZBTCVCDataAPI.calculateVaultReservingFee(vaultInfo, vaultInfo.reservingFeeModel, Date.now() / 1000);
|
|
143
|
+
return (reservingFeeDelta + vaultInfo.liquidity + vaultInfo.reservedAmount) * (await this.getOraclePrice(vault)).getPriceUnchecked().getPriceAsNumberUnchecked() / (10 ** this.consts.coins[vault].decimals);
|
|
144
|
+
});
|
|
145
|
+
const symbolPromises = Object.keys(this.consts.zoCore.symbols).map(async (symbol) => {
|
|
146
|
+
const [direction, tokenId] = (0, utils_2.parseSymbolKey)(symbol);
|
|
147
|
+
const symbolInfo = await this.getSymbolInfo(tokenId, direction === 'long');
|
|
148
|
+
const deltaSize = ZBTCVCDataAPI.calcDeltaSize(symbolInfo, (await this.getOraclePrice(tokenId)).getPriceUnchecked().getPriceAsNumberUnchecked());
|
|
149
|
+
const fundingFeeDelta = ZBTCVCDataAPI.calculateSymbolFundingFee(symbolInfo, symbolInfo.fundingFeeModel, (await this.getOraclePrice(tokenId)).getPriceUnchecked().getPriceAsNumberUnchecked(), marketInfo.lpSupplyWithDecimals, Date.now() / 1000);
|
|
150
|
+
return fundingFeeDelta + deltaSize;
|
|
151
|
+
});
|
|
152
|
+
const [vaultValues, symbolValues] = await Promise.all([Promise.all(vaultPromises), Promise.all(symbolPromises)]);
|
|
153
|
+
value = vaultValues.reduce((acc, curr) => acc + curr, 0);
|
|
154
|
+
value += symbolValues.reduce((acc, curr) => acc + curr, 0);
|
|
155
|
+
zbtcvcPrice = value / marketInfo.lpSupplyWithDecimals;
|
|
156
|
+
return {
|
|
157
|
+
marketCap: value,
|
|
158
|
+
price: zbtcvcPrice,
|
|
159
|
+
supply: marketInfo.lpSupplyWithDecimals,
|
|
160
|
+
apr: (fee / value) * 365 / days,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Gets ZBTCVC market information
|
|
165
|
+
*/
|
|
166
|
+
async getMarketInfo() {
|
|
167
|
+
this.validateCache();
|
|
168
|
+
if (this.marketInfoCache) {
|
|
169
|
+
return this.marketInfoCache;
|
|
170
|
+
}
|
|
171
|
+
const rawData = await this.provider.getObject({
|
|
172
|
+
id: this.consts.zoCore.market,
|
|
173
|
+
options: {
|
|
174
|
+
showContent: true,
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
return ZBTCVCDataAPI.parseMarketInfo(rawData);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Gets ZBTCVC vault information
|
|
181
|
+
*/
|
|
182
|
+
async getVaultInfo(vaultToken) {
|
|
183
|
+
this.validateCache();
|
|
184
|
+
if (this.vaultInfoCache[vaultToken]) {
|
|
185
|
+
return this.vaultInfoCache[vaultToken];
|
|
186
|
+
}
|
|
187
|
+
const rawData = await this.provider.getDynamicFieldObject({
|
|
188
|
+
parentId: this.consts.zoCore.vaultsParent,
|
|
189
|
+
name: {
|
|
190
|
+
type: `${this.consts.zoCore.package}::market::VaultName<${this.consts.coins[vaultToken].module}>`,
|
|
191
|
+
value: { dummy_field: false },
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
return await this.parseVaultInfo(rawData);
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Gets ZBTCVC symbol information
|
|
198
|
+
*/
|
|
199
|
+
async getSymbolInfo(indexToken, long) {
|
|
200
|
+
this.validateCache();
|
|
201
|
+
const symbol = (0, utils_2.joinSymbol)(long ? 'long' : 'short', indexToken);
|
|
202
|
+
if (this.symbolInfoCache[symbol]) {
|
|
203
|
+
return this.symbolInfoCache[symbol];
|
|
204
|
+
}
|
|
205
|
+
const rawData = await this.provider.getDynamicFieldObject({
|
|
206
|
+
parentId: this.consts.zoCore.symbolsParent,
|
|
207
|
+
name: {
|
|
208
|
+
type: `${this.consts.zoCore.package}::market::SymbolName<${this.consts.coins[indexToken].module}, ${this.consts.zoCore.package}::market::${long ? 'LONG' : 'SHORT'}>`,
|
|
209
|
+
value: { dummy_field: false },
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
return await this.parseSymbolInfo(rawData, long);
|
|
213
|
+
}
|
|
214
|
+
async getPositionConfig(indexToken, long) {
|
|
215
|
+
this.validateCache();
|
|
216
|
+
const symbol = (0, utils_2.joinSymbol)(long ? 'long' : 'short', indexToken);
|
|
217
|
+
if (this.positionConfigCache[symbol]) {
|
|
218
|
+
return this.positionConfigCache[symbol];
|
|
219
|
+
}
|
|
220
|
+
const rawData = await this.provider.getObject({
|
|
221
|
+
id: this.consts.zoCore.symbols[symbol].positionConfig,
|
|
222
|
+
options: {
|
|
223
|
+
showContent: true,
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
return ZBTCVCDataAPI.parsePositionConfig(rawData);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Gets ZBTCVC symbol configuration
|
|
230
|
+
*/
|
|
231
|
+
async getSymbolConfig(indexToken, long) {
|
|
232
|
+
this.validateCache();
|
|
233
|
+
try {
|
|
234
|
+
const rawData = await this.provider.getDynamicFieldObject({
|
|
235
|
+
parentId: this.consts.zoCore.market,
|
|
236
|
+
name: {
|
|
237
|
+
type: `${this.consts.zoCore.package}::market::SymbolName<${this.consts.coins[indexToken].module}, ${this.consts.zoCore.package}::market::${long ? 'LONG' : 'SHORT'}>`,
|
|
238
|
+
value: { dummy_field: false },
|
|
239
|
+
},
|
|
240
|
+
});
|
|
241
|
+
return ZBTCVCDataAPI.parseSymbolConfig(rawData);
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
// If the dynamic field doesn't exist, return null
|
|
245
|
+
console.error('Symbol Config Not Found');
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
async getPositionCapInfoList(owner) {
|
|
250
|
+
const positionCapInfoList = [];
|
|
251
|
+
let cursor;
|
|
252
|
+
let hasNextPage = true;
|
|
253
|
+
while (hasNextPage) {
|
|
254
|
+
const positionCaps = await this.provider.getOwnedObjects({
|
|
255
|
+
owner,
|
|
256
|
+
filter: {
|
|
257
|
+
MoveModule: {
|
|
258
|
+
package: this.consts.zoCore.package,
|
|
259
|
+
module: 'market',
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
options: {
|
|
263
|
+
showType: true,
|
|
264
|
+
},
|
|
265
|
+
cursor,
|
|
266
|
+
});
|
|
267
|
+
for (const positionCap of positionCaps.data) {
|
|
268
|
+
if (positionCap.data?.type?.includes('PositionCap')) {
|
|
269
|
+
positionCapInfoList.push({
|
|
270
|
+
positionCapId: positionCap.data.objectId,
|
|
271
|
+
symbol0: positionCap.data.type.split('<')[1].split(',')[0].trim(),
|
|
272
|
+
symbol1: positionCap.data.type.split('<')[1].split(',')[1].split(',')[0].trim(),
|
|
273
|
+
long: positionCap.data.type.includes('LONG'),
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
// If we don't want to fetch all pages or there are no more pages, break the loop
|
|
278
|
+
hasNextPage = positionCaps.hasNextPage;
|
|
279
|
+
cursor = positionCaps.nextCursor;
|
|
280
|
+
}
|
|
281
|
+
return positionCapInfoList;
|
|
282
|
+
}
|
|
283
|
+
async getPositionInfoList(positionCapInfoList, owner, batchSize = 10) {
|
|
284
|
+
const positionInfoList = [];
|
|
285
|
+
// Process in batches of 10
|
|
286
|
+
for (let i = 0; i < positionCapInfoList.length; i += batchSize) {
|
|
287
|
+
const batch = positionCapInfoList.slice(i, i + batchSize);
|
|
288
|
+
await Promise.all(batch.map(async (positionCapInfo) => {
|
|
289
|
+
try {
|
|
290
|
+
const positionRaw = await this.provider.getDynamicFieldObject({
|
|
291
|
+
parentId: this.consts.zoCore.positionsParent,
|
|
292
|
+
name: {
|
|
293
|
+
type: `${this.consts.zoCore.package}::market::PositionName<${positionCapInfo.symbol0}, ${positionCapInfo.symbol1}, ${this.consts.zoCore.package}::market::${positionCapInfo.long ? 'LONG' : 'SHORT'}>`,
|
|
294
|
+
value: {
|
|
295
|
+
owner,
|
|
296
|
+
id: positionCapInfo.positionCapId,
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
});
|
|
300
|
+
positionInfoList.push(await this.parsePositionInfo(positionRaw, positionCapInfo.positionCapId));
|
|
301
|
+
}
|
|
302
|
+
catch (error) {
|
|
303
|
+
// Position might have been deleted after force settlement
|
|
304
|
+
console.warn(`Failed to parse position info for position cap ID ${positionCapInfo.positionCapId}: ${error}`);
|
|
305
|
+
// Continue with next position without adding this one to the list
|
|
306
|
+
}
|
|
307
|
+
}));
|
|
308
|
+
}
|
|
309
|
+
return positionInfoList.sort((a, b) => a.openTimestamp > b.openTimestamp ? 1 : -1);
|
|
310
|
+
}
|
|
311
|
+
async getOpenPositions() {
|
|
312
|
+
let positionDynamicFields = [];
|
|
313
|
+
let _continue = true;
|
|
314
|
+
let cursor;
|
|
315
|
+
while (_continue) {
|
|
316
|
+
// data here will be a list of dynamic fields containing name and value
|
|
317
|
+
const { data, nextCursor, hasNextPage } = await this.provider.getDynamicFields({
|
|
318
|
+
parentId: this.consts.zoCore.positionsParent,
|
|
319
|
+
cursor,
|
|
320
|
+
});
|
|
321
|
+
positionDynamicFields = positionDynamicFields.concat(data);
|
|
322
|
+
_continue = hasNextPage;
|
|
323
|
+
cursor = nextCursor;
|
|
324
|
+
}
|
|
325
|
+
// then we query by dynamic field names and order by time
|
|
326
|
+
const positionInfoList = [];
|
|
327
|
+
await Promise.all(positionDynamicFields.map(async (positionDynamicField) => {
|
|
328
|
+
const positionRaw = await this.provider.getDynamicFieldObject({
|
|
329
|
+
parentId: this.consts.zoCore.positionsParent,
|
|
330
|
+
name: positionDynamicField.name,
|
|
331
|
+
});
|
|
332
|
+
if (positionRaw?.data?.content) {
|
|
333
|
+
const positionInfo = await this.parsePositionInfo(positionRaw, positionDynamicField.objectId);
|
|
334
|
+
if (positionInfo) {
|
|
335
|
+
positionInfoList.push(positionInfo);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}));
|
|
339
|
+
return positionInfoList
|
|
340
|
+
.filter(positionInfo => !positionInfo.closed)
|
|
341
|
+
.sort((a, b) => (a.openTimestamp > b.openTimestamp ? 1 : -1));
|
|
342
|
+
}
|
|
343
|
+
async getOrderCapInfoList(owner) {
|
|
344
|
+
const orderCapInfoList = [];
|
|
345
|
+
let cursor;
|
|
346
|
+
let hasNextPage = true;
|
|
347
|
+
while (hasNextPage) {
|
|
348
|
+
const orderCaps = await this.provider.getOwnedObjects({
|
|
349
|
+
owner,
|
|
350
|
+
filter: {
|
|
351
|
+
MoveModule: {
|
|
352
|
+
package: this.consts.zoCore.package,
|
|
353
|
+
module: 'market',
|
|
354
|
+
},
|
|
355
|
+
},
|
|
356
|
+
options: {
|
|
357
|
+
showType: true,
|
|
358
|
+
showContent: true,
|
|
359
|
+
},
|
|
360
|
+
cursor,
|
|
361
|
+
});
|
|
362
|
+
for (const orderCap of orderCaps.data) {
|
|
363
|
+
if (orderCap.data?.type?.includes('OrderCap')) {
|
|
364
|
+
orderCapInfoList.push({
|
|
365
|
+
orderCapId: orderCap.data.objectId,
|
|
366
|
+
symbol0: orderCap.data.type.split('<')[1].split(',')[0].trim(),
|
|
367
|
+
symbol1: orderCap.data.type.split('<')[1].split(',')[1].split(',')[0].trim(),
|
|
368
|
+
long: orderCap.data.type.includes('LONG'),
|
|
369
|
+
positionId: orderCap.data.content?.fields?.position_id,
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
hasNextPage = orderCaps.hasNextPage;
|
|
374
|
+
cursor = orderCaps.nextCursor;
|
|
375
|
+
}
|
|
376
|
+
return orderCapInfoList;
|
|
377
|
+
}
|
|
378
|
+
async getOrderInfoList(orderCapInfoList, owner, batchSize = 10) {
|
|
379
|
+
const orderInfoList = [];
|
|
380
|
+
// Process in batches of 10
|
|
381
|
+
for (let i = 0; i < orderCapInfoList.length; i += batchSize) {
|
|
382
|
+
const batch = orderCapInfoList.slice(i, i + batchSize);
|
|
383
|
+
await Promise.all(batch.map(async (orderCapInfo) => {
|
|
384
|
+
try {
|
|
385
|
+
const orderRaw = await this.provider.getDynamicFieldObject({
|
|
386
|
+
parentId: this.consts.zoCore.ordersParent,
|
|
387
|
+
name: {
|
|
388
|
+
// We have enforced collateral coin type to match with fee coin type so we can use symbol0 in the first slot and the last slot of the OrderName
|
|
389
|
+
type: `${this.consts.zoCore.package}::market::OrderName<${orderCapInfo.symbol0}, ${orderCapInfo.symbol1}, ${this.consts.zoCore.package}::market::${orderCapInfo.long ? 'LONG' : 'SHORT'}, ${orderCapInfo.symbol0}>`,
|
|
390
|
+
value: {
|
|
391
|
+
owner,
|
|
392
|
+
id: orderCapInfo.orderCapId,
|
|
393
|
+
position_id: {
|
|
394
|
+
vec: orderCapInfo.positionId ? [orderCapInfo.positionId] : [],
|
|
395
|
+
},
|
|
396
|
+
},
|
|
397
|
+
},
|
|
398
|
+
});
|
|
399
|
+
orderInfoList.push(this.parseOrderInfo(orderRaw, orderCapInfo.orderCapId));
|
|
400
|
+
}
|
|
401
|
+
catch (error) {
|
|
402
|
+
// Order might have been deleted
|
|
403
|
+
console.warn(`Failed to parse order info for order cap ID ${orderCapInfo.orderCapId}: ${error}`);
|
|
404
|
+
// Continue with next order without adding this one to the list
|
|
405
|
+
}
|
|
406
|
+
}));
|
|
407
|
+
}
|
|
408
|
+
return orderInfoList.sort((a, b) => a.createdAt > b.createdAt ? 1 : -1);
|
|
409
|
+
}
|
|
410
|
+
async hasReferral(referree) {
|
|
411
|
+
const raw = await this.getReferralData(referree);
|
|
412
|
+
return !raw.error;
|
|
413
|
+
}
|
|
414
|
+
async getReferralData(referree) {
|
|
415
|
+
const raw = await this.provider.getDynamicFieldObject({
|
|
416
|
+
parentId: this.consts.zoCore.referralsParent,
|
|
417
|
+
name: {
|
|
418
|
+
type: 'address',
|
|
419
|
+
value: referree,
|
|
420
|
+
},
|
|
421
|
+
});
|
|
422
|
+
return raw;
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Gets rebase fee model for ZBTCVC
|
|
426
|
+
*/
|
|
427
|
+
async getRebaseFeeModel() {
|
|
428
|
+
this.validateCache();
|
|
429
|
+
if (this.rebaseFeeModelCache) {
|
|
430
|
+
return this.rebaseFeeModelCache;
|
|
431
|
+
}
|
|
432
|
+
const rawData = await this.provider.getObject({
|
|
433
|
+
id: this.consts.zoCore.rebaseFeeModel,
|
|
434
|
+
options: {
|
|
435
|
+
showContent: true,
|
|
436
|
+
},
|
|
437
|
+
});
|
|
438
|
+
return ZBTCVCDataAPI.parseRebaseFeeModel(rawData);
|
|
439
|
+
}
|
|
440
|
+
async fundingFeeRate(indexToken, long) {
|
|
441
|
+
const symbol = await this.getSymbolInfo(indexToken, long);
|
|
442
|
+
if (symbol.lastUpdate <= 0) {
|
|
443
|
+
return 0;
|
|
444
|
+
}
|
|
445
|
+
const price = (await this.getOraclePrice(indexToken)).getPriceUnchecked().getPriceAsNumberUnchecked();
|
|
446
|
+
const lpSupplyAmount = (await this.getMarketInfo()).lpSupplyWithDecimals;
|
|
447
|
+
const model = symbol.fundingFeeModel;
|
|
448
|
+
const elapsed = consts_1.SECONDS_PER_EIGHT_HOUR;
|
|
449
|
+
const deltaSize = ZBTCVCDataAPI.calcDeltaSize(symbol, price);
|
|
450
|
+
const pnlPerLp = (symbol.realisedPnl + symbol.unrealisedFundingFeeValue + deltaSize) / lpSupplyAmount;
|
|
451
|
+
return ZBTCVCDataAPI.calcFundingFeeRate(model, pnlPerLp, elapsed);
|
|
452
|
+
}
|
|
453
|
+
async rebaseFeeRate(collateralToken, increase, amount) {
|
|
454
|
+
let vaultValue = 0;
|
|
455
|
+
if (!increase && amount > 0) {
|
|
456
|
+
amount = -amount;
|
|
457
|
+
}
|
|
458
|
+
const value = amount * (await this.getOraclePrice(collateralToken)).getPriceUnchecked().getPriceAsNumberUnchecked() / (10 ** this.consts.coins[collateralToken].decimals);
|
|
459
|
+
const vaultPromises = Object.keys(this.consts.zoCore.vaults).map(async (vault) => {
|
|
460
|
+
const vaultInfo = await this.getVaultInfo(vault);
|
|
461
|
+
const reservingFeeDelta = ZBTCVCDataAPI.calculateVaultReservingFee(vaultInfo, vaultInfo.reservingFeeModel, Date.now() / 1000);
|
|
462
|
+
const res = (reservingFeeDelta + vaultInfo.liquidity + vaultInfo.reservedAmount) * (await this.getOraclePrice(vault)).getPriceUnchecked().getPriceAsNumberUnchecked() / (10 ** this.consts.coins[vault].decimals);
|
|
463
|
+
if (collateralToken === vault) {
|
|
464
|
+
vaultValue = res;
|
|
465
|
+
}
|
|
466
|
+
return res;
|
|
467
|
+
});
|
|
468
|
+
const vaultValues = await Promise.all(vaultPromises);
|
|
469
|
+
const totalVaultValue = vaultValues.reduce((acc, curr) => acc + curr, 0);
|
|
470
|
+
const targetRatio = Number.parseInt(this.consts.zoCore.vaults[collateralToken].weight, 10) / Object.values(this.consts.zoCore.vaults)
|
|
471
|
+
.map(e => Number.parseInt(e.weight, 10))
|
|
472
|
+
.reduce((acc, curr) => acc + curr, 0);
|
|
473
|
+
return ZBTCVCDataAPI.calcRebaseFeeRate(await this.getRebaseFeeModel(), increase, (vaultValue + value) / (totalVaultValue + value), targetRatio);
|
|
474
|
+
}
|
|
475
|
+
async reservingFeeRate(collateralToken, amount = 0) {
|
|
476
|
+
const vaultInfo = await this.getVaultInfo(collateralToken);
|
|
477
|
+
const vaultSupply = vaultInfo.liquidity + vaultInfo.reservedAmount + vaultInfo.unrealisedReservingFeeAmount + amount;
|
|
478
|
+
const utilization = vaultSupply ? ((vaultInfo.reservedAmount + amount) / vaultSupply) : 0;
|
|
479
|
+
return ZBTCVCDataAPI.calcReservingFeeRate(vaultInfo.reservingFeeModel, utilization, consts_1.SECONDS_PER_EIGHT_HOUR);
|
|
480
|
+
}
|
|
481
|
+
async getHistory(trader, page, limit, orderType, symbol) {
|
|
482
|
+
const params = new URLSearchParams({
|
|
483
|
+
trader,
|
|
484
|
+
page: page.toString(),
|
|
485
|
+
limit: limit.toString(),
|
|
486
|
+
});
|
|
487
|
+
// Add filter parameters if provided
|
|
488
|
+
if (orderType && orderType !== 'all') {
|
|
489
|
+
params.append('orderType', orderType);
|
|
490
|
+
}
|
|
491
|
+
if (symbol && symbol !== 'all') {
|
|
492
|
+
params.append('symbol', symbol);
|
|
493
|
+
}
|
|
494
|
+
params.append('lpType', 'ZBTCVC');
|
|
495
|
+
const url = `${this.apiEndpoint}/traderEvents?${params}`;
|
|
496
|
+
const res = await fetch(url, {
|
|
497
|
+
method: 'GET',
|
|
498
|
+
headers: {
|
|
499
|
+
'Content-Type': 'application/json',
|
|
500
|
+
},
|
|
501
|
+
});
|
|
502
|
+
const response = await res.json();
|
|
503
|
+
return {
|
|
504
|
+
histories: response.data?.histories || [],
|
|
505
|
+
pagination: response.data?.pagination || {
|
|
506
|
+
total: 0,
|
|
507
|
+
page: 1,
|
|
508
|
+
limit: 20,
|
|
509
|
+
pages: 0,
|
|
510
|
+
},
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
// Private helper methods
|
|
514
|
+
static calcFundingFeeRate(model, pnlPerRate, elapsed) {
|
|
515
|
+
const dailyRate = Math.min(model.multiplier * Math.abs(pnlPerRate), model.max);
|
|
516
|
+
const secondsRate = dailyRate * elapsed / consts_1.SECONDS_PER_EIGHT_HOUR;
|
|
517
|
+
return pnlPerRate >= 0 ? -secondsRate : secondsRate;
|
|
518
|
+
}
|
|
519
|
+
static calcAccFundingFeeRate(symbol, model, price, lpSupplyAmount, timestamp) {
|
|
520
|
+
if (symbol.lastUpdate > 0) {
|
|
521
|
+
const elapsed = timestamp - symbol.lastUpdate;
|
|
522
|
+
if (elapsed > 0) {
|
|
523
|
+
const deltaSize = ZBTCVCDataAPI.calcDeltaSize(symbol, price);
|
|
524
|
+
const pnlPerLp = (symbol.realisedPnl + symbol.unrealisedFundingFeeValue + deltaSize) / lpSupplyAmount;
|
|
525
|
+
return symbol.accFundingRate + ZBTCVCDataAPI.calcFundingFeeRate(model, pnlPerLp, elapsed);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
return symbol.accFundingRate;
|
|
529
|
+
}
|
|
530
|
+
static calculateSymbolFundingFee(symbol, model, price, lpSupplyAmount, timestamp) {
|
|
531
|
+
const accFundingRate = ZBTCVCDataAPI.calcAccFundingFeeRate(symbol, model, price, lpSupplyAmount, timestamp);
|
|
532
|
+
return symbol.unrealisedFundingFeeValue + (accFundingRate - symbol.accFundingRate) * symbol.openingSize;
|
|
533
|
+
}
|
|
534
|
+
static calculatePositionReserveFee(position, vault, model, timestamp) {
|
|
535
|
+
const accReservingRate = ZBTCVCDataAPI.calcAccReservingFeeRate(vault, model, timestamp);
|
|
536
|
+
return position.reservingFeeAmount + (accReservingRate - vault.accReservingRate) * position.collateralAmount;
|
|
537
|
+
}
|
|
538
|
+
static calcAccReservingFeeRate(vault, model, timestamp) {
|
|
539
|
+
if (vault.lastUpdate > 0) {
|
|
540
|
+
const elapsed = timestamp - vault.lastUpdate;
|
|
541
|
+
if (elapsed > 0) {
|
|
542
|
+
const utilization = ZBTCVCDataAPI.vaultUtilization(vault);
|
|
543
|
+
return vault.accReservingRate + ZBTCVCDataAPI.calcReservingFeeRate(model, utilization, elapsed);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
return vault.accReservingRate;
|
|
547
|
+
}
|
|
548
|
+
static calcRebaseFeeRate(model, increase, ratio, targetRatio) {
|
|
549
|
+
if ((increase && ratio <= targetRatio) || (!increase && ratio >= targetRatio)) {
|
|
550
|
+
return model.base;
|
|
551
|
+
}
|
|
552
|
+
return model.base + model.multiplier * Math.abs(ratio - targetRatio);
|
|
553
|
+
}
|
|
554
|
+
static vaultUtilization(vault) {
|
|
555
|
+
const supplyAmount = vault.liquidity + vault.reservedAmount + vault.unrealisedReservingFeeAmount;
|
|
556
|
+
if (supplyAmount === 0) {
|
|
557
|
+
return 0;
|
|
558
|
+
}
|
|
559
|
+
return vault.reservedAmount / supplyAmount;
|
|
560
|
+
}
|
|
561
|
+
static calcReservingFeeRate(model, utilization, elapsed) {
|
|
562
|
+
return model.multiplier * utilization * elapsed / consts_1.SECONDS_PER_EIGHT_HOUR;
|
|
563
|
+
}
|
|
564
|
+
static calcDeltaSize(symbol, price) {
|
|
565
|
+
const latestSize = symbol.openingAmount / symbol.priceConfig.precision * price;
|
|
566
|
+
return symbol.long ? symbol.openingSize - latestSize : latestSize - symbol.openingSize;
|
|
567
|
+
}
|
|
568
|
+
static parseMarketInfo(raw) {
|
|
569
|
+
const content = raw.data.content.fields;
|
|
570
|
+
return {
|
|
571
|
+
lpSupply: content.lp_supply.fields.value,
|
|
572
|
+
positionId: content.positions.fields.id.id,
|
|
573
|
+
vaultId: content.vaults.fields.id.id,
|
|
574
|
+
symbolId: content.symbols.fields.id.id,
|
|
575
|
+
referralId: content.referrals.fields.id.id,
|
|
576
|
+
orderId: content.orders.fields.id.id,
|
|
577
|
+
rebaseFeeModel: content.rebase_fee_model,
|
|
578
|
+
lpSupplyWithDecimals: content.lp_supply.fields.value / (10 ** consts_1.ZBTCVC_TOKEN_DECIMALS),
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
async parseVaultInfo(raw) {
|
|
582
|
+
const vaultFields = raw.data.content.fields.value.fields;
|
|
583
|
+
const reservingFeeModelAddr = vaultFields.reserving_fee_model;
|
|
584
|
+
const reservingFeeModelRaw = await this.provider.getObject({
|
|
585
|
+
id: reservingFeeModelAddr,
|
|
586
|
+
options: {
|
|
587
|
+
showContent: true,
|
|
588
|
+
},
|
|
589
|
+
});
|
|
590
|
+
const reservingFeeModel = ZBTCVCDataAPI.parseReservingFeeModel(reservingFeeModelRaw);
|
|
591
|
+
return {
|
|
592
|
+
liquidity: (0, utils_2.parseValue)(vaultFields.liquidity),
|
|
593
|
+
reservedAmount: (0, utils_2.parseValue)(vaultFields.reserved_amount),
|
|
594
|
+
unrealisedReservingFeeAmount: (0, utils_2.parseValue)(vaultFields.unrealised_reserving_fee_amount),
|
|
595
|
+
accReservingRate: (0, utils_2.parseValue)(vaultFields.acc_reserving_rate),
|
|
596
|
+
enabled: vaultFields.enabled,
|
|
597
|
+
weight: (0, utils_2.parseValue)(vaultFields.weight),
|
|
598
|
+
lastUpdate: (0, utils_2.parseValue)(vaultFields.last_update),
|
|
599
|
+
reservingFeeModel,
|
|
600
|
+
priceConfig: {
|
|
601
|
+
maxInterval: (0, utils_2.parseValue)(vaultFields.price_config.fields.max_interval),
|
|
602
|
+
maxConfidence: (0, utils_2.parseValue)(vaultFields.price_config.fields.max_confidence),
|
|
603
|
+
precision: (0, utils_2.parseValue)(vaultFields.price_config.fields.precision),
|
|
604
|
+
feeder: vaultFields.price_config.fields.feeder,
|
|
605
|
+
},
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
async parseSymbolInfo(raw, long) {
|
|
609
|
+
const { objectId } = raw.data;
|
|
610
|
+
const { fields } = raw.data.content.fields.value;
|
|
611
|
+
const fundingFeeModelAddr = fields.funding_fee_model;
|
|
612
|
+
const fundingFeeModelRaw = await this.provider.getObject({
|
|
613
|
+
id: fundingFeeModelAddr,
|
|
614
|
+
options: {
|
|
615
|
+
showContent: true,
|
|
616
|
+
},
|
|
617
|
+
});
|
|
618
|
+
const fundingFeeModel = ZBTCVCDataAPI.parseFundingFeeModel(fundingFeeModelRaw);
|
|
619
|
+
return {
|
|
620
|
+
objectId,
|
|
621
|
+
openingSize: (0, utils_2.parseValue)(fields.opening_size),
|
|
622
|
+
openingAmount: (0, utils_2.parseValue)(fields.opening_amount),
|
|
623
|
+
accFundingRate: (0, utils_2.parseValue)(fields.acc_funding_rate),
|
|
624
|
+
realisedPnl: (0, utils_2.parseValue)(fields.realised_pnl),
|
|
625
|
+
unrealisedFundingFeeValue: (0, utils_2.parseValue)(fields.unrealised_funding_fee_value),
|
|
626
|
+
openEnabled: fields.open_enabled,
|
|
627
|
+
liquidateEnabled: fields.liquidate_enabled,
|
|
628
|
+
decreaseEnabled: fields.decrease_enabled,
|
|
629
|
+
lastUpdate: (0, utils_2.parseValue)(fields.last_update),
|
|
630
|
+
fundingFeeModel,
|
|
631
|
+
long,
|
|
632
|
+
priceConfig: {
|
|
633
|
+
maxInterval: (0, utils_2.parseValue)(fields.price_config.fields.max_interval),
|
|
634
|
+
maxConfidence: (0, utils_2.parseValue)(fields.price_config.fields.max_confidence),
|
|
635
|
+
precision: (0, utils_2.parseValue)(fields.price_config.fields.precision),
|
|
636
|
+
feeder: fields.price_config.fields.feeder,
|
|
637
|
+
},
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
static parsePositionConfig(raw) {
|
|
641
|
+
const positionConfigFields = raw.data.content.fields.inner.fields;
|
|
642
|
+
return {
|
|
643
|
+
decreaseFeeBps: (0, utils_2.parseValue)(positionConfigFields.decrease_fee_bps),
|
|
644
|
+
liquidationBonus: (0, utils_2.parseValue)(positionConfigFields.liquidation_bonus),
|
|
645
|
+
liquidationThreshold: (0, utils_2.parseValue)(positionConfigFields.liquidation_threshold),
|
|
646
|
+
maxLeverage: (0, utils_2.parseValue)(positionConfigFields.max_leverage),
|
|
647
|
+
minHoldingDuration: (0, utils_2.parseValue)(positionConfigFields.min_holding_duration),
|
|
648
|
+
openFeeBps: (0, utils_2.parseValue)(positionConfigFields.open_fee_bps),
|
|
649
|
+
maxReservedMultiplier: (0, utils_2.parseValue)(positionConfigFields.max_reserved_multiplier),
|
|
650
|
+
minCollateralValue: (0, utils_2.parseValue)(positionConfigFields.min_collateral_value),
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
static parseSymbolConfig(raw) {
|
|
654
|
+
const { fields } = raw.data.content;
|
|
655
|
+
return {
|
|
656
|
+
id: fields.id.id,
|
|
657
|
+
max_opening_size: (0, utils_2.parseValue)(fields.max_opening_size),
|
|
658
|
+
max_opening_size_enabled: fields.max_opening_size_enabled,
|
|
659
|
+
max_opening_size_per_position: (0, utils_2.parseValue)(fields.max_opening_size_per_position),
|
|
660
|
+
max_opening_size_per_position_enabled: fields.max_opening_size_per_position_enabled,
|
|
661
|
+
instant_exit_fee_config: {
|
|
662
|
+
instant_exit_tier_1_duration_threshold: (0, utils_2.parseValue)(fields.instant_exit_fee_config.fields.instant_exit_tier_1_duration_threshold),
|
|
663
|
+
instant_exit_tier_1_fee_bps: (0, utils_2.parseValue)(fields.instant_exit_fee_config.fields.instant_exit_tier_1_fee_bps.fields.value),
|
|
664
|
+
instant_exit_tier_1_fee_enabled: fields.instant_exit_fee_config.fields.instant_exit_tier_1_fee_enabled,
|
|
665
|
+
instant_exit_tier_2_duration_threshold: (0, utils_2.parseValue)(fields.instant_exit_fee_config.fields.instant_exit_tier_2_duration_threshold),
|
|
666
|
+
instant_exit_tier_2_fee_bps: (0, utils_2.parseValue)(fields.instant_exit_fee_config.fields.instant_exit_tier_2_fee_bps.fields.value),
|
|
667
|
+
instant_exit_tier_2_fee_enabled: fields.instant_exit_fee_config.fields.instant_exit_tier_2_fee_enabled,
|
|
668
|
+
instant_exit_tier_3_duration_threshold: (0, utils_2.parseValue)(fields.instant_exit_fee_config.fields.instant_exit_tier_3_duration_threshold),
|
|
669
|
+
instant_exit_tier_3_fee_bps: (0, utils_2.parseValue)(fields.instant_exit_fee_config.fields.instant_exit_tier_3_fee_bps.fields.value),
|
|
670
|
+
instant_exit_tier_3_fee_enabled: fields.instant_exit_fee_config.fields.instant_exit_tier_3_fee_enabled,
|
|
671
|
+
},
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
async parsePositionInfo(raw, id_) {
|
|
675
|
+
const { content } = raw.data;
|
|
676
|
+
const { fields } = content;
|
|
677
|
+
const positionFields = fields.value.fields;
|
|
678
|
+
const dataType = fields.name.type;
|
|
679
|
+
const positionInfo = {
|
|
680
|
+
id: id_,
|
|
681
|
+
long: dataType.includes('::market::LONG'),
|
|
682
|
+
owner: fields.name.fields.owner,
|
|
683
|
+
version: Number.parseInt(raw.data.version, 10),
|
|
684
|
+
collateralToken: (0, utils_2.suiSymbolToSymbol)(dataType.split('<')[1].split(',')[0].trim(), this.consts),
|
|
685
|
+
indexToken: (0, utils_2.suiSymbolToSymbol)(dataType.split(',')[1].trim(), this.consts),
|
|
686
|
+
collateralAmount: (0, utils_2.parseValue)(positionFields.collateral),
|
|
687
|
+
positionAmount: (0, utils_2.parseValue)(positionFields.position_amount),
|
|
688
|
+
reservedAmount: (0, utils_2.parseValue)(positionFields.reserved),
|
|
689
|
+
positionSize: (0, utils_2.parseValue)(positionFields.position_size),
|
|
690
|
+
lastFundingRate: (0, utils_2.parseValue)(positionFields.last_funding_rate),
|
|
691
|
+
lastReservingRate: (0, utils_2.parseValue)(positionFields.last_reserving_rate),
|
|
692
|
+
reservingFeeAmount: (0, utils_2.parseValue)(positionFields.reserving_fee_amount),
|
|
693
|
+
fundingFeeValue: (0, utils_2.parseValue)(positionFields.funding_fee_value),
|
|
694
|
+
closed: positionFields.closed,
|
|
695
|
+
openTimestamp: (0, utils_2.parseValue)(positionFields.open_timestamp),
|
|
696
|
+
};
|
|
697
|
+
positionInfo.reservingFeeAmount = ZBTCVCDataAPI.calculatePositionReserveFee(positionInfo, await this.getVaultInfo(positionInfo.collateralToken), (await this.getVaultInfo(positionInfo.collateralToken)).reservingFeeModel, Date.now() / 1000);
|
|
698
|
+
positionInfo.fundingFeeValue = ZBTCVCDataAPI.calculatePositionFundingFee(positionInfo, await this.getSymbolInfo(positionInfo.indexToken, positionInfo.long), (await this.getSymbolInfo(positionInfo.indexToken, positionInfo.long)).fundingFeeModel, (await this.getOraclePrice(positionInfo.indexToken)).getPriceUnchecked().getPriceAsNumberUnchecked(), (await this.getMarketInfo()).lpSupplyWithDecimals, Date.now() / 1000);
|
|
699
|
+
return positionInfo;
|
|
700
|
+
}
|
|
701
|
+
static calculatePositionFundingFee(position, symbol, model, price, lpSupplyAmount, timestamp) {
|
|
702
|
+
const accFundingRate = ZBTCVCDataAPI.calcAccFundingFeeRate(symbol, model, price, lpSupplyAmount, timestamp);
|
|
703
|
+
return position.fundingFeeValue + (accFundingRate - symbol.accFundingRate) * position.positionSize;
|
|
704
|
+
}
|
|
705
|
+
static parseRebaseFeeModel(raw) {
|
|
706
|
+
const { fields } = raw.data.content;
|
|
707
|
+
return {
|
|
708
|
+
base: (0, utils_2.parseValue)(fields.base),
|
|
709
|
+
multiplier: (0, utils_2.parseValue)(fields.multiplier),
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
static parseReservingFeeModel(raw) {
|
|
713
|
+
const content = raw.data.content.fields;
|
|
714
|
+
return {
|
|
715
|
+
multiplier: (0, utils_2.parseValue)(content.multiplier),
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
static parseFundingFeeModel(raw) {
|
|
719
|
+
const content = raw.data.content.fields;
|
|
720
|
+
return {
|
|
721
|
+
multiplier: (0, utils_2.parseValue)(content.multiplier),
|
|
722
|
+
max: (0, utils_2.parseValue)(content.max),
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
parseOrderInfo(raw, capId) {
|
|
726
|
+
const { content } = raw.data;
|
|
727
|
+
const { fields } = content.fields.value;
|
|
728
|
+
// Extract tokens from dataType
|
|
729
|
+
const dataType = content.type;
|
|
730
|
+
const orderType = content.fields.value.type.includes('OpenPositionOrder') ? 'OPEN_POSITION' : 'DECREASE_POSITION';
|
|
731
|
+
const ret = {
|
|
732
|
+
id: content.fields.id.id,
|
|
733
|
+
capId,
|
|
734
|
+
executed: fields.executed,
|
|
735
|
+
owner: content.fields.name.fields.owner,
|
|
736
|
+
collateralToken: (0, utils_2.suiSymbolToSymbol)(dataType.split('<')[2].split(',')[0].trim(), this.consts),
|
|
737
|
+
indexToken: (0, utils_2.suiSymbolToSymbol)(dataType.split(',')[1].trim(), this.consts),
|
|
738
|
+
feeToken: (0, utils_2.suiSymbolToSymbol)(dataType.split(',')[3].split('>')[0].trim(), this.consts),
|
|
739
|
+
indexPrice: (0, utils_2.parseValue)(fields.limited_index_price.fields.price || fields.limited_index_price),
|
|
740
|
+
collateralPriceThreshold: (0, utils_2.parseValue)(fields.collateral_price_threshold),
|
|
741
|
+
feeAmount: BigInt(fields.fee),
|
|
742
|
+
long: dataType.includes('::market::LONG'),
|
|
743
|
+
orderType,
|
|
744
|
+
createdAt: (0, utils_2.parseValue)(fields.created_at),
|
|
745
|
+
v11Order: !fields.limited_index_price.fields.price,
|
|
746
|
+
};
|
|
747
|
+
if (orderType === 'OPEN_POSITION') {
|
|
748
|
+
ret.openOrder = {
|
|
749
|
+
reserveAmount: BigInt(fields.reserve_amount),
|
|
750
|
+
collateralAmount: BigInt(fields.collateral),
|
|
751
|
+
openAmount: BigInt(fields.open_amount),
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
else {
|
|
755
|
+
ret.decreaseOrder = {
|
|
756
|
+
decreaseAmount: BigInt(fields.decrease_amount),
|
|
757
|
+
takeProfit: fields.take_profit,
|
|
758
|
+
};
|
|
759
|
+
}
|
|
760
|
+
return ret;
|
|
761
|
+
}
|
|
762
|
+
async getPastFee(days = 7) {
|
|
763
|
+
// TODO: Check with Sentio data
|
|
764
|
+
const url = `${this.apiEndpoint}/histories/proxy/fee?days=${days}`;
|
|
765
|
+
const res = await fetch(url, {
|
|
766
|
+
method: 'GET',
|
|
767
|
+
headers: {
|
|
768
|
+
'Content-Type': 'application/json',
|
|
769
|
+
},
|
|
770
|
+
});
|
|
771
|
+
return Number.parseFloat(await res.text() || '0');
|
|
772
|
+
}
|
|
773
|
+
static calculateVaultReservingFee(vaultInfo, reservingFeeModel, currentTime) {
|
|
774
|
+
const timeDelta = currentTime - vaultInfo.lastUpdate;
|
|
775
|
+
const periods = Math.floor(timeDelta / consts_1.SECONDS_PER_EIGHT_HOUR);
|
|
776
|
+
return vaultInfo.unrealisedReservingFeeAmount
|
|
777
|
+
+ (vaultInfo.reservedAmount * reservingFeeModel.multiplier * periods) / 1e18;
|
|
778
|
+
}
|
|
779
|
+
static parseCredential(raw, pool) {
|
|
780
|
+
const stakedAmount = BigInt(raw.data.content.fields.stake);
|
|
781
|
+
const accRewardPerShare = BigInt(raw.data.content.fields.acc_reward_per_share);
|
|
782
|
+
return {
|
|
783
|
+
id: raw.data.objectId,
|
|
784
|
+
lockUntil: (0, utils_2.parseValue)(raw.data.content.fields.lock_until),
|
|
785
|
+
amount: stakedAmount,
|
|
786
|
+
accRewardPerShare,
|
|
787
|
+
claimable: ((pool.accRewardPerShare - accRewardPerShare) * stakedAmount)
|
|
788
|
+
/ BigInt(1e18),
|
|
789
|
+
};
|
|
790
|
+
}
|
|
791
|
+
static parseStakePool(raw) {
|
|
792
|
+
const content = raw.data.content.fields;
|
|
793
|
+
const pool = {
|
|
794
|
+
id: content.id.id,
|
|
795
|
+
enabled: content.enabled,
|
|
796
|
+
lastUpdatedTime: (0, utils_2.parseValue)(content.last_updated_time),
|
|
797
|
+
stakedAmount: BigInt(content.staked_amount),
|
|
798
|
+
reward: BigInt(content.reward_vault),
|
|
799
|
+
startTime: (0, utils_2.parseValue)(content.start_time),
|
|
800
|
+
endTime: (0, utils_2.parseValue)(content.end_time),
|
|
801
|
+
rewardRate: BigInt(content.reward_rate),
|
|
802
|
+
accRewardPerShare: BigInt(content.acc_reward_per_share),
|
|
803
|
+
lockDuration: (0, utils_2.parseValue)(content.lock_duration),
|
|
804
|
+
};
|
|
805
|
+
ZBTCVCDataAPI.refreshPool(pool, Math.floor(Date.now() / 1000));
|
|
806
|
+
return pool;
|
|
807
|
+
}
|
|
808
|
+
static refreshPool(pool, timestamp) {
|
|
809
|
+
if (timestamp <= pool.lastUpdatedTime || timestamp < pool.startTime) {
|
|
810
|
+
return;
|
|
811
|
+
}
|
|
812
|
+
const applicableEndTime = Math.max(pool.endTime, pool.lastUpdatedTime);
|
|
813
|
+
const calculationEndTime = Math.min(timestamp, applicableEndTime);
|
|
814
|
+
if (calculationEndTime > pool.lastUpdatedTime && pool.stakedAmount > BigInt(0) && pool.rewardRate > BigInt(0)) {
|
|
815
|
+
const timeDiff = BigInt(calculationEndTime - pool.lastUpdatedTime);
|
|
816
|
+
const rewardAmount = timeDiff * pool.rewardRate;
|
|
817
|
+
const rewardPerShare = (rewardAmount * BigInt(1e18)) / pool.stakedAmount;
|
|
818
|
+
pool.accRewardPerShare += rewardPerShare;
|
|
819
|
+
}
|
|
820
|
+
pool.lastUpdatedTime = calculationEndTime;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
exports.ZBTCVCDataAPI = ZBTCVCDataAPI;
|
|
824
|
+
//# sourceMappingURL=ZBTCVCDataAPI.cjs.map
|