@liquidium/client 0.2.0 → 0.3.0
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 +58 -11
- package/dist/index.cjs +302 -143
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +235 -113
- package/dist/index.d.ts +235 -113
- package/dist/index.js +301 -144
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1593,9 +1593,9 @@ function buildActivityStatusPath(request) {
|
|
|
1593
1593
|
request.id
|
|
1594
1594
|
)}/status?${query.toString()}`;
|
|
1595
1595
|
}
|
|
1596
|
-
function
|
|
1597
|
-
const query = new URLSearchParams({
|
|
1598
|
-
return `${INSTANT_LOANS}/
|
|
1596
|
+
function buildInstantLoanFindPath(request) {
|
|
1597
|
+
const query = new URLSearchParams({ query: request.query });
|
|
1598
|
+
return `${INSTANT_LOANS}/find?${query.toString()}`;
|
|
1599
1599
|
}
|
|
1600
1600
|
function buildInstantLoanCollateralHintPath(request) {
|
|
1601
1601
|
return `${INSTANT_LOANS}/${encodeURIComponent(
|
|
@@ -2224,6 +2224,41 @@ function mapHistoryStatusToApi(status) {
|
|
|
2224
2224
|
return status.toUpperCase();
|
|
2225
2225
|
}
|
|
2226
2226
|
|
|
2227
|
+
// src/core/utils/api-response-parsers.ts
|
|
2228
|
+
var MILLISECONDS_PER_SECOND2 = 1e3;
|
|
2229
|
+
function parseNonEmptyApiString(value, field) {
|
|
2230
|
+
if (!value) {
|
|
2231
|
+
throwInvalidApiResponseField(field);
|
|
2232
|
+
}
|
|
2233
|
+
return value;
|
|
2234
|
+
}
|
|
2235
|
+
function parseUnsignedApiBigint(value, field) {
|
|
2236
|
+
if (!value || !/^\d+$/.test(value)) {
|
|
2237
|
+
throwInvalidApiResponseField(field);
|
|
2238
|
+
}
|
|
2239
|
+
return BigInt(value);
|
|
2240
|
+
}
|
|
2241
|
+
function parseIsoApiTimestampToUnixSeconds(value, field) {
|
|
2242
|
+
const timestamp = parseNonEmptyApiString(value, field);
|
|
2243
|
+
const timestampMilliseconds = Date.parse(timestamp);
|
|
2244
|
+
if (!Number.isFinite(timestampMilliseconds)) {
|
|
2245
|
+
throwInvalidApiResponseField(field);
|
|
2246
|
+
}
|
|
2247
|
+
return BigInt(Math.floor(timestampMilliseconds / MILLISECONDS_PER_SECOND2));
|
|
2248
|
+
}
|
|
2249
|
+
function parseApiStringUnion(value, allowedValues, field) {
|
|
2250
|
+
if (value !== void 0 && allowedValues.includes(value)) {
|
|
2251
|
+
return value;
|
|
2252
|
+
}
|
|
2253
|
+
throwInvalidApiResponseField(field);
|
|
2254
|
+
}
|
|
2255
|
+
function throwInvalidApiResponseField(field) {
|
|
2256
|
+
throw new LiquidiumError(
|
|
2257
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
2258
|
+
`Invalid ${field.context} ${field.label}`
|
|
2259
|
+
);
|
|
2260
|
+
}
|
|
2261
|
+
|
|
2227
2262
|
// src/core/utils/asset-decimals.ts
|
|
2228
2263
|
var ASSET_NATIVE_DECIMALS = {
|
|
2229
2264
|
BTC: 8n,
|
|
@@ -3107,6 +3142,39 @@ function assertSupportsIcrcAccountInflowTarget(asset) {
|
|
|
3107
3142
|
);
|
|
3108
3143
|
}
|
|
3109
3144
|
|
|
3145
|
+
// src/core/borrow-minimums.ts
|
|
3146
|
+
var MIN_BORROW_AMOUNTS_BY_ASSET = {
|
|
3147
|
+
BTC: 5100n,
|
|
3148
|
+
// 5,100 sats = 0.000051 BTC
|
|
3149
|
+
USDC: 1000000n,
|
|
3150
|
+
// 1 USDC
|
|
3151
|
+
USDT: 1000000n
|
|
3152
|
+
// 1 USDT
|
|
3153
|
+
};
|
|
3154
|
+
function getMinimumBorrowAmount(asset) {
|
|
3155
|
+
if (!isMinimumBorrowAsset(asset)) {
|
|
3156
|
+
return 0n;
|
|
3157
|
+
}
|
|
3158
|
+
return MIN_BORROW_AMOUNTS_BY_ASSET[asset];
|
|
3159
|
+
}
|
|
3160
|
+
function getBorrowAmountMinimumValidationError(params) {
|
|
3161
|
+
const minimumAmount = getMinimumBorrowAmount(params.asset);
|
|
3162
|
+
if (minimumAmount <= 0n || params.amount >= minimumAmount) {
|
|
3163
|
+
return null;
|
|
3164
|
+
}
|
|
3165
|
+
return {
|
|
3166
|
+
asset: params.asset,
|
|
3167
|
+
minimumAmount,
|
|
3168
|
+
message: formatMinimumBorrowAmountMessage(params.asset, minimumAmount)
|
|
3169
|
+
};
|
|
3170
|
+
}
|
|
3171
|
+
function formatMinimumBorrowAmountMessage(asset, minimumAmount) {
|
|
3172
|
+
return `Borrow amount must be at least ${minimumAmount} base units for ${asset}`;
|
|
3173
|
+
}
|
|
3174
|
+
function isMinimumBorrowAsset(asset) {
|
|
3175
|
+
return Object.hasOwn(MIN_BORROW_AMOUNTS_BY_ASSET, asset);
|
|
3176
|
+
}
|
|
3177
|
+
|
|
3110
3178
|
// src/modules/quote/types.ts
|
|
3111
3179
|
var QuoteValidationErrorCode = /* @__PURE__ */ ((QuoteValidationErrorCode2) => {
|
|
3112
3180
|
QuoteValidationErrorCode2["INVALID_LTV"] = "INVALID_LTV";
|
|
@@ -3129,7 +3197,6 @@ var BASIS_POINTS_DENOMINATOR = 10000n;
|
|
|
3129
3197
|
var BPS_PER_PERCENT = 100n;
|
|
3130
3198
|
var MIN_LTV_BPS = 0n;
|
|
3131
3199
|
var HIGH_LTV_WARNING_THRESHOLD_BPS = 8000n;
|
|
3132
|
-
var MIN_BORROW_AMOUNT_BASE_UNITS = 5000n;
|
|
3133
3200
|
var INTERNAL_USD_DECIMAL_PLACES = 8;
|
|
3134
3201
|
var PRICE_SCALE_DECIMAL_PLACES = 8;
|
|
3135
3202
|
var QuoteModule = class {
|
|
@@ -3187,11 +3254,12 @@ var QuoteModule = class {
|
|
|
3187
3254
|
message: `Price not available for collateral asset: ${collateralPool.asset}`
|
|
3188
3255
|
});
|
|
3189
3256
|
}
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3257
|
+
const borrowAmountError = createBorrowAmountValidationError({
|
|
3258
|
+
amount: request.borrowAmount,
|
|
3259
|
+
asset: borrowPool.asset
|
|
3260
|
+
});
|
|
3261
|
+
if (borrowAmountError) {
|
|
3262
|
+
validationErrors.push(borrowAmountError);
|
|
3195
3263
|
}
|
|
3196
3264
|
if (request.collateralAmount <= 0n) {
|
|
3197
3265
|
validationErrors.push({
|
|
@@ -3313,16 +3381,12 @@ var QuoteModule = class {
|
|
|
3313
3381
|
message: `Price not available for collateral asset: ${collateralAsset}`
|
|
3314
3382
|
});
|
|
3315
3383
|
}
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
validationErrors.push({
|
|
3323
|
-
code: "BORROW_AMOUNT_TOO_LOW" /* BORROW_AMOUNT_TOO_LOW */,
|
|
3324
|
-
message: `Borrow amount must be at least ${MIN_BORROW_AMOUNT_BASE_UNITS} base units`
|
|
3325
|
-
});
|
|
3384
|
+
const borrowAmountError = createBorrowAmountValidationError({
|
|
3385
|
+
amount: borrowAmount,
|
|
3386
|
+
asset: borrowAsset
|
|
3387
|
+
});
|
|
3388
|
+
if (borrowAmountError) {
|
|
3389
|
+
validationErrors.push(borrowAmountError);
|
|
3326
3390
|
}
|
|
3327
3391
|
if (targetLtvBps <= MIN_LTV_BPS) {
|
|
3328
3392
|
validationErrors.push({
|
|
@@ -3445,6 +3509,22 @@ function createQuoteResult(params) {
|
|
|
3445
3509
|
warnings: params.warnings
|
|
3446
3510
|
};
|
|
3447
3511
|
}
|
|
3512
|
+
function createBorrowAmountValidationError(params) {
|
|
3513
|
+
if (params.amount <= 0n) {
|
|
3514
|
+
return {
|
|
3515
|
+
code: "BORROW_AMOUNT_TOO_LOW" /* BORROW_AMOUNT_TOO_LOW */,
|
|
3516
|
+
message: "Borrow amount must be greater than 0"
|
|
3517
|
+
};
|
|
3518
|
+
}
|
|
3519
|
+
const minimumBorrowAmountError = getBorrowAmountMinimumValidationError(params);
|
|
3520
|
+
if (!minimumBorrowAmountError) {
|
|
3521
|
+
return null;
|
|
3522
|
+
}
|
|
3523
|
+
return {
|
|
3524
|
+
code: "BORROW_AMOUNT_TOO_LOW" /* BORROW_AMOUNT_TOO_LOW */,
|
|
3525
|
+
message: minimumBorrowAmountError.message
|
|
3526
|
+
};
|
|
3527
|
+
}
|
|
3448
3528
|
function computeUsdInternalFromBaseUnits(params) {
|
|
3449
3529
|
const { amountBaseUnits, priceScaled, assetDecimalPlaces } = params;
|
|
3450
3530
|
const scaleDiff = INTERNAL_USD_DECIMAL_PLACES - PRICE_SCALE_DECIMAL_PLACES;
|
|
@@ -3570,6 +3650,14 @@ var RATE_SCALE2 = 10n ** 27n;
|
|
|
3570
3650
|
var SECONDS_PER_YEAR = 31536000n;
|
|
3571
3651
|
var ETH_STABLECOIN_INFLOW_FEE_FALLBACK = 1500000n;
|
|
3572
3652
|
var INSTANT_LOAN_MIN_SLIPPAGE_BUFFER_BPS = 200n;
|
|
3653
|
+
var INSTANT_LOAN_FIND_QUERY_MAX_LENGTH = 256;
|
|
3654
|
+
var INSTANT_LOAN_WIRE_CONTEXT = "instant loan";
|
|
3655
|
+
var INSTANT_LOAN_ASSETS = [
|
|
3656
|
+
Asset.BTC,
|
|
3657
|
+
Asset.SOL,
|
|
3658
|
+
Asset.USDC,
|
|
3659
|
+
Asset.USDT
|
|
3660
|
+
];
|
|
3573
3661
|
var InstantLoansModule = class {
|
|
3574
3662
|
constructor(canisterContext, apiClient, lending, positions) {
|
|
3575
3663
|
this.canisterContext = canisterContext;
|
|
@@ -3626,7 +3714,19 @@ var InstantLoansModule = class {
|
|
|
3626
3714
|
borrowDestination,
|
|
3627
3715
|
refundDestination
|
|
3628
3716
|
});
|
|
3629
|
-
|
|
3717
|
+
const loanId = parseUnsignedApiBigint(response.loan.loanId, {
|
|
3718
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
3719
|
+
label: "loan ID"
|
|
3720
|
+
});
|
|
3721
|
+
const collateralAmount = parseUnsignedApiBigint(
|
|
3722
|
+
response.loan.collateral.amountHint,
|
|
3723
|
+
{
|
|
3724
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
3725
|
+
label: "collateral amount"
|
|
3726
|
+
}
|
|
3727
|
+
);
|
|
3728
|
+
const record = await this.getLoanRecord(loanId);
|
|
3729
|
+
return await this.mapLoanRecord(record, collateralAmount);
|
|
3630
3730
|
}
|
|
3631
3731
|
/**
|
|
3632
3732
|
* Resolves canonical canister state by loan id or short reference.
|
|
@@ -3639,21 +3739,30 @@ var InstantLoansModule = class {
|
|
|
3639
3739
|
*/
|
|
3640
3740
|
async get(request) {
|
|
3641
3741
|
const loanId = "loanId" in request ? request.loanId : decodeRef(request.ref);
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3742
|
+
const record = await this.getLoanRecord(loanId);
|
|
3743
|
+
const collateralAmount = await this.getCollateralAmountHint(loanId);
|
|
3744
|
+
return await this.mapLoanRecord(record, collateralAmount);
|
|
3745
|
+
}
|
|
3746
|
+
/**
|
|
3747
|
+
* Finds instant loans by short reference, numeric loan id string, address, or transaction id.
|
|
3748
|
+
*
|
|
3749
|
+
* Search returns lightweight matches. Call `get({ loanId })` or `get({ ref })`
|
|
3750
|
+
* when the user selects a match and you need hydrated loan state.
|
|
3751
|
+
*
|
|
3752
|
+
* @param query - Short reference, address, transaction id/hash, or numeric loan id string.
|
|
3753
|
+
* @returns Matching loan ids and references from the search index.
|
|
3754
|
+
*/
|
|
3755
|
+
async find(query) {
|
|
3756
|
+
const validatedQuery = validateInstantLoanFindQuery(query);
|
|
3757
|
+
const candidates = await this.findCandidateLoansByQuery(validatedQuery);
|
|
3758
|
+
return uniqueInstantLoanFindCandidates(candidates).map((candidate) => ({
|
|
3759
|
+
loanId: candidate.loanId,
|
|
3760
|
+
ref: candidate.ref,
|
|
3761
|
+
createdAt: candidate.createdAt,
|
|
3762
|
+
collateral: candidate.collateral,
|
|
3763
|
+
borrow: candidate.borrow,
|
|
3764
|
+
profileId: candidate.profileId
|
|
3765
|
+
}));
|
|
3657
3766
|
}
|
|
3658
3767
|
/**
|
|
3659
3768
|
* Returns the active instant-loans canister config via direct query.
|
|
@@ -3751,28 +3860,29 @@ var InstantLoansModule = class {
|
|
|
3751
3860
|
throw mapCanisterCallErrorToLiquidiumError("list_warmed_profiles", error);
|
|
3752
3861
|
}
|
|
3753
3862
|
}
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
* refund address but not the loan reference.
|
|
3760
|
-
*
|
|
3761
|
-
* @param address - Borrow or refund address to search for.
|
|
3762
|
-
* @returns Lightweight loan candidates associated with the address.
|
|
3763
|
-
*/
|
|
3764
|
-
async findByAddress(address) {
|
|
3765
|
-
const trimmedAddress = address.trim();
|
|
3766
|
-
if (!trimmedAddress) {
|
|
3767
|
-
throw new LiquidiumError(
|
|
3768
|
-
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
3769
|
-
"Address lookup requires a non-empty address"
|
|
3770
|
-
);
|
|
3771
|
-
}
|
|
3772
|
-
const apiClient = this.requireApi("Instant loan address lookup");
|
|
3773
|
-
const response = await apiClient.get(buildInstantLoanAddressLookupPath({ address: trimmedAddress }));
|
|
3863
|
+
async findCandidateLoansByQuery(query) {
|
|
3864
|
+
const apiClient = this.requireApi("Instant loan find");
|
|
3865
|
+
const response = await apiClient.get(
|
|
3866
|
+
buildInstantLoanFindPath({ query })
|
|
3867
|
+
);
|
|
3774
3868
|
return (response.candidates ?? response.loans ?? []).map(mapCandidateWire);
|
|
3775
3869
|
}
|
|
3870
|
+
async getLoanRecord(loanId) {
|
|
3871
|
+
try {
|
|
3872
|
+
const result = await createInstantLoansActor(
|
|
3873
|
+
this.canisterContext
|
|
3874
|
+
).get_loan(loanId);
|
|
3875
|
+
if ("Err" in result) {
|
|
3876
|
+
throw mapInstantLoansErrorToLiquidiumError(result.Err);
|
|
3877
|
+
}
|
|
3878
|
+
return result.Ok;
|
|
3879
|
+
} catch (error) {
|
|
3880
|
+
if (error instanceof LiquidiumError) {
|
|
3881
|
+
throw error;
|
|
3882
|
+
}
|
|
3883
|
+
throw mapCanisterCallErrorToLiquidiumError("get_loan", error);
|
|
3884
|
+
}
|
|
3885
|
+
}
|
|
3776
3886
|
async mapLoanRecord(record, collateralAmount) {
|
|
3777
3887
|
return await this.hydrateLoan({
|
|
3778
3888
|
loanId: record.id,
|
|
@@ -3786,35 +3896,22 @@ var InstantLoansModule = class {
|
|
|
3786
3896
|
borrowAsset: getVariantKey(record.borrow_asset),
|
|
3787
3897
|
borrowAmount: record.borrow_amount,
|
|
3788
3898
|
borrowDestination: accountFromCanister(record.borrow_destination),
|
|
3789
|
-
refundDestination: accountFromCanister(record.refund_destination)
|
|
3899
|
+
refundDestination: accountFromCanister(record.refund_destination),
|
|
3900
|
+
depositDetectedTimestamp: record.deposit_detected_ts[0] ?? null,
|
|
3901
|
+
expiryTimestamp: record.expires_at[0] ?? deriveDepositExpiryTimestamp({
|
|
3902
|
+
depositDetectedTimestamp: record.deposit_detected_ts[0] ?? null,
|
|
3903
|
+
depositWindowSeconds: record.ltv_timer_s
|
|
3904
|
+
})
|
|
3790
3905
|
});
|
|
3791
3906
|
}
|
|
3792
3907
|
async getCollateralAmountHint(loanId) {
|
|
3793
|
-
const apiClient = this.requireApi("Instant loan
|
|
3794
|
-
const response = await apiClient.get(
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
loanId,
|
|
3801
|
-
profileId: loan.profileId,
|
|
3802
|
-
ltvMaxBps: parseBigintWire(loan.ltvMaxBps, "max LTV"),
|
|
3803
|
-
depositWindowSeconds: parseBigintWire(
|
|
3804
|
-
loan.depositWindowSeconds,
|
|
3805
|
-
"deposit window"
|
|
3806
|
-
),
|
|
3807
|
-
collateralPoolId: loan.collateral.poolId,
|
|
3808
|
-
collateralAmount: parseBigintWire(
|
|
3809
|
-
loan.collateral.amountHint,
|
|
3810
|
-
"collateral amount"
|
|
3811
|
-
),
|
|
3812
|
-
borrowPoolId: loan.borrow.poolId,
|
|
3813
|
-
collateralAsset: loan.collateral.asset,
|
|
3814
|
-
borrowAsset: loan.borrow.asset,
|
|
3815
|
-
borrowAmount: parseBigintWire(loan.borrow.amount, "borrow amount"),
|
|
3816
|
-
borrowDestination: accountFromWire(loan.borrow.destination),
|
|
3817
|
-
refundDestination: accountFromWire(loan.refundDestination)
|
|
3908
|
+
const apiClient = this.requireApi("Instant loan collateral hint");
|
|
3909
|
+
const response = await apiClient.get(
|
|
3910
|
+
buildInstantLoanCollateralHintPath({ loanId })
|
|
3911
|
+
);
|
|
3912
|
+
return parseUnsignedApiBigint(response.collateralAmountHint, {
|
|
3913
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
3914
|
+
label: "collateral amount"
|
|
3818
3915
|
});
|
|
3819
3916
|
}
|
|
3820
3917
|
async hydrateLoan(input) {
|
|
@@ -3868,7 +3965,9 @@ var InstantLoansModule = class {
|
|
|
3868
3965
|
collateralAmount,
|
|
3869
3966
|
decimals: collateralDecimals,
|
|
3870
3967
|
asset: collateralAsset,
|
|
3871
|
-
target: depositTarget
|
|
3968
|
+
target: depositTarget,
|
|
3969
|
+
detectedTimestamp: input.depositDetectedTimestamp,
|
|
3970
|
+
expiryTimestamp: input.expiryTimestamp
|
|
3872
3971
|
});
|
|
3873
3972
|
const repayment = {
|
|
3874
3973
|
amount: repaymentAmount,
|
|
@@ -3932,7 +4031,9 @@ var InstantLoansModule = class {
|
|
|
3932
4031
|
inflowFeeAmount: inflowFee.totalFee,
|
|
3933
4032
|
asset: input.asset,
|
|
3934
4033
|
chain: input.target.chain,
|
|
3935
|
-
target: input.target
|
|
4034
|
+
target: input.target,
|
|
4035
|
+
detectedTimestamp: input.detectedTimestamp,
|
|
4036
|
+
expiryTimestamp: input.expiryTimestamp
|
|
3936
4037
|
};
|
|
3937
4038
|
}
|
|
3938
4039
|
async estimateRepaymentInflowFee(asset, chain) {
|
|
@@ -4028,6 +4129,12 @@ function deriveInstantLoanStatus(input) {
|
|
|
4028
4129
|
}
|
|
4029
4130
|
return InstantLoanStatus.awaitingDeposit;
|
|
4030
4131
|
}
|
|
4132
|
+
function deriveDepositExpiryTimestamp(input) {
|
|
4133
|
+
if (input.depositDetectedTimestamp === null) {
|
|
4134
|
+
return null;
|
|
4135
|
+
}
|
|
4136
|
+
return input.depositDetectedTimestamp + input.depositWindowSeconds;
|
|
4137
|
+
}
|
|
4031
4138
|
function validateCreateRequest(request) {
|
|
4032
4139
|
if (request.collateralAmount <= 0n) {
|
|
4033
4140
|
throw new LiquidiumError(
|
|
@@ -4076,18 +4183,6 @@ function accountFromCanister(account) {
|
|
|
4076
4183
|
}
|
|
4077
4184
|
return { type: "External", address: account.External };
|
|
4078
4185
|
}
|
|
4079
|
-
function accountFromWire(account) {
|
|
4080
|
-
if ("Native" in account) {
|
|
4081
|
-
return { type: "Native", principal: account.Native };
|
|
4082
|
-
}
|
|
4083
|
-
if ("External" in account) {
|
|
4084
|
-
return { type: "External", address: account.External };
|
|
4085
|
-
}
|
|
4086
|
-
if (account.type === "Native") {
|
|
4087
|
-
return { type: "Native", principal: account.principal };
|
|
4088
|
-
}
|
|
4089
|
-
return { type: "External", address: account.address };
|
|
4090
|
-
}
|
|
4091
4186
|
function mapInstantLoanEvent(event) {
|
|
4092
4187
|
return {
|
|
4093
4188
|
id: event.id,
|
|
@@ -4206,55 +4301,80 @@ function decodeRef(ref) {
|
|
|
4206
4301
|
);
|
|
4207
4302
|
}
|
|
4208
4303
|
}
|
|
4209
|
-
function
|
|
4210
|
-
|
|
4211
|
-
const ref = wire.ref ?? wire.short_ref ?? publicIdFromInt(loanId);
|
|
4212
|
-
const createdAt = wire.createdAt ?? wire.created_at;
|
|
4213
|
-
return {
|
|
4214
|
-
loanId,
|
|
4215
|
-
ref,
|
|
4216
|
-
profileId: requiredString(
|
|
4217
|
-
wire.profileId ?? wire.lending_profile,
|
|
4218
|
-
"profile ID"
|
|
4219
|
-
),
|
|
4220
|
-
...createdAt ? { createdAt: new Date(createdAt) } : {},
|
|
4221
|
-
collateralPoolId: requiredString(
|
|
4222
|
-
wire.collateralPoolId ?? wire.lend_pool_ic_id,
|
|
4223
|
-
"collateral pool ID"
|
|
4224
|
-
),
|
|
4225
|
-
borrowPoolId: requiredString(
|
|
4226
|
-
wire.borrowPoolId ?? wire.borrow_pool_ic_id,
|
|
4227
|
-
"borrow pool ID"
|
|
4228
|
-
),
|
|
4229
|
-
collateralAsset: requiredString(
|
|
4230
|
-
wire.collateralAsset ?? wire.lend_asset,
|
|
4231
|
-
"collateral asset"
|
|
4232
|
-
),
|
|
4233
|
-
borrowAsset: requiredString(
|
|
4234
|
-
wire.borrowAsset ?? wire.borrow_asset,
|
|
4235
|
-
"borrow asset"
|
|
4236
|
-
),
|
|
4237
|
-
collateralAmount: parseBigintWire(
|
|
4238
|
-
wire.collateralAmount,
|
|
4239
|
-
"collateral amount"
|
|
4240
|
-
)
|
|
4241
|
-
};
|
|
4242
|
-
}
|
|
4243
|
-
function parseBigintWire(value, label) {
|
|
4244
|
-
if (!value || !/^\d+$/.test(value)) {
|
|
4304
|
+
function validateInstantLoanFindQuery(query) {
|
|
4305
|
+
if (typeof query !== "string") {
|
|
4245
4306
|
throw new LiquidiumError(
|
|
4246
4307
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
4247
|
-
|
|
4308
|
+
"Instant loan find query must be a string"
|
|
4248
4309
|
);
|
|
4249
4310
|
}
|
|
4250
|
-
|
|
4311
|
+
const trimmedQuery = query.trim();
|
|
4312
|
+
if (!trimmedQuery) {
|
|
4313
|
+
throw new LiquidiumError(
|
|
4314
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
4315
|
+
"Instant loan find query must be non-empty"
|
|
4316
|
+
);
|
|
4317
|
+
}
|
|
4318
|
+
if (trimmedQuery.length > INSTANT_LOAN_FIND_QUERY_MAX_LENGTH) {
|
|
4319
|
+
throw new LiquidiumError(
|
|
4320
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
4321
|
+
`Instant loan find query must be at most ${INSTANT_LOAN_FIND_QUERY_MAX_LENGTH.toString()} characters`
|
|
4322
|
+
);
|
|
4323
|
+
}
|
|
4324
|
+
return trimmedQuery;
|
|
4251
4325
|
}
|
|
4252
|
-
function
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4326
|
+
function uniqueInstantLoanFindCandidates(candidates) {
|
|
4327
|
+
const candidatesByLoanId = /* @__PURE__ */ new Map();
|
|
4328
|
+
for (const candidate of candidates) {
|
|
4329
|
+
if (!candidatesByLoanId.has(candidate.loanId)) {
|
|
4330
|
+
candidatesByLoanId.set(candidate.loanId, candidate);
|
|
4331
|
+
}
|
|
4332
|
+
}
|
|
4333
|
+
return [...candidatesByLoanId.values()];
|
|
4334
|
+
}
|
|
4335
|
+
function mapCandidateWire(wire) {
|
|
4336
|
+
return {
|
|
4337
|
+
loanId: parseUnsignedApiBigint(wire.loan_id, {
|
|
4338
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
4339
|
+
label: "loan ID"
|
|
4340
|
+
}),
|
|
4341
|
+
ref: parseNonEmptyApiString(wire.short_ref, {
|
|
4342
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
4343
|
+
label: "short reference"
|
|
4344
|
+
}),
|
|
4345
|
+
createdAt: parseIsoApiTimestampToUnixSeconds(wire.created_at, {
|
|
4346
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
4347
|
+
label: "creation timestamp"
|
|
4348
|
+
}),
|
|
4349
|
+
collateral: {
|
|
4350
|
+
poolId: parseNonEmptyApiString(wire.lend_pool_ic_id, {
|
|
4351
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
4352
|
+
label: "lend pool ID"
|
|
4353
|
+
}),
|
|
4354
|
+
asset: parseApiStringUnion(wire.lend_asset, INSTANT_LOAN_ASSETS, {
|
|
4355
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
4356
|
+
label: "lend asset"
|
|
4357
|
+
}),
|
|
4358
|
+
amount: parseUnsignedApiBigint(wire.collateral_amount, {
|
|
4359
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
4360
|
+
label: "collateral amount"
|
|
4361
|
+
})
|
|
4362
|
+
},
|
|
4363
|
+
borrow: {
|
|
4364
|
+
poolId: parseNonEmptyApiString(wire.borrow_pool_ic_id, {
|
|
4365
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
4366
|
+
label: "borrow pool ID"
|
|
4367
|
+
}),
|
|
4368
|
+
asset: parseApiStringUnion(wire.borrow_asset, INSTANT_LOAN_ASSETS, {
|
|
4369
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
4370
|
+
label: "borrow asset"
|
|
4371
|
+
})
|
|
4372
|
+
},
|
|
4373
|
+
profileId: parseNonEmptyApiString(wire.profile, {
|
|
4374
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
4375
|
+
label: "profile ID"
|
|
4376
|
+
})
|
|
4377
|
+
};
|
|
4258
4378
|
}
|
|
4259
4379
|
function mapInstantLoansErrorToLiquidiumError(error) {
|
|
4260
4380
|
const [key, payload] = Object.entries(error)[0];
|
|
@@ -4715,9 +4835,28 @@ var LendingModule = class {
|
|
|
4715
4835
|
"Borrow requires a signer account"
|
|
4716
4836
|
);
|
|
4717
4837
|
}
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4838
|
+
if (request.amount <= 0n) {
|
|
4839
|
+
throw new LiquidiumError(
|
|
4840
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
4841
|
+
"Borrow amount must be greater than 0"
|
|
4842
|
+
);
|
|
4843
|
+
}
|
|
4844
|
+
const selectedPool = await this.getPoolById(request.poolId);
|
|
4845
|
+
const selectedAsset = getVariantKey(selectedPool.asset);
|
|
4846
|
+
const minimumBorrowAmountError = getBorrowAmountMinimumValidationError({
|
|
4847
|
+
amount: request.amount,
|
|
4848
|
+
asset: selectedAsset
|
|
4849
|
+
});
|
|
4850
|
+
if (minimumBorrowAmountError) {
|
|
4851
|
+
throw new LiquidiumError(
|
|
4852
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
4853
|
+
minimumBorrowAmountError.message
|
|
4854
|
+
);
|
|
4855
|
+
}
|
|
4856
|
+
const receiverAddress = normalizeExternalAddress({
|
|
4857
|
+
address: destinationAccount,
|
|
4858
|
+
asset: selectedAsset,
|
|
4859
|
+
chain: getVariantKey(selectedPool.chain)
|
|
4721
4860
|
});
|
|
4722
4861
|
const lendingActor = createLendingActor(this.canisterContext);
|
|
4723
4862
|
try {
|
|
@@ -5840,7 +5979,7 @@ var PositionsModule = class {
|
|
|
5840
5979
|
pool,
|
|
5841
5980
|
priceUsd,
|
|
5842
5981
|
suppliedUsd: nativeAmountToUsdScaled(
|
|
5843
|
-
position.deposited
|
|
5982
|
+
position.deposited,
|
|
5844
5983
|
position.depositedDecimals,
|
|
5845
5984
|
priceUsd
|
|
5846
5985
|
),
|
|
@@ -5875,6 +6014,24 @@ var PositionsModule = class {
|
|
|
5875
6014
|
const buffered = rawDebt * (BPS_SCALE + bufferBps) / BPS_SCALE;
|
|
5876
6015
|
return { amount: buffered, decimals: position.borrowedDecimals };
|
|
5877
6016
|
}
|
|
6017
|
+
/**
|
|
6018
|
+
* Returns the current full withdraw amount for a position.
|
|
6019
|
+
*
|
|
6020
|
+
* `Position.deposited` already reflects the current supplied balance at the
|
|
6021
|
+
* latest lending index; do not add `earnedInterest` to this amount.
|
|
6022
|
+
* Pass `amount` to withdraw calls and use `decimals` for display formatting.
|
|
6023
|
+
*
|
|
6024
|
+
* @param profileId - The Liquidium profile principal text.
|
|
6025
|
+
* @param poolId - The pool principal text.
|
|
6026
|
+
* @returns Full withdraw amount in the supplied asset's base units.
|
|
6027
|
+
*/
|
|
6028
|
+
async getFullWithdrawAmount(profileId, poolId) {
|
|
6029
|
+
const position = await this.getPosition(profileId, poolId);
|
|
6030
|
+
if (!position) {
|
|
6031
|
+
return { amount: 0n, decimals: 0n };
|
|
6032
|
+
}
|
|
6033
|
+
return { amount: position.deposited, decimals: position.depositedDecimals };
|
|
6034
|
+
}
|
|
5878
6035
|
};
|
|
5879
6036
|
function nativeAmountToUsdScaled(amount, nativeDecimals, priceUsd) {
|
|
5880
6037
|
if (amount <= 0n || priceUsd <= 0) {
|
|
@@ -5985,6 +6142,7 @@ exports.LendingModule = LendingModule;
|
|
|
5985
6142
|
exports.LiquidiumClient = LiquidiumClient;
|
|
5986
6143
|
exports.LiquidiumError = LiquidiumError;
|
|
5987
6144
|
exports.LiquidiumErrorCode = LiquidiumErrorCode;
|
|
6145
|
+
exports.MIN_BORROW_AMOUNTS_BY_ASSET = MIN_BORROW_AMOUNTS_BY_ASSET;
|
|
5988
6146
|
exports.MarketModule = MarketModule;
|
|
5989
6147
|
exports.OutflowType = OutflowType;
|
|
5990
6148
|
exports.PositionsModule = PositionsModule;
|
|
@@ -6002,6 +6160,7 @@ exports.UserHistoryStatus = UserHistoryStatus;
|
|
|
6002
6160
|
exports.WalletExecutionKind = WalletExecutionKind;
|
|
6003
6161
|
exports.createTransferErc20Transaction = createTransferErc20Transaction;
|
|
6004
6162
|
exports.executeWith = executeWith;
|
|
6163
|
+
exports.getMinimumBorrowAmount = getMinimumBorrowAmount;
|
|
6005
6164
|
exports.intFromPublicId = intFromPublicId;
|
|
6006
6165
|
exports.publicIdFromInt = publicIdFromInt;
|
|
6007
6166
|
//# sourceMappingURL=index.cjs.map
|