@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.cjs
CHANGED
|
@@ -47,6 +47,7 @@ var LiquidiumErrorCode = {
|
|
|
47
47
|
WITHDRAW_TOO_LOW: "WITHDRAW_TOO_LOW",
|
|
48
48
|
REPAYMENT_EXCEEDS_DEBT: "REPAYMENT_EXCEEDS_DEBT",
|
|
49
49
|
INVALID_ADDRESS: "INVALID_ADDRESS",
|
|
50
|
+
CONTRACT_DESTINATION_UNSUPPORTED: "CONTRACT_DESTINATION_UNSUPPORTED",
|
|
50
51
|
DEPOSIT_ADDRESS_ERROR: "DEPOSIT_ADDRESS_ERROR",
|
|
51
52
|
// Transport
|
|
52
53
|
NETWORK_ERROR: "NETWORK_ERROR",
|
|
@@ -1055,8 +1056,11 @@ function normalizeEvmAddress(address) {
|
|
|
1055
1056
|
// src/core/utils/time.ts
|
|
1056
1057
|
var MILLISECONDS_PER_SECOND = 1e3;
|
|
1057
1058
|
var SIGNATURE_VALIDITY_5_MINUTES_IN_SECONDS = 5n * 60n;
|
|
1059
|
+
function getCurrentUnixTimestampSeconds() {
|
|
1060
|
+
return BigInt(Math.floor(Date.now() / MILLISECONDS_PER_SECOND));
|
|
1061
|
+
}
|
|
1058
1062
|
function computeExpiryTimestampFromNow(signatureValidityInSeconds = SIGNATURE_VALIDITY_5_MINUTES_IN_SECONDS) {
|
|
1059
|
-
return
|
|
1063
|
+
return getCurrentUnixTimestampSeconds() + signatureValidityInSeconds;
|
|
1060
1064
|
}
|
|
1061
1065
|
|
|
1062
1066
|
// src/core/utils/variant.ts
|
|
@@ -1276,6 +1280,31 @@ var AccountsModule = class {
|
|
|
1276
1280
|
throw mapCanisterCallErrorToLiquidiumError("get_wallet_profile", error);
|
|
1277
1281
|
}
|
|
1278
1282
|
}
|
|
1283
|
+
/**
|
|
1284
|
+
* Checks whether a profile is registered with the protocol.
|
|
1285
|
+
*
|
|
1286
|
+
* Production profile registration always links an initial wallet, and the
|
|
1287
|
+
* protocol prevents removal of a profile's final wallet. This method uses
|
|
1288
|
+
* that invariant because the current canister API has no direct existence
|
|
1289
|
+
* query.
|
|
1290
|
+
*
|
|
1291
|
+
* @param profileId - The Liquidium profile principal text.
|
|
1292
|
+
* @returns `true` when the profile has at least one linked wallet.
|
|
1293
|
+
*/
|
|
1294
|
+
async profileExists(profileId) {
|
|
1295
|
+
try {
|
|
1296
|
+
const profilePrincipal = parseProfilePrincipal(profileId);
|
|
1297
|
+
const wallets = await createLendingActor(
|
|
1298
|
+
this.canisterContext
|
|
1299
|
+
).get_profile_wallets(profilePrincipal);
|
|
1300
|
+
return wallets.length > 0;
|
|
1301
|
+
} catch (error) {
|
|
1302
|
+
if (error instanceof LiquidiumError) {
|
|
1303
|
+
throw error;
|
|
1304
|
+
}
|
|
1305
|
+
throw mapCanisterCallErrorToLiquidiumError("get_profile_wallets", error);
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1279
1308
|
/**
|
|
1280
1309
|
* Returns the current nonce for a wallet address.
|
|
1281
1310
|
*
|
|
@@ -1381,6 +1410,17 @@ var AccountsModule = class {
|
|
|
1381
1410
|
function normalizeProfileAccount(account) {
|
|
1382
1411
|
return normalizeEvmAddress(account);
|
|
1383
1412
|
}
|
|
1413
|
+
function parseProfilePrincipal(profileId) {
|
|
1414
|
+
try {
|
|
1415
|
+
return principal.Principal.fromText(profileId);
|
|
1416
|
+
} catch (error) {
|
|
1417
|
+
throw new LiquidiumError(
|
|
1418
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
1419
|
+
`Invalid profile id: ${profileId}`,
|
|
1420
|
+
error
|
|
1421
|
+
);
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1384
1424
|
function createInitializeAccountMessage(expiryTimestamp, nonce) {
|
|
1385
1425
|
return `Liquidium: Initialize Account
|
|
1386
1426
|
|
|
@@ -1744,19 +1784,29 @@ var SdkApiQueryParam = {
|
|
|
1744
1784
|
to: "to"
|
|
1745
1785
|
};
|
|
1746
1786
|
var ACTIVITIES = `${SDK_API_V2_PATH}/activities`;
|
|
1787
|
+
var HISTORY_ACTIVITIES = `${SDK_API_V2_PATH}/history/activities`;
|
|
1747
1788
|
var HISTORY_USERS = `${SDK_API_V2_PATH}/history/users`;
|
|
1748
1789
|
var INFLOW = `${SDK_API_V2_PATH}/inflow`;
|
|
1749
1790
|
var SIMPLE_LOANS = `${SDK_API_V1_PATH}/instant-loans`;
|
|
1750
|
-
function
|
|
1751
|
-
|
|
1791
|
+
function buildEthereumAddressBytecodePath(request) {
|
|
1792
|
+
return `${SDK_API_V2_PATH}/ethereum/addresses/${encodeURIComponent(
|
|
1793
|
+
request.address
|
|
1794
|
+
)}/bytecode`;
|
|
1795
|
+
}
|
|
1796
|
+
function buildHistoryUserTransactionsPath(profileId, query) {
|
|
1797
|
+
const base = `${HISTORY_USERS}/${encodeURIComponent(profileId)}/transactions`;
|
|
1752
1798
|
const qs = query.toString();
|
|
1753
1799
|
return qs ? `${base}?${qs}` : base;
|
|
1754
1800
|
}
|
|
1755
|
-
function buildHistoryUserLiquidationsPath(
|
|
1756
|
-
const base = `${HISTORY_USERS}/${encodeURIComponent(
|
|
1801
|
+
function buildHistoryUserLiquidationsPath(profileId, query) {
|
|
1802
|
+
const base = `${HISTORY_USERS}/${encodeURIComponent(profileId)}/liquidations`;
|
|
1757
1803
|
const qs = query.toString();
|
|
1758
1804
|
return qs ? `${base}?${qs}` : base;
|
|
1759
1805
|
}
|
|
1806
|
+
function buildProtocolActivityPath(query) {
|
|
1807
|
+
const qs = query.toString();
|
|
1808
|
+
return qs ? `${HISTORY_ACTIVITIES}?${qs}` : HISTORY_ACTIVITIES;
|
|
1809
|
+
}
|
|
1760
1810
|
function buildActivitiesPath(request) {
|
|
1761
1811
|
const query = new URLSearchParams({
|
|
1762
1812
|
[SdkApiQueryParam.profileId]: request.profileId
|
|
@@ -2055,6 +2105,9 @@ function mapActivityTopUp(wire) {
|
|
|
2055
2105
|
}
|
|
2056
2106
|
|
|
2057
2107
|
// src/modules/history/history.ts
|
|
2108
|
+
var MIN_HISTORY_LIMIT = 1;
|
|
2109
|
+
var MAX_USER_HISTORY_LIMIT = 200;
|
|
2110
|
+
var MAX_PROTOCOL_ACTIVITY_LIMIT = 100;
|
|
2058
2111
|
var HistoryModule = class {
|
|
2059
2112
|
constructor(apiClient) {
|
|
2060
2113
|
this.apiClient = apiClient;
|
|
@@ -2072,11 +2125,11 @@ var HistoryModule = class {
|
|
|
2072
2125
|
/**
|
|
2073
2126
|
* Returns transaction history for a user.
|
|
2074
2127
|
*
|
|
2075
|
-
* @param
|
|
2128
|
+
* @param profileId - The Liquidium profile principal text.
|
|
2076
2129
|
* @param filters - Optional pool, operation, state, time range, and pagination filters.
|
|
2077
2130
|
* @returns Paginated user history entries.
|
|
2078
2131
|
*/
|
|
2079
|
-
async getUserTransactionHistory(
|
|
2132
|
+
async getUserTransactionHistory(profileId, filters = {}) {
|
|
2080
2133
|
const apiClient = this.requireApi();
|
|
2081
2134
|
const query = new URLSearchParams();
|
|
2082
2135
|
if (filters.cursor) {
|
|
@@ -2104,9 +2157,10 @@ var HistoryModule = class {
|
|
|
2104
2157
|
query.set(SdkApiQueryParam.to, filters.to);
|
|
2105
2158
|
}
|
|
2106
2159
|
if (filters.limit !== void 0) {
|
|
2160
|
+
validateHistoryLimit(filters.limit, MAX_USER_HISTORY_LIMIT);
|
|
2107
2161
|
query.set(SdkApiQueryParam.limit, String(filters.limit));
|
|
2108
2162
|
}
|
|
2109
|
-
const requestPath = buildHistoryUserTransactionsPath(
|
|
2163
|
+
const requestPath = buildHistoryUserTransactionsPath(profileId, query);
|
|
2110
2164
|
const response = await apiClient.get(requestPath);
|
|
2111
2165
|
return {
|
|
2112
2166
|
items: response.items.map(mapUserTransactionHistoryEntry),
|
|
@@ -2116,11 +2170,11 @@ var HistoryModule = class {
|
|
|
2116
2170
|
/**
|
|
2117
2171
|
* Returns liquidation history for a user.
|
|
2118
2172
|
*
|
|
2119
|
-
* @param
|
|
2173
|
+
* @param profileId - The Liquidium profile principal text.
|
|
2120
2174
|
* @param filters - Optional pool, time range, and pagination filters.
|
|
2121
2175
|
* @returns Paginated liquidation history entries.
|
|
2122
2176
|
*/
|
|
2123
|
-
async getLiquidationHistory(
|
|
2177
|
+
async getLiquidationHistory(profileId, filters = {}) {
|
|
2124
2178
|
const apiClient = this.requireApi();
|
|
2125
2179
|
const query = new URLSearchParams();
|
|
2126
2180
|
if (filters.cursor) {
|
|
@@ -2139,16 +2193,52 @@ var HistoryModule = class {
|
|
|
2139
2193
|
query.set(SdkApiQueryParam.to, filters.to);
|
|
2140
2194
|
}
|
|
2141
2195
|
if (filters.limit !== void 0) {
|
|
2196
|
+
validateHistoryLimit(filters.limit, MAX_USER_HISTORY_LIMIT);
|
|
2142
2197
|
query.set(SdkApiQueryParam.limit, String(filters.limit));
|
|
2143
2198
|
}
|
|
2144
|
-
const requestPath = buildHistoryUserLiquidationsPath(
|
|
2199
|
+
const requestPath = buildHistoryUserLiquidationsPath(profileId, query);
|
|
2145
2200
|
const response = await apiClient.get(requestPath);
|
|
2146
2201
|
return {
|
|
2147
2202
|
items: response.items.map(mapUserLiquidationHistoryEntry),
|
|
2148
2203
|
nextCursor: response.nextCursor
|
|
2149
2204
|
};
|
|
2150
2205
|
}
|
|
2206
|
+
/**
|
|
2207
|
+
* Returns recent protocol-wide lending activity across all users.
|
|
2208
|
+
*
|
|
2209
|
+
* @param filters - Optional pool, operation, and limit filters.
|
|
2210
|
+
* @returns Recent confirmed lending activity entries.
|
|
2211
|
+
*/
|
|
2212
|
+
async getProtocolActivity(filters = {}) {
|
|
2213
|
+
const apiClient = this.requireApi();
|
|
2214
|
+
const query = new URLSearchParams();
|
|
2215
|
+
if (filters.poolId) {
|
|
2216
|
+
query.set(SdkApiQueryParam.poolId, filters.poolId);
|
|
2217
|
+
}
|
|
2218
|
+
if (filters.operations?.length) {
|
|
2219
|
+
query.set(SdkApiQueryParam.operations, filters.operations.join(","));
|
|
2220
|
+
}
|
|
2221
|
+
if (filters.limit !== void 0) {
|
|
2222
|
+
validateHistoryLimit(filters.limit, MAX_PROTOCOL_ACTIVITY_LIMIT);
|
|
2223
|
+
query.set(SdkApiQueryParam.limit, String(filters.limit));
|
|
2224
|
+
}
|
|
2225
|
+
const requestPath = buildProtocolActivityPath(query);
|
|
2226
|
+
const response = await apiClient.get(requestPath);
|
|
2227
|
+
return response.items.map(mapProtocolActivityEntry);
|
|
2228
|
+
}
|
|
2151
2229
|
};
|
|
2230
|
+
function mapProtocolActivityEntry(item) {
|
|
2231
|
+
return {
|
|
2232
|
+
id: item.id,
|
|
2233
|
+
operation: item.operation,
|
|
2234
|
+
poolId: item.poolId,
|
|
2235
|
+
asset: item.asset,
|
|
2236
|
+
decimals: item.decimals,
|
|
2237
|
+
amount: parseBigInt(item.amount, "protocol activity amount"),
|
|
2238
|
+
timestamp: item.timestamp,
|
|
2239
|
+
txids: item.txids
|
|
2240
|
+
};
|
|
2241
|
+
}
|
|
2152
2242
|
function mapUserTransactionHistoryEntry(item) {
|
|
2153
2243
|
return {
|
|
2154
2244
|
id: item.id,
|
|
@@ -2171,7 +2261,12 @@ function mapUserLiquidationHistoryEntry(item) {
|
|
|
2171
2261
|
amount: parseBigInt(item.amount, "history user amount"),
|
|
2172
2262
|
poolId: item.poolId,
|
|
2173
2263
|
timestamp: item.timestamp,
|
|
2174
|
-
status:
|
|
2264
|
+
status: {
|
|
2265
|
+
operation: "liquidation",
|
|
2266
|
+
state: "completed",
|
|
2267
|
+
confirmations: null,
|
|
2268
|
+
requiredConfirmations: null
|
|
2269
|
+
},
|
|
2175
2270
|
txids: item.txids
|
|
2176
2271
|
};
|
|
2177
2272
|
}
|
|
@@ -2196,6 +2291,15 @@ function validateHistoryStateFilter(state) {
|
|
|
2196
2291
|
);
|
|
2197
2292
|
}
|
|
2198
2293
|
}
|
|
2294
|
+
function validateHistoryLimit(limit, maximumLimit) {
|
|
2295
|
+
if (Number.isInteger(limit) && limit >= MIN_HISTORY_LIMIT && limit <= maximumLimit) {
|
|
2296
|
+
return;
|
|
2297
|
+
}
|
|
2298
|
+
throw new LiquidiumError(
|
|
2299
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
2300
|
+
`History limit must be an integer between ${MIN_HISTORY_LIMIT} and ${maximumLimit}`
|
|
2301
|
+
);
|
|
2302
|
+
}
|
|
2199
2303
|
|
|
2200
2304
|
// src/core/utils/inflow-subaccount.ts
|
|
2201
2305
|
var INFLOW_DEPOSIT_PREFIX = 1;
|
|
@@ -3245,6 +3349,71 @@ function accountTypeToString(accountType) {
|
|
|
3245
3349
|
return `Principal:${accountType.data}`;
|
|
3246
3350
|
}
|
|
3247
3351
|
}
|
|
3352
|
+
var EMPTY_EVM_BYTECODE = "0x";
|
|
3353
|
+
var LAST_ETHEREUM_MAINNET_PRECOMPILE_ADDRESS = 0x11n;
|
|
3354
|
+
var CONTRACT_DESTINATION_UNSUPPORTED_MESSAGE = "Contract addresses are not supported for native ETH withdrawals or borrowing";
|
|
3355
|
+
var RESERVED_DESTINATION_MESSAGE = "Ethereum outflow destination must not be the zero address or a precompile";
|
|
3356
|
+
async function guardEthereumOutflowDestination({
|
|
3357
|
+
address,
|
|
3358
|
+
apiClient,
|
|
3359
|
+
asset,
|
|
3360
|
+
chain,
|
|
3361
|
+
evmReadClient
|
|
3362
|
+
}) {
|
|
3363
|
+
if (chain !== Chain.ETH) {
|
|
3364
|
+
return;
|
|
3365
|
+
}
|
|
3366
|
+
const normalizedAddress = viem.getAddress(address);
|
|
3367
|
+
if (BigInt(normalizedAddress) <= LAST_ETHEREUM_MAINNET_PRECOMPILE_ADDRESS) {
|
|
3368
|
+
throw new LiquidiumError(
|
|
3369
|
+
LiquidiumErrorCode.INVALID_ADDRESS,
|
|
3370
|
+
RESERVED_DESTINATION_MESSAGE
|
|
3371
|
+
);
|
|
3372
|
+
}
|
|
3373
|
+
if (asset !== Asset.ETH) {
|
|
3374
|
+
return;
|
|
3375
|
+
}
|
|
3376
|
+
if (evmReadClient?.chain?.id === chains.mainnet.id && evmReadClient.getCode) {
|
|
3377
|
+
let bytecode;
|
|
3378
|
+
try {
|
|
3379
|
+
bytecode = await evmReadClient.getCode({
|
|
3380
|
+
address: normalizedAddress
|
|
3381
|
+
});
|
|
3382
|
+
} catch {
|
|
3383
|
+
return;
|
|
3384
|
+
}
|
|
3385
|
+
if (bytecode === void 0 || bytecode === EMPTY_EVM_BYTECODE) {
|
|
3386
|
+
return;
|
|
3387
|
+
}
|
|
3388
|
+
if (typeof bytecode !== "string" || !/^0x(?:[0-9a-fA-F]{2})*$/.test(bytecode)) {
|
|
3389
|
+
return;
|
|
3390
|
+
}
|
|
3391
|
+
throw new LiquidiumError(
|
|
3392
|
+
LiquidiumErrorCode.CONTRACT_DESTINATION_UNSUPPORTED,
|
|
3393
|
+
CONTRACT_DESTINATION_UNSUPPORTED_MESSAGE
|
|
3394
|
+
);
|
|
3395
|
+
}
|
|
3396
|
+
if (!apiClient) {
|
|
3397
|
+
return;
|
|
3398
|
+
}
|
|
3399
|
+
let response;
|
|
3400
|
+
try {
|
|
3401
|
+
response = await apiClient.get(
|
|
3402
|
+
buildEthereumAddressBytecodePath({ address: normalizedAddress })
|
|
3403
|
+
);
|
|
3404
|
+
} catch {
|
|
3405
|
+
return;
|
|
3406
|
+
}
|
|
3407
|
+
if (!response || typeof response !== "object" || !("hasDeployedBytecode" in response) || typeof response.hasDeployedBytecode !== "boolean") {
|
|
3408
|
+
return;
|
|
3409
|
+
}
|
|
3410
|
+
if (response.hasDeployedBytecode) {
|
|
3411
|
+
throw new LiquidiumError(
|
|
3412
|
+
LiquidiumErrorCode.CONTRACT_DESTINATION_UNSUPPORTED,
|
|
3413
|
+
CONTRACT_DESTINATION_UNSUPPORTED_MESSAGE
|
|
3414
|
+
);
|
|
3415
|
+
}
|
|
3416
|
+
}
|
|
3248
3417
|
|
|
3249
3418
|
// src/core/pool-ledger-assets.ts
|
|
3250
3419
|
function getPoolLedgerAssetRoute(params) {
|
|
@@ -4627,6 +4796,13 @@ var LendingModule = class {
|
|
|
4627
4796
|
poolChain: selectedPool.chain,
|
|
4628
4797
|
destinationChain: request.chain
|
|
4629
4798
|
});
|
|
4799
|
+
await guardEthereumOutflowDestination({
|
|
4800
|
+
address: receiver.address,
|
|
4801
|
+
apiClient: this.apiClient,
|
|
4802
|
+
asset: selectedAsset,
|
|
4803
|
+
chain: request.chain,
|
|
4804
|
+
evmReadClient: this.evmReadClient
|
|
4805
|
+
});
|
|
4630
4806
|
const lendingActor = createLendingActor(this.canisterContext);
|
|
4631
4807
|
try {
|
|
4632
4808
|
const expiryTimestamp = computeExpiryTimestampFromNow();
|
|
@@ -4645,7 +4821,9 @@ var LendingModule = class {
|
|
|
4645
4821
|
};
|
|
4646
4822
|
const withdrawSubmissionData = {
|
|
4647
4823
|
...withdrawActionData,
|
|
4648
|
-
|
|
4824
|
+
asset: selectedAsset,
|
|
4825
|
+
receiverAccount: receiver.canisterAccount,
|
|
4826
|
+
receiverAddress: receiver.address
|
|
4649
4827
|
};
|
|
4650
4828
|
return {
|
|
4651
4829
|
kind: WalletActionKind.createWithdraw,
|
|
@@ -4677,6 +4855,13 @@ var LendingModule = class {
|
|
|
4677
4855
|
}
|
|
4678
4856
|
}
|
|
4679
4857
|
async submitWithdraw(request, signatureInfo) {
|
|
4858
|
+
await guardEthereumOutflowDestination({
|
|
4859
|
+
address: request.receiverAddress,
|
|
4860
|
+
apiClient: this.apiClient,
|
|
4861
|
+
asset: request.asset,
|
|
4862
|
+
chain: request.chain,
|
|
4863
|
+
evmReadClient: this.evmReadClient
|
|
4864
|
+
});
|
|
4680
4865
|
try {
|
|
4681
4866
|
const result = await createLendingActor(this.canisterContext).withdraw(
|
|
4682
4867
|
principal.Principal.fromText(request.profileId),
|
|
@@ -4781,6 +4966,13 @@ var LendingModule = class {
|
|
|
4781
4966
|
poolChain: selectedPool.chain,
|
|
4782
4967
|
destinationChain: request.chain
|
|
4783
4968
|
});
|
|
4969
|
+
await guardEthereumOutflowDestination({
|
|
4970
|
+
address: receiver.address,
|
|
4971
|
+
apiClient: this.apiClient,
|
|
4972
|
+
asset: selectedAsset,
|
|
4973
|
+
chain: request.chain,
|
|
4974
|
+
evmReadClient: this.evmReadClient
|
|
4975
|
+
});
|
|
4784
4976
|
await this.guardBorrowSameAssetPolicy({
|
|
4785
4977
|
profileId: request.profileId,
|
|
4786
4978
|
pool: selectedPool
|
|
@@ -4803,7 +4995,9 @@ var LendingModule = class {
|
|
|
4803
4995
|
};
|
|
4804
4996
|
const borrowSubmissionData = {
|
|
4805
4997
|
...borrowActionData,
|
|
4806
|
-
|
|
4998
|
+
asset: selectedAsset,
|
|
4999
|
+
receiverAccount: receiver.canisterAccount,
|
|
5000
|
+
receiverAddress: receiver.address
|
|
4807
5001
|
};
|
|
4808
5002
|
return {
|
|
4809
5003
|
kind: WalletActionKind.createBorrow,
|
|
@@ -4832,6 +5026,13 @@ var LendingModule = class {
|
|
|
4832
5026
|
}
|
|
4833
5027
|
}
|
|
4834
5028
|
async submitBorrow(request, signatureInfo) {
|
|
5029
|
+
await guardEthereumOutflowDestination({
|
|
5030
|
+
address: request.receiverAddress,
|
|
5031
|
+
apiClient: this.apiClient,
|
|
5032
|
+
asset: request.asset,
|
|
5033
|
+
chain: request.chain,
|
|
5034
|
+
evmReadClient: this.evmReadClient
|
|
5035
|
+
});
|
|
4835
5036
|
try {
|
|
4836
5037
|
const result = await createLendingActor(
|
|
4837
5038
|
this.canisterContext
|
|
@@ -5151,9 +5352,78 @@ function mapOutflowTypeToStatusOperation(outflowType) {
|
|
|
5151
5352
|
return outflowType;
|
|
5152
5353
|
}
|
|
5153
5354
|
|
|
5355
|
+
// src/core/asset-metadata.ts
|
|
5356
|
+
var ASSET_METADATA = {
|
|
5357
|
+
[Asset.BTC]: {
|
|
5358
|
+
symbol: Asset.BTC,
|
|
5359
|
+
displayName: "Bitcoin"
|
|
5360
|
+
},
|
|
5361
|
+
[Asset.ETH]: {
|
|
5362
|
+
symbol: Asset.ETH,
|
|
5363
|
+
displayName: "Ethereum"
|
|
5364
|
+
},
|
|
5365
|
+
[Asset.ICP]: {
|
|
5366
|
+
symbol: Asset.ICP,
|
|
5367
|
+
displayName: "Internet Computer"
|
|
5368
|
+
},
|
|
5369
|
+
[Asset.USDC]: {
|
|
5370
|
+
symbol: Asset.USDC,
|
|
5371
|
+
displayName: "USD Coin"
|
|
5372
|
+
},
|
|
5373
|
+
[Asset.USDT]: {
|
|
5374
|
+
symbol: Asset.USDT,
|
|
5375
|
+
displayName: "Tether USD"
|
|
5376
|
+
}
|
|
5377
|
+
};
|
|
5378
|
+
function getAssetMetadata(asset) {
|
|
5379
|
+
return ASSET_METADATA[asset];
|
|
5380
|
+
}
|
|
5381
|
+
|
|
5154
5382
|
// src/core/rates.ts
|
|
5155
5383
|
var RATE_SCALE = 1000000000000000000000000000n;
|
|
5156
5384
|
var RATE_DECIMALS = BigInt(RATE_SCALE.toString().length - 1);
|
|
5385
|
+
var INTEREST_YEAR_365_DAYS_SECONDS = 31536000n;
|
|
5386
|
+
var SUPPLY_COMPOUNDING_INTERVAL_15_SECONDS = 15n;
|
|
5387
|
+
function estimateBorrowApy(borrowApr) {
|
|
5388
|
+
return estimateCompoundedApy(borrowApr, 1n);
|
|
5389
|
+
}
|
|
5390
|
+
function estimateSupplyApy(supplyApr) {
|
|
5391
|
+
return estimateCompoundedApy(
|
|
5392
|
+
supplyApr,
|
|
5393
|
+
SUPPLY_COMPOUNDING_INTERVAL_15_SECONDS
|
|
5394
|
+
);
|
|
5395
|
+
}
|
|
5396
|
+
function estimateCompoundedApy(apr, compoundingIntervalSeconds) {
|
|
5397
|
+
if (apr < 0n) {
|
|
5398
|
+
throw new RangeError("APR cannot be negative");
|
|
5399
|
+
}
|
|
5400
|
+
if (apr === 0n) {
|
|
5401
|
+
return 0n;
|
|
5402
|
+
}
|
|
5403
|
+
const periodsPerYear = INTEREST_YEAR_365_DAYS_SECONDS / compoundingIntervalSeconds;
|
|
5404
|
+
const ratePerPeriod = apr * compoundingIntervalSeconds / INTEREST_YEAR_365_DAYS_SECONDS;
|
|
5405
|
+
const annualGrowth = fixedPointPow(
|
|
5406
|
+
RATE_SCALE + ratePerPeriod,
|
|
5407
|
+
periodsPerYear
|
|
5408
|
+
);
|
|
5409
|
+
return annualGrowth - RATE_SCALE;
|
|
5410
|
+
}
|
|
5411
|
+
function fixedPointPow(base, exponent) {
|
|
5412
|
+
let remainingExponent = exponent;
|
|
5413
|
+
let currentBase = base;
|
|
5414
|
+
let result = RATE_SCALE;
|
|
5415
|
+
while (remainingExponent > 0n) {
|
|
5416
|
+
if (remainingExponent % 2n === 1n) {
|
|
5417
|
+
result = fixedPointMultiply(result, currentBase);
|
|
5418
|
+
}
|
|
5419
|
+
currentBase = fixedPointMultiply(currentBase, currentBase);
|
|
5420
|
+
remainingExponent /= 2n;
|
|
5421
|
+
}
|
|
5422
|
+
return result;
|
|
5423
|
+
}
|
|
5424
|
+
function fixedPointMultiply(left, right) {
|
|
5425
|
+
return (left * right + RATE_SCALE / 2n) / RATE_SCALE;
|
|
5426
|
+
}
|
|
5157
5427
|
|
|
5158
5428
|
// src/core/utils/asset-decimals.ts
|
|
5159
5429
|
var ASSET_NATIVE_DECIMALS = {
|
|
@@ -5180,12 +5450,14 @@ var DECIMAL_BASE = 10;
|
|
|
5180
5450
|
var PAIR_SEPARATOR = "_";
|
|
5181
5451
|
var USDT_SYMBOL = "USDT";
|
|
5182
5452
|
function mapDecodedPoolToPool(pool, rate) {
|
|
5453
|
+
const assetMetadata = getAssetMetadata(pool.asset);
|
|
5183
5454
|
const totalSupply = pool.total_supply_at_last_sync * pool.lending_index / RATE_SCALE;
|
|
5184
5455
|
const totalDebt = pool.total_debt_at_last_sync * pool.borrow_index / RATE_SCALE;
|
|
5185
5456
|
const availableLiquidity = totalSupply > totalDebt ? totalSupply - totalDebt : 0n;
|
|
5186
5457
|
return {
|
|
5187
5458
|
id: pool.principal.toString(),
|
|
5188
5459
|
asset: pool.asset,
|
|
5460
|
+
displayName: assetMetadata.displayName,
|
|
5189
5461
|
chain: pool.chain,
|
|
5190
5462
|
decimals: getAssetNativeDecimals(pool.asset),
|
|
5191
5463
|
frozen: pool.frozen,
|
|
@@ -5201,7 +5473,9 @@ function mapDecodedPoolToPool(pool, rate) {
|
|
|
5201
5473
|
reserveFactor: pool.reserve_factor,
|
|
5202
5474
|
rateDecimals: RATE_DECIMALS,
|
|
5203
5475
|
lendingRate: rate[1],
|
|
5476
|
+
estimatedLendingApy: estimateSupplyApy(rate[1]),
|
|
5204
5477
|
borrowingRate: rate[0],
|
|
5478
|
+
estimatedBorrowingApy: estimateBorrowApy(rate[0]),
|
|
5205
5479
|
utilizationRate: rate[2],
|
|
5206
5480
|
baseRate: pool.base_rate,
|
|
5207
5481
|
optimalUtilizationRate: pool.optimal_utilization_rate,
|
|
@@ -5235,7 +5509,9 @@ function mapGetPoolRateResponseToPoolRate(rate) {
|
|
|
5235
5509
|
return {
|
|
5236
5510
|
rateDecimals: RATE_DECIMALS,
|
|
5237
5511
|
borrowRate: rate[0],
|
|
5512
|
+
estimatedBorrowApy: estimateBorrowApy(rate[0]),
|
|
5238
5513
|
lendRate: rate[1],
|
|
5514
|
+
estimatedLendApy: estimateSupplyApy(rate[1]),
|
|
5239
5515
|
utilizationRate: rate[2]
|
|
5240
5516
|
};
|
|
5241
5517
|
}
|
|
@@ -5289,15 +5565,32 @@ var MarketModule = class {
|
|
|
5289
5565
|
}
|
|
5290
5566
|
}
|
|
5291
5567
|
/**
|
|
5292
|
-
* Returns the
|
|
5568
|
+
* Returns the current cached asset prices reported by the protocol.
|
|
5293
5569
|
*
|
|
5294
|
-
* @returns The
|
|
5570
|
+
* @returns The current protocol price map keyed by market asset symbol.
|
|
5295
5571
|
*/
|
|
5296
5572
|
async getAssetPrices() {
|
|
5573
|
+
return (await this.getAssetPriceSnapshot()).prices;
|
|
5574
|
+
}
|
|
5575
|
+
/**
|
|
5576
|
+
* Returns protocol prices with the time at which the SDK completed the fetch.
|
|
5577
|
+
*
|
|
5578
|
+
* `fetchedAt` is an SDK retrieval time, not an oracle observation timestamp.
|
|
5579
|
+
* The current lending canister price response does not expose the underlying
|
|
5580
|
+
* oracle timestamp.
|
|
5581
|
+
*
|
|
5582
|
+
* @returns Protocol prices and their SDK fetch timestamp.
|
|
5583
|
+
*/
|
|
5584
|
+
async getAssetPriceSnapshot() {
|
|
5297
5585
|
try {
|
|
5298
|
-
|
|
5586
|
+
const prices = mapGetPricesResponseToAssetPrices(
|
|
5299
5587
|
await createLendingActor(this.canisterContext).get_prices()
|
|
5300
5588
|
);
|
|
5589
|
+
const fetchedAtUnixSeconds = getCurrentUnixTimestampSeconds();
|
|
5590
|
+
return {
|
|
5591
|
+
prices,
|
|
5592
|
+
fetchedAt: fetchedAtUnixSeconds
|
|
5593
|
+
};
|
|
5301
5594
|
} catch (error) {
|
|
5302
5595
|
if (error instanceof LiquidiumError) {
|
|
5303
5596
|
throw error;
|
|
@@ -5399,6 +5692,10 @@ function decodeSupportedFlexiblePools(rawPools) {
|
|
|
5399
5692
|
return decodedPools;
|
|
5400
5693
|
}
|
|
5401
5694
|
|
|
5695
|
+
// src/modules/positions/health-factor.ts
|
|
5696
|
+
var HEALTH_FACTOR_SCALE = 1000n;
|
|
5697
|
+
var HEALTH_FACTOR_DECIMALS = 3n;
|
|
5698
|
+
|
|
5402
5699
|
// src/modules/positions/mappers.ts
|
|
5403
5700
|
var USD_VALUE_SCALE_DECIMALS = 27n;
|
|
5404
5701
|
function mapDecodedPositionViewToPosition(view) {
|
|
@@ -5527,11 +5824,13 @@ var PositionsModule = class {
|
|
|
5527
5824
|
const [healthFactor, userStatsRecord] = await createFlexibleLendingActor(
|
|
5528
5825
|
this.canisterContext
|
|
5529
5826
|
).get_health_factor(principal.Principal.fromText(profileId));
|
|
5827
|
+
const userStats = mapDecodedUserStatsToUserStats(
|
|
5828
|
+
decodeFlexibleUserStats(userStatsRecord)
|
|
5829
|
+
);
|
|
5530
5830
|
return {
|
|
5531
|
-
healthFactor,
|
|
5532
|
-
|
|
5533
|
-
|
|
5534
|
-
)
|
|
5831
|
+
healthFactor: userStats.debt === 0n ? null : healthFactor,
|
|
5832
|
+
healthFactorDecimals: HEALTH_FACTOR_DECIMALS,
|
|
5833
|
+
userStats
|
|
5535
5834
|
};
|
|
5536
5835
|
} catch (error) {
|
|
5537
5836
|
if (error instanceof LiquidiumError) {
|
|
@@ -5571,7 +5870,7 @@ var PositionsModule = class {
|
|
|
5571
5870
|
* @returns Derived position summary for the requested profile.
|
|
5572
5871
|
*/
|
|
5573
5872
|
async getUserPositionSummary(profileId) {
|
|
5574
|
-
const { healthFactor, userStats } = await this.getHealthFactor(profileId);
|
|
5873
|
+
const { healthFactor, healthFactorDecimals, userStats } = await this.getHealthFactor(profileId);
|
|
5575
5874
|
const collateral = userStats.collateral;
|
|
5576
5875
|
const debt = userStats.debt;
|
|
5577
5876
|
const maxBorrowableUsd = userStats.borrowingPower.maxBorrowableUsd;
|
|
@@ -5587,7 +5886,8 @@ var PositionsModule = class {
|
|
|
5587
5886
|
currentLtvBps,
|
|
5588
5887
|
weightedMaxLtvBps: userStats.borrowingPower.weightedMaxLtv,
|
|
5589
5888
|
weightedLiquidationThresholdBps: userStats.weightedLiquidationThreshold,
|
|
5590
|
-
healthFactor
|
|
5889
|
+
healthFactor,
|
|
5890
|
+
healthFactorDecimals
|
|
5591
5891
|
};
|
|
5592
5892
|
}
|
|
5593
5893
|
/**
|
|
@@ -6871,9 +7171,9 @@ function isSimpleLoanDepositExpired(input) {
|
|
|
6871
7171
|
if (input.expiryTimestamp === null) {
|
|
6872
7172
|
return false;
|
|
6873
7173
|
}
|
|
6874
|
-
return input.expiryTimestamp <=
|
|
7174
|
+
return input.expiryTimestamp <= getCurrentUnixTimestampSeconds2();
|
|
6875
7175
|
}
|
|
6876
|
-
function
|
|
7176
|
+
function getCurrentUnixTimestampSeconds2() {
|
|
6877
7177
|
return BigInt(Math.floor(Date.now() / MILLISECONDS_PER_SECOND3));
|
|
6878
7178
|
}
|
|
6879
7179
|
function deriveDepositExpiryTimestamp(input) {
|
|
@@ -7474,6 +7774,7 @@ function resolveEvmReadClient(config) {
|
|
|
7474
7774
|
});
|
|
7475
7775
|
}
|
|
7476
7776
|
|
|
7777
|
+
exports.ASSET_METADATA = ASSET_METADATA;
|
|
7477
7778
|
exports.AccountsModule = AccountsModule;
|
|
7478
7779
|
exports.ActivitiesModule = ActivitiesModule;
|
|
7479
7780
|
exports.ActivityFilter = ActivityFilter;
|
|
@@ -7482,7 +7783,10 @@ exports.CK_ETH_DEPOSIT_CONTRACT_ADDRESS = CK_ETH_DEPOSIT_CONTRACT_ADDRESS;
|
|
|
7482
7783
|
exports.Chain = Chain;
|
|
7483
7784
|
exports.Environment = Environment;
|
|
7484
7785
|
exports.EvmSupplyApprovalStrategy = EvmSupplyApprovalStrategy;
|
|
7786
|
+
exports.HEALTH_FACTOR_DECIMALS = HEALTH_FACTOR_DECIMALS;
|
|
7787
|
+
exports.HEALTH_FACTOR_SCALE = HEALTH_FACTOR_SCALE;
|
|
7485
7788
|
exports.HistoryModule = HistoryModule;
|
|
7789
|
+
exports.INTEREST_YEAR_365_DAYS_SECONDS = INTEREST_YEAR_365_DAYS_SECONDS;
|
|
7486
7790
|
exports.LendingModule = LendingModule;
|
|
7487
7791
|
exports.LiquidiumAccountType = LiquidiumAccountType;
|
|
7488
7792
|
exports.LiquidiumClient = LiquidiumClient;
|
|
@@ -7499,6 +7803,7 @@ exports.QuoteValidationErrorCode = QuoteValidationErrorCode;
|
|
|
7499
7803
|
exports.QuoteWarningCode = QuoteWarningCode;
|
|
7500
7804
|
exports.RATE_DECIMALS = RATE_DECIMALS;
|
|
7501
7805
|
exports.RATE_SCALE = RATE_SCALE;
|
|
7806
|
+
exports.SUPPLY_COMPOUNDING_INTERVAL_15_SECONDS = SUPPLY_COMPOUNDING_INTERVAL_15_SECONDS;
|
|
7502
7807
|
exports.SimpleLoanCreatedError = SimpleLoanCreatedError;
|
|
7503
7808
|
exports.SimpleLoansModule = SimpleLoansModule;
|
|
7504
7809
|
exports.SupplyAction = SupplyAction;
|
|
@@ -7508,7 +7813,10 @@ exports.USDT_CONTRACT_ADDRESS = USDT_CONTRACT_ADDRESS;
|
|
|
7508
7813
|
exports.WalletActionKind = WalletActionKind;
|
|
7509
7814
|
exports.WalletExecutionKind = WalletExecutionKind;
|
|
7510
7815
|
exports.createTransferErc20Transaction = createTransferErc20Transaction;
|
|
7816
|
+
exports.estimateBorrowApy = estimateBorrowApy;
|
|
7817
|
+
exports.estimateSupplyApy = estimateSupplyApy;
|
|
7511
7818
|
exports.executeWith = executeWith;
|
|
7819
|
+
exports.getAssetMetadata = getAssetMetadata;
|
|
7512
7820
|
exports.getMinimumBorrowAmount = getMinimumBorrowAmount;
|
|
7513
7821
|
exports.getMinimumDepositAmount = getMinimumDepositAmount;
|
|
7514
7822
|
exports.getMinimumWithdrawAmount = getMinimumWithdrawAmount;
|