@liquidium/client 0.6.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +333 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +164 -30
- package/dist/index.d.ts +164 -30
- package/dist/index.js +326 -26
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -45,6 +45,7 @@ var LiquidiumErrorCode = {
|
|
|
45
45
|
WITHDRAW_TOO_LOW: "WITHDRAW_TOO_LOW",
|
|
46
46
|
REPAYMENT_EXCEEDS_DEBT: "REPAYMENT_EXCEEDS_DEBT",
|
|
47
47
|
INVALID_ADDRESS: "INVALID_ADDRESS",
|
|
48
|
+
CONTRACT_DESTINATION_UNSUPPORTED: "CONTRACT_DESTINATION_UNSUPPORTED",
|
|
48
49
|
DEPOSIT_ADDRESS_ERROR: "DEPOSIT_ADDRESS_ERROR",
|
|
49
50
|
// Transport
|
|
50
51
|
NETWORK_ERROR: "NETWORK_ERROR",
|
|
@@ -1053,8 +1054,11 @@ function normalizeEvmAddress(address) {
|
|
|
1053
1054
|
// src/core/utils/time.ts
|
|
1054
1055
|
var MILLISECONDS_PER_SECOND = 1e3;
|
|
1055
1056
|
var SIGNATURE_VALIDITY_5_MINUTES_IN_SECONDS = 5n * 60n;
|
|
1057
|
+
function getCurrentUnixTimestampSeconds() {
|
|
1058
|
+
return BigInt(Math.floor(Date.now() / MILLISECONDS_PER_SECOND));
|
|
1059
|
+
}
|
|
1056
1060
|
function computeExpiryTimestampFromNow(signatureValidityInSeconds = SIGNATURE_VALIDITY_5_MINUTES_IN_SECONDS) {
|
|
1057
|
-
return
|
|
1061
|
+
return getCurrentUnixTimestampSeconds() + signatureValidityInSeconds;
|
|
1058
1062
|
}
|
|
1059
1063
|
|
|
1060
1064
|
// src/core/utils/variant.ts
|
|
@@ -1274,6 +1278,31 @@ var AccountsModule = class {
|
|
|
1274
1278
|
throw mapCanisterCallErrorToLiquidiumError("get_wallet_profile", error);
|
|
1275
1279
|
}
|
|
1276
1280
|
}
|
|
1281
|
+
/**
|
|
1282
|
+
* Checks whether a profile is registered with the protocol.
|
|
1283
|
+
*
|
|
1284
|
+
* Production profile registration always links an initial wallet, and the
|
|
1285
|
+
* protocol prevents removal of a profile's final wallet. This method uses
|
|
1286
|
+
* that invariant because the current canister API has no direct existence
|
|
1287
|
+
* query.
|
|
1288
|
+
*
|
|
1289
|
+
* @param profileId - The Liquidium profile principal text.
|
|
1290
|
+
* @returns `true` when the profile has at least one linked wallet.
|
|
1291
|
+
*/
|
|
1292
|
+
async profileExists(profileId) {
|
|
1293
|
+
try {
|
|
1294
|
+
const profilePrincipal = parseProfilePrincipal(profileId);
|
|
1295
|
+
const wallets = await createLendingActor(
|
|
1296
|
+
this.canisterContext
|
|
1297
|
+
).get_profile_wallets(profilePrincipal);
|
|
1298
|
+
return wallets.length > 0;
|
|
1299
|
+
} catch (error) {
|
|
1300
|
+
if (error instanceof LiquidiumError) {
|
|
1301
|
+
throw error;
|
|
1302
|
+
}
|
|
1303
|
+
throw mapCanisterCallErrorToLiquidiumError("get_profile_wallets", error);
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1277
1306
|
/**
|
|
1278
1307
|
* Returns the current nonce for a wallet address.
|
|
1279
1308
|
*
|
|
@@ -1379,6 +1408,17 @@ var AccountsModule = class {
|
|
|
1379
1408
|
function normalizeProfileAccount(account) {
|
|
1380
1409
|
return normalizeEvmAddress(account);
|
|
1381
1410
|
}
|
|
1411
|
+
function parseProfilePrincipal(profileId) {
|
|
1412
|
+
try {
|
|
1413
|
+
return Principal.fromText(profileId);
|
|
1414
|
+
} catch (error) {
|
|
1415
|
+
throw new LiquidiumError(
|
|
1416
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
1417
|
+
`Invalid profile id: ${profileId}`,
|
|
1418
|
+
error
|
|
1419
|
+
);
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1382
1422
|
function createInitializeAccountMessage(expiryTimestamp, nonce) {
|
|
1383
1423
|
return `Liquidium: Initialize Account
|
|
1384
1424
|
|
|
@@ -1742,19 +1782,29 @@ var SdkApiQueryParam = {
|
|
|
1742
1782
|
to: "to"
|
|
1743
1783
|
};
|
|
1744
1784
|
var ACTIVITIES = `${SDK_API_V2_PATH}/activities`;
|
|
1785
|
+
var HISTORY_ACTIVITIES = `${SDK_API_V2_PATH}/history/activities`;
|
|
1745
1786
|
var HISTORY_USERS = `${SDK_API_V2_PATH}/history/users`;
|
|
1746
1787
|
var INFLOW = `${SDK_API_V2_PATH}/inflow`;
|
|
1747
1788
|
var SIMPLE_LOANS = `${SDK_API_V1_PATH}/instant-loans`;
|
|
1748
|
-
function
|
|
1749
|
-
|
|
1789
|
+
function buildEthereumAddressBytecodePath(request) {
|
|
1790
|
+
return `${SDK_API_V2_PATH}/ethereum/addresses/${encodeURIComponent(
|
|
1791
|
+
request.address
|
|
1792
|
+
)}/bytecode`;
|
|
1793
|
+
}
|
|
1794
|
+
function buildHistoryUserTransactionsPath(profileId, query) {
|
|
1795
|
+
const base = `${HISTORY_USERS}/${encodeURIComponent(profileId)}/transactions`;
|
|
1750
1796
|
const qs = query.toString();
|
|
1751
1797
|
return qs ? `${base}?${qs}` : base;
|
|
1752
1798
|
}
|
|
1753
|
-
function buildHistoryUserLiquidationsPath(
|
|
1754
|
-
const base = `${HISTORY_USERS}/${encodeURIComponent(
|
|
1799
|
+
function buildHistoryUserLiquidationsPath(profileId, query) {
|
|
1800
|
+
const base = `${HISTORY_USERS}/${encodeURIComponent(profileId)}/liquidations`;
|
|
1755
1801
|
const qs = query.toString();
|
|
1756
1802
|
return qs ? `${base}?${qs}` : base;
|
|
1757
1803
|
}
|
|
1804
|
+
function buildProtocolActivityPath(query) {
|
|
1805
|
+
const qs = query.toString();
|
|
1806
|
+
return qs ? `${HISTORY_ACTIVITIES}?${qs}` : HISTORY_ACTIVITIES;
|
|
1807
|
+
}
|
|
1758
1808
|
function buildActivitiesPath(request) {
|
|
1759
1809
|
const query = new URLSearchParams({
|
|
1760
1810
|
[SdkApiQueryParam.profileId]: request.profileId
|
|
@@ -2053,6 +2103,9 @@ function mapActivityTopUp(wire) {
|
|
|
2053
2103
|
}
|
|
2054
2104
|
|
|
2055
2105
|
// src/modules/history/history.ts
|
|
2106
|
+
var MIN_HISTORY_LIMIT = 1;
|
|
2107
|
+
var MAX_USER_HISTORY_LIMIT = 200;
|
|
2108
|
+
var MAX_PROTOCOL_ACTIVITY_LIMIT = 100;
|
|
2056
2109
|
var HistoryModule = class {
|
|
2057
2110
|
constructor(apiClient) {
|
|
2058
2111
|
this.apiClient = apiClient;
|
|
@@ -2070,11 +2123,11 @@ var HistoryModule = class {
|
|
|
2070
2123
|
/**
|
|
2071
2124
|
* Returns transaction history for a user.
|
|
2072
2125
|
*
|
|
2073
|
-
* @param
|
|
2126
|
+
* @param profileId - The Liquidium profile principal text.
|
|
2074
2127
|
* @param filters - Optional pool, operation, state, time range, and pagination filters.
|
|
2075
2128
|
* @returns Paginated user history entries.
|
|
2076
2129
|
*/
|
|
2077
|
-
async getUserTransactionHistory(
|
|
2130
|
+
async getUserTransactionHistory(profileId, filters = {}) {
|
|
2078
2131
|
const apiClient = this.requireApi();
|
|
2079
2132
|
const query = new URLSearchParams();
|
|
2080
2133
|
if (filters.cursor) {
|
|
@@ -2102,9 +2155,10 @@ var HistoryModule = class {
|
|
|
2102
2155
|
query.set(SdkApiQueryParam.to, filters.to);
|
|
2103
2156
|
}
|
|
2104
2157
|
if (filters.limit !== void 0) {
|
|
2158
|
+
validateHistoryLimit(filters.limit, MAX_USER_HISTORY_LIMIT);
|
|
2105
2159
|
query.set(SdkApiQueryParam.limit, String(filters.limit));
|
|
2106
2160
|
}
|
|
2107
|
-
const requestPath = buildHistoryUserTransactionsPath(
|
|
2161
|
+
const requestPath = buildHistoryUserTransactionsPath(profileId, query);
|
|
2108
2162
|
const response = await apiClient.get(requestPath);
|
|
2109
2163
|
return {
|
|
2110
2164
|
items: response.items.map(mapUserTransactionHistoryEntry),
|
|
@@ -2114,11 +2168,11 @@ var HistoryModule = class {
|
|
|
2114
2168
|
/**
|
|
2115
2169
|
* Returns liquidation history for a user.
|
|
2116
2170
|
*
|
|
2117
|
-
* @param
|
|
2171
|
+
* @param profileId - The Liquidium profile principal text.
|
|
2118
2172
|
* @param filters - Optional pool, time range, and pagination filters.
|
|
2119
2173
|
* @returns Paginated liquidation history entries.
|
|
2120
2174
|
*/
|
|
2121
|
-
async getLiquidationHistory(
|
|
2175
|
+
async getLiquidationHistory(profileId, filters = {}) {
|
|
2122
2176
|
const apiClient = this.requireApi();
|
|
2123
2177
|
const query = new URLSearchParams();
|
|
2124
2178
|
if (filters.cursor) {
|
|
@@ -2137,16 +2191,52 @@ var HistoryModule = class {
|
|
|
2137
2191
|
query.set(SdkApiQueryParam.to, filters.to);
|
|
2138
2192
|
}
|
|
2139
2193
|
if (filters.limit !== void 0) {
|
|
2194
|
+
validateHistoryLimit(filters.limit, MAX_USER_HISTORY_LIMIT);
|
|
2140
2195
|
query.set(SdkApiQueryParam.limit, String(filters.limit));
|
|
2141
2196
|
}
|
|
2142
|
-
const requestPath = buildHistoryUserLiquidationsPath(
|
|
2197
|
+
const requestPath = buildHistoryUserLiquidationsPath(profileId, query);
|
|
2143
2198
|
const response = await apiClient.get(requestPath);
|
|
2144
2199
|
return {
|
|
2145
2200
|
items: response.items.map(mapUserLiquidationHistoryEntry),
|
|
2146
2201
|
nextCursor: response.nextCursor
|
|
2147
2202
|
};
|
|
2148
2203
|
}
|
|
2204
|
+
/**
|
|
2205
|
+
* Returns recent protocol-wide lending activity across all users.
|
|
2206
|
+
*
|
|
2207
|
+
* @param filters - Optional pool, operation, and limit filters.
|
|
2208
|
+
* @returns Recent confirmed lending activity entries.
|
|
2209
|
+
*/
|
|
2210
|
+
async getProtocolActivity(filters = {}) {
|
|
2211
|
+
const apiClient = this.requireApi();
|
|
2212
|
+
const query = new URLSearchParams();
|
|
2213
|
+
if (filters.poolId) {
|
|
2214
|
+
query.set(SdkApiQueryParam.poolId, filters.poolId);
|
|
2215
|
+
}
|
|
2216
|
+
if (filters.operations?.length) {
|
|
2217
|
+
query.set(SdkApiQueryParam.operations, filters.operations.join(","));
|
|
2218
|
+
}
|
|
2219
|
+
if (filters.limit !== void 0) {
|
|
2220
|
+
validateHistoryLimit(filters.limit, MAX_PROTOCOL_ACTIVITY_LIMIT);
|
|
2221
|
+
query.set(SdkApiQueryParam.limit, String(filters.limit));
|
|
2222
|
+
}
|
|
2223
|
+
const requestPath = buildProtocolActivityPath(query);
|
|
2224
|
+
const response = await apiClient.get(requestPath);
|
|
2225
|
+
return response.items.map(mapProtocolActivityEntry);
|
|
2226
|
+
}
|
|
2149
2227
|
};
|
|
2228
|
+
function mapProtocolActivityEntry(item) {
|
|
2229
|
+
return {
|
|
2230
|
+
id: item.id,
|
|
2231
|
+
operation: item.operation,
|
|
2232
|
+
poolId: item.poolId,
|
|
2233
|
+
asset: item.asset,
|
|
2234
|
+
decimals: item.decimals,
|
|
2235
|
+
amount: parseBigInt(item.amount, "protocol activity amount"),
|
|
2236
|
+
timestamp: item.timestamp,
|
|
2237
|
+
txids: item.txids
|
|
2238
|
+
};
|
|
2239
|
+
}
|
|
2150
2240
|
function mapUserTransactionHistoryEntry(item) {
|
|
2151
2241
|
return {
|
|
2152
2242
|
id: item.id,
|
|
@@ -2169,7 +2259,12 @@ function mapUserLiquidationHistoryEntry(item) {
|
|
|
2169
2259
|
amount: parseBigInt(item.amount, "history user amount"),
|
|
2170
2260
|
poolId: item.poolId,
|
|
2171
2261
|
timestamp: item.timestamp,
|
|
2172
|
-
status:
|
|
2262
|
+
status: {
|
|
2263
|
+
operation: "liquidation",
|
|
2264
|
+
state: "completed",
|
|
2265
|
+
confirmations: null,
|
|
2266
|
+
requiredConfirmations: null
|
|
2267
|
+
},
|
|
2173
2268
|
txids: item.txids
|
|
2174
2269
|
};
|
|
2175
2270
|
}
|
|
@@ -2194,6 +2289,15 @@ function validateHistoryStateFilter(state) {
|
|
|
2194
2289
|
);
|
|
2195
2290
|
}
|
|
2196
2291
|
}
|
|
2292
|
+
function validateHistoryLimit(limit, maximumLimit) {
|
|
2293
|
+
if (Number.isInteger(limit) && limit >= MIN_HISTORY_LIMIT && limit <= maximumLimit) {
|
|
2294
|
+
return;
|
|
2295
|
+
}
|
|
2296
|
+
throw new LiquidiumError(
|
|
2297
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
2298
|
+
`History limit must be an integer between ${MIN_HISTORY_LIMIT} and ${maximumLimit}`
|
|
2299
|
+
);
|
|
2300
|
+
}
|
|
2197
2301
|
|
|
2198
2302
|
// src/core/utils/inflow-subaccount.ts
|
|
2199
2303
|
var INFLOW_DEPOSIT_PREFIX = 1;
|
|
@@ -3243,6 +3347,71 @@ function accountTypeToString(accountType) {
|
|
|
3243
3347
|
return `Principal:${accountType.data}`;
|
|
3244
3348
|
}
|
|
3245
3349
|
}
|
|
3350
|
+
var EMPTY_EVM_BYTECODE = "0x";
|
|
3351
|
+
var LAST_ETHEREUM_MAINNET_PRECOMPILE_ADDRESS = 0x11n;
|
|
3352
|
+
var CONTRACT_DESTINATION_UNSUPPORTED_MESSAGE = "Contract addresses are not supported for native ETH withdrawals or borrowing";
|
|
3353
|
+
var RESERVED_DESTINATION_MESSAGE = "Ethereum outflow destination must not be the zero address or a precompile";
|
|
3354
|
+
async function guardEthereumOutflowDestination({
|
|
3355
|
+
address,
|
|
3356
|
+
apiClient,
|
|
3357
|
+
asset,
|
|
3358
|
+
chain,
|
|
3359
|
+
evmReadClient
|
|
3360
|
+
}) {
|
|
3361
|
+
if (chain !== Chain.ETH) {
|
|
3362
|
+
return;
|
|
3363
|
+
}
|
|
3364
|
+
const normalizedAddress = getAddress(address);
|
|
3365
|
+
if (BigInt(normalizedAddress) <= LAST_ETHEREUM_MAINNET_PRECOMPILE_ADDRESS) {
|
|
3366
|
+
throw new LiquidiumError(
|
|
3367
|
+
LiquidiumErrorCode.INVALID_ADDRESS,
|
|
3368
|
+
RESERVED_DESTINATION_MESSAGE
|
|
3369
|
+
);
|
|
3370
|
+
}
|
|
3371
|
+
if (asset !== Asset.ETH) {
|
|
3372
|
+
return;
|
|
3373
|
+
}
|
|
3374
|
+
if (evmReadClient?.chain?.id === mainnet.id && evmReadClient.getCode) {
|
|
3375
|
+
let bytecode;
|
|
3376
|
+
try {
|
|
3377
|
+
bytecode = await evmReadClient.getCode({
|
|
3378
|
+
address: normalizedAddress
|
|
3379
|
+
});
|
|
3380
|
+
} catch {
|
|
3381
|
+
return;
|
|
3382
|
+
}
|
|
3383
|
+
if (bytecode === void 0 || bytecode === EMPTY_EVM_BYTECODE) {
|
|
3384
|
+
return;
|
|
3385
|
+
}
|
|
3386
|
+
if (typeof bytecode !== "string" || !/^0x(?:[0-9a-fA-F]{2})*$/.test(bytecode)) {
|
|
3387
|
+
return;
|
|
3388
|
+
}
|
|
3389
|
+
throw new LiquidiumError(
|
|
3390
|
+
LiquidiumErrorCode.CONTRACT_DESTINATION_UNSUPPORTED,
|
|
3391
|
+
CONTRACT_DESTINATION_UNSUPPORTED_MESSAGE
|
|
3392
|
+
);
|
|
3393
|
+
}
|
|
3394
|
+
if (!apiClient) {
|
|
3395
|
+
return;
|
|
3396
|
+
}
|
|
3397
|
+
let response;
|
|
3398
|
+
try {
|
|
3399
|
+
response = await apiClient.get(
|
|
3400
|
+
buildEthereumAddressBytecodePath({ address: normalizedAddress })
|
|
3401
|
+
);
|
|
3402
|
+
} catch {
|
|
3403
|
+
return;
|
|
3404
|
+
}
|
|
3405
|
+
if (!response || typeof response !== "object" || !("hasDeployedBytecode" in response) || typeof response.hasDeployedBytecode !== "boolean") {
|
|
3406
|
+
return;
|
|
3407
|
+
}
|
|
3408
|
+
if (response.hasDeployedBytecode) {
|
|
3409
|
+
throw new LiquidiumError(
|
|
3410
|
+
LiquidiumErrorCode.CONTRACT_DESTINATION_UNSUPPORTED,
|
|
3411
|
+
CONTRACT_DESTINATION_UNSUPPORTED_MESSAGE
|
|
3412
|
+
);
|
|
3413
|
+
}
|
|
3414
|
+
}
|
|
3246
3415
|
|
|
3247
3416
|
// src/core/pool-ledger-assets.ts
|
|
3248
3417
|
function getPoolLedgerAssetRoute(params) {
|
|
@@ -4625,6 +4794,13 @@ var LendingModule = class {
|
|
|
4625
4794
|
poolChain: selectedPool.chain,
|
|
4626
4795
|
destinationChain: request.chain
|
|
4627
4796
|
});
|
|
4797
|
+
await guardEthereumOutflowDestination({
|
|
4798
|
+
address: receiver.address,
|
|
4799
|
+
apiClient: this.apiClient,
|
|
4800
|
+
asset: selectedAsset,
|
|
4801
|
+
chain: request.chain,
|
|
4802
|
+
evmReadClient: this.evmReadClient
|
|
4803
|
+
});
|
|
4628
4804
|
const lendingActor = createLendingActor(this.canisterContext);
|
|
4629
4805
|
try {
|
|
4630
4806
|
const expiryTimestamp = computeExpiryTimestampFromNow();
|
|
@@ -4643,7 +4819,9 @@ var LendingModule = class {
|
|
|
4643
4819
|
};
|
|
4644
4820
|
const withdrawSubmissionData = {
|
|
4645
4821
|
...withdrawActionData,
|
|
4646
|
-
|
|
4822
|
+
asset: selectedAsset,
|
|
4823
|
+
receiverAccount: receiver.canisterAccount,
|
|
4824
|
+
receiverAddress: receiver.address
|
|
4647
4825
|
};
|
|
4648
4826
|
return {
|
|
4649
4827
|
kind: WalletActionKind.createWithdraw,
|
|
@@ -4675,6 +4853,13 @@ var LendingModule = class {
|
|
|
4675
4853
|
}
|
|
4676
4854
|
}
|
|
4677
4855
|
async submitWithdraw(request, signatureInfo) {
|
|
4856
|
+
await guardEthereumOutflowDestination({
|
|
4857
|
+
address: request.receiverAddress,
|
|
4858
|
+
apiClient: this.apiClient,
|
|
4859
|
+
asset: request.asset,
|
|
4860
|
+
chain: request.chain,
|
|
4861
|
+
evmReadClient: this.evmReadClient
|
|
4862
|
+
});
|
|
4678
4863
|
try {
|
|
4679
4864
|
const result = await createLendingActor(this.canisterContext).withdraw(
|
|
4680
4865
|
Principal.fromText(request.profileId),
|
|
@@ -4779,6 +4964,13 @@ var LendingModule = class {
|
|
|
4779
4964
|
poolChain: selectedPool.chain,
|
|
4780
4965
|
destinationChain: request.chain
|
|
4781
4966
|
});
|
|
4967
|
+
await guardEthereumOutflowDestination({
|
|
4968
|
+
address: receiver.address,
|
|
4969
|
+
apiClient: this.apiClient,
|
|
4970
|
+
asset: selectedAsset,
|
|
4971
|
+
chain: request.chain,
|
|
4972
|
+
evmReadClient: this.evmReadClient
|
|
4973
|
+
});
|
|
4782
4974
|
await this.guardBorrowSameAssetPolicy({
|
|
4783
4975
|
profileId: request.profileId,
|
|
4784
4976
|
pool: selectedPool
|
|
@@ -4801,7 +4993,9 @@ var LendingModule = class {
|
|
|
4801
4993
|
};
|
|
4802
4994
|
const borrowSubmissionData = {
|
|
4803
4995
|
...borrowActionData,
|
|
4804
|
-
|
|
4996
|
+
asset: selectedAsset,
|
|
4997
|
+
receiverAccount: receiver.canisterAccount,
|
|
4998
|
+
receiverAddress: receiver.address
|
|
4805
4999
|
};
|
|
4806
5000
|
return {
|
|
4807
5001
|
kind: WalletActionKind.createBorrow,
|
|
@@ -4830,6 +5024,13 @@ var LendingModule = class {
|
|
|
4830
5024
|
}
|
|
4831
5025
|
}
|
|
4832
5026
|
async submitBorrow(request, signatureInfo) {
|
|
5027
|
+
await guardEthereumOutflowDestination({
|
|
5028
|
+
address: request.receiverAddress,
|
|
5029
|
+
apiClient: this.apiClient,
|
|
5030
|
+
asset: request.asset,
|
|
5031
|
+
chain: request.chain,
|
|
5032
|
+
evmReadClient: this.evmReadClient
|
|
5033
|
+
});
|
|
4833
5034
|
try {
|
|
4834
5035
|
const result = await createLendingActor(
|
|
4835
5036
|
this.canisterContext
|
|
@@ -5149,9 +5350,78 @@ function mapOutflowTypeToStatusOperation(outflowType) {
|
|
|
5149
5350
|
return outflowType;
|
|
5150
5351
|
}
|
|
5151
5352
|
|
|
5353
|
+
// src/core/asset-metadata.ts
|
|
5354
|
+
var ASSET_METADATA = {
|
|
5355
|
+
[Asset.BTC]: {
|
|
5356
|
+
symbol: Asset.BTC,
|
|
5357
|
+
displayName: "Bitcoin"
|
|
5358
|
+
},
|
|
5359
|
+
[Asset.ETH]: {
|
|
5360
|
+
symbol: Asset.ETH,
|
|
5361
|
+
displayName: "Ethereum"
|
|
5362
|
+
},
|
|
5363
|
+
[Asset.ICP]: {
|
|
5364
|
+
symbol: Asset.ICP,
|
|
5365
|
+
displayName: "Internet Computer"
|
|
5366
|
+
},
|
|
5367
|
+
[Asset.USDC]: {
|
|
5368
|
+
symbol: Asset.USDC,
|
|
5369
|
+
displayName: "USD Coin"
|
|
5370
|
+
},
|
|
5371
|
+
[Asset.USDT]: {
|
|
5372
|
+
symbol: Asset.USDT,
|
|
5373
|
+
displayName: "Tether USD"
|
|
5374
|
+
}
|
|
5375
|
+
};
|
|
5376
|
+
function getAssetMetadata(asset) {
|
|
5377
|
+
return ASSET_METADATA[asset];
|
|
5378
|
+
}
|
|
5379
|
+
|
|
5152
5380
|
// src/core/rates.ts
|
|
5153
5381
|
var RATE_SCALE = 1000000000000000000000000000n;
|
|
5154
5382
|
var RATE_DECIMALS = BigInt(RATE_SCALE.toString().length - 1);
|
|
5383
|
+
var INTEREST_YEAR_365_DAYS_SECONDS = 31536000n;
|
|
5384
|
+
var SUPPLY_COMPOUNDING_INTERVAL_15_SECONDS = 15n;
|
|
5385
|
+
function estimateBorrowApy(borrowApr) {
|
|
5386
|
+
return estimateCompoundedApy(borrowApr, 1n);
|
|
5387
|
+
}
|
|
5388
|
+
function estimateSupplyApy(supplyApr) {
|
|
5389
|
+
return estimateCompoundedApy(
|
|
5390
|
+
supplyApr,
|
|
5391
|
+
SUPPLY_COMPOUNDING_INTERVAL_15_SECONDS
|
|
5392
|
+
);
|
|
5393
|
+
}
|
|
5394
|
+
function estimateCompoundedApy(apr, compoundingIntervalSeconds) {
|
|
5395
|
+
if (apr < 0n) {
|
|
5396
|
+
throw new RangeError("APR cannot be negative");
|
|
5397
|
+
}
|
|
5398
|
+
if (apr === 0n) {
|
|
5399
|
+
return 0n;
|
|
5400
|
+
}
|
|
5401
|
+
const periodsPerYear = INTEREST_YEAR_365_DAYS_SECONDS / compoundingIntervalSeconds;
|
|
5402
|
+
const ratePerPeriod = apr * compoundingIntervalSeconds / INTEREST_YEAR_365_DAYS_SECONDS;
|
|
5403
|
+
const annualGrowth = fixedPointPow(
|
|
5404
|
+
RATE_SCALE + ratePerPeriod,
|
|
5405
|
+
periodsPerYear
|
|
5406
|
+
);
|
|
5407
|
+
return annualGrowth - RATE_SCALE;
|
|
5408
|
+
}
|
|
5409
|
+
function fixedPointPow(base, exponent) {
|
|
5410
|
+
let remainingExponent = exponent;
|
|
5411
|
+
let currentBase = base;
|
|
5412
|
+
let result = RATE_SCALE;
|
|
5413
|
+
while (remainingExponent > 0n) {
|
|
5414
|
+
if (remainingExponent % 2n === 1n) {
|
|
5415
|
+
result = fixedPointMultiply(result, currentBase);
|
|
5416
|
+
}
|
|
5417
|
+
currentBase = fixedPointMultiply(currentBase, currentBase);
|
|
5418
|
+
remainingExponent /= 2n;
|
|
5419
|
+
}
|
|
5420
|
+
return result;
|
|
5421
|
+
}
|
|
5422
|
+
function fixedPointMultiply(left, right) {
|
|
5423
|
+
return (left * right + RATE_SCALE / 2n) / RATE_SCALE;
|
|
5424
|
+
}
|
|
5155
5425
|
|
|
5156
5426
|
// src/core/utils/asset-decimals.ts
|
|
5157
5427
|
var ASSET_NATIVE_DECIMALS = {
|
|
@@ -5178,12 +5448,14 @@ var DECIMAL_BASE = 10;
|
|
|
5178
5448
|
var PAIR_SEPARATOR = "_";
|
|
5179
5449
|
var USDT_SYMBOL = "USDT";
|
|
5180
5450
|
function mapDecodedPoolToPool(pool, rate) {
|
|
5451
|
+
const assetMetadata = getAssetMetadata(pool.asset);
|
|
5181
5452
|
const totalSupply = pool.total_supply_at_last_sync * pool.lending_index / RATE_SCALE;
|
|
5182
5453
|
const totalDebt = pool.total_debt_at_last_sync * pool.borrow_index / RATE_SCALE;
|
|
5183
5454
|
const availableLiquidity = totalSupply > totalDebt ? totalSupply - totalDebt : 0n;
|
|
5184
5455
|
return {
|
|
5185
5456
|
id: pool.principal.toString(),
|
|
5186
5457
|
asset: pool.asset,
|
|
5458
|
+
displayName: assetMetadata.displayName,
|
|
5187
5459
|
chain: pool.chain,
|
|
5188
5460
|
decimals: getAssetNativeDecimals(pool.asset),
|
|
5189
5461
|
frozen: pool.frozen,
|
|
@@ -5199,7 +5471,9 @@ function mapDecodedPoolToPool(pool, rate) {
|
|
|
5199
5471
|
reserveFactor: pool.reserve_factor,
|
|
5200
5472
|
rateDecimals: RATE_DECIMALS,
|
|
5201
5473
|
lendingRate: rate[1],
|
|
5474
|
+
estimatedLendingApy: estimateSupplyApy(rate[1]),
|
|
5202
5475
|
borrowingRate: rate[0],
|
|
5476
|
+
estimatedBorrowingApy: estimateBorrowApy(rate[0]),
|
|
5203
5477
|
utilizationRate: rate[2],
|
|
5204
5478
|
baseRate: pool.base_rate,
|
|
5205
5479
|
optimalUtilizationRate: pool.optimal_utilization_rate,
|
|
@@ -5233,7 +5507,9 @@ function mapGetPoolRateResponseToPoolRate(rate) {
|
|
|
5233
5507
|
return {
|
|
5234
5508
|
rateDecimals: RATE_DECIMALS,
|
|
5235
5509
|
borrowRate: rate[0],
|
|
5510
|
+
estimatedBorrowApy: estimateBorrowApy(rate[0]),
|
|
5236
5511
|
lendRate: rate[1],
|
|
5512
|
+
estimatedLendApy: estimateSupplyApy(rate[1]),
|
|
5237
5513
|
utilizationRate: rate[2]
|
|
5238
5514
|
};
|
|
5239
5515
|
}
|
|
@@ -5287,15 +5563,32 @@ var MarketModule = class {
|
|
|
5287
5563
|
}
|
|
5288
5564
|
}
|
|
5289
5565
|
/**
|
|
5290
|
-
* Returns the
|
|
5566
|
+
* Returns the current cached asset prices reported by the protocol.
|
|
5291
5567
|
*
|
|
5292
|
-
* @returns The
|
|
5568
|
+
* @returns The current protocol price map keyed by market asset symbol.
|
|
5293
5569
|
*/
|
|
5294
5570
|
async getAssetPrices() {
|
|
5571
|
+
return (await this.getAssetPriceSnapshot()).prices;
|
|
5572
|
+
}
|
|
5573
|
+
/**
|
|
5574
|
+
* Returns protocol prices with the time at which the SDK completed the fetch.
|
|
5575
|
+
*
|
|
5576
|
+
* `fetchedAt` is an SDK retrieval time, not an oracle observation timestamp.
|
|
5577
|
+
* The current lending canister price response does not expose the underlying
|
|
5578
|
+
* oracle timestamp.
|
|
5579
|
+
*
|
|
5580
|
+
* @returns Protocol prices and their SDK fetch timestamp.
|
|
5581
|
+
*/
|
|
5582
|
+
async getAssetPriceSnapshot() {
|
|
5295
5583
|
try {
|
|
5296
|
-
|
|
5584
|
+
const prices = mapGetPricesResponseToAssetPrices(
|
|
5297
5585
|
await createLendingActor(this.canisterContext).get_prices()
|
|
5298
5586
|
);
|
|
5587
|
+
const fetchedAtUnixSeconds = getCurrentUnixTimestampSeconds();
|
|
5588
|
+
return {
|
|
5589
|
+
prices,
|
|
5590
|
+
fetchedAt: fetchedAtUnixSeconds
|
|
5591
|
+
};
|
|
5299
5592
|
} catch (error) {
|
|
5300
5593
|
if (error instanceof LiquidiumError) {
|
|
5301
5594
|
throw error;
|
|
@@ -5397,6 +5690,10 @@ function decodeSupportedFlexiblePools(rawPools) {
|
|
|
5397
5690
|
return decodedPools;
|
|
5398
5691
|
}
|
|
5399
5692
|
|
|
5693
|
+
// src/modules/positions/health-factor.ts
|
|
5694
|
+
var HEALTH_FACTOR_SCALE = 1000n;
|
|
5695
|
+
var HEALTH_FACTOR_DECIMALS = 3n;
|
|
5696
|
+
|
|
5400
5697
|
// src/modules/positions/mappers.ts
|
|
5401
5698
|
var USD_VALUE_SCALE_DECIMALS = 27n;
|
|
5402
5699
|
function mapDecodedPositionViewToPosition(view) {
|
|
@@ -5525,11 +5822,13 @@ var PositionsModule = class {
|
|
|
5525
5822
|
const [healthFactor, userStatsRecord] = await createFlexibleLendingActor(
|
|
5526
5823
|
this.canisterContext
|
|
5527
5824
|
).get_health_factor(Principal.fromText(profileId));
|
|
5825
|
+
const userStats = mapDecodedUserStatsToUserStats(
|
|
5826
|
+
decodeFlexibleUserStats(userStatsRecord)
|
|
5827
|
+
);
|
|
5528
5828
|
return {
|
|
5529
|
-
healthFactor,
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
)
|
|
5829
|
+
healthFactor: userStats.debt === 0n ? null : healthFactor,
|
|
5830
|
+
healthFactorDecimals: HEALTH_FACTOR_DECIMALS,
|
|
5831
|
+
userStats
|
|
5533
5832
|
};
|
|
5534
5833
|
} catch (error) {
|
|
5535
5834
|
if (error instanceof LiquidiumError) {
|
|
@@ -5569,7 +5868,7 @@ var PositionsModule = class {
|
|
|
5569
5868
|
* @returns Derived position summary for the requested profile.
|
|
5570
5869
|
*/
|
|
5571
5870
|
async getUserPositionSummary(profileId) {
|
|
5572
|
-
const { healthFactor, userStats } = await this.getHealthFactor(profileId);
|
|
5871
|
+
const { healthFactor, healthFactorDecimals, userStats } = await this.getHealthFactor(profileId);
|
|
5573
5872
|
const collateral = userStats.collateral;
|
|
5574
5873
|
const debt = userStats.debt;
|
|
5575
5874
|
const maxBorrowableUsd = userStats.borrowingPower.maxBorrowableUsd;
|
|
@@ -5585,7 +5884,8 @@ var PositionsModule = class {
|
|
|
5585
5884
|
currentLtvBps,
|
|
5586
5885
|
weightedMaxLtvBps: userStats.borrowingPower.weightedMaxLtv,
|
|
5587
5886
|
weightedLiquidationThresholdBps: userStats.weightedLiquidationThreshold,
|
|
5588
|
-
healthFactor
|
|
5887
|
+
healthFactor,
|
|
5888
|
+
healthFactorDecimals
|
|
5589
5889
|
};
|
|
5590
5890
|
}
|
|
5591
5891
|
/**
|
|
@@ -6869,9 +7169,9 @@ function isSimpleLoanDepositExpired(input) {
|
|
|
6869
7169
|
if (input.expiryTimestamp === null) {
|
|
6870
7170
|
return false;
|
|
6871
7171
|
}
|
|
6872
|
-
return input.expiryTimestamp <=
|
|
7172
|
+
return input.expiryTimestamp <= getCurrentUnixTimestampSeconds2();
|
|
6873
7173
|
}
|
|
6874
|
-
function
|
|
7174
|
+
function getCurrentUnixTimestampSeconds2() {
|
|
6875
7175
|
return BigInt(Math.floor(Date.now() / MILLISECONDS_PER_SECOND3));
|
|
6876
7176
|
}
|
|
6877
7177
|
function deriveDepositExpiryTimestamp(input) {
|
|
@@ -7472,6 +7772,6 @@ function resolveEvmReadClient(config) {
|
|
|
7472
7772
|
});
|
|
7473
7773
|
}
|
|
7474
7774
|
|
|
7475
|
-
export { AccountsModule, ActivitiesModule, ActivityFilter, Asset, CK_ETH_DEPOSIT_CONTRACT_ADDRESS, Chain, Environment, EvmSupplyApprovalStrategy, HistoryModule, LendingModule, LiquidiumAccountType, LiquidiumClient, LiquidiumError, LiquidiumErrorCode, MIN_BORROW_AMOUNTS_BY_ASSET, MIN_DEPOSIT_AMOUNTS_BY_ASSET, MIN_WITHDRAW_AMOUNTS_BY_ASSET, MarketModule, OutflowType, PositionsModule, QuoteModule, QuoteValidationErrorCode, QuoteWarningCode, RATE_DECIMALS, RATE_SCALE, SimpleLoanCreatedError, SimpleLoansModule, SupplyAction, SupplyPlanType, USDC_CONTRACT_ADDRESS, USDT_CONTRACT_ADDRESS, WalletActionKind, WalletExecutionKind, createTransferErc20Transaction, executeWith, getMinimumBorrowAmount, getMinimumDepositAmount, getMinimumWithdrawAmount, intFromPublicId, isAssetIdentifier, publicIdFromInt };
|
|
7775
|
+
export { ASSET_METADATA, AccountsModule, ActivitiesModule, ActivityFilter, Asset, CK_ETH_DEPOSIT_CONTRACT_ADDRESS, Chain, Environment, EvmSupplyApprovalStrategy, HEALTH_FACTOR_DECIMALS, HEALTH_FACTOR_SCALE, HistoryModule, INTEREST_YEAR_365_DAYS_SECONDS, LendingModule, LiquidiumAccountType, LiquidiumClient, LiquidiumError, LiquidiumErrorCode, MIN_BORROW_AMOUNTS_BY_ASSET, MIN_DEPOSIT_AMOUNTS_BY_ASSET, MIN_WITHDRAW_AMOUNTS_BY_ASSET, MarketModule, OutflowType, PositionsModule, QuoteModule, QuoteValidationErrorCode, QuoteWarningCode, RATE_DECIMALS, RATE_SCALE, SUPPLY_COMPOUNDING_INTERVAL_15_SECONDS, SimpleLoanCreatedError, SimpleLoansModule, SupplyAction, SupplyPlanType, USDC_CONTRACT_ADDRESS, USDT_CONTRACT_ADDRESS, WalletActionKind, WalletExecutionKind, createTransferErc20Transaction, estimateBorrowApy, estimateSupplyApy, executeWith, getAssetMetadata, getMinimumBorrowAmount, getMinimumDepositAmount, getMinimumWithdrawAmount, intFromPublicId, isAssetIdentifier, publicIdFromInt };
|
|
7476
7776
|
//# sourceMappingURL=index.js.map
|
|
7477
7777
|
//# sourceMappingURL=index.js.map
|