@spicenet-io/spiceflow-ui 4.18.1 → 4.18.2-cash.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -341,6 +341,30 @@ a failed application callback after the external action has confirmed.
341
341
  - `onSubmit` on `SpiceSupply`, `SpiceLock`, `SpiceDeposit` and the shared controller fires once when the user submits and the SDK accepts it, before any wallet prompt. Use it for "transaction in progress" feedback instead of listening for clicks on SDK buttons.
342
342
  - `max()` on the shared controller (`useSpiceSupply`, `useSpiceLock`) resolves the fee-aware Max for the selected source, or `null` when there is none or the action fixes its output. The host sets the result as the amount.
343
343
 
344
+ ### Combined Cash balance
345
+
346
+ `SpiceDeposit` opens a new Add cash flow by default, even when the embedded
347
+ wallet holds leftover funds. With combined Cash enabled, those funds remain
348
+ available to Cash actions.
349
+ Clients that still need the legacy incomplete-deposit prompt can set
350
+ `skipRecovery={false}`; it is no longer shown automatically from a wallet balance.
351
+
352
+ Set `combineSourceBalances: true` on `SpiceSupply`, `SpiceLock`, `useSpiceSupply`,
353
+ `useSpiceLock` or `useSpiceAction` to show a token in the embedded wallet and its
354
+ mapped escrow balance on the same chain as one row, and to fund an action from
355
+ both. It is off by default; without it, wallet and escrow balances stay separate
356
+ rows and each action spends only the selected row.
357
+
358
+ Routed actions use escrow first and deposit only the wallet shortfall. Actions
359
+ paid in place keep wallet funds where they are and withdraw only the escrow
360
+ shortfall. The reviewed quote fixes the amount taken from each balance, and both
361
+ are checked again before signing.
362
+
363
+ Custom presentations read `assets.selectable` and
364
+ `assets.getAvailableBalance(asset)`, which returns the combined amount in the
365
+ asset's raw units, or `undefined` while a balance cannot be verified. Pass the
366
+ same getter to `AssetSelector`. Each physical `Asset.balance` is unchanged.
367
+
344
368
  ### Native action review
345
369
 
346
370
  `SpiceSupply` displays the actual fee total for `feeOnlyAction` even when no
@@ -1,3 +1,3 @@
1
1
  "use client";
2
2
  (function(){if(typeof document==="undefined"||document.getElementById("spiceflow-styles"))return;var s=document.createElement("style");s.id="spiceflow-styles";s.textContent="@keyframes spiceflow-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@media (prefers-reduced-motion:reduce){*,:after,:before{animation-duration:.001ms!important;animation-iteration-count:1!important;scroll-behavior:auto!important;transition-duration:.001ms!important}}.spiceflow-focus-ring:focus-visible,[data-spiceflow-focus]:focus-visible{border-radius:4px;outline:2px solid currentColor;outline-offset:2px}@media (forced-colors:active){.spiceflow-focus-ring:focus-visible,[data-spiceflow-focus]:focus-visible{outline:2px solid Highlight}}.ibm-plex-mono-thin{font-weight:100}.ibm-plex-mono-extralight,.ibm-plex-mono-thin{font-family:IBM Plex Mono,monospace!important;font-style:normal}.ibm-plex-mono-extralight{font-weight:200}.ibm-plex-mono-light{font-weight:300}.ibm-plex-mono-light,.ibm-plex-mono-regular{font-family:IBM Plex Mono,monospace!important;font-style:normal}.ibm-plex-mono-regular{font-weight:400}.ibm-plex-mono-medium{font-weight:500}.ibm-plex-mono-medium,.ibm-plex-mono-semibold{font-family:IBM Plex Mono,monospace!important;font-style:normal}.ibm-plex-mono-semibold{font-weight:600}.ibm-plex-mono-bold{font-family:IBM Plex Mono,monospace!important;font-style:normal;font-weight:700}#privy-modal-content button{border-radius:6px;font-family:IBM Plex Mono,monospace!important;font-size:small;letter-spacing:-.5px;text-transform:uppercase}#privy-modal-content input{background:#fff;border-radius:6px;padding-top:5px!important}#privy-dialog-title{display:none!important;font-size:18px;padding-bottom:10px;padding-top:10px}.AppLogoContainer-sc-a206bd44-0{display:none}#privy-modal-content{background:var(--Neutral-0,#fafafa);border:6px solid var(--Neutral-1,#e9e9e9);box-shadow:inset 0 0 0 1px rgba(0,0,0,.15),0 330px 92px transparent,0 211px 84px rgba(0,0,0,.01),0 119px 71px rgba(0,0,0,.05),0 53px 53px rgba(0,0,0,.09),0 13px 29px rgba(0,0,0,.1);height:auto!important;padding-bottom:10px}.Subtitle-sc-ddbf22b4-4{font-size:12px;margin-top:-14px;opacity:.5}.StyledLink-sc-1c6127e5-0{background:none!important}.StyledLink-sc-c8577138-0,.login-method-button{font-family:IBM Plex Mono,monospace!important}.StyledLink-sc-c8577138-0{font-style:uppercase}#protected-by-privy{color:#000!important}";document.head.appendChild(s)})();
3
- import{P as g}from"./privy-C3vXoSsE.js";import"react/jsx-runtime";import"react";import"@spicenet-io/spiceflow-core";import"@tanstack/react-query";import"viem";import"@privy-io/react-auth";import"wagmi";import"viem/actions";export{g as PrivyLogin};
3
+ import{P as g}from"./privy-BzDs681Z.js";import"react/jsx-runtime";import"react";import"@spicenet-io/spiceflow-core";import"@tanstack/react-query";import"viem";import"@privy-io/react-auth";import"wagmi";import"viem/actions";export{g as PrivyLogin};
@@ -1,6 +1,14 @@
1
+ import { type Address } from "viem";
1
2
  import type { ChainBatch } from "../../../types/authorization";
2
3
  import type { SelectedAsset } from "../../../types/assets";
3
4
  import type { DepositModalProps, PostDepositContext } from "../../../types/deposit";
5
+ export declare function buildEscrowDepositCalls({ escrowAddress, tokenAddress, isNative, amount, gasFeeAmount, }: {
6
+ escrowAddress: Address;
7
+ tokenAddress: Address;
8
+ isNative: boolean;
9
+ amount: bigint;
10
+ gasFeeAmount: bigint;
11
+ }): ChainBatch["calls"];
4
12
  export declare function buildPostDepositContext({ sourceChainId, selectedAsset, destinationChainId, destinationTokenAddress, isCrossDenomination, convertedUsdAmount, }: {
5
13
  sourceChainId: number;
6
14
  selectedAsset: SelectedAsset;
@@ -5,11 +5,13 @@ import type { SelectedAsset } from "../../../types/assets";
5
5
  import type { ChainBatch } from "../../../types/authorization";
6
6
  import type { DestinationTokenConfig, PivotRoute, SpiceSupplyProps, SupplyBatchBuildOptions } from "../../../types/supply";
7
7
  import type { ResolvedExactOutputSwap } from "../../../utils/swapQuotes";
8
+ import { type CombinedSourceGroup } from "../../../utils/combinedSourceBalances";
8
9
  type EstimateFn = (chainBatches: ChainBatch[], tokenAddress: string, tokenTransferAmount: bigint, options?: ExecutionOptions) => Promise<FeeEstimateSummary>;
9
10
  export declare function getPivotEscrowAmount(sourceSwap: Pick<ResolvedSwap, "amountOutMinimum">, gasSkim: bigint): bigint;
10
11
  export declare function stripSpicenetFundingBatches(batches: ChainBatch[]): ChainBatch[];
11
12
  export declare function scaleTokenAmount(amount: bigint, fromDecimals: number, toDecimals: number): bigint;
12
13
  export interface BatchBuilderContext {
14
+ combinedSourceGroup?: CombinedSourceGroup;
13
15
  currentPaymentAmount: string;
14
16
  isFeeInclusiveInput?: boolean;
15
17
  feeOnlyAction?: boolean;
@@ -18,6 +18,7 @@ export declare function rankFeeFundingCandidates(args: {
18
18
  balances: Asset[];
19
19
  order?: FeeFundingLevel[];
20
20
  reserve?: FeePreviewContext["feeFundingReserve"];
21
+ reserves?: FeePreviewContext["feeFundingReserves"];
21
22
  }): Candidate[];
22
23
  export declare function quoteFeeFunding(ctx: FeePreviewContext, estimateFeePreview: (ctx: FeePreviewContext) => Promise<SupplyFeeQuote | null>): Promise<SupplyFeeQuote | null>;
23
24
  export declare function quoteFundedAction(ctx: FeePreviewContext, batch: BatchBuilderContext, estimate: (ctx: FeePreviewContext) => Promise<SupplyFeeQuote | null>, outputProceeds?: boolean): Promise<SupplyFeeQuote | null>;
@@ -13,6 +13,8 @@ type EstimateFn = (chainBatches: ChainBatch[], tokenAddress: string, tokenTransf
13
13
  type BuildPayBatchesFn = (options?: SupplyBatchBuildOptions) => Promise<ChainBatch[]>;
14
14
  type BuildSupplyBatchesFn = (options?: SupplyBatchBuildOptions) => Promise<ChainBatch[]>;
15
15
  export type SupplyFeeQuote = {
16
+ sourceAllocation?: import("../../../utils/combinedSourceBalances").CombinedSourceAllocation;
17
+ feeSourceAllocation?: import("../../../utils/combinedSourceBalances").CombinedSourceAllocation;
16
18
  externalGasReserve?: ExternalGasReserve;
17
19
  fundedFeeToken?: DestinationTokenConfig;
18
20
  actionDefinition?: Parameters<NonNullable<SupplyBatchBuildOptions["onActionCalls"]>>[0];
@@ -97,6 +99,18 @@ export declare function estimateSupplyMaxAmount(ctx: {
97
99
  feeExecutionMode: SpiceSupplyProps["feeExecutionMode"];
98
100
  }): Promise<string | null>;
99
101
  export interface FeePreviewContext {
102
+ combinedSourceGroup?: import("../../../utils/combinedSourceBalances").CombinedSourceGroup;
103
+ getCombinedSourceGroup?: (asset: Asset, reserve?: {
104
+ asset: Asset;
105
+ amount: bigint;
106
+ } | {
107
+ asset: Asset;
108
+ amount: bigint;
109
+ }[]) => import("../../../utils/combinedSourceBalances").CombinedSourceGroup | undefined;
110
+ feeFundingReserves?: {
111
+ asset: Asset;
112
+ amount: bigint;
113
+ }[];
100
114
  externalGasRecipient?: Address;
101
115
  externalGasCalls?: (plan: SupplyFeeQuote) => Promise<ChainBatch["calls"]>;
102
116
  externalGasReserve?: ExternalGasReserve;
@@ -27,6 +27,7 @@ export declare function useSpiceEmbeddedWithdraw(params: {
27
27
  policyExcluded?: boolean;
28
28
  } | null;
29
29
  assets: {
30
+ getAvailableBalance: (asset: Asset) => bigint | undefined;
30
31
  selectable: Asset[];
31
32
  displayAssets: Asset[];
32
33
  filteredSpiceAssets: Asset[];
@@ -88,6 +89,7 @@ export declare function useSpiceEmbeddedWithdraw(params: {
88
89
  error: string | null;
89
90
  };
90
91
  amount: {
92
+ availableBalance: bigint | undefined;
91
93
  sourceRequiredAmount: bigint | null;
92
94
  parsed: number;
93
95
  isInsufficientBalance: boolean;
@@ -2,7 +2,7 @@ import { type Address } from "viem";
2
2
  import type { Asset, SelectedAsset } from "../types/assets";
3
3
  import type { DestinationTokenConfig, SpiceSupplyProps } from "../types/supply";
4
4
  export type SpiceActionSource = Asset;
5
- export interface UseSpiceActionOptions extends Pick<SpiceSupplyProps, "amountDirection" | "actionProceeds" | "feeFunding"> {
5
+ export interface UseSpiceActionOptions extends Pick<SpiceSupplyProps, "amountDirection" | "actionProceeds" | "feeFunding" | "combineSourceBalances"> {
6
6
  destinationToken: DestinationTokenConfig | undefined;
7
7
  recipient?: Address;
8
8
  buildActionCalls: SpiceSupplyProps["buildActionCalls"];
@@ -17,6 +17,8 @@ export interface UseSpiceActionOptions extends Pick<SpiceSupplyProps, "amountDir
17
17
  }
18
18
  export declare function useSpiceAction({ amount, enabled, ...options }: UseSpiceActionOptions): {
19
19
  sources: Asset[];
20
+ getAvailableBalance: (asset: Asset) => bigint | undefined;
21
+ availableBalance: bigint | undefined;
20
22
  selectedAsset: SelectedAsset | null;
21
23
  setSelectedAsset: import("react").Dispatch<import("react").SetStateAction<SelectedAsset | null>>;
22
24
  selectAsset: (asset: Asset) => void;
@@ -1,6 +1,8 @@
1
1
  import { type CreateActionRequest } from "@spicenet-io/spiceflow-core";
2
2
  import type { LimitOrderInput, PreparedLimitOrder } from "../types/limitOrders";
3
- export declare function useSpiceLimitOrders(): {
3
+ export declare function useSpiceLimitOrders(options?: {
4
+ combineSourceBalances?: boolean;
5
+ }): {
4
6
  prepareOrder: (input: LimitOrderInput) => Promise<PreparedLimitOrder>;
5
7
  signOrder: (prepared: PreparedLimitOrder) => Promise<CreateActionRequest>;
6
8
  placeOrder: (request: CreateActionRequest) => Promise<import("..").LimitOrder>;
@@ -1,6 +1,6 @@
1
1
  import type { Asset, SelectedAsset } from "../types/assets";
2
2
  import type { SpiceLockModalProps } from "../types/lock";
3
- export interface UseSpiceLockParams extends Pick<SpiceLockModalProps, "lockBatches" | "lockChainId" | "lockTokenSymbol" | "lockTokenLogoURI" | "destinationTokenAddress" | "destinationTokenDecimals" | "beneficiary" | "onSubmit" | "onLockSuccess" | "onLockError" | "buildSpicenetBatch" | "feeFunding"> {
3
+ export interface UseSpiceLockParams extends Pick<SpiceLockModalProps, "lockBatches" | "lockChainId" | "lockTokenSymbol" | "lockTokenLogoURI" | "destinationTokenAddress" | "destinationTokenDecimals" | "beneficiary" | "onSubmit" | "onLockSuccess" | "onLockError" | "buildSpicenetBatch" | "feeFunding" | "combineSourceBalances"> {
4
4
  enabled: boolean;
5
5
  selectedAsset: SelectedAsset | null;
6
6
  recoveryKey?: string;
@@ -52,6 +52,7 @@ export declare function useSpiceLock(params: UseSpiceLockParams): {
52
52
  policyExcluded?: boolean;
53
53
  } | null;
54
54
  assets: {
55
+ getAvailableBalance: (asset: Asset) => bigint | undefined;
55
56
  selectable: Asset[];
56
57
  displayAssets: Asset[];
57
58
  filteredSpiceAssets: Asset[];
@@ -85,6 +86,7 @@ export declare function useSpiceLock(params: UseSpiceLockParams): {
85
86
  error: string | null;
86
87
  };
87
88
  amount: {
89
+ availableBalance: bigint | undefined;
88
90
  sourceRequiredAmount: bigint | null;
89
91
  parsed: number;
90
92
  isInsufficientBalance: boolean;
@@ -5,7 +5,7 @@ import { type SupplyFeeQuote } from "../components/SpiceSupply/lib/feePreview";
5
5
  import type { Asset, SelectedAsset } from "../types/assets";
6
6
  import type { DestinationTokenDeclaration, SpiceSupplyProps } from "../types/supply";
7
7
  import type { FeePreview } from "../types/ui";
8
- export interface UseSpiceSupplyParams extends Pick<SpiceSupplyProps, "sourceChains" | "supportedSourceAssets" | "buildActionCalls" | "feeExecutionMode" | "buildSpicenetBatch" | "onPayExecute" | "resolveExactOutputSwap" | "amountDirection" | "onSubmit" | "onSuccess" | "onError" | "additionalSourceTokens" | "includeExternalWalletAssets" | "includeCrossChainEmbeddedAssets" | "feeOnlyAction" | "actionInput" | "actionProceeds" | "feeFunding" | "maxSlippage" | "resolveInputSwap" | "feeFundingReserve" | "beforeSubmit" | "submitDisabled"> {
8
+ export interface UseSpiceSupplyParams extends Pick<SpiceSupplyProps, "sourceChains" | "supportedSourceAssets" | "buildActionCalls" | "feeExecutionMode" | "buildSpicenetBatch" | "onPayExecute" | "resolveExactOutputSwap" | "amountDirection" | "onSubmit" | "onSuccess" | "onError" | "additionalSourceTokens" | "includeExternalWalletAssets" | "includeCrossChainEmbeddedAssets" | "combineSourceBalances" | "feeOnlyAction" | "actionInput" | "actionProceeds" | "feeFunding" | "maxSlippage" | "resolveInputSwap" | "feeFundingReserve" | "beforeSubmit" | "submitDisabled"> {
9
9
  quotedInclusivePlatformFee?: boolean;
10
10
  enabled?: boolean;
11
11
  destinationToken: DestinationTokenDeclaration | undefined;
@@ -29,6 +29,7 @@ export declare function useSpiceSupply(params: UseSpiceSupplyParams): {
29
29
  policyExcluded?: boolean;
30
30
  } | null;
31
31
  assets: {
32
+ getAvailableBalance: (asset: Asset) => bigint | undefined;
32
33
  selectable: Asset[];
33
34
  displayAssets: Asset[];
34
35
  filteredSpiceAssets: Asset[];
@@ -90,6 +91,7 @@ export declare function useSpiceSupply(params: UseSpiceSupplyParams): {
90
91
  error: string | null;
91
92
  };
92
93
  amount: {
94
+ availableBalance: bigint | undefined;
93
95
  sourceRequiredAmount: bigint | null;
94
96
  parsed: number;
95
97
  isInsufficientBalance: boolean;