@liquidium/client 0.5.0 → 0.6.0-rc.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/dist/index.js CHANGED
@@ -5,8 +5,8 @@ import { Principal } from '@icp-sdk/core/principal';
5
5
  import { base64, base64nopad } from '@scure/base';
6
6
  import { idlLabelToId } from '@icp-sdk/core/candid';
7
7
  import { decodeIcrcAccount, encodeIcrcAccount } from '@icp-sdk/canisters/ledger/icrc';
8
- import { AccountIdentifier, SubAccount } from '@icp-sdk/canisters/ledger/icp';
9
8
  import { validate, Network } from 'bitcoin-address-validation';
9
+ import { AccountIdentifier, SubAccount } from '@icp-sdk/canisters/ledger/icp';
10
10
 
11
11
  // src/client.ts
12
12
 
@@ -86,6 +86,7 @@ var Environment = {
86
86
  };
87
87
  var Asset = {
88
88
  BTC: "BTC",
89
+ ETH: "ETH",
89
90
  ICP: "ICP",
90
91
  USDC: "USDC",
91
92
  USDT: "USDT"
@@ -100,9 +101,9 @@ function isAssetIdentifier(identifier) {
100
101
  case Chain.BTC:
101
102
  return identifier.asset === Asset.BTC;
102
103
  case Chain.ETH:
103
- return identifier.asset === Asset.USDC || identifier.asset === Asset.USDT;
104
+ return identifier.asset === Asset.ETH || identifier.asset === Asset.USDC || identifier.asset === Asset.USDT;
104
105
  case Chain.ICP:
105
- return identifier.asset === Asset.BTC || identifier.asset === Asset.ICP || identifier.asset === Asset.USDC || identifier.asset === Asset.USDT;
106
+ return identifier.asset === Asset.BTC || identifier.asset === Asset.ETH || identifier.asset === Asset.ICP || identifier.asset === Asset.USDC || identifier.asset === Asset.USDT;
106
107
  default:
107
108
  return false;
108
109
  }
@@ -125,6 +126,7 @@ var MAINNET_CANISTER_IDS = {
125
126
  lending: "hyk4r-jqaaa-aaaar-qb4ca-cai",
126
127
  pools: {
127
128
  btc: "hkmli-faaaa-aaaar-qb4ba-cai",
129
+ eth: "qcg7y-syaaa-aaaar-qb75q-cai",
128
130
  usdt: "hnnn4-iyaaa-aaaar-qb4bq-cai",
129
131
  usdc: "6sna2-oiaaa-aaaar-qb66q-cai",
130
132
  icp: "r2pk3-4yaaa-aaaar-qb7zq-cai"
@@ -143,6 +145,7 @@ var SUPPORTED_CANISTER_ID_OVERRIDE_KEYS = /* @__PURE__ */ new Set([
143
145
  ]);
144
146
  var SUPPORTED_POOL_CANISTER_ID_OVERRIDE_KEYS = /* @__PURE__ */ new Set([
145
147
  "btc",
148
+ "eth",
146
149
  "usdt",
147
150
  "usdc",
148
151
  "icp"
@@ -193,6 +196,8 @@ var CK_CANISTER_IDS = {
193
196
  BTC: {
194
197
  minter: "mqygn-kiaaa-aaaar-qaadq-cai",
195
198
  ledger: "mxzaz-hqaaa-aaaar-qaada-cai"},
199
+ ETH: {
200
+ ledger: "ss2fx-dyaaa-aaaar-qacoq-cai"},
196
201
  USDT: {
197
202
  ledger: "cngnf-vqaaa-aaaar-qag4q-cai"},
198
203
  USDC: {
@@ -431,6 +436,7 @@ var idlFactory = ({ IDL }) => {
431
436
  });
432
437
  const Assets = IDL.Variant({
433
438
  "BTC": IDL.Null,
439
+ "ETH": IDL.Null,
434
440
  "ICP": IDL.Null,
435
441
  "SOL": IDL.Null,
436
442
  "USDC": IDL.Null,
@@ -1014,6 +1020,16 @@ var ERC20_ABI = [
1014
1020
  }
1015
1021
  ];
1016
1022
  var CK_DEPOSIT_ABI = [
1023
+ {
1024
+ inputs: [
1025
+ { internalType: "bytes32", name: "principal", type: "bytes32" },
1026
+ { internalType: "bytes32", name: "subaccount", type: "bytes32" }
1027
+ ],
1028
+ name: "depositEth",
1029
+ outputs: [],
1030
+ stateMutability: "payable",
1031
+ type: "function"
1032
+ },
1017
1033
  {
1018
1034
  inputs: [
1019
1035
  { internalType: "address", name: "erc20Address", type: "address" },
@@ -1397,7 +1413,7 @@ function mapCanisterWalletToWallet(canisterWallet) {
1397
1413
  );
1398
1414
  }
1399
1415
  }
1400
- var KNOWN_ASSET_TAGS = ["BTC", "ICP", "USDC", "USDT"];
1416
+ var KNOWN_ASSET_TAGS = ["BTC", "ETH", "ICP", "USDC", "USDT"];
1401
1417
  var KNOWN_CHAIN_TAGS = ["BTC", "ETH", "ICP"];
1402
1418
  function extractVariantTag(variant, knownTags) {
1403
1419
  const [key] = Object.keys(variant);
@@ -2223,28 +2239,7 @@ function createTransferErc20Transaction(params) {
2223
2239
  };
2224
2240
  }
2225
2241
  function createDepositErc20Transaction(params) {
2226
- const expectedDestinationAccount = encodeIcrcAccount({
2227
- owner: Principal.fromText(params.poolId),
2228
- subaccount: encodeInflowSubaccount({
2229
- action: params.action,
2230
- principal: Principal.fromText(params.profileId)
2231
- })
2232
- });
2233
- if (params.destinationAccount !== expectedDestinationAccount) {
2234
- throw new LiquidiumError(
2235
- LiquidiumErrorCode.VALIDATION_ERROR,
2236
- "ETH supply destination account does not match the expected inflow account"
2237
- );
2238
- }
2239
- const principalBytes32 = encodePrincipalToBytes32(
2240
- Principal.fromText(params.poolId)
2241
- );
2242
- const subaccountHex = encodeBytes32Hex(
2243
- encodeInflowSubaccount({
2244
- action: params.action,
2245
- principal: Principal.fromText(params.profileId)
2246
- })
2247
- );
2242
+ const { principalBytes32, subaccountHex } = createDepositAccountContext(params);
2248
2243
  return {
2249
2244
  to: params.depositContractAddress,
2250
2245
  data: encodeFunctionData({
@@ -2259,6 +2254,40 @@ function createDepositErc20Transaction(params) {
2259
2254
  })
2260
2255
  };
2261
2256
  }
2257
+ function createDepositEthTransaction(params) {
2258
+ const { principalBytes32, subaccountHex } = createDepositAccountContext(params);
2259
+ return {
2260
+ to: params.depositContractAddress,
2261
+ data: encodeFunctionData({
2262
+ abi: CK_DEPOSIT_ABI,
2263
+ functionName: "depositEth",
2264
+ args: [principalBytes32, subaccountHex]
2265
+ }),
2266
+ value: params.amount.toString()
2267
+ };
2268
+ }
2269
+ function createDepositAccountContext(params) {
2270
+ const inflowSubaccount = encodeInflowSubaccount({
2271
+ action: params.action,
2272
+ principal: Principal.fromText(params.profileId)
2273
+ });
2274
+ const expectedDestinationAccount = encodeIcrcAccount({
2275
+ owner: Principal.fromText(params.poolId),
2276
+ subaccount: inflowSubaccount
2277
+ });
2278
+ if (params.destinationAccount !== expectedDestinationAccount) {
2279
+ throw new LiquidiumError(
2280
+ LiquidiumErrorCode.VALIDATION_ERROR,
2281
+ "ETH supply destination account does not match the expected inflow account"
2282
+ );
2283
+ }
2284
+ return {
2285
+ principalBytes32: encodePrincipalToBytes32(
2286
+ Principal.fromText(params.poolId)
2287
+ ),
2288
+ subaccountHex: encodeBytes32Hex(inflowSubaccount)
2289
+ };
2290
+ }
2262
2291
  function encodePrincipalToBytes32(principal) {
2263
2292
  const principalBytes = principal.toUint8Array();
2264
2293
  if (principalBytes.length > 29) {
@@ -2278,12 +2307,59 @@ function encodeBytes32Hex(bytes) {
2278
2307
  (byte) => byte.toString(16).padStart(2, "0")
2279
2308
  ).join("")}`;
2280
2309
  }
2310
+ var BTC_MAINNET_ADDRESS_ERROR = "Address must be a valid mainnet BTC address";
2311
+ var EVM_ADDRESS_ERROR = "Address must be a valid EVM address";
2312
+ var ADDRESS_CHAIN_MISMATCH_ERROR = "Address chain must match asset";
2313
+ function normalizeExternalAddress(params) {
2314
+ if (params.asset === Asset.BTC) {
2315
+ if (params.chain !== Chain.BTC) {
2316
+ throw new LiquidiumError(
2317
+ LiquidiumErrorCode.INVALID_ADDRESS,
2318
+ ADDRESS_CHAIN_MISMATCH_ERROR
2319
+ );
2320
+ }
2321
+ if (!validate(params.address, Network.mainnet)) {
2322
+ throw new LiquidiumError(
2323
+ LiquidiumErrorCode.INVALID_ADDRESS,
2324
+ BTC_MAINNET_ADDRESS_ERROR
2325
+ );
2326
+ }
2327
+ return params.address;
2328
+ }
2329
+ if (isEvmAsset(params.asset)) {
2330
+ if (params.chain !== Chain.ETH) {
2331
+ throw new LiquidiumError(
2332
+ LiquidiumErrorCode.INVALID_ADDRESS,
2333
+ ADDRESS_CHAIN_MISMATCH_ERROR
2334
+ );
2335
+ }
2336
+ if (!isAddress(params.address)) {
2337
+ throw new LiquidiumError(
2338
+ LiquidiumErrorCode.INVALID_ADDRESS,
2339
+ EVM_ADDRESS_ERROR
2340
+ );
2341
+ }
2342
+ return getAddress(params.address);
2343
+ }
2344
+ return params.address;
2345
+ }
2346
+ function normalizeAndValidateEvmAddress(address, errorMessage) {
2347
+ if (!isAddress(address)) {
2348
+ throw new LiquidiumError(LiquidiumErrorCode.INVALID_ADDRESS, errorMessage);
2349
+ }
2350
+ return getAddress(address);
2351
+ }
2352
+ function isEvmAsset(asset) {
2353
+ return asset === Asset.ETH || asset === Asset.USDC || asset === Asset.USDT;
2354
+ }
2281
2355
 
2282
2356
  // src/core/borrow-minimums.ts
2283
2357
  var MINIMUM_BTC_BORROW_AMOUNT_SATS = 5100n;
2358
+ var MINIMUM_ETH_BORROW_AMOUNT_WEI = 5000000000000000n;
2284
2359
  var MINIMUM_STABLECOIN_BORROW_AMOUNT_BASE_UNITS = 1000000n;
2285
2360
  var MIN_BORROW_AMOUNTS_BY_ASSET = {
2286
2361
  [Asset.BTC]: MINIMUM_BTC_BORROW_AMOUNT_SATS,
2362
+ [Asset.ETH]: MINIMUM_ETH_BORROW_AMOUNT_WEI,
2287
2363
  [Asset.USDC]: MINIMUM_STABLECOIN_BORROW_AMOUNT_BASE_UNITS,
2288
2364
  [Asset.USDT]: MINIMUM_STABLECOIN_BORROW_AMOUNT_BASE_UNITS
2289
2365
  };
@@ -3177,6 +3253,13 @@ function getPoolLedgerAssetRoute(params) {
3177
3253
  chain: params.chain
3178
3254
  };
3179
3255
  }
3256
+ if (params.asset === Asset.ETH && (params.chain === Chain.ETH || params.chain === Chain.ICP)) {
3257
+ return {
3258
+ ledgerCanisterId: CK_CANISTER_IDS.ETH.ledger,
3259
+ asset: Asset.ETH,
3260
+ chain: params.chain
3261
+ };
3262
+ }
3180
3263
  if (params.asset === Asset.USDT && (params.chain === Chain.ETH || params.chain === Chain.ICP)) {
3181
3264
  return {
3182
3265
  ledgerCanisterId: CK_CANISTER_IDS.USDT.ledger,
@@ -3251,9 +3334,11 @@ function createLiquidiumStatus(params) {
3251
3334
 
3252
3335
  // src/core/withdraw-minimums.ts
3253
3336
  var MINIMUM_BTC_WITHDRAW_AMOUNT_SATS = 5000n;
3337
+ var MINIMUM_ETH_WITHDRAW_AMOUNT_WEI = 5000000000000000n;
3254
3338
  var MINIMUM_STABLECOIN_WITHDRAW_AMOUNT_BASE_UNITS = 1000000n;
3255
3339
  var MIN_WITHDRAW_AMOUNTS_BY_ASSET = {
3256
3340
  [Asset.BTC]: MINIMUM_BTC_WITHDRAW_AMOUNT_SATS,
3341
+ [Asset.ETH]: MINIMUM_ETH_WITHDRAW_AMOUNT_WEI,
3257
3342
  [Asset.USDC]: MINIMUM_STABLECOIN_WITHDRAW_AMOUNT_BASE_UNITS,
3258
3343
  [Asset.USDT]: MINIMUM_STABLECOIN_WITHDRAW_AMOUNT_BASE_UNITS
3259
3344
  };
@@ -3390,7 +3475,7 @@ function resolveSupplyMechanism(params) {
3390
3475
  if (params.mechanism !== SupplyPlanType.contractInteraction) {
3391
3476
  return SupplyPlanType.transfer;
3392
3477
  }
3393
- if (params.identifier.chain === Chain.ETH && (params.identifier.asset === Asset.USDC || params.identifier.asset === Asset.USDT)) {
3478
+ if (params.identifier.chain === Chain.ETH && (params.identifier.asset === Asset.ETH || params.identifier.asset === Asset.USDC || params.identifier.asset === Asset.USDT)) {
3394
3479
  return SupplyPlanType.contractInteraction;
3395
3480
  }
3396
3481
  throw new LiquidiumError(
@@ -3413,6 +3498,12 @@ function getEthStablecoinContractAddress(asset) {
3413
3498
  `ETH stablecoin contract address is not configured for ${asset}`
3414
3499
  );
3415
3500
  }
3501
+ function getEthDepositTokenAddress(asset) {
3502
+ if (asset === Asset.ETH) {
3503
+ return [];
3504
+ }
3505
+ return [getEthStablecoinContractAddress(asset)];
3506
+ }
3416
3507
  function mapDepositAccountErrorToLiquidiumError(error) {
3417
3508
  if ("InvalidEvmAddress" in error) {
3418
3509
  return new LiquidiumError(
@@ -3476,7 +3567,7 @@ function resolveSupplyAssetIdentifier(params) {
3476
3567
  return { asset: Asset.BTC, chain: Chain.ICP };
3477
3568
  }
3478
3569
  }
3479
- if ((params.asset === Asset.USDC || params.asset === Asset.USDT) && params.poolChain === Chain.ETH) {
3570
+ if ((params.asset === Asset.ETH || params.asset === Asset.USDC || params.asset === Asset.USDT) && params.poolChain === Chain.ETH) {
3480
3571
  if (params.transferChain === Chain.ETH) {
3481
3572
  return { asset: params.asset, chain: Chain.ETH };
3482
3573
  }
@@ -3494,7 +3585,6 @@ function resolveSupplyAssetIdentifier(params) {
3494
3585
  }
3495
3586
  async function getChainAddressSupplyTarget(canisterContext, profileId, request) {
3496
3587
  if (request.chain === Chain.ETH) {
3497
- const tokenAddress = getEthStablecoinContractAddress(request.asset);
3498
3588
  const subaccount2 = encodeInflowSubaccount({
3499
3589
  action: request.action,
3500
3590
  principal: Principal.fromText(profileId)
@@ -3506,17 +3596,21 @@ async function getChainAddressSupplyTarget(canisterContext, profileId, request)
3506
3596
  owner: Principal.fromText(request.poolId),
3507
3597
  subaccount: [subaccount2]
3508
3598
  },
3509
- [tokenAddress]
3599
+ getEthDepositTokenAddress(request.asset)
3510
3600
  );
3511
3601
  if ("Err" in result) {
3512
3602
  throw mapDepositAccountErrorToLiquidiumError(result.Err);
3513
3603
  }
3604
+ const address2 = normalizeAndValidateEvmAddress(
3605
+ result.Ok,
3606
+ "Deposit address canister returned an invalid EVM address"
3607
+ );
3514
3608
  return {
3515
3609
  poolId: request.poolId,
3516
3610
  asset: request.asset,
3517
3611
  chain: request.chain,
3518
3612
  action: request.action,
3519
- address: result.Ok
3613
+ address: address2
3520
3614
  };
3521
3615
  }
3522
3616
  const configuredBtcPoolId = canisterContext.canisterIds.pools.btc;
@@ -3595,50 +3689,38 @@ function roundInflowFeeEstimate(request, totalFee) {
3595
3689
  function roundUpToNearest(amount, roundingUnit) {
3596
3690
  return ceilDivBigint(amount, roundingUnit) * roundingUnit;
3597
3691
  }
3598
- var BTC_MAINNET_ADDRESS_ERROR = "Address must be a valid mainnet BTC address";
3599
- var EVM_ADDRESS_ERROR = "Address must be a valid EVM address";
3600
- var ADDRESS_CHAIN_MISMATCH_ERROR = "Address chain must match asset";
3601
- function normalizeExternalAddress(params) {
3602
- if (params.asset === Asset.BTC) {
3603
- if (params.chain !== Chain.BTC) {
3604
- throw new LiquidiumError(
3605
- LiquidiumErrorCode.INVALID_ADDRESS,
3606
- ADDRESS_CHAIN_MISMATCH_ERROR
3607
- );
3608
- }
3609
- if (!validate(params.address, Network.mainnet)) {
3610
- throw new LiquidiumError(
3611
- LiquidiumErrorCode.INVALID_ADDRESS,
3612
- BTC_MAINNET_ADDRESS_ERROR
3613
- );
3614
- }
3615
- return params.address;
3616
- }
3617
- if (isEthStablecoin2(params.asset)) {
3618
- if (params.chain !== Chain.ETH) {
3619
- throw new LiquidiumError(
3620
- LiquidiumErrorCode.INVALID_ADDRESS,
3621
- ADDRESS_CHAIN_MISMATCH_ERROR
3622
- );
3623
- }
3624
- if (!isAddress(params.address)) {
3625
- throw new LiquidiumError(
3626
- LiquidiumErrorCode.INVALID_ADDRESS,
3627
- EVM_ADDRESS_ERROR
3628
- );
3629
- }
3630
- return getAddress(params.address);
3692
+
3693
+ // src/core/deposit-minimums.ts
3694
+ var MINIMUM_BTC_DEPOSIT_AMOUNT_SATS = 5100n;
3695
+ var MINIMUM_ETH_DEPOSIT_AMOUNT_WEI = 5000000000000000n;
3696
+ var MINIMUM_ICP_DEPOSIT_AMOUNT_E8S = 10000n;
3697
+ var MINIMUM_STABLECOIN_DEPOSIT_AMOUNT_BASE_UNITS = 1000000n;
3698
+ var MIN_DEPOSIT_AMOUNTS_BY_ASSET = {
3699
+ [Asset.BTC]: MINIMUM_BTC_DEPOSIT_AMOUNT_SATS,
3700
+ [Asset.ETH]: MINIMUM_ETH_DEPOSIT_AMOUNT_WEI,
3701
+ [Asset.ICP]: MINIMUM_ICP_DEPOSIT_AMOUNT_E8S,
3702
+ [Asset.USDC]: MINIMUM_STABLECOIN_DEPOSIT_AMOUNT_BASE_UNITS,
3703
+ [Asset.USDT]: MINIMUM_STABLECOIN_DEPOSIT_AMOUNT_BASE_UNITS
3704
+ };
3705
+ function getMinimumDepositAmount(asset) {
3706
+ if (!isMinimumDepositAsset(asset)) {
3707
+ return 0n;
3631
3708
  }
3632
- return params.address;
3709
+ return MIN_DEPOSIT_AMOUNTS_BY_ASSET[asset];
3633
3710
  }
3634
- function normalizeAndValidateEvmAddress(address, errorMessage) {
3635
- if (!isAddress(address)) {
3636
- throw new LiquidiumError(LiquidiumErrorCode.INVALID_ADDRESS, errorMessage);
3711
+ function getDepositAmountMinimumValidationError(params) {
3712
+ const minimumAmount = getMinimumDepositAmount(params.asset);
3713
+ if (minimumAmount <= 0n || params.amount >= minimumAmount) {
3714
+ return null;
3637
3715
  }
3638
- return getAddress(address);
3716
+ return {
3717
+ asset: params.asset,
3718
+ minimumAmount,
3719
+ message: `Deposit amount must be at least ${minimumAmount} base units for ${params.asset}`
3720
+ };
3639
3721
  }
3640
- function isEthStablecoin2(asset) {
3641
- return asset === Asset.USDC || asset === Asset.USDT;
3722
+ function isMinimumDepositAsset(asset) {
3723
+ return Object.hasOwn(MIN_DEPOSIT_AMOUNTS_BY_ASSET, asset);
3642
3724
  }
3643
3725
 
3644
3726
  // src/core/utils/retry.ts
@@ -3705,7 +3787,13 @@ var SupplyFlowExecutor = class {
3705
3787
  params;
3706
3788
  async create(request) {
3707
3789
  const requestedMechanism = request.mechanism ?? null;
3708
- if (requestedMechanism === null && request.walletAdapter === void 0 && (request.account !== void 0 || request.amount !== void 0)) {
3790
+ if (requestedMechanism !== null && requestedMechanism !== SupplyPlanType.transfer && requestedMechanism !== SupplyPlanType.contractInteraction) {
3791
+ throw new LiquidiumError(
3792
+ LiquidiumErrorCode.VALIDATION_ERROR,
3793
+ `Unsupported supply mechanism: ${String(requestedMechanism)}`
3794
+ );
3795
+ }
3796
+ if (requestedMechanism !== SupplyPlanType.contractInteraction && request.walletAdapter === void 0 && (request.account !== void 0 || request.amount !== void 0)) {
3709
3797
  throw new LiquidiumError(
3710
3798
  LiquidiumErrorCode.VALIDATION_ERROR,
3711
3799
  "Wallet-executed supply requires walletAdapter, account, and amount"
@@ -3715,6 +3803,13 @@ var SupplyFlowExecutor = class {
3715
3803
  this.params.canisterContext,
3716
3804
  request.poolId
3717
3805
  );
3806
+ if (request.amount !== void 0) {
3807
+ validateDepositMinimum({
3808
+ action: request.action,
3809
+ amount: request.amount,
3810
+ asset: selectedPool.asset
3811
+ });
3812
+ }
3718
3813
  const target = await resolveSupplyTargetForPool(
3719
3814
  this.params.canisterContext,
3720
3815
  {
@@ -3779,6 +3874,11 @@ var SupplyFlowExecutor = class {
3779
3874
  this.params.canisterContext,
3780
3875
  request.poolId
3781
3876
  );
3877
+ validateDepositMinimum({
3878
+ action: request.action,
3879
+ amount: request.amount,
3880
+ asset: selectedPool.asset
3881
+ });
3782
3882
  return await this.getEvmSupplyContextForPool({
3783
3883
  request,
3784
3884
  asset: selectedPool.asset,
@@ -3850,13 +3950,17 @@ var SupplyFlowExecutor = class {
3850
3950
  "Wallet-executed supply requires a wallet adapter"
3851
3951
  );
3852
3952
  }
3853
- const account = request.account?.trim();
3854
- if (!account) {
3953
+ const accountInput = request.account?.trim();
3954
+ if (!accountInput) {
3855
3955
  throw new LiquidiumError(
3856
3956
  LiquidiumErrorCode.VALIDATION_ERROR,
3857
3957
  "Wallet-executed transfer supply requires an account"
3858
3958
  );
3859
3959
  }
3960
+ const senderAccount = target.chain === Chain.ETH ? normalizeAndValidateEvmAddress(
3961
+ accountInput,
3962
+ "Invalid EVM wallet address"
3963
+ ) : accountInput;
3860
3964
  if (!request.amount || request.amount <= 0n) {
3861
3965
  throw new LiquidiumError(
3862
3966
  LiquidiumErrorCode.VALIDATION_ERROR,
@@ -3872,14 +3976,14 @@ var SupplyFlowExecutor = class {
3872
3976
  to: decodeIcrcAccountAddress(target.address).account,
3873
3977
  amount: request.amount
3874
3978
  },
3875
- senderAccount: account,
3979
+ senderAccount,
3876
3980
  action: request.action
3877
3981
  }) : await this.sendChainAddressSupplyTransaction({
3878
3982
  walletAdapter: request.walletAdapter,
3879
3983
  chain: target.chain,
3880
3984
  toAddress: target.address,
3881
3985
  amount: request.amount,
3882
- senderAccount: account,
3986
+ senderAccount,
3883
3987
  asset: target.asset,
3884
3988
  action: request.action
3885
3989
  });
@@ -3911,10 +4015,10 @@ var SupplyFlowExecutor = class {
3911
4015
  }
3912
4016
  async executeContractSupply(params) {
3913
4017
  const { request, target, defaultSubmitInflowRequest } = params;
3914
- if (!isEthStablecoin(target.asset, target.chain)) {
4018
+ if (target.chain !== Chain.ETH || target.asset !== Asset.ETH && !isEthStablecoin(target.asset, target.chain)) {
3915
4019
  throw new LiquidiumError(
3916
4020
  LiquidiumErrorCode.VALIDATION_ERROR,
3917
- "Contract-interaction supply is only supported for ETH stablecoin targets"
4021
+ "Contract-interaction supply is only supported for native ETH and ETH stablecoin targets"
3918
4022
  );
3919
4023
  }
3920
4024
  const walletAddressInput = request.account?.trim();
@@ -3934,6 +4038,12 @@ var SupplyFlowExecutor = class {
3934
4038
  "Contract-interaction supply requires a positive amount"
3935
4039
  );
3936
4040
  }
4041
+ if (request.amount > MAX_UINT256) {
4042
+ throw new LiquidiumError(
4043
+ LiquidiumErrorCode.VALIDATION_ERROR,
4044
+ "Contract-interaction supply amount exceeds uint256 maximum"
4045
+ );
4046
+ }
3937
4047
  const walletAdapter = request.walletAdapter;
3938
4048
  if (!walletAdapter?.sendEthTransaction) {
3939
4049
  throw new LiquidiumError(
@@ -3942,6 +4052,26 @@ var SupplyFlowExecutor = class {
3942
4052
  );
3943
4053
  }
3944
4054
  this.params.requireApi();
4055
+ if (target.asset === Asset.ETH) {
4056
+ const depositTxid2 = await this.sendEthContractTransaction(
4057
+ walletAdapter,
4058
+ walletAddress,
4059
+ createDepositEthTransaction({
4060
+ depositContractAddress: CK_ETH_DEPOSIT_CONTRACT_ADDRESS,
4061
+ amount: request.amount,
4062
+ poolId: request.poolId,
4063
+ profileId: request.profileId,
4064
+ destinationAccount: target.address,
4065
+ action: request.action
4066
+ }),
4067
+ `supply-${request.action}-deposit-eth`
4068
+ );
4069
+ await this.registerContractSupplyInflow(
4070
+ depositTxid2,
4071
+ defaultSubmitInflowRequest
4072
+ );
4073
+ return depositTxid2;
4074
+ }
3945
4075
  this.requireEvmReadClient(
3946
4076
  "Contract-interaction supply requires an EVM RPC URL or public client"
3947
4077
  );
@@ -4015,11 +4145,17 @@ var SupplyFlowExecutor = class {
4015
4145
  }),
4016
4146
  `supply-${request.action}-deposit-erc20`
4017
4147
  );
4148
+ await this.registerContractSupplyInflow(
4149
+ depositTxid,
4150
+ defaultSubmitInflowRequest
4151
+ );
4152
+ return depositTxid;
4153
+ }
4154
+ async registerContractSupplyInflow(txid, defaultSubmitInflowRequest) {
4018
4155
  try {
4019
- await this.submitInflowWithRetry(depositTxid, defaultSubmitInflowRequest);
4156
+ await this.submitInflowWithRetry(txid, defaultSubmitInflowRequest);
4020
4157
  } catch {
4021
4158
  }
4022
- return depositTxid;
4023
4159
  }
4024
4160
  async sendChainAddressSupplyTransaction(params) {
4025
4161
  switch (params.chain) {
@@ -4228,6 +4364,22 @@ function isContractInteractionSupplyRequest(request) {
4228
4364
  function mapSupplyActionToStatusOperation(action) {
4229
4365
  return action === SupplyAction.repayment ? "repayment" : "deposit";
4230
4366
  }
4367
+ function validateDepositMinimum(params) {
4368
+ if (params.action !== SupplyAction.deposit) {
4369
+ return;
4370
+ }
4371
+ const minimumDepositAmountError = getDepositAmountMinimumValidationError({
4372
+ amount: params.amount,
4373
+ asset: params.asset
4374
+ });
4375
+ if (!minimumDepositAmountError) {
4376
+ return;
4377
+ }
4378
+ throw new LiquidiumError(
4379
+ LiquidiumErrorCode.VALIDATION_ERROR,
4380
+ minimumDepositAmountError.message
4381
+ );
4382
+ }
4231
4383
  function shouldSubmitInflow(params) {
4232
4384
  if (params.mechanism !== SupplyPlanType.transfer) {
4233
4385
  return true;
@@ -4758,7 +4910,7 @@ var LendingModule = class {
4758
4910
  return await this.createSupplyFlowExecutor().getEvmSupplyContext(request);
4759
4911
  }
4760
4912
  /**
4761
- * Returns the read-only deposit address for an ETH stablecoin inflow target.
4913
+ * Returns the read-only deposit address for an ETH-chain inflow target.
4762
4914
  *
4763
4915
  * This is a query call that does not create or mutate state. Use it when you
4764
4916
  * need the deposit address without hitting the authorization-gated update path.
@@ -4767,13 +4919,22 @@ var LendingModule = class {
4767
4919
  * @returns The EVM deposit address for the derived account.
4768
4920
  */
4769
4921
  async getDepositAddress(request) {
4770
- if (!isEthStablecoin(request.asset, Chain.ETH)) {
4922
+ if (request.asset !== Asset.ETH && !isEthStablecoin(request.asset, Chain.ETH)) {
4923
+ throw new LiquidiumError(
4924
+ LiquidiumErrorCode.VALIDATION_ERROR,
4925
+ "getDepositAddress is only supported for ETH-chain assets"
4926
+ );
4927
+ }
4928
+ const selectedPool = await getPoolById(
4929
+ this.canisterContext,
4930
+ request.poolId
4931
+ );
4932
+ if (selectedPool.asset !== request.asset || selectedPool.chain !== Chain.ETH) {
4771
4933
  throw new LiquidiumError(
4772
4934
  LiquidiumErrorCode.VALIDATION_ERROR,
4773
- "getDepositAddress is only supported for ETH stablecoins"
4935
+ `Deposit address asset ${request.asset} does not match pool ${request.poolId}`
4774
4936
  );
4775
4937
  }
4776
- const tokenAddress = getEthStablecoinContractAddress(request.asset);
4777
4938
  const subaccount = encodeInflowSubaccount({
4778
4939
  action: request.action,
4779
4940
  principal: Principal.fromText(request.profileId)
@@ -4785,17 +4946,20 @@ var LendingModule = class {
4785
4946
  owner: Principal.fromText(request.poolId),
4786
4947
  subaccount: [subaccount]
4787
4948
  },
4788
- [tokenAddress]
4949
+ getEthDepositTokenAddress(request.asset)
4789
4950
  );
4790
4951
  if ("Err" in result) {
4791
4952
  throw mapDepositAccountErrorToLiquidiumError(result.Err);
4792
4953
  }
4793
- return result.Ok;
4954
+ return normalizeAndValidateEvmAddress(
4955
+ result.Ok,
4956
+ "Deposit address canister returned an invalid EVM address"
4957
+ );
4794
4958
  }
4795
4959
  /**
4796
4960
  * Estimates the network/deposit fee for an inflow target.
4797
4961
  *
4798
- * ETH stablecoin deposit-address estimates are served by the deposit-address
4962
+ * ETH-chain deposit-address estimates are served by the deposit-address
4799
4963
  * canister. BTC estimates include the ckBTC minter deposit fee and ledger fee.
4800
4964
  * ICP-chain estimates return the corresponding ICRC ledger fee.
4801
4965
  *
@@ -4809,10 +4973,10 @@ var LendingModule = class {
4809
4973
  totalFee: roundInflowFeeEstimate(request, ledgerFee)
4810
4974
  };
4811
4975
  }
4812
- if (isEthStablecoin(request.asset, request.chain)) {
4976
+ if (request.chain === Chain.ETH && (request.asset === Asset.ETH || isEthStablecoin(request.asset, request.chain))) {
4813
4977
  const result = await createDepositAccountsActor(
4814
4978
  this.canisterContext
4815
- ).estimate_deposit_fee([getEthStablecoinContractAddress(request.asset)]);
4979
+ ).estimate_deposit_fee(getEthDepositTokenAddress(request.asset));
4816
4980
  if ("Err" in result) {
4817
4981
  throw mapDepositAccountErrorToLiquidiumError(result.Err);
4818
4982
  }
@@ -4986,6 +5150,7 @@ var RATE_DECIMALS = BigInt(RATE_SCALE.toString().length - 1);
4986
5150
  // src/core/utils/asset-decimals.ts
4987
5151
  var ASSET_NATIVE_DECIMALS = {
4988
5152
  BTC: 8n,
5153
+ ETH: 18n,
4989
5154
  ICP: 8n,
4990
5155
  USDC: 6n,
4991
5156
  USDT: 6n,
@@ -5007,8 +5172,8 @@ var DECIMAL_BASE = 10;
5007
5172
  var PAIR_SEPARATOR = "_";
5008
5173
  var USDT_SYMBOL = "USDT";
5009
5174
  function mapDecodedPoolToPool(pool, rate) {
5010
- const totalSupply = pool.total_supply_at_last_sync;
5011
- const totalDebt = pool.total_debt_at_last_sync;
5175
+ const totalSupply = pool.total_supply_at_last_sync * pool.lending_index / RATE_SCALE;
5176
+ const totalDebt = pool.total_debt_at_last_sync * pool.borrow_index / RATE_SCALE;
5012
5177
  const availableLiquidity = totalSupply > totalDebt ? totalSupply - totalDebt : 0n;
5013
5178
  return {
5014
5179
  id: pool.principal.toString(),
@@ -5075,6 +5240,7 @@ function formatPrice(price, decimals) {
5075
5240
  var ZERO_POOL_RATE = [0n, 0n, 0n];
5076
5241
  var BACKING_POOL_CHAIN_BY_ASSET = {
5077
5242
  [Asset.BTC]: Chain.BTC,
5243
+ [Asset.ETH]: Chain.ETH,
5078
5244
  [Asset.ICP]: Chain.ICP,
5079
5245
  [Asset.USDC]: Chain.ETH,
5080
5246
  [Asset.USDT]: Chain.ETH
@@ -5965,12 +6131,14 @@ var REPAYMENT_BUFFER_SECONDS = 86400n;
5965
6131
  var RATE_SCALE2 = 10n ** 27n;
5966
6132
  var SECONDS_PER_YEAR = 31536000n;
5967
6133
  var MILLISECONDS_PER_SECOND3 = 1e3;
6134
+ var ETH_NATIVE_INFLOW_FEE_FALLBACK_WEI = 250000000000000n;
5968
6135
  var ETH_STABLECOIN_INFLOW_FEE_FALLBACK = 1500000n;
5969
6136
  var SIMPLE_LOAN_MIN_SLIPPAGE_BUFFER_BPS = 200n;
5970
6137
  var SIMPLE_LOAN_FIND_QUERY_MAX_LENGTH = 256;
5971
6138
  var SIMPLE_LOAN_WIRE_CONTEXT = "simple loan";
5972
6139
  var SIMPLE_LOAN_ASSETS = [
5973
6140
  Asset.BTC,
6141
+ Asset.ETH,
5974
6142
  Asset.ICP,
5975
6143
  Asset.USDC,
5976
6144
  Asset.USDT
@@ -6401,7 +6569,7 @@ var SimpleLoansModule = class {
6401
6569
  const target = input.targets[chain];
6402
6570
  if (!target) continue;
6403
6571
  assertTargetAsset(target, input.asset);
6404
- const inflowFee = await this.lending.estimateInflowFee(target);
6572
+ const inflowFee = await this.estimateInitialDepositInflowFee(target);
6405
6573
  targets[chain] = {
6406
6574
  amount: input.collateralAmount + inflowFee.totalFee,
6407
6575
  inflowFeeAmount: inflowFee.totalFee,
@@ -6417,6 +6585,24 @@ var SimpleLoansModule = class {
6417
6585
  expiryTimestamp: input.expiryTimestamp
6418
6586
  };
6419
6587
  }
6588
+ async estimateInitialDepositInflowFee(target) {
6589
+ try {
6590
+ const fee = await this.lending.estimateInflowFee(target);
6591
+ if (shouldUseNativeEthInflowFeeFallback(target, fee.totalFee)) {
6592
+ return {
6593
+ totalFee: getRepaymentInflowFeeFallback(target.asset, target.chain)
6594
+ };
6595
+ }
6596
+ return fee;
6597
+ } catch (error) {
6598
+ if (target.asset !== Asset.ETH || target.chain !== Chain.ETH) {
6599
+ throw error;
6600
+ }
6601
+ return {
6602
+ totalFee: getRepaymentInflowFeeFallback(target.asset, target.chain)
6603
+ };
6604
+ }
6605
+ }
6420
6606
  async resolveSimpleLoanInflowTargets(request) {
6421
6607
  const selectedPool = await getPoolById(
6422
6608
  this.canisterContext,
@@ -6467,6 +6653,12 @@ var SimpleLoansModule = class {
6467
6653
  async estimateRepaymentInflowFee(target) {
6468
6654
  try {
6469
6655
  const fee = await this.lending.estimateInflowFee(target);
6656
+ if (shouldUseNativeEthInflowFeeFallback(target, fee.totalFee)) {
6657
+ return {
6658
+ totalFee: getRepaymentInflowFeeFallback(target.asset, target.chain),
6659
+ estimateAvailable: false
6660
+ };
6661
+ }
6470
6662
  return { totalFee: fee.totalFee, estimateAvailable: true };
6471
6663
  } catch {
6472
6664
  return {
@@ -6542,11 +6734,17 @@ var SimpleLoansModule = class {
6542
6734
  }
6543
6735
  };
6544
6736
  function getRepaymentInflowFeeFallback(asset, chain) {
6737
+ if (chain === Chain.ETH && asset === Asset.ETH) {
6738
+ return ETH_NATIVE_INFLOW_FEE_FALLBACK_WEI;
6739
+ }
6545
6740
  if (chain === "ETH" && (asset === "USDT" || asset === "USDC")) {
6546
6741
  return ETH_STABLECOIN_INFLOW_FEE_FALLBACK;
6547
6742
  }
6548
6743
  return 0n;
6549
6744
  }
6745
+ function shouldUseNativeEthInflowFeeFallback(target, totalFee) {
6746
+ return totalFee <= 0n && target.asset === Asset.ETH && target.chain === Chain.ETH;
6747
+ }
6550
6748
  function assertTargetAsset(target, expectedAsset) {
6551
6749
  if (target.asset === expectedAsset) {
6552
6750
  return;
@@ -6696,7 +6894,7 @@ function inferSimpleLoanDeliveryChain(destination, asset) {
6696
6894
  if (asset === Asset.BTC) {
6697
6895
  return Chain.BTC;
6698
6896
  }
6699
- if (asset === Asset.USDC || asset === Asset.USDT) {
6897
+ if (asset === Asset.ETH || asset === Asset.USDC || asset === Asset.USDT) {
6700
6898
  return Chain.ETH;
6701
6899
  }
6702
6900
  return Chain.ICP;
@@ -7229,6 +7427,6 @@ function resolveEvmReadClient(config) {
7229
7427
  });
7230
7428
  }
7231
7429
 
7232
- export { AccountsModule, ActivitiesModule, ActivityFilter, Asset, CK_ETH_DEPOSIT_CONTRACT_ADDRESS, Chain, Environment, EvmSupplyApprovalStrategy, HistoryModule, LendingModule, LiquidiumAccountType, LiquidiumClient, LiquidiumError, LiquidiumErrorCode, MIN_BORROW_AMOUNTS_BY_ASSET, MIN_WITHDRAW_AMOUNTS_BY_ASSET, MarketModule, OutflowType, PositionsModule, QuoteModule, QuoteValidationErrorCode, QuoteWarningCode, RATE_DECIMALS, RATE_SCALE, SimpleLoanCreatedError, SimpleLoansModule, SupplyAction, SupplyPlanType, USDC_CONTRACT_ADDRESS, USDT_CONTRACT_ADDRESS, WalletActionKind, WalletExecutionKind, createTransferErc20Transaction, executeWith, getMinimumBorrowAmount, getMinimumWithdrawAmount, intFromPublicId, isAssetIdentifier, publicIdFromInt };
7430
+ export { AccountsModule, ActivitiesModule, ActivityFilter, Asset, CK_ETH_DEPOSIT_CONTRACT_ADDRESS, Chain, Environment, EvmSupplyApprovalStrategy, HistoryModule, LendingModule, LiquidiumAccountType, LiquidiumClient, LiquidiumError, LiquidiumErrorCode, MIN_BORROW_AMOUNTS_BY_ASSET, MIN_DEPOSIT_AMOUNTS_BY_ASSET, MIN_WITHDRAW_AMOUNTS_BY_ASSET, MarketModule, OutflowType, PositionsModule, QuoteModule, QuoteValidationErrorCode, QuoteWarningCode, RATE_DECIMALS, RATE_SCALE, SimpleLoanCreatedError, SimpleLoansModule, SupplyAction, SupplyPlanType, USDC_CONTRACT_ADDRESS, USDT_CONTRACT_ADDRESS, WalletActionKind, WalletExecutionKind, createTransferErc20Transaction, executeWith, getMinimumBorrowAmount, getMinimumDepositAmount, getMinimumWithdrawAmount, intFromPublicId, isAssetIdentifier, publicIdFromInt };
7233
7431
  //# sourceMappingURL=index.js.map
7234
7432
  //# sourceMappingURL=index.js.map