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