@perena/vault-sdk 1.0.23 → 1.0.25
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/index.d.ts +322 -157
- package/dist/index.js +1479 -284
- package/package.json +5 -1
package/dist/index.js
CHANGED
|
@@ -250,9 +250,9 @@ var require_meta = __commonJS({
|
|
|
250
250
|
exports2.toCustomAccountMeta = toCustomAccountMeta;
|
|
251
251
|
exports2.toCustomAccountMetaFromWeb3AccountMeta = toCustomAccountMetaFromWeb3AccountMeta;
|
|
252
252
|
var roles_1 = require_roles();
|
|
253
|
-
function toCustomAccountMeta(
|
|
253
|
+
function toCustomAccountMeta(address12, isWritable, requiredAtaDetails, isSigner) {
|
|
254
254
|
const role = (0, roles_1.getAccountRole)(isWritable ?? false, isSigner ?? false);
|
|
255
|
-
return { address:
|
|
255
|
+
return { address: address12, role, isRequiredAta: requiredAtaDetails };
|
|
256
256
|
}
|
|
257
257
|
function toCustomAccountMetaFromWeb3AccountMeta(web3AccountMeta) {
|
|
258
258
|
return toCustomAccountMeta(web3AccountMeta.pubkey.toBase58(), web3AccountMeta.isWritable, void 0, web3AccountMeta.isSigner);
|
|
@@ -611,12 +611,12 @@ var require_transaction = __commonJS({
|
|
|
611
611
|
async function sendVersionedTransaction({ connection, payer, instructions: instructions2, lookupTables }) {
|
|
612
612
|
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash("confirmed");
|
|
613
613
|
const lookupTableAccounts = await fetchLookupTables(connection, lookupTables);
|
|
614
|
-
const
|
|
614
|
+
const message2 = new web3_js_1.TransactionMessage({
|
|
615
615
|
payerKey: payer.publicKey,
|
|
616
616
|
recentBlockhash: blockhash,
|
|
617
617
|
instructions: instructions2
|
|
618
618
|
}).compileToV0Message(lookupTableAccounts);
|
|
619
|
-
const tx = new web3_js_1.VersionedTransaction(
|
|
619
|
+
const tx = new web3_js_1.VersionedTransaction(message2);
|
|
620
620
|
tx.sign([payer]);
|
|
621
621
|
const signature = await connection.sendRawTransaction(tx.serialize(), {
|
|
622
622
|
skipPreflight: true
|
|
@@ -1200,8 +1200,8 @@ var require_cpiClient = __commonJS({
|
|
|
1200
1200
|
var kit_1 = require("@solana/kit");
|
|
1201
1201
|
var common_1 = require_dist();
|
|
1202
1202
|
var constants_1 = require_constants3();
|
|
1203
|
-
function account(
|
|
1204
|
-
return { address:
|
|
1203
|
+
function account(address12, role) {
|
|
1204
|
+
return { address: address12, role };
|
|
1205
1205
|
}
|
|
1206
1206
|
function requiredAddress(value, label) {
|
|
1207
1207
|
if (!value) {
|
|
@@ -1290,7 +1290,7 @@ var require_cpiClient = __commonJS({
|
|
|
1290
1290
|
});
|
|
1291
1291
|
const bankAndOracleRemainingAccounts = [
|
|
1292
1292
|
account(this.accounts.bank, kit_1.AccountRole.READONLY),
|
|
1293
|
-
...this.accounts.oracleAccounts.map((
|
|
1293
|
+
...this.accounts.oracleAccounts.map((address12) => account(address12, kit_1.AccountRole.READONLY))
|
|
1294
1294
|
];
|
|
1295
1295
|
return {
|
|
1296
1296
|
cpiType: params.cpiType ?? common_1.CpiTypes.MARGINFI_WITHDRAW,
|
|
@@ -1414,11 +1414,17 @@ __export(index_exports, {
|
|
|
1414
1414
|
JupiterPriceSource: () => JupiterPriceSource,
|
|
1415
1415
|
JupiterSwapBuilder: () => JupiterSwapBuilder,
|
|
1416
1416
|
KaminoPositionProvider: () => KaminoPositionProvider,
|
|
1417
|
+
LOCAL_PROTOCOL_ADMIN: () => LOCAL_PROTOCOL_ADMIN,
|
|
1418
|
+
LivePriceSource: () => LivePriceSource,
|
|
1417
1419
|
MAX_PRICE_STALENESS_THRESHOLD_SECS: () => MAX_PRICE_STALENESS_THRESHOLD_SECS,
|
|
1418
1420
|
ManagerRedepositAssetBuilder: () => ManagerRedepositAssetBuilder,
|
|
1419
1421
|
ManagerWithdrawAssetBuilder: () => ManagerWithdrawAssetBuilder,
|
|
1420
1422
|
MarginfiPositionProvider: () => MarginfiPositionProvider,
|
|
1421
1423
|
MockYieldTracker: () => MockYieldTracker,
|
|
1424
|
+
NEST_API_BASE_URL: () => NEST_API_BASE_URL,
|
|
1425
|
+
NEST_RWA_SHARE_MINT: () => NEST_RWA_SHARE_MINT,
|
|
1426
|
+
NEST_VAULT_SLUG: () => NEST_VAULT_SLUG,
|
|
1427
|
+
NestPriceSource: () => NestPriceSource,
|
|
1422
1428
|
OracleService: () => OracleService,
|
|
1423
1429
|
PROGRAM_FEE_EXEMPT_OWNER_WHITELIST: () => PROGRAM_FEE_EXEMPT_OWNER_WHITELIST,
|
|
1424
1430
|
PROTOCOL_ADMIN: () => PROTOCOL_ADMIN,
|
|
@@ -1461,6 +1467,7 @@ __export(index_exports, {
|
|
|
1461
1467
|
WithdrawalQueueService: () => WithdrawalQueueService,
|
|
1462
1468
|
addCashflowUpdate: () => addCashflowUpdate,
|
|
1463
1469
|
address: () => import_kit10.address,
|
|
1470
|
+
applyEffectiveApy: () => applyEffectiveApy,
|
|
1464
1471
|
confirmYieldPayment: () => confirmYieldPayment,
|
|
1465
1472
|
createAccount: () => createAccount,
|
|
1466
1473
|
createLiveConsensusOracleDeps: () => createLiveConsensusOracleDeps,
|
|
@@ -1472,7 +1479,9 @@ __export(index_exports, {
|
|
|
1472
1479
|
dateToStr: () => dateToStr,
|
|
1473
1480
|
defaultKeypairPath: () => defaultKeypairPath,
|
|
1474
1481
|
deleteAccount: () => deleteAccount,
|
|
1482
|
+
fetchNestTokenPrice: () => fetchNestTokenPrice,
|
|
1475
1483
|
findSquadsWalletRoute: () => findSquadsWalletRoute,
|
|
1484
|
+
formatSettlementSimulation: () => formatSettlementSimulation,
|
|
1476
1485
|
fromUiAmount: () => fromUiAmount,
|
|
1477
1486
|
getAccounts: () => getAccounts,
|
|
1478
1487
|
getBalance: () => getBalance,
|
|
@@ -1493,6 +1502,7 @@ __export(index_exports, {
|
|
|
1493
1502
|
resolveSquadsWalletRoute: () => resolveSquadsWalletRoute,
|
|
1494
1503
|
roundToNextUtcMidnight: () => roundToNextUtcMidnight,
|
|
1495
1504
|
runLiveConsensusOracle: () => runLiveConsensusOracle,
|
|
1505
|
+
simulateConsensusOracleSettlement: () => simulateConsensusOracleSettlement,
|
|
1496
1506
|
systemClock: () => systemClock,
|
|
1497
1507
|
toUiAmount: () => toUiAmount,
|
|
1498
1508
|
updateAccount: () => updateAccount,
|
|
@@ -1511,6 +1521,9 @@ var VAULT_PROGRAM_ID = (0, import_kit.address)(
|
|
|
1511
1521
|
);
|
|
1512
1522
|
var VAULT_PROGRAM_PUBLIC_KEY = new import_web3.PublicKey(VAULT_PROGRAM_ID);
|
|
1513
1523
|
var PROTOCOL_ADMIN = (0, import_kit.address)(
|
|
1524
|
+
"4jMRBkpWrfhhwFYTwG3o7hmsXQwbJUwdyUX8htB6KwLJ"
|
|
1525
|
+
);
|
|
1526
|
+
var LOCAL_PROTOCOL_ADMIN = (0, import_kit.address)(
|
|
1514
1527
|
"BQJZAhDnvgSGHjdAbzQEXRBYzSBuWgSYqDzhDnUSRWGR"
|
|
1515
1528
|
);
|
|
1516
1529
|
var PROTOCOL_FEE_RECIPIENT = (0, import_kit.address)(
|
|
@@ -1519,10 +1532,11 @@ var PROTOCOL_FEE_RECIPIENT = (0, import_kit.address)(
|
|
|
1519
1532
|
var PROGRAM_FEE_EXEMPT_OWNER_WHITELIST = [
|
|
1520
1533
|
(0, import_kit.address)("Hobbakk1LmW2DhE4nAKnCeU1iK7V7pKHTq3ihaE2i8qG"),
|
|
1521
1534
|
(0, import_kit.address)("7C39GeKrqLygmgV9D4bicUaiyFhKrX6Eevk6PDACwuj7"),
|
|
1522
|
-
(0, import_kit.address)("LYC8YiiSzQfPpxUW2tpxfuPKGZwywAJhXKUfDP2B66f")
|
|
1535
|
+
(0, import_kit.address)("LYC8YiiSzQfPpxUW2tpxfuPKGZwywAJhXKUfDP2B66f"),
|
|
1536
|
+
(0, import_kit.address)("soBBAHNhFyWF4QBCK9BJLVkX6d6NZt37ozNaPV5aq3H")
|
|
1523
1537
|
];
|
|
1524
1538
|
var VAULT_CREATOR_WHITELIST = [
|
|
1525
|
-
(0, import_kit.address)("
|
|
1539
|
+
(0, import_kit.address)("4jMRBkpWrfhhwFYTwG3o7hmsXQwbJUwdyUX8htB6KwLJ")
|
|
1526
1540
|
];
|
|
1527
1541
|
var TOKEN_PROGRAM_ID = (0, import_kit.address)(
|
|
1528
1542
|
import_spl_token.TOKEN_2022_PROGRAM_ID.toBase58()
|
|
@@ -1768,8 +1782,7 @@ var IDL = {
|
|
|
1768
1782
|
{
|
|
1769
1783
|
"name": "fee_asset_mint",
|
|
1770
1784
|
"docs": [
|
|
1771
|
-
"
|
|
1772
|
-
"an `is_base` holding; choose a mint whose vault ATA has liquidity."
|
|
1785
|
+
"Legacy fee-asset account retained in this instruction's account schema."
|
|
1773
1786
|
]
|
|
1774
1787
|
},
|
|
1775
1788
|
{
|
|
@@ -1832,7 +1845,7 @@ var IDL = {
|
|
|
1832
1845
|
{
|
|
1833
1846
|
"name": "fee_vault",
|
|
1834
1847
|
"docs": [
|
|
1835
|
-
"
|
|
1848
|
+
"Legacy fee-vault account retained in this instruction's account schema."
|
|
1836
1849
|
],
|
|
1837
1850
|
"writable": true
|
|
1838
1851
|
},
|
|
@@ -1926,84 +1939,18 @@ var IDL = {
|
|
|
1926
1939
|
"signer": true
|
|
1927
1940
|
},
|
|
1928
1941
|
{
|
|
1929
|
-
"name": "vault"
|
|
1930
|
-
},
|
|
1931
|
-
{
|
|
1932
|
-
"name": "fee_asset_mint",
|
|
1933
|
-
"docs": [
|
|
1934
|
-
"Vault base asset whose fee-vault ATA should be swept. Must match an",
|
|
1935
|
-
"`is_base` holding with a fresh price."
|
|
1936
|
-
]
|
|
1937
|
-
},
|
|
1938
|
-
{
|
|
1939
|
-
"name": "fee_vault",
|
|
1940
|
-
"docs": [
|
|
1941
|
-
"Per-vault fee-vault PDA: token authority + accounting for accrued fees."
|
|
1942
|
-
],
|
|
1942
|
+
"name": "vault",
|
|
1943
1943
|
"writable": true
|
|
1944
1944
|
},
|
|
1945
1945
|
{
|
|
1946
|
-
"name": "
|
|
1947
|
-
"writable": true
|
|
1948
|
-
"pda": {
|
|
1949
|
-
"seeds": [
|
|
1950
|
-
{
|
|
1951
|
-
"kind": "account",
|
|
1952
|
-
"path": "fee_vault"
|
|
1953
|
-
},
|
|
1954
|
-
{
|
|
1955
|
-
"kind": "account",
|
|
1956
|
-
"path": "fee_asset_token_program"
|
|
1957
|
-
},
|
|
1958
|
-
{
|
|
1959
|
-
"kind": "account",
|
|
1960
|
-
"path": "fee_asset_mint"
|
|
1961
|
-
}
|
|
1962
|
-
],
|
|
1963
|
-
"program": {
|
|
1964
|
-
"kind": "const",
|
|
1965
|
-
"value": [
|
|
1966
|
-
140,
|
|
1967
|
-
151,
|
|
1968
|
-
37,
|
|
1969
|
-
143,
|
|
1970
|
-
78,
|
|
1971
|
-
36,
|
|
1972
|
-
137,
|
|
1973
|
-
241,
|
|
1974
|
-
187,
|
|
1975
|
-
61,
|
|
1976
|
-
16,
|
|
1977
|
-
41,
|
|
1978
|
-
20,
|
|
1979
|
-
142,
|
|
1980
|
-
13,
|
|
1981
|
-
131,
|
|
1982
|
-
11,
|
|
1983
|
-
90,
|
|
1984
|
-
19,
|
|
1985
|
-
153,
|
|
1986
|
-
218,
|
|
1987
|
-
255,
|
|
1988
|
-
16,
|
|
1989
|
-
132,
|
|
1990
|
-
4,
|
|
1991
|
-
142,
|
|
1992
|
-
123,
|
|
1993
|
-
216,
|
|
1994
|
-
219,
|
|
1995
|
-
233,
|
|
1996
|
-
248,
|
|
1997
|
-
89
|
|
1998
|
-
]
|
|
1999
|
-
}
|
|
2000
|
-
}
|
|
1946
|
+
"name": "share_mint",
|
|
1947
|
+
"writable": true
|
|
2001
1948
|
},
|
|
2002
1949
|
{
|
|
2003
1950
|
"name": "fee_collector"
|
|
2004
1951
|
},
|
|
2005
1952
|
{
|
|
2006
|
-
"name": "
|
|
1953
|
+
"name": "fee_collector_share_ata",
|
|
2007
1954
|
"writable": true,
|
|
2008
1955
|
"pda": {
|
|
2009
1956
|
"seeds": [
|
|
@@ -2013,11 +1960,11 @@ var IDL = {
|
|
|
2013
1960
|
},
|
|
2014
1961
|
{
|
|
2015
1962
|
"kind": "account",
|
|
2016
|
-
"path": "
|
|
1963
|
+
"path": "share_token_program"
|
|
2017
1964
|
},
|
|
2018
1965
|
{
|
|
2019
1966
|
"kind": "account",
|
|
2020
|
-
"path": "
|
|
1967
|
+
"path": "share_mint"
|
|
2021
1968
|
}
|
|
2022
1969
|
],
|
|
2023
1970
|
"program": {
|
|
@@ -2063,7 +2010,7 @@ var IDL = {
|
|
|
2063
2010
|
"name": "protocol_fee_collector"
|
|
2064
2011
|
},
|
|
2065
2012
|
{
|
|
2066
|
-
"name": "
|
|
2013
|
+
"name": "protocol_fee_collector_share_ata",
|
|
2067
2014
|
"writable": true,
|
|
2068
2015
|
"pda": {
|
|
2069
2016
|
"seeds": [
|
|
@@ -2073,11 +2020,11 @@ var IDL = {
|
|
|
2073
2020
|
},
|
|
2074
2021
|
{
|
|
2075
2022
|
"kind": "account",
|
|
2076
|
-
"path": "
|
|
2023
|
+
"path": "share_token_program"
|
|
2077
2024
|
},
|
|
2078
2025
|
{
|
|
2079
2026
|
"kind": "account",
|
|
2080
|
-
"path": "
|
|
2027
|
+
"path": "share_mint"
|
|
2081
2028
|
}
|
|
2082
2029
|
],
|
|
2083
2030
|
"program": {
|
|
@@ -2120,7 +2067,7 @@ var IDL = {
|
|
|
2120
2067
|
}
|
|
2121
2068
|
},
|
|
2122
2069
|
{
|
|
2123
|
-
"name": "
|
|
2070
|
+
"name": "share_token_program"
|
|
2124
2071
|
},
|
|
2125
2072
|
{
|
|
2126
2073
|
"name": "associated_token_program",
|
|
@@ -3003,7 +2950,9 @@ var IDL = {
|
|
|
3003
2950
|
{
|
|
3004
2951
|
"name": "share_mint",
|
|
3005
2952
|
"docs": [
|
|
3006
|
-
"Curator-supplied share mint. Its decimals
|
|
2953
|
+
"Curator-supplied share mint. Its decimals define the vault accounting",
|
|
2954
|
+
"precision. `asset_mint` may use a different precision, which is stored",
|
|
2955
|
+
"on its holding and handled by holding-price conversion.",
|
|
3007
2956
|
"Unless `for_migration`, it must have zero supply with mint authority on",
|
|
3008
2957
|
"the curator; authority is transferred to the vault PDA on success.",
|
|
3009
2958
|
"Migration uses the legacy bank mint and defers transfer."
|
|
@@ -3227,8 +3176,8 @@ var IDL = {
|
|
|
3227
3176
|
{
|
|
3228
3177
|
"name": "fee_vault",
|
|
3229
3178
|
"docs": [
|
|
3230
|
-
"
|
|
3231
|
-
"
|
|
3179
|
+
"Legacy fee-vault account retained in this instruction's account schema.",
|
|
3180
|
+
"New fees accrue as pending vault shares."
|
|
3232
3181
|
],
|
|
3233
3182
|
"writable": true
|
|
3234
3183
|
},
|
|
@@ -3522,8 +3471,8 @@ var IDL = {
|
|
|
3522
3471
|
{
|
|
3523
3472
|
"name": "fee_vault",
|
|
3524
3473
|
"docs": [
|
|
3525
|
-
"
|
|
3526
|
-
"
|
|
3474
|
+
"Legacy fee-vault account retained in this instruction's account schema.",
|
|
3475
|
+
"New fees accrue as pending vault shares."
|
|
3527
3476
|
],
|
|
3528
3477
|
"writable": true
|
|
3529
3478
|
},
|
|
@@ -4018,8 +3967,8 @@ var IDL = {
|
|
|
4018
3967
|
{
|
|
4019
3968
|
"name": "fee_vault",
|
|
4020
3969
|
"docs": [
|
|
4021
|
-
"
|
|
4022
|
-
"
|
|
3970
|
+
"Legacy fee-vault account retained in this instruction's account schema.",
|
|
3971
|
+
"New fees accrue as pending vault shares."
|
|
4023
3972
|
],
|
|
4024
3973
|
"writable": true
|
|
4025
3974
|
},
|
|
@@ -4320,8 +4269,8 @@ var IDL = {
|
|
|
4320
4269
|
{
|
|
4321
4270
|
"name": "fee_vault",
|
|
4322
4271
|
"docs": [
|
|
4323
|
-
"
|
|
4324
|
-
"
|
|
4272
|
+
"Legacy fee-vault account retained in this instruction's account schema.",
|
|
4273
|
+
"New fees accrue as pending vault shares."
|
|
4325
4274
|
],
|
|
4326
4275
|
"writable": true
|
|
4327
4276
|
},
|
|
@@ -5111,8 +5060,8 @@ var IDL = {
|
|
|
5111
5060
|
{
|
|
5112
5061
|
"name": "fee_vault",
|
|
5113
5062
|
"docs": [
|
|
5114
|
-
"
|
|
5115
|
-
"
|
|
5063
|
+
"Legacy fee-vault account retained in this instruction's account schema.",
|
|
5064
|
+
"New fees accrue as pending vault shares."
|
|
5116
5065
|
],
|
|
5117
5066
|
"writable": true
|
|
5118
5067
|
},
|
|
@@ -5400,8 +5349,8 @@ var IDL = {
|
|
|
5400
5349
|
{
|
|
5401
5350
|
"name": "fee_vault",
|
|
5402
5351
|
"docs": [
|
|
5403
|
-
"
|
|
5404
|
-
"
|
|
5352
|
+
"Legacy fee-vault account retained in this instruction's account schema.",
|
|
5353
|
+
"New fees accrue as pending vault shares."
|
|
5405
5354
|
],
|
|
5406
5355
|
"writable": true
|
|
5407
5356
|
},
|
|
@@ -5695,8 +5644,8 @@ var IDL = {
|
|
|
5695
5644
|
{
|
|
5696
5645
|
"name": "fee_vault",
|
|
5697
5646
|
"docs": [
|
|
5698
|
-
"
|
|
5699
|
-
"
|
|
5647
|
+
"Legacy fee-vault account retained in this instruction's account schema.",
|
|
5648
|
+
"New fees accrue as pending vault shares."
|
|
5700
5649
|
],
|
|
5701
5650
|
"writable": true
|
|
5702
5651
|
},
|
|
@@ -6000,8 +5949,8 @@ var IDL = {
|
|
|
6000
5949
|
{
|
|
6001
5950
|
"name": "fee_vault",
|
|
6002
5951
|
"docs": [
|
|
6003
|
-
"
|
|
6004
|
-
"
|
|
5952
|
+
"Legacy fee-vault account retained in this instruction's account schema.",
|
|
5953
|
+
"New fees accrue as pending vault shares."
|
|
6005
5954
|
],
|
|
6006
5955
|
"writable": true
|
|
6007
5956
|
},
|
|
@@ -7422,9 +7371,6 @@ var IDL = {
|
|
|
7422
7371
|
},
|
|
7423
7372
|
{
|
|
7424
7373
|
"name": "idle_bank_tranche",
|
|
7425
|
-
"docs": [
|
|
7426
|
-
"path rejects initialized state because it cannot represent junior claims."
|
|
7427
|
-
],
|
|
7428
7374
|
"pda": {
|
|
7429
7375
|
"seeds": [
|
|
7430
7376
|
{
|
|
@@ -7583,7 +7529,7 @@ var IDL = {
|
|
|
7583
7529
|
{
|
|
7584
7530
|
"name": "yielding_bank_tranche",
|
|
7585
7531
|
"docs": [
|
|
7586
|
-
"
|
|
7532
|
+
"tranche was already consumed by its regular vault migrations."
|
|
7587
7533
|
],
|
|
7588
7534
|
"pda": {
|
|
7589
7535
|
"seeds": [
|
|
@@ -7761,9 +7707,6 @@ var IDL = {
|
|
|
7761
7707
|
},
|
|
7762
7708
|
{
|
|
7763
7709
|
"name": "vault_tranche_state",
|
|
7764
|
-
"docs": [
|
|
7765
|
-
"be initialized and consistent with destination.tranching_enabled."
|
|
7766
|
-
],
|
|
7767
7710
|
"writable": true,
|
|
7768
7711
|
"pda": {
|
|
7769
7712
|
"seeds": [
|
|
@@ -9787,6 +9730,69 @@ var IDL = {
|
|
|
9787
9730
|
}
|
|
9788
9731
|
]
|
|
9789
9732
|
},
|
|
9733
|
+
{
|
|
9734
|
+
"name": "trigger_bank_circuit_breaker",
|
|
9735
|
+
"discriminator": [
|
|
9736
|
+
250,
|
|
9737
|
+
236,
|
|
9738
|
+
165,
|
|
9739
|
+
211,
|
|
9740
|
+
181,
|
|
9741
|
+
241,
|
|
9742
|
+
74,
|
|
9743
|
+
84
|
|
9744
|
+
],
|
|
9745
|
+
"accounts": [
|
|
9746
|
+
{
|
|
9747
|
+
"name": "bank_state",
|
|
9748
|
+
"writable": true,
|
|
9749
|
+
"pda": {
|
|
9750
|
+
"seeds": [
|
|
9751
|
+
{
|
|
9752
|
+
"kind": "const",
|
|
9753
|
+
"value": [
|
|
9754
|
+
66,
|
|
9755
|
+
65,
|
|
9756
|
+
78,
|
|
9757
|
+
75
|
|
9758
|
+
]
|
|
9759
|
+
},
|
|
9760
|
+
{
|
|
9761
|
+
"kind": "account",
|
|
9762
|
+
"path": "bank_state"
|
|
9763
|
+
}
|
|
9764
|
+
]
|
|
9765
|
+
}
|
|
9766
|
+
},
|
|
9767
|
+
{
|
|
9768
|
+
"name": "bank_manager",
|
|
9769
|
+
"writable": true,
|
|
9770
|
+
"signer": true
|
|
9771
|
+
},
|
|
9772
|
+
{
|
|
9773
|
+
"name": "system_program",
|
|
9774
|
+
"address": "11111111111111111111111111111111"
|
|
9775
|
+
},
|
|
9776
|
+
{
|
|
9777
|
+
"name": "token_program",
|
|
9778
|
+
"address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
|
|
9779
|
+
}
|
|
9780
|
+
],
|
|
9781
|
+
"args": [
|
|
9782
|
+
{
|
|
9783
|
+
"name": "is_halted",
|
|
9784
|
+
"type": "bool"
|
|
9785
|
+
},
|
|
9786
|
+
{
|
|
9787
|
+
"name": "is_halted_deposit",
|
|
9788
|
+
"type": "bool"
|
|
9789
|
+
},
|
|
9790
|
+
{
|
|
9791
|
+
"name": "is_halted_withdrawal",
|
|
9792
|
+
"type": "bool"
|
|
9793
|
+
}
|
|
9794
|
+
]
|
|
9795
|
+
},
|
|
9790
9796
|
{
|
|
9791
9797
|
"name": "trigger_vault_circuit_breaker",
|
|
9792
9798
|
"discriminator": [
|
|
@@ -10458,11 +10464,11 @@ var IDL = {
|
|
|
10458
10464
|
"name": "vault_oracle",
|
|
10459
10465
|
"docs": [
|
|
10460
10466
|
"Required when enabling tranching organically (`for_migration == false`)",
|
|
10461
|
-
"on a vault that still has main shareholders accruing fixed APY
|
|
10462
|
-
"
|
|
10463
|
-
"
|
|
10464
|
-
"
|
|
10465
|
-
"
|
|
10467
|
+
"on a vault that still has main shareholders accruing fixed APY. A fresh",
|
|
10468
|
+
"settlement establishes the regular sleeve's booked NAV and physical",
|
|
10469
|
+
"surplus immediately before the new tranche sleeve is introduced. Not",
|
|
10470
|
+
"needed on the migration path, whose accounting is reconstructed wholesale",
|
|
10471
|
+
"from the legacy state.",
|
|
10466
10472
|
"",
|
|
10467
10473
|
"Kept LAST (a trailing optional account) so legacy clients that predate it",
|
|
10468
10474
|
"\u2014 e.g. the migration path building against the frozen bankineco IDL \u2014",
|
|
@@ -10548,8 +10554,8 @@ var IDL = {
|
|
|
10548
10554
|
{
|
|
10549
10555
|
"name": "destination_fee_vault",
|
|
10550
10556
|
"docs": [
|
|
10551
|
-
"
|
|
10552
|
-
"
|
|
10557
|
+
"Legacy fee-vault account retained in this instruction's account schema.",
|
|
10558
|
+
"New fees accrue as pending vault shares."
|
|
10553
10559
|
],
|
|
10554
10560
|
"writable": true
|
|
10555
10561
|
},
|
|
@@ -11866,21 +11872,11 @@ var IDL = {
|
|
|
11866
11872
|
{
|
|
11867
11873
|
"name": "FeeVault",
|
|
11868
11874
|
"docs": [
|
|
11869
|
-
"
|
|
11870
|
-
"",
|
|
11871
|
-
"The PDA is both the token authority over the fee-asset ATAs that physically",
|
|
11872
|
-
"hold accrued fees and the ledger of what is owed to whom. All four fee types",
|
|
11873
|
-
"\u2014 mint, burn, performance, and protocol \u2014 accrue here.",
|
|
11874
|
-
"",
|
|
11875
|
-
"Ledger amounts (`*_owed` / `*_collected`) are denominated in the vault's",
|
|
11876
|
-
"**accounting unit** (the same unit as TVL / holding prices), not raw token",
|
|
11877
|
-
"units. Token custody may still be split across ATAs for different base-asset",
|
|
11878
|
-
"mints; the permissionless fee crank converts each ATA's balance to accounting",
|
|
11879
|
-
"value via that mint's fresh holding price, pays out, and reduces these",
|
|
11880
|
-
"counters by the accounting value cleared.",
|
|
11875
|
+
"Legacy per-vault fee custody account.",
|
|
11881
11876
|
"",
|
|
11882
|
-
"
|
|
11883
|
-
"
|
|
11877
|
+
"New fee accrual is denominated in canonical vault shares and stored on",
|
|
11878
|
+
"`VaultAccounting`. This account remains in existing instruction schemas for",
|
|
11879
|
+
"compatibility; its historical accounting-unit counters are no longer updated."
|
|
11884
11880
|
],
|
|
11885
11881
|
"serialization": "bytemuck",
|
|
11886
11882
|
"repr": {
|
|
@@ -12105,8 +12101,9 @@ var IDL = {
|
|
|
12105
12101
|
{
|
|
12106
12102
|
"name": "migrate_amount",
|
|
12107
12103
|
"docs": [
|
|
12108
|
-
"
|
|
12109
|
-
"
|
|
12104
|
+
"Partial migration remains unsupported. `None` performs a regular full",
|
|
12105
|
+
"vault migration; `Some(0)` explicitly marks the final in-scope vault and",
|
|
12106
|
+
"permits bounded terminal source-accounting reconciliation."
|
|
12110
12107
|
],
|
|
12111
12108
|
"type": {
|
|
12112
12109
|
"option": "u64"
|
|
@@ -13412,8 +13409,7 @@ var IDL = {
|
|
|
13412
13409
|
{
|
|
13413
13410
|
"name": "_padding_bool",
|
|
13414
13411
|
"docs": [
|
|
13415
|
-
"Reserved
|
|
13416
|
-
"preserve the on-chain account layout for already-deployed vaults."
|
|
13412
|
+
"Reserved byte retained for on-chain account layout compatibility."
|
|
13417
13413
|
],
|
|
13418
13414
|
"type": {
|
|
13419
13415
|
"defined": {
|
|
@@ -13724,7 +13720,7 @@ var IDL = {
|
|
|
13724
13720
|
{
|
|
13725
13721
|
"name": "tvl_limit",
|
|
13726
13722
|
"docs": [
|
|
13727
|
-
"Maximum TVL in
|
|
13723
|
+
"Maximum TVL in vault accounting units. `0` disables the cap."
|
|
13728
13724
|
],
|
|
13729
13725
|
"type": "u64"
|
|
13730
13726
|
},
|
|
@@ -14784,7 +14780,7 @@ var IDL = {
|
|
|
14784
14780
|
{
|
|
14785
14781
|
"name": "total_mint_supply",
|
|
14786
14782
|
"docs": [
|
|
14787
|
-
"
|
|
14783
|
+
"Effective share supply: physical mint supply plus unminted fee shares."
|
|
14788
14784
|
],
|
|
14789
14785
|
"type": "u64"
|
|
14790
14786
|
},
|
|
@@ -14838,12 +14834,26 @@ var IDL = {
|
|
|
14838
14834
|
}
|
|
14839
14835
|
}
|
|
14840
14836
|
},
|
|
14837
|
+
{
|
|
14838
|
+
"name": "pending_curator_fee_shares",
|
|
14839
|
+
"docs": [
|
|
14840
|
+
"Vault shares owed to the curator but not yet minted."
|
|
14841
|
+
],
|
|
14842
|
+
"type": "u64"
|
|
14843
|
+
},
|
|
14844
|
+
{
|
|
14845
|
+
"name": "pending_protocol_fee_shares",
|
|
14846
|
+
"docs": [
|
|
14847
|
+
"Vault shares owed to the protocol but not yet minted."
|
|
14848
|
+
],
|
|
14849
|
+
"type": "u64"
|
|
14850
|
+
},
|
|
14841
14851
|
{
|
|
14842
14852
|
"name": "_padding1",
|
|
14843
14853
|
"type": {
|
|
14844
14854
|
"array": [
|
|
14845
14855
|
"u64",
|
|
14846
|
-
|
|
14856
|
+
30
|
|
14847
14857
|
]
|
|
14848
14858
|
}
|
|
14849
14859
|
},
|
|
@@ -14892,8 +14902,8 @@ var IDL = {
|
|
|
14892
14902
|
{
|
|
14893
14903
|
"name": "asset_decimals",
|
|
14894
14904
|
"docs": [
|
|
14895
|
-
"
|
|
14896
|
-
"
|
|
14905
|
+
"Vault accounting precision. This matches the vault share mint; each",
|
|
14906
|
+
"holding stores its own mint precision independently."
|
|
14897
14907
|
],
|
|
14898
14908
|
"type": "u8"
|
|
14899
14909
|
},
|
|
@@ -14925,7 +14935,7 @@ var IDL = {
|
|
|
14925
14935
|
{
|
|
14926
14936
|
"name": "tvl_limit",
|
|
14927
14937
|
"docs": [
|
|
14928
|
-
"Maximum TVL in
|
|
14938
|
+
"Maximum TVL in vault accounting units. `0` disables the cap."
|
|
14929
14939
|
],
|
|
14930
14940
|
"type": "u64"
|
|
14931
14941
|
},
|
|
@@ -15709,8 +15719,8 @@ function coerceBool(value) {
|
|
|
15709
15719
|
if (value && typeof value.toBool === "function") {
|
|
15710
15720
|
return value.toBool();
|
|
15711
15721
|
}
|
|
15712
|
-
const
|
|
15713
|
-
return Boolean(
|
|
15722
|
+
const record2 = value;
|
|
15723
|
+
return Boolean(record2?.value ?? record2?.[0]);
|
|
15714
15724
|
}
|
|
15715
15725
|
|
|
15716
15726
|
// src/client/builders/base.ts
|
|
@@ -15746,8 +15756,8 @@ function coerceBool2(value) {
|
|
|
15746
15756
|
if (value && typeof value.toBool === "function") {
|
|
15747
15757
|
return value.toBool();
|
|
15748
15758
|
}
|
|
15749
|
-
const
|
|
15750
|
-
return Boolean(
|
|
15759
|
+
const record2 = value;
|
|
15760
|
+
return Boolean(record2?.value ?? record2?.[0]);
|
|
15751
15761
|
}
|
|
15752
15762
|
function pubkeyToAddress(value) {
|
|
15753
15763
|
if (typeof value === "string") return (0, import_kit5.address)(value);
|
|
@@ -15757,8 +15767,8 @@ function pubkeyToAddress(value) {
|
|
|
15757
15767
|
return (0, import_kit5.address)(String(value));
|
|
15758
15768
|
}
|
|
15759
15769
|
function tokenProgramAddressFromIdlEnum(value) {
|
|
15760
|
-
const
|
|
15761
|
-
if (
|
|
15770
|
+
const record2 = value;
|
|
15771
|
+
if (record2 && "token2022" in record2) {
|
|
15762
15772
|
return TOKEN_PROGRAM_ID;
|
|
15763
15773
|
}
|
|
15764
15774
|
return (0, import_kit5.address)(import_spl_token2.TOKEN_PROGRAM_ID.toBase58());
|
|
@@ -16132,7 +16142,7 @@ var CreateVaultBuilder = class extends VaultBuilderBase {
|
|
|
16132
16142
|
const [vault] = await this.pda.deriveVaultPda(vaultId);
|
|
16133
16143
|
const [vaultOracle] = await this.pda.deriveVaultOraclePda(vault);
|
|
16134
16144
|
const [feeVault] = await this.pda.deriveFeeAuthorityPda(vault);
|
|
16135
|
-
const
|
|
16145
|
+
const accountingDecimals = (await (0, import_token.fetchMint)(this.rpc, txArgs.shareMint)).data.decimals;
|
|
16136
16146
|
return {
|
|
16137
16147
|
curator: txArgs.curator,
|
|
16138
16148
|
vault,
|
|
@@ -16157,7 +16167,7 @@ var CreateVaultBuilder = class extends VaultBuilderBase {
|
|
|
16157
16167
|
initialMintSharePrice: null,
|
|
16158
16168
|
basePriceOracleType: txArgs.basePriceOracleType ?? 1,
|
|
16159
16169
|
basePrice: new import_core3.BN(
|
|
16160
|
-
(txArgs.basePrice ?? 10n ** BigInt(
|
|
16170
|
+
(txArgs.basePrice ?? 10n ** BigInt(accountingDecimals)).toString()
|
|
16161
16171
|
),
|
|
16162
16172
|
basePriceOracleAccount: txArgs.basePriceOracleAccount ?? DEFAULT_PRICE_ORACLE_ACCOUNT,
|
|
16163
16173
|
forMigration: txArgs.forMigration ?? false
|
|
@@ -16333,8 +16343,9 @@ var SetProtocolFeeBuilder = class extends VaultBuilderBase {
|
|
|
16333
16343
|
const [derivedVaultOracle] = await this.pda.deriveVaultOraclePda(
|
|
16334
16344
|
txArgs.vault
|
|
16335
16345
|
);
|
|
16346
|
+
const defaultProtocolAuthority = this.program.programId.toBase58() === VAULT_PROGRAM_ID ? LOCAL_PROTOCOL_ADMIN : PROTOCOL_ADMIN;
|
|
16336
16347
|
return {
|
|
16337
|
-
protocolAuthority: txArgs.protocolAuthority ??
|
|
16348
|
+
protocolAuthority: txArgs.protocolAuthority ?? defaultProtocolAuthority,
|
|
16338
16349
|
vault: txArgs.vault,
|
|
16339
16350
|
vaultOracle: txArgs.vaultOracle ?? derivedVaultOracle,
|
|
16340
16351
|
args: {
|
|
@@ -16531,82 +16542,53 @@ var CrankPerformanceFeesBuilder = class extends VaultBuilderBase {
|
|
|
16531
16542
|
return this.program.methods.crankPerformanceFees().accountsPartial({
|
|
16532
16543
|
cranker: (0, import_common18.toWeb3Pk)(args.cranker),
|
|
16533
16544
|
vault: (0, import_common18.toWeb3Pk)(args.vault),
|
|
16534
|
-
|
|
16535
|
-
feeVault: (0, import_common18.toWeb3Pk)(args.feeVault),
|
|
16536
|
-
feeVaultAta: (0, import_common18.toWeb3Pk)(args.feeVaultAta),
|
|
16545
|
+
shareMint: (0, import_common18.toWeb3Pk)(args.shareMint),
|
|
16537
16546
|
feeCollector: (0, import_common18.toWeb3Pk)(args.feeCollector),
|
|
16538
|
-
|
|
16547
|
+
feeCollectorShareAta: (0, import_common18.toWeb3Pk)(args.feeCollectorShareAta),
|
|
16539
16548
|
protocolFeeCollector: (0, import_common18.toWeb3Pk)(args.protocolFeeCollector),
|
|
16540
|
-
|
|
16541
|
-
args.
|
|
16549
|
+
protocolFeeCollectorShareAta: (0, import_common18.toWeb3Pk)(
|
|
16550
|
+
args.protocolFeeCollectorShareAta
|
|
16542
16551
|
),
|
|
16543
|
-
|
|
16552
|
+
shareTokenProgram: (0, import_common18.toWeb3Pk)(args.shareTokenProgram),
|
|
16544
16553
|
associatedTokenProgram: import_spl_token6.ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
16545
16554
|
systemProgram: import_web38.SystemProgram.programId
|
|
16546
16555
|
}).instruction().then(import_common18.toKitInstruction);
|
|
16547
16556
|
}
|
|
16548
16557
|
async deriveIxArgs(txArgs) {
|
|
16549
|
-
const
|
|
16558
|
+
const vaultState = await this.account.fetchVault(txArgs.vault);
|
|
16559
|
+
const shareMint = (0, import_common18.fromWeb3Pk)(vaultState.mint);
|
|
16560
|
+
const shareTokenProgram = txArgs.shareTokenProgram ?? tokenProgramAddressFromIdlEnum(vaultState.mintTokenProgram);
|
|
16561
|
+
const feeCollector = await resolveVaultFeeCollector(
|
|
16550
16562
|
this.account,
|
|
16551
16563
|
txArgs.vault,
|
|
16552
|
-
txArgs.
|
|
16564
|
+
txArgs.feeCollector
|
|
16553
16565
|
);
|
|
16554
|
-
const [feeVault] = await this.pda.deriveFeeAuthorityPda(txArgs.vault);
|
|
16555
|
-
const [feeCollector, feeAssetTokenProgram] = await Promise.all([
|
|
16556
|
-
resolveVaultFeeCollector(this.account, txArgs.vault, txArgs.feeCollector),
|
|
16557
|
-
resolveFeeAssetTokenProgram(
|
|
16558
|
-
this.account,
|
|
16559
|
-
txArgs.vault,
|
|
16560
|
-
feeAssetMint,
|
|
16561
|
-
txArgs.feeAssetTokenProgram
|
|
16562
|
-
)
|
|
16563
|
-
]);
|
|
16564
16566
|
const protocolFeeCollector = resolveProtocolFeeRecipient(
|
|
16565
16567
|
txArgs.protocolFeeCollector
|
|
16566
16568
|
);
|
|
16567
16569
|
return {
|
|
16568
16570
|
cranker: txArgs.cranker,
|
|
16569
16571
|
vault: txArgs.vault,
|
|
16570
|
-
|
|
16571
|
-
feeVault,
|
|
16572
|
-
feeVaultAta: (0, import_common18.getAtaAddress)(
|
|
16573
|
-
feeAssetMint,
|
|
16574
|
-
feeVault,
|
|
16575
|
-
feeAssetTokenProgram,
|
|
16576
|
-
true
|
|
16577
|
-
),
|
|
16572
|
+
shareMint,
|
|
16578
16573
|
feeCollector,
|
|
16579
|
-
|
|
16580
|
-
|
|
16574
|
+
feeCollectorShareAta: (0, import_common18.getAtaAddress)(
|
|
16575
|
+
shareMint,
|
|
16581
16576
|
feeCollector,
|
|
16582
|
-
|
|
16577
|
+
shareTokenProgram
|
|
16583
16578
|
),
|
|
16584
16579
|
protocolFeeCollector,
|
|
16585
16580
|
// The protocol fee recipient is a hardcoded protocol-controlled address
|
|
16586
16581
|
// that may be off-curve (e.g. a PDA / multisig vault), so allow an
|
|
16587
16582
|
// off-curve owner when deriving its ATA.
|
|
16588
|
-
|
|
16589
|
-
|
|
16583
|
+
protocolFeeCollectorShareAta: (0, import_common18.getAtaAddress)(
|
|
16584
|
+
shareMint,
|
|
16590
16585
|
protocolFeeCollector,
|
|
16591
|
-
|
|
16586
|
+
shareTokenProgram,
|
|
16592
16587
|
true
|
|
16593
16588
|
),
|
|
16594
|
-
|
|
16589
|
+
shareTokenProgram
|
|
16595
16590
|
};
|
|
16596
16591
|
}
|
|
16597
|
-
async buildPreambleInstructions(args) {
|
|
16598
|
-
const payer = (0, import_common18.toWeb3Pk)(args.cranker);
|
|
16599
|
-
return [
|
|
16600
|
-
(0, import_spl_token6.createAssociatedTokenAccountIdempotentInstruction)(
|
|
16601
|
-
payer,
|
|
16602
|
-
(0, import_common18.toWeb3Pk)(args.feeVaultAta),
|
|
16603
|
-
(0, import_common18.toWeb3Pk)(args.feeVault),
|
|
16604
|
-
(0, import_common18.toWeb3Pk)(args.feeAssetMint),
|
|
16605
|
-
(0, import_common18.toWeb3Pk)(args.feeAssetTokenProgram),
|
|
16606
|
-
import_spl_token6.ASSOCIATED_TOKEN_PROGRAM_ID
|
|
16607
|
-
)
|
|
16608
|
-
].map(import_common18.toKitInstruction);
|
|
16609
|
-
}
|
|
16610
16592
|
async buildPlanExtras(args) {
|
|
16611
16593
|
return {
|
|
16612
16594
|
postSuccessCacheInvalidations: [{ vaultPda: args.vault }]
|
|
@@ -16614,11 +16596,10 @@ var CrankPerformanceFeesBuilder = class extends VaultBuilderBase {
|
|
|
16614
16596
|
}
|
|
16615
16597
|
async getTx(txArgs) {
|
|
16616
16598
|
const args = await this.deriveIxArgs(txArgs);
|
|
16617
|
-
const preambleInstructions = await this.buildPreambleInstructions(args);
|
|
16618
16599
|
const instruction = await this.getIx(args);
|
|
16619
16600
|
const extras = await this.buildPlanExtras(args);
|
|
16620
16601
|
return {
|
|
16621
|
-
instructions: [
|
|
16602
|
+
instructions: [instruction],
|
|
16622
16603
|
...extras ?? {}
|
|
16623
16604
|
};
|
|
16624
16605
|
}
|
|
@@ -19287,6 +19268,70 @@ var JupiterPriceSource = class {
|
|
|
19287
19268
|
}
|
|
19288
19269
|
};
|
|
19289
19270
|
|
|
19271
|
+
// src/services/consensusOracle/nestPriceSource.ts
|
|
19272
|
+
var import_kit12 = require("@solana/kit");
|
|
19273
|
+
var NEST_API_BASE_URL = "https://api.nest.credit/v1";
|
|
19274
|
+
var NEST_VAULT_SLUG = "nest-perena-vault";
|
|
19275
|
+
var NEST_RWA_SHARE_MINT = (0, import_kit12.address)(
|
|
19276
|
+
"VyXKJnVhkSkB6KAozSZCiLQbuB1k1r6Nu4etNYVo5LJ"
|
|
19277
|
+
);
|
|
19278
|
+
async function fetchNestTokenPrice(nestVaultSlug = NEST_VAULT_SLUG, opts = {}) {
|
|
19279
|
+
const baseUrl = (opts.baseUrl ?? NEST_API_BASE_URL).replace(/\/$/, "");
|
|
19280
|
+
const response = await (opts.fetchFn ?? fetch)(
|
|
19281
|
+
`${baseUrl}/vaults/${encodeURIComponent(nestVaultSlug)}/price`
|
|
19282
|
+
);
|
|
19283
|
+
if (!response.ok) {
|
|
19284
|
+
throw new Error(
|
|
19285
|
+
`Nest price API request failed: ${response.status} ${response.statusText}`
|
|
19286
|
+
);
|
|
19287
|
+
}
|
|
19288
|
+
const body = await response.json();
|
|
19289
|
+
const price = [body.data?.interpolatedPrice, body.data?.price].map(Number).find((candidate) => Number.isFinite(candidate) && candidate > 0);
|
|
19290
|
+
if (price === void 0) {
|
|
19291
|
+
throw new Error("Nest price API returned no positive share price");
|
|
19292
|
+
}
|
|
19293
|
+
return price;
|
|
19294
|
+
}
|
|
19295
|
+
var NestPriceSource = class {
|
|
19296
|
+
constructor(opts = {}) {
|
|
19297
|
+
this.shareMint = opts.shareMint ?? NEST_RWA_SHARE_MINT;
|
|
19298
|
+
this.nestVaultSlug = opts.nestVaultSlug ?? NEST_VAULT_SLUG;
|
|
19299
|
+
this.options = { baseUrl: opts.baseUrl, fetchFn: opts.fetchFn };
|
|
19300
|
+
}
|
|
19301
|
+
async fetchUsdPrices(mints) {
|
|
19302
|
+
if (!mints.some((mint) => mint.toString() === this.shareMint.toString())) {
|
|
19303
|
+
return {};
|
|
19304
|
+
}
|
|
19305
|
+
return {
|
|
19306
|
+
[this.shareMint.toString()]: await fetchNestTokenPrice(
|
|
19307
|
+
this.nestVaultSlug,
|
|
19308
|
+
this.options
|
|
19309
|
+
)
|
|
19310
|
+
};
|
|
19311
|
+
}
|
|
19312
|
+
};
|
|
19313
|
+
|
|
19314
|
+
// src/services/consensusOracle/livePriceSource.ts
|
|
19315
|
+
var LivePriceSource = class {
|
|
19316
|
+
constructor(opts = {}) {
|
|
19317
|
+
this.jupiter = opts.jupiter ?? new JupiterPriceSource();
|
|
19318
|
+
this.nest = opts.nest ?? new NestPriceSource();
|
|
19319
|
+
}
|
|
19320
|
+
async fetchUsdPrices(mints) {
|
|
19321
|
+
const unique = [
|
|
19322
|
+
...new Map(mints.map((mint) => [mint.toString(), mint])).values()
|
|
19323
|
+
];
|
|
19324
|
+
const nestMint = this.nest.shareMint.toString();
|
|
19325
|
+
const jupiterMints = unique.filter((mint) => mint.toString() !== nestMint);
|
|
19326
|
+
const nestMints = unique.filter((mint) => mint.toString() === nestMint);
|
|
19327
|
+
const [jupiterPrices, nestPrices] = await Promise.all([
|
|
19328
|
+
this.jupiter.fetchUsdPrices(jupiterMints),
|
|
19329
|
+
this.nest.fetchUsdPrices(nestMints)
|
|
19330
|
+
]);
|
|
19331
|
+
return { ...jupiterPrices, ...nestPrices };
|
|
19332
|
+
}
|
|
19333
|
+
};
|
|
19334
|
+
|
|
19290
19335
|
// src/services/consensusOracle/jupiterBalanceSource.ts
|
|
19291
19336
|
var import_web323 = require("@solana/web3.js");
|
|
19292
19337
|
var import_spl_token19 = require("@solana/spl-token");
|
|
@@ -19395,12 +19440,12 @@ var StaticPositionProvider = class {
|
|
|
19395
19440
|
};
|
|
19396
19441
|
|
|
19397
19442
|
// src/services/consensusOracle/kaminoPositionProvider.ts
|
|
19398
|
-
var
|
|
19443
|
+
var import_kit13 = require("@solana/kit");
|
|
19399
19444
|
var import_web324 = require("@solana/web3.js");
|
|
19400
19445
|
var import_klend_sdk = require("@kamino-finance/klend-sdk");
|
|
19401
19446
|
async function readKaminoBalance(manager, vault, sharesHolder) {
|
|
19402
19447
|
const userShares = await manager.getUserSharesBalanceSingleVault(
|
|
19403
|
-
(0,
|
|
19448
|
+
(0, import_kit13.address)(sharesHolder.toBase58()),
|
|
19404
19449
|
vault
|
|
19405
19450
|
);
|
|
19406
19451
|
const tokensPerShare = await manager.getTokensPerShareSingleVault(vault);
|
|
@@ -19416,7 +19461,7 @@ var KaminoPositionProvider = class {
|
|
|
19416
19461
|
async positionsFor(ctx) {
|
|
19417
19462
|
const refs = ctx.refs.filter((r) => r.kind === "kamino");
|
|
19418
19463
|
if (refs.length === 0) return [];
|
|
19419
|
-
const rpc = (0,
|
|
19464
|
+
const rpc = (0, import_kit13.createSolanaRpc)(this.rpcUrl);
|
|
19420
19465
|
const slotDuration = await (0, import_klend_sdk.getMedianSlotDurationInMsFromLastEpochs)();
|
|
19421
19466
|
const manager = new import_klend_sdk.KaminoManager(rpc, slotDuration);
|
|
19422
19467
|
const out = [];
|
|
@@ -19429,7 +19474,7 @@ var KaminoPositionProvider = class {
|
|
|
19429
19474
|
);
|
|
19430
19475
|
continue;
|
|
19431
19476
|
}
|
|
19432
|
-
const kVault = new import_klend_sdk.KaminoVault(rpc, (0,
|
|
19477
|
+
const kVault = new import_klend_sdk.KaminoVault(rpc, (0, import_kit13.address)(vaultState));
|
|
19433
19478
|
const amount = await readKaminoBalance(
|
|
19434
19479
|
manager,
|
|
19435
19480
|
kVault,
|
|
@@ -19544,17 +19589,21 @@ var MarginfiPositionProvider = class {
|
|
|
19544
19589
|
};
|
|
19545
19590
|
|
|
19546
19591
|
// src/services/consensusOracle/liveConsensusOracleDeps.ts
|
|
19592
|
+
var YIELD_TRACKER_DECIMALS = 6;
|
|
19547
19593
|
function createLiveConsensusOracleDeps(connection, opts = {}) {
|
|
19548
19594
|
const log = opts.log ?? (() => {
|
|
19549
19595
|
});
|
|
19550
19596
|
const deps = {
|
|
19551
|
-
priceSource: new
|
|
19597
|
+
priceSource: new LivePriceSource(),
|
|
19552
19598
|
balanceSource: new JupiterBalanceSource(connection, {
|
|
19553
19599
|
rpcOnly: opts.rpcOnly ?? false,
|
|
19554
19600
|
log
|
|
19555
19601
|
}),
|
|
19556
19602
|
yieldTracker: {
|
|
19557
|
-
getTotalOutstandingYield,
|
|
19603
|
+
async getTotalOutstandingYield(accountNames, start, end) {
|
|
19604
|
+
const raw = await getTotalOutstandingYield(accountNames, start, end);
|
|
19605
|
+
return raw / 10 ** YIELD_TRACKER_DECIMALS;
|
|
19606
|
+
},
|
|
19558
19607
|
getYieldPayments
|
|
19559
19608
|
}
|
|
19560
19609
|
};
|
|
@@ -19571,41 +19620,977 @@ function createLiveConsensusOracleDeps(connection, opts = {}) {
|
|
|
19571
19620
|
}
|
|
19572
19621
|
|
|
19573
19622
|
// src/services/consensusOracle/consensusOracleService.ts
|
|
19574
|
-
var
|
|
19623
|
+
var import_web327 = require("@solana/web3.js");
|
|
19575
19624
|
var import_common41 = __toESM(require_dist());
|
|
19576
|
-
|
|
19577
|
-
|
|
19578
|
-
|
|
19579
|
-
|
|
19580
|
-
|
|
19581
|
-
|
|
19582
|
-
|
|
19583
|
-
|
|
19584
|
-
|
|
19585
|
-
|
|
19586
|
-
|
|
19587
|
-
|
|
19588
|
-
|
|
19589
|
-
|
|
19590
|
-
|
|
19591
|
-
|
|
19592
|
-
|
|
19593
|
-
|
|
19594
|
-
|
|
19595
|
-
|
|
19625
|
+
|
|
19626
|
+
// src/services/consensusOracle/settlementSimulator.ts
|
|
19627
|
+
var import_kit14 = require("@solana/kit");
|
|
19628
|
+
var import_web326 = require("@solana/web3.js");
|
|
19629
|
+
var DEFAULT_SHARE_PRICE = 1000000n;
|
|
19630
|
+
var BPS_DENOMINATOR2 = 10000n;
|
|
19631
|
+
var SECONDS_PER_YEAR = 31536000n;
|
|
19632
|
+
var DEFAULT_STALENESS_SECS = 86400n;
|
|
19633
|
+
var CONSENSUS_MAX_DIFF_BPS = 8n;
|
|
19634
|
+
var MIN_CONSENSUS_SIGNERS = 2;
|
|
19635
|
+
var MAX_HOLDINGS = 12;
|
|
19636
|
+
var MAX_SIGNERS = 4;
|
|
19637
|
+
var ENTRY_SIZE = 272;
|
|
19638
|
+
var ENTRIES_OFFSET = 40;
|
|
19639
|
+
var PRICE_OFFSET = 40;
|
|
19640
|
+
var EXTERNAL_OFFSET = PRICE_OFFSET + MAX_HOLDINGS * 8;
|
|
19641
|
+
var APY_SCALE = 1000000000000000000n;
|
|
19642
|
+
var APY_LN_2 = 693147180559945309n;
|
|
19643
|
+
var APY_SERIES_TERMS = 32;
|
|
19644
|
+
function simulateConsensusOracleSettlement(args) {
|
|
19645
|
+
const warnings = [];
|
|
19646
|
+
const blockers = [];
|
|
19647
|
+
const vaultAccounting = record(args.vault.accounting);
|
|
19648
|
+
const feesConfig = record(args.vault.config.fees);
|
|
19649
|
+
const apyConfig = record(args.vault.config.apy);
|
|
19650
|
+
const tranchingEnabled = bool(args.vault.tranchingEnabled);
|
|
19651
|
+
const currentTvl = bigint(vaultAccounting.tvl);
|
|
19652
|
+
const pendingCuratorShares = bigint(vaultAccounting.pendingCuratorFeeShares);
|
|
19653
|
+
const pendingProtocolShares = bigint(
|
|
19654
|
+
vaultAccounting.pendingProtocolFeeShares
|
|
19655
|
+
);
|
|
19656
|
+
const cachedSupply = bigint(vaultAccounting.totalMintSupply);
|
|
19657
|
+
const reconciledSupply = args.physicalShareSupply === void 0 ? cachedSupply : args.physicalShareSupply + pendingCuratorShares + pendingProtocolShares;
|
|
19658
|
+
if (args.physicalShareSupply === void 0) {
|
|
19659
|
+
warnings.push(
|
|
19660
|
+
"regular share-mint supply was unavailable; using cached effective supply"
|
|
19661
|
+
);
|
|
19662
|
+
} else if (reconciledSupply !== cachedSupply) {
|
|
19663
|
+
warnings.push(
|
|
19664
|
+
`crank supply reconciliation changes regular supply ${cachedSupply} -> ${reconciledSupply}`
|
|
19665
|
+
);
|
|
19596
19666
|
}
|
|
19597
|
-
|
|
19598
|
-
|
|
19599
|
-
|
|
19600
|
-
|
|
19601
|
-
|
|
19602
|
-
|
|
19603
|
-
|
|
19604
|
-
|
|
19605
|
-
|
|
19606
|
-
|
|
19667
|
+
const holdings = args.vault.holdings.map(decodeHolding);
|
|
19668
|
+
const oracle = decodeOracleData(args.oracleData, args.nowTs);
|
|
19669
|
+
const signerEntry = oracle.entries.find(
|
|
19670
|
+
(entry) => entry.signer === args.signer.toString()
|
|
19671
|
+
);
|
|
19672
|
+
if (!signerEntry) {
|
|
19673
|
+
blockers.push(`signer ${args.signer} is not registered in the oracle`);
|
|
19674
|
+
} else {
|
|
19675
|
+
signerEntry.lastUpdateTs = args.nowTs;
|
|
19676
|
+
for (const update of args.updates) {
|
|
19677
|
+
signerEntry.prices[update.holdingIndex] = update.price;
|
|
19678
|
+
signerEntry.externalAmounts[update.holdingIndex] = update.externalAmount;
|
|
19679
|
+
}
|
|
19680
|
+
}
|
|
19681
|
+
const consensus = applyConsensus(
|
|
19682
|
+
holdings,
|
|
19683
|
+
oracle.entries,
|
|
19684
|
+
args.nowTs,
|
|
19685
|
+
oracle.stalenessThresholdSecs
|
|
19686
|
+
);
|
|
19687
|
+
const proposedUpdatesLanded = args.updates.filter(
|
|
19688
|
+
(update) => consensus.find(
|
|
19689
|
+
(result) => result.holdingIndex === update.holdingIndex && result.wouldUpdateHolding
|
|
19690
|
+
)
|
|
19691
|
+
).length;
|
|
19692
|
+
const consensusSummary = {
|
|
19693
|
+
allProposedUpdatesLand: proposedUpdatesLanded === args.updates.length && args.updates.length > 0,
|
|
19694
|
+
proposedUpdatesLanded,
|
|
19695
|
+
proposedUpdatesTotal: args.updates.length
|
|
19696
|
+
};
|
|
19697
|
+
const currentTranche = tranchingEnabled ? decodeTrancheState(args.trancheState, args, warnings, blockers) : void 0;
|
|
19698
|
+
const current = snapshot(
|
|
19699
|
+
currentTvl,
|
|
19700
|
+
reconciledSupply,
|
|
19701
|
+
bigint(vaultAccounting.mintSharePrice),
|
|
19702
|
+
currentTranche
|
|
19703
|
+
);
|
|
19704
|
+
let grossNav;
|
|
19705
|
+
try {
|
|
19706
|
+
grossNav = grossNavFromHoldings(
|
|
19707
|
+
holdings,
|
|
19708
|
+
args.nowTs,
|
|
19709
|
+
positiveOrDefault(
|
|
19710
|
+
bigint(args.vault.config.priceStalenessThresholdSecs),
|
|
19711
|
+
DEFAULT_STALENESS_SECS
|
|
19712
|
+
)
|
|
19713
|
+
);
|
|
19714
|
+
} catch (error) {
|
|
19715
|
+
blockers.push(message(error));
|
|
19716
|
+
}
|
|
19717
|
+
if (grossNav === void 0 || blockers.length > 0) {
|
|
19718
|
+
return {
|
|
19719
|
+
nowTs: args.nowTs,
|
|
19720
|
+
assetDecimals: args.vault.config.assetDecimals,
|
|
19721
|
+
...consensusSummary,
|
|
19722
|
+
canSettle: false,
|
|
19723
|
+
blockers,
|
|
19724
|
+
warnings,
|
|
19725
|
+
consensus,
|
|
19726
|
+
grossNav,
|
|
19727
|
+
current
|
|
19728
|
+
};
|
|
19729
|
+
}
|
|
19730
|
+
try {
|
|
19731
|
+
const settlement = settleVault({
|
|
19732
|
+
grossNav,
|
|
19733
|
+
nowTs: args.nowTs,
|
|
19734
|
+
currentTvl,
|
|
19735
|
+
currentSharePrice: bigint(vaultAccounting.mintSharePrice),
|
|
19736
|
+
totalSupply: reconciledSupply,
|
|
19737
|
+
lossesEnabled: bool(args.vault.lossesEnabled),
|
|
19738
|
+
accountingLastUpdateTs: bigint(vaultAccounting.lastUpdateTs),
|
|
19739
|
+
priorSettledNavTs: oracle.settledNavTs,
|
|
19740
|
+
performanceFeeBps: number(feesConfig.performanceFeeBps),
|
|
19741
|
+
protocolFeeBps: number(feesConfig.protocolFeeBps),
|
|
19742
|
+
hwmSharePrice: bigint(vaultAccounting.hwmSharePrice),
|
|
19743
|
+
fixedApyBps: number(apyConfig.fixedApyBps),
|
|
19744
|
+
maxApyBps: number(apyConfig.maxApyBps),
|
|
19745
|
+
accruedApyBalance: bigint(apyConfig.accruedApyBalance),
|
|
19746
|
+
apyAnchorSharePrice: bigint(apyConfig.anchorSharePrice),
|
|
19747
|
+
apyAnchorTs: bigint(apyConfig.anchorTs),
|
|
19748
|
+
tranche: currentTranche
|
|
19749
|
+
});
|
|
19750
|
+
return {
|
|
19751
|
+
nowTs: args.nowTs,
|
|
19752
|
+
assetDecimals: args.vault.config.assetDecimals,
|
|
19753
|
+
...consensusSummary,
|
|
19754
|
+
canSettle: true,
|
|
19755
|
+
blockers,
|
|
19756
|
+
warnings,
|
|
19757
|
+
consensus,
|
|
19758
|
+
grossNav,
|
|
19759
|
+
settledAccountingNav: settlement.settledAccountingNav,
|
|
19760
|
+
current,
|
|
19761
|
+
projected: settlement.projected,
|
|
19762
|
+
performanceFees: settlement.performanceFees
|
|
19763
|
+
};
|
|
19764
|
+
} catch (error) {
|
|
19765
|
+
const blocker = message(error);
|
|
19766
|
+
blockers.push(blocker);
|
|
19767
|
+
if (blocker.includes("MaxApyExceeded")) {
|
|
19768
|
+
try {
|
|
19769
|
+
const settlement = settleVault({
|
|
19770
|
+
grossNav,
|
|
19771
|
+
nowTs: args.nowTs,
|
|
19772
|
+
currentTvl,
|
|
19773
|
+
currentSharePrice: bigint(vaultAccounting.mintSharePrice),
|
|
19774
|
+
totalSupply: reconciledSupply,
|
|
19775
|
+
lossesEnabled: bool(args.vault.lossesEnabled),
|
|
19776
|
+
accountingLastUpdateTs: bigint(vaultAccounting.lastUpdateTs),
|
|
19777
|
+
priorSettledNavTs: oracle.settledNavTs,
|
|
19778
|
+
performanceFeeBps: number(feesConfig.performanceFeeBps),
|
|
19779
|
+
protocolFeeBps: number(feesConfig.protocolFeeBps),
|
|
19780
|
+
hwmSharePrice: bigint(vaultAccounting.hwmSharePrice),
|
|
19781
|
+
fixedApyBps: number(apyConfig.fixedApyBps),
|
|
19782
|
+
maxApyBps: 0,
|
|
19783
|
+
accruedApyBalance: bigint(apyConfig.accruedApyBalance),
|
|
19784
|
+
apyAnchorSharePrice: bigint(apyConfig.anchorSharePrice),
|
|
19785
|
+
apyAnchorTs: bigint(apyConfig.anchorTs),
|
|
19786
|
+
tranche: currentTranche
|
|
19787
|
+
});
|
|
19788
|
+
return {
|
|
19789
|
+
nowTs: args.nowTs,
|
|
19790
|
+
assetDecimals: args.vault.config.assetDecimals,
|
|
19791
|
+
...consensusSummary,
|
|
19792
|
+
canSettle: false,
|
|
19793
|
+
blockers,
|
|
19794
|
+
warnings,
|
|
19795
|
+
consensus,
|
|
19796
|
+
grossNav,
|
|
19797
|
+
settledAccountingNav: settlement.settledAccountingNav,
|
|
19798
|
+
current,
|
|
19799
|
+
projectionRequiresMaxApyDisabled: true,
|
|
19800
|
+
projected: settlement.projected,
|
|
19801
|
+
performanceFees: settlement.performanceFees
|
|
19802
|
+
};
|
|
19803
|
+
} catch (projectionError) {
|
|
19804
|
+
warnings.push(
|
|
19805
|
+
`could not calculate the uncapped projection: ${message(
|
|
19806
|
+
projectionError
|
|
19807
|
+
)}`
|
|
19808
|
+
);
|
|
19809
|
+
}
|
|
19810
|
+
}
|
|
19811
|
+
return {
|
|
19812
|
+
nowTs: args.nowTs,
|
|
19813
|
+
assetDecimals: args.vault.config.assetDecimals,
|
|
19814
|
+
...consensusSummary,
|
|
19815
|
+
canSettle: false,
|
|
19816
|
+
blockers,
|
|
19817
|
+
warnings,
|
|
19818
|
+
consensus,
|
|
19819
|
+
grossNav,
|
|
19820
|
+
current
|
|
19821
|
+
};
|
|
19822
|
+
}
|
|
19823
|
+
}
|
|
19824
|
+
function applyConsensus(holdings, entries, nowTs, stalenessThresholdSecs) {
|
|
19825
|
+
const results = [];
|
|
19826
|
+
for (let index = 0; index < holdings.length; index += 1) {
|
|
19827
|
+
const holding = holdings[index];
|
|
19828
|
+
if (holding.cleared || holding.priceOracleType !== "consensusoracle") {
|
|
19829
|
+
continue;
|
|
19830
|
+
}
|
|
19831
|
+
const reports = entries.filter(
|
|
19832
|
+
(entry) => entry.signer !== import_web326.PublicKey.default.toBase58() && isFresh(entry.lastUpdateTs, nowTs, stalenessThresholdSecs) && (entry.prices[index] ?? 0n) > 0n
|
|
19833
|
+
);
|
|
19834
|
+
const prices = reports.map((entry) => entry.prices[index] ?? 0n);
|
|
19835
|
+
const amounts = reports.map((entry) => entry.externalAmounts[index] ?? 0n);
|
|
19836
|
+
let reason;
|
|
19837
|
+
if (reports.length < MIN_CONSENSUS_SIGNERS) {
|
|
19838
|
+
reason = `only ${reports.length} fresh priced report(s); need ${MIN_CONSENSUS_SIGNERS}`;
|
|
19839
|
+
} else if (!withinDeviation(prices)) {
|
|
19840
|
+
reason = `price reports exceed ${CONSENSUS_MAX_DIFF_BPS}bps pairwise deviation`;
|
|
19841
|
+
} else if (!withinDeviation(amounts)) {
|
|
19842
|
+
reason = `external-amount reports exceed ${CONSENSUS_MAX_DIFF_BPS}bps pairwise deviation`;
|
|
19843
|
+
}
|
|
19844
|
+
if (reason) {
|
|
19845
|
+
results.push({
|
|
19846
|
+
holdingIndex: index,
|
|
19847
|
+
mint: holding.mint,
|
|
19848
|
+
reportCount: reports.length,
|
|
19849
|
+
wouldUpdateHolding: false,
|
|
19850
|
+
reason
|
|
19851
|
+
});
|
|
19852
|
+
continue;
|
|
19853
|
+
}
|
|
19854
|
+
const settledPrice = average(prices);
|
|
19855
|
+
const settledExternalAmount = average(amounts);
|
|
19856
|
+
const latestTs = reports.reduce(
|
|
19857
|
+
(latest, entry) => entry.lastUpdateTs > latest ? entry.lastUpdateTs : latest,
|
|
19858
|
+
0n
|
|
19859
|
+
);
|
|
19860
|
+
const wouldUpdateHolding = latestTs > holding.lastUpdateTs && latestTs <= nowTs;
|
|
19861
|
+
if (wouldUpdateHolding) {
|
|
19862
|
+
holding.price = settledPrice;
|
|
19863
|
+
holding.externalAmount = settledExternalAmount;
|
|
19864
|
+
holding.lastUpdateTs = latestTs;
|
|
19865
|
+
if (!holding.isBase && holding.localAmount === 0n && holding.externalAmount === 0n) {
|
|
19866
|
+
holding.cleared = true;
|
|
19867
|
+
}
|
|
19868
|
+
}
|
|
19869
|
+
results.push({
|
|
19870
|
+
holdingIndex: index,
|
|
19871
|
+
mint: holding.mint,
|
|
19872
|
+
reportCount: reports.length,
|
|
19873
|
+
settledPrice,
|
|
19874
|
+
settledExternalAmount,
|
|
19875
|
+
wouldUpdateHolding,
|
|
19876
|
+
reason: wouldUpdateHolding ? void 0 : `aggregate timestamp ${latestTs} is not newer than holding timestamp ${holding.lastUpdateTs}`
|
|
19877
|
+
});
|
|
19878
|
+
}
|
|
19879
|
+
return results;
|
|
19880
|
+
}
|
|
19881
|
+
function settleVault(args) {
|
|
19882
|
+
const regularSurplusBefore = args.tranche ? max(args.accruedApyBalance, 0n) : 0n;
|
|
19883
|
+
const physicalNavBefore = args.currentTvl + regularSurplusBefore;
|
|
19884
|
+
if (args.grossNav < physicalNavBefore && !args.lossesEnabled) {
|
|
19885
|
+
throw new Error(
|
|
19886
|
+
`crank would fail LossesDisabled: gross NAV ${args.grossNav} < physical NAV ${physicalNavBefore}`
|
|
19887
|
+
);
|
|
19888
|
+
}
|
|
19889
|
+
const priorTs = args.priorSettledNavTs > 0n ? args.priorSettledNavTs : max(args.accountingLastUpdateTs, args.apyAnchorTs);
|
|
19890
|
+
const nextApyValue = args.tranche ? args.grossNav : sharePriceForValue(args.grossNav, args.totalSupply);
|
|
19891
|
+
if (nextApyValue !== void 0) {
|
|
19892
|
+
validateRealizedApy(
|
|
19893
|
+
args.tranche ? physicalNavBefore : args.currentSharePrice,
|
|
19894
|
+
priorTs,
|
|
19895
|
+
nextApyValue,
|
|
19896
|
+
args.nowTs,
|
|
19897
|
+
args.maxApyBps
|
|
19898
|
+
);
|
|
19899
|
+
}
|
|
19900
|
+
let regularValue;
|
|
19901
|
+
let regularSharePrice = args.currentSharePrice;
|
|
19902
|
+
let curatorFee = 0n;
|
|
19903
|
+
let protocolFee = 0n;
|
|
19904
|
+
let settledAccountingNav;
|
|
19905
|
+
if (args.tranche) {
|
|
19906
|
+
const regularGrossValue = settleTrancheNav(
|
|
19907
|
+
args.tranche,
|
|
19908
|
+
physicalNavBefore,
|
|
19909
|
+
args.grossNav,
|
|
19910
|
+
args.nowTs
|
|
19911
|
+
);
|
|
19912
|
+
regularValue = settleFixedApyNav({
|
|
19913
|
+
currentSharePrice: args.currentSharePrice,
|
|
19914
|
+
reportedNav: regularGrossValue,
|
|
19915
|
+
nowTs: args.nowTs,
|
|
19916
|
+
totalSupply: args.totalSupply,
|
|
19917
|
+
fixedApyBps: args.fixedApyBps,
|
|
19918
|
+
anchorSharePrice: args.apyAnchorSharePrice,
|
|
19919
|
+
anchorTs: args.apyAnchorTs
|
|
19920
|
+
});
|
|
19921
|
+
settledAccountingNav = regularValue + args.tranche.junior.value + args.tranche.senior.value;
|
|
19922
|
+
const juniorFees = settleShareClassPerformanceFee(
|
|
19923
|
+
args.tranche.junior,
|
|
19924
|
+
args.performanceFeeBps,
|
|
19925
|
+
args.protocolFeeBps
|
|
19926
|
+
);
|
|
19927
|
+
const regularFees = settleRegularPerformanceFee(
|
|
19928
|
+
regularValue,
|
|
19929
|
+
args.totalSupply,
|
|
19930
|
+
args.hwmSharePrice,
|
|
19931
|
+
args.performanceFeeBps,
|
|
19932
|
+
args.protocolFeeBps
|
|
19933
|
+
);
|
|
19934
|
+
regularValue = regularFees.netValue;
|
|
19935
|
+
regularSharePrice = sharePriceForValue(regularValue, args.totalSupply) ?? regularSharePrice;
|
|
19936
|
+
curatorFee = juniorFees.curator + regularFees.fees.curator;
|
|
19937
|
+
protocolFee = juniorFees.protocol + regularFees.fees.protocol;
|
|
19938
|
+
} else {
|
|
19939
|
+
settledAccountingNav = settleFixedApyNav({
|
|
19940
|
+
currentSharePrice: args.currentSharePrice,
|
|
19941
|
+
reportedNav: args.grossNav,
|
|
19942
|
+
nowTs: args.nowTs,
|
|
19943
|
+
totalSupply: args.totalSupply,
|
|
19944
|
+
fixedApyBps: args.fixedApyBps,
|
|
19945
|
+
anchorSharePrice: args.apyAnchorSharePrice,
|
|
19946
|
+
anchorTs: args.apyAnchorTs
|
|
19947
|
+
});
|
|
19948
|
+
const regularFees = settleRegularPerformanceFee(
|
|
19949
|
+
settledAccountingNav,
|
|
19950
|
+
args.totalSupply,
|
|
19951
|
+
args.hwmSharePrice,
|
|
19952
|
+
args.performanceFeeBps,
|
|
19953
|
+
args.protocolFeeBps
|
|
19954
|
+
);
|
|
19955
|
+
regularValue = regularFees.netValue;
|
|
19956
|
+
regularSharePrice = sharePriceForValue(regularValue, args.totalSupply) ?? regularSharePrice;
|
|
19957
|
+
curatorFee = regularFees.fees.curator;
|
|
19958
|
+
protocolFee = regularFees.fees.protocol;
|
|
19959
|
+
}
|
|
19960
|
+
const totalFees = curatorFee + protocolFee;
|
|
19961
|
+
const netRegularBacking = mulDiv2(
|
|
19962
|
+
args.totalSupply,
|
|
19963
|
+
regularSharePrice,
|
|
19964
|
+
DEFAULT_SHARE_PRICE
|
|
19965
|
+
);
|
|
19966
|
+
let mintedShares = 0n;
|
|
19967
|
+
if (totalFees > 0n) {
|
|
19968
|
+
mintedShares = args.totalSupply === 0n ? totalFees : mulDiv2(totalFees, args.totalSupply, netRegularBacking);
|
|
19969
|
+
if (mintedShares === 0n) {
|
|
19970
|
+
throw new Error(
|
|
19971
|
+
"crank would fail ZeroAssetAmount while accruing fee shares"
|
|
19972
|
+
);
|
|
19973
|
+
}
|
|
19974
|
+
}
|
|
19975
|
+
const projectedSupply = args.totalSupply + mintedShares;
|
|
19976
|
+
const projected = snapshot(
|
|
19977
|
+
// Fee value is carved out, then added back when converted to vault shares.
|
|
19978
|
+
settledAccountingNav,
|
|
19979
|
+
projectedSupply,
|
|
19980
|
+
regularSharePrice,
|
|
19981
|
+
args.tranche
|
|
19982
|
+
);
|
|
19983
|
+
return {
|
|
19984
|
+
settledAccountingNav,
|
|
19985
|
+
projected,
|
|
19986
|
+
performanceFees: {
|
|
19987
|
+
curator: curatorFee,
|
|
19988
|
+
protocol: protocolFee,
|
|
19989
|
+
total: totalFees,
|
|
19990
|
+
mintedShares
|
|
19991
|
+
}
|
|
19992
|
+
};
|
|
19993
|
+
}
|
|
19994
|
+
function settleTrancheNav(tranche, currentTvl, nextTvl, nowTs) {
|
|
19995
|
+
const before = tranche.junior.value + tranche.senior.value;
|
|
19996
|
+
if (before === 0n) {
|
|
19997
|
+
tranche.lastSettledTs = nowTs;
|
|
19998
|
+
return nextTvl;
|
|
19999
|
+
}
|
|
20000
|
+
if (currentTvl <= 0n || before > currentTvl) {
|
|
20001
|
+
throw new Error(
|
|
20002
|
+
`crank would fail InvalidArgument: tranche value ${before}, current TVL ${currentTvl}`
|
|
20003
|
+
);
|
|
20004
|
+
}
|
|
20005
|
+
const after = mulDiv2(before, nextTvl, currentTvl);
|
|
20006
|
+
if (after >= before) {
|
|
20007
|
+
let gain = after - before;
|
|
20008
|
+
const entitlement = seniorEntitlement(tranche, nowTs);
|
|
20009
|
+
const seniorGain = entitlement < gain ? entitlement : gain;
|
|
20010
|
+
tranche.senior.value += seniorGain;
|
|
20011
|
+
gain -= seniorGain;
|
|
20012
|
+
if (gain > 0n) {
|
|
20013
|
+
if (tranche.junior.totalSupply > 0n) tranche.junior.value += gain;
|
|
20014
|
+
else tranche.senior.value += gain;
|
|
20015
|
+
}
|
|
20016
|
+
} else {
|
|
20017
|
+
const loss = before - after;
|
|
20018
|
+
const juniorLoss = tranche.junior.value < loss ? tranche.junior.value : loss;
|
|
20019
|
+
tranche.junior.value -= juniorLoss;
|
|
20020
|
+
tranche.senior.value -= loss - juniorLoss;
|
|
20021
|
+
}
|
|
20022
|
+
refreshShareClass(tranche.junior);
|
|
20023
|
+
refreshShareClass(tranche.senior);
|
|
20024
|
+
tranche.lastSettledTs = nowTs;
|
|
20025
|
+
return nextTvl - tranche.junior.value - tranche.senior.value;
|
|
20026
|
+
}
|
|
20027
|
+
function seniorEntitlement(tranche, nowTs) {
|
|
20028
|
+
if (tranche.seniorApyAnchorTs <= 0n) {
|
|
20029
|
+
tranche.seniorApyAnchorSharePrice = tranche.senior.sharePrice;
|
|
20030
|
+
tranche.seniorApyAnchorTs = tranche.lastSettledTs > 0n ? tranche.lastSettledTs : nowTs;
|
|
20031
|
+
}
|
|
20032
|
+
if (tranche.seniorFixedApyBps === 0 || tranche.seniorApyAnchorSharePrice === 0n || tranche.senior.totalSupply === 0n || tranche.seniorApyAnchorTs <= 0n || nowTs <= tranche.seniorApyAnchorTs) {
|
|
20033
|
+
return 0n;
|
|
20034
|
+
}
|
|
20035
|
+
const targetPrice = applyEffectiveApy(
|
|
20036
|
+
tranche.seniorApyAnchorSharePrice,
|
|
20037
|
+
tranche.seniorFixedApyBps,
|
|
20038
|
+
nowTs - tranche.seniorApyAnchorTs
|
|
20039
|
+
);
|
|
20040
|
+
const targetValue = mulDiv2(
|
|
20041
|
+
targetPrice,
|
|
20042
|
+
tranche.senior.totalSupply,
|
|
20043
|
+
DEFAULT_SHARE_PRICE
|
|
20044
|
+
);
|
|
20045
|
+
return targetValue > tranche.senior.value ? targetValue - tranche.senior.value : 0n;
|
|
20046
|
+
}
|
|
20047
|
+
function settleShareClassPerformanceFee(shareClass, performanceFeeBps, protocolFeeBps) {
|
|
20048
|
+
refreshShareClass(shareClass);
|
|
20049
|
+
const grossPrice = shareClass.sharePrice;
|
|
20050
|
+
if (shareClass.hwmSharePrice === 0n) {
|
|
20051
|
+
shareClass.hwmSharePrice = grossPrice;
|
|
20052
|
+
return noFees();
|
|
20053
|
+
}
|
|
20054
|
+
if (performanceFeeBps + protocolFeeBps === 0 || shareClass.totalSupply === 0n || grossPrice <= shareClass.hwmSharePrice) {
|
|
20055
|
+
return noFees();
|
|
20056
|
+
}
|
|
20057
|
+
const gainValue = mulDiv2(
|
|
20058
|
+
grossPrice - shareClass.hwmSharePrice,
|
|
20059
|
+
shareClass.totalSupply,
|
|
20060
|
+
DEFAULT_SHARE_PRICE
|
|
20061
|
+
);
|
|
20062
|
+
const fees = feeAmounts(gainValue, performanceFeeBps, protocolFeeBps);
|
|
20063
|
+
const total = fees.curator + fees.protocol;
|
|
20064
|
+
if (total > 0n) {
|
|
20065
|
+
shareClass.value -= total;
|
|
20066
|
+
refreshShareClass(shareClass);
|
|
20067
|
+
shareClass.hwmSharePrice = shareClass.sharePrice;
|
|
20068
|
+
}
|
|
20069
|
+
return fees;
|
|
20070
|
+
}
|
|
20071
|
+
function settleRegularPerformanceFee(grossValue, supply, hwmSharePrice, performanceFeeBps, protocolFeeBps) {
|
|
20072
|
+
if (supply === 0n) return { netValue: grossValue, fees: noFees() };
|
|
20073
|
+
const grossPrice = sharePriceForValue(grossValue, supply);
|
|
20074
|
+
if (hwmSharePrice === 0n || grossPrice <= hwmSharePrice || performanceFeeBps + protocolFeeBps === 0) {
|
|
20075
|
+
return { netValue: grossValue, fees: noFees() };
|
|
20076
|
+
}
|
|
20077
|
+
const gainValue = mulDiv2(
|
|
20078
|
+
supply,
|
|
20079
|
+
grossPrice - hwmSharePrice,
|
|
20080
|
+
DEFAULT_SHARE_PRICE
|
|
20081
|
+
);
|
|
20082
|
+
const fees = feeAmounts(gainValue, performanceFeeBps, protocolFeeBps);
|
|
20083
|
+
return {
|
|
20084
|
+
netValue: grossValue - fees.curator - fees.protocol,
|
|
20085
|
+
fees
|
|
20086
|
+
};
|
|
20087
|
+
}
|
|
20088
|
+
function settleFixedApyNav(args) {
|
|
20089
|
+
if (args.totalSupply === 0n) return 0n;
|
|
20090
|
+
if (args.fixedApyBps === 0 || args.currentSharePrice === 0n || args.anchorSharePrice === 0n || args.anchorTs <= 0n) {
|
|
20091
|
+
return args.reportedNav;
|
|
20092
|
+
}
|
|
20093
|
+
if (args.nowTs <= args.anchorTs) {
|
|
20094
|
+
const anchoredNav = mulDiv2(
|
|
20095
|
+
args.totalSupply,
|
|
20096
|
+
args.anchorSharePrice,
|
|
20097
|
+
DEFAULT_SHARE_PRICE
|
|
20098
|
+
);
|
|
20099
|
+
if (args.reportedNav !== anchoredNav) {
|
|
20100
|
+
throw new Error("crank would fail InvalidOracleUpdate at APY anchor");
|
|
20101
|
+
}
|
|
20102
|
+
return args.reportedNav;
|
|
20103
|
+
}
|
|
20104
|
+
const fixedPrice = applyEffectiveApy(
|
|
20105
|
+
args.anchorSharePrice,
|
|
20106
|
+
args.fixedApyBps,
|
|
20107
|
+
args.nowTs - args.anchorTs
|
|
20108
|
+
);
|
|
20109
|
+
const fixedNav = mulDiv2(args.totalSupply, fixedPrice, DEFAULT_SHARE_PRICE);
|
|
20110
|
+
return args.reportedNav >= fixedNav ? fixedNav : args.reportedNav;
|
|
20111
|
+
}
|
|
20112
|
+
function validateRealizedApy(priorValue, priorTs, nextValue, nextTs, maxApyBps) {
|
|
20113
|
+
if (maxApyBps === 0 || priorValue === 0n || priorTs <= 0n || nextValue <= priorValue) {
|
|
20114
|
+
return;
|
|
20115
|
+
}
|
|
20116
|
+
const elapsed = nextTs - priorTs;
|
|
20117
|
+
if (elapsed <= 0n) throw new Error("crank would fail MaxApyExceeded");
|
|
20118
|
+
const lhs = (nextValue - priorValue) * BPS_DENOMINATOR2 * SECONDS_PER_YEAR;
|
|
20119
|
+
const rhs = BigInt(maxApyBps) * priorValue * elapsed;
|
|
20120
|
+
if (lhs > rhs) {
|
|
20121
|
+
const implied = lhs / (priorValue * elapsed);
|
|
20122
|
+
throw new Error(
|
|
20123
|
+
`crank would fail MaxApyExceeded: implied ${implied}bps > ${maxApyBps}bps`
|
|
20124
|
+
);
|
|
20125
|
+
}
|
|
20126
|
+
}
|
|
20127
|
+
function grossNavFromHoldings(holdings, nowTs, stalenessSecs) {
|
|
20128
|
+
let nav = 0n;
|
|
20129
|
+
for (const holding of holdings) {
|
|
20130
|
+
if (holding.cleared) continue;
|
|
20131
|
+
const amount = holding.localAmount + holding.externalAmount;
|
|
20132
|
+
if (amount === 0n && !holding.isBase) continue;
|
|
20133
|
+
if (holding.price <= 0n) {
|
|
20134
|
+
throw new Error(`crank blocked: holding ${holding.mint} is unpriced`);
|
|
20135
|
+
}
|
|
20136
|
+
if (holding.priceOracleType !== "none" && (holding.lastUpdateTs <= 0n || nowTs - holding.lastUpdateTs < 0n || nowTs - holding.lastUpdateTs > stalenessSecs)) {
|
|
20137
|
+
throw new Error(
|
|
20138
|
+
`crank blocked: holding ${holding.mint} price is stale (ts=${holding.lastUpdateTs})`
|
|
20139
|
+
);
|
|
20140
|
+
}
|
|
20141
|
+
if (amount > 0n) {
|
|
20142
|
+
nav += mulDiv2(amount, holding.price, 10n ** BigInt(holding.decimals));
|
|
20143
|
+
}
|
|
20144
|
+
}
|
|
20145
|
+
return nav;
|
|
20146
|
+
}
|
|
20147
|
+
function decodeOracleData(data, nowTs) {
|
|
20148
|
+
if (data.length < ENTRIES_OFFSET + MAX_SIGNERS * ENTRY_SIZE) {
|
|
20149
|
+
throw new Error(`oracle payload is too short (${data.length} bytes)`);
|
|
20150
|
+
}
|
|
20151
|
+
const entries = [];
|
|
20152
|
+
for (let signerIndex = 0; signerIndex < MAX_SIGNERS; signerIndex += 1) {
|
|
20153
|
+
const offset = ENTRIES_OFFSET + signerIndex * ENTRY_SIZE;
|
|
20154
|
+
const signerBytes = new Uint8Array(data.slice(offset, offset + 32));
|
|
20155
|
+
const prices = Array.from(
|
|
20156
|
+
{ length: MAX_HOLDINGS },
|
|
20157
|
+
(_, holdingIndex) => readU64(data, offset + PRICE_OFFSET + holdingIndex * 8)
|
|
20158
|
+
);
|
|
20159
|
+
const externalAmounts = Array.from(
|
|
20160
|
+
{ length: MAX_HOLDINGS },
|
|
20161
|
+
(_, holdingIndex) => readU64(data, offset + EXTERNAL_OFFSET + holdingIndex * 8)
|
|
20162
|
+
);
|
|
20163
|
+
entries.push({
|
|
20164
|
+
signer: new import_web326.PublicKey(signerBytes).toBase58(),
|
|
20165
|
+
lastUpdateTs: readI64(data, offset + 32),
|
|
20166
|
+
prices,
|
|
20167
|
+
externalAmounts
|
|
20168
|
+
});
|
|
20169
|
+
}
|
|
20170
|
+
const pendingOffset = ENTRIES_OFFSET + MAX_SIGNERS * ENTRY_SIZE;
|
|
20171
|
+
const pendingEffectiveTs = readI64(data, pendingOffset + 128);
|
|
20172
|
+
const pendingCount = data[pendingOffset + 136] ?? 0;
|
|
20173
|
+
if (pendingCount > 0 && pendingCount <= MAX_SIGNERS && nowTs >= pendingEffectiveTs) {
|
|
20174
|
+
for (let index = 0; index < MAX_SIGNERS; index += 1) {
|
|
20175
|
+
const signerBytes = new Uint8Array(
|
|
20176
|
+
data.slice(pendingOffset + index * 32, pendingOffset + (index + 1) * 32)
|
|
20177
|
+
);
|
|
20178
|
+
entries[index] = {
|
|
20179
|
+
signer: index < pendingCount ? new import_web326.PublicKey(signerBytes).toBase58() : import_web326.PublicKey.default.toBase58(),
|
|
20180
|
+
lastUpdateTs: 0n,
|
|
20181
|
+
prices: Array(MAX_HOLDINGS).fill(0n),
|
|
20182
|
+
externalAmounts: Array(MAX_HOLDINGS).fill(0n)
|
|
20183
|
+
};
|
|
20184
|
+
}
|
|
20185
|
+
}
|
|
20186
|
+
return {
|
|
20187
|
+
settledNavTs: readI64(data, 8),
|
|
20188
|
+
stalenessThresholdSecs: positiveOrDefault(
|
|
20189
|
+
readI64(data, 32),
|
|
20190
|
+
DEFAULT_STALENESS_SECS
|
|
20191
|
+
),
|
|
20192
|
+
entries
|
|
20193
|
+
};
|
|
20194
|
+
}
|
|
20195
|
+
function decodeHolding(value) {
|
|
20196
|
+
const holding = record(value);
|
|
20197
|
+
const mintString = pubkeyString3(holding.mint);
|
|
20198
|
+
return {
|
|
20199
|
+
mint: (0, import_kit14.address)(mintString),
|
|
20200
|
+
decimals: number(holding.decimals),
|
|
20201
|
+
priceOracleType: variant(holding.priceOracleType),
|
|
20202
|
+
isBase: bool(holding.isBase),
|
|
20203
|
+
localAmount: bigint(holding.localAmount),
|
|
20204
|
+
externalAmount: bigint(holding.externalAmount),
|
|
20205
|
+
price: bigint(holding.price),
|
|
20206
|
+
lastUpdateTs: bigint(holding.lastUpdateTs),
|
|
20207
|
+
cleared: mintString === import_web326.PublicKey.default.toBase58()
|
|
20208
|
+
};
|
|
20209
|
+
}
|
|
20210
|
+
function decodeTrancheState(decoded, args, warnings, blockers) {
|
|
20211
|
+
if (!decoded) {
|
|
20212
|
+
blockers.push("tranching is enabled but the tranche state was unavailable");
|
|
20213
|
+
return void 0;
|
|
20214
|
+
}
|
|
20215
|
+
const junior = decodeShareClass(decoded.junior);
|
|
20216
|
+
const senior = decodeShareClass(decoded.senior);
|
|
20217
|
+
if (args.physicalJuniorSupply === void 0) {
|
|
20218
|
+
warnings.push(
|
|
20219
|
+
"junior mint supply unavailable; using cached tranche supply"
|
|
20220
|
+
);
|
|
20221
|
+
} else {
|
|
20222
|
+
junior.totalSupply = args.physicalJuniorSupply;
|
|
20223
|
+
refreshShareClass(junior);
|
|
20224
|
+
}
|
|
20225
|
+
if (args.physicalSeniorSupply === void 0) {
|
|
20226
|
+
warnings.push(
|
|
20227
|
+
"senior mint supply unavailable; using cached tranche supply"
|
|
20228
|
+
);
|
|
20229
|
+
} else {
|
|
20230
|
+
senior.totalSupply = args.physicalSeniorSupply;
|
|
20231
|
+
refreshShareClass(senior);
|
|
20232
|
+
}
|
|
20233
|
+
return {
|
|
20234
|
+
junior,
|
|
20235
|
+
senior,
|
|
20236
|
+
seniorFixedApyBps: number(decoded.config.seniorFixedApyBps),
|
|
20237
|
+
lastSettledTs: bigint(decoded.lastSettledTs),
|
|
20238
|
+
seniorApyAnchorSharePrice: bigint(decoded.seniorApyAnchorSharePrice),
|
|
20239
|
+
seniorApyAnchorTs: bigint(decoded.seniorApyAnchorTs)
|
|
20240
|
+
};
|
|
20241
|
+
}
|
|
20242
|
+
function decodeShareClass(value) {
|
|
20243
|
+
const decoded = record(value);
|
|
20244
|
+
return {
|
|
20245
|
+
value: bigint(decoded.value),
|
|
20246
|
+
totalSupply: bigint(decoded.totalSupply),
|
|
20247
|
+
sharePrice: bigint(decoded.sharePrice),
|
|
20248
|
+
hwmSharePrice: bigint(decoded.hwmSharePrice)
|
|
20249
|
+
};
|
|
20250
|
+
}
|
|
20251
|
+
function snapshot(tvl, regularSupply, regularSharePrice, tranche) {
|
|
20252
|
+
const regularValue = mulDiv2(
|
|
20253
|
+
regularSupply,
|
|
20254
|
+
regularSharePrice,
|
|
20255
|
+
DEFAULT_SHARE_PRICE
|
|
20256
|
+
);
|
|
20257
|
+
return {
|
|
20258
|
+
tvl,
|
|
20259
|
+
regular: {
|
|
20260
|
+
value: regularValue,
|
|
20261
|
+
totalSupply: regularSupply,
|
|
20262
|
+
sharePrice: regularSharePrice
|
|
20263
|
+
},
|
|
20264
|
+
...tranche ? {
|
|
20265
|
+
junior: publicShareClass(tranche.junior),
|
|
20266
|
+
senior: publicShareClass(tranche.senior)
|
|
20267
|
+
} : {}
|
|
20268
|
+
};
|
|
20269
|
+
}
|
|
20270
|
+
function publicShareClass(value) {
|
|
20271
|
+
return {
|
|
20272
|
+
value: value.value,
|
|
20273
|
+
totalSupply: value.totalSupply,
|
|
20274
|
+
sharePrice: value.sharePrice
|
|
20275
|
+
};
|
|
20276
|
+
}
|
|
20277
|
+
function refreshShareClass(value) {
|
|
20278
|
+
value.sharePrice = value.totalSupply === 0n ? DEFAULT_SHARE_PRICE : mulDiv2(value.value, DEFAULT_SHARE_PRICE, value.totalSupply);
|
|
20279
|
+
}
|
|
20280
|
+
function sharePriceForValue(value, supply) {
|
|
20281
|
+
return supply === 0n ? void 0 : mulDiv2(value, DEFAULT_SHARE_PRICE, supply);
|
|
20282
|
+
}
|
|
20283
|
+
function feeAmounts(value, performanceFeeBps, protocolFeeBps) {
|
|
20284
|
+
return {
|
|
20285
|
+
curator: mulDiv2(value, BigInt(performanceFeeBps), BPS_DENOMINATOR2),
|
|
20286
|
+
protocol: mulDiv2(value, BigInt(protocolFeeBps), BPS_DENOMINATOR2)
|
|
20287
|
+
};
|
|
20288
|
+
}
|
|
20289
|
+
function noFees() {
|
|
20290
|
+
return { curator: 0n, protocol: 0n };
|
|
20291
|
+
}
|
|
20292
|
+
function withinDeviation(values) {
|
|
20293
|
+
for (let i = 0; i < values.length; i += 1) {
|
|
20294
|
+
for (let j = i + 1; j < values.length; j += 1) {
|
|
20295
|
+
const a = values[i];
|
|
20296
|
+
const b = values[j];
|
|
20297
|
+
if (a === b) continue;
|
|
20298
|
+
if (a === 0n || b === 0n) return false;
|
|
20299
|
+
const diff = abs(a * BPS_DENOMINATOR2 / b - BPS_DENOMINATOR2);
|
|
20300
|
+
if (diff > CONSENSUS_MAX_DIFF_BPS) return false;
|
|
20301
|
+
}
|
|
20302
|
+
}
|
|
20303
|
+
return true;
|
|
20304
|
+
}
|
|
20305
|
+
function average(values) {
|
|
20306
|
+
return values.reduce((sum, value) => sum + value, 0n) / BigInt(values.length);
|
|
20307
|
+
}
|
|
20308
|
+
function isFresh(lastTs, nowTs, staleness) {
|
|
20309
|
+
if (lastTs <= 0n) return false;
|
|
20310
|
+
const age = nowTs - lastTs;
|
|
20311
|
+
return age >= 0n && age <= staleness;
|
|
20312
|
+
}
|
|
20313
|
+
function applyEffectiveApy(anchor, apyBps, elapsedSecs) {
|
|
20314
|
+
if (anchor === 0n || apyBps === 0 || elapsedSecs === 0n) return anchor;
|
|
20315
|
+
if (apyBps < 0 || apyBps > 1e4) throw new Error("invalid APY bps");
|
|
20316
|
+
const base = APY_SCALE + mulDiv2(BigInt(apyBps), APY_SCALE, BPS_DENOMINATOR2);
|
|
20317
|
+
const wholeYears = elapsedSecs / SECONDS_PER_YEAR;
|
|
20318
|
+
const remainder = elapsedSecs % SECONDS_PER_YEAR;
|
|
20319
|
+
const wholeMultiplier = fixedPointPow(base, wholeYears);
|
|
20320
|
+
const fractionalMultiplier = remainder === 0n ? APY_SCALE : fixedPointExp(
|
|
20321
|
+
mulDiv2(
|
|
20322
|
+
fixedPointLnBetweenOneAndTwo(base),
|
|
20323
|
+
remainder,
|
|
20324
|
+
SECONDS_PER_YEAR
|
|
20325
|
+
)
|
|
20326
|
+
);
|
|
20327
|
+
return mulDiv2(
|
|
20328
|
+
anchor,
|
|
20329
|
+
fixedPointMul(wholeMultiplier, fractionalMultiplier),
|
|
20330
|
+
APY_SCALE
|
|
20331
|
+
);
|
|
20332
|
+
}
|
|
20333
|
+
function fixedPointMul(lhs, rhs) {
|
|
20334
|
+
const lhsWhole = lhs / APY_SCALE;
|
|
20335
|
+
const lhsRemainder = lhs % APY_SCALE;
|
|
20336
|
+
const rhsWhole = rhs / APY_SCALE;
|
|
20337
|
+
const rhsRemainder = rhs % APY_SCALE;
|
|
20338
|
+
return lhsWhole * rhs + lhsRemainder * rhsWhole + lhsRemainder * rhsRemainder / APY_SCALE;
|
|
20339
|
+
}
|
|
20340
|
+
function fixedPointPow(baseInput, exponentInput) {
|
|
20341
|
+
let base = baseInput;
|
|
20342
|
+
let exponent = exponentInput;
|
|
20343
|
+
let result = APY_SCALE;
|
|
20344
|
+
while (exponent > 0n) {
|
|
20345
|
+
if ((exponent & 1n) === 1n) result = fixedPointMul(result, base);
|
|
20346
|
+
exponent >>= 1n;
|
|
20347
|
+
if (exponent > 0n) base = fixedPointMul(base, base);
|
|
20348
|
+
}
|
|
20349
|
+
return result;
|
|
20350
|
+
}
|
|
20351
|
+
function fixedPointLnBetweenOneAndTwo(value) {
|
|
20352
|
+
if (value < APY_SCALE || value > 2n * APY_SCALE) {
|
|
20353
|
+
throw new Error("APY logarithm input out of range");
|
|
20354
|
+
}
|
|
20355
|
+
const z = mulDiv2(value - APY_SCALE, APY_SCALE, value + APY_SCALE);
|
|
20356
|
+
const zSquared = fixedPointMul(z, z);
|
|
20357
|
+
let power = z;
|
|
20358
|
+
let sum = 0n;
|
|
20359
|
+
for (let index = 0; index < APY_SERIES_TERMS; index += 1) {
|
|
20360
|
+
sum += power / BigInt(2 * index + 1);
|
|
20361
|
+
power = fixedPointMul(power, zSquared);
|
|
20362
|
+
}
|
|
20363
|
+
return sum * 2n;
|
|
20364
|
+
}
|
|
20365
|
+
function fixedPointExp(value) {
|
|
20366
|
+
if (value > APY_LN_2) throw new Error("APY exponent input out of range");
|
|
20367
|
+
let sum = APY_SCALE;
|
|
20368
|
+
let term = APY_SCALE;
|
|
20369
|
+
for (let divisor = 1; divisor <= APY_SERIES_TERMS; divisor += 1) {
|
|
20370
|
+
term = fixedPointMul(term, value) / BigInt(divisor);
|
|
20371
|
+
if (term === 0n) break;
|
|
20372
|
+
sum += term;
|
|
20373
|
+
}
|
|
20374
|
+
return sum;
|
|
20375
|
+
}
|
|
20376
|
+
function readU64(data, offset) {
|
|
20377
|
+
let value = 0n;
|
|
20378
|
+
for (let index = 0; index < 8; index += 1) {
|
|
20379
|
+
value |= BigInt(data[offset + index] ?? 0) << BigInt(index * 8);
|
|
20380
|
+
}
|
|
20381
|
+
return value;
|
|
20382
|
+
}
|
|
20383
|
+
function readI64(data, offset) {
|
|
20384
|
+
const value = readU64(data, offset);
|
|
20385
|
+
return value >= 0x8000000000000000n ? value - 0x10000000000000000n : value;
|
|
20386
|
+
}
|
|
20387
|
+
function mulDiv2(a, b, c) {
|
|
20388
|
+
if (c === 0n) throw new Error("division by zero in settlement simulation");
|
|
20389
|
+
return a * b / c;
|
|
20390
|
+
}
|
|
20391
|
+
function record(value) {
|
|
20392
|
+
return value && typeof value === "object" ? value : {};
|
|
20393
|
+
}
|
|
20394
|
+
function bigint(value) {
|
|
20395
|
+
if (value === void 0 || value === null) return 0n;
|
|
20396
|
+
if (typeof value === "bigint") return value;
|
|
20397
|
+
if (typeof value === "number" || typeof value === "string") {
|
|
20398
|
+
return BigInt(value);
|
|
20399
|
+
}
|
|
20400
|
+
return BigInt(String(value));
|
|
20401
|
+
}
|
|
20402
|
+
function number(value) {
|
|
20403
|
+
return Number(bigint(value));
|
|
20404
|
+
}
|
|
20405
|
+
function bool(value) {
|
|
20406
|
+
if (typeof value === "boolean") return value;
|
|
20407
|
+
if (typeof value === "number") return value !== 0;
|
|
20408
|
+
if (value && typeof value.toBool === "function") {
|
|
20409
|
+
return value.toBool();
|
|
20410
|
+
}
|
|
20411
|
+
const pod = value;
|
|
20412
|
+
return Boolean(pod?.value ?? pod?.[0]);
|
|
20413
|
+
}
|
|
20414
|
+
function variant(value) {
|
|
20415
|
+
return (value && typeof value === "object" ? Object.keys(value)[0] ?? "" : String(value ?? "")).toLowerCase();
|
|
20416
|
+
}
|
|
20417
|
+
function pubkeyString3(value) {
|
|
20418
|
+
if (typeof value === "string") return value;
|
|
20419
|
+
if (value && typeof value.toBase58 === "function") {
|
|
20420
|
+
return value.toBase58();
|
|
20421
|
+
}
|
|
20422
|
+
return String(value);
|
|
20423
|
+
}
|
|
20424
|
+
function positiveOrDefault(value, fallback) {
|
|
20425
|
+
return value > 0n ? value : fallback;
|
|
20426
|
+
}
|
|
20427
|
+
function max(a, b) {
|
|
20428
|
+
return a > b ? a : b;
|
|
20429
|
+
}
|
|
20430
|
+
function abs(value) {
|
|
20431
|
+
return value < 0n ? -value : value;
|
|
20432
|
+
}
|
|
20433
|
+
function message(error) {
|
|
20434
|
+
return error instanceof Error ? error.message : String(error);
|
|
20435
|
+
}
|
|
20436
|
+
function formatSettlementSimulation(simulation) {
|
|
20437
|
+
const lines = [];
|
|
20438
|
+
lines.push(
|
|
20439
|
+
` proposed oracle values: ${simulation.allProposedUpdatesLand ? "WOULD REACH CONSENSUS" : "WOULD NOT ALL LAND"} (${simulation.proposedUpdatesLanded}/${simulation.proposedUpdatesTotal} holdings)`
|
|
20440
|
+
);
|
|
20441
|
+
lines.push(
|
|
20442
|
+
` crank simulation: ${simulation.canSettle ? "WOULD SETTLE" : "BLOCKED"}`
|
|
20443
|
+
);
|
|
20444
|
+
for (const holding of simulation.consensus) {
|
|
20445
|
+
const detail = holding.settledPrice ? `price=${holding.settledPrice} external=${holding.settledExternalAmount}` : holding.reason ?? "no aggregate";
|
|
20446
|
+
lines.push(
|
|
20447
|
+
` consensus #${holding.holdingIndex} ${holding.mint}: ${holding.reportCount} report(s), ${holding.wouldUpdateHolding ? "lands" : "unchanged"} (${detail})`
|
|
20448
|
+
);
|
|
20449
|
+
}
|
|
20450
|
+
if (simulation.grossNav !== void 0) {
|
|
20451
|
+
lines.push(
|
|
20452
|
+
` gross NAV: ${formatUnits(
|
|
20453
|
+
simulation.grossNav,
|
|
20454
|
+
simulation.assetDecimals
|
|
20455
|
+
)} [${simulation.grossNav}]`
|
|
20456
|
+
);
|
|
20457
|
+
}
|
|
20458
|
+
if (simulation.settledAccountingNav !== void 0 && simulation.settledAccountingNav !== simulation.grossNav) {
|
|
20459
|
+
lines.push(
|
|
20460
|
+
` accounting NAV after fixed APY: ${formatUnits(
|
|
20461
|
+
simulation.settledAccountingNav,
|
|
20462
|
+
simulation.assetDecimals
|
|
20463
|
+
)} [${simulation.settledAccountingNav}]`
|
|
20464
|
+
);
|
|
20465
|
+
}
|
|
20466
|
+
if (simulation.projected) {
|
|
20467
|
+
if (simulation.projectionRequiresMaxApyDisabled) {
|
|
20468
|
+
lines.push(" projection with max APY disabled (max_apy_bps=0):");
|
|
20469
|
+
}
|
|
20470
|
+
lines.push(
|
|
20471
|
+
` TVL: ${formatTransition(
|
|
20472
|
+
simulation.current.tvl,
|
|
20473
|
+
simulation.projected.tvl,
|
|
20474
|
+
simulation.assetDecimals
|
|
20475
|
+
)}`
|
|
20476
|
+
);
|
|
20477
|
+
lines.push(
|
|
20478
|
+
` regular: ${formatTransition(
|
|
20479
|
+
simulation.current.regular.sharePrice,
|
|
20480
|
+
simulation.projected.regular.sharePrice,
|
|
20481
|
+
6
|
|
20482
|
+
)} per share`
|
|
20483
|
+
);
|
|
20484
|
+
lines.push(
|
|
20485
|
+
` supply ${simulation.current.regular.totalSupply} -> ${simulation.projected.regular.totalSupply}, backing ${simulation.current.regular.value} -> ${simulation.projected.regular.value}`
|
|
20486
|
+
);
|
|
20487
|
+
if (simulation.current.junior && simulation.projected.junior) {
|
|
20488
|
+
lines.push(
|
|
20489
|
+
` junior: ${formatTransition(
|
|
20490
|
+
simulation.current.junior.sharePrice,
|
|
20491
|
+
simulation.projected.junior.sharePrice,
|
|
20492
|
+
6
|
|
20493
|
+
)} per share`
|
|
20494
|
+
);
|
|
20495
|
+
lines.push(
|
|
20496
|
+
` supply ${simulation.current.junior.totalSupply} -> ${simulation.projected.junior.totalSupply}, value ${simulation.current.junior.value} -> ${simulation.projected.junior.value}`
|
|
20497
|
+
);
|
|
20498
|
+
}
|
|
20499
|
+
if (simulation.current.senior && simulation.projected.senior) {
|
|
20500
|
+
lines.push(
|
|
20501
|
+
` senior: ${formatTransition(
|
|
20502
|
+
simulation.current.senior.sharePrice,
|
|
20503
|
+
simulation.projected.senior.sharePrice,
|
|
20504
|
+
6
|
|
20505
|
+
)} per share`
|
|
20506
|
+
);
|
|
20507
|
+
lines.push(
|
|
20508
|
+
` supply ${simulation.current.senior.totalSupply} -> ${simulation.projected.senior.totalSupply}, value ${simulation.current.senior.value} -> ${simulation.projected.senior.value}`
|
|
20509
|
+
);
|
|
20510
|
+
}
|
|
20511
|
+
}
|
|
20512
|
+
if (simulation.performanceFees) {
|
|
20513
|
+
lines.push(
|
|
20514
|
+
` performance fees: curator=${simulation.performanceFees.curator} protocol=${simulation.performanceFees.protocol} total=${simulation.performanceFees.total} fee_shares=${simulation.performanceFees.mintedShares}`
|
|
20515
|
+
);
|
|
20516
|
+
}
|
|
20517
|
+
for (const blocker of simulation.blockers)
|
|
20518
|
+
lines.push(` BLOCKER: ${blocker}`);
|
|
20519
|
+
for (const warning of simulation.warnings)
|
|
20520
|
+
lines.push(` warning: ${warning}`);
|
|
20521
|
+
return lines;
|
|
20522
|
+
}
|
|
20523
|
+
function formatTransition(before, after, decimals) {
|
|
20524
|
+
return `${formatUnits(before, decimals)} [${before}] -> ${formatUnits(
|
|
20525
|
+
after,
|
|
20526
|
+
decimals
|
|
20527
|
+
)} [${after}]`;
|
|
20528
|
+
}
|
|
20529
|
+
function formatUnits(value, decimals) {
|
|
20530
|
+
const negative = value < 0n;
|
|
20531
|
+
const absolute = negative ? -value : value;
|
|
20532
|
+
const scale = 10n ** BigInt(decimals);
|
|
20533
|
+
const whole = absolute / scale;
|
|
20534
|
+
const fraction = (absolute % scale).toString().padStart(decimals, "0").replace(/0+$/, "");
|
|
20535
|
+
return `${negative ? "-" : ""}${whole}${fraction ? `.${fraction}` : ""}`;
|
|
20536
|
+
}
|
|
20537
|
+
|
|
20538
|
+
// src/services/consensusOracle/consensusOracleService.ts
|
|
20539
|
+
var SYSTEM_PROGRAM2 = "11111111111111111111111111111111";
|
|
20540
|
+
var PRICE_ORACLE_TYPES_BY_INDEX2 = [
|
|
20541
|
+
"none",
|
|
20542
|
+
"consensusOracle",
|
|
20543
|
+
"pyth",
|
|
20544
|
+
"perenaVault"
|
|
20545
|
+
];
|
|
20546
|
+
var CONSENSUS_ORACLE_VARIANT = "consensusoracle";
|
|
20547
|
+
var LIVE_ORACLE_VARIANTS = /* @__PURE__ */ new Set(["pyth", "perenavault"]);
|
|
20548
|
+
var LIVE_PRICE_REFRESH_INTERVAL_SECS = 60n * 60n;
|
|
20549
|
+
var DEFAULT_PRICE_STALENESS_THRESHOLD_SECS3 = 24n * 60n * 60n;
|
|
20550
|
+
function variantName2(value) {
|
|
20551
|
+
if (typeof value === "number") {
|
|
20552
|
+
return PRICE_ORACLE_TYPES_BY_INDEX2[value] ?? String(value);
|
|
20553
|
+
}
|
|
20554
|
+
if (typeof value === "bigint") {
|
|
20555
|
+
return PRICE_ORACLE_TYPES_BY_INDEX2[Number(value)] ?? String(value);
|
|
20556
|
+
}
|
|
20557
|
+
if (value && typeof value === "object") return Object.keys(value)[0] ?? "";
|
|
20558
|
+
return String(value ?? "");
|
|
20559
|
+
}
|
|
20560
|
+
function coerceBool3(value) {
|
|
20561
|
+
if (typeof value === "boolean") return value;
|
|
20562
|
+
if (typeof value === "number") return value !== 0;
|
|
20563
|
+
const record2 = value;
|
|
20564
|
+
return Boolean(record2?.value ?? record2?.[0]);
|
|
20565
|
+
}
|
|
20566
|
+
function toBigInt2(value) {
|
|
20567
|
+
if (typeof value === "bigint") return value;
|
|
20568
|
+
if (typeof value === "number") return BigInt(Math.trunc(value));
|
|
20569
|
+
if (typeof value === "string" && value.length > 0) return BigInt(value);
|
|
20570
|
+
if (value !== null && value !== void 0) return BigInt(String(value));
|
|
20571
|
+
return 0n;
|
|
20572
|
+
}
|
|
20573
|
+
function priceInAccountingUnit(usd, baseUsd, assetDecimals) {
|
|
20574
|
+
return BigInt(Math.round(usd / baseUsd * 10 ** assetDecimals));
|
|
20575
|
+
}
|
|
20576
|
+
function sumPositionsByMint(positions) {
|
|
20577
|
+
const byMint = /* @__PURE__ */ new Map();
|
|
20578
|
+
for (const pos of positions) {
|
|
20579
|
+
const key = pos.mint.toString();
|
|
20580
|
+
byMint.set(key, (byMint.get(key) ?? 0n) + pos.amount);
|
|
20581
|
+
}
|
|
20582
|
+
return byMint;
|
|
20583
|
+
}
|
|
20584
|
+
function parseExternalLiquidityRefs(vaultState) {
|
|
20585
|
+
const slots = vaultState.externalLiquidity;
|
|
20586
|
+
if (!Array.isArray(slots)) return [];
|
|
20587
|
+
const refs = [];
|
|
20588
|
+
for (const slot of slots) {
|
|
20589
|
+
const data = slot?.data;
|
|
20590
|
+
if (!data || data.length < 40) continue;
|
|
20591
|
+
if (data[0] !== 1) continue;
|
|
19607
20592
|
const pubkeyBytes = new Uint8Array(data.slice(8, 40));
|
|
19608
|
-
const userAccount = new
|
|
20593
|
+
const userAccount = new import_web327.PublicKey(pubkeyBytes).toBase58();
|
|
19609
20594
|
refs.push({
|
|
19610
20595
|
kind: "marginfi",
|
|
19611
20596
|
mint: "",
|
|
@@ -19629,24 +20614,71 @@ var ConsensusOracleService = class {
|
|
|
19629
20614
|
const log = opts.log ?? (() => {
|
|
19630
20615
|
});
|
|
19631
20616
|
const dryRun = opts.dryRun ?? false;
|
|
19632
|
-
|
|
19633
|
-
const
|
|
20617
|
+
let vaultState = await this.fetchDecodedVault(target.vault);
|
|
20618
|
+
const refreshedLivePrices = await this.refreshLiveOraclePrices(
|
|
20619
|
+
signer,
|
|
20620
|
+
target.vault,
|
|
20621
|
+
vaultState,
|
|
20622
|
+
log,
|
|
20623
|
+
dryRun
|
|
20624
|
+
);
|
|
20625
|
+
if (refreshedLivePrices) {
|
|
20626
|
+
vaultState = await this.fetchDecodedVault(target.vault);
|
|
20627
|
+
}
|
|
20628
|
+
const receiptMints = await this.fetchReceiptMints(target.vault, vaultState);
|
|
20629
|
+
const consensusHoldings = selectConsensusHoldings(
|
|
20630
|
+
vaultState.holdings,
|
|
20631
|
+
receiptMints
|
|
20632
|
+
);
|
|
20633
|
+
const filteredCount = vaultState.holdings.filter(
|
|
20634
|
+
(holding) => receiptMints.has((0, import_common41.fromWeb3Pk)(holding.mint).toString())
|
|
20635
|
+
).length;
|
|
20636
|
+
if (filteredCount > 0) {
|
|
20637
|
+
log(
|
|
20638
|
+
`vault ${target.vault}: excluded ${filteredCount} vault/tranche receipt mint holding(s)`
|
|
20639
|
+
);
|
|
20640
|
+
}
|
|
19634
20641
|
if (consensusHoldings.length === 0) {
|
|
19635
20642
|
log(`vault ${target.vault}: no consensus holdings, skipping`);
|
|
19636
20643
|
return { vault: target.vault, updates: [], dryRun };
|
|
19637
20644
|
}
|
|
19638
|
-
|
|
20645
|
+
const filteredTarget = filterTargetHoldings(target, receiptMints);
|
|
20646
|
+
await this.assertNoUnconfirmedYieldPayments(filteredTarget);
|
|
19639
20647
|
const inputs = await this.gatherPricingInputs(
|
|
19640
|
-
|
|
20648
|
+
filteredTarget,
|
|
19641
20649
|
vaultState,
|
|
19642
20650
|
consensusHoldings
|
|
19643
20651
|
);
|
|
19644
20652
|
const updates = await this.buildUpdates(consensusHoldings, inputs);
|
|
19645
20653
|
if (dryRun) {
|
|
19646
20654
|
log(`vault ${target.vault}: dry run, ${updates.length} holding(s)`);
|
|
19647
|
-
|
|
20655
|
+
try {
|
|
20656
|
+
const settlementSimulation = await this.simulateDryRunSettlement(
|
|
20657
|
+
signer,
|
|
20658
|
+
target.vault,
|
|
20659
|
+
vaultState,
|
|
20660
|
+
updates
|
|
20661
|
+
);
|
|
20662
|
+
return {
|
|
20663
|
+
vault: target.vault,
|
|
20664
|
+
updates,
|
|
20665
|
+
dryRun: true,
|
|
20666
|
+
settlementSimulation
|
|
20667
|
+
};
|
|
20668
|
+
} catch (error) {
|
|
20669
|
+
const settlementSimulationError = error instanceof Error ? error.message : String(error);
|
|
20670
|
+
log(
|
|
20671
|
+
`vault ${target.vault}: settlement simulation unavailable: ${settlementSimulationError}`
|
|
20672
|
+
);
|
|
20673
|
+
return {
|
|
20674
|
+
vault: target.vault,
|
|
20675
|
+
updates,
|
|
20676
|
+
dryRun: true,
|
|
20677
|
+
settlementSimulationError
|
|
20678
|
+
};
|
|
20679
|
+
}
|
|
19648
20680
|
}
|
|
19649
|
-
const { updateSignature, crankSignature, crankSkippedReason } = await this.settleVault(signer,
|
|
20681
|
+
const { updateSignature, crankSignature, crankSkippedReason } = await this.settleVault(signer, filteredTarget, updates, vaultState, log);
|
|
19650
20682
|
return {
|
|
19651
20683
|
vault: target.vault,
|
|
19652
20684
|
updates,
|
|
@@ -19656,6 +20688,43 @@ var ConsensusOracleService = class {
|
|
|
19656
20688
|
crankSkippedReason
|
|
19657
20689
|
};
|
|
19658
20690
|
}
|
|
20691
|
+
/** Read canonical supplies and replay the exact on-chain settlement path. */
|
|
20692
|
+
async simulateDryRunSettlement(signer, vault, vaultState, updates) {
|
|
20693
|
+
const tranchingEnabled = coerceBool3(vaultState.tranchingEnabled);
|
|
20694
|
+
const [oracleState, trancheState] = await Promise.all([
|
|
20695
|
+
this.client.account.fetchVaultOracleForVault(vault, { fresh: true }),
|
|
20696
|
+
tranchingEnabled ? this.client.account.fetchVaultTrancheStateForVault(vault, {
|
|
20697
|
+
fresh: true
|
|
20698
|
+
}) : Promise.resolve(void 0)
|
|
20699
|
+
]);
|
|
20700
|
+
const mintKeys = [new import_web327.PublicKey(vaultState.mint)];
|
|
20701
|
+
if (trancheState) {
|
|
20702
|
+
mintKeys.push(
|
|
20703
|
+
new import_web327.PublicKey(trancheState.config.juniorMint),
|
|
20704
|
+
new import_web327.PublicKey(trancheState.config.seniorMint)
|
|
20705
|
+
);
|
|
20706
|
+
}
|
|
20707
|
+
const mintAccounts = await this.client.provider.connection.getMultipleAccountsInfo(
|
|
20708
|
+
mintKeys,
|
|
20709
|
+
"confirmed"
|
|
20710
|
+
);
|
|
20711
|
+
const supplies = mintAccounts.map((info, index) => {
|
|
20712
|
+
if (!info)
|
|
20713
|
+
throw new Error(`share mint ${mintKeys[index]} does not exist`);
|
|
20714
|
+
return readSplMintSupply(info.data);
|
|
20715
|
+
});
|
|
20716
|
+
return simulateConsensusOracleSettlement({
|
|
20717
|
+
vault: vaultState,
|
|
20718
|
+
oracleData: oracleState.data,
|
|
20719
|
+
trancheState,
|
|
20720
|
+
updates,
|
|
20721
|
+
signer: (0, import_common41.fromWeb3Pk)(signer.publicKey),
|
|
20722
|
+
nowTs: BigInt(Math.floor(this.clock.now() / 1e3)),
|
|
20723
|
+
physicalShareSupply: supplies[0],
|
|
20724
|
+
physicalJuniorSupply: tranchingEnabled ? supplies[1] : void 0,
|
|
20725
|
+
physicalSeniorSupply: tranchingEnabled ? supplies[2] : void 0
|
|
20726
|
+
});
|
|
20727
|
+
}
|
|
19659
20728
|
/**
|
|
19660
20729
|
* Fail closed while any configured yield account has an unsettled payment.
|
|
19661
20730
|
* The payout must be confirmed only after it is visible in the same wallet
|
|
@@ -19777,6 +20846,86 @@ var ConsensusOracleService = class {
|
|
|
19777
20846
|
fresh: true
|
|
19778
20847
|
});
|
|
19779
20848
|
}
|
|
20849
|
+
/**
|
|
20850
|
+
* Keep active permissionless price sources warm so they cannot block the NAV
|
|
20851
|
+
* crank after the consensus report lands. Prices are refreshed at least once
|
|
20852
|
+
* per hour, or at the vault's shorter staleness interval when configured.
|
|
20853
|
+
*/
|
|
20854
|
+
async refreshLiveOraclePrices(signer, vault, vaultState, log, dryRun) {
|
|
20855
|
+
const nowSecs = BigInt(Math.floor(this.clock.now() / 1e3));
|
|
20856
|
+
const configuredStaleness = toBigInt2(
|
|
20857
|
+
vaultState.config.priceStalenessThresholdSecs
|
|
20858
|
+
);
|
|
20859
|
+
const stalenessThreshold = configuredStaleness > 0n ? configuredStaleness : DEFAULT_PRICE_STALENESS_THRESHOLD_SECS3;
|
|
20860
|
+
const refreshInterval = stalenessThreshold < LIVE_PRICE_REFRESH_INTERVAL_SECS ? stalenessThreshold : LIVE_PRICE_REFRESH_INTERVAL_SECS;
|
|
20861
|
+
const targets = [];
|
|
20862
|
+
for (const holding of vaultState.holdings) {
|
|
20863
|
+
const oracleType = variantName2(holding.priceOracleType).toLowerCase();
|
|
20864
|
+
if (!LIVE_ORACLE_VARIANTS.has(oracleType)) continue;
|
|
20865
|
+
const mint = (0, import_common41.fromWeb3Pk)(holding.mint);
|
|
20866
|
+
if (mint.toString() === SYSTEM_PROGRAM2) continue;
|
|
20867
|
+
const activeAmount = toBigInt2(holding.localAmount) + toBigInt2(holding.externalAmount);
|
|
20868
|
+
if (activeAmount === 0n) continue;
|
|
20869
|
+
const lastUpdateTs = toBigInt2(holding.lastUpdateTs);
|
|
20870
|
+
const ageSecs = nowSecs - lastUpdateTs;
|
|
20871
|
+
if (lastUpdateTs > 0n && ageSecs >= 0n && ageSecs < refreshInterval) {
|
|
20872
|
+
continue;
|
|
20873
|
+
}
|
|
20874
|
+
if (!holding.priceOracleAccount) {
|
|
20875
|
+
log(
|
|
20876
|
+
`vault ${vault}: cannot refresh ${mint}; ${oracleType} holding has no oracle account`
|
|
20877
|
+
);
|
|
20878
|
+
continue;
|
|
20879
|
+
}
|
|
20880
|
+
const oracleAccount = (0, import_common41.fromWeb3Pk)(holding.priceOracleAccount);
|
|
20881
|
+
if (oracleAccount.toString() === SYSTEM_PROGRAM2) {
|
|
20882
|
+
log(
|
|
20883
|
+
`vault ${vault}: cannot refresh ${mint}; ${oracleType} holding has no oracle account`
|
|
20884
|
+
);
|
|
20885
|
+
continue;
|
|
20886
|
+
}
|
|
20887
|
+
targets.push({ mint, oracleAccount });
|
|
20888
|
+
}
|
|
20889
|
+
if (targets.length === 0) return false;
|
|
20890
|
+
if (dryRun) {
|
|
20891
|
+
log(
|
|
20892
|
+
`vault ${vault}: dry run, would refresh ${targets.length} live asset price(s)`
|
|
20893
|
+
);
|
|
20894
|
+
return false;
|
|
20895
|
+
}
|
|
20896
|
+
log(
|
|
20897
|
+
`vault ${vault}: refreshing ${targets.length} live asset price(s) due for hourly refresh`
|
|
20898
|
+
);
|
|
20899
|
+
const results = await this.oracle.refreshAssetPrices(
|
|
20900
|
+
signer,
|
|
20901
|
+
vault,
|
|
20902
|
+
targets,
|
|
20903
|
+
log
|
|
20904
|
+
);
|
|
20905
|
+
return results.some((result) => Boolean(result.signature));
|
|
20906
|
+
}
|
|
20907
|
+
/**
|
|
20908
|
+
* Receipt mints issued by this vault are liabilities/shares, not underlying
|
|
20909
|
+
* assets for its own NAV. Exclude them even if they were registered as
|
|
20910
|
+
* consensus-priced holdings.
|
|
20911
|
+
*/
|
|
20912
|
+
async fetchReceiptMints(vault, vaultState) {
|
|
20913
|
+
const receiptMints = /* @__PURE__ */ new Set();
|
|
20914
|
+
if (vaultState.mint) {
|
|
20915
|
+
receiptMints.add((0, import_common41.fromWeb3Pk)(vaultState.mint).toString());
|
|
20916
|
+
}
|
|
20917
|
+
if (!coerceBool3(vaultState.tranchingEnabled)) return receiptMints;
|
|
20918
|
+
const trancheState = await this.client.account.fetchVaultTrancheStateForVault(vault, {
|
|
20919
|
+
fresh: true
|
|
20920
|
+
});
|
|
20921
|
+
receiptMints.add(
|
|
20922
|
+
(0, import_common41.fromWeb3Pk)(trancheState.config.juniorMint).toString()
|
|
20923
|
+
);
|
|
20924
|
+
receiptMints.add(
|
|
20925
|
+
(0, import_common41.fromWeb3Pk)(trancheState.config.seniorMint).toString()
|
|
20926
|
+
);
|
|
20927
|
+
return receiptMints;
|
|
20928
|
+
}
|
|
19780
20929
|
/** Fetch every external input the per-holding updates draw on, in parallel-ish. */
|
|
19781
20930
|
async gatherPricingInputs(target, vaultState, consensusHoldings) {
|
|
19782
20931
|
const manager = (0, import_common41.fromWeb3Pk)(vaultState.roles.manager);
|
|
@@ -19922,12 +21071,13 @@ var ConsensusOracleService = class {
|
|
|
19922
21071
|
};
|
|
19923
21072
|
}
|
|
19924
21073
|
/**
|
|
19925
|
-
* Fetch the current
|
|
19926
|
-
*
|
|
21074
|
+
* Fetch the current settlement timestamp and log the APY implied by the
|
|
21075
|
+
* prospective update, so MaxApyExceeded failures are diagnosable.
|
|
19927
21076
|
*
|
|
19928
21077
|
* NAV is expressed in the vault's accounting unit (scaled by assetDecimals).
|
|
19929
|
-
*
|
|
19930
|
-
*
|
|
21078
|
+
* Mirrors `gross_nav_from_holdings`: consensus updates overlay their target
|
|
21079
|
+
* slots, while live-priced and otherwise unchanged holdings retain their
|
|
21080
|
+
* current price/external amount.
|
|
19931
21081
|
*/
|
|
19932
21082
|
async logProspectiveApy(vault, updates, vaultState, log) {
|
|
19933
21083
|
try {
|
|
@@ -19936,22 +21086,38 @@ var ConsensusOracleService = class {
|
|
|
19936
21086
|
});
|
|
19937
21087
|
const data = oracle.data;
|
|
19938
21088
|
if (!data || data.length < 16) return;
|
|
19939
|
-
const settledNav = readI64LE(data, 0);
|
|
19940
21089
|
const settledNavTs = readI64LE(data, 8);
|
|
19941
|
-
if (
|
|
19942
|
-
const
|
|
19943
|
-
|
|
19944
|
-
|
|
19945
|
-
|
|
19946
|
-
|
|
19947
|
-
|
|
21090
|
+
if (settledNavTs <= 0n) return;
|
|
21091
|
+
const updatesByIndex = new Map(
|
|
21092
|
+
updates.map((update) => [update.holdingIndex, update])
|
|
21093
|
+
);
|
|
21094
|
+
const prospectiveNav = vaultState.holdings.reduce(
|
|
21095
|
+
(sum, holding, holdingIndex) => {
|
|
21096
|
+
const mint = (0, import_common41.fromWeb3Pk)(holding.mint).toString();
|
|
21097
|
+
if (mint === SYSTEM_PROGRAM2) return sum;
|
|
21098
|
+
const update = updatesByIndex.get(holdingIndex);
|
|
21099
|
+
const localAmount = toBigInt2(holding.localAmount);
|
|
21100
|
+
const externalAmount = update ? update.externalAmount : toBigInt2(holding.externalAmount);
|
|
21101
|
+
const amount = localAmount + externalAmount;
|
|
21102
|
+
if (amount === 0n) return sum;
|
|
21103
|
+
const price = update ? update.price : toBigInt2(holding.price);
|
|
21104
|
+
if (price <= 0n) return sum;
|
|
21105
|
+
const scale = 10n ** BigInt(holding.decimals);
|
|
21106
|
+
return sum + amount * price / scale;
|
|
21107
|
+
},
|
|
21108
|
+
0n
|
|
21109
|
+
);
|
|
21110
|
+
const currentTvl = toBigInt2(vaultState.accounting?.tvl);
|
|
21111
|
+
const accruedApyBalance = coerceBool3(vaultState.tranchingEnabled) ? toBigInt2(vaultState.config.apy?.accruedApyBalance) : 0n;
|
|
21112
|
+
const physicalNavBefore = currentTvl + (accruedApyBalance > 0n ? accruedApyBalance : 0n);
|
|
21113
|
+
if (physicalNavBefore <= 0n) return;
|
|
19948
21114
|
const nowSecs = BigInt(Math.floor(this.clock.now() / 1e3));
|
|
19949
21115
|
const elapsedSecs = nowSecs - settledNavTs;
|
|
19950
21116
|
if (elapsedSecs <= 0n) return;
|
|
19951
|
-
const
|
|
19952
|
-
const apyBps = (prospectiveNav -
|
|
21117
|
+
const SECONDS_PER_YEAR3 = 365n * 24n * 3600n;
|
|
21118
|
+
const apyBps = (prospectiveNav - physicalNavBefore) * SECONDS_PER_YEAR3 * 10000n / (physicalNavBefore * elapsedSecs);
|
|
19953
21119
|
log(
|
|
19954
|
-
`vault ${vault}: prospective NAV ${prospectiveNav} vs
|
|
21120
|
+
`vault ${vault}: prospective NAV ${prospectiveNav} vs physical baseline ${physicalNavBefore} (elapsed ${elapsedSecs}s) \u2192 implied APY ${apyBps}bps`
|
|
19955
21121
|
);
|
|
19956
21122
|
} catch {
|
|
19957
21123
|
}
|
|
@@ -19965,13 +21131,23 @@ function readI64LE(data, offset) {
|
|
|
19965
21131
|
if (value >= 0x8000000000000000n) value -= 0x10000000000000000n;
|
|
19966
21132
|
return value;
|
|
19967
21133
|
}
|
|
19968
|
-
|
|
19969
|
-
|
|
21134
|
+
function readSplMintSupply(data) {
|
|
21135
|
+
if (data.length < 44) {
|
|
21136
|
+
throw new Error(`invalid SPL mint account: expected at least 44 bytes`);
|
|
21137
|
+
}
|
|
21138
|
+
let supply = 0n;
|
|
21139
|
+
for (let i = 0; i < 8; i += 1) {
|
|
21140
|
+
supply |= BigInt(data[36 + i]) << BigInt(8 * i);
|
|
21141
|
+
}
|
|
21142
|
+
return supply;
|
|
21143
|
+
}
|
|
21144
|
+
var ENTRY_SIZE2 = 272;
|
|
21145
|
+
var ENTRIES_OFFSET2 = 40;
|
|
19970
21146
|
var MAX_CONSENSUS_SIGNERS = 4;
|
|
19971
21147
|
function signerInOracleData(data, signerBytes) {
|
|
19972
21148
|
const ZERO_PUBKEY = new Uint8Array(32);
|
|
19973
21149
|
for (let i = 0; i < MAX_CONSENSUS_SIGNERS; i++) {
|
|
19974
|
-
const off =
|
|
21150
|
+
const off = ENTRIES_OFFSET2 + i * ENTRY_SIZE2;
|
|
19975
21151
|
const slice = data.slice(off, off + 32);
|
|
19976
21152
|
if (slice.length < 32) break;
|
|
19977
21153
|
const bytes = new Uint8Array(slice);
|
|
@@ -19981,12 +21157,21 @@ function signerInOracleData(data, signerBytes) {
|
|
|
19981
21157
|
}
|
|
19982
21158
|
return false;
|
|
19983
21159
|
}
|
|
19984
|
-
function selectConsensusHoldings(holdings) {
|
|
21160
|
+
function selectConsensusHoldings(holdings, excludedMints = /* @__PURE__ */ new Set()) {
|
|
19985
21161
|
return holdings.map((holding, holdingIndex) => ({ holding, holdingIndex })).filter(({ holding }) => {
|
|
19986
21162
|
const mint = (0, import_common41.fromWeb3Pk)(holding.mint);
|
|
19987
|
-
return mint !== SYSTEM_PROGRAM2 && variantName2(holding.priceOracleType).toLowerCase() === CONSENSUS_ORACLE_VARIANT;
|
|
21163
|
+
return mint !== SYSTEM_PROGRAM2 && !excludedMints.has(mint.toString()) && variantName2(holding.priceOracleType).toLowerCase() === CONSENSUS_ORACLE_VARIANT;
|
|
19988
21164
|
});
|
|
19989
21165
|
}
|
|
21166
|
+
function filterTargetHoldings(target, excludedMints) {
|
|
21167
|
+
if (!target.holdings?.length || excludedMints.size === 0) return target;
|
|
21168
|
+
return {
|
|
21169
|
+
...target,
|
|
21170
|
+
holdings: target.holdings.filter(
|
|
21171
|
+
(holding) => !excludedMints.has(holding.mint.toString())
|
|
21172
|
+
)
|
|
21173
|
+
};
|
|
21174
|
+
}
|
|
19990
21175
|
|
|
19991
21176
|
// src/services/consensusOracle/runLiveConsensusOracle.ts
|
|
19992
21177
|
async function runLiveConsensusOracle(env, oracleSigner, opts = {}) {
|
|
@@ -20010,7 +21195,7 @@ async function runLiveConsensusOracle(env, oracleSigner, opts = {}) {
|
|
|
20010
21195
|
}
|
|
20011
21196
|
|
|
20012
21197
|
// src/services/consensusOracle/mockYieldTracker.ts
|
|
20013
|
-
var
|
|
21198
|
+
var SECONDS_PER_YEAR2 = 365 * 24 * 60 * 60;
|
|
20014
21199
|
var MockYieldTracker = class {
|
|
20015
21200
|
constructor(opts = {}) {
|
|
20016
21201
|
this.accounts = /* @__PURE__ */ new Map();
|
|
@@ -20065,12 +21250,12 @@ var MockYieldTracker = class {
|
|
|
20065
21250
|
let segStart = windowStartMs;
|
|
20066
21251
|
for (const cf of boundaries) {
|
|
20067
21252
|
const dtSecs = (cf.ts - segStart) / 1e3;
|
|
20068
|
-
totalYield += principal * apr * (dtSecs /
|
|
21253
|
+
totalYield += principal * apr * (dtSecs / SECONDS_PER_YEAR2);
|
|
20069
21254
|
principal += cf.amount;
|
|
20070
21255
|
segStart = cf.ts;
|
|
20071
21256
|
}
|
|
20072
21257
|
const tailSecs = Math.max(0, (windowEndMs - segStart) / 1e3);
|
|
20073
|
-
totalYield += principal * apr * (tailSecs /
|
|
21258
|
+
totalYield += principal * apr * (tailSecs / SECONDS_PER_YEAR2);
|
|
20074
21259
|
const paidYield = state.yieldPayments.reduce((sum, payment) => {
|
|
20075
21260
|
return payment.status === "confirmed" && payment.effectiveAt > windowStartMs && payment.effectiveAt <= windowEndMs ? sum + payment.amount : sum;
|
|
20076
21261
|
}, 0);
|
|
@@ -20090,22 +21275,22 @@ var MockYieldTracker = class {
|
|
|
20090
21275
|
async getTotalYield(accountNames, start, end) {
|
|
20091
21276
|
let total = 0;
|
|
20092
21277
|
for (const name of accountNames) {
|
|
20093
|
-
const
|
|
20094
|
-
total +=
|
|
21278
|
+
const snapshot2 = await this.getYield(name, start, end);
|
|
21279
|
+
total += snapshot2.totalYield;
|
|
20095
21280
|
}
|
|
20096
21281
|
return total;
|
|
20097
21282
|
}
|
|
20098
21283
|
async getTotalOutstandingYield(accountNames, start, end) {
|
|
20099
21284
|
let total = 0;
|
|
20100
21285
|
for (const name of accountNames) {
|
|
20101
|
-
const
|
|
20102
|
-
total +=
|
|
21286
|
+
const snapshot2 = await this.getYield(name, start, end);
|
|
21287
|
+
total += snapshot2.outstandingYield;
|
|
20103
21288
|
}
|
|
20104
21289
|
return total;
|
|
20105
21290
|
}
|
|
20106
21291
|
async getBalance(accountName, atTime) {
|
|
20107
|
-
const
|
|
20108
|
-
return
|
|
21292
|
+
const snapshot2 = await this.getYield(accountName, void 0, atTime);
|
|
21293
|
+
return snapshot2.principalAtEnd + snapshot2.outstandingYield;
|
|
20109
21294
|
}
|
|
20110
21295
|
async addCashflow(params) {
|
|
20111
21296
|
const state = this.require(params.accountName);
|
|
@@ -20157,12 +21342,12 @@ var MockYieldTracker = class {
|
|
|
20157
21342
|
let cumulativePaid = 0;
|
|
20158
21343
|
for (const candidate of chronologicalPayments) {
|
|
20159
21344
|
cumulativePaid += candidate.amount;
|
|
20160
|
-
const
|
|
21345
|
+
const snapshot2 = await this.getYield(
|
|
20161
21346
|
params.accountName,
|
|
20162
21347
|
void 0,
|
|
20163
21348
|
new Date(candidate.effectiveAt)
|
|
20164
21349
|
);
|
|
20165
|
-
if (cumulativePaid >
|
|
21350
|
+
if (cumulativePaid > snapshot2.totalYield + 1e-9) {
|
|
20166
21351
|
throw new Error("Confirmed payment exceeds accrued unpaid yield");
|
|
20167
21352
|
}
|
|
20168
21353
|
}
|
|
@@ -20172,8 +21357,8 @@ var MockYieldTracker = class {
|
|
|
20172
21357
|
};
|
|
20173
21358
|
|
|
20174
21359
|
// src/services/externalLiquidityIntegrityService.ts
|
|
20175
|
-
var
|
|
20176
|
-
var
|
|
21360
|
+
var import_kit15 = require("@solana/kit");
|
|
21361
|
+
var import_web328 = require("@solana/web3.js");
|
|
20177
21362
|
var import_common42 = __toESM(require_dist());
|
|
20178
21363
|
var import_marginfi2 = __toESM(require_dist2());
|
|
20179
21364
|
function parseActiveSlots(externalLiquidity) {
|
|
@@ -20186,12 +21371,12 @@ function parseActiveSlots(externalLiquidity) {
|
|
|
20186
21371
|
if (discriminant === 0) continue;
|
|
20187
21372
|
if (discriminant !== 1) continue;
|
|
20188
21373
|
const pubkeyBytes = new Uint8Array(data.slice(8, 40));
|
|
20189
|
-
const userAccount = (0, import_common42.toAddress)(new
|
|
21374
|
+
const userAccount = (0, import_common42.toAddress)(new import_web328.PublicKey(pubkeyBytes));
|
|
20190
21375
|
results.push({ index: i, source: "marginfi", userAccount });
|
|
20191
21376
|
}
|
|
20192
21377
|
return results;
|
|
20193
21378
|
}
|
|
20194
|
-
function
|
|
21379
|
+
function toBigInt3(value) {
|
|
20195
21380
|
if (typeof value === "bigint") return value;
|
|
20196
21381
|
if (value !== null && value !== void 0) return BigInt(String(value));
|
|
20197
21382
|
return 0n;
|
|
@@ -20252,7 +21437,7 @@ var ExternalLiquidityIntegrityService = class {
|
|
|
20252
21437
|
return result;
|
|
20253
21438
|
}
|
|
20254
21439
|
const hwManagerAddress = (0, import_common42.fromWeb3Pk)(hwManager.publicKey);
|
|
20255
|
-
const vaultPk = new
|
|
21440
|
+
const vaultPk = new import_web328.PublicKey(vault.toString());
|
|
20256
21441
|
const registeredHwManager = pubkeyStr(
|
|
20257
21442
|
vaultState.roles.hwManager
|
|
20258
21443
|
);
|
|
@@ -20271,7 +21456,7 @@ var ExternalLiquidityIntegrityService = class {
|
|
|
20271
21456
|
}
|
|
20272
21457
|
const holdings = vaultState.holdings.filter((h) => {
|
|
20273
21458
|
const mint = pubkeyStr(h.mint);
|
|
20274
|
-
return !isZeroPubkey2(mint) &&
|
|
21459
|
+
return !isZeroPubkey2(mint) && toBigInt3(h.localAmount) > 0n;
|
|
20275
21460
|
});
|
|
20276
21461
|
if (holdings.length === 0) {
|
|
20277
21462
|
log(`Vault ${vault} slot ${slot.index}: no local balance to deploy`);
|
|
@@ -20279,8 +21464,8 @@ var ExternalLiquidityIntegrityService = class {
|
|
|
20279
21464
|
continue;
|
|
20280
21465
|
}
|
|
20281
21466
|
for (const holding of holdings) {
|
|
20282
|
-
const mintAddress = (0,
|
|
20283
|
-
const localAmount =
|
|
21467
|
+
const mintAddress = (0, import_kit15.address)(pubkeyStr(holding.mint));
|
|
21468
|
+
const localAmount = toBigInt3(holding.localAmount);
|
|
20284
21469
|
const marginfiAccounts = (0, import_marginfi2.marginfiAccountsForMint)(mintAddress);
|
|
20285
21470
|
if (!marginfiAccounts) {
|
|
20286
21471
|
log(
|
|
@@ -20395,11 +21580,17 @@ var ExternalLiquidityIntegrityService = class {
|
|
|
20395
21580
|
JupiterPriceSource,
|
|
20396
21581
|
JupiterSwapBuilder,
|
|
20397
21582
|
KaminoPositionProvider,
|
|
21583
|
+
LOCAL_PROTOCOL_ADMIN,
|
|
21584
|
+
LivePriceSource,
|
|
20398
21585
|
MAX_PRICE_STALENESS_THRESHOLD_SECS,
|
|
20399
21586
|
ManagerRedepositAssetBuilder,
|
|
20400
21587
|
ManagerWithdrawAssetBuilder,
|
|
20401
21588
|
MarginfiPositionProvider,
|
|
20402
21589
|
MockYieldTracker,
|
|
21590
|
+
NEST_API_BASE_URL,
|
|
21591
|
+
NEST_RWA_SHARE_MINT,
|
|
21592
|
+
NEST_VAULT_SLUG,
|
|
21593
|
+
NestPriceSource,
|
|
20403
21594
|
OracleService,
|
|
20404
21595
|
PROGRAM_FEE_EXEMPT_OWNER_WHITELIST,
|
|
20405
21596
|
PROTOCOL_ADMIN,
|
|
@@ -20442,6 +21633,7 @@ var ExternalLiquidityIntegrityService = class {
|
|
|
20442
21633
|
WithdrawalQueueService,
|
|
20443
21634
|
addCashflowUpdate,
|
|
20444
21635
|
address,
|
|
21636
|
+
applyEffectiveApy,
|
|
20445
21637
|
confirmYieldPayment,
|
|
20446
21638
|
createAccount,
|
|
20447
21639
|
createLiveConsensusOracleDeps,
|
|
@@ -20453,7 +21645,9 @@ var ExternalLiquidityIntegrityService = class {
|
|
|
20453
21645
|
dateToStr,
|
|
20454
21646
|
defaultKeypairPath,
|
|
20455
21647
|
deleteAccount,
|
|
21648
|
+
fetchNestTokenPrice,
|
|
20456
21649
|
findSquadsWalletRoute,
|
|
21650
|
+
formatSettlementSimulation,
|
|
20457
21651
|
fromUiAmount,
|
|
20458
21652
|
getAccounts,
|
|
20459
21653
|
getBalance,
|
|
@@ -20474,6 +21668,7 @@ var ExternalLiquidityIntegrityService = class {
|
|
|
20474
21668
|
resolveSquadsWalletRoute,
|
|
20475
21669
|
roundToNextUtcMidnight,
|
|
20476
21670
|
runLiveConsensusOracle,
|
|
21671
|
+
simulateConsensusOracleSettlement,
|
|
20477
21672
|
systemClock,
|
|
20478
21673
|
toUiAmount,
|
|
20479
21674
|
updateAccount,
|