@compass-labs/widgets 0.1.11 → 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 () => {
@@ -3904,8 +3909,21 @@ function EarnAccount({
3904
3909
  return {
3905
3910
  balance: usdcPosition.balance || "0",
3906
3911
  pnl: usdcPosition.pnl ? {
3907
- totalPnl: usdcPosition.pnl.totalPnl || "0"
3908
- } : void 0
3912
+ unrealizedPnl: usdcPosition.pnl.unrealizedPnl || "0",
3913
+ realizedPnl: usdcPosition.pnl.realizedPnl || "0",
3914
+ totalPnl: usdcPosition.pnl.totalPnl || "0",
3915
+ totalDeposited: usdcPosition.pnl.totalDeposited || "0"
3916
+ } : void 0,
3917
+ deposits: (usdcPosition.deposits || []).map((d) => ({
3918
+ amount: d.inputAmount || d.amount || "0",
3919
+ blockNumber: d.blockNumber || 0,
3920
+ txHash: d.transactionHash || d.txHash || ""
3921
+ })),
3922
+ withdrawals: (usdcPosition.withdrawals || []).map((w) => ({
3923
+ amount: w.outputAmount || w.amount || "0",
3924
+ blockNumber: w.blockNumber || 0,
3925
+ txHash: w.transactionHash || w.txHash || ""
3926
+ }))
3909
3927
  };
3910
3928
  },
3911
3929
  enabled: !!address,
@@ -3914,10 +3932,10 @@ function EarnAccount({
3914
3932
  const market = marketQuery.data;
3915
3933
  const userPosition = positionQuery.data;
3916
3934
  const depositedBalance = parseFloat(userPosition?.balance || "0");
3917
- const available = parseFloat(availableBalance);
3918
- const totalBalance = available + depositedBalance;
3919
- const earnings = parseFloat(userPosition?.pnl?.totalPnl || "0");
3920
- const needsSwap = fundToken !== "USDC";
3935
+ const earnAccountTotal = parseFloat(earnAccountTotalUsd);
3936
+ const totalBalance = earnAccountTotal + depositedBalance;
3937
+ const needsActionSwap = selectedToken !== "USDC";
3938
+ const needsFundSwap = fundToken !== "USDC";
3921
3939
  const ensureTokenApproval = async (token) => {
3922
3940
  setFundStatus(`Checking ${token} approval...`);
3923
3941
  const approveResponse = await fetch("/api/compass/transfer/approve", {
@@ -3987,7 +4005,7 @@ function EarnAccount({
3987
4005
  setFundError(null);
3988
4006
  try {
3989
4007
  await ensureTokenApproval(fundToken);
3990
- if (needsSwap) {
4008
+ if (needsFundSwap) {
3991
4009
  setFundStatus(`Preparing ${fundToken} transfer...`);
3992
4010
  const transferPrepareResponse = await fetch("/api/compass/transfer/prepare", {
3993
4011
  method: "POST",
@@ -4132,55 +4150,193 @@ function EarnAccount({
4132
4150
  } finally {
4133
4151
  setIsFunding(false);
4134
4152
  }
4135
- }, [address, fundAmount, fundToken, needsSwap, signTypedData, queryClient, balancesQuery]);
4153
+ }, [address, fundAmount, fundToken, needsFundSwap, signTypedData, queryClient, balancesQuery]);
4136
4154
  const handleAction = async () => {
4137
4155
  if (!market || !amount || parseFloat(amount) <= 0 || !address || !signTypedData) return;
4138
4156
  setIsProcessing(true);
4139
4157
  setError(null);
4140
- setStatusMessage(activeTab === "deposit" ? "Preparing deposit..." : "Preparing withdrawal...");
4158
+ const isDeposit = activeTab === "deposit";
4141
4159
  try {
4142
- const isDeposit = activeTab === "deposit";
4143
- const prepareEndpoint = isDeposit ? "/api/compass/deposit/prepare" : "/api/compass/withdraw/prepare";
4144
- const executeEndpoint = isDeposit ? "/api/compass/deposit/execute" : "/api/compass/withdraw/execute";
4145
- const prepareResponse = await fetch(prepareEndpoint, {
4146
- method: "POST",
4147
- headers: { "Content-Type": "application/json" },
4148
- body: JSON.stringify({
4149
- owner: address,
4150
- chain: CHAIN_ID,
4151
- venueType: "AAVE",
4152
- token: "USDC",
4153
- amount
4154
- })
4155
- });
4156
- if (!prepareResponse.ok) {
4157
- const errData = await prepareResponse.json();
4158
- throw new Error(errData.error || "Failed to prepare transaction");
4159
- }
4160
- const prepareData = await prepareResponse.json();
4161
- setStatusMessage("Please sign the transaction...");
4162
- const signature = await signTypedData({
4163
- domain: prepareData.domain,
4164
- types: prepareData.normalizedTypes,
4165
- primaryType: "SafeTx",
4166
- message: prepareData.message
4167
- });
4168
- setStatusMessage("Executing transaction...");
4169
- const executeResponse = await fetch(executeEndpoint, {
4170
- method: "POST",
4171
- headers: { "Content-Type": "application/json" },
4172
- body: JSON.stringify({
4173
- owner: address,
4174
- chain: CHAIN_ID,
4175
- eip712: prepareData.eip712,
4176
- signature
4177
- })
4178
- });
4179
- if (!executeResponse.ok) {
4180
- const errData = await executeResponse.json();
4181
- 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;
4182
4339
  }
4183
- const { txHash } = await executeResponse.json();
4184
4340
  setStatusMessage("Transaction successful!");
4185
4341
  setAmount("");
4186
4342
  queryClient.invalidateQueries({ queryKey: ["earnAccountBalances"] });
@@ -4195,7 +4351,7 @@ function EarnAccount({
4195
4351
  borrowApy: null,
4196
4352
  tvlUsd: null
4197
4353
  };
4198
- if (activeTab === "deposit") {
4354
+ if (isDeposit) {
4199
4355
  onSupply?.(marketData, amount, txHash || "");
4200
4356
  } else {
4201
4357
  onWithdraw?.(marketData, amount, txHash || "");
@@ -4208,7 +4364,7 @@ function EarnAccount({
4208
4364
  setIsProcessing(false);
4209
4365
  }
4210
4366
  };
4211
- const maxAmount = activeTab === "deposit" ? available : depositedBalance;
4367
+ const maxAmount = activeTab === "deposit" ? parseFloat(selectedTokenBalance) : depositedBalance;
4212
4368
  if (marketQuery.isLoading) {
4213
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)" } }) });
4214
4370
  }
@@ -4263,28 +4419,39 @@ function EarnAccount({
4263
4419
  padding: compact ? "var(--compass-spacing-card)" : "calc(var(--compass-spacing-card) * 1.25)"
4264
4420
  },
4265
4421
  children: [
4266
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", style: { gap: "calc(var(--compass-spacing-unit) * 0.5)" }, children: [
4267
- /* @__PURE__ */ jsxRuntime.jsx(
4268
- "span",
4269
- {
4270
- className: "text-xs font-medium uppercase tracking-wide",
4271
- style: { color: "var(--compass-color-text-tertiary)" },
4272
- children: "Total Balance"
4273
- }
4274
- ),
4275
- /* @__PURE__ */ jsxRuntime.jsx(
4276
- "span",
4277
- {
4278
- className: "font-bold",
4279
- style: {
4280
- color: "var(--compass-color-text)",
4281
- fontSize: compact ? "2rem" : "2.5rem",
4282
- lineHeight: "1"
4283
- },
4284
- children: formatCurrency(totalBalance)
4285
- }
4286
- )
4287
- ] }),
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
+ ),
4288
4455
  /* @__PURE__ */ jsxRuntime.jsx(
4289
4456
  "div",
4290
4457
  {
@@ -4341,32 +4508,22 @@ function EarnAccount({
4341
4508
  ]
4342
4509
  }
4343
4510
  ),
4344
- showPnL && earnings > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
4345
- "div",
4511
+ userPosition?.pnl && /* @__PURE__ */ jsxRuntime.jsx(
4512
+ PnLSummary,
4346
4513
  {
4347
- className: "flex items-center justify-between",
4348
- style: {
4349
- backgroundColor: "var(--compass-color-surface)",
4350
- border: "1px solid var(--compass-color-border)",
4351
- borderRadius: "var(--compass-border-radius-lg)",
4352
- padding: spacing
4353
- },
4354
- children: [
4355
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--compass-color-text-secondary)" }, children: "Total Earnings" }),
4356
- /* @__PURE__ */ jsxRuntime.jsxs(
4357
- "span",
4358
- {
4359
- className: "font-semibold",
4360
- style: { color: "var(--compass-color-success)" },
4361
- children: [
4362
- "+",
4363
- formatCurrency(earnings)
4364
- ]
4365
- }
4366
- )
4367
- ]
4514
+ pnl: userPosition.pnl,
4515
+ tokenSymbol: "USDC",
4516
+ tokenPrice: 1
4368
4517
  }
4369
4518
  ),
4519
+ userPosition?.deposits?.length || userPosition?.withdrawals?.length ? /* @__PURE__ */ jsxRuntime.jsx(
4520
+ TransactionHistory,
4521
+ {
4522
+ deposits: userPosition.deposits,
4523
+ withdrawals: userPosition.withdrawals,
4524
+ tokenSymbol: "USDC"
4525
+ }
4526
+ ) : null,
4370
4527
  /* @__PURE__ */ jsxRuntime.jsxs(
4371
4528
  "div",
4372
4529
  {
@@ -4383,6 +4540,7 @@ function EarnAccount({
4383
4540
  {
4384
4541
  onClick: () => {
4385
4542
  setActiveTab("deposit");
4543
+ setSelectedToken("USDC");
4386
4544
  setError(null);
4387
4545
  },
4388
4546
  className: "flex-1 flex items-center justify-center font-medium transition-all",
@@ -4406,6 +4564,7 @@ function EarnAccount({
4406
4564
  {
4407
4565
  onClick: () => {
4408
4566
  setActiveTab("withdraw");
4567
+ setSelectedToken("USDC");
4409
4568
  setError(null);
4410
4569
  },
4411
4570
  className: "flex-1 flex items-center justify-center font-medium transition-all",
@@ -4431,22 +4590,15 @@ function EarnAccount({
4431
4590
  /* @__PURE__ */ jsxRuntime.jsxs(
4432
4591
  "div",
4433
4592
  {
4434
- className: "flex items-center",
4593
+ className: "flex items-center flex-wrap",
4435
4594
  style: {
4436
4595
  backgroundColor: "var(--compass-color-surface)",
4437
4596
  border: "1px solid var(--compass-color-border)",
4438
4597
  borderRadius: "var(--compass-border-radius-lg)",
4439
- padding: spacing
4598
+ padding: spacing,
4599
+ gap: "calc(var(--compass-spacing-unit) * 0.5)"
4440
4600
  },
4441
4601
  children: [
4442
- /* @__PURE__ */ jsxRuntime.jsx(
4443
- "span",
4444
- {
4445
- className: "font-medium",
4446
- style: { color: "var(--compass-color-text-secondary)", fontSize: compact ? "1.25rem" : "1.5rem", marginRight: "calc(var(--compass-spacing-unit) * 0.25)" },
4447
- children: "$"
4448
- }
4449
- ),
4450
4602
  /* @__PURE__ */ jsxRuntime.jsx(
4451
4603
  "input",
4452
4604
  {
@@ -4459,9 +4611,64 @@ function EarnAccount({
4459
4611
  placeholder: "0.00",
4460
4612
  disabled: isProcessing,
4461
4613
  className: "flex-1 font-medium bg-transparent outline-none",
4462
- 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 }
4463
4615
  }
4464
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
+ ] }),
4465
4672
  /* @__PURE__ */ jsxRuntime.jsx(
4466
4673
  "button",
4467
4674
  {
@@ -4473,7 +4680,8 @@ function EarnAccount({
4473
4680
  border: "1px solid var(--compass-color-border)",
4474
4681
  color: "var(--compass-color-text-secondary)",
4475
4682
  borderRadius: "var(--compass-border-radius-md)",
4476
- 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
4477
4685
  },
4478
4686
  children: "MAX"
4479
4687
  }
@@ -4481,9 +4689,30 @@ function EarnAccount({
4481
4689
  ]
4482
4690
  }
4483
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
+ ),
4484
4709
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", style: { padding: "0 calc(var(--compass-spacing-unit) * 0.25)" }, children: [
4485
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm", style: { color: "var(--compass-color-text-tertiary)" }, children: "Available balance" }),
4486
- /* @__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
+ ] })
4487
4716
  ] })
4488
4717
  ] }),
4489
4718
  error && /* @__PURE__ */ jsxRuntime.jsx(
@@ -4516,7 +4745,7 @@ function EarnAccount({
4516
4745
  children: isProcessing ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center justify-center", style: { gap: "calc(var(--compass-spacing-unit) * 0.5)" }, children: [
4517
4746
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { size: compact ? 16 : 20, className: "animate-spin" }),
4518
4747
  "Processing..."
4519
- ] }) : activeTab === "deposit" ? "Deposit funds" : "Withdraw funds"
4748
+ ] }) : needsActionSwap ? activeTab === "deposit" ? `Swap & Deposit` : `Withdraw & Swap` : activeTab === "deposit" ? "Deposit funds" : "Withdraw funds"
4520
4749
  }
4521
4750
  ),
4522
4751
  statusMessage && !error && /* @__PURE__ */ jsxRuntime.jsx(
@@ -4637,7 +4866,7 @@ function EarnAccount({
4637
4866
  }
4638
4867
  )
4639
4868
  ] }),
4640
- needsSwap && /* @__PURE__ */ jsxRuntime.jsxs(
4869
+ needsFundSwap && /* @__PURE__ */ jsxRuntime.jsxs(
4641
4870
  "div",
4642
4871
  {
4643
4872
  className: "flex items-center gap-2 p-3 rounded-xl text-sm",
@@ -4749,7 +4978,7 @@ function EarnAccount({
4749
4978
  "Processing..."
4750
4979
  ] }) : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center justify-center gap-2", children: [
4751
4980
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDownLeft, { size: 20 }),
4752
- needsSwap ? `Swap ${fundToken} & Transfer` : "Transfer to Savings"
4981
+ needsFundSwap ? `Swap ${fundToken} & Transfer` : "Transfer to Savings"
4753
4982
  ] })
4754
4983
  }
4755
4984
  ),
@@ -4763,6 +4992,115 @@ function EarnAccount({
4763
4992
  )
4764
4993
  ] })
4765
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
+ }
4766
5104
  )
4767
5105
  ] });
4768
5106
  }