@b3dotfun/sdk 0.0.29-alpha.4 → 0.0.29-alpha.6

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.
@@ -27,6 +27,7 @@ const RecipientSelection_1 = require("./common/RecipientSelection");
27
27
  const escrow_1 = require("../../../anyspend/abis/escrow");
28
28
  const lucide_react_1 = require("lucide-react");
29
29
  const PanelOnramp_1 = require("./common/PanelOnramp");
30
+ const SLIPPAGE_PERCENT = 3;
30
31
  function generateEncodedDataForDepositHype(amount, beneficiary) {
31
32
  (0, invariant_1.default)(BigInt(amount) > 0, "Amount must be greater than zero");
32
33
  const encodedData = (0, viem_1.encodeFunctionData)({
@@ -50,6 +51,7 @@ function AnySpendDepositHypeInner({ loadOrder, mode = "modal", recipientAddress,
50
51
  onTransactionSuccess: onSuccess,
51
52
  sourceTokenAddress,
52
53
  sourceTokenChainId,
54
+ slippage: SLIPPAGE_PERCENT,
53
55
  });
54
56
  // Button state logic
55
57
  const btnInfo = (0, react_3.useMemo)(() => {
@@ -133,7 +135,10 @@ function AnySpendDepositHypeInner({ loadOrder, mode = "modal", recipientAddress,
133
135
  (0, invariant_1.default)(selectedRecipientAddress, "Recipient address is not found");
134
136
  (0, invariant_1.default)(depositContractAddress, "Deposit contract address is not found");
135
137
  const srcAmountBigInt = BigInt(activeInputAmountInWei);
136
- const depositAmountWei = anyspendQuote.data?.currencyOut?.amount || "0";
138
+ // TODO: temp subtract 3% for slippage
139
+ const originalDepositAmountWei = anyspendQuote.data?.currencyOut?.amount || "0";
140
+ const depositAmountWei = ((BigInt(originalDepositAmountWei) * BigInt(100 - SLIPPAGE_PERCENT)) /
141
+ BigInt(100)).toString();
137
142
  const encodedData = generateEncodedDataForDepositHype(depositAmountWei, selectedRecipientAddress);
138
143
  createOrder({
139
144
  recipientAddress: selectedRecipientAddress,
@@ -240,7 +245,6 @@ function AnySpendDepositHypeInner({ loadOrder, mode = "modal", recipientAddress,
240
245
  setSelectedFiatPaymentMethod(method);
241
246
  setActivePanel(useAnyspendFlow_1.PanelView.MAIN);
242
247
  }, srcAmountOnRamp: srcAmount }));
243
- console.log("activePanel", activePanel, orderId, oat);
244
248
  // If showing token selection, render with panel transitions
245
249
  return ((0, jsx_runtime_1.jsx)(react_1.StyleRoot, { children: (0, jsx_runtime_1.jsx)("div", { className: (0, cn_1.cn)("anyspend-container font-inter mx-auto w-full max-w-[460px]", mode === "page" &&
246
250
  "bg-as-surface-primary border-as-border-secondary overflow-hidden rounded-2xl border shadow-xl"), children: (0, jsx_runtime_1.jsx)(react_1.TransitionPanel, { activeIndex: orderId
@@ -49,6 +49,9 @@ function getOrderSuccessText({ order, tournament, formattedActualDstAmount, dstT
49
49
  actionText = `funded ${tournament?.name}`;
50
50
  return `Successfully ${actionText}`;
51
51
  case "custom":
52
+ if (order.metadata.action === anyspend_1.DEPOSIT_HYPE_ACTION) {
53
+ return `Successfully deposited ${(0, number_1.formatTokenAmount)(BigInt(order.payload?.amount || "0"), 18)} HYPE to ${recipient}`;
54
+ }
52
55
  actionText = order.metadata.action || `executed contract`;
53
56
  return `Successfully ${actionText}`;
54
57
  default:
@@ -18,8 +18,9 @@ interface UseAnyspendFlowProps {
18
18
  onTransactionSuccess?: () => void;
19
19
  sourceTokenAddress?: string;
20
20
  sourceTokenChainId?: number;
21
+ slippage?: number;
21
22
  }
22
- export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrder, isDepositMode, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, }: UseAnyspendFlowProps): {
23
+ export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrder, isDepositMode, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, slippage, }: UseAnyspendFlowProps): {
23
24
  activePanel: PanelView;
24
25
  setActivePanel: import("react").Dispatch<import("react").SetStateAction<PanelView>>;
25
26
  orderId: string | undefined;
@@ -22,7 +22,7 @@ var PanelView;
22
22
  PanelView[PanelView["ORDER_DETAILS"] = 4] = "ORDER_DETAILS";
23
23
  PanelView[PanelView["LOADING"] = 5] = "LOADING";
24
24
  })(PanelView || (exports.PanelView = PanelView = {}));
25
- function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder, isDepositMode = false, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, }) {
25
+ function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder, isDepositMode = false, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, slippage = 0, }) {
26
26
  const searchParams = (0, react_2.useSearchParamsSSR)();
27
27
  const router = (0, react_2.useRouter)();
28
28
  // Panel and order state
@@ -103,13 +103,15 @@ function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder,
103
103
  if (anyspendQuote?.data?.currencyOut?.amount && anyspendQuote.data.currencyOut.currency?.decimals) {
104
104
  const amount = anyspendQuote.data.currencyOut.amount;
105
105
  const decimals = anyspendQuote.data.currencyOut.currency.decimals;
106
- const formattedAmount = (0, number_1.formatTokenAmount)(BigInt(amount), decimals, 6, false);
106
+ // Apply slippage (0-100) - reduce amount by slippage percentageFixed slippage value
107
+ const amountWithSlippage = (BigInt(amount) * BigInt(100 - slippage)) / BigInt(100);
108
+ const formattedAmount = (0, number_1.formatTokenAmount)(amountWithSlippage, decimals, 6, false);
107
109
  setDstAmount(formattedAmount);
108
110
  }
109
111
  else {
110
112
  setDstAmount("");
111
113
  }
112
- }, [anyspendQuote]);
114
+ }, [anyspendQuote, slippage]);
113
115
  // Update useEffect for URL parameter to not override loadOrder
114
116
  (0, react_3.useEffect)(() => {
115
117
  if (loadOrder)
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LinkAccount = LinkAccount;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const constants_1 = require("../../../../shared/constants");
5
6
  const thirdweb_1 = require("../../../../shared/utils/thirdweb");
6
7
  const lucide_react_1 = require("lucide-react");
7
8
  const react_1 = require("react");
@@ -97,6 +98,10 @@ function LinkAccount({ onSuccess: onSuccessCallback, onError, onClose, chain, pa
97
98
  client: thirdweb_1.client,
98
99
  strategy: "email",
99
100
  email,
101
+ ecosystem: {
102
+ id: constants_1.ecosystemWalletId,
103
+ partnerId: partnerId,
104
+ },
100
105
  });
101
106
  }
102
107
  else if (selectedMethod === "phone") {
@@ -104,6 +109,10 @@ function LinkAccount({ onSuccess: onSuccessCallback, onError, onClose, chain, pa
104
109
  client: thirdweb_1.client,
105
110
  strategy: "phone",
106
111
  phoneNumber: phone,
112
+ ecosystem: {
113
+ id: constants_1.ecosystemWalletId,
114
+ partnerId: partnerId,
115
+ },
107
116
  });
108
117
  }
109
118
  setOtpSent(true);
@@ -117,10 +126,12 @@ function LinkAccount({ onSuccess: onSuccessCallback, onError, onClose, chain, pa
117
126
  };
118
127
  const handleLinkAccount = async () => {
119
128
  if (!otp) {
129
+ console.error("No OTP entered");
120
130
  setError("Please enter the verification code");
121
131
  return;
122
132
  }
123
133
  try {
134
+ setOtpSent(false);
124
135
  setLinkingState(true, selectedMethod);
125
136
  setError(null);
126
137
  if (selectedMethod === "email") {
@@ -139,17 +150,12 @@ function LinkAccount({ onSuccess: onSuccessCallback, onError, onClose, chain, pa
139
150
  verificationCode: otp,
140
151
  }, mutationOptions);
141
152
  }
142
- onSuccess?.();
143
- onClose?.();
144
153
  }
145
154
  catch (error) {
146
155
  console.error("Error linking account:", error);
147
156
  setError(error instanceof Error ? error.message : "Failed to link account");
148
157
  onError?.(error);
149
158
  }
150
- finally {
151
- setLinkingState(false);
152
- }
153
159
  };
154
160
  const handleSocialLink = async (strategy) => {
155
161
  try {
@@ -200,17 +206,24 @@ function LinkAccount({ onSuccess: onSuccessCallback, onError, onClose, chain, pa
200
206
  setError(null);
201
207
  setLinkingState(false);
202
208
  }, [isLinking, setSelectedMethod, setEmail, setPhone, setOtp, setOtpSent, setError, setLinkingState]);
209
+ const handleFinishedLinking = (0, react_1.useCallback)((success) => {
210
+ if (success) {
211
+ onSuccess?.();
212
+ onClose?.();
213
+ }
214
+ setLinkingState(false);
215
+ navigateBack();
216
+ setB3ModalContentType({
217
+ type: "manageAccount",
218
+ activeTab: "settings",
219
+ setActiveTab: () => { },
220
+ chain,
221
+ partnerId,
222
+ });
223
+ }, [chain, navigateBack, partnerId, setB3ModalContentType, setLinkingState, onSuccess, onClose]);
203
224
  (0, react_1.useEffect)(() => {
204
225
  if (isLinking) {
205
- setLinkingState(false);
206
- navigateBack();
207
- setB3ModalContentType({
208
- type: "manageAccount",
209
- activeTab: "settings",
210
- setActiveTab: () => { },
211
- chain,
212
- partnerId,
213
- });
226
+ handleFinishedLinking(true);
214
227
  }
215
228
  // eslint-disable-next-line react-hooks/exhaustive-deps
216
229
  }, [profiles.length]);
@@ -224,5 +237,5 @@ function LinkAccount({ onSuccess: onSuccessCallback, onError, onClose, chain, pa
224
237
  else {
225
238
  handleSocialLink(method.id);
226
239
  }
227
- }, disabled: linkingMethod === method.id, children: isLinking && linkingMethod === method.id ? (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "animate-spin" }) : method.label }, method.id))), availableAuthMethods.length === 0 && ((0, jsx_runtime_1.jsx)("div", { className: "text-b3-foreground-muted py-8 text-center", children: "All available authentication methods have been connected" }))] })) : ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [selectedMethod === "email" && ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-b3-grey font-neue-montreal-medium text-sm", children: "Email Address" }), (0, jsx_runtime_1.jsx)("input", { type: "email", placeholder: "Enter your email", className: "bg-b3-line text-b3-grey font-neue-montreal-medium focus:ring-b3-primary-blue/20 w-full rounded-xl p-4 focus:outline-none focus:ring-2", value: email, onChange: e => setEmail(e.target.value), disabled: otpSent || (isLinking && linkingMethod === "email") })] })), selectedMethod === "phone" && ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-b3-grey font-neue-montreal-medium text-sm", children: "Phone Number" }), (0, jsx_runtime_1.jsx)("input", { type: "tel", placeholder: "Enter your phone number", className: "bg-b3-line text-b3-grey font-neue-montreal-medium focus:ring-b3-primary-blue/20 w-full rounded-xl p-4 focus:outline-none focus:ring-2", value: phone, onChange: e => setPhone(e.target.value), disabled: otpSent || (isLinking && linkingMethod === "phone") }), (0, jsx_runtime_1.jsx)("p", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "Include country code (e.g., +1 for US)" })] })), error && (0, jsx_runtime_1.jsx)("div", { className: "text-b3-negative font-neue-montreal-medium py-2 text-sm", children: error }), otpSent ? ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-b3-grey font-neue-montreal-medium text-sm", children: "Verification Code" }), (0, jsx_runtime_1.jsx)("input", { type: "text", placeholder: "Enter verification code", className: "bg-b3-line text-b3-grey font-neue-montreal-medium focus:ring-b3-primary-blue/20 w-full rounded-xl p-4 focus:outline-none focus:ring-2", value: otp, onChange: e => setOtp(e.target.value), disabled: isLinking && linkingMethod === selectedMethod })] }), (0, jsx_runtime_1.jsx)(button_1.Button, { className: "bg-b3-primary-blue hover:bg-b3-primary-blue/90 font-neue-montreal-semibold h-12 w-full text-white", onClick: handleLinkAccount, disabled: !otp || (isLinking && linkingMethod === selectedMethod), children: isLinking && linkingMethod === selectedMethod ? (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "animate-spin" }) : "Link Account" })] })) : ((0, jsx_runtime_1.jsx)(button_1.Button, { className: "bg-b3-primary-blue hover:bg-b3-primary-blue/90 font-neue-montreal-semibold h-12 w-full text-white", onClick: handleSendOTP, disabled: (!email && !phone) || (isLinking && linkingMethod === selectedMethod), children: isLinking && linkingMethod === selectedMethod ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "animate-spin" })) : ("Send Verification Code") }))] }))] }));
240
+ }, disabled: linkingMethod === method.id, children: isLinking && linkingMethod === method.id ? (0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "animate-spin" }) : method.label }, method.id))), availableAuthMethods.length === 0 && ((0, jsx_runtime_1.jsx)("div", { className: "text-b3-foreground-muted py-8 text-center", children: "All available authentication methods have been connected" }))] })) : ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [selectedMethod === "email" && ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-b3-grey font-neue-montreal-medium text-sm", children: "Email Address" }), (0, jsx_runtime_1.jsx)("input", { type: "email", placeholder: "Enter your email", className: "bg-b3-line text-b3-grey font-neue-montreal-medium focus:ring-b3-primary-blue/20 w-full rounded-xl p-4 focus:outline-none focus:ring-2", value: email, onChange: e => setEmail(e.target.value), disabled: otpSent || (isLinking && linkingMethod === "email") })] })), selectedMethod === "phone" && ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-b3-grey font-neue-montreal-medium text-sm", children: "Phone Number" }), (0, jsx_runtime_1.jsx)("input", { type: "tel", placeholder: "Enter your phone number", className: "bg-b3-line text-b3-grey font-neue-montreal-medium focus:ring-b3-primary-blue/20 w-full rounded-xl p-4 focus:outline-none focus:ring-2", value: phone, onChange: e => setPhone(e.target.value), disabled: otpSent || (isLinking && linkingMethod === "phone") }), (0, jsx_runtime_1.jsx)("p", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "Include country code (e.g., +1 for US)" })] })), error && (0, jsx_runtime_1.jsx)("div", { className: "text-b3-negative font-neue-montreal-medium py-2 text-sm", children: error }), otpSent ? ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-b3-grey font-neue-montreal-medium text-sm", children: "Verification Code" }), (0, jsx_runtime_1.jsx)("input", { type: "text", placeholder: "Enter verification code", className: "bg-b3-line text-b3-grey font-neue-montreal-medium focus:ring-b3-primary-blue/20 w-full rounded-xl p-4 focus:outline-none focus:ring-2", value: otp, onChange: e => setOtp(e.target.value) })] }), (0, jsx_runtime_1.jsx)(button_1.Button, { className: "bg-b3-primary-blue hover:bg-b3-primary-blue/90 font-neue-montreal-semibold h-12 w-full text-white", onClick: handleLinkAccount, children: "Link Account" })] })) : ((0, jsx_runtime_1.jsx)(button_1.Button, { className: "bg-b3-primary-blue hover:bg-b3-primary-blue/90 font-neue-montreal-semibold h-12 w-full text-white", onClick: handleSendOTP, disabled: (!email && !phone) || (isLinking && linkingMethod === selectedMethod), children: isLinking && linkingMethod === selectedMethod ? ((0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "animate-spin" })) : ("Send Verification Code") }))] }))] }));
228
241
  }
@@ -140,5 +140,5 @@ function ManageAccount({ onLogout, onSwap: _onSwap, onDeposit: _onDeposit, chain
140
140
  if (["balance", "assets", "apps", "settings"].includes(tab)) {
141
141
  setActiveTab?.(tab);
142
142
  }
143
- }, children: [(0, jsx_runtime_1.jsxs)(react_1.TabsListPrimitive, { className: "font-neue-montreal-semibold text-b3-grey flex h-8 w-full items-start justify-start gap-8 border-0 text-xl md:p-4", children: [(0, jsx_runtime_1.jsx)(react_1.TabTriggerPrimitive, { value: "balance", className: "data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4", children: "Overview" }), (0, jsx_runtime_1.jsx)(react_1.TabTriggerPrimitive, { value: "assets", className: "data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4", children: "Mints" }), (0, jsx_runtime_1.jsx)(react_1.TabTriggerPrimitive, { value: "apps", className: "data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4", children: "Apps" }), (0, jsx_runtime_1.jsx)(react_1.TabTriggerPrimitive, { value: "settings", className: "data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4", children: "Settings" })] }), (0, jsx_runtime_1.jsx)(react_1.TabsContentPrimitive, { value: "balance", className: "pt-4 md:p-4", children: (0, jsx_runtime_1.jsx)(BalanceContent, {}) }), (0, jsx_runtime_1.jsx)(react_1.TabsContentPrimitive, { value: "assets", className: "pt-4 md:p-4", children: (0, jsx_runtime_1.jsx)(AssetsContent, {}) }), (0, jsx_runtime_1.jsx)(react_1.TabsContentPrimitive, { value: "apps", className: "pt-4 md:p-4", children: (0, jsx_runtime_1.jsx)(AppsContent, {}) }), (0, jsx_runtime_1.jsx)(react_1.TabsContentPrimitive, { value: "settings", className: "pt-4 md:p-4", children: (0, jsx_runtime_1.jsx)(SettingsContent, {}) })] }) }) }));
143
+ }, children: [(0, jsx_runtime_1.jsxs)(react_1.TabsListPrimitive, { className: "font-neue-montreal-semibold text-b3-grey flex h-8 w-full items-start justify-start gap-8 border-0 text-xl md:p-4", children: [(0, jsx_runtime_1.jsx)(react_1.TabTriggerPrimitive, { value: "balance", className: "data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4", children: "Overview" }), (0, jsx_runtime_1.jsx)(react_1.TabTriggerPrimitive, { value: "assets", className: "data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4", children: "Mints" }), (0, jsx_runtime_1.jsx)(react_1.TabTriggerPrimitive, { value: "settings", className: "data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4", children: "Settings" })] }), (0, jsx_runtime_1.jsx)(react_1.TabsContentPrimitive, { value: "balance", className: "pt-4 md:p-4", children: (0, jsx_runtime_1.jsx)(BalanceContent, {}) }), (0, jsx_runtime_1.jsx)(react_1.TabsContentPrimitive, { value: "assets", className: "pt-4 md:p-4", children: (0, jsx_runtime_1.jsx)(AssetsContent, {}) }), (0, jsx_runtime_1.jsx)(react_1.TabsContentPrimitive, { value: "apps", className: "pt-4 md:p-4", children: (0, jsx_runtime_1.jsx)(AppsContent, {}) }), (0, jsx_runtime_1.jsx)(react_1.TabsContentPrimitive, { value: "settings", className: "pt-4 md:p-4", children: (0, jsx_runtime_1.jsx)(SettingsContent, {}) })] }) }) }));
144
144
  }
@@ -21,6 +21,7 @@ import { RecipientSelection } from "./common/RecipientSelection.js";
21
21
  import { ESCROW_ABI } from "../../../anyspend/abis/escrow.js";
22
22
  import { ArrowDown } from "lucide-react";
23
23
  import { PanelOnramp } from "./common/PanelOnramp.js";
24
+ const SLIPPAGE_PERCENT = 3;
24
25
  function generateEncodedDataForDepositHype(amount, beneficiary) {
25
26
  invariant(BigInt(amount) > 0, "Amount must be greater than zero");
26
27
  const encodedData = encodeFunctionData({
@@ -44,6 +45,7 @@ function AnySpendDepositHypeInner({ loadOrder, mode = "modal", recipientAddress,
44
45
  onTransactionSuccess: onSuccess,
45
46
  sourceTokenAddress,
46
47
  sourceTokenChainId,
48
+ slippage: SLIPPAGE_PERCENT,
47
49
  });
48
50
  // Button state logic
49
51
  const btnInfo = useMemo(() => {
@@ -127,7 +129,10 @@ function AnySpendDepositHypeInner({ loadOrder, mode = "modal", recipientAddress,
127
129
  invariant(selectedRecipientAddress, "Recipient address is not found");
128
130
  invariant(depositContractAddress, "Deposit contract address is not found");
129
131
  const srcAmountBigInt = BigInt(activeInputAmountInWei);
130
- const depositAmountWei = anyspendQuote.data?.currencyOut?.amount || "0";
132
+ // TODO: temp subtract 3% for slippage
133
+ const originalDepositAmountWei = anyspendQuote.data?.currencyOut?.amount || "0";
134
+ const depositAmountWei = ((BigInt(originalDepositAmountWei) * BigInt(100 - SLIPPAGE_PERCENT)) /
135
+ BigInt(100)).toString();
131
136
  const encodedData = generateEncodedDataForDepositHype(depositAmountWei, selectedRecipientAddress);
132
137
  createOrder({
133
138
  recipientAddress: selectedRecipientAddress,
@@ -234,7 +239,6 @@ function AnySpendDepositHypeInner({ loadOrder, mode = "modal", recipientAddress,
234
239
  setSelectedFiatPaymentMethod(method);
235
240
  setActivePanel(PanelView.MAIN);
236
241
  }, srcAmountOnRamp: srcAmount }));
237
- console.log("activePanel", activePanel, orderId, oat);
238
242
  // If showing token selection, render with panel transitions
239
243
  return (_jsx(StyleRoot, { children: _jsx("div", { className: cn("anyspend-container font-inter mx-auto w-full max-w-[460px]", mode === "page" &&
240
244
  "bg-as-surface-primary border-as-border-secondary overflow-hidden rounded-2xl border shadow-xl"), children: _jsx(TransitionPanel, { activeIndex: orderId
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { ALL_CHAINS, getChainName, getErrorDisplay, getExplorerTxUrl, getPaymentUrl, getStatusDisplay, isNativeToken, RELAY_ETH_ADDRESS, RELAY_SOLANA_MAINNET_CHAIN_ID, } from "../../../../anyspend/index.js";
3
+ import { ALL_CHAINS, DEPOSIT_HYPE_ACTION, getChainName, getErrorDisplay, getExplorerTxUrl, getPaymentUrl, getStatusDisplay, isNativeToken, RELAY_ETH_ADDRESS, RELAY_SOLANA_MAINNET_CHAIN_ID, } from "../../../../anyspend/index.js";
4
4
  import { Badge, Button, CopyToClipboard, ShinyButton, Skeleton, TextLoop, TextShimmer, useAccountWallet, useModalStore, useProfile, useUnifiedChainSwitchAndExecute, } from "../../../../global-account/react/index.js";
5
5
  import { useRouter, useSearchParams } from "../../../../shared/react/hooks/index.js";
6
6
  import { cn } from "../../../../shared/utils/index.js";
@@ -43,6 +43,9 @@ function getOrderSuccessText({ order, tournament, formattedActualDstAmount, dstT
43
43
  actionText = `funded ${tournament?.name}`;
44
44
  return `Successfully ${actionText}`;
45
45
  case "custom":
46
+ if (order.metadata.action === DEPOSIT_HYPE_ACTION) {
47
+ return `Successfully deposited ${formatTokenAmount(BigInt(order.payload?.amount || "0"), 18)} HYPE to ${recipient}`;
48
+ }
46
49
  actionText = order.metadata.action || `executed contract`;
47
50
  return `Successfully ${actionText}`;
48
51
  default:
@@ -18,8 +18,9 @@ interface UseAnyspendFlowProps {
18
18
  onTransactionSuccess?: () => void;
19
19
  sourceTokenAddress?: string;
20
20
  sourceTokenChainId?: number;
21
+ slippage?: number;
21
22
  }
22
- export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrder, isDepositMode, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, }: UseAnyspendFlowProps): {
23
+ export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrder, isDepositMode, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, slippage, }: UseAnyspendFlowProps): {
23
24
  activePanel: PanelView;
24
25
  setActivePanel: import("react").Dispatch<import("react").SetStateAction<PanelView>>;
25
26
  orderId: string | undefined;
@@ -18,7 +18,7 @@ export var PanelView;
18
18
  PanelView[PanelView["ORDER_DETAILS"] = 4] = "ORDER_DETAILS";
19
19
  PanelView[PanelView["LOADING"] = 5] = "LOADING";
20
20
  })(PanelView || (PanelView = {}));
21
- export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder, isDepositMode = false, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, }) {
21
+ export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder, isDepositMode = false, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, slippage = 0, }) {
22
22
  const searchParams = useSearchParamsSSR();
23
23
  const router = useRouter();
24
24
  // Panel and order state
@@ -99,13 +99,15 @@ export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, load
99
99
  if (anyspendQuote?.data?.currencyOut?.amount && anyspendQuote.data.currencyOut.currency?.decimals) {
100
100
  const amount = anyspendQuote.data.currencyOut.amount;
101
101
  const decimals = anyspendQuote.data.currencyOut.currency.decimals;
102
- const formattedAmount = formatTokenAmount(BigInt(amount), decimals, 6, false);
102
+ // Apply slippage (0-100) - reduce amount by slippage percentageFixed slippage value
103
+ const amountWithSlippage = (BigInt(amount) * BigInt(100 - slippage)) / BigInt(100);
104
+ const formattedAmount = formatTokenAmount(amountWithSlippage, decimals, 6, false);
103
105
  setDstAmount(formattedAmount);
104
106
  }
105
107
  else {
106
108
  setDstAmount("");
107
109
  }
108
- }, [anyspendQuote]);
110
+ }, [anyspendQuote, slippage]);
109
111
  // Update useEffect for URL parameter to not override loadOrder
110
112
  useEffect(() => {
111
113
  if (loadOrder)
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ecosystemWalletId } from "../../../../shared/constants/index.js";
2
3
  import { client } from "../../../../shared/utils/thirdweb.js";
3
4
  import { Loader2 } from "lucide-react";
4
5
  import { useCallback, useEffect, useState } from "react";
@@ -94,6 +95,10 @@ export function LinkAccount({ onSuccess: onSuccessCallback, onError, onClose, ch
94
95
  client,
95
96
  strategy: "email",
96
97
  email,
98
+ ecosystem: {
99
+ id: ecosystemWalletId,
100
+ partnerId: partnerId,
101
+ },
97
102
  });
98
103
  }
99
104
  else if (selectedMethod === "phone") {
@@ -101,6 +106,10 @@ export function LinkAccount({ onSuccess: onSuccessCallback, onError, onClose, ch
101
106
  client,
102
107
  strategy: "phone",
103
108
  phoneNumber: phone,
109
+ ecosystem: {
110
+ id: ecosystemWalletId,
111
+ partnerId: partnerId,
112
+ },
104
113
  });
105
114
  }
106
115
  setOtpSent(true);
@@ -114,10 +123,12 @@ export function LinkAccount({ onSuccess: onSuccessCallback, onError, onClose, ch
114
123
  };
115
124
  const handleLinkAccount = async () => {
116
125
  if (!otp) {
126
+ console.error("No OTP entered");
117
127
  setError("Please enter the verification code");
118
128
  return;
119
129
  }
120
130
  try {
131
+ setOtpSent(false);
121
132
  setLinkingState(true, selectedMethod);
122
133
  setError(null);
123
134
  if (selectedMethod === "email") {
@@ -136,17 +147,12 @@ export function LinkAccount({ onSuccess: onSuccessCallback, onError, onClose, ch
136
147
  verificationCode: otp,
137
148
  }, mutationOptions);
138
149
  }
139
- onSuccess?.();
140
- onClose?.();
141
150
  }
142
151
  catch (error) {
143
152
  console.error("Error linking account:", error);
144
153
  setError(error instanceof Error ? error.message : "Failed to link account");
145
154
  onError?.(error);
146
155
  }
147
- finally {
148
- setLinkingState(false);
149
- }
150
156
  };
151
157
  const handleSocialLink = async (strategy) => {
152
158
  try {
@@ -197,17 +203,24 @@ export function LinkAccount({ onSuccess: onSuccessCallback, onError, onClose, ch
197
203
  setError(null);
198
204
  setLinkingState(false);
199
205
  }, [isLinking, setSelectedMethod, setEmail, setPhone, setOtp, setOtpSent, setError, setLinkingState]);
206
+ const handleFinishedLinking = useCallback((success) => {
207
+ if (success) {
208
+ onSuccess?.();
209
+ onClose?.();
210
+ }
211
+ setLinkingState(false);
212
+ navigateBack();
213
+ setB3ModalContentType({
214
+ type: "manageAccount",
215
+ activeTab: "settings",
216
+ setActiveTab: () => { },
217
+ chain,
218
+ partnerId,
219
+ });
220
+ }, [chain, navigateBack, partnerId, setB3ModalContentType, setLinkingState, onSuccess, onClose]);
200
221
  useEffect(() => {
201
222
  if (isLinking) {
202
- setLinkingState(false);
203
- navigateBack();
204
- setB3ModalContentType({
205
- type: "manageAccount",
206
- activeTab: "settings",
207
- setActiveTab: () => { },
208
- chain,
209
- partnerId,
210
- });
223
+ handleFinishedLinking(true);
211
224
  }
212
225
  // eslint-disable-next-line react-hooks/exhaustive-deps
213
226
  }, [profiles.length]);
@@ -221,5 +234,5 @@ export function LinkAccount({ onSuccess: onSuccessCallback, onError, onClose, ch
221
234
  else {
222
235
  handleSocialLink(method.id);
223
236
  }
224
- }, disabled: linkingMethod === method.id, children: isLinking && linkingMethod === method.id ? _jsx(Loader2, { className: "animate-spin" }) : method.label }, method.id))), availableAuthMethods.length === 0 && (_jsx("div", { className: "text-b3-foreground-muted py-8 text-center", children: "All available authentication methods have been connected" }))] })) : (_jsxs("div", { className: "space-y-4", children: [selectedMethod === "email" && (_jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-b3-grey font-neue-montreal-medium text-sm", children: "Email Address" }), _jsx("input", { type: "email", placeholder: "Enter your email", className: "bg-b3-line text-b3-grey font-neue-montreal-medium focus:ring-b3-primary-blue/20 w-full rounded-xl p-4 focus:outline-none focus:ring-2", value: email, onChange: e => setEmail(e.target.value), disabled: otpSent || (isLinking && linkingMethod === "email") })] })), selectedMethod === "phone" && (_jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-b3-grey font-neue-montreal-medium text-sm", children: "Phone Number" }), _jsx("input", { type: "tel", placeholder: "Enter your phone number", className: "bg-b3-line text-b3-grey font-neue-montreal-medium focus:ring-b3-primary-blue/20 w-full rounded-xl p-4 focus:outline-none focus:ring-2", value: phone, onChange: e => setPhone(e.target.value), disabled: otpSent || (isLinking && linkingMethod === "phone") }), _jsx("p", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "Include country code (e.g., +1 for US)" })] })), error && _jsx("div", { className: "text-b3-negative font-neue-montreal-medium py-2 text-sm", children: error }), otpSent ? (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-b3-grey font-neue-montreal-medium text-sm", children: "Verification Code" }), _jsx("input", { type: "text", placeholder: "Enter verification code", className: "bg-b3-line text-b3-grey font-neue-montreal-medium focus:ring-b3-primary-blue/20 w-full rounded-xl p-4 focus:outline-none focus:ring-2", value: otp, onChange: e => setOtp(e.target.value), disabled: isLinking && linkingMethod === selectedMethod })] }), _jsx(Button, { className: "bg-b3-primary-blue hover:bg-b3-primary-blue/90 font-neue-montreal-semibold h-12 w-full text-white", onClick: handleLinkAccount, disabled: !otp || (isLinking && linkingMethod === selectedMethod), children: isLinking && linkingMethod === selectedMethod ? _jsx(Loader2, { className: "animate-spin" }) : "Link Account" })] })) : (_jsx(Button, { className: "bg-b3-primary-blue hover:bg-b3-primary-blue/90 font-neue-montreal-semibold h-12 w-full text-white", onClick: handleSendOTP, disabled: (!email && !phone) || (isLinking && linkingMethod === selectedMethod), children: isLinking && linkingMethod === selectedMethod ? (_jsx(Loader2, { className: "animate-spin" })) : ("Send Verification Code") }))] }))] }));
237
+ }, disabled: linkingMethod === method.id, children: isLinking && linkingMethod === method.id ? _jsx(Loader2, { className: "animate-spin" }) : method.label }, method.id))), availableAuthMethods.length === 0 && (_jsx("div", { className: "text-b3-foreground-muted py-8 text-center", children: "All available authentication methods have been connected" }))] })) : (_jsxs("div", { className: "space-y-4", children: [selectedMethod === "email" && (_jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-b3-grey font-neue-montreal-medium text-sm", children: "Email Address" }), _jsx("input", { type: "email", placeholder: "Enter your email", className: "bg-b3-line text-b3-grey font-neue-montreal-medium focus:ring-b3-primary-blue/20 w-full rounded-xl p-4 focus:outline-none focus:ring-2", value: email, onChange: e => setEmail(e.target.value), disabled: otpSent || (isLinking && linkingMethod === "email") })] })), selectedMethod === "phone" && (_jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-b3-grey font-neue-montreal-medium text-sm", children: "Phone Number" }), _jsx("input", { type: "tel", placeholder: "Enter your phone number", className: "bg-b3-line text-b3-grey font-neue-montreal-medium focus:ring-b3-primary-blue/20 w-full rounded-xl p-4 focus:outline-none focus:ring-2", value: phone, onChange: e => setPhone(e.target.value), disabled: otpSent || (isLinking && linkingMethod === "phone") }), _jsx("p", { className: "text-b3-foreground-muted font-neue-montreal-medium text-sm", children: "Include country code (e.g., +1 for US)" })] })), error && _jsx("div", { className: "text-b3-negative font-neue-montreal-medium py-2 text-sm", children: error }), otpSent ? (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-b3-grey font-neue-montreal-medium text-sm", children: "Verification Code" }), _jsx("input", { type: "text", placeholder: "Enter verification code", className: "bg-b3-line text-b3-grey font-neue-montreal-medium focus:ring-b3-primary-blue/20 w-full rounded-xl p-4 focus:outline-none focus:ring-2", value: otp, onChange: e => setOtp(e.target.value) })] }), _jsx(Button, { className: "bg-b3-primary-blue hover:bg-b3-primary-blue/90 font-neue-montreal-semibold h-12 w-full text-white", onClick: handleLinkAccount, children: "Link Account" })] })) : (_jsx(Button, { className: "bg-b3-primary-blue hover:bg-b3-primary-blue/90 font-neue-montreal-semibold h-12 w-full text-white", onClick: handleSendOTP, disabled: (!email && !phone) || (isLinking && linkingMethod === selectedMethod), children: isLinking && linkingMethod === selectedMethod ? (_jsx(Loader2, { className: "animate-spin" })) : ("Send Verification Code") }))] }))] }));
225
238
  }
@@ -134,5 +134,5 @@ export function ManageAccount({ onLogout, onSwap: _onSwap, onDeposit: _onDeposit
134
134
  if (["balance", "assets", "apps", "settings"].includes(tab)) {
135
135
  setActiveTab?.(tab);
136
136
  }
137
- }, children: [_jsxs(TabsListPrimitive, { className: "font-neue-montreal-semibold text-b3-grey flex h-8 w-full items-start justify-start gap-8 border-0 text-xl md:p-4", children: [_jsx(TabTriggerPrimitive, { value: "balance", className: "data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4", children: "Overview" }), _jsx(TabTriggerPrimitive, { value: "assets", className: "data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4", children: "Mints" }), _jsx(TabTriggerPrimitive, { value: "apps", className: "data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4", children: "Apps" }), _jsx(TabTriggerPrimitive, { value: "settings", className: "data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4", children: "Settings" })] }), _jsx(TabsContentPrimitive, { value: "balance", className: "pt-4 md:p-4", children: _jsx(BalanceContent, {}) }), _jsx(TabsContentPrimitive, { value: "assets", className: "pt-4 md:p-4", children: _jsx(AssetsContent, {}) }), _jsx(TabsContentPrimitive, { value: "apps", className: "pt-4 md:p-4", children: _jsx(AppsContent, {}) }), _jsx(TabsContentPrimitive, { value: "settings", className: "pt-4 md:p-4", children: _jsx(SettingsContent, {}) })] }) }) }));
137
+ }, children: [_jsxs(TabsListPrimitive, { className: "font-neue-montreal-semibold text-b3-grey flex h-8 w-full items-start justify-start gap-8 border-0 text-xl md:p-4", children: [_jsx(TabTriggerPrimitive, { value: "balance", className: "data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4", children: "Overview" }), _jsx(TabTriggerPrimitive, { value: "assets", className: "data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4", children: "Mints" }), _jsx(TabTriggerPrimitive, { value: "settings", className: "data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4", children: "Settings" })] }), _jsx(TabsContentPrimitive, { value: "balance", className: "pt-4 md:p-4", children: _jsx(BalanceContent, {}) }), _jsx(TabsContentPrimitive, { value: "assets", className: "pt-4 md:p-4", children: _jsx(AssetsContent, {}) }), _jsx(TabsContentPrimitive, { value: "apps", className: "pt-4 md:p-4", children: _jsx(AppsContent, {}) }), _jsx(TabsContentPrimitive, { value: "settings", className: "pt-4 md:p-4", children: _jsx(SettingsContent, {}) })] }) }) }));
138
138
  }
@@ -18,8 +18,9 @@ interface UseAnyspendFlowProps {
18
18
  onTransactionSuccess?: () => void;
19
19
  sourceTokenAddress?: string;
20
20
  sourceTokenChainId?: number;
21
+ slippage?: number;
21
22
  }
22
- export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrder, isDepositMode, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, }: UseAnyspendFlowProps): {
23
+ export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrder, isDepositMode, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, slippage, }: UseAnyspendFlowProps): {
23
24
  activePanel: PanelView;
24
25
  setActivePanel: import("react").Dispatch<import("react").SetStateAction<PanelView>>;
25
26
  orderId: string | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@b3dotfun/sdk",
3
- "version": "0.0.29-alpha.4",
3
+ "version": "0.0.29-alpha.6",
4
4
  "source": "src/index.ts",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "react-native": "./dist/cjs/index.native.js",
@@ -22,6 +22,8 @@ import { ESCROW_ABI } from "@b3dotfun/sdk/anyspend/abis/escrow";
22
22
  import { ArrowDown } from "lucide-react";
23
23
  import { PanelOnramp } from "./common/PanelOnramp";
24
24
 
25
+ const SLIPPAGE_PERCENT = 3;
26
+
25
27
  function generateEncodedDataForDepositHype(amount: string, beneficiary: string): string {
26
28
  invariant(BigInt(amount) > 0, "Amount must be greater than zero");
27
29
  const encodedData = encodeFunctionData({
@@ -107,6 +109,7 @@ function AnySpendDepositHypeInner({
107
109
  onTransactionSuccess: onSuccess,
108
110
  sourceTokenAddress,
109
111
  sourceTokenChainId,
112
+ slippage: SLIPPAGE_PERCENT,
110
113
  });
111
114
 
112
115
  // Button state logic
@@ -308,7 +311,12 @@ function AnySpendDepositHypeInner({
308
311
  invariant(depositContractAddress, "Deposit contract address is not found");
309
312
 
310
313
  const srcAmountBigInt = BigInt(activeInputAmountInWei);
311
- const depositAmountWei = anyspendQuote.data?.currencyOut?.amount || "0";
314
+ // TODO: temp subtract 3% for slippage
315
+ const originalDepositAmountWei = anyspendQuote.data?.currencyOut?.amount || "0";
316
+ const depositAmountWei = (
317
+ (BigInt(originalDepositAmountWei) * BigInt(100 - SLIPPAGE_PERCENT)) /
318
+ BigInt(100)
319
+ ).toString();
312
320
  const encodedData = generateEncodedDataForDepositHype(depositAmountWei, selectedRecipientAddress);
313
321
 
314
322
  createOrder({
@@ -472,8 +480,6 @@ function AnySpendDepositHypeInner({
472
480
  />
473
481
  );
474
482
 
475
- console.log("activePanel", activePanel, orderId, oat);
476
-
477
483
  // If showing token selection, render with panel transitions
478
484
  return (
479
485
  <StyleRoot>
@@ -2,6 +2,7 @@
2
2
 
3
3
  import {
4
4
  ALL_CHAINS,
5
+ DEPOSIT_HYPE_ACTION,
5
6
  getChainName,
6
7
  getErrorDisplay,
7
8
  getExplorerTxUrl,
@@ -97,6 +98,9 @@ function getOrderSuccessText({
97
98
  actionText = `funded ${tournament?.name}`;
98
99
  return `Successfully ${actionText}`;
99
100
  case "custom":
101
+ if (order.metadata.action === DEPOSIT_HYPE_ACTION) {
102
+ return `Successfully deposited ${formatTokenAmount(BigInt(order.payload?.amount || "0"), 18)} HYPE to ${recipient}`;
103
+ }
100
104
  actionText = order.metadata.action || `executed contract`;
101
105
  return `Successfully ${actionText}`;
102
106
  default:
@@ -35,6 +35,7 @@ interface UseAnyspendFlowProps {
35
35
  onTransactionSuccess?: () => void;
36
36
  sourceTokenAddress?: string;
37
37
  sourceTokenChainId?: number;
38
+ slippage?: number;
38
39
  }
39
40
 
40
41
  export function useAnyspendFlow({
@@ -46,6 +47,7 @@ export function useAnyspendFlow({
46
47
  onTransactionSuccess,
47
48
  sourceTokenAddress,
48
49
  sourceTokenChainId,
50
+ slippage = 0,
49
51
  }: UseAnyspendFlowProps) {
50
52
  const searchParams = useSearchParamsSSR();
51
53
  const router = useRouter();
@@ -144,12 +146,16 @@ export function useAnyspendFlow({
144
146
  if (anyspendQuote?.data?.currencyOut?.amount && anyspendQuote.data.currencyOut.currency?.decimals) {
145
147
  const amount = anyspendQuote.data.currencyOut.amount;
146
148
  const decimals = anyspendQuote.data.currencyOut.currency.decimals;
147
- const formattedAmount = formatTokenAmount(BigInt(amount), decimals, 6, false);
149
+
150
+ // Apply slippage (0-100) - reduce amount by slippage percentageFixed slippage value
151
+ const amountWithSlippage = (BigInt(amount) * BigInt(100 - slippage)) / BigInt(100);
152
+
153
+ const formattedAmount = formatTokenAmount(amountWithSlippage, decimals, 6, false);
148
154
  setDstAmount(formattedAmount);
149
155
  } else {
150
156
  setDstAmount("");
151
157
  }
152
- }, [anyspendQuote]);
158
+ }, [anyspendQuote, slippage]);
153
159
 
154
160
  // Update useEffect for URL parameter to not override loadOrder
155
161
  useEffect(() => {
@@ -1,3 +1,4 @@
1
+ import { ecosystemWalletId } from "@b3dotfun/sdk/shared/constants";
1
2
  import { client } from "@b3dotfun/sdk/shared/utils/thirdweb";
2
3
  import { Loader2 } from "lucide-react";
3
4
  import { useCallback, useEffect, useState } from "react";
@@ -122,12 +123,20 @@ export function LinkAccount({
122
123
  client,
123
124
  strategy: "email",
124
125
  email,
126
+ ecosystem: {
127
+ id: ecosystemWalletId,
128
+ partnerId: partnerId,
129
+ },
125
130
  });
126
131
  } else if (selectedMethod === "phone") {
127
132
  await preAuthenticate({
128
133
  client,
129
134
  strategy: "phone",
130
135
  phoneNumber: phone,
136
+ ecosystem: {
137
+ id: ecosystemWalletId,
138
+ partnerId: partnerId,
139
+ },
131
140
  });
132
141
  }
133
142
 
@@ -142,11 +151,13 @@ export function LinkAccount({
142
151
 
143
152
  const handleLinkAccount = async () => {
144
153
  if (!otp) {
154
+ console.error("No OTP entered");
145
155
  setError("Please enter the verification code");
146
156
  return;
147
157
  }
148
158
 
149
159
  try {
160
+ setOtpSent(false);
150
161
  setLinkingState(true, selectedMethod);
151
162
  setError(null);
152
163
 
@@ -171,15 +182,10 @@ export function LinkAccount({
171
182
  mutationOptions,
172
183
  );
173
184
  }
174
-
175
- onSuccess?.();
176
- onClose?.();
177
185
  } catch (error) {
178
186
  console.error("Error linking account:", error);
179
187
  setError(error instanceof Error ? error.message : "Failed to link account");
180
188
  onError?.(error as Error);
181
- } finally {
182
- setLinkingState(false);
183
189
  }
184
190
  };
185
191
 
@@ -239,8 +245,13 @@ export function LinkAccount({
239
245
  setLinkingState(false);
240
246
  }, [isLinking, setSelectedMethod, setEmail, setPhone, setOtp, setOtpSent, setError, setLinkingState]);
241
247
 
242
- useEffect(() => {
243
- if (isLinking) {
248
+ const handleFinishedLinking = useCallback(
249
+ (success: boolean) => {
250
+ if (success) {
251
+ onSuccess?.();
252
+ onClose?.();
253
+ }
254
+
244
255
  setLinkingState(false);
245
256
  navigateBack();
246
257
  setB3ModalContentType({
@@ -250,6 +261,13 @@ export function LinkAccount({
250
261
  chain,
251
262
  partnerId,
252
263
  });
264
+ },
265
+ [chain, navigateBack, partnerId, setB3ModalContentType, setLinkingState, onSuccess, onClose],
266
+ );
267
+
268
+ useEffect(() => {
269
+ if (isLinking) {
270
+ handleFinishedLinking(true);
253
271
  }
254
272
  // eslint-disable-next-line react-hooks/exhaustive-deps
255
273
  }, [profiles.length]);
@@ -338,15 +356,13 @@ export function LinkAccount({
338
356
  className="bg-b3-line text-b3-grey font-neue-montreal-medium focus:ring-b3-primary-blue/20 w-full rounded-xl p-4 focus:outline-none focus:ring-2"
339
357
  value={otp}
340
358
  onChange={e => setOtp(e.target.value)}
341
- disabled={isLinking && linkingMethod === selectedMethod}
342
359
  />
343
360
  </div>
344
361
  <Button
345
362
  className="bg-b3-primary-blue hover:bg-b3-primary-blue/90 font-neue-montreal-semibold h-12 w-full text-white"
346
363
  onClick={handleLinkAccount}
347
- disabled={!otp || (isLinking && linkingMethod === selectedMethod)}
348
364
  >
349
- {isLinking && linkingMethod === selectedMethod ? <Loader2 className="animate-spin" /> : "Link Account"}
365
+ Link Account
350
366
  </Button>
351
367
  </div>
352
368
  ) : (
@@ -597,12 +597,16 @@ export function ManageAccount({
597
597
  >
598
598
  Mints
599
599
  </TabTriggerPrimitive>
600
+ {/*
601
+ // TODO: Apps is a remnant of session key flow. Moving forward, we should find a way to properly associate apps from linked partners that a user has logged in with
602
+ https://linear.app/npclabs/issue/B3-2318/find-a-way-to-properly-display-which-partner-apps-a-user-has-logged-in
603
+
600
604
  <TabTriggerPrimitive
601
605
  value="apps"
602
606
  className="data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4"
603
607
  >
604
608
  Apps
605
- </TabTriggerPrimitive>
609
+ </TabTriggerPrimitive> */}
606
610
  <TabTriggerPrimitive
607
611
  value="settings"
608
612
  className="data-[state=active]:text-b3-primary-blue data-[state=active]:border-b-b3-primary-blue flex-none rounded-none border-0 p-0 pb-1 text-xl leading-none tracking-wide transition-colors data-[state=active]:border-b data-[state=active]:bg-white md:pb-4"