@compass-labs/widgets 0.1.12 → 0.1.13

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
@@ -3789,6 +3789,7 @@ function AaveMarketsList({
3789
3789
  ] });
3790
3790
  }
3791
3791
  var CHAIN_ID = "ethereum";
3792
+ var SUPPORTED_TOKENS = ["USDC", "USDT", "DAI", "WETH", "SBC", "AUSD"];
3792
3793
  function formatCurrency(amount) {
3793
3794
  if (!amount) return "$0.00";
3794
3795
  const num = typeof amount === "string" ? parseFloat(amount) : amount;
@@ -3825,16 +3826,19 @@ function EarnAccount({
3825
3826
  const { isDeployed } = useEarnAccount();
3826
3827
  const queryClient = reactQuery.useQueryClient();
3827
3828
  const [activeTab, setActiveTab] = react.useState("deposit");
3829
+ const [selectedToken, setSelectedToken] = react.useState("USDC");
3828
3830
  const [amount, setAmount] = react.useState("");
3829
3831
  const [isProcessing, setIsProcessing] = react.useState(false);
3830
3832
  const [error, setError] = react.useState(null);
3831
3833
  const [statusMessage, setStatusMessage] = react.useState("");
3834
+ const [isTokenDropdownOpen, setIsTokenDropdownOpen] = react.useState(false);
3832
3835
  const [isFundModalOpen, setIsFundModalOpen] = react.useState(false);
3833
3836
  const [fundAmount, setFundAmount] = react.useState("");
3834
3837
  const [fundToken, setFundToken] = react.useState("USDC");
3835
3838
  const [isFunding, setIsFunding] = react.useState(false);
3836
3839
  const [fundError, setFundError] = react.useState(null);
3837
3840
  const [fundStatus, setFundStatus] = react.useState("");
3841
+ const [isBalancesModalOpen, setIsBalancesModalOpen] = react.useState(false);
3838
3842
  const FUND_TOKENS = ["USDC", "DAI"];
3839
3843
  const walletBalanceQuery = reactQuery.useQuery({
3840
3844
  queryKey: ["walletBalance", CHAIN_ID, address, fundToken],
@@ -3870,7 +3874,8 @@ function EarnAccount({
3870
3874
  enabled: !!address && isDeployed,
3871
3875
  staleTime: 30 * 1e3
3872
3876
  });
3873
- const availableBalance = balancesQuery.data?.balances?.["USDC"]?.balance || "0";
3877
+ const selectedTokenBalance = balancesQuery.data?.balances?.[selectedToken]?.balance || "0";
3878
+ const earnAccountTotalUsd = balancesQuery.data?.totalUsdValue || "0";
3874
3879
  const marketQuery = reactQuery.useQuery({
3875
3880
  queryKey: ["earnAccountUSDC", CHAIN_ID],
3876
3881
  queryFn: async () => {
@@ -3927,10 +3932,10 @@ function EarnAccount({
3927
3932
  const market = marketQuery.data;
3928
3933
  const userPosition = positionQuery.data;
3929
3934
  const depositedBalance = parseFloat(userPosition?.balance || "0");
3930
- const available = parseFloat(availableBalance);
3931
- const totalBalance = available + depositedBalance;
3932
- const earnings = parseFloat(userPosition?.pnl?.totalPnl || "0");
3933
- const needsSwap = fundToken !== "USDC";
3935
+ const earnAccountTotal = parseFloat(earnAccountTotalUsd);
3936
+ const totalBalance = earnAccountTotal + depositedBalance;
3937
+ const needsActionSwap = selectedToken !== "USDC";
3938
+ const needsFundSwap = fundToken !== "USDC";
3934
3939
  const ensureTokenApproval = async (token) => {
3935
3940
  setFundStatus(`Checking ${token} approval...`);
3936
3941
  const approveResponse = await fetch("/api/compass/transfer/approve", {
@@ -4000,7 +4005,7 @@ function EarnAccount({
4000
4005
  setFundError(null);
4001
4006
  try {
4002
4007
  await ensureTokenApproval(fundToken);
4003
- if (needsSwap) {
4008
+ if (needsFundSwap) {
4004
4009
  setFundStatus(`Preparing ${fundToken} transfer...`);
4005
4010
  const transferPrepareResponse = await fetch("/api/compass/transfer/prepare", {
4006
4011
  method: "POST",
@@ -4145,55 +4150,193 @@ function EarnAccount({
4145
4150
  } finally {
4146
4151
  setIsFunding(false);
4147
4152
  }
4148
- }, [address, fundAmount, fundToken, needsSwap, signTypedData, queryClient, balancesQuery]);
4153
+ }, [address, fundAmount, fundToken, needsFundSwap, signTypedData, queryClient, balancesQuery]);
4149
4154
  const handleAction = async () => {
4150
4155
  if (!market || !amount || parseFloat(amount) <= 0 || !address || !signTypedData) return;
4151
4156
  setIsProcessing(true);
4152
4157
  setError(null);
4153
- setStatusMessage(activeTab === "deposit" ? "Preparing deposit..." : "Preparing withdrawal...");
4158
+ const isDeposit = activeTab === "deposit";
4154
4159
  try {
4155
- const isDeposit = activeTab === "deposit";
4156
- const prepareEndpoint = isDeposit ? "/api/compass/deposit/prepare" : "/api/compass/withdraw/prepare";
4157
- const executeEndpoint = isDeposit ? "/api/compass/deposit/execute" : "/api/compass/withdraw/execute";
4158
- const prepareResponse = await fetch(prepareEndpoint, {
4159
- method: "POST",
4160
- headers: { "Content-Type": "application/json" },
4161
- body: JSON.stringify({
4162
- owner: address,
4163
- chain: CHAIN_ID,
4164
- venueType: "AAVE",
4165
- token: "USDC",
4166
- amount
4167
- })
4168
- });
4169
- if (!prepareResponse.ok) {
4170
- const errData = await prepareResponse.json();
4171
- throw new Error(errData.error || "Failed to prepare transaction");
4172
- }
4173
- const prepareData = await prepareResponse.json();
4174
- setStatusMessage("Please sign the transaction...");
4175
- const signature = await signTypedData({
4176
- domain: prepareData.domain,
4177
- types: prepareData.normalizedTypes,
4178
- primaryType: "SafeTx",
4179
- message: prepareData.message
4180
- });
4181
- setStatusMessage("Executing transaction...");
4182
- const executeResponse = await fetch(executeEndpoint, {
4183
- method: "POST",
4184
- headers: { "Content-Type": "application/json" },
4185
- body: JSON.stringify({
4186
- owner: address,
4187
- chain: CHAIN_ID,
4188
- eip712: prepareData.eip712,
4189
- signature
4190
- })
4191
- });
4192
- if (!executeResponse.ok) {
4193
- const errData = await executeResponse.json();
4194
- throw new Error(errData.error || "Transaction failed");
4160
+ let txHash;
4161
+ if (needsActionSwap) {
4162
+ if (isDeposit) {
4163
+ setStatusMessage(`Getting swap quote...`);
4164
+ const quoteResponse = await fetch(
4165
+ `/api/compass/swap/quote?owner=${address}&chain=${CHAIN_ID}&tokenIn=${selectedToken}&tokenOut=USDC&amountIn=${amount}`
4166
+ );
4167
+ if (!quoteResponse.ok) {
4168
+ const errorData = await quoteResponse.json();
4169
+ throw new Error(errorData.error || "Failed to get swap quote");
4170
+ }
4171
+ const quoteData = await quoteResponse.json();
4172
+ const estimatedOutput = quoteData.estimatedAmountOut;
4173
+ if (!estimatedOutput || parseFloat(estimatedOutput) <= 0) {
4174
+ throw new Error("Invalid swap quote - no output amount");
4175
+ }
4176
+ const depositAmount = (parseFloat(estimatedOutput) * 0.99).toString();
4177
+ setStatusMessage(`Preparing swap and deposit...`);
4178
+ const bundleActions = [
4179
+ {
4180
+ body: {
4181
+ actionType: "V2_SWAP",
4182
+ tokenIn: selectedToken,
4183
+ tokenOut: "USDC",
4184
+ amountIn: amount,
4185
+ maxSlippagePercent: 1
4186
+ }
4187
+ },
4188
+ {
4189
+ body: {
4190
+ actionType: "V2_MANAGE",
4191
+ action: "DEPOSIT",
4192
+ venue: { type: "AAVE", token: "USDC" },
4193
+ amount: depositAmount
4194
+ }
4195
+ }
4196
+ ];
4197
+ const prepareResponse = await fetch("/api/compass/bundle/prepare", {
4198
+ method: "POST",
4199
+ headers: { "Content-Type": "application/json" },
4200
+ body: JSON.stringify({
4201
+ owner: address,
4202
+ chain: CHAIN_ID,
4203
+ actions: bundleActions
4204
+ })
4205
+ });
4206
+ if (!prepareResponse.ok) {
4207
+ const errorData = await prepareResponse.json();
4208
+ throw new Error(errorData.error || "Failed to prepare bundle");
4209
+ }
4210
+ const { eip712, normalizedTypes, domain, message } = await prepareResponse.json();
4211
+ setStatusMessage("Please sign the transaction...");
4212
+ const signature = await signTypedData({
4213
+ domain,
4214
+ types: normalizedTypes,
4215
+ primaryType: "SafeTx",
4216
+ message
4217
+ });
4218
+ setStatusMessage("Executing swap and deposit...");
4219
+ const executeResponse = await fetch("/api/compass/bundle/execute", {
4220
+ method: "POST",
4221
+ headers: { "Content-Type": "application/json" },
4222
+ body: JSON.stringify({
4223
+ owner: address,
4224
+ eip712,
4225
+ signature,
4226
+ chain: CHAIN_ID
4227
+ })
4228
+ });
4229
+ if (!executeResponse.ok) {
4230
+ const errorData = await executeResponse.json();
4231
+ throw new Error(errorData.error || "Failed to execute bundle");
4232
+ }
4233
+ const result = await executeResponse.json();
4234
+ txHash = result.txHash;
4235
+ } else {
4236
+ setStatusMessage(`Preparing withdraw and swap...`);
4237
+ const bundleActions = [
4238
+ {
4239
+ body: {
4240
+ actionType: "V2_MANAGE",
4241
+ action: "WITHDRAW",
4242
+ venue: { type: "AAVE", token: "USDC" },
4243
+ amount
4244
+ }
4245
+ },
4246
+ {
4247
+ body: {
4248
+ actionType: "V2_SWAP",
4249
+ tokenIn: "USDC",
4250
+ tokenOut: selectedToken,
4251
+ amountIn: amount,
4252
+ maxSlippagePercent: 1
4253
+ }
4254
+ }
4255
+ ];
4256
+ const prepareResponse = await fetch("/api/compass/bundle/prepare", {
4257
+ method: "POST",
4258
+ headers: { "Content-Type": "application/json" },
4259
+ body: JSON.stringify({
4260
+ owner: address,
4261
+ chain: CHAIN_ID,
4262
+ actions: bundleActions
4263
+ })
4264
+ });
4265
+ if (!prepareResponse.ok) {
4266
+ const errorData = await prepareResponse.json();
4267
+ throw new Error(errorData.error || "Failed to prepare bundle");
4268
+ }
4269
+ const { eip712, normalizedTypes, domain, message } = await prepareResponse.json();
4270
+ setStatusMessage("Please sign the transaction...");
4271
+ const signature = await signTypedData({
4272
+ domain,
4273
+ types: normalizedTypes,
4274
+ primaryType: "SafeTx",
4275
+ message
4276
+ });
4277
+ setStatusMessage("Executing withdraw and swap...");
4278
+ const executeResponse = await fetch("/api/compass/bundle/execute", {
4279
+ method: "POST",
4280
+ headers: { "Content-Type": "application/json" },
4281
+ body: JSON.stringify({
4282
+ owner: address,
4283
+ eip712,
4284
+ signature,
4285
+ chain: CHAIN_ID
4286
+ })
4287
+ });
4288
+ if (!executeResponse.ok) {
4289
+ const errorData = await executeResponse.json();
4290
+ throw new Error(errorData.error || "Failed to execute bundle");
4291
+ }
4292
+ const result = await executeResponse.json();
4293
+ txHash = result.txHash;
4294
+ }
4295
+ } else {
4296
+ setStatusMessage(isDeposit ? "Preparing deposit..." : "Preparing withdrawal...");
4297
+ const prepareEndpoint = isDeposit ? "/api/compass/deposit/prepare" : "/api/compass/withdraw/prepare";
4298
+ const executeEndpoint = isDeposit ? "/api/compass/deposit/execute" : "/api/compass/withdraw/execute";
4299
+ const prepareResponse = await fetch(prepareEndpoint, {
4300
+ method: "POST",
4301
+ headers: { "Content-Type": "application/json" },
4302
+ body: JSON.stringify({
4303
+ owner: address,
4304
+ chain: CHAIN_ID,
4305
+ venueType: "AAVE",
4306
+ token: "USDC",
4307
+ amount
4308
+ })
4309
+ });
4310
+ if (!prepareResponse.ok) {
4311
+ const errData = await prepareResponse.json();
4312
+ throw new Error(errData.error || "Failed to prepare transaction");
4313
+ }
4314
+ const prepareData = await prepareResponse.json();
4315
+ setStatusMessage("Please sign the transaction...");
4316
+ const signature = await signTypedData({
4317
+ domain: prepareData.domain,
4318
+ types: prepareData.normalizedTypes,
4319
+ primaryType: "SafeTx",
4320
+ message: prepareData.message
4321
+ });
4322
+ setStatusMessage("Executing transaction...");
4323
+ const executeResponse = await fetch(executeEndpoint, {
4324
+ method: "POST",
4325
+ headers: { "Content-Type": "application/json" },
4326
+ body: JSON.stringify({
4327
+ owner: address,
4328
+ chain: CHAIN_ID,
4329
+ eip712: prepareData.eip712,
4330
+ signature
4331
+ })
4332
+ });
4333
+ if (!executeResponse.ok) {
4334
+ const errData = await executeResponse.json();
4335
+ throw new Error(errData.error || "Transaction failed");
4336
+ }
4337
+ const result = await executeResponse.json();
4338
+ txHash = result.txHash;
4195
4339
  }
4196
- const { txHash } = await executeResponse.json();
4197
4340
  setStatusMessage("Transaction successful!");
4198
4341
  setAmount("");
4199
4342
  queryClient.invalidateQueries({ queryKey: ["earnAccountBalances"] });
@@ -4208,7 +4351,7 @@ function EarnAccount({
4208
4351
  borrowApy: null,
4209
4352
  tvlUsd: null
4210
4353
  };
4211
- if (activeTab === "deposit") {
4354
+ if (isDeposit) {
4212
4355
  onSupply?.(marketData, amount, txHash || "");
4213
4356
  } else {
4214
4357
  onWithdraw?.(marketData, amount, txHash || "");
@@ -4221,7 +4364,7 @@ function EarnAccount({
4221
4364
  setIsProcessing(false);
4222
4365
  }
4223
4366
  };
4224
- const maxAmount = activeTab === "deposit" ? available : depositedBalance;
4367
+ const maxAmount = activeTab === "deposit" ? parseFloat(selectedTokenBalance) : depositedBalance;
4225
4368
  if (marketQuery.isLoading) {
4226
4369
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center py-16", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { size: 32, className: "animate-spin", style: { color: "var(--compass-color-primary)" } }) });
4227
4370
  }
@@ -4276,28 +4419,39 @@ function EarnAccount({
4276
4419
  padding: compact ? "var(--compass-spacing-card)" : "calc(var(--compass-spacing-card) * 1.25)"
4277
4420
  },
4278
4421
  children: [
4279
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", style: { gap: "calc(var(--compass-spacing-unit) * 0.5)" }, children: [
4280
- /* @__PURE__ */ jsxRuntime.jsx(
4281
- "span",
4282
- {
4283
- className: "text-xs font-medium uppercase tracking-wide",
4284
- style: { color: "var(--compass-color-text-tertiary)" },
4285
- children: "Total Balance"
4286
- }
4287
- ),
4288
- /* @__PURE__ */ jsxRuntime.jsx(
4289
- "span",
4290
- {
4291
- className: "font-bold",
4292
- style: {
4293
- color: "var(--compass-color-text)",
4294
- fontSize: compact ? "2rem" : "2.5rem",
4295
- lineHeight: "1"
4296
- },
4297
- children: formatCurrency(totalBalance)
4298
- }
4299
- )
4300
- ] }),
4422
+ /* @__PURE__ */ jsxRuntime.jsxs(
4423
+ "button",
4424
+ {
4425
+ onClick: () => setIsBalancesModalOpen(true),
4426
+ className: "flex flex-col text-left w-full transition-opacity hover:opacity-80",
4427
+ style: { gap: "calc(var(--compass-spacing-unit) * 0.5)" },
4428
+ children: [
4429
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", style: { gap: "calc(var(--compass-spacing-unit) * 0.5)" }, children: [
4430
+ /* @__PURE__ */ jsxRuntime.jsx(
4431
+ "span",
4432
+ {
4433
+ className: "text-xs font-medium uppercase tracking-wide",
4434
+ style: { color: "var(--compass-color-text-tertiary)" },
4435
+ children: "Total Balance"
4436
+ }
4437
+ ),
4438
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { size: 12, style: { color: "var(--compass-color-text-tertiary)" } })
4439
+ ] }),
4440
+ /* @__PURE__ */ jsxRuntime.jsx(
4441
+ "span",
4442
+ {
4443
+ className: "font-bold",
4444
+ style: {
4445
+ color: "var(--compass-color-text)",
4446
+ fontSize: compact ? "2rem" : "2.5rem",
4447
+ lineHeight: "1"
4448
+ },
4449
+ children: formatCurrency(totalBalance)
4450
+ }
4451
+ )
4452
+ ]
4453
+ }
4454
+ ),
4301
4455
  /* @__PURE__ */ jsxRuntime.jsx(
4302
4456
  "div",
4303
4457
  {
@@ -4354,32 +4508,6 @@ function EarnAccount({
4354
4508
  ]
4355
4509
  }
4356
4510
  ),
4357
- showPnL && earnings > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
4358
- "div",
4359
- {
4360
- className: "flex items-center justify-between",
4361
- style: {
4362
- backgroundColor: "var(--compass-color-surface)",
4363
- border: "1px solid var(--compass-color-border)",
4364
- borderRadius: "var(--compass-border-radius-lg)",
4365
- padding: spacing
4366
- },
4367
- children: [
4368
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--compass-color-text-secondary)" }, children: "Total Earnings" }),
4369
- /* @__PURE__ */ jsxRuntime.jsxs(
4370
- "span",
4371
- {
4372
- className: "font-semibold",
4373
- style: { color: "var(--compass-color-success)" },
4374
- children: [
4375
- "+",
4376
- formatCurrency(earnings)
4377
- ]
4378
- }
4379
- )
4380
- ]
4381
- }
4382
- ),
4383
4511
  userPosition?.pnl && /* @__PURE__ */ jsxRuntime.jsx(
4384
4512
  PnLSummary,
4385
4513
  {
@@ -4412,6 +4540,7 @@ function EarnAccount({
4412
4540
  {
4413
4541
  onClick: () => {
4414
4542
  setActiveTab("deposit");
4543
+ setSelectedToken("USDC");
4415
4544
  setError(null);
4416
4545
  },
4417
4546
  className: "flex-1 flex items-center justify-center font-medium transition-all",
@@ -4435,6 +4564,7 @@ function EarnAccount({
4435
4564
  {
4436
4565
  onClick: () => {
4437
4566
  setActiveTab("withdraw");
4567
+ setSelectedToken("USDC");
4438
4568
  setError(null);
4439
4569
  },
4440
4570
  className: "flex-1 flex items-center justify-center font-medium transition-all",
@@ -4460,22 +4590,15 @@ function EarnAccount({
4460
4590
  /* @__PURE__ */ jsxRuntime.jsxs(
4461
4591
  "div",
4462
4592
  {
4463
- className: "flex items-center",
4593
+ className: "flex items-center flex-wrap",
4464
4594
  style: {
4465
4595
  backgroundColor: "var(--compass-color-surface)",
4466
4596
  border: "1px solid var(--compass-color-border)",
4467
4597
  borderRadius: "var(--compass-border-radius-lg)",
4468
- padding: spacing
4598
+ padding: spacing,
4599
+ gap: "calc(var(--compass-spacing-unit) * 0.5)"
4469
4600
  },
4470
4601
  children: [
4471
- /* @__PURE__ */ jsxRuntime.jsx(
4472
- "span",
4473
- {
4474
- className: "font-medium",
4475
- style: { color: "var(--compass-color-text-secondary)", fontSize: compact ? "1.25rem" : "1.5rem", marginRight: "calc(var(--compass-spacing-unit) * 0.25)" },
4476
- children: "$"
4477
- }
4478
- ),
4479
4602
  /* @__PURE__ */ jsxRuntime.jsx(
4480
4603
  "input",
4481
4604
  {
@@ -4488,9 +4611,64 @@ function EarnAccount({
4488
4611
  placeholder: "0.00",
4489
4612
  disabled: isProcessing,
4490
4613
  className: "flex-1 font-medium bg-transparent outline-none",
4491
- style: { color: "var(--compass-color-text)", fontSize: compact ? "1.25rem" : "1.5rem" }
4614
+ style: { color: "var(--compass-color-text)", fontSize: compact ? "1.25rem" : "1.5rem", minWidth: 0 }
4492
4615
  }
4493
4616
  ),
4617
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", style: { flexShrink: 0 }, children: [
4618
+ /* @__PURE__ */ jsxRuntime.jsxs(
4619
+ "button",
4620
+ {
4621
+ onClick: () => setIsTokenDropdownOpen(!isTokenDropdownOpen),
4622
+ disabled: isProcessing,
4623
+ className: "flex items-center font-medium",
4624
+ style: {
4625
+ backgroundColor: "var(--compass-color-surface-elevated, var(--compass-color-background))",
4626
+ border: "1px solid var(--compass-color-border)",
4627
+ color: "var(--compass-color-text)",
4628
+ borderRadius: "var(--compass-border-radius-md)",
4629
+ padding: "calc(var(--compass-spacing-unit) * 0.5) calc(var(--compass-spacing-unit) * 0.75)",
4630
+ gap: "calc(var(--compass-spacing-unit) * 0.25)",
4631
+ fontSize: compact ? "0.875rem" : "1rem"
4632
+ },
4633
+ children: [
4634
+ selectedToken,
4635
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { size: compact ? 14 : 16, style: { color: "var(--compass-color-text-tertiary)" } })
4636
+ ]
4637
+ }
4638
+ ),
4639
+ isTokenDropdownOpen && /* @__PURE__ */ jsxRuntime.jsx(
4640
+ "div",
4641
+ {
4642
+ className: "absolute right-0 mt-1 z-10",
4643
+ style: {
4644
+ backgroundColor: "var(--compass-color-surface)",
4645
+ border: "1px solid var(--compass-color-border)",
4646
+ borderRadius: "var(--compass-border-radius-lg)",
4647
+ boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
4648
+ minWidth: "100px"
4649
+ },
4650
+ children: SUPPORTED_TOKENS.map((token) => /* @__PURE__ */ jsxRuntime.jsx(
4651
+ "button",
4652
+ {
4653
+ onClick: () => {
4654
+ setSelectedToken(token);
4655
+ setIsTokenDropdownOpen(false);
4656
+ setError(null);
4657
+ },
4658
+ className: "w-full text-left font-medium transition-colors",
4659
+ style: {
4660
+ padding: "calc(var(--compass-spacing-unit) * 0.5) calc(var(--compass-spacing-unit) * 0.75)",
4661
+ color: token === selectedToken ? "var(--compass-color-primary)" : "var(--compass-color-text)",
4662
+ backgroundColor: token === selectedToken ? "var(--compass-color-primary-muted, rgba(99, 102, 241, 0.1))" : "transparent",
4663
+ fontSize: compact ? "0.875rem" : "1rem"
4664
+ },
4665
+ children: token
4666
+ },
4667
+ token
4668
+ ))
4669
+ }
4670
+ )
4671
+ ] }),
4494
4672
  /* @__PURE__ */ jsxRuntime.jsx(
4495
4673
  "button",
4496
4674
  {
@@ -4502,7 +4680,8 @@ function EarnAccount({
4502
4680
  border: "1px solid var(--compass-color-border)",
4503
4681
  color: "var(--compass-color-text-secondary)",
4504
4682
  borderRadius: "var(--compass-border-radius-md)",
4505
- padding: "calc(var(--compass-spacing-unit) * 0.5) calc(var(--compass-spacing-unit) * 0.75)"
4683
+ padding: "calc(var(--compass-spacing-unit) * 0.5) calc(var(--compass-spacing-unit) * 0.75)",
4684
+ flexShrink: 0
4506
4685
  },
4507
4686
  children: "MAX"
4508
4687
  }
@@ -4510,9 +4689,30 @@ function EarnAccount({
4510
4689
  ]
4511
4690
  }
4512
4691
  ),
4692
+ needsActionSwap && /* @__PURE__ */ jsxRuntime.jsxs(
4693
+ "div",
4694
+ {
4695
+ className: "flex items-center text-sm",
4696
+ style: {
4697
+ backgroundColor: "var(--compass-color-primary-muted, rgba(99, 102, 241, 0.1))",
4698
+ color: "var(--compass-color-primary)",
4699
+ borderRadius: "var(--compass-border-radius-lg)",
4700
+ padding: "calc(var(--compass-spacing-unit) * 0.5) calc(var(--compass-spacing-unit) * 0.75)",
4701
+ gap: "calc(var(--compass-spacing-unit) * 0.5)"
4702
+ },
4703
+ children: [
4704
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRight, { size: 14 }),
4705
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: activeTab === "deposit" ? `Swaps ${selectedToken} to USDC, then deposits` : `Withdraws USDC, then swaps to ${selectedToken}` })
4706
+ ]
4707
+ }
4708
+ ),
4513
4709
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", style: { padding: "0 calc(var(--compass-spacing-unit) * 0.25)" }, children: [
4514
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm", style: { color: "var(--compass-color-text-tertiary)" }, children: "Available balance" }),
4515
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", style: { color: "var(--compass-color-text-secondary)" }, children: formatCurrency(maxAmount) })
4710
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm", style: { color: "var(--compass-color-text-tertiary)" }, children: activeTab === "deposit" ? `Available ${selectedToken}` : "Available to withdraw" }),
4711
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-medium", style: { color: "var(--compass-color-text-secondary)" }, children: [
4712
+ formatAmount2(maxAmount),
4713
+ " ",
4714
+ activeTab === "deposit" ? selectedToken : "USDC"
4715
+ ] })
4516
4716
  ] })
4517
4717
  ] }),
4518
4718
  error && /* @__PURE__ */ jsxRuntime.jsx(
@@ -4545,7 +4745,7 @@ function EarnAccount({
4545
4745
  children: isProcessing ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center justify-center", style: { gap: "calc(var(--compass-spacing-unit) * 0.5)" }, children: [
4546
4746
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { size: compact ? 16 : 20, className: "animate-spin" }),
4547
4747
  "Processing..."
4548
- ] }) : activeTab === "deposit" ? "Deposit funds" : "Withdraw funds"
4748
+ ] }) : needsActionSwap ? activeTab === "deposit" ? `Swap & Deposit` : `Withdraw & Swap` : activeTab === "deposit" ? "Deposit funds" : "Withdraw funds"
4549
4749
  }
4550
4750
  ),
4551
4751
  statusMessage && !error && /* @__PURE__ */ jsxRuntime.jsx(
@@ -4666,7 +4866,7 @@ function EarnAccount({
4666
4866
  }
4667
4867
  )
4668
4868
  ] }),
4669
- needsSwap && /* @__PURE__ */ jsxRuntime.jsxs(
4869
+ needsFundSwap && /* @__PURE__ */ jsxRuntime.jsxs(
4670
4870
  "div",
4671
4871
  {
4672
4872
  className: "flex items-center gap-2 p-3 rounded-xl text-sm",
@@ -4778,7 +4978,7 @@ function EarnAccount({
4778
4978
  "Processing..."
4779
4979
  ] }) : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center justify-center gap-2", children: [
4780
4980
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDownLeft, { size: 20 }),
4781
- needsSwap ? `Swap ${fundToken} & Transfer` : "Transfer to Savings"
4981
+ needsFundSwap ? `Swap ${fundToken} & Transfer` : "Transfer to Savings"
4782
4982
  ] })
4783
4983
  }
4784
4984
  ),
@@ -4792,6 +4992,115 @@ function EarnAccount({
4792
4992
  )
4793
4993
  ] })
4794
4994
  }
4995
+ ),
4996
+ /* @__PURE__ */ jsxRuntime.jsx(
4997
+ ActionModal,
4998
+ {
4999
+ isOpen: isBalancesModalOpen,
5000
+ onClose: () => setIsBalancesModalOpen(false),
5001
+ title: "Balance Breakdown",
5002
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
5003
+ balancesQuery.data?.balances && Object.keys(balancesQuery.data.balances).length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5004
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
5005
+ /* @__PURE__ */ jsxRuntime.jsx(
5006
+ "span",
5007
+ {
5008
+ className: "text-xs font-medium uppercase tracking-wide",
5009
+ style: { color: "var(--compass-color-text-tertiary)" },
5010
+ children: "Available in Account"
5011
+ }
5012
+ ),
5013
+ Object.entries(balancesQuery.data.balances).map(([symbol, data]) => /* @__PURE__ */ jsxRuntime.jsxs(
5014
+ "div",
5015
+ {
5016
+ className: "flex items-center justify-between p-3 rounded-lg",
5017
+ style: {
5018
+ backgroundColor: "var(--compass-color-surface)",
5019
+ border: "1px solid var(--compass-color-border)"
5020
+ },
5021
+ children: [
5022
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", style: { color: "var(--compass-color-text)" }, children: symbol }),
5023
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-end", children: [
5024
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono font-medium", style: { color: "var(--compass-color-text)" }, children: formatAmount2(data.balance) }),
5025
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs", style: { color: "var(--compass-color-text-tertiary)" }, children: formatCurrency(data.usdValue) })
5026
+ ] })
5027
+ ]
5028
+ },
5029
+ symbol
5030
+ ))
5031
+ ] }),
5032
+ /* @__PURE__ */ jsxRuntime.jsxs(
5033
+ "div",
5034
+ {
5035
+ className: "flex items-center justify-between pt-2",
5036
+ style: { borderTop: "1px solid var(--compass-color-border)" },
5037
+ children: [
5038
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm", style: { color: "var(--compass-color-text-secondary)" }, children: "Subtotal" }),
5039
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold", style: { color: "var(--compass-color-text)" }, children: formatCurrency(earnAccountTotalUsd) })
5040
+ ]
5041
+ }
5042
+ )
5043
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
5044
+ "div",
5045
+ {
5046
+ className: "text-center py-4",
5047
+ style: { color: "var(--compass-color-text-tertiary)" },
5048
+ children: "No tokens in account"
5049
+ }
5050
+ ),
5051
+ depositedBalance > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 pt-2", style: { borderTop: "1px solid var(--compass-color-border)" }, children: [
5052
+ /* @__PURE__ */ jsxRuntime.jsx(
5053
+ "span",
5054
+ {
5055
+ className: "text-xs font-medium uppercase tracking-wide",
5056
+ style: { color: "var(--compass-color-text-tertiary)" },
5057
+ children: "Earning Interest (Aave)"
5058
+ }
5059
+ ),
5060
+ /* @__PURE__ */ jsxRuntime.jsxs(
5061
+ "div",
5062
+ {
5063
+ className: "flex items-center justify-between p-3 rounded-lg",
5064
+ style: {
5065
+ backgroundColor: "var(--compass-color-success-muted, rgba(34, 197, 94, 0.1))",
5066
+ border: "1px solid var(--compass-color-success)"
5067
+ },
5068
+ children: [
5069
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
5070
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrendingUp, { size: 16, style: { color: "var(--compass-color-success)" } }),
5071
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", style: { color: "var(--compass-color-text)" }, children: "USDC" })
5072
+ ] }),
5073
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-end", children: [
5074
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono font-medium", style: { color: "var(--compass-color-text)" }, children: formatAmount2(depositedBalance) }),
5075
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs", style: { color: "var(--compass-color-success)" }, children: [
5076
+ formatAPY3(market?.supplyApy || null),
5077
+ "% APY"
5078
+ ] })
5079
+ ] })
5080
+ ]
5081
+ }
5082
+ )
5083
+ ] }),
5084
+ /* @__PURE__ */ jsxRuntime.jsxs(
5085
+ "div",
5086
+ {
5087
+ className: "flex items-center justify-between pt-3 mt-2",
5088
+ style: { borderTop: "2px solid var(--compass-color-border)" },
5089
+ children: [
5090
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold", style: { color: "var(--compass-color-text)" }, children: "Total Balance" }),
5091
+ /* @__PURE__ */ jsxRuntime.jsx(
5092
+ "span",
5093
+ {
5094
+ className: "font-bold text-xl",
5095
+ style: { color: "var(--compass-color-text)" },
5096
+ children: formatCurrency(totalBalance)
5097
+ }
5098
+ )
5099
+ ]
5100
+ }
5101
+ )
5102
+ ] })
5103
+ }
4795
5104
  )
4796
5105
  ] });
4797
5106
  }