thirdweb 5.112.4 → 5.113.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/dist/cjs/exports/react.js +4 -1
- package/dist/cjs/exports/react.js.map +1 -1
- package/dist/cjs/exports/react.native.js +4 -1
- package/dist/cjs/exports/react.native.js.map +1 -1
- package/dist/cjs/react/core/hooks/x402/useFetchWithPaymentCore.js +110 -0
- package/dist/cjs/react/core/hooks/x402/useFetchWithPaymentCore.js.map +1 -0
- package/dist/cjs/react/native/hooks/x402/useFetchWithPayment.js +89 -0
- package/dist/cjs/react/native/hooks/x402/useFetchWithPayment.js.map +1 -0
- package/dist/cjs/react/web/hooks/x402/useFetchWithPayment.js +168 -0
- package/dist/cjs/react/web/hooks/x402/useFetchWithPayment.js.map +1 -0
- package/dist/cjs/react/web/ui/components/basic.js +1 -1
- package/dist/cjs/react/web/ui/x402/PaymentErrorModal.js +107 -0
- package/dist/cjs/react/web/ui/x402/PaymentErrorModal.js.map +1 -0
- package/dist/cjs/react/web/ui/x402/SignInRequiredModal.js +28 -0
- package/dist/cjs/react/web/ui/x402/SignInRequiredModal.js.map +1 -0
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/wallets/coinbase/coinbase-web.js +9 -0
- package/dist/cjs/wallets/coinbase/coinbase-web.js.map +1 -1
- package/dist/cjs/x402/facilitator.js +1 -1
- package/dist/cjs/x402/fetchWithPayment.js +9 -7
- package/dist/cjs/x402/fetchWithPayment.js.map +1 -1
- package/dist/cjs/x402/settle-payment.js +1 -1
- package/dist/cjs/x402/verify-payment.js +1 -1
- package/dist/esm/exports/react.js +2 -0
- package/dist/esm/exports/react.js.map +1 -1
- package/dist/esm/exports/react.native.js +2 -0
- package/dist/esm/exports/react.native.js.map +1 -1
- package/dist/esm/react/core/hooks/x402/useFetchWithPaymentCore.js +107 -0
- package/dist/esm/react/core/hooks/x402/useFetchWithPaymentCore.js.map +1 -0
- package/dist/esm/react/native/hooks/x402/useFetchWithPayment.js +86 -0
- package/dist/esm/react/native/hooks/x402/useFetchWithPayment.js.map +1 -0
- package/dist/esm/react/web/hooks/x402/useFetchWithPayment.js +165 -0
- package/dist/esm/react/web/hooks/x402/useFetchWithPayment.js.map +1 -0
- package/dist/esm/react/web/ui/components/basic.js +1 -1
- package/dist/esm/react/web/ui/x402/PaymentErrorModal.js +104 -0
- package/dist/esm/react/web/ui/x402/PaymentErrorModal.js.map +1 -0
- package/dist/esm/react/web/ui/x402/SignInRequiredModal.js +25 -0
- package/dist/esm/react/web/ui/x402/SignInRequiredModal.js.map +1 -0
- package/dist/esm/version.js +1 -1
- package/dist/esm/wallets/coinbase/coinbase-web.js +9 -0
- package/dist/esm/wallets/coinbase/coinbase-web.js.map +1 -1
- package/dist/esm/x402/facilitator.js +1 -1
- package/dist/esm/x402/fetchWithPayment.js +9 -7
- package/dist/esm/x402/fetchWithPayment.js.map +1 -1
- package/dist/esm/x402/settle-payment.js +1 -1
- package/dist/esm/x402/verify-payment.js +1 -1
- package/dist/scripts/bridge-widget.js +50 -50
- package/dist/types/exports/react.d.ts +1 -0
- package/dist/types/exports/react.d.ts.map +1 -1
- package/dist/types/exports/react.native.d.ts +1 -0
- package/dist/types/exports/react.native.d.ts.map +1 -1
- package/dist/types/react/core/hooks/x402/useFetchWithPaymentCore.d.ts +131 -0
- package/dist/types/react/core/hooks/x402/useFetchWithPaymentCore.d.ts.map +1 -0
- package/dist/types/react/native/hooks/x402/useFetchWithPayment.d.ts +189 -0
- package/dist/types/react/native/hooks/x402/useFetchWithPayment.d.ts.map +1 -0
- package/dist/types/react/web/hooks/x402/useFetchWithPayment.d.ts +248 -0
- package/dist/types/react/web/hooks/x402/useFetchWithPayment.d.ts.map +1 -0
- package/dist/types/react/web/ui/x402/PaymentErrorModal.d.ts +20 -0
- package/dist/types/react/web/ui/x402/PaymentErrorModal.d.ts.map +1 -0
- package/dist/types/react/web/ui/x402/SignInRequiredModal.d.ts +12 -0
- package/dist/types/react/web/ui/x402/SignInRequiredModal.d.ts.map +1 -0
- package/dist/types/version.d.ts +1 -1
- package/dist/types/x402/facilitator.d.ts +1 -1
- package/dist/types/x402/fetchWithPayment.d.ts +7 -3
- package/dist/types/x402/fetchWithPayment.d.ts.map +1 -1
- package/dist/types/x402/schemas.d.ts +2 -2
- package/dist/types/x402/settle-payment.d.ts +1 -1
- package/dist/types/x402/verify-payment.d.ts +1 -1
- package/package.json +1 -1
- package/src/exports/react.native.ts +5 -0
- package/src/exports/react.ts +5 -0
- package/src/react/core/hooks/x402/useFetchWithPaymentCore.ts +160 -0
- package/src/react/native/hooks/x402/useFetchWithPayment.ts +96 -0
- package/src/react/web/hooks/x402/useFetchWithPayment.tsx +238 -0
- package/src/react/web/ui/components/basic.tsx +1 -1
- package/src/react/web/ui/x402/PaymentErrorModal.tsx +261 -0
- package/src/react/web/ui/x402/SignInRequiredModal.tsx +75 -0
- package/src/version.ts +1 -1
- package/src/wallets/coinbase/coinbase-web.ts +10 -0
- package/src/x402/facilitator.ts +1 -1
- package/src/x402/fetchWithPayment.ts +19 -12
- package/src/x402/settle-payment.ts +1 -1
- package/src/x402/verify-payment.ts +1 -1
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { getCachedChain } from "../../../../chains/utils.js";
|
|
4
|
+
import type { ThirdwebClient } from "../../../../client/client.js";
|
|
5
|
+
import {
|
|
6
|
+
extractEvmChainId,
|
|
7
|
+
networkToCaip2ChainId,
|
|
8
|
+
type RequestedPaymentRequirements,
|
|
9
|
+
} from "../../../../x402/schemas.js";
|
|
10
|
+
import type { PaymentRequiredResult } from "../../../../x402/types.js";
|
|
11
|
+
import { CustomThemeProvider } from "../../../core/design-system/CustomThemeProvider.js";
|
|
12
|
+
import type { Theme } from "../../../core/design-system/index.js";
|
|
13
|
+
import { spacing } from "../../../core/design-system/index.js";
|
|
14
|
+
import { useActiveWallet } from "../../../core/hooks/wallets/useActiveWallet.js";
|
|
15
|
+
import { BuyWidget, type BuyWidgetProps } from "../Bridge/BuyWidget.js";
|
|
16
|
+
import {
|
|
17
|
+
Container,
|
|
18
|
+
ModalHeader,
|
|
19
|
+
ScreenBottomContainer,
|
|
20
|
+
} from "../components/basic.js";
|
|
21
|
+
import { Button } from "../components/buttons.js";
|
|
22
|
+
import { Modal } from "../components/Modal.js";
|
|
23
|
+
import { Text } from "../components/text.js";
|
|
24
|
+
|
|
25
|
+
type PaymentErrorModalProps = {
|
|
26
|
+
client: ThirdwebClient;
|
|
27
|
+
errorData: PaymentRequiredResult["responseBody"];
|
|
28
|
+
onRetry: () => void;
|
|
29
|
+
onCancel: () => void;
|
|
30
|
+
theme: Theme | "light" | "dark";
|
|
31
|
+
fundWalletOptions?: Partial<
|
|
32
|
+
Omit<
|
|
33
|
+
BuyWidgetProps,
|
|
34
|
+
| "client"
|
|
35
|
+
| "chain"
|
|
36
|
+
| "tokenAddress"
|
|
37
|
+
| "amount"
|
|
38
|
+
| "onSuccess"
|
|
39
|
+
| "onCancel"
|
|
40
|
+
| "theme"
|
|
41
|
+
>
|
|
42
|
+
>;
|
|
43
|
+
paymentRequirementsSelector?: (
|
|
44
|
+
paymentRequirements: RequestedPaymentRequirements[],
|
|
45
|
+
) => RequestedPaymentRequirements | undefined;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
type Screen = "error" | "buy-widget";
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @internal
|
|
52
|
+
*/
|
|
53
|
+
export function PaymentErrorModal(props: PaymentErrorModalProps) {
|
|
54
|
+
const {
|
|
55
|
+
client,
|
|
56
|
+
errorData,
|
|
57
|
+
onRetry,
|
|
58
|
+
onCancel,
|
|
59
|
+
theme,
|
|
60
|
+
fundWalletOptions,
|
|
61
|
+
paymentRequirementsSelector,
|
|
62
|
+
} = props;
|
|
63
|
+
const [screen, setScreen] = useState<Screen>("error");
|
|
64
|
+
const isInsufficientFunds = errorData.error === "insufficient_funds";
|
|
65
|
+
const wallet = useActiveWallet();
|
|
66
|
+
|
|
67
|
+
// Extract chain and token info from errorData for BuyWidget
|
|
68
|
+
const getBuyWidgetConfig = () => {
|
|
69
|
+
if (!errorData.accepts || errorData.accepts.length === 0) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Get payment requirements from errorData
|
|
74
|
+
const parsedPaymentRequirements = errorData.accepts;
|
|
75
|
+
|
|
76
|
+
// Get the current chain from wallet
|
|
77
|
+
const currentChain = wallet?.getChain();
|
|
78
|
+
const currentChainId = currentChain?.id;
|
|
79
|
+
|
|
80
|
+
// Select payment requirement using the same logic as wrapFetchWithPayment
|
|
81
|
+
const selectedRequirement = paymentRequirementsSelector
|
|
82
|
+
? paymentRequirementsSelector(parsedPaymentRequirements)
|
|
83
|
+
: defaultPaymentRequirementsSelector(
|
|
84
|
+
parsedPaymentRequirements,
|
|
85
|
+
currentChainId,
|
|
86
|
+
"exact",
|
|
87
|
+
errorData.error,
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
if (!selectedRequirement) return null;
|
|
91
|
+
|
|
92
|
+
const caip2ChainId = networkToCaip2ChainId(selectedRequirement.network);
|
|
93
|
+
const chainId = extractEvmChainId(caip2ChainId);
|
|
94
|
+
|
|
95
|
+
if (!chainId) return null;
|
|
96
|
+
|
|
97
|
+
const chain = getCachedChain(chainId);
|
|
98
|
+
const tokenAddress = selectedRequirement.asset as `0x${string}`;
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
chain,
|
|
102
|
+
tokenAddress,
|
|
103
|
+
amount: undefined,
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const buyWidgetConfig = isInsufficientFunds ? getBuyWidgetConfig() : null;
|
|
108
|
+
|
|
109
|
+
if (screen === "buy-widget" && buyWidgetConfig) {
|
|
110
|
+
return (
|
|
111
|
+
<CustomThemeProvider theme={theme}>
|
|
112
|
+
<Modal
|
|
113
|
+
className="tw-payment-error-modal"
|
|
114
|
+
hideCloseIcon={false}
|
|
115
|
+
open={true}
|
|
116
|
+
setOpen={(open) => {
|
|
117
|
+
if (!open) {
|
|
118
|
+
onCancel();
|
|
119
|
+
}
|
|
120
|
+
}}
|
|
121
|
+
size="compact"
|
|
122
|
+
title="Top up your wallet"
|
|
123
|
+
crossContainerStyles={{
|
|
124
|
+
position: "absolute",
|
|
125
|
+
right: spacing.lg,
|
|
126
|
+
top: spacing.lg,
|
|
127
|
+
zIndex: 1,
|
|
128
|
+
}}
|
|
129
|
+
>
|
|
130
|
+
{/* BuyWidget without padding */}
|
|
131
|
+
<BuyWidget
|
|
132
|
+
client={client}
|
|
133
|
+
theme={theme}
|
|
134
|
+
chain={buyWidgetConfig.chain}
|
|
135
|
+
tokenAddress={buyWidgetConfig.tokenAddress}
|
|
136
|
+
amount={buyWidgetConfig.amount}
|
|
137
|
+
style={{
|
|
138
|
+
border: "none",
|
|
139
|
+
width: "100%",
|
|
140
|
+
}}
|
|
141
|
+
buttonLabel="Continue"
|
|
142
|
+
title="Get funds"
|
|
143
|
+
description="Top up your wallet to complete your payment."
|
|
144
|
+
{...fundWalletOptions}
|
|
145
|
+
onSuccess={() => {
|
|
146
|
+
// Close modal and retry the payment
|
|
147
|
+
onRetry();
|
|
148
|
+
}}
|
|
149
|
+
onCancel={() => {
|
|
150
|
+
// Go back to error screen
|
|
151
|
+
setScreen("error");
|
|
152
|
+
}}
|
|
153
|
+
/>
|
|
154
|
+
</Modal>
|
|
155
|
+
</CustomThemeProvider>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Error screen (default)
|
|
160
|
+
return (
|
|
161
|
+
<CustomThemeProvider theme={theme}>
|
|
162
|
+
<Modal
|
|
163
|
+
className="tw-payment-error-modal"
|
|
164
|
+
hideCloseIcon={true}
|
|
165
|
+
open={true}
|
|
166
|
+
setOpen={(open) => {
|
|
167
|
+
if (!open) {
|
|
168
|
+
onCancel();
|
|
169
|
+
}
|
|
170
|
+
}}
|
|
171
|
+
size="compact"
|
|
172
|
+
title="Payment Failed"
|
|
173
|
+
>
|
|
174
|
+
<Container p="lg">
|
|
175
|
+
<ModalHeader title="Payment failed" />
|
|
176
|
+
|
|
177
|
+
<Container
|
|
178
|
+
flex="column"
|
|
179
|
+
gap="lg"
|
|
180
|
+
style={{
|
|
181
|
+
paddingTop: spacing.lg,
|
|
182
|
+
}}
|
|
183
|
+
>
|
|
184
|
+
{/* Error Message */}
|
|
185
|
+
<Text
|
|
186
|
+
size="sm"
|
|
187
|
+
style={{
|
|
188
|
+
color: "inherit",
|
|
189
|
+
lineHeight: 1.5,
|
|
190
|
+
}}
|
|
191
|
+
>
|
|
192
|
+
{isInsufficientFunds
|
|
193
|
+
? "Your wallet doesn't have enough funds to complete this payment. Please top up your wallet and try again."
|
|
194
|
+
: errorData.errorMessage ||
|
|
195
|
+
"An error occurred while processing your payment."}
|
|
196
|
+
</Text>
|
|
197
|
+
</Container>
|
|
198
|
+
</Container>
|
|
199
|
+
|
|
200
|
+
{/* Action Buttons */}
|
|
201
|
+
<ScreenBottomContainer>
|
|
202
|
+
{isInsufficientFunds && buyWidgetConfig ? (
|
|
203
|
+
<>
|
|
204
|
+
<Button
|
|
205
|
+
fullWidth
|
|
206
|
+
gap="xs"
|
|
207
|
+
onClick={() => setScreen("buy-widget")}
|
|
208
|
+
variant="accent"
|
|
209
|
+
>
|
|
210
|
+
Top up your wallet
|
|
211
|
+
</Button>
|
|
212
|
+
<Button fullWidth gap="xs" onClick={onCancel} variant="secondary">
|
|
213
|
+
Cancel
|
|
214
|
+
</Button>
|
|
215
|
+
</>
|
|
216
|
+
) : (
|
|
217
|
+
<>
|
|
218
|
+
<Button fullWidth gap="xs" onClick={onRetry} variant="accent">
|
|
219
|
+
Try Again
|
|
220
|
+
</Button>
|
|
221
|
+
<Button fullWidth gap="xs" onClick={onCancel} variant="secondary">
|
|
222
|
+
Cancel
|
|
223
|
+
</Button>
|
|
224
|
+
</>
|
|
225
|
+
)}
|
|
226
|
+
</ScreenBottomContainer>
|
|
227
|
+
</Modal>
|
|
228
|
+
</CustomThemeProvider>
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Default payment requirement selector - same logic as in fetchWithPayment.ts
|
|
233
|
+
function defaultPaymentRequirementsSelector(
|
|
234
|
+
paymentRequirements: RequestedPaymentRequirements[],
|
|
235
|
+
chainId: number | undefined,
|
|
236
|
+
scheme: "exact",
|
|
237
|
+
_error?: string,
|
|
238
|
+
): RequestedPaymentRequirements | undefined {
|
|
239
|
+
if (!paymentRequirements.length) {
|
|
240
|
+
return undefined;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// If we have a chainId, find matching payment requirements
|
|
244
|
+
if (chainId !== undefined) {
|
|
245
|
+
const matchingPaymentRequirements = paymentRequirements.find(
|
|
246
|
+
(x) =>
|
|
247
|
+
extractEvmChainId(networkToCaip2ChainId(x.network)) === chainId &&
|
|
248
|
+
x.scheme === scheme,
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
if (matchingPaymentRequirements) {
|
|
252
|
+
return matchingPaymentRequirements;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// If no matching payment requirements, use the first payment requirement
|
|
257
|
+
const firstPaymentRequirement = paymentRequirements.find(
|
|
258
|
+
(x) => x.scheme === scheme,
|
|
259
|
+
);
|
|
260
|
+
return firstPaymentRequirement;
|
|
261
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { CustomThemeProvider } from "../../../core/design-system/CustomThemeProvider.js";
|
|
3
|
+
import type { Theme } from "../../../core/design-system/index.js";
|
|
4
|
+
import { spacing } from "../../../core/design-system/index.js";
|
|
5
|
+
import {
|
|
6
|
+
Container,
|
|
7
|
+
ModalHeader,
|
|
8
|
+
ScreenBottomContainer,
|
|
9
|
+
} from "../components/basic.js";
|
|
10
|
+
import { Button } from "../components/buttons.js";
|
|
11
|
+
import { Modal } from "../components/Modal.js";
|
|
12
|
+
import { Text } from "../components/text.js";
|
|
13
|
+
|
|
14
|
+
type SignInRequiredModalProps = {
|
|
15
|
+
theme: Theme | "light" | "dark";
|
|
16
|
+
onSignIn: () => void;
|
|
17
|
+
onCancel: () => void;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @internal
|
|
22
|
+
*/
|
|
23
|
+
export function SignInRequiredModal(props: SignInRequiredModalProps) {
|
|
24
|
+
const { theme, onSignIn, onCancel } = props;
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<CustomThemeProvider theme={theme}>
|
|
28
|
+
<Modal
|
|
29
|
+
className="tw-signin-required-modal"
|
|
30
|
+
hideCloseIcon={true}
|
|
31
|
+
open={true}
|
|
32
|
+
setOpen={(open) => {
|
|
33
|
+
if (!open) {
|
|
34
|
+
onCancel();
|
|
35
|
+
}
|
|
36
|
+
}}
|
|
37
|
+
size="compact"
|
|
38
|
+
title="Sign in required"
|
|
39
|
+
>
|
|
40
|
+
<Container p="lg">
|
|
41
|
+
<ModalHeader title="Sign in required" />
|
|
42
|
+
|
|
43
|
+
<Container
|
|
44
|
+
flex="column"
|
|
45
|
+
gap="lg"
|
|
46
|
+
style={{
|
|
47
|
+
paddingTop: spacing.lg,
|
|
48
|
+
}}
|
|
49
|
+
>
|
|
50
|
+
{/* Description */}
|
|
51
|
+
<Text
|
|
52
|
+
size="sm"
|
|
53
|
+
style={{
|
|
54
|
+
color: "inherit",
|
|
55
|
+
lineHeight: 1.5,
|
|
56
|
+
}}
|
|
57
|
+
>
|
|
58
|
+
Account required to complete payment, please sign in to continue.
|
|
59
|
+
</Text>
|
|
60
|
+
</Container>
|
|
61
|
+
</Container>
|
|
62
|
+
|
|
63
|
+
{/* Action Buttons */}
|
|
64
|
+
<ScreenBottomContainer>
|
|
65
|
+
<Button fullWidth gap="xs" onClick={onSignIn} variant="accent">
|
|
66
|
+
Sign in
|
|
67
|
+
</Button>
|
|
68
|
+
<Button fullWidth gap="xs" onClick={onCancel} variant="secondary">
|
|
69
|
+
Cancel
|
|
70
|
+
</Button>
|
|
71
|
+
</ScreenBottomContainer>
|
|
72
|
+
</Modal>
|
|
73
|
+
</CustomThemeProvider>
|
|
74
|
+
);
|
|
75
|
+
}
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = "5.
|
|
1
|
+
export const version = "5.113.0";
|
|
@@ -474,6 +474,16 @@ async function switchChainCoinbaseWalletSDK(
|
|
|
474
474
|
provider: ProviderInterface,
|
|
475
475
|
chain: Chain,
|
|
476
476
|
) {
|
|
477
|
+
// check if chain is already connected
|
|
478
|
+
const connectedChainId = (await provider.request({
|
|
479
|
+
method: "eth_chainId",
|
|
480
|
+
})) as string | number;
|
|
481
|
+
const connectedChain = getCachedChain(normalizeChainId(connectedChainId));
|
|
482
|
+
if (connectedChain?.id === chain.id) {
|
|
483
|
+
// chain is already connected, no need to switch
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
|
|
477
487
|
const chainIdHex = numberToHex(chain.id);
|
|
478
488
|
|
|
479
489
|
try {
|
package/src/x402/facilitator.ts
CHANGED
|
@@ -23,7 +23,7 @@ import { createPaymentHeader } from "./sign.js";
|
|
|
23
23
|
* @param fetch - The fetch function to wrap (typically globalThis.fetch)
|
|
24
24
|
* @param client - The thirdweb client used to access RPC infrastructure
|
|
25
25
|
* @param wallet - The wallet used to sign payment messages
|
|
26
|
-
* @param maxValue - The maximum allowed payment amount in base units
|
|
26
|
+
* @param maxValue - The maximum allowed payment amount in base units
|
|
27
27
|
* @returns A wrapped fetch function that handles 402 responses automatically
|
|
28
28
|
*
|
|
29
29
|
* @example
|
|
@@ -46,13 +46,18 @@ import { createPaymentHeader } from "./sign.js";
|
|
|
46
46
|
* @throws {Error} If a payment has already been attempted for this request
|
|
47
47
|
* @throws {Error} If there's an error creating the payment header
|
|
48
48
|
*
|
|
49
|
-
* @
|
|
49
|
+
* @x402
|
|
50
50
|
*/
|
|
51
51
|
export function wrapFetchWithPayment(
|
|
52
52
|
fetch: typeof globalThis.fetch,
|
|
53
53
|
client: ThirdwebClient,
|
|
54
54
|
wallet: Wallet,
|
|
55
|
-
|
|
55
|
+
options?: {
|
|
56
|
+
maxValue?: bigint;
|
|
57
|
+
paymentRequirementsSelector?: (
|
|
58
|
+
paymentRequirements: RequestedPaymentRequirements[],
|
|
59
|
+
) => RequestedPaymentRequirements | undefined;
|
|
60
|
+
},
|
|
56
61
|
) {
|
|
57
62
|
return async (input: RequestInfo, init?: RequestInit) => {
|
|
58
63
|
const response = await fetch(input, init);
|
|
@@ -78,12 +83,14 @@ export function wrapFetchWithPayment(
|
|
|
78
83
|
"Wallet not connected. Please connect your wallet to continue.",
|
|
79
84
|
);
|
|
80
85
|
}
|
|
81
|
-
const selectedPaymentRequirements =
|
|
82
|
-
parsedPaymentRequirements
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
86
|
+
const selectedPaymentRequirements = options?.paymentRequirementsSelector
|
|
87
|
+
? options.paymentRequirementsSelector(parsedPaymentRequirements)
|
|
88
|
+
: defaultPaymentRequirementsSelector(
|
|
89
|
+
parsedPaymentRequirements,
|
|
90
|
+
chain.id,
|
|
91
|
+
"exact",
|
|
92
|
+
error,
|
|
93
|
+
);
|
|
87
94
|
|
|
88
95
|
if (!selectedPaymentRequirements) {
|
|
89
96
|
throw new Error(
|
|
@@ -92,11 +99,11 @@ export function wrapFetchWithPayment(
|
|
|
92
99
|
}
|
|
93
100
|
|
|
94
101
|
if (
|
|
95
|
-
maxValue &&
|
|
96
|
-
BigInt(selectedPaymentRequirements.maxAmountRequired) > maxValue
|
|
102
|
+
options?.maxValue &&
|
|
103
|
+
BigInt(selectedPaymentRequirements.maxAmountRequired) > options.maxValue
|
|
97
104
|
) {
|
|
98
105
|
throw new Error(
|
|
99
|
-
`Payment amount exceeds maximum allowed (currently set to ${maxValue} in base units)`,
|
|
106
|
+
`Payment amount exceeds maximum allowed (currently set to ${options.maxValue} in base units)`,
|
|
100
107
|
);
|
|
101
108
|
}
|
|
102
109
|
|