@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/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 idlFactory2 = ({ IDL }) => {
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: Assets,
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: Assets,
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: Assets,
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: Assets
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: Assets,
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: Assets,
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 createInstantLoansActor(canisterContext) {
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(idlFactory2, {
1520
- agent: canisterContext.agent,
1521
- canisterId
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 buildInstantLoanAddressLookupPath(request) {
1597
- const query = new URLSearchParams({ address: request.address });
1598
- return `${INSTANT_LOANS}/address?${query.toString()}`;
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 createInstantLoansActor(
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 idlFactory3 = ({ IDL }) => {
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(idlFactory3, {
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 idlFactory4 = ({ IDL }) => {
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(idlFactory4, {
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
- return await this.mapLoanWire(response.loan);
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
- try {
3688
- const result = await createInstantLoansActor(
3689
- this.canisterContext
3690
- ).get_loan(loanId);
3691
- if ("Err" in result) {
3692
- throw mapInstantLoansErrorToLiquidiumError(result.Err);
3693
- }
3694
- const collateralAmount = await this.getCollateralAmountHint(loanId);
3695
- return await this.mapLoanRecord(result.Ok, collateralAmount);
3696
- } catch (error) {
3697
- if (error instanceof LiquidiumError) {
3698
- throw error;
3699
- }
3700
- throw mapCanisterCallErrorToLiquidiumError("get_loan", error);
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 createInstantLoansActor(
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 createInstantLoansActor(
3885
+ const event = await createFlexibleInstantLoansActor(
3729
3886
  this.canisterContext
3730
3887
  ).get_event(eventId);
3731
- return event[0] ? mapInstantLoanEvent(event[0]) : null;
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 createInstantLoansActor(
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 createInstantLoansActor(
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 createInstantLoansActor(
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 createInstantLoansActor(
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
- * Finds candidate loans associated with an address through the Liquidium SDK
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
- buildInstantLoanAddressLookupPath({ address: trimmedAddress })
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: getVariantKey(record.lend_asset),
3833
- borrowAsset: getVariantKey(record.borrow_asset),
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 lookup");
4009
+ const apiClient = this.requireApi("Instant loan collateral hint");
3841
4010
  const response = await apiClient.get(
3842
4011
  buildInstantLoanCollateralHintPath({ loanId })
3843
4012
  );
3844
- return parseBigintWire(response.collateralAmountHint, "collateral amount");
3845
- }
3846
- async mapLoanWire(loan) {
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: assetFromCanister(event.lend_asset),
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: assetFromCanister(event.borrow_asset)
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 mapCandidateWire(wire) {
4259
- const loanId = parseBigintWire(wire.loanId ?? wire.loan_id, "loan ID");
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
- `Invalid instant loan ${label}`
4406
+ "Instant loan find query must be a string"
4297
4407
  );
4298
4408
  }
4299
- return BigInt(value);
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 requiredString(value, label) {
4302
- if (value?.trim()) return value;
4303
- throw new LiquidiumError(
4304
- LiquidiumErrorCode.VALIDATION_ERROR,
4305
- `Missing instant loan ${label}`
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 idlFactory5 = ({ IDL }) => IDL.Service({
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(idlFactory5, {
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 mapLendingPoolRecordToPool(pool, rate) {
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: getVariantKey(pool.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 lendingActor = createLendingActor(this.canisterContext);
5606
- const lendingPools = await lendingActor.list_pools();
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
- lendingPools.map(async (pool) => {
5609
- const poolRate = await lendingActor.get_pool_rate(pool.principal);
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 mapLendingPoolRecordToPool(pool, resolvedPoolRate);
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 mapPositionViewToPosition(view) {
5717
- const asset = getVariantKey(view.asset);
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 mapUserStatsRecordToUserStats(record) {
6089
+ function mapDecodedUserStatsToUserStats(stats) {
6090
+ return mapUserStatsLikeToUserStats(stats);
6091
+ }
6092
+ function mapUserStatsLikeToUserStats(stats) {
5739
6093
  return {
5740
- debt: record.debt,
6094
+ debt: stats.debt,
5741
6095
  debtDecimals: USD_VALUE_SCALE_DECIMALS,
5742
- collateral: record.collateral,
6096
+ collateral: stats.collateral,
5743
6097
  collateralDecimals: USD_VALUE_SCALE_DECIMALS,
5744
- weightedLiquidationThreshold: record.weighted_liquidation_threshold,
6098
+ weightedLiquidationThreshold: stats.weighted_liquidation_threshold,
5745
6099
  borrowingPower: mapBorrowingPowerRecordToBorrowingPower(
5746
- record.borrowing_power
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 createLendingActor(
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
- return mapPositionViewToPosition(view);
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 = createLendingActor(this.canisterContext);
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
- stats.positions.map(
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(mapPositionViewToPosition);
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 createLendingActor(
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: mapUserStatsRecordToUserStats(userStatsRecord)
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 createLendingActor(
6200
+ const result = await createFlexibleLendingActor(
5840
6201
  this.canisterContext
5841
6202
  ).get_profile_stats(principal.Principal.fromText(profileId));
5842
- return mapUserStatsRecordToUserStats(result);
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 + position.earnedInterest,
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) {