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