@liquidium/client 0.2.1 → 0.3.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/README.md +42 -7
- package/dist/index.cjs +570 -191
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +77 -46
- package/dist/index.d.ts +77 -46
- package/dist/index.js +570 -191
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import { encodeFunctionData, createPublicClient, http, isAddress, getAddress } f
|
|
|
2
2
|
import { mainnet } from 'viem/chains';
|
|
3
3
|
import { Actor, HttpAgent } from '@icp-sdk/core/agent';
|
|
4
4
|
import { Principal } from '@icp-sdk/core/principal';
|
|
5
|
+
import { idlLabelToId } from '@icp-sdk/core/candid';
|
|
5
6
|
import { encodeIcrcAccount } from '@dfinity/ledger-icrc';
|
|
6
7
|
import { Principal as Principal$1 } from '@dfinity/principal';
|
|
7
8
|
import { validate, Network } from 'bitcoin-address-validation';
|
|
@@ -1305,17 +1306,35 @@ function mapCanisterWalletToWallet(canisterWallet) {
|
|
|
1305
1306
|
);
|
|
1306
1307
|
}
|
|
1307
1308
|
}
|
|
1308
|
-
var
|
|
1309
|
+
var KNOWN_ASSET_TAGS = ["BTC", "SOL", "USDC", "USDT"];
|
|
1310
|
+
var KNOWN_CHAIN_TAGS = ["BTC", "ETH", "SOL"];
|
|
1311
|
+
function extractVariantTag(variant, knownTags) {
|
|
1312
|
+
const [key] = Object.keys(variant);
|
|
1313
|
+
if (!key) {
|
|
1314
|
+
return null;
|
|
1315
|
+
}
|
|
1316
|
+
if (knownTags.includes(key)) {
|
|
1317
|
+
return key;
|
|
1318
|
+
}
|
|
1319
|
+
const hashMatch = /^_(\d+)_$/.exec(key);
|
|
1320
|
+
if (!hashMatch) {
|
|
1321
|
+
return null;
|
|
1322
|
+
}
|
|
1323
|
+
const hash = Number(hashMatch[1]);
|
|
1324
|
+
for (const tag of knownTags) {
|
|
1325
|
+
if (idlLabelToId(tag) === hash) {
|
|
1326
|
+
return tag;
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
return null;
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
// src/core/canisters/instant-loans/flexible-actor.ts
|
|
1333
|
+
var flexibleInstantLoansIdlFactory = ({ IDL }) => {
|
|
1309
1334
|
const AccountType = IDL.Variant({
|
|
1310
1335
|
Native: IDL.Principal,
|
|
1311
1336
|
External: IDL.Text
|
|
1312
1337
|
});
|
|
1313
|
-
const Assets = IDL.Variant({
|
|
1314
|
-
BTC: IDL.Null,
|
|
1315
|
-
SOL: IDL.Null,
|
|
1316
|
-
USDC: IDL.Null,
|
|
1317
|
-
USDT: IDL.Null
|
|
1318
|
-
});
|
|
1319
1338
|
const SignatureVerificationError = IDL.Variant({
|
|
1320
1339
|
InvalidEthSignature: IDL.Null,
|
|
1321
1340
|
UnsupportedChain: IDL.Null,
|
|
@@ -1386,13 +1405,13 @@ var idlFactory2 = ({ IDL }) => {
|
|
|
1386
1405
|
});
|
|
1387
1406
|
const CreateLoanRequest = IDL.Record({
|
|
1388
1407
|
borrow_destination: AccountType,
|
|
1389
|
-
lend_asset:
|
|
1408
|
+
lend_asset: IDL.Unknown,
|
|
1390
1409
|
borrow_amount: IDL.Nat,
|
|
1391
1410
|
lend_pool_id: IDL.Principal,
|
|
1392
1411
|
refund_destination: AccountType,
|
|
1393
1412
|
ltv_max_bps: IDL.Nat64,
|
|
1394
1413
|
borrow_pool_id: IDL.Principal,
|
|
1395
|
-
borrow_asset:
|
|
1414
|
+
borrow_asset: IDL.Unknown,
|
|
1396
1415
|
ltv_timer_s: IDL.Nat64
|
|
1397
1416
|
});
|
|
1398
1417
|
const CreateLoanResponse = IDL.Record({
|
|
@@ -1408,7 +1427,7 @@ var idlFactory2 = ({ IDL }) => {
|
|
|
1408
1427
|
LoanCreated: IDL.Record({
|
|
1409
1428
|
loan_id: IDL.Nat,
|
|
1410
1429
|
borrow_destination: AccountType,
|
|
1411
|
-
lend_asset:
|
|
1430
|
+
lend_asset: IDL.Unknown,
|
|
1412
1431
|
borrow_amount: IDL.Nat,
|
|
1413
1432
|
lend_pool_id: IDL.Principal,
|
|
1414
1433
|
refund_destination: AccountType,
|
|
@@ -1416,7 +1435,7 @@ var idlFactory2 = ({ IDL }) => {
|
|
|
1416
1435
|
ltv_timer_s: IDL.Nat64,
|
|
1417
1436
|
lending_profile: IDL.Principal,
|
|
1418
1437
|
borrow_pool_id: IDL.Principal,
|
|
1419
|
-
borrow_asset:
|
|
1438
|
+
borrow_asset: IDL.Unknown
|
|
1420
1439
|
}),
|
|
1421
1440
|
FullLendWithdrawalRequested: IDL.Record({
|
|
1422
1441
|
loan_id: IDL.Nat,
|
|
@@ -1467,7 +1486,7 @@ var idlFactory2 = ({ IDL }) => {
|
|
|
1467
1486
|
authorisation: AuthorisationType,
|
|
1468
1487
|
borrow_destination: AccountType,
|
|
1469
1488
|
started: IDL.Bool,
|
|
1470
|
-
lend_asset:
|
|
1489
|
+
lend_asset: IDL.Unknown,
|
|
1471
1490
|
created_at: IDL.Nat64,
|
|
1472
1491
|
schema_version: IDL.Nat16,
|
|
1473
1492
|
borrow_amount: IDL.Nat,
|
|
@@ -1478,7 +1497,7 @@ var idlFactory2 = ({ IDL }) => {
|
|
|
1478
1497
|
lending_profile: IDL.Principal,
|
|
1479
1498
|
expires_at: IDL.Opt(IDL.Nat64),
|
|
1480
1499
|
borrow_pool_id: IDL.Principal,
|
|
1481
|
-
borrow_asset:
|
|
1500
|
+
borrow_asset: IDL.Unknown,
|
|
1482
1501
|
deposit_detected_ts: IDL.Opt(IDL.Nat64)
|
|
1483
1502
|
});
|
|
1484
1503
|
const LoanResult = IDL.Variant({ Ok: Loan, Err: InstantLoansError });
|
|
@@ -1506,7 +1525,7 @@ var idlFactory2 = ({ IDL }) => {
|
|
|
1506
1525
|
list_warmed_profiles: IDL.Func([], [IDL.Vec(WarmedProfile)], ["query"])
|
|
1507
1526
|
});
|
|
1508
1527
|
};
|
|
1509
|
-
function
|
|
1528
|
+
function createFlexibleInstantLoansActor(canisterContext) {
|
|
1510
1529
|
const canisterId = canisterContext.canisterIds.instantLoans;
|
|
1511
1530
|
if (!canisterId) {
|
|
1512
1531
|
throw new LiquidiumError(
|
|
@@ -1514,10 +1533,84 @@ function createInstantLoansActor(canisterContext) {
|
|
|
1514
1533
|
"Instant loans canister ID is not configured"
|
|
1515
1534
|
);
|
|
1516
1535
|
}
|
|
1517
|
-
return Actor.createActor(
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1536
|
+
return Actor.createActor(
|
|
1537
|
+
flexibleInstantLoansIdlFactory,
|
|
1538
|
+
{
|
|
1539
|
+
agent: canisterContext.agent,
|
|
1540
|
+
canisterId
|
|
1541
|
+
}
|
|
1542
|
+
);
|
|
1543
|
+
}
|
|
1544
|
+
function decodeFlexibleInstantLoanRecord(record) {
|
|
1545
|
+
const lend_asset = extractVariantTag(record.lend_asset, KNOWN_ASSET_TAGS);
|
|
1546
|
+
const borrow_asset = extractVariantTag(record.borrow_asset, KNOWN_ASSET_TAGS);
|
|
1547
|
+
if (!lend_asset || !borrow_asset) {
|
|
1548
|
+
return null;
|
|
1549
|
+
}
|
|
1550
|
+
return {
|
|
1551
|
+
id: record.id,
|
|
1552
|
+
authorisation: record.authorisation,
|
|
1553
|
+
borrow_destination: record.borrow_destination,
|
|
1554
|
+
started: record.started,
|
|
1555
|
+
lend_asset,
|
|
1556
|
+
created_at: record.created_at,
|
|
1557
|
+
schema_version: record.schema_version,
|
|
1558
|
+
borrow_amount: record.borrow_amount,
|
|
1559
|
+
lend_pool_id: record.lend_pool_id,
|
|
1560
|
+
refund_destination: record.refund_destination,
|
|
1561
|
+
ltv_max_bps: record.ltv_max_bps,
|
|
1562
|
+
ltv_timer_s: record.ltv_timer_s,
|
|
1563
|
+
lending_profile: record.lending_profile,
|
|
1564
|
+
borrow_pool_id: record.borrow_pool_id,
|
|
1565
|
+
borrow_asset,
|
|
1566
|
+
expires_at: record.expires_at,
|
|
1567
|
+
deposit_detected_ts: record.deposit_detected_ts
|
|
1568
|
+
};
|
|
1569
|
+
}
|
|
1570
|
+
function decodeFlexibleHeadlessLoanEvent(event) {
|
|
1571
|
+
if ("LoanCreated" in event.event_type) {
|
|
1572
|
+
const decoded = decodeLoanCreatedEvent(event.event_type.LoanCreated);
|
|
1573
|
+
if (!decoded) {
|
|
1574
|
+
return null;
|
|
1575
|
+
}
|
|
1576
|
+
return {
|
|
1577
|
+
id: event.id,
|
|
1578
|
+
schema_version: event.schema_version,
|
|
1579
|
+
timestamp: event.timestamp,
|
|
1580
|
+
event_type: decoded
|
|
1581
|
+
};
|
|
1582
|
+
}
|
|
1583
|
+
return {
|
|
1584
|
+
id: event.id,
|
|
1585
|
+
schema_version: event.schema_version,
|
|
1586
|
+
timestamp: event.timestamp,
|
|
1587
|
+
event_type: event.event_type
|
|
1588
|
+
};
|
|
1589
|
+
}
|
|
1590
|
+
function decodeLoanCreatedEvent(payload) {
|
|
1591
|
+
const lend_asset = extractVariantTag(payload.lend_asset, KNOWN_ASSET_TAGS);
|
|
1592
|
+
const borrow_asset = extractVariantTag(
|
|
1593
|
+
payload.borrow_asset,
|
|
1594
|
+
KNOWN_ASSET_TAGS
|
|
1595
|
+
);
|
|
1596
|
+
if (!lend_asset || !borrow_asset) {
|
|
1597
|
+
return null;
|
|
1598
|
+
}
|
|
1599
|
+
return {
|
|
1600
|
+
LoanCreated: {
|
|
1601
|
+
loan_id: payload.loan_id,
|
|
1602
|
+
borrow_destination: payload.borrow_destination,
|
|
1603
|
+
lend_asset,
|
|
1604
|
+
borrow_amount: payload.borrow_amount,
|
|
1605
|
+
lend_pool_id: payload.lend_pool_id,
|
|
1606
|
+
refund_destination: payload.refund_destination,
|
|
1607
|
+
ltv_max_bps: payload.ltv_max_bps,
|
|
1608
|
+
ltv_timer_s: payload.ltv_timer_s,
|
|
1609
|
+
lending_profile: payload.lending_profile,
|
|
1610
|
+
borrow_pool_id: payload.borrow_pool_id,
|
|
1611
|
+
borrow_asset
|
|
1612
|
+
}
|
|
1613
|
+
};
|
|
1521
1614
|
}
|
|
1522
1615
|
|
|
1523
1616
|
// src/core/sdk-api-paths.ts
|
|
@@ -1591,9 +1684,9 @@ function buildActivityStatusPath(request) {
|
|
|
1591
1684
|
request.id
|
|
1592
1685
|
)}/status?${query.toString()}`;
|
|
1593
1686
|
}
|
|
1594
|
-
function
|
|
1595
|
-
const query = new URLSearchParams({
|
|
1596
|
-
return `${INSTANT_LOANS}/
|
|
1687
|
+
function buildInstantLoanFindPath(request) {
|
|
1688
|
+
const query = new URLSearchParams({ query: request.query });
|
|
1689
|
+
return `${INSTANT_LOANS}/find?${query.toString()}`;
|
|
1597
1690
|
}
|
|
1598
1691
|
function buildInstantLoanCollateralHintPath(request) {
|
|
1599
1692
|
return `${INSTANT_LOANS}/${encodeURIComponent(
|
|
@@ -1807,7 +1900,7 @@ var ActivitiesModule = class {
|
|
|
1807
1900
|
);
|
|
1808
1901
|
}
|
|
1809
1902
|
try {
|
|
1810
|
-
const result = await
|
|
1903
|
+
const result = await createFlexibleInstantLoansActor(
|
|
1811
1904
|
this.canisterContext
|
|
1812
1905
|
).get_loan(loanId);
|
|
1813
1906
|
if ("Err" in result) {
|
|
@@ -2222,6 +2315,41 @@ function mapHistoryStatusToApi(status) {
|
|
|
2222
2315
|
return status.toUpperCase();
|
|
2223
2316
|
}
|
|
2224
2317
|
|
|
2318
|
+
// src/core/utils/api-response-parsers.ts
|
|
2319
|
+
var MILLISECONDS_PER_SECOND2 = 1e3;
|
|
2320
|
+
function parseNonEmptyApiString(value, field) {
|
|
2321
|
+
if (!value) {
|
|
2322
|
+
throwInvalidApiResponseField(field);
|
|
2323
|
+
}
|
|
2324
|
+
return value;
|
|
2325
|
+
}
|
|
2326
|
+
function parseUnsignedApiBigint(value, field) {
|
|
2327
|
+
if (!value || !/^\d+$/.test(value)) {
|
|
2328
|
+
throwInvalidApiResponseField(field);
|
|
2329
|
+
}
|
|
2330
|
+
return BigInt(value);
|
|
2331
|
+
}
|
|
2332
|
+
function parseIsoApiTimestampToUnixSeconds(value, field) {
|
|
2333
|
+
const timestamp = parseNonEmptyApiString(value, field);
|
|
2334
|
+
const timestampMilliseconds = Date.parse(timestamp);
|
|
2335
|
+
if (!Number.isFinite(timestampMilliseconds)) {
|
|
2336
|
+
throwInvalidApiResponseField(field);
|
|
2337
|
+
}
|
|
2338
|
+
return BigInt(Math.floor(timestampMilliseconds / MILLISECONDS_PER_SECOND2));
|
|
2339
|
+
}
|
|
2340
|
+
function parseApiStringUnion(value, allowedValues, field) {
|
|
2341
|
+
if (value !== void 0 && allowedValues.includes(value)) {
|
|
2342
|
+
return value;
|
|
2343
|
+
}
|
|
2344
|
+
throwInvalidApiResponseField(field);
|
|
2345
|
+
}
|
|
2346
|
+
function throwInvalidApiResponseField(field) {
|
|
2347
|
+
throw new LiquidiumError(
|
|
2348
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
2349
|
+
`Invalid ${field.context} ${field.label}`
|
|
2350
|
+
);
|
|
2351
|
+
}
|
|
2352
|
+
|
|
2225
2353
|
// src/core/utils/asset-decimals.ts
|
|
2226
2354
|
var ASSET_NATIVE_DECIMALS = {
|
|
2227
2355
|
BTC: 8n,
|
|
@@ -2241,7 +2369,7 @@ function getAssetNativeDecimals(asset) {
|
|
|
2241
2369
|
}
|
|
2242
2370
|
|
|
2243
2371
|
// src/generated/canisters/ck-btc-minter/declaration.js
|
|
2244
|
-
var
|
|
2372
|
+
var idlFactory2 = ({ IDL }) => {
|
|
2245
2373
|
const Mode = IDL.Variant({
|
|
2246
2374
|
"RestrictedTo": IDL.Vec(IDL.Principal),
|
|
2247
2375
|
"DepositsRestrictedTo": IDL.Vec(IDL.Principal),
|
|
@@ -2621,14 +2749,14 @@ var idlFactory3 = ({ IDL }) => {
|
|
|
2621
2749
|
// src/core/canisters/ckbtc/minter.ts
|
|
2622
2750
|
function createCkBtcMinterActor(canisterContext) {
|
|
2623
2751
|
const canisterId = CK_CANISTER_IDS.btcMinter;
|
|
2624
|
-
return Actor.createActor(
|
|
2752
|
+
return Actor.createActor(idlFactory2, {
|
|
2625
2753
|
agent: canisterContext.agent,
|
|
2626
2754
|
canisterId
|
|
2627
2755
|
});
|
|
2628
2756
|
}
|
|
2629
2757
|
|
|
2630
2758
|
// src/generated/canisters/deposit-accounts/deposit_accounts.did.js
|
|
2631
|
-
var
|
|
2759
|
+
var idlFactory3 = ({ IDL }) => {
|
|
2632
2760
|
const DepositAccountErrors = IDL.Variant({
|
|
2633
2761
|
"Busy": IDL.Null,
|
|
2634
2762
|
"NotFound": IDL.Null,
|
|
@@ -2848,7 +2976,7 @@ function createDepositAccountsActor(canisterContext) {
|
|
|
2848
2976
|
"ETH deposit canister ID is not configured"
|
|
2849
2977
|
);
|
|
2850
2978
|
}
|
|
2851
|
-
return Actor.createActor(
|
|
2979
|
+
return Actor.createActor(idlFactory3, {
|
|
2852
2980
|
agent: canisterContext.agent,
|
|
2853
2981
|
canisterId
|
|
2854
2982
|
});
|
|
@@ -3613,6 +3741,14 @@ var RATE_SCALE2 = 10n ** 27n;
|
|
|
3613
3741
|
var SECONDS_PER_YEAR = 31536000n;
|
|
3614
3742
|
var ETH_STABLECOIN_INFLOW_FEE_FALLBACK = 1500000n;
|
|
3615
3743
|
var INSTANT_LOAN_MIN_SLIPPAGE_BUFFER_BPS = 200n;
|
|
3744
|
+
var INSTANT_LOAN_FIND_QUERY_MAX_LENGTH = 256;
|
|
3745
|
+
var INSTANT_LOAN_WIRE_CONTEXT = "instant loan";
|
|
3746
|
+
var INSTANT_LOAN_ASSETS = [
|
|
3747
|
+
Asset.BTC,
|
|
3748
|
+
Asset.SOL,
|
|
3749
|
+
Asset.USDC,
|
|
3750
|
+
Asset.USDT
|
|
3751
|
+
];
|
|
3616
3752
|
var InstantLoansModule = class {
|
|
3617
3753
|
constructor(canisterContext, apiClient, lending, positions) {
|
|
3618
3754
|
this.canisterContext = canisterContext;
|
|
@@ -3669,7 +3805,19 @@ var InstantLoansModule = class {
|
|
|
3669
3805
|
borrowDestination,
|
|
3670
3806
|
refundDestination
|
|
3671
3807
|
});
|
|
3672
|
-
|
|
3808
|
+
const loanId = parseUnsignedApiBigint(response.loan.loanId, {
|
|
3809
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
3810
|
+
label: "loan ID"
|
|
3811
|
+
});
|
|
3812
|
+
const collateralAmount = parseUnsignedApiBigint(
|
|
3813
|
+
response.loan.collateral.amountHint,
|
|
3814
|
+
{
|
|
3815
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
3816
|
+
label: "collateral amount"
|
|
3817
|
+
}
|
|
3818
|
+
);
|
|
3819
|
+
const record = await this.getLoanRecord(loanId);
|
|
3820
|
+
return await this.mapLoanRecord(record, collateralAmount);
|
|
3673
3821
|
}
|
|
3674
3822
|
/**
|
|
3675
3823
|
* Resolves canonical canister state by loan id or short reference.
|
|
@@ -3682,21 +3830,30 @@ var InstantLoansModule = class {
|
|
|
3682
3830
|
*/
|
|
3683
3831
|
async get(request) {
|
|
3684
3832
|
const loanId = "loanId" in request ? request.loanId : decodeRef(request.ref);
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3833
|
+
const record = await this.getLoanRecord(loanId);
|
|
3834
|
+
const collateralAmount = await this.getCollateralAmountHint(loanId);
|
|
3835
|
+
return await this.mapLoanRecord(record, collateralAmount);
|
|
3836
|
+
}
|
|
3837
|
+
/**
|
|
3838
|
+
* Finds instant loans by short reference, numeric loan id string, address, or transaction id.
|
|
3839
|
+
*
|
|
3840
|
+
* Search returns lightweight matches. Call `get({ loanId })` or `get({ ref })`
|
|
3841
|
+
* when the user selects a match and you need hydrated loan state.
|
|
3842
|
+
*
|
|
3843
|
+
* @param query - Short reference, address, transaction id/hash, or numeric loan id string.
|
|
3844
|
+
* @returns Matching loan ids and references from the search index.
|
|
3845
|
+
*/
|
|
3846
|
+
async find(query) {
|
|
3847
|
+
const validatedQuery = validateInstantLoanFindQuery(query);
|
|
3848
|
+
const candidates = await this.findCandidateLoansByQuery(validatedQuery);
|
|
3849
|
+
return uniqueInstantLoanFindCandidates(candidates).map((candidate) => ({
|
|
3850
|
+
loanId: candidate.loanId,
|
|
3851
|
+
ref: candidate.ref,
|
|
3852
|
+
createdAt: candidate.createdAt,
|
|
3853
|
+
collateral: candidate.collateral,
|
|
3854
|
+
borrow: candidate.borrow,
|
|
3855
|
+
profileId: candidate.profileId
|
|
3856
|
+
}));
|
|
3700
3857
|
}
|
|
3701
3858
|
/**
|
|
3702
3859
|
* Returns the active instant-loans canister config via direct query.
|
|
@@ -3705,7 +3862,7 @@ var InstantLoansModule = class {
|
|
|
3705
3862
|
*/
|
|
3706
3863
|
async getConfig() {
|
|
3707
3864
|
try {
|
|
3708
|
-
const config = await
|
|
3865
|
+
const config = await createFlexibleInstantLoansActor(
|
|
3709
3866
|
this.canisterContext
|
|
3710
3867
|
).get_config();
|
|
3711
3868
|
return {
|
|
@@ -3723,10 +3880,11 @@ var InstantLoansModule = class {
|
|
|
3723
3880
|
*/
|
|
3724
3881
|
async getEvent(eventId) {
|
|
3725
3882
|
try {
|
|
3726
|
-
const event = await
|
|
3883
|
+
const event = await createFlexibleInstantLoansActor(
|
|
3727
3884
|
this.canisterContext
|
|
3728
3885
|
).get_event(eventId);
|
|
3729
|
-
|
|
3886
|
+
const decoded = event[0] ? decodeFlexibleHeadlessLoanEvent(event[0]) : null;
|
|
3887
|
+
return decoded ? mapInstantLoanEvent(decoded) : null;
|
|
3730
3888
|
} catch (error) {
|
|
3731
3889
|
throw mapCanisterCallErrorToLiquidiumError("get_event", error);
|
|
3732
3890
|
}
|
|
@@ -3739,10 +3897,10 @@ var InstantLoansModule = class {
|
|
|
3739
3897
|
*/
|
|
3740
3898
|
async listEvents(request) {
|
|
3741
3899
|
try {
|
|
3742
|
-
const events = await
|
|
3900
|
+
const events = await createFlexibleInstantLoansActor(
|
|
3743
3901
|
this.canisterContext
|
|
3744
3902
|
).list_events(request.start, request.limit);
|
|
3745
|
-
return events.map(([, event]) => mapInstantLoanEvent(event));
|
|
3903
|
+
return events.map(([, event]) => decodeFlexibleHeadlessLoanEvent(event)).filter((event) => event !== null).map((event) => mapInstantLoanEvent(event));
|
|
3746
3904
|
} catch (error) {
|
|
3747
3905
|
throw mapCanisterCallErrorToLiquidiumError("list_events", error);
|
|
3748
3906
|
}
|
|
@@ -3754,7 +3912,7 @@ var InstantLoansModule = class {
|
|
|
3754
3912
|
*/
|
|
3755
3913
|
async listAccessList() {
|
|
3756
3914
|
try {
|
|
3757
|
-
const principals = await
|
|
3915
|
+
const principals = await createFlexibleInstantLoansActor(
|
|
3758
3916
|
this.canisterContext
|
|
3759
3917
|
).list_access_list();
|
|
3760
3918
|
return principals.map((principal) => principal.toText());
|
|
@@ -3769,7 +3927,7 @@ var InstantLoansModule = class {
|
|
|
3769
3927
|
*/
|
|
3770
3928
|
async countWarmedProfiles() {
|
|
3771
3929
|
try {
|
|
3772
|
-
return await
|
|
3930
|
+
return await createFlexibleInstantLoansActor(
|
|
3773
3931
|
this.canisterContext
|
|
3774
3932
|
).count_warmed_profiles();
|
|
3775
3933
|
} catch (error) {
|
|
@@ -3786,7 +3944,7 @@ var InstantLoansModule = class {
|
|
|
3786
3944
|
*/
|
|
3787
3945
|
async listWarmedProfiles() {
|
|
3788
3946
|
try {
|
|
3789
|
-
const profiles = await
|
|
3947
|
+
const profiles = await createFlexibleInstantLoansActor(
|
|
3790
3948
|
this.canisterContext
|
|
3791
3949
|
).list_warmed_profiles();
|
|
3792
3950
|
return profiles.map(mapWarmedProfile);
|
|
@@ -3794,30 +3952,36 @@ var InstantLoansModule = class {
|
|
|
3794
3952
|
throw mapCanisterCallErrorToLiquidiumError("list_warmed_profiles", error);
|
|
3795
3953
|
}
|
|
3796
3954
|
}
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
* API. Returns discovery candidates only; call `get(...)` to hydrate canister state.
|
|
3800
|
-
*
|
|
3801
|
-
* Candidates are useful for recovery flows where the user knows a borrow or
|
|
3802
|
-
* refund address but not the loan reference.
|
|
3803
|
-
*
|
|
3804
|
-
* @param address - Borrow or refund address to search for.
|
|
3805
|
-
* @returns Lightweight loan candidates associated with the address.
|
|
3806
|
-
*/
|
|
3807
|
-
async findByAddress(address) {
|
|
3808
|
-
const trimmedAddress = address.trim();
|
|
3809
|
-
if (!trimmedAddress) {
|
|
3810
|
-
throw new LiquidiumError(
|
|
3811
|
-
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
3812
|
-
"Address lookup requires a non-empty address"
|
|
3813
|
-
);
|
|
3814
|
-
}
|
|
3815
|
-
const apiClient = this.requireApi("Instant loan address lookup");
|
|
3955
|
+
async findCandidateLoansByQuery(query) {
|
|
3956
|
+
const apiClient = this.requireApi("Instant loan find");
|
|
3816
3957
|
const response = await apiClient.get(
|
|
3817
|
-
|
|
3958
|
+
buildInstantLoanFindPath({ query })
|
|
3818
3959
|
);
|
|
3819
3960
|
return (response.candidates ?? response.loans ?? []).map(mapCandidateWire);
|
|
3820
3961
|
}
|
|
3962
|
+
async getLoanRecord(loanId) {
|
|
3963
|
+
try {
|
|
3964
|
+
const result = await createFlexibleInstantLoansActor(
|
|
3965
|
+
this.canisterContext
|
|
3966
|
+
).get_loan(loanId);
|
|
3967
|
+
if ("Err" in result) {
|
|
3968
|
+
throw mapInstantLoansErrorToLiquidiumError(result.Err);
|
|
3969
|
+
}
|
|
3970
|
+
const decoded = decodeFlexibleInstantLoanRecord(result.Ok);
|
|
3971
|
+
if (!decoded) {
|
|
3972
|
+
throw new LiquidiumError(
|
|
3973
|
+
LiquidiumErrorCode.POOL_NOT_FOUND,
|
|
3974
|
+
`Instant loan ${loanId.toString()} uses an unsupported asset`
|
|
3975
|
+
);
|
|
3976
|
+
}
|
|
3977
|
+
return decoded;
|
|
3978
|
+
} catch (error) {
|
|
3979
|
+
if (error instanceof LiquidiumError) {
|
|
3980
|
+
throw error;
|
|
3981
|
+
}
|
|
3982
|
+
throw mapCanisterCallErrorToLiquidiumError("get_loan", error);
|
|
3983
|
+
}
|
|
3984
|
+
}
|
|
3821
3985
|
async mapLoanRecord(record, collateralAmount) {
|
|
3822
3986
|
return await this.hydrateLoan({
|
|
3823
3987
|
loanId: record.id,
|
|
@@ -3827,41 +3991,26 @@ var InstantLoansModule = class {
|
|
|
3827
3991
|
collateralPoolId: record.lend_pool_id.toText(),
|
|
3828
3992
|
collateralAmount,
|
|
3829
3993
|
borrowPoolId: record.borrow_pool_id.toText(),
|
|
3830
|
-
collateralAsset:
|
|
3831
|
-
borrowAsset:
|
|
3994
|
+
collateralAsset: record.lend_asset,
|
|
3995
|
+
borrowAsset: record.borrow_asset,
|
|
3832
3996
|
borrowAmount: record.borrow_amount,
|
|
3833
3997
|
borrowDestination: accountFromCanister(record.borrow_destination),
|
|
3834
|
-
refundDestination: accountFromCanister(record.refund_destination)
|
|
3998
|
+
refundDestination: accountFromCanister(record.refund_destination),
|
|
3999
|
+
depositDetectedTimestamp: record.deposit_detected_ts[0] ?? null,
|
|
4000
|
+
expiryTimestamp: record.expires_at[0] ?? deriveDepositExpiryTimestamp({
|
|
4001
|
+
depositDetectedTimestamp: record.deposit_detected_ts[0] ?? null,
|
|
4002
|
+
depositWindowSeconds: record.ltv_timer_s
|
|
4003
|
+
})
|
|
3835
4004
|
});
|
|
3836
4005
|
}
|
|
3837
4006
|
async getCollateralAmountHint(loanId) {
|
|
3838
|
-
const apiClient = this.requireApi("Instant loan
|
|
4007
|
+
const apiClient = this.requireApi("Instant loan collateral hint");
|
|
3839
4008
|
const response = await apiClient.get(
|
|
3840
4009
|
buildInstantLoanCollateralHintPath({ loanId })
|
|
3841
4010
|
);
|
|
3842
|
-
return
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
const loanId = parseBigintWire(loan.loanId, "loan ID");
|
|
3846
|
-
return await this.hydrateLoan({
|
|
3847
|
-
loanId,
|
|
3848
|
-
profileId: loan.profileId,
|
|
3849
|
-
ltvMaxBps: parseBigintWire(loan.ltvMaxBps, "max LTV"),
|
|
3850
|
-
depositWindowSeconds: parseBigintWire(
|
|
3851
|
-
loan.depositWindowSeconds,
|
|
3852
|
-
"deposit window"
|
|
3853
|
-
),
|
|
3854
|
-
collateralPoolId: loan.collateral.poolId,
|
|
3855
|
-
collateralAmount: parseBigintWire(
|
|
3856
|
-
loan.collateral.amountHint,
|
|
3857
|
-
"collateral amount"
|
|
3858
|
-
),
|
|
3859
|
-
borrowPoolId: loan.borrow.poolId,
|
|
3860
|
-
collateralAsset: loan.collateral.asset,
|
|
3861
|
-
borrowAsset: loan.borrow.asset,
|
|
3862
|
-
borrowAmount: parseBigintWire(loan.borrow.amount, "borrow amount"),
|
|
3863
|
-
borrowDestination: accountFromWire(loan.borrow.destination),
|
|
3864
|
-
refundDestination: accountFromWire(loan.refundDestination)
|
|
4011
|
+
return parseUnsignedApiBigint(response.collateralAmountHint, {
|
|
4012
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
4013
|
+
label: "collateral amount"
|
|
3865
4014
|
});
|
|
3866
4015
|
}
|
|
3867
4016
|
async hydrateLoan(input) {
|
|
@@ -3915,7 +4064,9 @@ var InstantLoansModule = class {
|
|
|
3915
4064
|
collateralAmount,
|
|
3916
4065
|
decimals: collateralDecimals,
|
|
3917
4066
|
asset: collateralAsset,
|
|
3918
|
-
target: depositTarget
|
|
4067
|
+
target: depositTarget,
|
|
4068
|
+
detectedTimestamp: input.depositDetectedTimestamp,
|
|
4069
|
+
expiryTimestamp: input.expiryTimestamp
|
|
3919
4070
|
});
|
|
3920
4071
|
const repayment = {
|
|
3921
4072
|
amount: repaymentAmount,
|
|
@@ -3979,7 +4130,9 @@ var InstantLoansModule = class {
|
|
|
3979
4130
|
inflowFeeAmount: inflowFee.totalFee,
|
|
3980
4131
|
asset: input.asset,
|
|
3981
4132
|
chain: input.target.chain,
|
|
3982
|
-
target: input.target
|
|
4133
|
+
target: input.target,
|
|
4134
|
+
detectedTimestamp: input.detectedTimestamp,
|
|
4135
|
+
expiryTimestamp: input.expiryTimestamp
|
|
3983
4136
|
};
|
|
3984
4137
|
}
|
|
3985
4138
|
async estimateRepaymentInflowFee(asset, chain) {
|
|
@@ -4075,6 +4228,12 @@ function deriveInstantLoanStatus(input) {
|
|
|
4075
4228
|
}
|
|
4076
4229
|
return InstantLoanStatus.awaitingDeposit;
|
|
4077
4230
|
}
|
|
4231
|
+
function deriveDepositExpiryTimestamp(input) {
|
|
4232
|
+
if (input.depositDetectedTimestamp === null) {
|
|
4233
|
+
return null;
|
|
4234
|
+
}
|
|
4235
|
+
return input.depositDetectedTimestamp + input.depositWindowSeconds;
|
|
4236
|
+
}
|
|
4078
4237
|
function validateCreateRequest(request) {
|
|
4079
4238
|
if (request.collateralAmount <= 0n) {
|
|
4080
4239
|
throw new LiquidiumError(
|
|
@@ -4123,18 +4282,6 @@ function accountFromCanister(account) {
|
|
|
4123
4282
|
}
|
|
4124
4283
|
return { type: "External", address: account.External };
|
|
4125
4284
|
}
|
|
4126
|
-
function accountFromWire(account) {
|
|
4127
|
-
if ("Native" in account) {
|
|
4128
|
-
return { type: "Native", principal: account.Native };
|
|
4129
|
-
}
|
|
4130
|
-
if ("External" in account) {
|
|
4131
|
-
return { type: "External", address: account.External };
|
|
4132
|
-
}
|
|
4133
|
-
if (account.type === "Native") {
|
|
4134
|
-
return { type: "Native", principal: account.principal };
|
|
4135
|
-
}
|
|
4136
|
-
return { type: "External", address: account.address };
|
|
4137
|
-
}
|
|
4138
4285
|
function mapInstantLoanEvent(event) {
|
|
4139
4286
|
return {
|
|
4140
4287
|
id: event.id,
|
|
@@ -4150,7 +4297,7 @@ function mapInstantLoanEventType(eventType) {
|
|
|
4150
4297
|
type: "LoanCreated",
|
|
4151
4298
|
loanId: event.loan_id,
|
|
4152
4299
|
borrowDestination: accountFromCanister(event.borrow_destination),
|
|
4153
|
-
collateralAsset:
|
|
4300
|
+
collateralAsset: event.lend_asset,
|
|
4154
4301
|
borrowAmount: event.borrow_amount,
|
|
4155
4302
|
collateralPoolId: event.lend_pool_id.toText(),
|
|
4156
4303
|
refundDestination: accountFromCanister(event.refund_destination),
|
|
@@ -4158,7 +4305,7 @@ function mapInstantLoanEventType(eventType) {
|
|
|
4158
4305
|
depositWindowSeconds: event.ltv_timer_s,
|
|
4159
4306
|
profileId: event.lending_profile.toText(),
|
|
4160
4307
|
borrowPoolId: event.borrow_pool_id.toText(),
|
|
4161
|
-
borrowAsset:
|
|
4308
|
+
borrowAsset: event.borrow_asset
|
|
4162
4309
|
};
|
|
4163
4310
|
}
|
|
4164
4311
|
if ("FullLendWithdrawalRequested" in eventType) {
|
|
@@ -4236,9 +4383,6 @@ function authorizationFromCanister(authorization) {
|
|
|
4236
4383
|
address: authorization.EthSignature.address
|
|
4237
4384
|
};
|
|
4238
4385
|
}
|
|
4239
|
-
function assetFromCanister(asset) {
|
|
4240
|
-
return getVariantKey(asset);
|
|
4241
|
-
}
|
|
4242
4386
|
function legFromCanister(leg) {
|
|
4243
4387
|
return getVariantKey(leg);
|
|
4244
4388
|
}
|
|
@@ -4253,55 +4397,80 @@ function decodeRef(ref) {
|
|
|
4253
4397
|
);
|
|
4254
4398
|
}
|
|
4255
4399
|
}
|
|
4256
|
-
function
|
|
4257
|
-
|
|
4258
|
-
const ref = wire.ref ?? wire.short_ref ?? publicIdFromInt(loanId);
|
|
4259
|
-
const createdAt = wire.createdAt ?? wire.created_at;
|
|
4260
|
-
return {
|
|
4261
|
-
loanId,
|
|
4262
|
-
ref,
|
|
4263
|
-
profileId: requiredString(
|
|
4264
|
-
wire.profileId ?? wire.lending_profile,
|
|
4265
|
-
"profile ID"
|
|
4266
|
-
),
|
|
4267
|
-
...createdAt ? { createdAt: new Date(createdAt) } : {},
|
|
4268
|
-
collateralPoolId: requiredString(
|
|
4269
|
-
wire.collateralPoolId ?? wire.lend_pool_ic_id,
|
|
4270
|
-
"collateral pool ID"
|
|
4271
|
-
),
|
|
4272
|
-
borrowPoolId: requiredString(
|
|
4273
|
-
wire.borrowPoolId ?? wire.borrow_pool_ic_id,
|
|
4274
|
-
"borrow pool ID"
|
|
4275
|
-
),
|
|
4276
|
-
collateralAsset: requiredString(
|
|
4277
|
-
wire.collateralAsset ?? wire.lend_asset,
|
|
4278
|
-
"collateral asset"
|
|
4279
|
-
),
|
|
4280
|
-
borrowAsset: requiredString(
|
|
4281
|
-
wire.borrowAsset ?? wire.borrow_asset,
|
|
4282
|
-
"borrow asset"
|
|
4283
|
-
),
|
|
4284
|
-
collateralAmount: parseBigintWire(
|
|
4285
|
-
wire.collateralAmount,
|
|
4286
|
-
"collateral amount"
|
|
4287
|
-
)
|
|
4288
|
-
};
|
|
4289
|
-
}
|
|
4290
|
-
function parseBigintWire(value, label) {
|
|
4291
|
-
if (!value || !/^\d+$/.test(value)) {
|
|
4400
|
+
function validateInstantLoanFindQuery(query) {
|
|
4401
|
+
if (typeof query !== "string") {
|
|
4292
4402
|
throw new LiquidiumError(
|
|
4293
4403
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
4294
|
-
|
|
4404
|
+
"Instant loan find query must be a string"
|
|
4295
4405
|
);
|
|
4296
4406
|
}
|
|
4297
|
-
|
|
4407
|
+
const trimmedQuery = query.trim();
|
|
4408
|
+
if (!trimmedQuery) {
|
|
4409
|
+
throw new LiquidiumError(
|
|
4410
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
4411
|
+
"Instant loan find query must be non-empty"
|
|
4412
|
+
);
|
|
4413
|
+
}
|
|
4414
|
+
if (trimmedQuery.length > INSTANT_LOAN_FIND_QUERY_MAX_LENGTH) {
|
|
4415
|
+
throw new LiquidiumError(
|
|
4416
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
4417
|
+
`Instant loan find query must be at most ${INSTANT_LOAN_FIND_QUERY_MAX_LENGTH.toString()} characters`
|
|
4418
|
+
);
|
|
4419
|
+
}
|
|
4420
|
+
return trimmedQuery;
|
|
4298
4421
|
}
|
|
4299
|
-
function
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4422
|
+
function uniqueInstantLoanFindCandidates(candidates) {
|
|
4423
|
+
const candidatesByLoanId = /* @__PURE__ */ new Map();
|
|
4424
|
+
for (const candidate of candidates) {
|
|
4425
|
+
if (!candidatesByLoanId.has(candidate.loanId)) {
|
|
4426
|
+
candidatesByLoanId.set(candidate.loanId, candidate);
|
|
4427
|
+
}
|
|
4428
|
+
}
|
|
4429
|
+
return [...candidatesByLoanId.values()];
|
|
4430
|
+
}
|
|
4431
|
+
function mapCandidateWire(wire) {
|
|
4432
|
+
return {
|
|
4433
|
+
loanId: parseUnsignedApiBigint(wire.loan_id, {
|
|
4434
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
4435
|
+
label: "loan ID"
|
|
4436
|
+
}),
|
|
4437
|
+
ref: parseNonEmptyApiString(wire.short_ref, {
|
|
4438
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
4439
|
+
label: "short reference"
|
|
4440
|
+
}),
|
|
4441
|
+
createdAt: parseIsoApiTimestampToUnixSeconds(wire.created_at, {
|
|
4442
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
4443
|
+
label: "creation timestamp"
|
|
4444
|
+
}),
|
|
4445
|
+
collateral: {
|
|
4446
|
+
poolId: parseNonEmptyApiString(wire.lend_pool_ic_id, {
|
|
4447
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
4448
|
+
label: "lend pool ID"
|
|
4449
|
+
}),
|
|
4450
|
+
asset: parseApiStringUnion(wire.lend_asset, INSTANT_LOAN_ASSETS, {
|
|
4451
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
4452
|
+
label: "lend asset"
|
|
4453
|
+
}),
|
|
4454
|
+
amount: parseUnsignedApiBigint(wire.collateral_amount, {
|
|
4455
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
4456
|
+
label: "collateral amount"
|
|
4457
|
+
})
|
|
4458
|
+
},
|
|
4459
|
+
borrow: {
|
|
4460
|
+
poolId: parseNonEmptyApiString(wire.borrow_pool_ic_id, {
|
|
4461
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
4462
|
+
label: "borrow pool ID"
|
|
4463
|
+
}),
|
|
4464
|
+
asset: parseApiStringUnion(wire.borrow_asset, INSTANT_LOAN_ASSETS, {
|
|
4465
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
4466
|
+
label: "borrow asset"
|
|
4467
|
+
})
|
|
4468
|
+
},
|
|
4469
|
+
profileId: parseNonEmptyApiString(wire.profile, {
|
|
4470
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
4471
|
+
label: "profile ID"
|
|
4472
|
+
})
|
|
4473
|
+
};
|
|
4305
4474
|
}
|
|
4306
4475
|
function mapInstantLoansErrorToLiquidiumError(error) {
|
|
4307
4476
|
const [key, payload] = Object.entries(error)[0];
|
|
@@ -4441,12 +4610,12 @@ function encodeBytes32Hex(bytes) {
|
|
|
4441
4610
|
(byte) => byte.toString(16).padStart(2, "0")
|
|
4442
4611
|
).join("")}`;
|
|
4443
4612
|
}
|
|
4444
|
-
var
|
|
4613
|
+
var idlFactory4 = ({ IDL }) => IDL.Service({
|
|
4445
4614
|
icrc1_fee: IDL.Func([], [IDL.Nat], ["query"])
|
|
4446
4615
|
});
|
|
4447
4616
|
function createCkBtcLedgerActor(canisterContext) {
|
|
4448
4617
|
const canisterId = CK_CANISTER_IDS.btcLedger;
|
|
4449
|
-
return Actor.createActor(
|
|
4618
|
+
return Actor.createActor(idlFactory4, {
|
|
4450
4619
|
agent: canisterContext.agent,
|
|
4451
4620
|
canisterId
|
|
4452
4621
|
});
|
|
@@ -5513,21 +5682,203 @@ function shouldSubmitInflow(params) {
|
|
|
5513
5682
|
}
|
|
5514
5683
|
return !isEthStablecoin(params.instruction.asset, params.instruction.chain);
|
|
5515
5684
|
}
|
|
5685
|
+
var flexibleLendingIdlFactory = ({ IDL }) => {
|
|
5686
|
+
const PoolRecord = IDL.Record({
|
|
5687
|
+
principal: IDL.Principal,
|
|
5688
|
+
asset: IDL.Unknown,
|
|
5689
|
+
chain: IDL.Unknown,
|
|
5690
|
+
total_supply_at_last_sync: IDL.Nat,
|
|
5691
|
+
total_debt_at_last_sync: IDL.Nat,
|
|
5692
|
+
supply_cap: IDL.Opt(IDL.Nat),
|
|
5693
|
+
borrow_cap: IDL.Opt(IDL.Nat),
|
|
5694
|
+
max_ltv: IDL.Nat64,
|
|
5695
|
+
liquidation_threshold: IDL.Nat64,
|
|
5696
|
+
liquidation_bonus: IDL.Nat64,
|
|
5697
|
+
protocol_liquidation_fee: IDL.Nat64,
|
|
5698
|
+
reserve_factor: IDL.Nat64,
|
|
5699
|
+
base_rate: IDL.Nat,
|
|
5700
|
+
optimal_utilization_rate: IDL.Nat,
|
|
5701
|
+
rate_slope_before: IDL.Nat,
|
|
5702
|
+
rate_slope_after: IDL.Nat,
|
|
5703
|
+
lending_index: IDL.Nat,
|
|
5704
|
+
borrow_index: IDL.Nat,
|
|
5705
|
+
same_asset_borrowing: IDL.Opt(IDL.Bool),
|
|
5706
|
+
frozen: IDL.Bool,
|
|
5707
|
+
last_updated: IDL.Opt(IDL.Nat64)
|
|
5708
|
+
});
|
|
5709
|
+
const BorrowingPowerRecord = IDL.Record({
|
|
5710
|
+
max_borrowable_usd: IDL.Nat,
|
|
5711
|
+
weighted_max_ltv: IDL.Nat
|
|
5712
|
+
});
|
|
5713
|
+
const PositionRecord = IDL.Record({
|
|
5714
|
+
asset: IDL.Unknown,
|
|
5715
|
+
total_debt_interest: IDL.Nat,
|
|
5716
|
+
borrow_index_snapshot: IDL.Nat,
|
|
5717
|
+
lending_index_snapshot: IDL.Nat,
|
|
5718
|
+
debt_scaled: IDL.Nat,
|
|
5719
|
+
total_earned_interest: IDL.Nat,
|
|
5720
|
+
deposit_scaled: IDL.Nat,
|
|
5721
|
+
pool_id: IDL.Principal,
|
|
5722
|
+
unpaid_debt_interest: IDL.Nat,
|
|
5723
|
+
last_update: IDL.Nat64,
|
|
5724
|
+
user_profile: IDL.Principal
|
|
5725
|
+
});
|
|
5726
|
+
const UserStatsRecord = IDL.Record({
|
|
5727
|
+
debt: IDL.Nat,
|
|
5728
|
+
collateral: IDL.Nat,
|
|
5729
|
+
acumulated_interest: IDL.Nat,
|
|
5730
|
+
borrowing_power: BorrowingPowerRecord,
|
|
5731
|
+
positions: IDL.Vec(PositionRecord),
|
|
5732
|
+
weighted_liquidation_threshold: IDL.Nat
|
|
5733
|
+
});
|
|
5734
|
+
const PositionViewRecord = IDL.Record({
|
|
5735
|
+
lending_index_now: IDL.Nat,
|
|
5736
|
+
interest_since_snapshot: IDL.Nat,
|
|
5737
|
+
asset: IDL.Unknown,
|
|
5738
|
+
total_debt_interest: IDL.Nat,
|
|
5739
|
+
borrow_index_snapshot: IDL.Nat,
|
|
5740
|
+
debt_native_now: IDL.Nat,
|
|
5741
|
+
borrow_index_now: IDL.Nat,
|
|
5742
|
+
lending_index_snapshot: IDL.Nat,
|
|
5743
|
+
debt_scaled: IDL.Nat,
|
|
5744
|
+
total_earned_interest: IDL.Nat,
|
|
5745
|
+
deposit_scaled: IDL.Nat,
|
|
5746
|
+
earned_since_snapshot: IDL.Nat,
|
|
5747
|
+
deposited_native_now: IDL.Nat,
|
|
5748
|
+
pool_id: IDL.Principal,
|
|
5749
|
+
last_update: IDL.Nat64,
|
|
5750
|
+
user_profile: IDL.Principal
|
|
5751
|
+
});
|
|
5752
|
+
return IDL.Service({
|
|
5753
|
+
list_pools: IDL.Func([], [IDL.Vec(PoolRecord)], ["query"]),
|
|
5754
|
+
get_pool_rate: IDL.Func(
|
|
5755
|
+
[IDL.Principal],
|
|
5756
|
+
[IDL.Opt(IDL.Tuple(IDL.Nat, IDL.Nat, IDL.Nat))],
|
|
5757
|
+
["query"]
|
|
5758
|
+
),
|
|
5759
|
+
get_health_factor: IDL.Func(
|
|
5760
|
+
[IDL.Principal],
|
|
5761
|
+
[IDL.Nat, UserStatsRecord],
|
|
5762
|
+
["query"]
|
|
5763
|
+
),
|
|
5764
|
+
get_profile_stats: IDL.Func([IDL.Principal], [UserStatsRecord], ["query"]),
|
|
5765
|
+
get_position: IDL.Func(
|
|
5766
|
+
[IDL.Principal, IDL.Principal],
|
|
5767
|
+
[IDL.Opt(PositionViewRecord)],
|
|
5768
|
+
["query"]
|
|
5769
|
+
)
|
|
5770
|
+
});
|
|
5771
|
+
};
|
|
5772
|
+
function createFlexibleLendingActor(canisterContext) {
|
|
5773
|
+
const canisterId = canisterContext.canisterIds.lending;
|
|
5774
|
+
if (!canisterId) {
|
|
5775
|
+
throw new LiquidiumError(
|
|
5776
|
+
LiquidiumErrorCode.SERVICE_UNAVAILABLE,
|
|
5777
|
+
"Lending canister ID is not configured"
|
|
5778
|
+
);
|
|
5779
|
+
}
|
|
5780
|
+
return Actor.createActor(flexibleLendingIdlFactory, {
|
|
5781
|
+
agent: canisterContext.agent,
|
|
5782
|
+
canisterId
|
|
5783
|
+
});
|
|
5784
|
+
}
|
|
5785
|
+
function decodeFlexiblePool(pool) {
|
|
5786
|
+
const asset = extractVariantTag(pool.asset, KNOWN_ASSET_TAGS);
|
|
5787
|
+
const chain = extractVariantTag(pool.chain, KNOWN_CHAIN_TAGS);
|
|
5788
|
+
if (!asset || !chain) {
|
|
5789
|
+
return null;
|
|
5790
|
+
}
|
|
5791
|
+
return {
|
|
5792
|
+
principal: pool.principal,
|
|
5793
|
+
asset,
|
|
5794
|
+
chain,
|
|
5795
|
+
total_supply_at_last_sync: pool.total_supply_at_last_sync,
|
|
5796
|
+
total_debt_at_last_sync: pool.total_debt_at_last_sync,
|
|
5797
|
+
supply_cap: pool.supply_cap,
|
|
5798
|
+
borrow_cap: pool.borrow_cap,
|
|
5799
|
+
max_ltv: pool.max_ltv,
|
|
5800
|
+
liquidation_threshold: pool.liquidation_threshold,
|
|
5801
|
+
liquidation_bonus: pool.liquidation_bonus,
|
|
5802
|
+
protocol_liquidation_fee: pool.protocol_liquidation_fee,
|
|
5803
|
+
reserve_factor: pool.reserve_factor,
|
|
5804
|
+
base_rate: pool.base_rate,
|
|
5805
|
+
optimal_utilization_rate: pool.optimal_utilization_rate,
|
|
5806
|
+
rate_slope_before: pool.rate_slope_before,
|
|
5807
|
+
rate_slope_after: pool.rate_slope_after,
|
|
5808
|
+
lending_index: pool.lending_index,
|
|
5809
|
+
borrow_index: pool.borrow_index,
|
|
5810
|
+
same_asset_borrowing: pool.same_asset_borrowing,
|
|
5811
|
+
frozen: pool.frozen,
|
|
5812
|
+
last_updated: pool.last_updated
|
|
5813
|
+
};
|
|
5814
|
+
}
|
|
5815
|
+
function decodeFlexiblePosition(position) {
|
|
5816
|
+
const asset = extractVariantTag(position.asset, KNOWN_ASSET_TAGS);
|
|
5817
|
+
if (!asset) {
|
|
5818
|
+
return null;
|
|
5819
|
+
}
|
|
5820
|
+
return {
|
|
5821
|
+
asset,
|
|
5822
|
+
total_debt_interest: position.total_debt_interest,
|
|
5823
|
+
borrow_index_snapshot: position.borrow_index_snapshot,
|
|
5824
|
+
lending_index_snapshot: position.lending_index_snapshot,
|
|
5825
|
+
debt_scaled: position.debt_scaled,
|
|
5826
|
+
total_earned_interest: position.total_earned_interest,
|
|
5827
|
+
deposit_scaled: position.deposit_scaled,
|
|
5828
|
+
pool_id: position.pool_id,
|
|
5829
|
+
unpaid_debt_interest: position.unpaid_debt_interest,
|
|
5830
|
+
last_update: position.last_update,
|
|
5831
|
+
user_profile: position.user_profile
|
|
5832
|
+
};
|
|
5833
|
+
}
|
|
5834
|
+
function decodeFlexiblePositionView(view) {
|
|
5835
|
+
const asset = extractVariantTag(view.asset, KNOWN_ASSET_TAGS);
|
|
5836
|
+
if (!asset) {
|
|
5837
|
+
return null;
|
|
5838
|
+
}
|
|
5839
|
+
return {
|
|
5840
|
+
lending_index_now: view.lending_index_now,
|
|
5841
|
+
interest_since_snapshot: view.interest_since_snapshot,
|
|
5842
|
+
asset,
|
|
5843
|
+
total_debt_interest: view.total_debt_interest,
|
|
5844
|
+
borrow_index_snapshot: view.borrow_index_snapshot,
|
|
5845
|
+
debt_native_now: view.debt_native_now,
|
|
5846
|
+
borrow_index_now: view.borrow_index_now,
|
|
5847
|
+
lending_index_snapshot: view.lending_index_snapshot,
|
|
5848
|
+
debt_scaled: view.debt_scaled,
|
|
5849
|
+
total_earned_interest: view.total_earned_interest,
|
|
5850
|
+
deposit_scaled: view.deposit_scaled,
|
|
5851
|
+
earned_since_snapshot: view.earned_since_snapshot,
|
|
5852
|
+
deposited_native_now: view.deposited_native_now,
|
|
5853
|
+
pool_id: view.pool_id,
|
|
5854
|
+
last_update: view.last_update,
|
|
5855
|
+
user_profile: view.user_profile
|
|
5856
|
+
};
|
|
5857
|
+
}
|
|
5858
|
+
function decodeFlexibleUserStats(stats) {
|
|
5859
|
+
return {
|
|
5860
|
+
debt: stats.debt,
|
|
5861
|
+
collateral: stats.collateral,
|
|
5862
|
+
acumulated_interest: stats.acumulated_interest,
|
|
5863
|
+
borrowing_power: stats.borrowing_power,
|
|
5864
|
+
positions: stats.positions.map(decodeFlexiblePosition).filter((position) => position !== null),
|
|
5865
|
+
weighted_liquidation_threshold: stats.weighted_liquidation_threshold
|
|
5866
|
+
};
|
|
5867
|
+
}
|
|
5516
5868
|
|
|
5517
5869
|
// src/modules/market/mappers.ts
|
|
5518
5870
|
var DECIMAL_BASE = 10;
|
|
5519
5871
|
var PAIR_SEPARATOR = "_";
|
|
5520
5872
|
var USDT_SYMBOL = "USDT";
|
|
5521
|
-
function
|
|
5522
|
-
const asset = getVariantKey(pool.asset);
|
|
5873
|
+
function mapDecodedPoolToPool(pool, rate) {
|
|
5523
5874
|
const totalSupply = pool.total_supply_at_last_sync;
|
|
5524
5875
|
const totalDebt = pool.total_debt_at_last_sync;
|
|
5525
5876
|
const availableLiquidity = totalSupply > totalDebt ? totalSupply - totalDebt : 0n;
|
|
5526
5877
|
return {
|
|
5527
5878
|
id: pool.principal.toString(),
|
|
5528
|
-
asset,
|
|
5529
|
-
chain:
|
|
5530
|
-
decimals: getAssetNativeDecimals(asset),
|
|
5879
|
+
asset: pool.asset,
|
|
5880
|
+
chain: pool.chain,
|
|
5881
|
+
decimals: getAssetNativeDecimals(pool.asset),
|
|
5531
5882
|
frozen: pool.frozen,
|
|
5532
5883
|
totalSupply,
|
|
5533
5884
|
totalDebt,
|
|
@@ -5600,13 +5951,14 @@ var MarketModule = class {
|
|
|
5600
5951
|
async listPools() {
|
|
5601
5952
|
void this.apiClient;
|
|
5602
5953
|
try {
|
|
5603
|
-
const
|
|
5604
|
-
const
|
|
5954
|
+
const flexibleActor = createFlexibleLendingActor(this.canisterContext);
|
|
5955
|
+
const rawPools = await flexibleActor.list_pools();
|
|
5956
|
+
const decodedPools = rawPools.map(decodeFlexiblePool).filter((pool) => pool !== null);
|
|
5605
5957
|
return await Promise.all(
|
|
5606
|
-
|
|
5607
|
-
const poolRate = await
|
|
5958
|
+
decodedPools.map(async (pool) => {
|
|
5959
|
+
const poolRate = await flexibleActor.get_pool_rate(pool.principal);
|
|
5608
5960
|
const resolvedPoolRate = poolRate[0] ?? ZERO_POOL_RATE;
|
|
5609
|
-
return
|
|
5961
|
+
return mapDecodedPoolToPool(pool, resolvedPoolRate);
|
|
5610
5962
|
})
|
|
5611
5963
|
);
|
|
5612
5964
|
} catch (error) {
|
|
@@ -5711,12 +6063,11 @@ var MarketModule = class {
|
|
|
5711
6063
|
|
|
5712
6064
|
// src/modules/positions/mappers.ts
|
|
5713
6065
|
var USD_VALUE_SCALE_DECIMALS = 27n;
|
|
5714
|
-
function
|
|
5715
|
-
const
|
|
5716
|
-
const nativeDecimals = getAssetNativeDecimals(asset);
|
|
6066
|
+
function mapDecodedPositionViewToPosition(view) {
|
|
6067
|
+
const nativeDecimals = getAssetNativeDecimals(view.asset);
|
|
5717
6068
|
return {
|
|
5718
6069
|
poolId: view.pool_id.toText(),
|
|
5719
|
-
asset,
|
|
6070
|
+
asset: view.asset,
|
|
5720
6071
|
deposited: view.deposited_native_now,
|
|
5721
6072
|
depositedDecimals: nativeDecimals,
|
|
5722
6073
|
borrowed: view.debt_native_now,
|
|
@@ -5733,15 +6084,18 @@ function mapBorrowingPowerRecordToBorrowingPower(record) {
|
|
|
5733
6084
|
maxBorrowableUsdDecimals: USD_VALUE_SCALE_DECIMALS
|
|
5734
6085
|
};
|
|
5735
6086
|
}
|
|
5736
|
-
function
|
|
6087
|
+
function mapDecodedUserStatsToUserStats(stats) {
|
|
6088
|
+
return mapUserStatsLikeToUserStats(stats);
|
|
6089
|
+
}
|
|
6090
|
+
function mapUserStatsLikeToUserStats(stats) {
|
|
5737
6091
|
return {
|
|
5738
|
-
debt:
|
|
6092
|
+
debt: stats.debt,
|
|
5739
6093
|
debtDecimals: USD_VALUE_SCALE_DECIMALS,
|
|
5740
|
-
collateral:
|
|
6094
|
+
collateral: stats.collateral,
|
|
5741
6095
|
collateralDecimals: USD_VALUE_SCALE_DECIMALS,
|
|
5742
|
-
weightedLiquidationThreshold:
|
|
6096
|
+
weightedLiquidationThreshold: stats.weighted_liquidation_threshold,
|
|
5743
6097
|
borrowingPower: mapBorrowingPowerRecordToBorrowingPower(
|
|
5744
|
-
|
|
6098
|
+
stats.borrowing_power
|
|
5745
6099
|
)
|
|
5746
6100
|
};
|
|
5747
6101
|
}
|
|
@@ -5765,14 +6119,18 @@ var PositionsModule = class {
|
|
|
5765
6119
|
*/
|
|
5766
6120
|
async getPosition(profileId, poolId) {
|
|
5767
6121
|
try {
|
|
5768
|
-
const result = await
|
|
6122
|
+
const result = await createFlexibleLendingActor(
|
|
5769
6123
|
this.canisterContext
|
|
5770
6124
|
).get_position(Principal.fromText(profileId), Principal.fromText(poolId));
|
|
5771
6125
|
const view = result[0];
|
|
5772
6126
|
if (!view) {
|
|
5773
6127
|
return null;
|
|
5774
6128
|
}
|
|
5775
|
-
|
|
6129
|
+
const decodedView = decodeFlexiblePositionView(view);
|
|
6130
|
+
if (!decodedView) {
|
|
6131
|
+
return null;
|
|
6132
|
+
}
|
|
6133
|
+
return mapDecodedPositionViewToPosition(decodedView);
|
|
5776
6134
|
} catch (error) {
|
|
5777
6135
|
if (error instanceof LiquidiumError) {
|
|
5778
6136
|
throw error;
|
|
@@ -5788,15 +6146,16 @@ var PositionsModule = class {
|
|
|
5788
6146
|
*/
|
|
5789
6147
|
async listPositions(profileId) {
|
|
5790
6148
|
try {
|
|
5791
|
-
const actor =
|
|
6149
|
+
const actor = createFlexibleLendingActor(this.canisterContext);
|
|
5792
6150
|
const profilePrincipal = Principal.fromText(profileId);
|
|
5793
6151
|
const stats = await actor.get_profile_stats(profilePrincipal);
|
|
6152
|
+
const decodedStats = decodeFlexibleUserStats(stats);
|
|
5794
6153
|
const positionViews = await Promise.all(
|
|
5795
|
-
|
|
6154
|
+
decodedStats.positions.map(
|
|
5796
6155
|
(position) => actor.get_position(profilePrincipal, position.pool_id)
|
|
5797
6156
|
)
|
|
5798
6157
|
);
|
|
5799
|
-
return positionViews.map((result) => result[0]).filter((view) => view !== void 0).map(
|
|
6158
|
+
return positionViews.map((result) => result[0]).filter((view) => view !== void 0).map(decodeFlexiblePositionView).filter((view) => view !== null).map(mapDecodedPositionViewToPosition);
|
|
5800
6159
|
} catch (error) {
|
|
5801
6160
|
if (error instanceof LiquidiumError) {
|
|
5802
6161
|
throw error;
|
|
@@ -5812,12 +6171,14 @@ var PositionsModule = class {
|
|
|
5812
6171
|
*/
|
|
5813
6172
|
async getHealthFactor(profileId) {
|
|
5814
6173
|
try {
|
|
5815
|
-
const [healthFactor, userStatsRecord] = await
|
|
6174
|
+
const [healthFactor, userStatsRecord] = await createFlexibleLendingActor(
|
|
5816
6175
|
this.canisterContext
|
|
5817
6176
|
).get_health_factor(Principal.fromText(profileId));
|
|
5818
6177
|
return {
|
|
5819
6178
|
healthFactor,
|
|
5820
|
-
userStats:
|
|
6179
|
+
userStats: mapDecodedUserStatsToUserStats(
|
|
6180
|
+
decodeFlexibleUserStats(userStatsRecord)
|
|
6181
|
+
)
|
|
5821
6182
|
};
|
|
5822
6183
|
} catch (error) {
|
|
5823
6184
|
if (error instanceof LiquidiumError) {
|
|
@@ -5834,10 +6195,10 @@ var PositionsModule = class {
|
|
|
5834
6195
|
*/
|
|
5835
6196
|
async getUserStats(profileId) {
|
|
5836
6197
|
try {
|
|
5837
|
-
const result = await
|
|
6198
|
+
const result = await createFlexibleLendingActor(
|
|
5838
6199
|
this.canisterContext
|
|
5839
6200
|
).get_profile_stats(Principal.fromText(profileId));
|
|
5840
|
-
return
|
|
6201
|
+
return mapDecodedUserStatsToUserStats(decodeFlexibleUserStats(result));
|
|
5841
6202
|
} catch (error) {
|
|
5842
6203
|
if (error instanceof LiquidiumError) {
|
|
5843
6204
|
throw error;
|
|
@@ -5906,7 +6267,7 @@ var PositionsModule = class {
|
|
|
5906
6267
|
pool,
|
|
5907
6268
|
priceUsd,
|
|
5908
6269
|
suppliedUsd: nativeAmountToUsdScaled(
|
|
5909
|
-
position.deposited
|
|
6270
|
+
position.deposited,
|
|
5910
6271
|
position.depositedDecimals,
|
|
5911
6272
|
priceUsd
|
|
5912
6273
|
),
|
|
@@ -5941,6 +6302,24 @@ var PositionsModule = class {
|
|
|
5941
6302
|
const buffered = rawDebt * (BPS_SCALE + bufferBps) / BPS_SCALE;
|
|
5942
6303
|
return { amount: buffered, decimals: position.borrowedDecimals };
|
|
5943
6304
|
}
|
|
6305
|
+
/**
|
|
6306
|
+
* Returns the current full withdraw amount for a position.
|
|
6307
|
+
*
|
|
6308
|
+
* `Position.deposited` already reflects the current supplied balance at the
|
|
6309
|
+
* latest lending index; do not add `earnedInterest` to this amount.
|
|
6310
|
+
* Pass `amount` to withdraw calls and use `decimals` for display formatting.
|
|
6311
|
+
*
|
|
6312
|
+
* @param profileId - The Liquidium profile principal text.
|
|
6313
|
+
* @param poolId - The pool principal text.
|
|
6314
|
+
* @returns Full withdraw amount in the supplied asset's base units.
|
|
6315
|
+
*/
|
|
6316
|
+
async getFullWithdrawAmount(profileId, poolId) {
|
|
6317
|
+
const position = await this.getPosition(profileId, poolId);
|
|
6318
|
+
if (!position) {
|
|
6319
|
+
return { amount: 0n, decimals: 0n };
|
|
6320
|
+
}
|
|
6321
|
+
return { amount: position.deposited, decimals: position.depositedDecimals };
|
|
6322
|
+
}
|
|
5944
6323
|
};
|
|
5945
6324
|
function nativeAmountToUsdScaled(amount, nativeDecimals, priceUsd) {
|
|
5946
6325
|
if (amount <= 0n || priceUsd <= 0) {
|