@affluent-org/sdk 0.0.1
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/.prettierrc +11 -0
- package/Refactoring.md +548 -0
- package/dist/_compiled/Account.compiled.json +1 -0
- package/dist/_compiled/Receipt.compiled.json +1 -0
- package/dist/_compiled/WTONWallet.compiled.json +1 -0
- package/dist/_compiled/index.d.ts +4 -0
- package/dist/_compiled/index.js +12 -0
- package/dist/affluent.d.ts +14 -0
- package/dist/affluent.js +20 -0
- package/dist/constants/constants.d.ts +2 -0
- package/dist/constants/constants.js +5 -0
- package/dist/constants/contracts.d.ts +9 -0
- package/dist/constants/contracts.js +18 -0
- package/dist/context.d.ts +43 -0
- package/dist/context.js +90 -0
- package/dist/contracts/common/type.d.ts +16 -0
- package/dist/contracts/common/type.js +2 -0
- package/dist/contracts/common/utils.d.ts +3 -0
- package/dist/contracts/common/utils.js +16 -0
- package/dist/contracts/core/account/index.d.ts +38 -0
- package/dist/contracts/core/account/index.js +128 -0
- package/dist/contracts/core/account/type.d.ts +18 -0
- package/dist/contracts/core/account/type.js +2 -0
- package/dist/contracts/core/pool/index.d.ts +149 -0
- package/dist/contracts/core/pool/index.js +379 -0
- package/dist/contracts/core/pool/serializer.d.ts +15 -0
- package/dist/contracts/core/pool/serializer.js +307 -0
- package/dist/contracts/core/pool/type.d.ts +136 -0
- package/dist/contracts/core/pool/type.js +2 -0
- package/dist/contracts/dedust-farm/MockDedustFarm.d.ts +41 -0
- package/dist/contracts/dedust-farm/MockDedustFarm.js +79 -0
- package/dist/contracts/external/tonstaker.d.ts +18 -0
- package/dist/contracts/external/tonstaker.js +26 -0
- package/dist/contracts/factory/factory.d.ts +24 -0
- package/dist/contracts/factory/factory.js +58 -0
- package/dist/contracts/factory/type.d.ts +11 -0
- package/dist/contracts/factory/type.js +2 -0
- package/dist/contracts/farm/distributor.d.ts +43 -0
- package/dist/contracts/farm/distributor.js +83 -0
- package/dist/contracts/farm/receipt.d.ts +40 -0
- package/dist/contracts/farm/receipt.js +68 -0
- package/dist/contracts/irm/jump-irm/serializer.d.ts +4 -0
- package/dist/contracts/irm/jump-irm/serializer.js +26 -0
- package/dist/contracts/irm/jump-irm/type.d.ts +8 -0
- package/dist/contracts/irm/jump-irm/type.js +2 -0
- package/dist/contracts/jetton/jetton-minter.d.ts +23 -0
- package/dist/contracts/jetton/jetton-minter.js +46 -0
- package/dist/contracts/jetton/jetton-wallet.d.ts +67 -0
- package/dist/contracts/jetton/jetton-wallet.js +119 -0
- package/dist/contracts/jetton/type.d.ts +7 -0
- package/dist/contracts/jetton/type.js +2 -0
- package/dist/contracts/liquid_token/dedust/minter.d.ts +56 -0
- package/dist/contracts/liquid_token/dedust/minter.js +112 -0
- package/dist/contracts/liquid_token/dedust/wallet.d.ts +127 -0
- package/dist/contracts/liquid_token/dedust/wallet.js +213 -0
- package/dist/contracts/liquid_token/stonfi/LFStonfiJettonMinter.d.ts +53 -0
- package/dist/contracts/liquid_token/stonfi/LFStonfiJettonMinter.js +110 -0
- package/dist/contracts/liquid_token/stonfi/LFStonfiJettonWallet.d.ts +169 -0
- package/dist/contracts/liquid_token/stonfi/LFStonfiJettonWallet.js +288 -0
- package/dist/contracts/oracle/composite-onchain-oracle/index.d.ts +108 -0
- package/dist/contracts/oracle/composite-onchain-oracle/index.js +185 -0
- package/dist/contracts/oracle/parser.d.ts +7 -0
- package/dist/contracts/oracle/parser.js +77 -0
- package/dist/contracts/oracle/redstone-onchain-oracle/index.d.ts +56 -0
- package/dist/contracts/oracle/redstone-onchain-oracle/index.js +159 -0
- package/dist/contracts/oracle/redstone-onchain-oracle/serializer.d.ts +4 -0
- package/dist/contracts/oracle/redstone-onchain-oracle/serializer.js +137 -0
- package/dist/contracts/oracle/redstone-onchain-oracle/type.d.ts +57 -0
- package/dist/contracts/oracle/redstone-onchain-oracle/type.js +18 -0
- package/dist/contracts/oracle/redstone-oracle/serializer.d.ts +3 -0
- package/dist/contracts/oracle/redstone-oracle/serializer.js +30 -0
- package/dist/contracts/oracle/redstone-oracle/type.d.ts +9 -0
- package/dist/contracts/oracle/redstone-oracle/type.js +2 -0
- package/dist/contracts/oracle/redstone-parser.d.ts +9 -0
- package/dist/contracts/oracle/redstone-parser.js +58 -0
- package/dist/contracts/rfq/rfq_auction/index.d.ts +216 -0
- package/dist/contracts/rfq/rfq_auction/index.js +334 -0
- package/dist/contracts/rfq/rfq_batch/index.d.ts +346 -0
- package/dist/contracts/rfq/rfq_batch/index.js +448 -0
- package/dist/contracts/rfq/rfq_event_emitter/index.d.ts +132 -0
- package/dist/contracts/rfq/rfq_event_emitter/index.js +143 -0
- package/dist/contracts/stonfi-farm/MockStonfiFarmItem.d.ts +41 -0
- package/dist/contracts/stonfi-farm/MockStonfiFarmItem.js +83 -0
- package/dist/contracts/stonfi-farm/MockStonfiFarmMinter.d.ts +45 -0
- package/dist/contracts/stonfi-farm/MockStonfiFarmMinter.js +92 -0
- package/dist/contracts/unknown-contract/index.d.ts +14 -0
- package/dist/contracts/unknown-contract/index.js +18 -0
- package/dist/contracts/vault/share-vault/index.d.ts +206 -0
- package/dist/contracts/vault/share-vault/index.js +373 -0
- package/dist/contracts/vault/strategy-vault/codec.d.ts +710 -0
- package/dist/contracts/vault/strategy-vault/codec.js +1256 -0
- package/dist/contracts/vault/strategy-vault/computation.d.ts +11 -0
- package/dist/contracts/vault/strategy-vault/computation.js +56 -0
- package/dist/contracts/vault/strategy-vault/constants.d.ts +163 -0
- package/dist/contracts/vault/strategy-vault/constants.js +170 -0
- package/dist/contracts/vault/strategy-vault/index.d.ts +587 -0
- package/dist/contracts/vault/strategy-vault/index.js +406 -0
- package/dist/contracts/vault/strategy-vault/type.d.ts +115 -0
- package/dist/contracts/vault/strategy-vault/type.js +2 -0
- package/dist/contracts/wton/jetton-minter.d.ts +35 -0
- package/dist/contracts/wton/jetton-minter.js +71 -0
- package/dist/contracts/wton/jetton-wallet.d.ts +90 -0
- package/dist/contracts/wton/jetton-wallet.js +153 -0
- package/dist/contracts/wton/type.d.ts +7 -0
- package/dist/contracts/wton/type.js +2 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.js +65 -0
- package/dist/lib/assert.d.ts +1 -0
- package/dist/lib/assert.js +9 -0
- package/dist/lib/query-cache.d.ts +5 -0
- package/dist/lib/query-cache.js +57 -0
- package/dist/lib/send-msg.d.ts +11 -0
- package/dist/lib/send-msg.js +9 -0
- package/dist/services/composite-oracle/computation.d.ts +55 -0
- package/dist/services/composite-oracle/computation.js +295 -0
- package/dist/services/composite-oracle/index.d.ts +45 -0
- package/dist/services/composite-oracle/index.js +110 -0
- package/dist/services/composite-oracle/query.d.ts +36 -0
- package/dist/services/composite-oracle/query.js +251 -0
- package/dist/services/composite-oracle/types.d.ts +82 -0
- package/dist/services/composite-oracle/types.js +11 -0
- package/dist/services/pool/computation.d.ts +75 -0
- package/dist/services/pool/computation.js +219 -0
- package/dist/services/pool/index.d.ts +94 -0
- package/dist/services/pool/index.js +139 -0
- package/dist/services/pool/oracle.d.ts +20 -0
- package/dist/services/pool/oracle.js +61 -0
- package/dist/services/pool/owner/index.d.ts +37 -0
- package/dist/services/pool/owner/index.js +76 -0
- package/dist/services/pool/owner/types.d.ts +18 -0
- package/dist/services/pool/owner/types.js +2 -0
- package/dist/services/pool/query.d.ts +64 -0
- package/dist/services/pool/query.js +282 -0
- package/dist/services/pool/user/index.d.ts +86 -0
- package/dist/services/pool/user/index.js +285 -0
- package/dist/services/pool/user/types.d.ts +44 -0
- package/dist/services/pool/user/types.js +2 -0
- package/dist/services/rfq-auction/index.d.ts +81 -0
- package/dist/services/rfq-auction/index.js +93 -0
- package/dist/services/rfq-auction/oracle.d.ts +19 -0
- package/dist/services/rfq-auction/oracle.js +60 -0
- package/dist/services/rfq-auction/query.d.ts +50 -0
- package/dist/services/rfq-auction/query.js +19 -0
- package/dist/services/rfq-auction/user/index.d.ts +63 -0
- package/dist/services/rfq-auction/user/index.js +218 -0
- package/dist/services/rfq-auction/user/types.d.ts +29 -0
- package/dist/services/rfq-auction/user/types.js +2 -0
- package/dist/services/rfq-batch/index.d.ts +78 -0
- package/dist/services/rfq-batch/index.js +132 -0
- package/dist/services/rfq-batch/oracle.d.ts +22 -0
- package/dist/services/rfq-batch/oracle.js +54 -0
- package/dist/services/rfq-batch/query.d.ts +46 -0
- package/dist/services/rfq-batch/query.js +34 -0
- package/dist/services/rfq-batch/user/index.d.ts +79 -0
- package/dist/services/rfq-batch/user/index.js +171 -0
- package/dist/services/rfq-batch/user/types.d.ts +37 -0
- package/dist/services/rfq-batch/user/types.js +2 -0
- package/dist/services/share-vault/computation.d.ts +24 -0
- package/dist/services/share-vault/computation.js +42 -0
- package/dist/services/share-vault/index.d.ts +90 -0
- package/dist/services/share-vault/index.js +128 -0
- package/dist/services/share-vault/manager/index.d.ts +40 -0
- package/dist/services/share-vault/manager/index.js +111 -0
- package/dist/services/share-vault/manager/types.d.ts +23 -0
- package/dist/services/share-vault/manager/types.js +2 -0
- package/dist/services/share-vault/owner/index.d.ts +64 -0
- package/dist/services/share-vault/owner/index.js +122 -0
- package/dist/services/share-vault/owner/types.d.ts +33 -0
- package/dist/services/share-vault/owner/types.js +2 -0
- package/dist/services/share-vault/query.d.ts +34 -0
- package/dist/services/share-vault/query.js +138 -0
- package/dist/services/share-vault/user/index.d.ts +33 -0
- package/dist/services/share-vault/user/index.js +106 -0
- package/dist/services/share-vault/user/types.d.ts +13 -0
- package/dist/services/share-vault/user/types.js +2 -0
- package/dist/services/strategy-vault/index.d.ts +2124 -0
- package/dist/services/strategy-vault/index.js +268 -0
- package/dist/services/strategy-vault/manager/index.d.ts +1968 -0
- package/dist/services/strategy-vault/manager/index.js +475 -0
- package/dist/services/strategy-vault/manager/types.d.ts +144 -0
- package/dist/services/strategy-vault/manager/types.js +2 -0
- package/dist/services/strategy-vault/oracle.d.ts +66 -0
- package/dist/services/strategy-vault/oracle.js +162 -0
- package/dist/services/strategy-vault/owner/index.d.ts +277 -0
- package/dist/services/strategy-vault/owner/index.js +333 -0
- package/dist/services/strategy-vault/owner/types.d.ts +146 -0
- package/dist/services/strategy-vault/owner/types.js +2 -0
- package/dist/services/strategy-vault/query.d.ts +138 -0
- package/dist/services/strategy-vault/query.js +59 -0
- package/dist/services/strategy-vault/user/index.d.ts +89 -0
- package/dist/services/strategy-vault/user/index.js +219 -0
- package/dist/services/strategy-vault/user/types.d.ts +46 -0
- package/dist/services/strategy-vault/user/types.js +2 -0
- package/dist/types/sender.d.ts +7 -0
- package/dist/types/sender.js +2 -0
- package/dist/utils/action-parser.d.ts +7 -0
- package/dist/utils/action-parser.js +20 -0
- package/dist/utils/external-message-hash.d.ts +45 -0
- package/dist/utils/external-message-hash.js +65 -0
- package/dist/utils/oracle/redstone/readonlyCachedRedstone.d.ts +3 -0
- package/dist/utils/oracle/redstone/readonlyCachedRedstone.js +25 -0
- package/dist/utils/oracle/redstone/redstoneHelper.d.ts +21 -0
- package/dist/utils/oracle/redstone/redstoneHelper.js +228 -0
- package/dist/utils/parser.d.ts +40 -0
- package/dist/utils/parser.js +580 -0
- package/dist/utils/pending-tracker/index.d.ts +14 -0
- package/dist/utils/pending-tracker/index.js +34 -0
- package/dist/utils/pending-tracker/trackable-sender.d.ts +16 -0
- package/dist/utils/pending-tracker/trackable-sender.js +87 -0
- package/dist/utils/pending-tracker/type.d.ts +78 -0
- package/dist/utils/pending-tracker/type.js +2 -0
- package/dist/utils/pending-tracker/v3-client.d.ts +31 -0
- package/dist/utils/pending-tracker/v3-client.js +104 -0
- package/dist/utils/risk_calculator/risk_calculator.d.ts +45 -0
- package/dist/utils/risk_calculator/risk_calculator.js +332 -0
- package/dist/utils/utils.d.ts +5 -0
- package/dist/utils/utils.js +12 -0
- package/package.json +46 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CompositeOracleFetcher = void 0;
|
|
4
|
+
const core_1 = require("@ton/core");
|
|
5
|
+
const context_1 = require("../../context");
|
|
6
|
+
const utils_1 = require("../../contracts/common/utils");
|
|
7
|
+
const pool_1 = require("../../contracts/core/pool");
|
|
8
|
+
const redstone_onchain_oracle_1 = require("../../contracts/oracle/redstone-onchain-oracle");
|
|
9
|
+
const type_1 = require("../../contracts/oracle/redstone-onchain-oracle/type");
|
|
10
|
+
const share_vault_1 = require("../../contracts/vault/share-vault");
|
|
11
|
+
const strategy_vault_1 = require("../../contracts/vault/strategy-vault");
|
|
12
|
+
const readonlyCachedRedstone_1 = require("../../utils/oracle/redstone/readonlyCachedRedstone");
|
|
13
|
+
const unknown_contract_1 = require("../../contracts/unknown-contract");
|
|
14
|
+
const types_1 = require("./types");
|
|
15
|
+
const computation_1 = require("./computation");
|
|
16
|
+
// ============================================================
|
|
17
|
+
// Query Class (I/O - fetching data)
|
|
18
|
+
// ============================================================
|
|
19
|
+
class CompositeOracleFetcher {
|
|
20
|
+
ctx;
|
|
21
|
+
constructor(ctx = context_1.AffluentContext.getInstance()) {
|
|
22
|
+
this.ctx = ctx;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Get oracle context - shared data needed for both price computation and on-chain params
|
|
26
|
+
*/
|
|
27
|
+
async getOracleContext(vaultAddress, vaultData, extraAssets) {
|
|
28
|
+
const vault = this.ctx.getByContract(strategy_vault_1.StrategyVault, (0, utils_1.toAddress)(vaultAddress));
|
|
29
|
+
vaultData = vaultData ?? (await vault.getVaultData());
|
|
30
|
+
const oracleConfig = vaultData.oracleConfig;
|
|
31
|
+
let { assets, vaultAssets } = (0, computation_1.separateAssets)(Object.keys(vaultData.assets), oracleConfig);
|
|
32
|
+
if (extraAssets) {
|
|
33
|
+
assets = [...new Set([...assets, ...extraAssets.assets])];
|
|
34
|
+
vaultAssets = [...new Set([...vaultAssets, ...extraAssets.vaultAssets])];
|
|
35
|
+
}
|
|
36
|
+
const vaultPositions = await this.fetchVaultPositions([...vaultAssets, (0, utils_1.toAddress)(vaultAddress)]);
|
|
37
|
+
const exposures = (0, computation_1.getExposures)(vaultPositions);
|
|
38
|
+
const allRequiredAssets = [...new Set([...assets, ...exposures.assets])];
|
|
39
|
+
return {
|
|
40
|
+
vaultData,
|
|
41
|
+
oracleConfig,
|
|
42
|
+
assets,
|
|
43
|
+
vaultAssets,
|
|
44
|
+
vaultPositions,
|
|
45
|
+
exposures,
|
|
46
|
+
allRequiredAssets,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
async fetchRawPrices(assets, oracleConfig) {
|
|
50
|
+
const result = redstone_onchain_oracle_1.RedstoneOnchainOracle.getOracleRequestParams(assets, oracleConfig);
|
|
51
|
+
const redstonePrices = await readonlyCachedRedstone_1.ReadonlyCachedRedstone.getPrices(result.redstoneAssetNames);
|
|
52
|
+
const rawPrices = {};
|
|
53
|
+
const onchainData = {};
|
|
54
|
+
for (const item of redstonePrices) {
|
|
55
|
+
try {
|
|
56
|
+
const rainfo = oracleConfig.redstoneAssetInfo[item.feedId.toString()];
|
|
57
|
+
if (!rainfo)
|
|
58
|
+
continue;
|
|
59
|
+
if (rainfo.assetType === 0) {
|
|
60
|
+
rawPrices[rainfo.address.toString()] = {
|
|
61
|
+
type: types_1.CompositeAssetType.NATIVE,
|
|
62
|
+
timestamp: item.timestamp,
|
|
63
|
+
price: (item.price * types_1.DECIMALS_OF_PRICE) / rainfo.precision,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
else if (rainfo.assetType === 1) {
|
|
67
|
+
onchainData[rainfo.address.toString()] = {
|
|
68
|
+
assetType: types_1.CompositeAssetType.SYNTHETIC1,
|
|
69
|
+
underlyingAddress: rainfo.underlyingAddress,
|
|
70
|
+
underlyingReserve: item.price,
|
|
71
|
+
totalSupply: rainfo.precision,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (e) { }
|
|
76
|
+
}
|
|
77
|
+
return { rawPrices, onchainData };
|
|
78
|
+
}
|
|
79
|
+
async fetchOnchainData(onchainDataInfo) {
|
|
80
|
+
const result = {};
|
|
81
|
+
for (const [asset, data] of Object.entries(onchainDataInfo)) {
|
|
82
|
+
if (data.sourceType === redstone_onchain_oracle_1.RedstoneOnchainOracle.SourceType.tonstakers && data.assetType === type_1.AssetType.SingleAsset) {
|
|
83
|
+
const state = await this.ctx.client.provider(core_1.Address.parse(data.sourceAddress.toString())).get("get_pool_state", []);
|
|
84
|
+
state.stack.readBigNumber();
|
|
85
|
+
result[asset] = {
|
|
86
|
+
assetType: types_1.CompositeAssetType.SYNTHETIC1,
|
|
87
|
+
underlyingAddress: data.underlyingAddress,
|
|
88
|
+
underlyingReserve: state.stack.readBigNumber(),
|
|
89
|
+
totalSupply: state.stack.readBigNumber(),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
else if (data.sourceType === redstone_onchain_oracle_1.RedstoneOnchainOracle.SourceType.dedust && data.assetType === type_1.AssetType.MultiAsset) {
|
|
93
|
+
if (this.ctx.network === "mainnet") {
|
|
94
|
+
const [reserves, jettonData] = await Promise.all([
|
|
95
|
+
this.ctx.client.provider(core_1.Address.parse(data.sourceAddress.toString())).get("get_reserves", []),
|
|
96
|
+
this.ctx.client.provider(core_1.Address.parse(data.sourceAddress.toString())).get("get_jetton_data", []),
|
|
97
|
+
]);
|
|
98
|
+
result[asset] = {
|
|
99
|
+
assetType: types_1.CompositeAssetType.SYNTHETIC2,
|
|
100
|
+
underlying0Address: data.underlying0Address,
|
|
101
|
+
underlying1Address: data.underlying1Address,
|
|
102
|
+
underlying0Reserve: reserves.stack.readBigNumber(),
|
|
103
|
+
underlying1Reserve: reserves.stack.readBigNumber(),
|
|
104
|
+
totalSupply: jettonData.stack.readBigNumber(),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
const state = await this.ctx.client.provider(core_1.Address.parse(data.sourceAddress.toString())).get("get_pool_state", []);
|
|
109
|
+
state.stack.readBigNumber();
|
|
110
|
+
result[asset] = {
|
|
111
|
+
assetType: types_1.CompositeAssetType.SYNTHETIC2,
|
|
112
|
+
underlying0Address: data.underlying0Address,
|
|
113
|
+
underlying1Address: data.underlying1Address,
|
|
114
|
+
underlying0Reserve: state.stack.readBigNumber(),
|
|
115
|
+
underlying1Reserve: state.stack.readBigNumber(),
|
|
116
|
+
totalSupply: state.stack.readBigNumber(),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
else if (data.sourceType === redstone_onchain_oracle_1.RedstoneOnchainOracle.SourceType.stonfi && data.assetType === type_1.AssetType.MultiAsset) {
|
|
121
|
+
if (this.ctx.network === "mainnet") {
|
|
122
|
+
const state = await this.ctx.client.provider(core_1.Address.parse(data.sourceAddress.toString())).get("get_pool_data", []);
|
|
123
|
+
state.stack.readNumber();
|
|
124
|
+
state.stack.readAddress();
|
|
125
|
+
const totalSupply = state.stack.readBigNumber();
|
|
126
|
+
result[asset] = {
|
|
127
|
+
assetType: types_1.CompositeAssetType.SYNTHETIC2,
|
|
128
|
+
underlying0Address: data.underlying0Address,
|
|
129
|
+
underlying1Address: data.underlying1Address,
|
|
130
|
+
underlying0Reserve: state.stack.readBigNumber(),
|
|
131
|
+
underlying1Reserve: state.stack.readBigNumber(),
|
|
132
|
+
totalSupply,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
const state = await this.ctx.client.provider(core_1.Address.parse(data.sourceAddress.toString())).get("get_pool_state", []);
|
|
137
|
+
state.stack.readBigNumber();
|
|
138
|
+
result[asset] = {
|
|
139
|
+
assetType: types_1.CompositeAssetType.SYNTHETIC2,
|
|
140
|
+
underlying0Address: data.underlying0Address,
|
|
141
|
+
underlying1Address: data.underlying1Address,
|
|
142
|
+
underlying0Reserve: state.stack.readBigNumber(),
|
|
143
|
+
underlying1Reserve: state.stack.readBigNumber(),
|
|
144
|
+
totalSupply: state.stack.readBigNumber(),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else if (data.sourceType === redstone_onchain_oracle_1.RedstoneOnchainOracle.SourceType.storm && data.assetType === type_1.AssetType.SingleAsset) {
|
|
149
|
+
if (this.ctx.network === "mainnet") {
|
|
150
|
+
const state = await this.ctx.client.provider(core_1.Address.parse(data.sourceAddress.toString())).get("get_vault_data", []);
|
|
151
|
+
state.stack.readAddress();
|
|
152
|
+
result[asset] = {
|
|
153
|
+
assetType: types_1.CompositeAssetType.SYNTHETIC1,
|
|
154
|
+
underlyingAddress: data.underlyingAddress,
|
|
155
|
+
underlyingReserve: state.stack.readBigNumber(),
|
|
156
|
+
totalSupply: data.totalSupply ?? BigInt(1e9),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
else if (data.sourceType === redstone_onchain_oracle_1.RedstoneOnchainOracle.SourceType.tradoor && data.assetType === type_1.AssetType.SingleAsset) {
|
|
161
|
+
if (this.ctx.network === "mainnet") {
|
|
162
|
+
const state = await this.ctx.client.provider(core_1.Address.parse(data.sourceAddress.toString())).get("tlpPrice", []);
|
|
163
|
+
result[asset] = {
|
|
164
|
+
assetType: types_1.CompositeAssetType.SYNTHETIC1,
|
|
165
|
+
underlyingAddress: data.underlyingAddress,
|
|
166
|
+
underlyingReserve: state.stack.readBigNumber(),
|
|
167
|
+
totalSupply: data.totalSupply ?? BigInt(18e9),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return result;
|
|
173
|
+
}
|
|
174
|
+
async fetchVaultPositions(vaultAddresses) {
|
|
175
|
+
const positions = {};
|
|
176
|
+
await Promise.all(vaultAddresses.map(async (vaultAddress) => {
|
|
177
|
+
const addressStr = vaultAddress.toString();
|
|
178
|
+
try {
|
|
179
|
+
const state = await this.ctx.getByContract(unknown_contract_1.UnknownContract, vaultAddress).getState();
|
|
180
|
+
if (state.state.type === "active" && state.state.data) {
|
|
181
|
+
const data = core_1.Cell.fromBoc(state.state.data)[0];
|
|
182
|
+
try {
|
|
183
|
+
const vaultData = strategy_vault_1.StrategyVault.parseVaultData(data);
|
|
184
|
+
positions[addressStr] = extractStrategyVaultPosition(vaultData);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
catch (e) { }
|
|
188
|
+
try {
|
|
189
|
+
const vaultData = share_vault_1.ShareVault.parseVaultData(data);
|
|
190
|
+
positions[addressStr] = extractShareVaultPosition(vaultData);
|
|
191
|
+
}
|
|
192
|
+
catch (e) { }
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
catch (e) { }
|
|
196
|
+
}));
|
|
197
|
+
return positions;
|
|
198
|
+
}
|
|
199
|
+
async fetchPoolInfos(poolAddresses) {
|
|
200
|
+
const poolInfos = {};
|
|
201
|
+
await Promise.all(poolAddresses.map(async (poolAddress) => {
|
|
202
|
+
try {
|
|
203
|
+
const pool = this.ctx.getByContract(pool_1.Pool, (0, utils_1.toAddress)(poolAddress));
|
|
204
|
+
const poolData = await pool.getPoolData();
|
|
205
|
+
poolInfos[poolAddress] = {};
|
|
206
|
+
for (const [asset, assetData] of Object.entries(poolData.assets)) {
|
|
207
|
+
poolInfos[poolAddress][asset] = {
|
|
208
|
+
totalSupplyAmount: assetData.totalSupplyAmount,
|
|
209
|
+
totalSupplyShare: assetData.totalSupplyShare,
|
|
210
|
+
totalBorrowAmount: assetData.totalBorrowAmount,
|
|
211
|
+
totalBorrowShare: assetData.totalBorrowShare,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch (e) { }
|
|
216
|
+
}));
|
|
217
|
+
return poolInfos;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
exports.CompositeOracleFetcher = CompositeOracleFetcher;
|
|
221
|
+
// ============================================================
|
|
222
|
+
// Helper Functions
|
|
223
|
+
// ============================================================
|
|
224
|
+
function extractStrategyVaultPosition(vaultData) {
|
|
225
|
+
const assets = {};
|
|
226
|
+
const poolPositions = {};
|
|
227
|
+
for (const [asset, assetData] of Object.entries(vaultData.assets)) {
|
|
228
|
+
assets[asset] = assetData.cash;
|
|
229
|
+
}
|
|
230
|
+
for (const [pool, poolAssets] of Object.entries(vaultData.factorialPools)) {
|
|
231
|
+
poolPositions[pool] = {};
|
|
232
|
+
for (const [asset, position] of Object.entries(poolAssets)) {
|
|
233
|
+
poolPositions[pool][asset] = { supply: position.supply, borrow: position.borrow };
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return { assets, poolPositions, totalSupply: vaultData.totalSupply };
|
|
237
|
+
}
|
|
238
|
+
function extractShareVaultPosition(vaultData) {
|
|
239
|
+
const asset = vaultData.asset.toString();
|
|
240
|
+
const poolPositions = {};
|
|
241
|
+
for (const pool of Object.values(vaultData.whitelistedPools)) {
|
|
242
|
+
poolPositions[pool.address.toString()] = {
|
|
243
|
+
[asset]: { supply: pool.supply, borrow: 0n },
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
return {
|
|
247
|
+
assets: { [asset]: vaultData.cash },
|
|
248
|
+
poolPositions,
|
|
249
|
+
totalSupply: vaultData.totalSupply,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Address } from "@ton/core";
|
|
2
|
+
export declare const DECIMALS_OF_PRICE = 100000000n;
|
|
3
|
+
export declare enum CompositeAssetType {
|
|
4
|
+
NATIVE = 0,
|
|
5
|
+
SYNTHETIC1 = 1,
|
|
6
|
+
SYNTHETIC2 = 2,
|
|
7
|
+
VAULT = 10
|
|
8
|
+
}
|
|
9
|
+
export type PriceEntry = {
|
|
10
|
+
type: CompositeAssetType;
|
|
11
|
+
price: bigint;
|
|
12
|
+
timestamp?: number;
|
|
13
|
+
};
|
|
14
|
+
export type Prices = Record<string, PriceEntry>;
|
|
15
|
+
export type PoolAssetPosition = {
|
|
16
|
+
supply: bigint;
|
|
17
|
+
borrow: bigint;
|
|
18
|
+
};
|
|
19
|
+
export type PoolPositions = Record<string, PoolAssetPosition>;
|
|
20
|
+
export type VaultPosition = {
|
|
21
|
+
assets: Record<string, bigint>;
|
|
22
|
+
poolPositions: Record<string, PoolPositions>;
|
|
23
|
+
totalSupply: bigint;
|
|
24
|
+
};
|
|
25
|
+
export type PoolShareInfo = {
|
|
26
|
+
totalSupplyAmount: bigint;
|
|
27
|
+
totalSupplyShare: bigint;
|
|
28
|
+
totalBorrowAmount: bigint;
|
|
29
|
+
totalBorrowShare: bigint;
|
|
30
|
+
};
|
|
31
|
+
export type PoolInfos = Record<string, Record<string, PoolShareInfo>>;
|
|
32
|
+
export type SingleAssetData = {
|
|
33
|
+
assetType: CompositeAssetType.SYNTHETIC1;
|
|
34
|
+
underlyingAddress: Address | string;
|
|
35
|
+
underlyingReserve: bigint;
|
|
36
|
+
totalSupply: bigint;
|
|
37
|
+
};
|
|
38
|
+
export type MultiAssetData = {
|
|
39
|
+
assetType: CompositeAssetType.SYNTHETIC2;
|
|
40
|
+
underlying0Address: Address | string;
|
|
41
|
+
underlying1Address: Address | string;
|
|
42
|
+
underlying0Reserve: bigint;
|
|
43
|
+
underlying1Reserve: bigint;
|
|
44
|
+
totalSupply: bigint;
|
|
45
|
+
};
|
|
46
|
+
export type SyntheticComposition = SingleAssetData | MultiAssetData;
|
|
47
|
+
export type SyntheticCompositions = Record<string, SyntheticComposition>;
|
|
48
|
+
/** @deprecated Use SyntheticComposition instead */
|
|
49
|
+
export type OnchainData = SyntheticComposition;
|
|
50
|
+
/** @deprecated Use SyntheticCompositions instead */
|
|
51
|
+
export type OnchainDataMap = SyntheticCompositions;
|
|
52
|
+
export type VaultPositions = Record<string, VaultPosition>;
|
|
53
|
+
export type VaultComposition = {
|
|
54
|
+
decomposed: Record<string, {
|
|
55
|
+
supply: bigint;
|
|
56
|
+
borrow: bigint;
|
|
57
|
+
}>;
|
|
58
|
+
totalSupply: bigint;
|
|
59
|
+
};
|
|
60
|
+
export type VaultCompositions = Record<string, VaultComposition>;
|
|
61
|
+
export type VaultPriceEntry = PriceEntry & {
|
|
62
|
+
additionalData: VaultComposition;
|
|
63
|
+
};
|
|
64
|
+
export type VaultPrices = Record<string, VaultPriceEntry>;
|
|
65
|
+
export type CompositeOracleResult = {
|
|
66
|
+
assetPrices: Prices;
|
|
67
|
+
vaultPrices: VaultPrices;
|
|
68
|
+
allPrices: Prices;
|
|
69
|
+
};
|
|
70
|
+
export type CompositeOracleInput = {
|
|
71
|
+
rawPrices: Prices;
|
|
72
|
+
syntheticCompositions: SyntheticCompositions;
|
|
73
|
+
vaultPositions: VaultPositions;
|
|
74
|
+
poolInfos: PoolInfos;
|
|
75
|
+
};
|
|
76
|
+
/** @deprecated Use CompositeOracleInput with syntheticCompositions instead */
|
|
77
|
+
export type CompositeOracleInputLegacy = {
|
|
78
|
+
rawPrices: Prices;
|
|
79
|
+
onchainData: OnchainDataMap;
|
|
80
|
+
vaultPositions: VaultPositions;
|
|
81
|
+
poolInfos: PoolInfos;
|
|
82
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CompositeAssetType = exports.DECIMALS_OF_PRICE = void 0;
|
|
4
|
+
exports.DECIMALS_OF_PRICE = 100000000n;
|
|
5
|
+
var CompositeAssetType;
|
|
6
|
+
(function (CompositeAssetType) {
|
|
7
|
+
CompositeAssetType[CompositeAssetType["NATIVE"] = 0] = "NATIVE";
|
|
8
|
+
CompositeAssetType[CompositeAssetType["SYNTHETIC1"] = 1] = "SYNTHETIC1";
|
|
9
|
+
CompositeAssetType[CompositeAssetType["SYNTHETIC2"] = 2] = "SYNTHETIC2";
|
|
10
|
+
CompositeAssetType[CompositeAssetType["VAULT"] = 10] = "VAULT";
|
|
11
|
+
})(CompositeAssetType || (exports.CompositeAssetType = CompositeAssetType = {}));
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { PoolState } from "../../contracts/core/pool/type";
|
|
2
|
+
import { AccountState, AccountAssetState } from "../../contracts/core/account/type";
|
|
3
|
+
import { Prices, VaultCompositions, SyntheticCompositions } from "../composite-oracle/types";
|
|
4
|
+
export type HealthResult = {
|
|
5
|
+
result: boolean;
|
|
6
|
+
healthy: boolean;
|
|
7
|
+
unhealthy: boolean;
|
|
8
|
+
collateral: bigint;
|
|
9
|
+
debt: bigint;
|
|
10
|
+
risk: bigint;
|
|
11
|
+
riskRatio: bigint;
|
|
12
|
+
leverageRatio: bigint;
|
|
13
|
+
};
|
|
14
|
+
/** @deprecated Use HealthResult instead */
|
|
15
|
+
export type RiskResult = HealthResult;
|
|
16
|
+
export type MaxBorrowableResult = {
|
|
17
|
+
amount: bigint;
|
|
18
|
+
reason: "RISK_RATIO_CONSTRAINT" | "LEVERAGE_CONSTRAINT" | "POOL_CASH_CONSTRAINT";
|
|
19
|
+
beforeAccountHealth: HealthResult;
|
|
20
|
+
afterAccountHealth: HealthResult;
|
|
21
|
+
};
|
|
22
|
+
export type MaxWithdrawableResult = {
|
|
23
|
+
amount: bigint;
|
|
24
|
+
reason: "RISK_RATIO_CONSTRAINT" | "LEVERAGE_CONSTRAINT" | "POOL_CASH_CONSTRAINT" | "USER_SUPPLY_CONSTRAINT";
|
|
25
|
+
beforeAccountHealth?: HealthResult;
|
|
26
|
+
afterAccountHealth?: HealthResult;
|
|
27
|
+
};
|
|
28
|
+
type Position = {
|
|
29
|
+
supply: bigint;
|
|
30
|
+
borrow: bigint;
|
|
31
|
+
};
|
|
32
|
+
type PositionMap = Record<string, Position>;
|
|
33
|
+
/**
|
|
34
|
+
* Simulate interest accrual on pool data
|
|
35
|
+
*/
|
|
36
|
+
export declare function simulateAccrueInterest(poolData: PoolState, time?: number): PoolState;
|
|
37
|
+
/**
|
|
38
|
+
* Convert share-based position to actual amounts
|
|
39
|
+
*/
|
|
40
|
+
export declare function convertShareToAmount(accountData: AccountState, poolData: PoolState): AccountState;
|
|
41
|
+
/**
|
|
42
|
+
* Check if account has any borrow positions
|
|
43
|
+
*/
|
|
44
|
+
export declare function haveBorrow(accountData: AccountState): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Get list of assets the account has positions in
|
|
47
|
+
*/
|
|
48
|
+
export declare function haveAssets(accountData: AccountState): string[];
|
|
49
|
+
/**
|
|
50
|
+
* Apply delta to account state
|
|
51
|
+
*/
|
|
52
|
+
export declare function applyDelta(accountData: AccountState, delta: Record<string, AccountAssetState>): AccountState;
|
|
53
|
+
/**
|
|
54
|
+
* Decompose synthetic/vault positions to native assets
|
|
55
|
+
*
|
|
56
|
+
* - SYNTHETIC1: stTON(100) → TON(105)
|
|
57
|
+
* - SYNTHETIC2: LP-TON-USDT(100) → TON(50) + USDT(50)
|
|
58
|
+
* - VAULT: StrategyVault(100) → TON(30) + USDT(70)
|
|
59
|
+
*
|
|
60
|
+
* 같은 native asset이 여러 경로로 나오면 누적됨
|
|
61
|
+
*/
|
|
62
|
+
export declare function decomposePositions(positions: Record<string, AccountAssetState>, syntheticCompositions: SyntheticCompositions, vaultCompositions?: VaultCompositions): PositionMap;
|
|
63
|
+
/** @deprecated Use decomposePositions instead */
|
|
64
|
+
export declare const decomposeAccountStatus: typeof decomposePositions;
|
|
65
|
+
/**
|
|
66
|
+
* Calculate risk metrics from decomposed account status
|
|
67
|
+
* Pure computation
|
|
68
|
+
*/
|
|
69
|
+
export declare function calculateRisk(decomposedAccountStatus: Record<string, Omit<AccountAssetState, "address">>, prices: Prices, poolData: PoolState): HealthResult;
|
|
70
|
+
/**
|
|
71
|
+
* Check if account is healthy (pure computation)
|
|
72
|
+
* Takes pre-fetched pool data, account status, and prices
|
|
73
|
+
*/
|
|
74
|
+
export declare function isHealthyFromData(poolData: PoolState, accountStatus: Record<string, AccountAssetState>, prices: Prices, syntheticCompositions: SyntheticCompositions, vaultCompositions?: VaultCompositions): HealthResult;
|
|
75
|
+
export {};
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.decomposeAccountStatus = void 0;
|
|
4
|
+
exports.simulateAccrueInterest = simulateAccrueInterest;
|
|
5
|
+
exports.convertShareToAmount = convertShareToAmount;
|
|
6
|
+
exports.haveBorrow = haveBorrow;
|
|
7
|
+
exports.haveAssets = haveAssets;
|
|
8
|
+
exports.applyDelta = applyDelta;
|
|
9
|
+
exports.decomposePositions = decomposePositions;
|
|
10
|
+
exports.calculateRisk = calculateRisk;
|
|
11
|
+
exports.isHealthyFromData = isHealthyFromData;
|
|
12
|
+
const core_1 = require("@ton/core");
|
|
13
|
+
const pool_1 = require("../../contracts/core/pool");
|
|
14
|
+
const account_1 = require("../../contracts/core/account");
|
|
15
|
+
const types_1 = require("../composite-oracle/types");
|
|
16
|
+
const utils_1 = require("../../contracts/common/utils");
|
|
17
|
+
// ============================================================
|
|
18
|
+
// Position Decomposition Helpers
|
|
19
|
+
// ============================================================
|
|
20
|
+
/**
|
|
21
|
+
* Try to decompose a synthetic/vault asset to its underlying assets
|
|
22
|
+
* Returns null if asset is native (no decomposition needed)
|
|
23
|
+
*/
|
|
24
|
+
function tryDecomposeAsset(asset, position, syntheticCompositions, vaultCompositions) {
|
|
25
|
+
const data = syntheticCompositions[asset];
|
|
26
|
+
// SYNTHETIC1: stTON, tsTON 같은 단일 underlying asset
|
|
27
|
+
if (data?.assetType === types_1.CompositeAssetType.SYNTHETIC1 &&
|
|
28
|
+
"underlyingReserve" in data &&
|
|
29
|
+
data.underlyingReserve &&
|
|
30
|
+
data.totalSupply) {
|
|
31
|
+
const ratio = data.underlyingReserve;
|
|
32
|
+
const total = data.totalSupply;
|
|
33
|
+
return [
|
|
34
|
+
{
|
|
35
|
+
address: (0, utils_1.toAddress)(data.underlyingAddress),
|
|
36
|
+
supply: (position.supply * ratio) / total,
|
|
37
|
+
borrow: (position.borrow * ratio) / total,
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
// SYNTHETIC2: LP 토큰 같은 2개 underlying assets
|
|
42
|
+
if (data?.assetType === types_1.CompositeAssetType.SYNTHETIC2 &&
|
|
43
|
+
"underlying0Reserve" in data &&
|
|
44
|
+
data.underlying0Reserve &&
|
|
45
|
+
data.underlying1Reserve &&
|
|
46
|
+
data.totalSupply) {
|
|
47
|
+
const total = data.totalSupply;
|
|
48
|
+
return [
|
|
49
|
+
{
|
|
50
|
+
address: (0, utils_1.toAddress)(data.underlying0Address),
|
|
51
|
+
supply: (position.supply * data.underlying0Reserve) / total,
|
|
52
|
+
borrow: (position.borrow * data.underlying0Reserve) / total,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
address: (0, utils_1.toAddress)(data.underlying1Address),
|
|
56
|
+
supply: (position.supply * data.underlying1Reserve) / total,
|
|
57
|
+
borrow: (position.borrow * data.underlying1Reserve) / total,
|
|
58
|
+
},
|
|
59
|
+
];
|
|
60
|
+
}
|
|
61
|
+
// VAULT: Strategy Vault - decomposed positions 사용
|
|
62
|
+
const vault = vaultCompositions[asset];
|
|
63
|
+
if (vault) {
|
|
64
|
+
const { decomposed, totalSupply } = vault;
|
|
65
|
+
return Object.entries(decomposed).map(([addr, pos]) => ({
|
|
66
|
+
address: core_1.Address.parse(addr),
|
|
67
|
+
// Vault는 supply/borrow가 교차됨
|
|
68
|
+
supply: (position.supply * pos.supply + position.borrow * pos.borrow) / totalSupply,
|
|
69
|
+
borrow: (position.supply * pos.borrow + position.borrow * pos.supply) / totalSupply,
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
return null; // Native asset
|
|
73
|
+
}
|
|
74
|
+
// ============================================================
|
|
75
|
+
// Pure Computation (no I/O)
|
|
76
|
+
// ============================================================
|
|
77
|
+
/**
|
|
78
|
+
* Simulate interest accrual on pool data
|
|
79
|
+
*/
|
|
80
|
+
function simulateAccrueInterest(poolData, time) {
|
|
81
|
+
return pool_1.Pool.simulateAccrueInterest(poolData, time);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Convert share-based position to actual amounts
|
|
85
|
+
*/
|
|
86
|
+
function convertShareToAmount(accountData, poolData) {
|
|
87
|
+
return account_1.Account.convertShareToAmount(accountData, poolData);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Check if account has any borrow positions
|
|
91
|
+
*/
|
|
92
|
+
function haveBorrow(accountData) {
|
|
93
|
+
return account_1.Account.haveBorrow(accountData);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Get list of assets the account has positions in
|
|
97
|
+
*/
|
|
98
|
+
function haveAssets(accountData) {
|
|
99
|
+
return account_1.Account.haveAssets(accountData);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Apply delta to account state
|
|
103
|
+
*/
|
|
104
|
+
function applyDelta(accountData, delta) {
|
|
105
|
+
return account_1.Account.applyDelta(accountData, delta);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Decompose synthetic/vault positions to native assets
|
|
109
|
+
*
|
|
110
|
+
* - SYNTHETIC1: stTON(100) → TON(105)
|
|
111
|
+
* - SYNTHETIC2: LP-TON-USDT(100) → TON(50) + USDT(50)
|
|
112
|
+
* - VAULT: StrategyVault(100) → TON(30) + USDT(70)
|
|
113
|
+
*
|
|
114
|
+
* 같은 native asset이 여러 경로로 나오면 누적됨
|
|
115
|
+
*/
|
|
116
|
+
function decomposePositions(positions, syntheticCompositions, vaultCompositions = {}) {
|
|
117
|
+
const accumulatedPositions = {};
|
|
118
|
+
const queue = [...Object.values(positions)];
|
|
119
|
+
while (queue.length > 0) {
|
|
120
|
+
const current = queue.shift();
|
|
121
|
+
if (current.supply === 0n && current.borrow === 0n)
|
|
122
|
+
continue;
|
|
123
|
+
// 모든 에셋을 누적 (synthetic/vault/native 모두)
|
|
124
|
+
const asset = current.address.toString();
|
|
125
|
+
accumulatedPositions[asset] ??= { supply: 0n, borrow: 0n };
|
|
126
|
+
accumulatedPositions[asset].supply += current.supply;
|
|
127
|
+
accumulatedPositions[asset].borrow += current.borrow;
|
|
128
|
+
// decompose 가능하면 underlying도 queue에 추가
|
|
129
|
+
const decomposed = tryDecomposeAsset(asset, current, syntheticCompositions, vaultCompositions);
|
|
130
|
+
if (decomposed) {
|
|
131
|
+
queue.push(...decomposed);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return accumulatedPositions;
|
|
135
|
+
}
|
|
136
|
+
/** @deprecated Use decomposePositions instead */
|
|
137
|
+
exports.decomposeAccountStatus = decomposePositions;
|
|
138
|
+
/**
|
|
139
|
+
* Calculate risk metrics from decomposed account status
|
|
140
|
+
* Pure computation
|
|
141
|
+
*/
|
|
142
|
+
function calculateRisk(decomposedAccountStatus, prices, poolData) {
|
|
143
|
+
let collateral = 0n;
|
|
144
|
+
let debt = 0n;
|
|
145
|
+
let risk = 0n;
|
|
146
|
+
for (const [asset, status] of Object.entries(decomposedAccountStatus)) {
|
|
147
|
+
const price = prices[asset];
|
|
148
|
+
if (!price)
|
|
149
|
+
continue;
|
|
150
|
+
const suppliedValue = (status.supply * price.price) / BigInt(1e8);
|
|
151
|
+
const borrowedValue = (status.borrow * price.price) / BigInt(1e8);
|
|
152
|
+
const assetConfig = poolData.assets[asset];
|
|
153
|
+
if (!assetConfig)
|
|
154
|
+
continue;
|
|
155
|
+
const isCollateral = assetConfig.isCollateral;
|
|
156
|
+
if (price.type === types_1.CompositeAssetType.NATIVE) {
|
|
157
|
+
if (isCollateral) {
|
|
158
|
+
collateral += suppliedValue;
|
|
159
|
+
}
|
|
160
|
+
debt += borrowedValue;
|
|
161
|
+
}
|
|
162
|
+
if (isCollateral) {
|
|
163
|
+
const delta = suppliedValue > borrowedValue ? suppliedValue - borrowedValue : borrowedValue - suppliedValue;
|
|
164
|
+
risk += (delta * assetConfig.riskFactor) / BigInt(1e4);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
risk += (borrowedValue * assetConfig.riskFactor) / BigInt(1e4);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (collateral === 0n && debt === 0n) {
|
|
171
|
+
return {
|
|
172
|
+
result: true,
|
|
173
|
+
healthy: true,
|
|
174
|
+
unhealthy: false,
|
|
175
|
+
collateral,
|
|
176
|
+
debt,
|
|
177
|
+
risk,
|
|
178
|
+
riskRatio: 0n,
|
|
179
|
+
leverageRatio: 0n,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
const netValue = collateral - debt;
|
|
183
|
+
if (netValue <= 0n) {
|
|
184
|
+
return {
|
|
185
|
+
result: false,
|
|
186
|
+
healthy: false,
|
|
187
|
+
unhealthy: true,
|
|
188
|
+
collateral,
|
|
189
|
+
debt,
|
|
190
|
+
risk,
|
|
191
|
+
riskRatio: 2n ** 128n - 1n,
|
|
192
|
+
leverageRatio: 2n ** 128n - 1n,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
const leverageRatio = (collateral * BigInt(1e4)) / netValue;
|
|
196
|
+
const riskRatio = (risk * BigInt(1e4)) / netValue;
|
|
197
|
+
const unhealthy = poolData.liquidateLeverageRatio === 0n
|
|
198
|
+
? riskRatio > poolData.liquidateVarRatio
|
|
199
|
+
: leverageRatio > poolData.liquidateLeverageRatio || riskRatio > poolData.liquidateVarRatio;
|
|
200
|
+
return {
|
|
201
|
+
result: !unhealthy,
|
|
202
|
+
healthy: !unhealthy,
|
|
203
|
+
unhealthy: unhealthy,
|
|
204
|
+
collateral,
|
|
205
|
+
debt,
|
|
206
|
+
risk,
|
|
207
|
+
riskRatio,
|
|
208
|
+
leverageRatio,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Check if account is healthy (pure computation)
|
|
213
|
+
* Takes pre-fetched pool data, account status, and prices
|
|
214
|
+
*/
|
|
215
|
+
function isHealthyFromData(poolData, accountStatus, prices, syntheticCompositions, vaultCompositions = {}) {
|
|
216
|
+
const simulatedPoolData = simulateAccrueInterest(poolData);
|
|
217
|
+
const decomposed = decomposePositions(accountStatus, syntheticCompositions, vaultCompositions);
|
|
218
|
+
return calculateRisk(decomposed, prices, simulatedPoolData);
|
|
219
|
+
}
|