@spicenet-io/spiceflow-ui 4.10.0-dev.20260909.6 → 4.10.0-dev.20260916.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +148 -28
  2. package/dist/auth-privy.cjs.js +1 -1
  3. package/dist/auth-privy.js +1 -1
  4. package/dist/components/AccountDisplay/parts/AccountCustomSection.d.ts +1 -1
  5. package/dist/components/AccountDisplay/parts/AccountHeader.d.ts +0 -1
  6. package/dist/components/AccountDisplay/parts/AccountIdleBalances.d.ts +3 -6
  7. package/dist/components/AccountDisplay/parts/AccountPanel.d.ts +3 -4
  8. package/dist/components/AccountDisplay/types.d.ts +17 -3
  9. package/dist/components/SpiceDeposit/lib/escrowCredit.d.ts +2 -0
  10. package/dist/components/SpiceLock/lib/helpers.d.ts +1 -0
  11. package/dist/components/SpiceSupply/lib/actionProceeds.d.ts +9 -2
  12. package/dist/components/SpiceSupply/lib/buildBatches.d.ts +22 -14
  13. package/dist/components/SpiceSupply/lib/executors.d.ts +11 -20
  14. package/dist/components/SpiceSupply/lib/externalAction.d.ts +3 -61
  15. package/dist/components/SpiceSupply/lib/feeConversion.d.ts +15 -7
  16. package/dist/components/SpiceSupply/lib/feeFunding.d.ts +21 -0
  17. package/dist/components/SpiceSupply/lib/feeOnlyExecution.d.ts +1 -1
  18. package/dist/components/SpiceSupply/lib/feePreview.d.ts +52 -16
  19. package/dist/components/SpiceSupply/lib/payFundingBatches.d.ts +2 -1
  20. package/dist/components/SpiceWithdraw/lib/helpers.d.ts +1 -2
  21. package/dist/components/SpiceWithdraw/lib/useEmbeddedWithdraw.d.ts +112 -5
  22. package/dist/components/SpiceWithdraw/parts/WithdrawBalanceCardHeader.d.ts +2 -3
  23. package/dist/components/SpiceWithdraw/parts/WithdrawDestinationCard.d.ts +4 -2
  24. package/dist/components/SpiceWithdraw/parts/WithdrawDetailsPanel.d.ts +4 -2
  25. package/dist/components/SpiceWithdraw/parts/WithdrawSourceCard.d.ts +4 -2
  26. package/dist/components/StatusDisplay/parts/StatusPanel.d.ts +2 -2
  27. package/dist/execution/directExecution.d.ts +11 -0
  28. package/dist/execution/escrowCredit.d.ts +18 -0
  29. package/dist/execution/externalWalletClient.d.ts +5 -0
  30. package/dist/execution/fundEmbeddedWallet.d.ts +9 -1
  31. package/dist/execution/pollIntentStep.d.ts +1 -0
  32. package/dist/execution/sourceFunding.d.ts +11 -28
  33. package/dist/execution/transactionReceipt.d.ts +1 -0
  34. package/dist/hooks/index.d.ts +9 -8
  35. package/dist/hooks/useDestinationToken.d.ts +20 -0
  36. package/dist/hooks/useInventoryResource.d.ts +21 -0
  37. package/dist/hooks/useIsUserWhitelisted.d.ts +12 -12
  38. package/dist/hooks/useLockWalletAssets.d.ts +1 -1
  39. package/dist/hooks/useSpiceAction.d.ts +46 -0
  40. package/dist/hooks/useSpiceAssets.d.ts +4 -1
  41. package/dist/hooks/useSpiceExecution.d.ts +6 -7
  42. package/dist/hooks/useSpiceInventory.d.ts +31 -0
  43. package/dist/hooks/useSpiceLock.d.ts +115 -0
  44. package/dist/hooks/useSpiceLockQuote.d.ts +35 -3
  45. package/dist/hooks/useSpiceRollupPrices.d.ts +9 -0
  46. package/dist/hooks/useSpiceSupply.d.ts +62 -28
  47. package/dist/hooks/useSupplyAssets.d.ts +23 -18
  48. package/dist/hooks/useSupplyQuote.d.ts +19 -5
  49. package/dist/hooks/useWalletBalances.d.ts +10 -4
  50. package/dist/index.cjs.js +14 -27
  51. package/dist/index.d.ts +53 -47
  52. package/dist/index.js +14 -27
  53. package/dist/privy-BJzR0dpS.js +2 -0
  54. package/dist/privy-CRczPd8g.js +2 -0
  55. package/dist/providers/SpiceFlowProvider.d.ts +5 -3
  56. package/dist/types/assets.d.ts +12 -4
  57. package/dist/types/lock.d.ts +7 -3
  58. package/dist/types/supply.d.ts +44 -4
  59. package/dist/types/withdraw.d.ts +8 -7
  60. package/dist/utils/actionDefinition.d.ts +2 -0
  61. package/dist/utils/amounts.d.ts +2 -0
  62. package/dist/utils/assetDisplay.d.ts +8 -0
  63. package/dist/utils/assetPolicy.d.ts +16 -0
  64. package/dist/utils/chains/index.d.ts +4 -4
  65. package/dist/utils/crossChainRouter/liquidityVenues.d.ts +11 -7
  66. package/dist/utils/crossChainRouter/uniV3.d.ts +9 -5
  67. package/dist/utils/directWithdraw.d.ts +0 -4
  68. package/dist/utils/fees.d.ts +6 -1
  69. package/dist/utils/inventoryStore.d.ts +27 -0
  70. package/dist/utils/prices/providerPrices.d.ts +12 -0
  71. package/dist/utils/relayer/index.d.ts +2 -3
  72. package/dist/utils/rollupBalances.d.ts +4 -0
  73. package/dist/utils/theme.d.ts +3 -3
  74. package/dist/utils/tokenResolution.d.ts +27 -2
  75. package/package.json +7 -2
  76. package/dist/components/AccountDisplay/tokenPrices.d.ts +0 -7
  77. package/dist/components/SpiceLock/lib/executors.d.ts +0 -76
  78. package/dist/components/SpiceSupply/lib/controlledFunding.d.ts +0 -54
  79. package/dist/components/SpiceSupply/lib/sourceConversion.d.ts +0 -13
  80. package/dist/components/SpiceWithdraw/parts/WithdrawBalancePopover.d.ts +0 -15
  81. package/dist/hooks/useDirectWithdraw.d.ts +0 -12
  82. package/dist/hooks/useSourceFundingConversion.d.ts +0 -22
  83. package/dist/privy-CFe_UmVo.js +0 -2
  84. package/dist/privy-oeYmzC_W.js +0 -2
  85. package/dist/utils/crossChainRouter/sourceFundingQuote.d.ts +0 -58
package/README.md CHANGED
@@ -2,39 +2,78 @@
2
2
 
3
3
  A React component library for building DeFi swap interfaces with multi-chain support.
4
4
 
5
- ## Installation
5
+ ## Version and migration
6
+
7
+ The shared inventory/action refactor merged in PR #103. As checked September 14, 2026,
8
+ `4.9.6-consistency.16` is published under `consistency`; npm `latest` remains `4.9.5`.
9
+ Check the actual registry tag and client pin before adopting it. See
10
+ [CONSISTENCY-MIGRATION.md](CONSISTENCY-MIGRATION.md) for migration breaks and candidate-specific evidence.
11
+ A merged source change does not publish npm or upgrade consuming apps.
12
+
13
+ The unified action controller in this source restores direct external execution for a wallet asset matching the destination token and chain. Clients keep one action definition across direct and routed execution. See [the migration guide](CONSISTENCY-MIGRATION.md#unreleased-direct-external-execution-in-the-unified-controller) for scope, gas, recovery and the unpublished release status.
14
+
15
+ ## Installation and provider setup
16
+
17
+ Select an approved exact version, preserving the app's dependency-age and security policies:
6
18
 
7
19
  ```bash
8
- npm install @spicenet-io/spiceflow-ui
20
+ bun add --exact @spicenet-io/spiceflow-ui@4.9.6-consistency.16
9
21
  ```
10
22
 
11
- ## Usage
23
+ The example is a prerelease selection, not a stable recommendation or a policy bypass.
24
+ Reuse compatible host-owned Privy, wagmi and QueryClient providers. Read the exact
25
+ package's peer dependencies; do not replace the wallet stack as part of a version bump.
12
26
 
13
27
  ```tsx
14
- import { SwapWidget, SpiceFlowProvider } from "@spicenet-io/spiceflow-ui";
28
+ import { SpiceFlowProvider } from "@spicenet-io/spiceflow-ui";
15
29
  import "@spicenet-io/spiceflow-ui/styles.css";
16
30
 
17
- function App() {
18
- return (
19
- <SpiceFlowProvider
20
- provider="privy"
21
- privyAppId="your-privy-app-id"
22
- dynamicEnvironmentId="your-env-id"
23
- paraApiKey="your-para-api-key"
24
- paraAppName="your-app-name"
25
- >
26
- <SwapWidget
27
- swapBatches={swapBatches}
28
- supportedChains={[1, 137, 42161]}
29
- showSlippageSettings={true}
30
- enableFlipSwap={true}
31
- theme="dark"
32
- />
33
- </SpiceFlowProvider>
34
- );
35
- }
31
+ // Inside the host's existing WagmiProvider → QueryClientProvider → PrivyProvider stack.
32
+ <SpiceFlowProvider
33
+ provider="privy"
34
+ network="mainnet"
35
+ nativeChainId={8453}
36
+ rpcOverrides={clientRpcUrls}
37
+ >
38
+ {children}
39
+ </SpiceFlowProvider>;
36
40
  ```
37
41
 
42
+ Configure Privy credentials/policy on the host's `PrivyProvider`. Supply client RPCs
43
+ for every enabled source, conversion and destination chain, and keep the SDK/wallet
44
+ chain sets aligned. Wallet-library transports alone do not configure SDK reads;
45
+ there is no internal RPC fallback. Keep private credentials out of browser bundles.
46
+
47
+ ## Integration ownership
48
+
49
+ - Use stock components when they fit the approved UI; use `useSpiceSupply` for custom
50
+ action forms. `useSpiceLock` and legacy `useSpiceAction` delegate to that controller.
51
+ - Supply destination metadata, protocol `buildActionCalls` or destination-only
52
+ `lockBatches`, beneficiary semantics, and awaited application updates. The SDK owns
53
+ inventory, routing, Max, fees, accepted plans, funding, execution and recovery.
54
+ - For custom holdings, use `useSpiceInventory` and `assetPositionId`. Keep raw balance,
55
+ default visibility and spend eligibility separate. Preserve rows during refresh;
56
+ stale/failed balances cannot authorize spending, and confirmed zero wins.
57
+ - In this unreleased source, eligible External-mode actions with a matching wallet token
58
+ and destination chain execute directly from the external signer, without embedded funding.
59
+ Other assets/chains still use embedded funding and the shared routed executor.
60
+ `onPayExecute` and `onLockExecute` remain blocked. `actionExecution.wallet: "external"`
61
+ makes the external wallet the caller of the host's calls: a matching-token source executes
62
+ directly; any other ERC20 input source routes the delivery to that wallet first, then the
63
+ wallet signs the calls (nothing persisted between the two phases). Verify contract
64
+ caller/beneficiary and NFT receiver behavior.
65
+ Published `.16` does not contain this restoration.
66
+ - Supply `input` adds fees to principal; `input-inclusive` uses a total budget; Pay
67
+ `output` fixes the destination amount. Use controller readiness/Max/status instead of
68
+ constructing an executor context or duplicating fee arithmetic in the host.
69
+ - Use controller recovery for uncertain funding and `retryFinalization()` for failed
70
+ application updates after settlement. Preserve original host terms across reload.
71
+ - Deposit and rollup Withdraw retain distinct execution semantics while sharing
72
+ inventory/policy. Account wallet withdrawal uses the fee-only Supply path.
73
+
74
+ Inventory isolation does not establish support for simultaneous differently configured
75
+ providers: underlying quote/execution transports still have global state.
76
+
38
77
  ## Liquidity venues
39
78
 
40
79
  When a flow has to swap on the destination chain, the SDK quotes every liquidity
@@ -108,12 +147,93 @@ it becomes a `protocol` everyone can name.
108
147
 
109
148
  ## Development
110
149
 
111
- ### Fee-Charging Intent Flows
150
+ ### Rollup balance pricing
151
+
152
+ Rollup USD values use the host-configured RPC provider's pricing capability when the balance API has no valid value. The built-in account panel and withdrawal modal enable this while open; custom `useSpiceAssets` consumers can opt in with `priceEnabled`. Quantities arrive independently. Lookups follow receipt mappings, prefer `nativeChainId`, and fall back to other supported chains with a configured Alchemy endpoint. Explicit account `tokenPrices` overrides still take precedence over provider quotes.
153
+
154
+ Wallet discovery and rollup balances share a one-minute quote cache. Pricing polls only while the view is open and the page is visible. A failed refresh can retain a marked stale quote for up to five minutes; an unavailable quote displays `—`. No extra key, internal RPC, or symbol-based ERC-20 price fallback is used.
155
+
156
+ ### Host-supplied token logos
157
+
158
+ `AccountDisplay.tokenLogos` maps a token symbol to a logo URL, the same key
159
+ shape `tokenPrices` uses. A discovered embedded-wallet balance falls back to
160
+ it when the RPC provider returns no logo, which is what happens for a token
161
+ that is not in the chain's configured token list. Provider metadata still
162
+ wins when it has a logo.
163
+
164
+ ```tsx
165
+ <AccountDisplay tokenLogos={{ TOKEN: tokenLogoUrl }} />
166
+ ```
167
+
168
+ ### Withdraw from an account balance
169
+
170
+ `AccountDisplay.onWithdrawClick` receives the rollup receipt-token ID when a
171
+ user clicks Withdraw on an idle rollup balance. The main Withdraw button calls
172
+ it without an ID. Pass the ID to `SpiceWithdraw.initialSourceAssetId` to open
173
+ the existing modal with that asset selected; the user chooses the destination
174
+ network inside the modal. Existing callbacks that take no arguments continue
175
+ to work.
176
+
177
+ ```tsx
178
+ const [withdrawOpen, setWithdrawOpen] = useState(false);
179
+ const [withdrawAssetId, setWithdrawAssetId] = useState<string>();
180
+
181
+ <AccountDisplay
182
+ onWithdrawClick={(receiptTokenId) => {
183
+ setWithdrawAssetId(receiptTokenId);
184
+ setWithdrawOpen(true);
185
+ }}
186
+ />
187
+ <SpiceWithdraw
188
+ isOpen={withdrawOpen}
189
+ onClose={() => setWithdrawOpen(false)}
190
+ initialSourceAssetId={withdrawAssetId}
191
+ buildSpicenetBatch={buildSpicenetWithdrawalBatch}
192
+ />
193
+ ```
194
+
195
+ Keep the integration's existing withdrawal batch builder and callbacks.
196
+ `initialSourceAssetId` selects a current balance by ID; it does not supply a
197
+ cached balance or change the receipt's supported withdrawal routes.
198
+
199
+ ### Action Fee Readiness
200
+
201
+ - Routed Supply, Pay and Lock actions must surface fee estimation before enabling submission.
202
+ - Eligible direct external actions still require an accepted plan but charge no Spicenet fee. Network gas remains payable in the external wallet; native Max reserves gas.
203
+ - Deposit gas and rollup withdrawal semantics remain distinct from action intent fees. Preserve their existing quote/readiness requirements.
204
+ - Account wallet withdrawal is a fee-only Supply action. Do not bypass its fee/readiness gates based on the label "withdraw".
205
+ - Custom actions use the shared controller's `canExecute`; an available balance or old quote alone is insufficient.
206
+
207
+ ### Fee funding for fee-only actions
208
+
209
+ - A fee-only action (`feeOnlyAction`) runs on what the executing wallet already holds; the SDK funds only the Spicenet fees, in the chain's fee token (`destinationToken`).
210
+ - With no `selectedAsset`, the SDK picks the fee source and the user is never asked. The action's input (`actionInput`) comes first, then its proceeds (`actionProceeds`), so the fee stays inside the action the user submitted; then other balances: same-chain embedded wallet before rollup, and within each, balances already in the fee token before balances that swap into it. The first source that simulates and covers the fee wins and is reported as `fees.fundingSource`; a source whose swap has no route, or that cannot cover the fee within slippage, is skipped for the next.
211
+ - Declare `actionInput` for every token the action consumes and honour the amount passed to `buildActionCalls`: when fees come from an input, the action is built for the remainder. Declare `actionProceeds` for a token the action leaves in the wallet. Both are optional; with neither, only balances can pay. Omit `actionProceeds` when the output is delivered to another owner.
212
+ - `feeFunding` overrides the level order per transaction, for example `["proceeds", "input", "balance"]`; the order inside the balance level is fixed. An empty list leaves the choice to the host's `selectedAsset`.
213
+ - A `selectedAsset` on a fee-only action is an explicit host choice and funds the fee from that balance as before.
214
+
215
+ ### Updating and releasing
216
+
217
+ Change the shared inventory/policy/controller owner and audit affected stock and custom
218
+ consumers. Use the central team's `workflow`, `ui-quality` and `shared/sdk.md` guidance;
219
+ keep skills in the skills repo rather than copying them here.
220
+
221
+ Read the central `shared/client-design-decisions.md` register before an upgrade. Map
222
+ applicable decision IDs to affected consumers and regression scenarios, and report each
223
+ result with exact candidate evidence. Preserve agreed behavior and ownership even when
224
+ types compile; a deliberate change needs an explicit product decision and migration plan.
225
+
226
+ Run focused regressions, `bun test`, `bun run typecheck` and `bun run build`, then validate
227
+ affected consumer builds and rendered/financial behavior on the exact candidate. Record
228
+ package identity, configuration, acceptance coverage and untested cases. Earlier candidate
229
+ results do not automatically apply to newer main or a new client.
112
230
 
113
- - `SpiceSupply` and `SpicePay` are fee-charging intent-execution flows and must surface fee estimation before enabling submission.
114
- - `SpiceLockModal` is also a fee-charging intent-execution flow and must surface fee estimation before enabling submission.
115
- - `SpiceDeposit` and `SpiceWithdraw` are treated as non-fee actions and should not use the fee-estimation gating UX.
116
- - Rule of thumb: every intent-execution flow other than deposit/withdraw should assume fees apply and should gate CTA enablement on successful fee estimation.
231
+ If core/API changes are needed, resolve those dependencies before their UI/app consumers.
232
+ An inventory/controller-only change does not inherently require a core release. After
233
+ explicit release authorization, publish a prerelease with a non-`latest` tag, verify its
234
+ registry artifact, and pin/test that exact version in each adopting app. Stable promotion,
235
+ client deployment and docs targeting are separate release decisions. This refactor adds
236
+ no automatic npm publishing.
117
237
 
118
238
  ### Building the Library
119
239
 
@@ -1,2 +1,2 @@
1
1
  "use client";
2
- "use strict";const r=require("./privy-CFe_UmVo.js");require("react/jsx-runtime"),require("react"),require("@spicenet-io/spiceflow-core"),require("viem"),require("viem/actions"),require("@privy-io/react-auth"),require("wagmi"),require("@tanstack/react-query"),exports.PrivyLogin=r.PrivyLogin;
2
+ "use strict";const r=require("./privy-BJzR0dpS.js");require("react/jsx-runtime"),require("react"),require("@spicenet-io/spiceflow-core"),require("@tanstack/react-query"),require("viem"),require("@privy-io/react-auth"),require("wagmi"),require("viem/actions"),exports.PrivyLogin=r.PrivyLogin;
@@ -1,2 +1,2 @@
1
1
  "use client";
2
- import{P as g}from"./privy-oeYmzC_W.js";import"react/jsx-runtime";import"react";import"@spicenet-io/spiceflow-core";import"viem";import"viem/actions";import"@privy-io/react-auth";import"wagmi";import"@tanstack/react-query";export{g as PrivyLogin};
2
+ import{P as g}from"./privy-CRczPd8g.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,6 @@
1
1
  import React from "react";
2
- import { CustomSection } from "../types";
3
2
  import type { ResolvedDarkPalette } from "../../../utils/theme";
3
+ import { CustomSection } from "../types";
4
4
  interface AccountCustomSectionProps {
5
5
  section: CustomSection;
6
6
  dk: ResolvedDarkPalette;
@@ -5,7 +5,6 @@ interface AccountHeaderProps {
5
5
  status: "active" | "inactive";
6
6
  statusLabel?: string;
7
7
  totalUsdValue: number;
8
- hasUnpricedAssets?: boolean;
9
8
  breakdownSubtitle: string;
10
9
  showUsdSummary?: boolean;
11
10
  address?: string;
@@ -1,11 +1,7 @@
1
1
  import React from "react";
2
- import { SpiceAsset } from "../types";
3
2
  import type { ResolvedDarkPalette } from "../../../utils/theme";
4
- export interface DirectWithdrawState {
5
- key: string;
6
- step: "pending" | "error";
7
- message?: string;
8
- }
3
+ import type { DirectWithdrawState } from "../types";
4
+ import { SpiceAsset } from "../types";
9
5
  interface AccountIdleBalancesProps {
10
6
  spiceAssets: SpiceAsset[];
11
7
  loading: boolean;
@@ -14,6 +10,7 @@ interface AccountIdleBalancesProps {
14
10
  canDirectWithdraw?: boolean;
15
11
  onDirectWithdraw?: (asset: SpiceAsset) => void;
16
12
  directWithdrawState?: DirectWithdrawState | null;
13
+ onWithdrawClick?: (receiptTokenId?: string) => void;
17
14
  }
18
15
  export declare const AccountIdleBalances: React.NamedExoticComponent<AccountIdleBalancesProps>;
19
16
  export {};
@@ -1,14 +1,13 @@
1
1
  import React from "react";
2
- import { SpiceAsset, CustomSection, AccountNotice } from "../types";
3
2
  import { VerifiedPendingDeposit } from "../../../hooks/usePendingDeposit";
4
3
  import type { ResolvedDarkPalette } from "../../../utils/theme";
5
- import { type DirectWithdrawState } from "./AccountIdleBalances";
4
+ import type { DirectWithdrawState } from "../types";
5
+ import { AccountNotice, CustomSection, SpiceAsset } from "../types";
6
6
  interface AccountPanelProps {
7
7
  appName: string;
8
8
  status: "active" | "inactive";
9
9
  statusLabel?: string;
10
10
  totalUsdValue: number;
11
- hasUnpricedAssets?: boolean;
12
11
  breakdownSubtitle: string;
13
12
  showUsdSummary?: boolean;
14
13
  address?: string;
@@ -18,7 +17,7 @@ interface AccountPanelProps {
18
17
  customSections: CustomSection[];
19
18
  notice?: AccountNotice | null;
20
19
  onDepositClick?: () => void;
21
- onWithdrawClick?: () => void;
20
+ onWithdrawClick?: (receiptTokenId?: string) => void;
22
21
  depositDisabled?: boolean;
23
22
  onCompleteDeposit?: (deposit: VerifiedPendingDeposit) => void;
24
23
  primaryColor?: string;
@@ -1,12 +1,13 @@
1
- import type { CustomStyles } from "../../types/theme";
2
- import { VerifiedPendingDeposit } from "../../hooks/usePendingDeposit";
3
1
  import type React from "react";
2
+ import { VerifiedPendingDeposit } from "../../hooks/usePendingDeposit";
3
+ import type { CustomStyles } from "../../types/theme";
4
4
  export interface CustomSectionItem {
5
5
  tokenSymbol: string;
6
6
  tokenLogoURI?: string;
7
7
  label: React.ReactNode;
8
8
  displayValue: string;
9
9
  valueColor?: "green" | "red" | "default";
10
+ onClick?: () => void;
10
11
  }
11
12
  export interface CustomSection {
12
13
  title: string;
@@ -14,6 +15,9 @@ export interface CustomSection {
14
15
  totalValue?: number;
15
16
  }
16
17
  export interface SpiceAsset {
18
+ owner?: string;
19
+ location?: "external" | "embedded" | "rollup";
20
+ positionId?: string;
17
21
  tokenAddress: string;
18
22
  tokenSymbol: string;
19
23
  tokenDisplaySymbol?: string;
@@ -24,7 +28,9 @@ export interface SpiceAsset {
24
28
  balance: string;
25
29
  balanceFormatted: number;
26
30
  usdValue: number;
31
+ priceStatus?: "fresh" | "stale" | "unavailable";
27
32
  logoURI?: string;
33
+ receiptTokenId?: string;
28
34
  directWithdraw?: boolean;
29
35
  }
30
36
  export interface BreakdownLabel {
@@ -42,15 +48,23 @@ export interface AccountDisplayProps {
42
48
  customSections?: CustomSection[];
43
49
  extraAssets?: SpiceAsset[];
44
50
  tokenPrices?: Record<string, number>;
51
+ tokenLogos?: Record<string, string>;
45
52
  breakdownLabels?: BreakdownLabel[];
46
53
  notice?: AccountNotice | null;
47
54
  styles?: CustomStyles;
48
55
  dark?: boolean;
49
56
  onDepositSuccess?: () => void;
50
57
  onDepositClick?: () => void;
51
- onWithdrawClick?: () => void;
58
+ onWithdrawClick?: (receiptTokenId?: string) => void;
52
59
  onCompleteDeposit?: (deposit: VerifiedPendingDeposit) => void;
53
60
  showModeToggle?: boolean;
54
61
  defaultMode?: "7702" | "non7702";
55
62
  showUsdSummary?: boolean;
63
+ alwaysShowEmbeddedIdle?: boolean;
64
+ showDisconnect?: boolean;
65
+ }
66
+ export interface DirectWithdrawState {
67
+ key: string;
68
+ step: "pending" | "error";
69
+ message?: string;
56
70
  }
@@ -0,0 +1,2 @@
1
+ import type { Asset } from "../../../types/assets";
2
+ export declare function isEscrowCreditable(asset: Pick<Asset, "address" | "chainId" | "isNative">): boolean;
@@ -3,6 +3,7 @@ import { type FeeEstimateSummary, type ResolvedSwap } from "@spicenet-io/spicefl
3
3
  import type { ChainAuthorization, ChainBatch } from "../../../types/authorization";
4
4
  import type { Asset } from "../../../types/assets";
5
5
  export declare function isDirectLockSource(asset: Asset, lockChainId: number): boolean;
6
+ export declare function isInPlaceLockSource(asset: Asset, lockChainId: number): boolean;
6
7
  export declare function composeLockSwapBatches(batches: ChainBatch[], params: {
7
8
  chainId: number;
8
9
  recipient: Address;
@@ -1,7 +1,12 @@
1
1
  import { type Address } from "viem";
2
2
  import type { ChainBatch } from "../../../types/authorization";
3
- import type { SpiceSupplyProps } from "../../../types/supply";
3
+ import type { SpiceSupplyProps, SupplyBatchBuildOptions } from "../../../types/supply";
4
4
  import type { SupplyFeeQuote } from "./feePreview";
5
+ export declare class InsufficientFeeFundingBalanceError extends Error {
6
+ readonly requiredAmount: bigint;
7
+ readonly balance: bigint;
8
+ constructor(requiredAmount: bigint, balance: bigint);
9
+ }
5
10
  export declare function appendProceedsFees(batches: ChainBatch[], owner: Address, token: Address, gas: bigint, platform: bigint): ChainBatch[];
6
11
  export declare function simulateProceedsBatch(batches: ChainBatch[], owner: Address, token: Address, signal?: AbortSignal, platformFeeMaximum?: bigint): Promise<bigint>;
7
12
  export declare function estimateProceedsFunding(args: {
@@ -10,5 +15,7 @@ export declare function estimateProceedsFunding(args: {
10
15
  token: Address;
11
16
  signal?: AbortSignal;
12
17
  baseline: () => Promise<SupplyFeeQuote | null>;
13
- buildBatches: (amount: bigint) => Promise<ChainBatch[]>;
18
+ buildBatches: (amount: bigint, options?: SupplyBatchBuildOptions) => Promise<ChainBatch[]>;
19
+ fundShortfall?: boolean;
20
+ actionAmountFor?: (fee: bigint) => bigint;
14
21
  }): Promise<SupplyFeeQuote>;
@@ -1,31 +1,27 @@
1
+ import type { FeeEstimateSummary, ResolvedSwap } from "@spicenet-io/spiceflow-core";
1
2
  import { type Address } from "viem";
2
- import type { ResolvedSwap } from "@spicenet-io/spiceflow-core";
3
- import type { ChainBatch } from "../../../types/authorization";
3
+ import type { ExecutionOptions } from "../../../hooks/useSpiceExecution";
4
4
  import type { SelectedAsset } from "../../../types/assets";
5
- import type { SpiceSupplyProps, SupplyBatchBuildOptions } from "../../../types/supply";
5
+ import type { ChainBatch } from "../../../types/authorization";
6
+ import type { PivotRoute, SpiceSupplyProps, SupplyBatchBuildOptions } from "../../../types/supply";
6
7
  import type { ResolvedExactOutputSwap } from "../../../utils/swapQuotes";
7
- import type { ExecutionOptions } from "../../../hooks/useSpiceExecution";
8
- import type { FeeEstimateSummary } from "@spicenet-io/spiceflow-core";
9
8
  type EstimateFn = (chainBatches: ChainBatch[], tokenAddress: string, tokenTransferAmount: bigint, options?: ExecutionOptions) => Promise<FeeEstimateSummary>;
10
- export declare function buildEmbeddedEscrowDepositBatch(token: Address, amount: bigint, chainId: number): ChainBatch;
11
- export declare function isExternalSource(asset: SelectedAsset["asset"] | null | undefined, isNon7702: boolean): boolean;
9
+ export declare function getPivotEscrowAmount(sourceSwap: Pick<ResolvedSwap, "amountOutMinimum">, gasSkim: bigint): bigint;
12
10
  export declare function stripSpicenetFundingBatches(batches: ChainBatch[]): ChainBatch[];
13
11
  export declare function scaleTokenAmount(amount: bigint, fromDecimals: number, toDecimals: number): bigint;
14
- export declare function resolveSupplyTokenDecimals(asset: SelectedAsset["asset"], destination: SpiceSupplyProps["destinationToken"], token: Address): Promise<number>;
15
12
  export interface BatchBuilderContext {
16
13
  currentPaymentAmount: string;
14
+ isFeeInclusiveInput?: boolean;
15
+ feeOnlyAction?: boolean;
16
+ swapInputAmount?: bigint | null;
17
17
  destinationToken: SpiceSupplyProps["destinationToken"];
18
18
  embeddedWalletAddress: string | null | undefined;
19
19
  providerEmbeddedAddress: string | null | undefined;
20
20
  externalWalletAddress: string | null | undefined;
21
21
  address: string | null | undefined;
22
22
  recipient?: Address;
23
- swapOutputRecipient?: Address;
24
23
  isNon7702: boolean;
25
24
  isPayMode: boolean;
26
- isFeeInclusiveInput?: boolean;
27
- swapInputAmount?: bigint | null;
28
- feeOnlyAction?: boolean;
29
25
  resolvedChainId: number;
30
26
  buildActionCalls: SpiceSupplyProps["buildActionCalls"];
31
27
  feeExecutionMode: SpiceSupplyProps["feeExecutionMode"];
@@ -33,12 +29,24 @@ export interface BatchBuilderContext {
33
29
  selectedAsset: SelectedAsset | null;
34
30
  needsSwap: boolean;
35
31
  resolvedSwap: ResolvedSwap | null;
32
+ resolveInputSwap?: (amountIn: bigint, selectedSwap?: ResolvedSwap) => Promise<ResolvedSwap>;
36
33
  exactOutputSwap: ResolvedExactOutputSwap | null;
37
34
  quoteAmountOut: bigint | null;
38
35
  resolvedTokenIn: Address | null;
36
+ sourceSwap?: ResolvedSwap | null;
37
+ sourceExactOutputSwap?: ResolvedExactOutputSwap | null;
38
+ resolveSourceExactOutputSwap?: (amountOut: bigint) => Promise<ResolvedExactOutputSwap>;
39
+ pivot?: PivotRoute | null;
39
40
  requestTimestampMs?: number;
40
41
  }
41
- export declare function buildPayChainBatches(ctx: BatchBuilderContext, options?: SupplyBatchBuildOptions): Promise<ChainBatch[]>;
42
- export declare function buildSupplyChainBatches(ctx: BatchBuilderContext, options?: SupplyBatchBuildOptions): Promise<ChainBatch[]>;
42
+ export declare function isPivotPay(ctx: Pick<BatchBuilderContext, "isPayMode" | "selectedAsset" | "resolvedChainId" | "pivot">): ctx is typeof ctx & {
43
+ pivot: PivotRoute;
44
+ };
45
+ export declare function isPivotSupply(ctx: Pick<BatchBuilderContext, "isPayMode" | "selectedAsset" | "resolvedChainId" | "sourceSwap" | "pivot">): ctx is typeof ctx & {
46
+ sourceSwap: ResolvedSwap;
47
+ pivot: PivotRoute;
48
+ };
49
+ export declare const buildPayChainBatches: (ctx: BatchBuilderContext, options?: SupplyBatchBuildOptions) => Promise<ChainBatch[]>;
50
+ export declare const buildSupplyChainBatches: (ctx: BatchBuilderContext, options?: SupplyBatchBuildOptions) => Promise<ChainBatch[]>;
43
51
  export declare function estimateRequiredGrossFunding(requiredNetFunding: bigint, buildBatches: (grossFundingAmount: bigint) => ChainBatch[] | Promise<ChainBatch[]>, fundingToken: Address, estimate: EstimateFn, executionOptions?: Pick<ExecutionOptions, "useCustomTransfers" | "userOverride">): Promise<bigint>;
44
52
  export {};
@@ -1,40 +1,40 @@
1
- import { type SourceConversionExecution } from "./sourceConversion";
1
+ import type { ResolvedSwap } from "@spicenet-io/spiceflow-core";
2
2
  import type { Dispatch, MutableRefObject, SetStateAction } from "react";
3
3
  import { type Address } from "viem";
4
- import { type TransactionObserver } from "../../../execution/externalWalletClient";
5
- import { type SourceFundingState } from "../../../execution/sourceFunding";
4
+ import type { ExecutionRunner } from "../../../execution/runner";
5
+ import type { ExecutionProgress } from "../../../hooks/useSpiceExecution";
6
6
  import type { SelectedAsset } from "../../../types/assets";
7
- import type { BuildPayBatchesFn, BuildSupplyBatchesFn, SpiceSupplyProps } from "../../../types/supply";
8
- import { type SupplyFeeQuote } from "./feePreview";
7
+ import type { BuildPayBatchesFn, BuildSupplyBatchesFn, PivotRoute, SpiceSupplyProps } from "../../../types/supply";
9
8
  import type { ResolvedExactOutputSwap } from "../../../utils/swapQuotes";
10
- import type { ExecutionProgress } from "../../../hooks/useSpiceExecution";
11
- import type { ExecutionRunner } from "../../../execution/runner";
9
+ import { type SupplyFeeQuote } from "./feePreview";
12
10
  export type SupplyStep = "idle" | "building" | "signing-delegation" | "signing-intent" | "submitting" | "executing" | "success" | "error";
13
11
  export type PaymentResult = {
14
12
  status: "processing" | "success" | "failed";
15
13
  txHash?: string;
16
14
  error?: string;
17
15
  };
18
- export { isExternalSource } from "./buildBatches";
19
16
  export type ExecutorContext = {
20
- signal?: AbortSignal;
21
17
  selectedAsset: SelectedAsset | null;
22
18
  parsedAmount: number;
23
19
  currentPaymentAmount: string;
24
20
  isInsufficientBalance: boolean;
25
21
  isPayMode: boolean;
26
22
  isFeeInclusiveInput?: boolean;
27
- swapInputAmount?: bigint | null;
28
23
  feeOnlyAction?: boolean;
29
24
  actionProceeds?: SpiceSupplyProps["actionProceeds"];
30
25
  validateFeeQuote?: () => void;
31
- onFeeQuoteChanged?: (quote: SupplyFeeQuote) => void;
26
+ executionTokenDecimals?: number;
27
+ signal?: AbortSignal;
32
28
  isNon7702: boolean;
29
+ directExternalAction?: boolean;
33
30
  isSourceDestToken: boolean;
34
31
  needsSwap: boolean;
35
32
  exactOutputSwap: ResolvedExactOutputSwap | null;
36
33
  selectedIsEquivalent: boolean;
37
34
  resolvedTokenIn: Address | null;
35
+ sourceSwap: ResolvedSwap | null;
36
+ sourceExactOutputSwap: ResolvedExactOutputSwap | null;
37
+ pivot: PivotRoute | null;
38
38
  embeddedWalletAddress: string | null | undefined;
39
39
  providerEmbeddedAddress: string | null | undefined;
40
40
  recipient?: Address;
@@ -53,14 +53,7 @@ export type ExecutorContext = {
53
53
  provider: string | null | undefined;
54
54
  resolvedChainId: number;
55
55
  executionTokenAddress: Address;
56
- executionTokenDecimals?: number;
57
56
  feeQuote: SupplyFeeQuote | null;
58
- fundingObserver?: TransactionObserver;
59
- sourceFunding?: SourceFundingState;
60
- sourceFundingRecoveryKey?: string;
61
- sourceConversion?: SourceConversionExecution;
62
- sourceConversionRequired?: boolean;
63
- onSourceFundingChange?: (state: SourceFundingState) => void;
64
57
  execution: ExecutionRunner & {
65
58
  buildPayChainBatches: BuildPayBatchesFn;
66
59
  buildSupplyChainBatches: BuildSupplyBatchesFn;
@@ -80,7 +73,5 @@ export type ExecutorContext = {
80
73
  abortControllerRef: MutableRefObject<AbortController | null>;
81
74
  };
82
75
  } & Pick<SpiceSupplyProps, "destinationToken" | "buildActionCalls" | "feeExecutionMode" | "buildSpicenetBatch" | "onPayExecute" | "onSuccess">;
83
- export declare function sourceFundingSelection(ctx: ExecutorContext): SelectedAsset | null;
84
- export declare function sourceFundingIdentity(ctx: ExecutorContext): string;
85
76
  export declare function executeSupply(ctx: ExecutorContext): Promise<void>;
86
77
  export declare function executePay(ctx: ExecutorContext): Promise<void>;
@@ -1,63 +1,5 @@
1
1
  import { type Address } from "viem";
2
- import { type SourceFundingState } from "../../../execution/sourceFunding";
3
- import { type ExecutorContext } from "./executors";
4
- import type { BuildActionCallsContext, SpiceSupplyProps } from "../../../types/supply";
5
- import type { Call } from "../../../types/authorization";
6
- export type ExternalActionExecution = {
7
- wallet: "external";
8
- recoveryKey: string;
9
- };
10
- export interface ExternalActionProgress {
11
- destinationToken: Address;
12
- destinationDecimals: number;
13
- phase: "funding" | "routing" | "action" | "complete";
14
- confirmedCalls: number;
15
- totalCalls: number;
16
- amount?: string;
17
- requiresRecovery: boolean;
18
- }
19
- type PendingTransaction = {
20
- chainId: number;
21
- hash?: `0x${string}`;
22
- };
23
- type StoredCall = {
24
- to: Address;
25
- value: string;
26
- data: `0x${string}`;
27
- };
28
- export interface ExternalActionRecord {
29
- version: 2;
30
- scope: string;
31
- destinationToken: Address;
32
- destinationDecimals: number;
33
- sourceKey: string;
34
- phase: ExternalActionProgress["phase"];
35
- amount?: string;
36
- calls?: StoredCall[];
37
- confirmedCalls: number;
38
- sourceFunding?: SourceFundingState;
39
- pendingCall?: PendingTransaction;
40
- routeSubmitted: boolean;
41
- route?: {
42
- actionId: string;
43
- intentId: string;
44
- intentIndex: number;
45
- spicenetSteps: boolean[];
46
- };
47
- lastHash?: `0x${string}`;
48
- }
49
- export declare function externalActionScope(network: string, chainId: number, external: string, embedded: string, recoveryKey: string): string;
50
- export declare function readExternalAction(scope: string): ExternalActionRecord | null;
51
- export declare function externalActionProgress(record: ExternalActionRecord): ExternalActionProgress;
52
- export declare function reconcileExternalFunding(scope: string): Promise<boolean>;
53
- export declare function clearCompletedExternalAction(scope: string): void;
2
+ import type { Call, ChainBatch } from "../../../types/authorization";
3
+ import type { BuildActionCallsContext } from "../../../types/supply";
54
4
  export declare function buildExternalDeliveryCalls(amount: bigint, context: BuildActionCallsContext, recipient: Address): Call[];
55
- export declare function executeExternalActionSupply(params: {
56
- scope: string;
57
- recovery?: "resume" | "balance";
58
- ctx: ExecutorContext;
59
- buildActionCalls: SpiceSupplyProps["buildActionCalls"];
60
- onRecord: (record: ExternalActionRecord | null) => void;
61
- isCurrent?: () => boolean;
62
- }): Promise<void>;
63
- export {};
5
+ export declare function externalDeliveryAmount(batches: ChainBatch[], token: Address, chainId: number, recipient: Address): bigint;
@@ -1,4 +1,6 @@
1
- import type { Address } from "viem";
1
+ import { type Address } from "viem";
2
+ import type { ChainBatch } from "../../../types/authorization";
3
+ export { InsufficientFeeFundingBalanceError } from "./actionProceeds";
2
4
  import type { FeePreviewContext, SupplyFeeQuote } from "./feePreview";
3
5
  export declare function resolveFeeFundingToken(asset: NonNullable<FeePreviewContext["selectedAsset"]>["asset"], chainId: number, feeToken: Address): Address | null;
4
6
  export interface FundingConversion {
@@ -7,10 +9,16 @@ export interface FundingConversion {
7
9
  amountInMax: bigint;
8
10
  amountOut: bigint;
9
11
  sourceAmountMax: bigint;
12
+ fromProceeds?: boolean;
13
+ fromInput?: boolean;
10
14
  }
11
- export declare class InsufficientFeeFundingBalanceError extends Error {
12
- readonly requiredAmount: bigint;
13
- readonly balance: bigint;
14
- constructor(requiredAmount: bigint, balance: bigint);
15
- }
16
- export declare function quoteConvertedFees(ctx: FeePreviewContext): Promise<SupplyFeeQuote>;
15
+ export declare function simulateInPlaceFees(ctx: FeePreviewContext, owner: Address, tokenOut: Address, batches: ChainBatch[]): Promise<{
16
+ gasFee: bigint;
17
+ gasQuoteSource: string;
18
+ simulationVerified?: boolean;
19
+ platformFee?: bigint;
20
+ }>;
21
+ export declare function quoteConvertedFees(ctx: FeePreviewContext, input?: {
22
+ token: Address;
23
+ amount: bigint;
24
+ }): Promise<SupplyFeeQuote>;
@@ -0,0 +1,21 @@
1
+ import type { Address } from "viem";
2
+ import type { Asset } from "../../../types/assets";
3
+ import type { FeeFundingLevel, FeeFundingSource, SpiceSupplyProps } from "../../../types/supply";
4
+ import type { FeePreviewContext, SupplyFeeQuote } from "./feePreview";
5
+ export declare const DEFAULT_FEE_FUNDING: FeeFundingLevel[];
6
+ type Candidate = FeeFundingSource & {
7
+ swap: boolean;
8
+ };
9
+ export declare function rankFeeFundingCandidates(args: {
10
+ feeToken: Address;
11
+ chainId: number;
12
+ inputs?: SpiceSupplyProps["actionInput"];
13
+ proceeds?: {
14
+ token: Address;
15
+ amount: bigint;
16
+ };
17
+ balances: Asset[];
18
+ order?: FeeFundingLevel[];
19
+ }): Candidate[];
20
+ export declare function quoteFeeFunding(ctx: FeePreviewContext, estimateFeePreview: (ctx: FeePreviewContext) => Promise<SupplyFeeQuote | null>): Promise<SupplyFeeQuote | null>;
21
+ export {};