@rhinestone/deposit-modal 0.9.1 → 0.10.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.
Files changed (30) hide show
  1. package/dist/{DepositModalReown-JUJI7UHE.mjs → DepositModalReown-MTWT6Y66.mjs} +5 -5
  2. package/dist/{DepositModalReown-YQSO4SVY.cjs → DepositModalReown-S3DSFXTX.cjs} +9 -9
  3. package/dist/{chunk-7OQO6JDC.mjs → chunk-5NJYW5FT.mjs} +3 -3
  4. package/dist/{chunk-QLZ5RZTA.mjs → chunk-5OEWGJR4.mjs} +1 -1
  5. package/dist/{chunk-WUQZYQRK.mjs → chunk-7TV7GLJB.mjs} +62 -1
  6. package/dist/{chunk-EEEQZOTJ.cjs → chunk-A42XAHIB.cjs} +66 -66
  7. package/dist/{chunk-SQOEHQNT.cjs → chunk-DEF767BA.cjs} +52 -52
  8. package/dist/{chunk-AYWEWI47.mjs → chunk-KW32UBUQ.mjs} +1 -1
  9. package/dist/{chunk-QGXAAFHU.mjs → chunk-LR7MKHYV.mjs} +2 -2
  10. package/dist/{chunk-N3OHR3T2.mjs → chunk-MHIOMTMM.mjs} +227 -24
  11. package/dist/{chunk-XJE5MRY4.cjs → chunk-NF4NBRUP.cjs} +1 -1
  12. package/dist/{chunk-6U2H3R3T.cjs → chunk-PUJHXHRA.cjs} +108 -47
  13. package/dist/{chunk-ITFRTPGF.cjs → chunk-UMCDZJMG.cjs} +57 -57
  14. package/dist/{chunk-GYEUZSQP.mjs → chunk-VDGT6NZQ.mjs} +1 -1
  15. package/dist/{chunk-EAUF7SGM.cjs → chunk-VTVOHNXM.cjs} +3 -3
  16. package/dist/{chunk-VQJHYWAE.cjs → chunk-W4YAOJPG.cjs} +570 -367
  17. package/dist/claim.cjs +5 -5
  18. package/dist/claim.mjs +4 -4
  19. package/dist/constants.cjs +2 -2
  20. package/dist/constants.d.cts +1 -1
  21. package/dist/constants.d.ts +1 -1
  22. package/dist/constants.mjs +1 -1
  23. package/dist/deposit.cjs +6 -6
  24. package/dist/deposit.mjs +5 -5
  25. package/dist/index.cjs +8 -8
  26. package/dist/index.mjs +7 -7
  27. package/dist/styles.css +14 -0
  28. package/dist/withdraw.cjs +5 -5
  29. package/dist/withdraw.mjs +4 -4
  30. package/package.json +1 -1
@@ -18,10 +18,10 @@ import {
18
18
  runAccountSetupDeduped,
19
19
  txRefsMatch,
20
20
  warnRemovedProps
21
- } from "./chunk-GYEUZSQP.mjs";
21
+ } from "./chunk-VDGT6NZQ.mjs";
22
22
  import {
23
23
  ListRow
24
- } from "./chunk-AYWEWI47.mjs";
24
+ } from "./chunk-KW32UBUQ.mjs";
25
25
  import {
26
26
  AlertTriangleIcon,
27
27
  AppleIcon,
@@ -77,7 +77,7 @@ import {
77
77
  useLatestRef,
78
78
  useRpcUrls,
79
79
  useStableRpcUrls
80
- } from "./chunk-WUQZYQRK.mjs";
80
+ } from "./chunk-7TV7GLJB.mjs";
81
81
  import {
82
82
  POLYMARKET_COLLATERAL_OFFRAMP_ADDRESS,
83
83
  POLYMARKET_ICON_URL,
@@ -90,6 +90,7 @@ import {
90
90
  readPolymarketBalances
91
91
  } from "./chunk-ILT2PITN.mjs";
92
92
  import {
93
+ CHAIN_BY_ID,
93
94
  HYPERCORE_CHAIN_ID,
94
95
  HYPERCORE_MIN_DEPOSIT_USD,
95
96
  NATIVE_TOKEN_ADDRESS,
@@ -262,18 +263,17 @@ var DAPP_IMPORT_CATALOG = [
262
263
  label: "Polymarket",
263
264
  iconUrl: cdnIconUrl("dapps", "polymarket")
264
265
  },
266
+ {
267
+ id: "aave",
268
+ label: "Aave",
269
+ iconUrl: cdnIconUrl("dapps", "aave")
270
+ },
265
271
  {
266
272
  id: "hyperliquid",
267
273
  label: "Hyperliquid",
268
274
  iconUrl: cdnIconUrl("dapps", "hyperliquid"),
269
275
  comingSoon: true
270
276
  },
271
- {
272
- id: "aave",
273
- label: "Aave",
274
- iconUrl: cdnIconUrl("dapps", "aave"),
275
- comingSoon: true
276
- },
277
277
  {
278
278
  id: "morpho",
279
279
  label: "Morpho",
@@ -1036,6 +1036,7 @@ function AmountStep({
1036
1036
  publicClient,
1037
1037
  address,
1038
1038
  balanceAddress,
1039
+ declaredBalance,
1039
1040
  asset,
1040
1041
  defaultAmount,
1041
1042
  switchChain,
@@ -1078,6 +1079,10 @@ function AmountStep({
1078
1079
  const hasPricing = tokenPriceUsd !== null;
1079
1080
  useEffect3(() => {
1080
1081
  let active = true;
1082
+ if (declaredBalance !== void 0) {
1083
+ setBalance(declaredBalance);
1084
+ return;
1085
+ }
1081
1086
  async function fetchBalance() {
1082
1087
  const balanceTarget = balanceAddress ?? address;
1083
1088
  if (!balanceTarget || !publicClient) return;
@@ -1097,7 +1102,7 @@ function AmountStep({
1097
1102
  return () => {
1098
1103
  active = false;
1099
1104
  };
1100
- }, [address, balanceAddress, publicClient, asset]);
1105
+ }, [address, balanceAddress, declaredBalance, publicClient, asset]);
1101
1106
  useEffect3(() => {
1102
1107
  if (chainMismatch && switchChain && !hasAttemptedSwitch.current) {
1103
1108
  hasAttemptedSwitch.current = true;
@@ -4385,6 +4390,7 @@ import { jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
4385
4390
  function DappImportAssetSelectStep({
4386
4391
  sourceLabel,
4387
4392
  assets,
4393
+ incompleteSummary,
4388
4394
  onSelect
4389
4395
  }) {
4390
4396
  return /* @__PURE__ */ jsxs19("div", { className: "rs-screen", children: [
@@ -4397,6 +4403,7 @@ function DappImportAssetSelectStep({
4397
4403
  subtitle: "Pick the balance to import"
4398
4404
  }
4399
4405
  ),
4406
+ incompleteSummary && /* @__PURE__ */ jsx22("div", { className: "rs-asset-notice", role: "status", children: incompleteSummary }),
4400
4407
  /* @__PURE__ */ jsx22("div", { className: "rs-asset-list", children: assets.map((asset) => {
4401
4408
  const tokenAmount = asset.balance ? tokenFormatter.format(
4402
4409
  Number(asset.balance) / 10 ** asset.decimals
@@ -4435,7 +4442,8 @@ function DappImportAssetSelectStep({
4435
4442
  /* @__PURE__ */ jsx22("span", { className: "rs-asset-name", children: asset.symbol }),
4436
4443
  /* @__PURE__ */ jsxs19("span", { className: "rs-asset-chain", children: [
4437
4444
  "on ",
4438
- asset.sourceLabel
4445
+ asset.sourceLabel,
4446
+ asset.qualifier ? ` \xB7 ${asset.qualifier}` : ""
4439
4447
  ] })
4440
4448
  ] }),
4441
4449
  /* @__PURE__ */ jsxs19("div", { className: "rs-asset-balance-small", children: [
@@ -4649,6 +4657,188 @@ function composeFiatMethods(regional, fallbackMethods) {
4649
4657
  };
4650
4658
  }
4651
4659
 
4660
+ // src/core/dapp-imports/balance-source.ts
4661
+ function dappImportBalanceSource(asset) {
4662
+ if (!isDappImportAsset(asset)) return {};
4663
+ if (asset.balanceAddress) return { balanceAddress: asset.balanceAddress };
4664
+ if (asset.balance === void 0) return {};
4665
+ try {
4666
+ return { declaredBalance: BigInt(asset.balance) };
4667
+ } catch {
4668
+ return {};
4669
+ }
4670
+ }
4671
+
4672
+ // src/core/dapp-imports/aave/index.ts
4673
+ var PROVIDER_ID = "aave";
4674
+ var SOURCE_LABEL = "Aave";
4675
+ var POLICY_REFUSED = [
4676
+ "below_deposit_floor",
4677
+ "deposit_not_whitelisted"
4678
+ ];
4679
+ var aaveProvider = {
4680
+ id: PROVIDER_ID,
4681
+ sourceLabel: SOURCE_LABEL,
4682
+ async fetchAvailability({ eoa, backend, signal }) {
4683
+ if (!backend) {
4684
+ throw new Error("Aave positions require a backend connection");
4685
+ }
4686
+ const response = await backend.getPositions(eoa);
4687
+ if (signal?.aborted) return null;
4688
+ const assets = toImportableAssets(response.positions);
4689
+ const failures = response.failures ?? [];
4690
+ if (assets.length === 0) {
4691
+ if (failures.length > 0) {
4692
+ throw new Error(
4693
+ `Could not read Aave positions: ${failures.map((failure) => failure.reason).join("; ")}`
4694
+ );
4695
+ }
4696
+ return null;
4697
+ }
4698
+ const availability = {
4699
+ providerId: PROVIDER_ID,
4700
+ // Deliberately the sum over importable assets rather than
4701
+ // `response.totalUsd`: the latter counts positions this flow filters out,
4702
+ // so using it would show a balance the user then cannot find.
4703
+ totalUsd: assets.reduce((sum, asset) => sum + (asset.balanceUsd ?? 0), 0),
4704
+ assets,
4705
+ // Some markets read, some did not. Erroring would discard positions the
4706
+ // user can migrate right now — and with ~29 markets on a keyless API, one
4707
+ // failing is the expected case, so erroring would be the normal outcome.
4708
+ // The list therefore stands, marked as a floor. The upstream reason names
4709
+ // an internal market, so it is summarised rather than surfaced.
4710
+ ...failures.length > 0 ? {
4711
+ incomplete: {
4712
+ summary: failures.length === 1 ? "One Aave market couldn't be loaded, so a position may be missing." : `${failures.length} Aave markets couldn't be loaded, so positions may be missing.`
4713
+ }
4714
+ } : {}
4715
+ };
4716
+ return availability;
4717
+ },
4718
+ async executeTransfer({ walletClient, recipient, asset, amount, backend }) {
4719
+ if (!backend) {
4720
+ throw new Error("Aave withdrawals require a backend connection");
4721
+ }
4722
+ const metadata = asset.providerMetadata;
4723
+ const account = walletClient.account;
4724
+ const chain = walletClient.chain;
4725
+ if (!account || !chain) {
4726
+ throw new Error("Wallet not connected");
4727
+ }
4728
+ if (chain.id !== metadata.chainId) {
4729
+ throw new Error(
4730
+ `Switch to ${metadata.marketName} chain (${metadata.chainId}) to sign`
4731
+ );
4732
+ }
4733
+ const prepared = await backend.prepareUnwind({
4734
+ address: account.address,
4735
+ // The backend resolves the recipient from this account rather than
4736
+ // trusting a supplied address. `amount` is always explicit — expressing
4737
+ // "everything" is the backend's call, since only it knows whether sweeping
4738
+ // accrued interest could push the delivered amount past a whitelist
4739
+ // ceiling and get the proceeds rejected after the withdraw succeeded.
4740
+ account: recipient,
4741
+ market: metadata.market,
4742
+ chainId: metadata.chainId,
4743
+ asset: metadata.asset,
4744
+ amount: amount.toString()
4745
+ });
4746
+ if (prepared.recipient.toLowerCase() !== recipient.toLowerCase()) {
4747
+ throw new Error(
4748
+ "Aave withdrawal would send funds to an unexpected address"
4749
+ );
4750
+ }
4751
+ if (prepared.transaction.chainId !== metadata.chainId) {
4752
+ throw new Error("Aave withdrawal was prepared for a different chain");
4753
+ }
4754
+ const txHash = await walletClient.sendTransaction({
4755
+ account,
4756
+ chain,
4757
+ to: prepared.transaction.to,
4758
+ data: prepared.transaction.data,
4759
+ value: BigInt(prepared.transaction.value)
4760
+ });
4761
+ return {
4762
+ txHash,
4763
+ // Aave pays out the underlying straight to the deposit address — no
4764
+ // unwrap, no swap, so what arrives is what was supplied.
4765
+ sourceToken: metadata.asset,
4766
+ sourceSymbol: asset.symbol,
4767
+ sourceDecimals: asset.decimals
4768
+ };
4769
+ }
4770
+ };
4771
+ function toImportableAssets(positions) {
4772
+ const assets = [];
4773
+ for (const position of positions) {
4774
+ const chainId = parseEvmChainId(position.chain);
4775
+ if (chainId === null) continue;
4776
+ if (!CHAIN_BY_ID[chainId]) continue;
4777
+ if (BigInt(position.maxWithdrawable) <= 0n) continue;
4778
+ if (position.constraints.some((c) => POLICY_REFUSED.includes(c))) continue;
4779
+ assets.push(buildAsset(position, chainId));
4780
+ }
4781
+ return qualifyAmbiguousMarkets(assets);
4782
+ }
4783
+ function buildAsset(position, chainId) {
4784
+ const { asset, market } = position;
4785
+ const token = asset.address.toLowerCase();
4786
+ const metadata = {
4787
+ market: market.address,
4788
+ marketName: market.name,
4789
+ chainId,
4790
+ asset: asset.address
4791
+ };
4792
+ return {
4793
+ // Market-keyed, so one chain holding the same token in two markets yields
4794
+ // two distinct rows rather than one that silently shadows the other.
4795
+ id: `aave:${chainId}:${market.address.toLowerCase()}:${token}`,
4796
+ chainId,
4797
+ token,
4798
+ symbol: asset.symbol,
4799
+ // The market name, not a token description: it is what tells four Aave v3
4800
+ // markets on Ethereum apart.
4801
+ name: market.name,
4802
+ decimals: asset.decimals,
4803
+ // `maxWithdrawable`, NOT the supplied balance. The amount selector lets the
4804
+ // user pick up to this, and seeding it with the supplied balance would let
4805
+ // them choose above the cap and sign a withdraw the pool rejects.
4806
+ balance: position.maxWithdrawable,
4807
+ balanceUsd: withdrawableUsd(position),
4808
+ source: PROVIDER_ID,
4809
+ sourceLabel: SOURCE_LABEL,
4810
+ reviewLabel: `You withdraw ${asset.symbol} from Aave`,
4811
+ // Aave sends the underlying itself to the deposit address, so the token the
4812
+ // orchestrator sees land is the same one and on the same chain.
4813
+ depositToken: token,
4814
+ depositChainId: chainId,
4815
+ providerMetadata: metadata
4816
+ };
4817
+ }
4818
+ function qualifyAmbiguousMarkets(assets) {
4819
+ const counts = /* @__PURE__ */ new Map();
4820
+ for (const asset of assets) {
4821
+ const key = `${asset.chainId}:${asset.token}`;
4822
+ counts.set(key, (counts.get(key) ?? 0) + 1);
4823
+ }
4824
+ return assets.map(
4825
+ (asset) => (counts.get(`${asset.chainId}:${asset.token}`) ?? 0) > 1 ? {
4826
+ ...asset,
4827
+ qualifier: asset.providerMetadata.marketName
4828
+ } : asset
4829
+ );
4830
+ }
4831
+ function withdrawableUsd(position) {
4832
+ const amount = BigInt(position.amount);
4833
+ const withdrawable = BigInt(position.maxWithdrawable);
4834
+ if (amount === 0n) return 0;
4835
+ if (withdrawable === amount) return position.usdValue;
4836
+ const SCALE = 1000000n;
4837
+ const ratio = Number(withdrawable * SCALE / amount) / Number(SCALE);
4838
+ const usd = position.usdValue * ratio;
4839
+ return Number.isFinite(usd) ? usd : 0;
4840
+ }
4841
+
4652
4842
  // src/core/dapp-imports/polymarket/index.ts
4653
4843
  import { formatUnits as formatUnits6 } from "viem";
4654
4844
 
@@ -4819,11 +5009,10 @@ function buildPusdUnwrapCalls(recipient, amount) {
4819
5009
  }
4820
5010
 
4821
5011
  // src/core/dapp-imports/polymarket/index.ts
4822
- var PROVIDER_ID = "polymarket";
5012
+ var PROVIDER_ID2 = "polymarket";
4823
5013
  var polymarketProvider = {
4824
- id: PROVIDER_ID,
5014
+ id: PROVIDER_ID2,
4825
5015
  sourceLabel: "Polymarket",
4826
- chainId: POLYMARKET_POLYGON_CHAIN_ID,
4827
5016
  async fetchAvailability({ eoa, getPublicClient: getPublicClient2, signal }) {
4828
5017
  const proxyWallet = await fetchPolymarketProxyWallet(eoa, signal);
4829
5018
  if (!proxyWallet) return null;
@@ -4846,17 +5035,17 @@ var polymarketProvider = {
4846
5035
  const assets = [];
4847
5036
  if (balances.pusd > 0n) {
4848
5037
  assets.push(
4849
- buildAsset({ tokenKind: "pusd", proxyWallet, walletKind, balance: balances.pusd })
5038
+ buildAsset2({ tokenKind: "pusd", proxyWallet, walletKind, balance: balances.pusd })
4850
5039
  );
4851
5040
  }
4852
5041
  if (balances.usdce > 0n) {
4853
5042
  assets.push(
4854
- buildAsset({ tokenKind: "usdce", proxyWallet, walletKind, balance: balances.usdce })
5043
+ buildAsset2({ tokenKind: "usdce", proxyWallet, walletKind, balance: balances.usdce })
4855
5044
  );
4856
5045
  }
4857
5046
  const totalUsd = assets.reduce((sum, a) => sum + (a.balanceUsd ?? 0), 0);
4858
5047
  const availability = {
4859
- providerId: PROVIDER_ID,
5048
+ providerId: PROVIDER_ID2,
4860
5049
  totalUsd,
4861
5050
  assets
4862
5051
  };
@@ -4904,7 +5093,7 @@ var polymarketProvider = {
4904
5093
  };
4905
5094
  }
4906
5095
  };
4907
- function buildAsset(params) {
5096
+ function buildAsset2(params) {
4908
5097
  const { tokenKind, proxyWallet, walletKind, balance } = params;
4909
5098
  const isPusd = tokenKind === "pusd";
4910
5099
  const tokenAddress = isPusd ? POLYMARKET_PUSD_ADDRESS : POLYMARKET_USDCE_ADDRESS;
@@ -4921,8 +5110,11 @@ function buildAsset(params) {
4921
5110
  decimals: 6,
4922
5111
  balance: balance.toString(),
4923
5112
  balanceUsd: Number.isFinite(balanceUsd) ? balanceUsd : 0,
4924
- source: PROVIDER_ID,
5113
+ source: PROVIDER_ID2,
4925
5114
  sourceLabel: "Polymarket",
5115
+ // The proxy wallet really does hold this ERC-20, so the amount step reads it
5116
+ // live rather than trusting the figure from the availability fetch.
5117
+ balanceAddress: proxyWallet,
4926
5118
  reviewLabel: isPusd ? "You send pUSD from Polymarket" : "You send USDC.e from Polymarket",
4927
5119
  // pUSD unwraps to USDC.e via the offramp; USDC.e is what actually
4928
5120
  // arrives at the smart account, so it's also what the orchestrator
@@ -4934,7 +5126,10 @@ function buildAsset(params) {
4934
5126
  }
4935
5127
 
4936
5128
  // src/core/dapp-imports/registry.ts
4937
- var DAPP_IMPORT_PROVIDERS = [polymarketProvider];
5129
+ var DAPP_IMPORT_PROVIDERS = [
5130
+ polymarketProvider,
5131
+ aaveProvider
5132
+ ];
4938
5133
  function getEnabledProviders(config) {
4939
5134
  if (!config) return [];
4940
5135
  return DAPP_IMPORT_PROVIDERS.filter(
@@ -6768,6 +6963,9 @@ function DepositFlow({
6768
6963
  return null;
6769
6964
  }
6770
6965
  },
6966
+ // Providers whose positions live behind the Rhinestone API rather than
6967
+ // an RPC (Aave) read them through here.
6968
+ backend: service,
6771
6969
  signal: controller.signal
6772
6970
  }).then((availability) => {
6773
6971
  if (controller.signal.aborted) return;
@@ -6792,7 +6990,8 @@ function DepositFlow({
6792
6990
  enabledDappImportProviders,
6793
6991
  dappImportAttemptNonce,
6794
6992
  storeApi,
6795
- rpcUrls
6993
+ rpcUrls,
6994
+ service
6796
6995
  ]);
6797
6996
  useLayoutEffect2(() => {
6798
6997
  if (!initialAssetMigrationProvider) return;
@@ -8096,6 +8295,7 @@ function DepositFlow({
8096
8295
  {
8097
8296
  sourceLabel: activeDappImportAvailability.assets[0]?.sourceLabel ?? activeDappImportProvider.sourceLabel,
8098
8297
  assets: activeDappImportAvailability.assets,
8298
+ incompleteSummary: activeDappImportAvailability.incomplete?.summary,
8099
8299
  onSelect: handleDappImportAssetSelected
8100
8300
  }
8101
8301
  ),
@@ -8105,7 +8305,7 @@ function DepositFlow({
8105
8305
  walletClient: signerContext.walletClient,
8106
8306
  publicClient: getReadClientForChain(effectiveStep.asset.chainId),
8107
8307
  address: ownerAddress,
8108
- balanceAddress: isDappImportAsset(effectiveStep.asset) ? effectiveStep.asset.providerMetadata.proxyWallet : void 0,
8308
+ ...dappImportBalanceSource(effectiveStep.asset),
8109
8309
  asset: effectiveStep.asset,
8110
8310
  defaultAmount: effectiveStep.inputAmountUsd ?? defaultAmount,
8111
8311
  switchChain: signerContext.switchChain,
@@ -8152,8 +8352,11 @@ function DepositFlow({
8152
8352
  const result = await activeDappImportProvider.executeTransfer(
8153
8353
  {
8154
8354
  walletClient: signerContext.walletClient,
8355
+ // The asset's chain: a provider's assets can span chains
8356
+ // (Aave positions exist on every deposit-enabled chain), so
8357
+ // there is no single provider-level chain to read from.
8155
8358
  publicClient: getReadClientForChain(
8156
- activeDappImportProvider.chainId
8359
+ effectiveStep.asset.chainId
8157
8360
  ),
8158
8361
  recipient: effectiveStep.smartAccount,
8159
8362
  asset: effectiveStep.asset,
@@ -8492,7 +8695,7 @@ DepositHistoryPanel.displayName = "DepositHistoryPanel";
8492
8695
  // src/DepositModal.tsx
8493
8696
  import { jsx as jsx27, jsxs as jsxs24 } from "react/jsx-runtime";
8494
8697
  var ReownDepositInner = lazy2(
8495
- () => import("./DepositModalReown-JUJI7UHE.mjs").then((m) => ({ default: m.DepositModalReown }))
8698
+ () => import("./DepositModalReown-MTWT6Y66.mjs").then((m) => ({ default: m.DepositModalReown }))
8496
8699
  );
8497
8700
  function sortByCreatedAtDesc(items) {
8498
8701
  return [...items].sort((a, b) => {
@@ -1,5 +1,5 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/core/version.ts
2
- var MODAL_VERSION = "0.9.1";
2
+ var MODAL_VERSION = "0.10.0";
3
3
  var SERVICE_HEADERS = {
4
4
  "Content-Type": "application/json",
5
5
  "x-deposit-modal-version": MODAL_VERSION