@funkit/connect 9.11.0 → 9.12.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/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # @funkit/connect
2
2
 
3
+ ## 9.12.0
4
+
5
+ ### Minor Changes
6
+
7
+ - ad8ebdf: Add gated combined-input overload to `createPolymarketWithdrawalConfig`. Pass both UDA and wallet-unwrap params; dispatch is decided at call time by the `enable-polymarket-wallet-withdrawal` Statsig gate. Single-flow overloads are now `@deprecated`.
8
+ - d9973bf: Add wallet-unwrap variant to `createPolymarketWithdrawalConfig` that encapsulates the pUSD → USDCe approve+unwrap and atomically batches it with the SDK's withdrawal transaction
9
+ - 1c4b50a: feat(connect): add `preWithdrawalAction` hook to `WalletWithdrawalConfig`
10
+ - 5a03929: feat(connect): add optional `sendTransactions` to `WithdrawalClient` for EIP-5792 atomic batching of approve + swap/deposit steps
11
+
12
+ ### Patch Changes
13
+
14
+ - 99062ff: chore(deps): bump vite to v8, vitest to 4.1.6, and storybook to v10
15
+ - 37cb800: feat(connect): improve swapped iframe skeleton loader
16
+ - ba2c3fa: Improved analytics for `createPolymarketWithdrawalConfig`.
17
+ - d9973bf: Lower wallet-unwrap variant of `createPolymarketWithdrawalConfig` minimum withdrawal to 0 USD
18
+ - 868ad27: Move useLighterWithdrawalBalances hook out of client entry into withdrawal modal
19
+ - 57f89a9: fix(connect): fix swapped iframe height
20
+ - fb64077: feat(connect): add notification banner text animations
21
+ - b592df7: Use config source chain for Lighter Secure withdrawal source token price lookup
22
+ - Updated dependencies [99062ff]
23
+ - @funkit/api-base@4.2.2
24
+ - @funkit/utils@3.0.1
25
+ - @funkit/chains@1.1.3
26
+ - @funkit/fun-relay@2.7.1
27
+
3
28
  ## 9.11.0
4
29
 
5
30
  ### Minor Changes
@@ -22,6 +47,17 @@
22
47
  - Updated dependencies [81e367b]
23
48
  - @funkit/api-base@4.2.1
24
49
 
50
+ ## 9.11.0-next.0
51
+
52
+ ### Minor Changes
53
+
54
+ - 2bf3417: feat(connect): add Rolly deposit actions factory via VaultDepositor
55
+
56
+ ### Patch Changes
57
+
58
+ - Updated dependencies [2bf3417]
59
+ - @funkit/api-base@4.2.1-next.0
60
+
25
61
  ## 9.10.0
26
62
 
27
63
  ### Minor Changes
@@ -3,6 +3,7 @@ declare const _default: {
3
3
  readonly 'enable-across-wallet-flow': false;
4
4
  readonly 'enable-empty-withdrawal-selection': false;
5
5
  readonly 'enable-permit-toggle': false;
6
+ readonly 'enable-polymarket-wallet-withdrawal': false;
6
7
  readonly 'enable-swapped-exchanges': false;
7
8
  readonly 'exact-in': false;
8
9
  readonly 'faster-notifications': false;
@@ -13,7 +13,6 @@
13
13
  * Both callbacks conform to CustomWithdrawalConfig.withdrawCallback; the
14
14
  * caller provides the actual on-chain implementation.
15
15
  */
16
- import type { LighterAccountIndex } from '@funkit/api-base';
17
16
  import type { Address } from 'viem';
18
17
  import type { CustomWithdrawalConfig, MultiMethodWithdrawalConfig } from '../providers/FunkitCheckoutContext/types';
19
18
  export type LighterTransferParams = {
@@ -94,21 +93,6 @@ export interface LighterSecureWithdrawalConfig {
94
93
  */
95
94
  getMinWithdrawalAmount?: (symbol: string) => number;
96
95
  }
97
- /** Free (withdrawable) balance for a single Lighter asset: balance - locked. */
98
- export declare function freeBalance(balance: string, lockedBalance: string): string;
99
- /**
100
- * Fetches all asset balances for a Lighter account. Returns:
101
- *
102
- * - `balances` — `Record<SYMBOL, freeBalance>` (uppercased symbol keys)
103
- * - `assets` — raw asset list from the API (for building source-token options)
104
- */
105
- export declare function useLighterWithdrawalBalances({ accountIndex, }: {
106
- accountIndex: LighterAccountIndex | undefined;
107
- }): {
108
- balances: Record<string, string>;
109
- assets: import("../utils/customer").LighterAsset[];
110
- isLoading: boolean;
111
- };
112
96
  /** Single-method config for Lighter's Secure withdrawal (bridge to Ethereum). */
113
97
  export declare function createLighterSecureWithdrawalConfig(config: LighterSecureWithdrawalConfig): CustomWithdrawalConfig;
114
98
  /**
@@ -118,8 +102,6 @@ export declare function createLighterSecureWithdrawalConfig(config: LighterSecur
118
102
  *
119
103
  * The hook owns every Lighter-specific concern that requires React context:
120
104
  * - the user's Lighter account index (resolved from `config.l1Address`)
121
- * - all Lighter asset balances (so the form validates against the real
122
- * account)
123
105
  * - the live Secure-withdrawal delay (`/api/v1/withdrawalDelay`)
124
106
  * - the active locale (so the disclaimer renders correctly)
125
107
  *
@@ -14,7 +14,7 @@ import { RELAY_LIGHTER_CHAIN_ID } from "@funkit/fun-relay";
14
14
  import { retry } from "@lifeomic/attempt";
15
15
  import { useQuery as useQuery2 } from "@tanstack/react-query";
16
16
  import i18next from "i18next";
17
- import React2, { useEffect, useMemo as useMemo2 } from "react";
17
+ import React2, { useMemo as useMemo2 } from "react";
18
18
  import { arbitrum, base, bsc, mainnet as mainnet2, optimism } from "viem/chains";
19
19
 
20
20
  // src/components/Icons/EvmWallet.tsx
@@ -249,42 +249,6 @@ async function getLighterAccountsByL1Address(address) {
249
249
  const data = await response.json();
250
250
  return data;
251
251
  }
252
- async function getLighterAccount(lookup, activeOnly) {
253
- const params = new URLSearchParams({
254
- by: lookup.by,
255
- value: String(lookup.value),
256
- ...activeOnly !== void 0 && { active_only: String(activeOnly) }
257
- });
258
- const response = await fetch(
259
- `https://mainnet.zklighter.elliot.ai/api/v1/account?${params}`
260
- );
261
- if (!response.ok) {
262
- throw new Error(`Failed to fetch lighter account: ${response.statusText}`);
263
- }
264
- return response.json();
265
- }
266
- function useLighterAccount(lookup, options) {
267
- const { apiKey } = useFunkitConfig();
268
- const isLighter = isLighterxyzCustomer(apiKey);
269
- const enabled = isLighter && lookup !== null && (lookup.by === "index" ? true : !!lookup.value && lookup.value !== "0x");
270
- const query = useQuery({
271
- queryKey: [
272
- "lighterAccount",
273
- lookup?.by,
274
- lookup?.value,
275
- options?.activeOnly
276
- ],
277
- // biome-ignore lint/style/noNonNullAssertion: already checked for null
278
- queryFn: () => getLighterAccount(lookup, options?.activeOnly),
279
- enabled,
280
- staleTime: 3e4,
281
- retry: false
282
- });
283
- return {
284
- ...query,
285
- account: query.data?.accounts?.[0]
286
- };
287
- }
288
252
  function useLighterAccounts({
289
253
  address
290
254
  }) {
@@ -488,48 +452,6 @@ var LIGHTER_DEFAULT_SECURE_MIN_WITHDRAWAL_AMOUNTS = {
488
452
  LDO: 2,
489
453
  AZTEC: 100
490
454
  };
491
- function freeBalance(balance, lockedBalance) {
492
- return String(Math.max(0, Number(balance) - Number(lockedBalance)));
493
- }
494
- function useLighterWithdrawalBalances({
495
- accountIndex
496
- }) {
497
- const { account, isLoading, error } = useLighterAccount(
498
- accountIndex ? { by: "index", value: accountIndex } : null
499
- );
500
- useEffect(() => {
501
- logger.debug("lighter:withdrawal:balances:query", {
502
- accountIndex,
503
- isLoading,
504
- hasAccount: !!account,
505
- error: error instanceof Error ? error.message : error
506
- });
507
- }, [accountIndex, isLoading, account, error]);
508
- const balances = useMemo2(() => {
509
- if (!account) {
510
- return {};
511
- }
512
- const result = {};
513
- for (const asset of account.assets) {
514
- const symbol = asset.symbol.toUpperCase();
515
- if (symbol === "USDC") {
516
- continue;
517
- }
518
- result[symbol] = freeBalance(asset.balance, asset.locked_balance);
519
- }
520
- result.USDC = account.total_asset_value;
521
- logger.info("lighter:withdrawal:balances:resolved", {
522
- accountIndex,
523
- balances: result
524
- });
525
- return result;
526
- }, [account, accountIndex]);
527
- return {
528
- balances,
529
- assets: account?.assets ?? [],
530
- isLoading
531
- };
532
- }
533
455
  function buildSecureWithdrawalCallback({
534
456
  exec
535
457
  }) {
@@ -660,7 +582,6 @@ function buildLighterMultiMethodConfig({
660
582
  config,
661
583
  accountIndex,
662
584
  t,
663
- withBalance,
664
585
  secureDelayText
665
586
  }) {
666
587
  const fastConfig = buildLighterFastWalletWithdrawalConfig({
@@ -690,12 +611,7 @@ function buildLighterMultiMethodConfig({
690
611
  subtitleText: t("withdrawal.fastDisclaimer"),
691
612
  icon: /* @__PURE__ */ React2.createElement(EvmWallet, { size: 20 }),
692
613
  valueIcon: /* @__PURE__ */ React2.createElement(ChainIconStack, { chainIds: LIGHTER_FAST_PREVIEW_CHAIN_IDS }),
693
- config: withBalance ? {
694
- ...fastConfig,
695
- withdrawalSourceTokenBalance: withBalance(
696
- fastConfig.sourceTokenSymbol
697
- )
698
- } : fastConfig
614
+ config: fastConfig
699
615
  };
700
616
  const secure = {
701
617
  id: "lighter-secure",
@@ -708,12 +624,7 @@ function buildLighterMultiMethodConfig({
708
624
  }),
709
625
  icon: /* @__PURE__ */ React2.createElement(EvmWallet, { size: 20 }),
710
626
  valueIcon: /* @__PURE__ */ React2.createElement(ChainIconStack, { chainIds: LIGHTER_SECURE_PREVIEW_CHAIN_IDS }),
711
- config: withBalance ? {
712
- ...secureConfig,
713
- withdrawalSourceTokenBalance: withBalance(
714
- secureConfig.sourceTokenSymbol
715
- )
716
- } : secureConfig
627
+ config: secureConfig
717
628
  };
718
629
  return {
719
630
  modalTitle: config.modalTitle ?? t("withdrawal.withdraw"),
@@ -727,9 +638,6 @@ function useLighterWithdrawalConfig(config) {
727
638
  address: config?.l1Address
728
639
  });
729
640
  const accountIndex = mainAccountIndex && /^\d+$/.test(mainAccountIndex) ? mainAccountIndex : void 0;
730
- const { balances } = useLighterWithdrawalBalances({
731
- accountIndex
732
- });
733
641
  const secureDelayText = useLighterSecureDelayText();
734
642
  return useMemo2(() => {
735
643
  if (!config || !accountIndex) {
@@ -739,15 +647,12 @@ function useLighterWithdrawalConfig(config) {
739
647
  config,
740
648
  accountIndex,
741
649
  t,
742
- withBalance: (symbol) => () => balances[symbol.toUpperCase()] ?? "0",
743
650
  secureDelayText
744
651
  });
745
- }, [config, accountIndex, balances, t, secureDelayText]);
652
+ }, [config, accountIndex, t, secureDelayText]);
746
653
  }
747
654
  export {
748
655
  LIGHTER_DEFAULT_SECURE_MIN_WITHDRAWAL_AMOUNTS,
749
656
  createLighterSecureWithdrawalConfig,
750
- freeBalance,
751
- useLighterWithdrawalBalances,
752
657
  useLighterWithdrawalConfig
753
658
  };
@@ -1,15 +1,23 @@
1
1
  /**
2
2
  * Polymarket V2 PMCT withdrawal.
3
3
  *
4
- * Withdrawal flow:
5
- * 1. Generate a UDA (User Deposit Address) for the withdrawal via api-base
6
- * 2. Transfer PMCT from user's Polymarket proxy to the UDA
7
- * 3. Backend handles: unwrap PMCT → USDC via PermissionedRamp + route to user
4
+ * Two flows are supported, dispatched on input shape:
8
5
  *
9
- * The callback conforms to CustomWithdrawalConfig.withdrawCallback.
6
+ * 1. **UDA / PMCT transfer** (legacy) — caller supplies `userId` +
7
+ * `sendPmctTransfer`. The backend handles the unwrap/route via
8
+ * PermissionedRamp. Returns a {@link CustomWithdrawalConfig}.
9
+ *
10
+ * 2. **Wallet unwrap** — caller supplies `proxyAddress`, a `publicClient`,
11
+ * and a batched `sendTransactions` primitive. `preWithdrawalAction`
12
+ * reads the pUSD allowance and returns the approve (when needed) +
13
+ * `unwrap()` to USDCe as an array of {@link WithdrawalTransaction}s.
14
+ * The SDK prepends those to the withdrawal txn and atomically broadcasts
15
+ * the batch via the integrator's `sendTransactions`. Returns a
16
+ * {@link WalletWithdrawalConfig}.
10
17
  */
11
- import type { Address } from 'viem';
12
- import type { CustomWithdrawalConfig } from '../providers/FunkitCheckoutContext/types';
18
+ import { type Address, type PublicClient, type TransactionReceipt } from 'viem';
19
+ import type { CustomWithdrawalConfig, FunkitWithdrawalConfig, WalletWithdrawalConfig } from '../providers/FunkitCheckoutContext/types';
20
+ import type { WithdrawalTransaction } from '../wallets/Wallet';
13
21
  export interface PolymarketWithdrawalCallbackConfig {
14
22
  userId: string;
15
23
  modalTitle?: string;
@@ -31,9 +39,69 @@ export interface PolymarketWithdrawalCallbackConfig {
31
39
  }) => Promise<void>;
32
40
  }
33
41
  /**
34
- * Creates a full CustomWithdrawalConfig for Polymarket V2 PMCT withdrawals.
42
+ * Caller-supplied batched submitter. Receives the full ordered list of txs
43
+ * (helper-injected approve+unwrap, then the SDK's withdrawal txn). Must
44
+ * broadcast them atomically in a single user signature and return a tx hash
45
+ * that {@link WithdrawalClient.confirmTransaction} can wait on.
46
+ */
47
+ export type PolymarketSendTransactions = (txs: WithdrawalTransaction[]) => Promise<string>;
48
+ export interface PolymarketWalletUnwrapWithdrawalConfig {
49
+ /** Polymarket proxy that holds pUSD and signs the batched tx. */
50
+ proxyAddress: Address;
51
+ /** Polygon public client used for the pre-flight allowance read. */
52
+ publicClient: PublicClient;
53
+ /**
54
+ * Batched send primitive. The SDK passes the full ordered list of txs —
55
+ * helper-emitted `approve(pUSD → offramp)` (only when allowance is
56
+ * insufficient) and `offramp.unwrap(USDCe, proxy, amount)` from
57
+ * `preWithdrawalAction`, followed by the withdrawal txn — and the
58
+ * integrator broadcasts them atomically in a single user signature.
59
+ */
60
+ sendTransactions: PolymarketSendTransactions;
61
+ /**
62
+ * Optional override for waiting on a tx receipt. Defaults to
63
+ * `publicClient.waitForTransactionReceipt`.
64
+ */
65
+ confirmTransaction?: (txHash: string, chainId: number) => Promise<TransactionReceipt>;
66
+ modalTitle?: string;
67
+ disableConnectedWallet?: boolean;
68
+ sourceTokenSymbol?: string;
69
+ sourceTokenAddress?: Address;
70
+ defaultReceiveToken?: string;
71
+ iconSrc?: string;
72
+ }
73
+ /**
74
+ * Combined input — supplies params for both flows. The runtime path is
75
+ * chosen at call time via the `enable-polymarket-wallet-withdrawal`
76
+ * Statsig gate (read synchronously through {@link checkFeatureGate}, so
77
+ * this stays a regular function callable from event handlers).
78
+ */
79
+ export interface PolymarketWithdrawalConfig extends PolymarketWithdrawalCallbackConfig, PolymarketWalletUnwrapWithdrawalConfig {
80
+ }
81
+ /**
82
+ * Combined / gated entry point. Returns a {@link CustomWithdrawalConfig}
83
+ * (UDA path) or {@link WalletWithdrawalConfig} (wallet-unwrap path)
84
+ * depending on the gate value at call time.
85
+ *
86
+ * ```ts
87
+ * const withdrawalConfig = createPolymarketWithdrawalConfig({
88
+ * userId: walletAddress,
89
+ * sendPmctTransfer: async ({ udaAddress, amountBaseUnit }) => { ... },
90
+ * proxyAddress,
91
+ * publicClient,
92
+ * sendTransactions: async (txs) => myBatchedSend(txs),
93
+ * })
94
+ * ```
95
+ */
96
+ export declare function createPolymarketWithdrawalConfig(config: PolymarketWithdrawalConfig): FunkitWithdrawalConfig;
97
+ /**
98
+ * Legacy UDA / PMCT transfer flow. Returns a {@link CustomWithdrawalConfig}.
99
+ *
100
+ * @deprecated Pass the combined {@link PolymarketWithdrawalConfig} instead so
101
+ * the wallet-unwrap rollout can be staged via the
102
+ * `enable-polymarket-wallet-withdrawal` Statsig gate. Direct callers of this
103
+ * single-flow overload bypass the gate.
35
104
  *
36
- * Usage:
37
105
  * ```ts
38
106
  * const withdrawalConfig = createPolymarketWithdrawalConfig({
39
107
  * userId: walletAddress,
@@ -42,3 +110,23 @@ export interface PolymarketWithdrawalCallbackConfig {
42
110
  * ```
43
111
  */
44
112
  export declare function createPolymarketWithdrawalConfig(config: PolymarketWithdrawalCallbackConfig): CustomWithdrawalConfig;
113
+ /**
114
+ * Wallet-flow with embedded pUSD → USDCe unwrap. Returns a
115
+ * {@link WalletWithdrawalConfig} whose `preWithdrawalAction` and `wallet`
116
+ * coordinate via a closure-scoped queue, so the integrator only sees the
117
+ * batched `sendTransactions` primitive.
118
+ *
119
+ * @deprecated Pass the combined {@link PolymarketWithdrawalConfig} instead so
120
+ * the wallet-unwrap rollout can be staged via the
121
+ * `enable-polymarket-wallet-withdrawal` Statsig gate. Direct callers of this
122
+ * single-flow overload bypass the gate.
123
+ *
124
+ * ```ts
125
+ * const withdrawalConfig = createPolymarketWithdrawalConfig({
126
+ * proxyAddress,
127
+ * publicClient,
128
+ * sendTransactions: async (txs) => myBatchedSend(txs),
129
+ * })
130
+ * ```
131
+ */
132
+ export declare function createPolymarketWithdrawalConfig(config: PolymarketWalletUnwrapWithdrawalConfig): WalletWithdrawalConfig;
@@ -8,6 +8,11 @@ import {
8
8
  POLYMARKET_API_KEY,
9
9
  initializeCheckoutTokenTransferAddress
10
10
  } from "@funkit/api-base";
11
+ import {
12
+ encodeFunctionData,
13
+ erc20Abi,
14
+ getAddress
15
+ } from "viem";
11
16
  import { polygon } from "viem/chains";
12
17
 
13
18
  // src/domains/paymentMethods.ts
@@ -323,9 +328,71 @@ function generateClientMetadataForTokenTransfer() {
323
328
  };
324
329
  }
325
330
 
331
+ // src/utils/statsig/checkFeatureGate.ts
332
+ import { StatsigClient } from "@statsig/react-bindings";
333
+
334
+ // src/providers/FunkitStatsigProvider.tsx
335
+ import { datadogLogs } from "@datadog/browser-logs";
336
+ import {
337
+ LogEventCompressionMode,
338
+ LogLevel,
339
+ StatsigProvider,
340
+ useClientAsyncInit
341
+ } from "@statsig/react-bindings";
342
+ import React8, { useEffect } from "react";
343
+ var STATSIG_CLIENT_KEY = "client-UmFd8WIJljA7cLmZuDqs3X25M8sKd5WIQP4BSC2bRbM";
344
+
345
+ // src/__generated__/default_feature_gates.ts
346
+ var default_feature_gates_default = {
347
+ "compliance-review-blocker": false,
348
+ "enable-across-wallet-flow": false,
349
+ "enable-empty-withdrawal-selection": false,
350
+ "enable-permit-toggle": false,
351
+ "enable-polymarket-wallet-withdrawal": false,
352
+ "enable-swapped-exchanges": false,
353
+ "exact-in": false,
354
+ "faster-notifications": false,
355
+ "new-token-transfer-config": false,
356
+ "new-withdrawal-config": false,
357
+ "polymarket-pusd-migration": false,
358
+ "saved-card-defaults-to-fiat-tab": false,
359
+ "test-testing-gate": false,
360
+ "wallet-flow-enable-exact-input-with-actions": false,
361
+ "you-receive-remove-swap-impact": false
362
+ };
363
+
364
+ // src/utils/statsig/checkFeatureGate.ts
365
+ function checkFeatureGate(name) {
366
+ try {
367
+ return StatsigClient.instance(STATSIG_CLIENT_KEY).checkGate(name);
368
+ } catch (err) {
369
+ logger.warn("checkFeatureGate:error", { name, err });
370
+ return default_feature_gates_default[name];
371
+ }
372
+ }
373
+
326
374
  // src/clients/polymarket.tsx
327
375
  var PMCT_WITHDRAW_ACTION_TYPE = "PMCT_WITHDRAW";
328
376
  var POLYGON_USDCE = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174";
377
+ var PUSD_TOKEN = {
378
+ address: getAddress("0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB"),
379
+ symbol: "pUSD",
380
+ iconSrc: "https://sdk-cdn.fun.xyz/images/pusd.svg"
381
+ };
382
+ var PUSD_OFFRAMP_ADDRESS = "0x2957922Eb93258b93368531d39fAcCA3B4dC5854";
383
+ var PUSD_OFFRAMP_ABI = [
384
+ {
385
+ name: "unwrap",
386
+ type: "function",
387
+ inputs: [
388
+ { name: "_asset", type: "address" },
389
+ { name: "_to", type: "address" },
390
+ { name: "_amount", type: "uint256" }
391
+ ],
392
+ outputs: [],
393
+ stateMutability: "nonpayable"
394
+ }
395
+ ];
329
396
  function createPolymarketWithdrawalCallback(config) {
330
397
  const { userId, sendPmctTransfer } = config;
331
398
  return async (param) => {
@@ -351,24 +418,20 @@ function createPolymarketWithdrawalCallback(config) {
351
418
  });
352
419
  const udaAddress = transferInit.depositAddr;
353
420
  logger.info("polymarket:withdrawal:udaGenerated", { udaAddress });
354
- const quote = funQuote;
355
- const amountStr = quote?.baseQuote?.estTotalFromAmountBaseUnit;
356
- if (!amountStr) {
357
- logger.error("polymarket:withdrawal:missingAmountInQuote", { quote });
358
- throw new Error("Missing withdrawal amount in quote");
359
- }
360
- const amount = BigInt(amountStr);
421
+ const amountBaseUnit = extractWithdrawalAmount(funQuote);
361
422
  await sendPmctTransfer({
362
423
  udaAddress,
363
- amountBaseUnit: amount
424
+ amountBaseUnit
364
425
  });
365
426
  logger.info("polymarket:withdrawal:transferSubmitted", {
366
427
  udaAddress,
367
- amountBaseUnit: amountStr
428
+ amountBaseUnit: amountBaseUnit.toString()
368
429
  });
430
+ return void 0;
369
431
  };
370
432
  }
371
- function createPolymarketWithdrawalConfig(config) {
433
+ function buildUdaWithdrawalConfig(config) {
434
+ logger.info("polymarket:withdrawal:flow", { flow: "uda" });
372
435
  return {
373
436
  modalTitle: config.modalTitle ?? "Withdraw",
374
437
  disableConnectedWallet: config.disableConnectedWallet,
@@ -381,6 +444,114 @@ function createPolymarketWithdrawalConfig(config) {
381
444
  getMinWithdrawalUSD: () => 3
382
445
  };
383
446
  }
447
+ function buildWalletUnwrapWithdrawalConfig(config) {
448
+ logger.info("polymarket:withdrawal:flow", { flow: "wallet-unwrap" });
449
+ const {
450
+ proxyAddress,
451
+ publicClient,
452
+ sendTransactions: callerSendTransactions,
453
+ confirmTransaction
454
+ } = config;
455
+ const wallet = {
456
+ address: () => proxyAddress,
457
+ getChainId: async () => polygon.id,
458
+ switchChain: async (chainId) => {
459
+ if (chainId !== polygon.id) {
460
+ throw new Error(
461
+ `Cannot switch chain: Polymarket withdrawal is fixed to ${polygon.id}, requested ${chainId}`
462
+ );
463
+ }
464
+ },
465
+ sendTransaction: async (_chainId, transaction) => callerSendTransactions([transaction]),
466
+ sendTransactions: async (_chainId, txs) => callerSendTransactions(txs),
467
+ confirmTransaction: confirmTransaction ?? (async (txHash) => publicClient.waitForTransactionReceipt({ hash: txHash }))
468
+ };
469
+ const preWithdrawalAction = async ({
470
+ funQuote
471
+ }) => {
472
+ logger.info("polymarket:withdrawal:wallet:start", { proxyAddress });
473
+ try {
474
+ const amountBaseUnit = extractWithdrawalAmount(funQuote);
475
+ const currentAllowance = await publicClient.readContract({
476
+ address: PUSD_TOKEN.address,
477
+ abi: erc20Abi,
478
+ functionName: "allowance",
479
+ args: [proxyAddress, PUSD_OFFRAMP_ADDRESS]
480
+ });
481
+ const needsApprovalTx = currentAllowance < amountBaseUnit;
482
+ logger.info("polymarket:withdrawal:wallet:allowanceChecked", {
483
+ proxyAddress,
484
+ amountBaseUnit: amountBaseUnit.toString(),
485
+ currentAllowance: currentAllowance.toString(),
486
+ needsApprovalTx
487
+ });
488
+ const txs = [];
489
+ if (needsApprovalTx) {
490
+ txs.push({
491
+ to: PUSD_TOKEN.address,
492
+ data: encodeFunctionData({
493
+ abi: erc20Abi,
494
+ functionName: "approve",
495
+ args: [PUSD_OFFRAMP_ADDRESS, amountBaseUnit]
496
+ }),
497
+ value: "0"
498
+ });
499
+ }
500
+ txs.push({
501
+ to: PUSD_OFFRAMP_ADDRESS,
502
+ data: encodeFunctionData({
503
+ abi: PUSD_OFFRAMP_ABI,
504
+ functionName: "unwrap",
505
+ args: [POLYGON_USDCE, proxyAddress, amountBaseUnit]
506
+ }),
507
+ value: "0"
508
+ });
509
+ logger.info("polymarket:withdrawal:wallet:txsStaged", {
510
+ proxyAddress,
511
+ txCount: txs.length,
512
+ needsApprovalTx
513
+ });
514
+ return txs;
515
+ } catch (err) {
516
+ logger.error("polymarket:withdrawal:wallet:error", err, {
517
+ phase: "preWithdrawal",
518
+ proxyAddress
519
+ });
520
+ throw err;
521
+ }
522
+ };
523
+ return {
524
+ modalTitle: config.modalTitle ?? "Withdraw",
525
+ disableConnectedWallet: config.disableConnectedWallet,
526
+ sourceChainId: polygon.id.toString(),
527
+ sourceTokenSymbol: config.sourceTokenSymbol ?? PUSD_TOKEN.symbol,
528
+ sourceTokenAddress: config.sourceTokenAddress ?? POLYGON_USDCE,
529
+ defaultReceiveToken: config.defaultReceiveToken ?? "USDC",
530
+ iconSrc: config.iconSrc ?? PUSD_TOKEN.iconSrc,
531
+ getMinWithdrawalUSD: () => 0,
532
+ wallet,
533
+ preWithdrawalAction
534
+ };
535
+ }
536
+ function extractWithdrawalAmount(funQuote) {
537
+ const quote = funQuote;
538
+ const amountStr = quote?.baseQuote?.estTotalFromAmountBaseUnit;
539
+ if (!amountStr) {
540
+ logger.error("polymarket:withdrawal:missingAmountInQuote", { quote });
541
+ throw new Error("Missing withdrawal amount in quote");
542
+ }
543
+ return BigInt(amountStr);
544
+ }
545
+ function createPolymarketWithdrawalConfig(config) {
546
+ if ("sendPmctTransfer" in config && "sendTransactions" in config) {
547
+ const walletUnwrapEnabled = checkFeatureGate(
548
+ "enable-polymarket-wallet-withdrawal"
549
+ );
550
+ logger.info("polymarket:withdrawal:gate", { walletUnwrapEnabled });
551
+ return walletUnwrapEnabled ? buildWalletUnwrapWithdrawalConfig(config) : buildUdaWithdrawalConfig(config);
552
+ }
553
+ return "sendPmctTransfer" in config ? buildUdaWithdrawalConfig(config) : buildWalletUnwrapWithdrawalConfig(config);
554
+ }
384
555
  export {
385
556
  createPolymarketWithdrawalConfig
386
557
  };
@@ -1,6 +1,6 @@
1
1
  export declare const DIALOG_WIDTH_WIDE = "450px";
2
2
  export declare const DIALOG_HEIGHT = 525;
3
- export declare const DIALOG_HEIGHT_SWAPPED_IFRAME = 580;
3
+ export declare const DIALOG_HEIGHT_SWAPPED_IFRAME = 525;
4
4
  export declare const DIALOG_INNER_PADDING_X = 12;
5
5
  export declare const SCROLL_BAR_WIDTH = 6;
6
6
  export declare const DIALOG_BOTTOM_PADDING = "15";
@@ -1,7 +1,7 @@
1
1
  import React, { type ReactNode } from 'react';
2
2
  import { type FunNotificationBannerIconProps } from './FunNotificationBannerIcon';
3
3
  interface FunNotificationBannerProps extends FunNotificationBannerIconProps {
4
- title: ReactNode;
4
+ title: string;
5
5
  description: ReactNode;
6
6
  /** Additional text-like content clarifying the description */
7
7
  disclaimer?: ReactNode;
@@ -1,10 +1,14 @@
1
+ import { type Easing } from 'motion/react';
1
2
  import { type FC } from 'react';
2
3
  import { type TextProps } from '../Text/Text';
3
4
  export interface AnimatedTextProps extends TextProps {
4
5
  animationDelay?: number;
6
+ animationDirection?: number;
5
7
  animationDuration?: number;
8
+ animationEase?: Easing | Easing[];
6
9
  animationMaxBlur?: number;
7
10
  animationMaxDistance?: number;
11
+ animationMode?: 'wait' | 'popLayout';
8
12
  textKey: number | string;
9
13
  }
10
14
  export declare const AnimatedText: FC<AnimatedTextProps>;
@@ -1,4 +1,5 @@
1
- export declare const useErc20Asset: ({ chainId, symbol, }: {
1
+ export declare const useErc20Asset: ({ chainId, symbol, enabled, }: {
2
2
  chainId: string | undefined;
3
3
  symbol: string | undefined;
4
+ enabled?: boolean;
4
5
  }) => import("@tanstack/react-query").UseQueryResult<import("@funkit/api-base").Erc20AssetInfo | null, Error>;
@@ -8,6 +8,8 @@ interface UseAssetAddressPriceParams {
8
8
  amount?: number;
9
9
  /** Asset symbol — when provided and the symbol is a stablecoin, price is hardcoded to 1 */
10
10
  symbol?: string;
11
+ /** Disable the query without changing other inputs. Defaults to true. */
12
+ enabled?: boolean;
11
13
  }
12
14
  type AssetPriceResult = {
13
15
  error: Error | null;
@@ -15,13 +17,15 @@ type AssetPriceResult = {
15
17
  /** unit price if custom amount is not provided */
16
18
  price: number | undefined;
17
19
  };
18
- export declare function useAssetAddressPrice({ chainId, assetTokenAddress, amount, refetchInterval, symbol, }: UseAssetAddressPriceParams): AssetPriceResult;
20
+ export declare function useAssetAddressPrice({ chainId, assetTokenAddress, amount, refetchInterval, symbol, enabled, }: UseAssetAddressPriceParams): AssetPriceResult;
19
21
  type AssetSymbolPriceParams = {
20
22
  chainId: string | undefined;
21
23
  symbol: string | undefined;
22
24
  refetchInterval?: number;
25
+ /** Disable the query without changing other inputs. Defaults to true. */
26
+ enabled?: boolean;
23
27
  };
24
- export declare const useAssetSymbolPrice: ({ chainId, symbol, refetchInterval, }: AssetSymbolPriceParams) => AssetPriceResult & {
28
+ export declare const useAssetSymbolPrice: ({ chainId, symbol, refetchInterval, enabled, }: AssetSymbolPriceParams) => AssetPriceResult & {
25
29
  asset?: Erc20AssetInfo | null;
26
30
  };
27
31
  export {};