@coinbase/create-cdp-app 0.0.27 → 0.0.29
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/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/template-nextjs/src/app/globals.css +4 -0
- package/template-nextjs/src/components/FundWallet.tsx +2 -2
- package/template-nextjs/src/components/theme.ts +2 -2
- package/template-react/src/index.css +4 -0
- package/template-react/src/theme.ts +2 -2
- package/template-react-native/App.tsx +201 -238
- package/template-react-native/EOATransaction.tsx +222 -263
- package/template-react-native/SmartAccountTransaction.tsx +346 -202
- package/template-react-native/components/DarkModeToggle.tsx +49 -0
- package/template-react-native/components/SignInModal.tsx +342 -0
- package/template-react-native/components/SunMoonIcon.tsx +105 -0
- package/template-react-native/components/UserIcon.tsx +54 -0
- package/template-react-native/components/WalletHeader.tsx +102 -0
- package/template-react-native/components/WelcomeScreen.tsx +73 -0
- package/template-react-native/theme/ThemeContext.tsx +58 -0
- package/template-react-native/types.ts +48 -0
|
@@ -1,9 +1,49 @@
|
|
|
1
1
|
import { useCurrentUser, useSendUserOperation } from "@coinbase/cdp-hooks";
|
|
2
2
|
import * as Clipboard from "expo-clipboard";
|
|
3
3
|
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import {
|
|
5
|
+
View,
|
|
6
|
+
Text,
|
|
7
|
+
TouchableOpacity,
|
|
8
|
+
StyleSheet,
|
|
9
|
+
Alert,
|
|
10
|
+
ActivityIndicator,
|
|
11
|
+
Linking,
|
|
12
|
+
} from "react-native";
|
|
13
|
+
import {
|
|
14
|
+
createPublicClient,
|
|
15
|
+
http,
|
|
16
|
+
formatEther,
|
|
17
|
+
parseUnits,
|
|
18
|
+
encodeFunctionData,
|
|
19
|
+
formatUnits,
|
|
20
|
+
} from "viem";
|
|
6
21
|
import { baseSepolia } from "viem/chains";
|
|
22
|
+
import { useTheme } from "./theme/ThemeContext";
|
|
23
|
+
|
|
24
|
+
// USDC contract address on Base Sepolia
|
|
25
|
+
const USDC_ADDRESS = "0x036CbD53842c5426634e7929541eC2318f3dCF7e" as const;
|
|
26
|
+
|
|
27
|
+
// ERC20 ABI for balance and transfer
|
|
28
|
+
const ERC20_ABI = [
|
|
29
|
+
{
|
|
30
|
+
name: "balanceOf",
|
|
31
|
+
type: "function",
|
|
32
|
+
stateMutability: "view",
|
|
33
|
+
inputs: [{ name: "account", type: "address" }],
|
|
34
|
+
outputs: [{ name: "", type: "uint256" }],
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "transfer",
|
|
38
|
+
type: "function",
|
|
39
|
+
stateMutability: "nonpayable",
|
|
40
|
+
inputs: [
|
|
41
|
+
{ name: "to", type: "address" },
|
|
42
|
+
{ name: "amount", type: "uint256" },
|
|
43
|
+
],
|
|
44
|
+
outputs: [{ name: "", type: "bool" }],
|
|
45
|
+
},
|
|
46
|
+
] as const;
|
|
7
47
|
|
|
8
48
|
const client = createPublicClient({
|
|
9
49
|
chain: baseSepolia,
|
|
@@ -26,7 +66,9 @@ function SmartAccountTransaction(props: Props) {
|
|
|
26
66
|
const { currentUser } = useCurrentUser();
|
|
27
67
|
const { sendUserOperation, data, error, status } = useSendUserOperation();
|
|
28
68
|
const [balance, setBalance] = useState<bigint | undefined>(undefined);
|
|
69
|
+
const [usdcBalance, setUsdcBalance] = useState<bigint | undefined>(undefined);
|
|
29
70
|
const [errorMessage, setErrorMessage] = useState("");
|
|
71
|
+
const { colors } = useTheme();
|
|
30
72
|
|
|
31
73
|
const smartAccount = currentUser?.evmSmartAccounts?.[0];
|
|
32
74
|
|
|
@@ -35,12 +77,32 @@ function SmartAccountTransaction(props: Props) {
|
|
|
35
77
|
return formatEther(balance);
|
|
36
78
|
}, [balance]);
|
|
37
79
|
|
|
80
|
+
const formattedUsdcBalance = useMemo(() => {
|
|
81
|
+
if (usdcBalance === undefined) return undefined;
|
|
82
|
+
return formatUnits(usdcBalance, 6); // USDC has 6 decimals
|
|
83
|
+
}, [usdcBalance]);
|
|
84
|
+
|
|
38
85
|
const getBalance = useCallback(async () => {
|
|
39
86
|
if (!smartAccount) return;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
// Get ETH balance
|
|
90
|
+
const ethBalance = await client.getBalance({
|
|
91
|
+
address: smartAccount,
|
|
92
|
+
});
|
|
93
|
+
setBalance(ethBalance);
|
|
94
|
+
|
|
95
|
+
// Get USDC balance
|
|
96
|
+
const usdcBalance = await client.readContract({
|
|
97
|
+
address: USDC_ADDRESS,
|
|
98
|
+
abi: ERC20_ABI,
|
|
99
|
+
functionName: "balanceOf",
|
|
100
|
+
args: [smartAccount],
|
|
101
|
+
});
|
|
102
|
+
setUsdcBalance(usdcBalance as bigint);
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error("Error fetching balances:", error);
|
|
105
|
+
}
|
|
44
106
|
}, [smartAccount]);
|
|
45
107
|
|
|
46
108
|
useEffect(() => {
|
|
@@ -51,34 +113,42 @@ function SmartAccountTransaction(props: Props) {
|
|
|
51
113
|
|
|
52
114
|
const handleSendUserOperation = async () => {
|
|
53
115
|
if (!smartAccount) {
|
|
54
|
-
Alert.alert("Error", "No Smart Account available");
|
|
116
|
+
Alert.alert("Error", "No Smart Account available.");
|
|
55
117
|
return;
|
|
56
118
|
}
|
|
57
119
|
|
|
58
120
|
setErrorMessage("");
|
|
59
121
|
|
|
60
122
|
try {
|
|
61
|
-
//
|
|
123
|
+
// Send 1 USDC to self as an example
|
|
124
|
+
const usdcAmount = parseUnits("1", 6); // USDC has 6 decimals
|
|
125
|
+
|
|
126
|
+
const transferData = encodeFunctionData({
|
|
127
|
+
abi: ERC20_ABI,
|
|
128
|
+
functionName: "transfer",
|
|
129
|
+
args: [smartAccount, usdcAmount],
|
|
130
|
+
});
|
|
131
|
+
|
|
62
132
|
const result = await sendUserOperation({
|
|
63
133
|
evmSmartAccount: smartAccount,
|
|
64
134
|
network: "base-sepolia",
|
|
65
135
|
calls: [
|
|
66
136
|
{
|
|
67
|
-
to:
|
|
68
|
-
|
|
137
|
+
to: USDC_ADDRESS,
|
|
138
|
+
data: transferData,
|
|
139
|
+
value: 0n,
|
|
69
140
|
},
|
|
70
141
|
],
|
|
71
142
|
});
|
|
72
143
|
|
|
73
144
|
if (result?.userOperationHash) {
|
|
74
|
-
Alert.alert("Success", "User Operation sent successfully!");
|
|
75
145
|
onSuccess?.();
|
|
76
146
|
getBalance();
|
|
77
147
|
}
|
|
78
148
|
} catch (err) {
|
|
79
149
|
const message = err instanceof Error ? err.message : "Failed to send user operation";
|
|
80
150
|
setErrorMessage(message);
|
|
81
|
-
Alert.alert("Transaction Failed", message);
|
|
151
|
+
Alert.alert("Transaction Failed", message + (message.endsWith(".") ? "" : "."));
|
|
82
152
|
}
|
|
83
153
|
};
|
|
84
154
|
|
|
@@ -88,217 +158,291 @@ function SmartAccountTransaction(props: Props) {
|
|
|
88
158
|
const copyToClipboard = async (text: string, label: string) => {
|
|
89
159
|
try {
|
|
90
160
|
await Clipboard.setStringAsync(text);
|
|
91
|
-
Alert.alert("Copied!", `${label} copied to clipboard
|
|
161
|
+
Alert.alert("Copied!", `${label} copied to clipboard.`);
|
|
92
162
|
} catch (error) {
|
|
93
|
-
Alert.alert("Error", "Failed to copy to clipboard");
|
|
163
|
+
Alert.alert("Error", "Failed to copy to clipboard.");
|
|
94
164
|
}
|
|
95
165
|
};
|
|
96
166
|
|
|
167
|
+
const openFaucet = () => {
|
|
168
|
+
const usdcFaucetUrl = `https://portal.cdp.coinbase.com/products/faucet?address=${smartAccount}&token=USDC`;
|
|
169
|
+
|
|
170
|
+
Alert.alert(
|
|
171
|
+
"Get testnet USDC",
|
|
172
|
+
"",
|
|
173
|
+
[
|
|
174
|
+
{
|
|
175
|
+
text: "Copy USDC Faucet Link",
|
|
176
|
+
onPress: () => copyToClipboard(usdcFaucetUrl, "USDC Faucet Link"),
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
text: "Open USDC Faucet",
|
|
180
|
+
onPress: () => Linking.openURL(usdcFaucetUrl),
|
|
181
|
+
style: "default",
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
text: "Cancel",
|
|
185
|
+
style: "cancel",
|
|
186
|
+
},
|
|
187
|
+
],
|
|
188
|
+
{ cancelable: true },
|
|
189
|
+
);
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
const hasBalance = balance && balance > 0n; // Still check ETH for gas
|
|
193
|
+
const hasUsdcBalance = usdcBalance && usdcBalance > 0n;
|
|
194
|
+
|
|
195
|
+
const createStyles = () =>
|
|
196
|
+
StyleSheet.create({
|
|
197
|
+
container: {
|
|
198
|
+
flex: 1,
|
|
199
|
+
paddingHorizontal: 20,
|
|
200
|
+
paddingVertical: 20,
|
|
201
|
+
},
|
|
202
|
+
balanceSection: {
|
|
203
|
+
backgroundColor: colors.cardBackground,
|
|
204
|
+
borderRadius: 12,
|
|
205
|
+
padding: 24,
|
|
206
|
+
marginBottom: 16,
|
|
207
|
+
alignItems: "center",
|
|
208
|
+
borderWidth: 1,
|
|
209
|
+
borderColor: colors.border,
|
|
210
|
+
},
|
|
211
|
+
balanceTitle: {
|
|
212
|
+
fontSize: 16,
|
|
213
|
+
fontWeight: "500",
|
|
214
|
+
color: colors.textSecondary,
|
|
215
|
+
marginBottom: 8,
|
|
216
|
+
},
|
|
217
|
+
balanceAmount: {
|
|
218
|
+
fontSize: 32,
|
|
219
|
+
fontWeight: "bold",
|
|
220
|
+
color: colors.text,
|
|
221
|
+
marginBottom: 16,
|
|
222
|
+
},
|
|
223
|
+
faucetButton: {
|
|
224
|
+
backgroundColor: colors.accent,
|
|
225
|
+
paddingHorizontal: 20,
|
|
226
|
+
paddingVertical: 12,
|
|
227
|
+
borderRadius: 8,
|
|
228
|
+
alignItems: "center",
|
|
229
|
+
width: "100%",
|
|
230
|
+
},
|
|
231
|
+
faucetButtonText: {
|
|
232
|
+
color: "#ffffff",
|
|
233
|
+
fontSize: 16,
|
|
234
|
+
fontWeight: "600",
|
|
235
|
+
},
|
|
236
|
+
transactionSection: {
|
|
237
|
+
backgroundColor: colors.cardBackground,
|
|
238
|
+
borderRadius: 12,
|
|
239
|
+
padding: 24,
|
|
240
|
+
borderWidth: 1,
|
|
241
|
+
borderColor: colors.border,
|
|
242
|
+
},
|
|
243
|
+
sectionTitle: {
|
|
244
|
+
fontSize: 18,
|
|
245
|
+
fontWeight: "600",
|
|
246
|
+
color: colors.text,
|
|
247
|
+
marginBottom: 8,
|
|
248
|
+
},
|
|
249
|
+
sectionSubtitle: {
|
|
250
|
+
fontSize: 14,
|
|
251
|
+
color: colors.textSecondary,
|
|
252
|
+
marginBottom: 20,
|
|
253
|
+
},
|
|
254
|
+
sendButton: {
|
|
255
|
+
backgroundColor: colors.accent,
|
|
256
|
+
paddingHorizontal: 20,
|
|
257
|
+
paddingVertical: 12,
|
|
258
|
+
borderRadius: 8,
|
|
259
|
+
alignItems: "center",
|
|
260
|
+
marginBottom: 16,
|
|
261
|
+
},
|
|
262
|
+
sendButtonDisabled: {
|
|
263
|
+
opacity: 0.6,
|
|
264
|
+
},
|
|
265
|
+
sendButtonText: {
|
|
266
|
+
color: "#ffffff",
|
|
267
|
+
fontSize: 16,
|
|
268
|
+
fontWeight: "600",
|
|
269
|
+
},
|
|
270
|
+
disabledText: {
|
|
271
|
+
fontSize: 14,
|
|
272
|
+
color: colors.textSecondary,
|
|
273
|
+
textAlign: "center",
|
|
274
|
+
fontStyle: "italic",
|
|
275
|
+
},
|
|
276
|
+
noteContainer: {
|
|
277
|
+
flexDirection: "row",
|
|
278
|
+
backgroundColor: "rgba(0, 128, 128, 0.1)",
|
|
279
|
+
borderRadius: 8,
|
|
280
|
+
padding: 16,
|
|
281
|
+
marginBottom: 20,
|
|
282
|
+
borderWidth: 1,
|
|
283
|
+
borderColor: "rgba(0, 128, 128, 0.3)",
|
|
284
|
+
},
|
|
285
|
+
noteIcon: {
|
|
286
|
+
fontSize: 16,
|
|
287
|
+
marginRight: 8,
|
|
288
|
+
marginTop: 2,
|
|
289
|
+
},
|
|
290
|
+
noteTextContainer: {
|
|
291
|
+
flex: 1,
|
|
292
|
+
},
|
|
293
|
+
noteTitle: {
|
|
294
|
+
fontSize: 14,
|
|
295
|
+
fontWeight: "600",
|
|
296
|
+
color: colors.text,
|
|
297
|
+
marginRight: 4,
|
|
298
|
+
},
|
|
299
|
+
noteText: {
|
|
300
|
+
fontSize: 14,
|
|
301
|
+
color: colors.text,
|
|
302
|
+
lineHeight: 20,
|
|
303
|
+
},
|
|
304
|
+
faucetLink: {
|
|
305
|
+
color: colors.accent,
|
|
306
|
+
textDecorationLine: "underline",
|
|
307
|
+
},
|
|
308
|
+
errorContainer: {
|
|
309
|
+
backgroundColor: colors.errorBackground,
|
|
310
|
+
padding: 12,
|
|
311
|
+
borderRadius: 8,
|
|
312
|
+
marginTop: 16,
|
|
313
|
+
},
|
|
314
|
+
errorText: {
|
|
315
|
+
color: "#cc0000",
|
|
316
|
+
fontSize: 14,
|
|
317
|
+
},
|
|
318
|
+
successContainer: {
|
|
319
|
+
backgroundColor: colors.successBackground,
|
|
320
|
+
padding: 16,
|
|
321
|
+
borderRadius: 8,
|
|
322
|
+
marginTop: 16,
|
|
323
|
+
},
|
|
324
|
+
successTitle: {
|
|
325
|
+
color: colors.accent,
|
|
326
|
+
fontSize: 16,
|
|
327
|
+
fontWeight: "600",
|
|
328
|
+
marginBottom: 12,
|
|
329
|
+
},
|
|
330
|
+
hashContainer: {
|
|
331
|
+
marginBottom: 12,
|
|
332
|
+
},
|
|
333
|
+
hashLabel: {
|
|
334
|
+
color: colors.accent,
|
|
335
|
+
fontSize: 14,
|
|
336
|
+
fontWeight: "600",
|
|
337
|
+
marginBottom: 6,
|
|
338
|
+
},
|
|
339
|
+
hashButton: {
|
|
340
|
+
backgroundColor: "rgba(0, 128, 128, 0.1)",
|
|
341
|
+
borderRadius: 6,
|
|
342
|
+
padding: 12,
|
|
343
|
+
borderWidth: 1,
|
|
344
|
+
borderColor: "rgba(0, 128, 128, 0.3)",
|
|
345
|
+
},
|
|
346
|
+
hashText: {
|
|
347
|
+
color: colors.accent,
|
|
348
|
+
fontSize: 12,
|
|
349
|
+
fontFamily: "monospace",
|
|
350
|
+
marginBottom: 4,
|
|
351
|
+
},
|
|
352
|
+
copyHint: {
|
|
353
|
+
color: colors.accent,
|
|
354
|
+
fontSize: 10,
|
|
355
|
+
fontStyle: "italic",
|
|
356
|
+
textAlign: "center",
|
|
357
|
+
},
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
const styles = createStyles();
|
|
361
|
+
|
|
97
362
|
return (
|
|
98
363
|
<View style={styles.container}>
|
|
99
|
-
|
|
100
|
-
<
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
onPress={
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
</TouchableOpacity>
|
|
364
|
+
{/* Balance Section */}
|
|
365
|
+
<View style={styles.balanceSection}>
|
|
366
|
+
<Text style={styles.balanceTitle}>Current Balance</Text>
|
|
367
|
+
<Text style={styles.balanceAmount}>
|
|
368
|
+
{formattedUsdcBalance === undefined ? "Loading..." : `${formattedUsdcBalance} USDC`}
|
|
369
|
+
</Text>
|
|
370
|
+
{!hasUsdcBalance && (
|
|
371
|
+
<TouchableOpacity style={styles.faucetButton} onPress={openFaucet}>
|
|
372
|
+
<Text style={styles.faucetButtonText}>Get funds from faucet</Text>
|
|
373
|
+
</TouchableOpacity>
|
|
374
|
+
)}
|
|
111
375
|
</View>
|
|
112
376
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
<Text style={styles.
|
|
116
|
-
|
|
377
|
+
{/* Transaction Section */}
|
|
378
|
+
<View style={styles.transactionSection}>
|
|
379
|
+
<Text style={styles.sectionTitle}>Transfer 1 USDC</Text>
|
|
380
|
+
<Text style={styles.sectionSubtitle}>
|
|
381
|
+
This example transaction sends 1 USDC from your wallet to itself.
|
|
117
382
|
</Text>
|
|
118
|
-
</View>
|
|
119
383
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
384
|
+
{!hasUsdcBalance && (
|
|
385
|
+
<View style={styles.noteContainer}>
|
|
386
|
+
<Text style={styles.noteIcon}>ℹ️</Text>
|
|
387
|
+
<View style={styles.noteTextContainer}>
|
|
388
|
+
<Text style={styles.noteTitle}>Note:</Text>
|
|
389
|
+
<Text style={styles.noteText}>
|
|
390
|
+
Even though this is a gasless transaction, you still need USDC in your account to
|
|
391
|
+
send it. Get some from the{" "}
|
|
392
|
+
<Text style={styles.faucetLink} onPress={openFaucet}>
|
|
393
|
+
CDP Faucet
|
|
394
|
+
</Text>
|
|
395
|
+
.
|
|
396
|
+
</Text>
|
|
397
|
+
</View>
|
|
398
|
+
</View>
|
|
129
399
|
)}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
<Text style={styles.copyHint}>📋 Tap to copy</Text>
|
|
150
|
-
</TouchableOpacity>
|
|
400
|
+
|
|
401
|
+
<TouchableOpacity
|
|
402
|
+
style={[
|
|
403
|
+
styles.sendButton,
|
|
404
|
+
(!smartAccount || isLoading || !hasUsdcBalance) && styles.sendButtonDisabled,
|
|
405
|
+
]}
|
|
406
|
+
onPress={handleSendUserOperation}
|
|
407
|
+
disabled={!smartAccount || isLoading || !hasUsdcBalance}
|
|
408
|
+
>
|
|
409
|
+
{isLoading ? (
|
|
410
|
+
<ActivityIndicator color="#fff" />
|
|
411
|
+
) : (
|
|
412
|
+
<Text style={styles.sendButtonText}>Transfer</Text>
|
|
413
|
+
)}
|
|
414
|
+
</TouchableOpacity>
|
|
415
|
+
|
|
416
|
+
{errorMessage || error ? (
|
|
417
|
+
<View style={styles.errorContainer}>
|
|
418
|
+
<Text style={styles.errorText}>{errorMessage || error?.message}</Text>
|
|
151
419
|
</View>
|
|
420
|
+
) : null}
|
|
421
|
+
|
|
422
|
+
{isSuccess && data?.transactionHash ? (
|
|
423
|
+
<View style={styles.successContainer}>
|
|
424
|
+
<Text style={styles.successTitle}>Transfer Complete</Text>
|
|
152
425
|
|
|
153
|
-
{data.userOpHash && (
|
|
154
426
|
<View style={styles.hashContainer}>
|
|
155
|
-
<Text style={styles.hashLabel}>
|
|
427
|
+
<Text style={styles.hashLabel}>Transaction Hash:</Text>
|
|
156
428
|
<TouchableOpacity
|
|
157
429
|
style={styles.hashButton}
|
|
158
|
-
onPress={() =>
|
|
430
|
+
onPress={() =>
|
|
431
|
+
copyToClipboard(
|
|
432
|
+
`https://sepolia.basescan.org/tx/${data.transactionHash}`,
|
|
433
|
+
"Block Explorer Link",
|
|
434
|
+
)
|
|
435
|
+
}
|
|
159
436
|
>
|
|
160
|
-
<Text style={styles.hashText}>{data.
|
|
161
|
-
<Text style={styles.copyHint}
|
|
437
|
+
<Text style={styles.hashText}>{data.transactionHash}</Text>
|
|
438
|
+
<Text style={styles.copyHint}>Tap to copy block explorer link</Text>
|
|
162
439
|
</TouchableOpacity>
|
|
163
440
|
</View>
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
441
|
+
</View>
|
|
442
|
+
) : null}
|
|
443
|
+
</View>
|
|
167
444
|
</View>
|
|
168
445
|
);
|
|
169
446
|
}
|
|
170
447
|
|
|
171
|
-
const styles = StyleSheet.create({
|
|
172
|
-
container: {
|
|
173
|
-
padding: 32,
|
|
174
|
-
backgroundColor: "#ffffff",
|
|
175
|
-
borderRadius: 16,
|
|
176
|
-
borderWidth: 1,
|
|
177
|
-
borderColor: "#dcdcdc",
|
|
178
|
-
marginHorizontal: 0,
|
|
179
|
-
marginVertical: 8,
|
|
180
|
-
alignItems: "stretch",
|
|
181
|
-
},
|
|
182
|
-
title: {
|
|
183
|
-
fontSize: 20,
|
|
184
|
-
fontWeight: "500",
|
|
185
|
-
marginBottom: 4,
|
|
186
|
-
textAlign: "center",
|
|
187
|
-
color: "#111111",
|
|
188
|
-
},
|
|
189
|
-
subtitle: {
|
|
190
|
-
fontSize: 14,
|
|
191
|
-
color: "#757575",
|
|
192
|
-
textAlign: "center",
|
|
193
|
-
marginBottom: 16,
|
|
194
|
-
},
|
|
195
|
-
infoContainer: {
|
|
196
|
-
marginBottom: 16,
|
|
197
|
-
width: "100%",
|
|
198
|
-
},
|
|
199
|
-
label: {
|
|
200
|
-
fontSize: 14,
|
|
201
|
-
fontWeight: "600",
|
|
202
|
-
color: "#757575",
|
|
203
|
-
marginBottom: 4,
|
|
204
|
-
},
|
|
205
|
-
value: {
|
|
206
|
-
fontSize: 14,
|
|
207
|
-
color: "#111111",
|
|
208
|
-
fontFamily: "monospace",
|
|
209
|
-
textAlign: "left",
|
|
210
|
-
},
|
|
211
|
-
button: {
|
|
212
|
-
backgroundColor: "#4CAF50",
|
|
213
|
-
padding: 15,
|
|
214
|
-
borderRadius: 8,
|
|
215
|
-
alignItems: "center",
|
|
216
|
-
alignSelf: "center",
|
|
217
|
-
marginVertical: 16,
|
|
218
|
-
minWidth: 188,
|
|
219
|
-
paddingHorizontal: 32,
|
|
220
|
-
},
|
|
221
|
-
buttonDisabled: {
|
|
222
|
-
opacity: 0.6,
|
|
223
|
-
},
|
|
224
|
-
buttonText: {
|
|
225
|
-
color: "#ffffff",
|
|
226
|
-
fontSize: 16,
|
|
227
|
-
fontWeight: "600",
|
|
228
|
-
},
|
|
229
|
-
errorContainer: {
|
|
230
|
-
backgroundColor: "#ffebee",
|
|
231
|
-
padding: 12,
|
|
232
|
-
borderRadius: 8,
|
|
233
|
-
borderColor: "#f44336",
|
|
234
|
-
borderWidth: 1,
|
|
235
|
-
width: "100%",
|
|
236
|
-
},
|
|
237
|
-
errorText: {
|
|
238
|
-
color: "#c62828",
|
|
239
|
-
fontSize: 14,
|
|
240
|
-
},
|
|
241
|
-
successContainer: {
|
|
242
|
-
backgroundColor: "rgba(76, 175, 80, 0.1)",
|
|
243
|
-
padding: 12,
|
|
244
|
-
borderRadius: 8,
|
|
245
|
-
borderColor: "rgba(76, 175, 80, 0.3)",
|
|
246
|
-
borderWidth: 1,
|
|
247
|
-
width: "100%",
|
|
248
|
-
},
|
|
249
|
-
successTitle: {
|
|
250
|
-
color: "#4caf50",
|
|
251
|
-
fontSize: 16,
|
|
252
|
-
fontWeight: "600",
|
|
253
|
-
marginBottom: 8,
|
|
254
|
-
},
|
|
255
|
-
hashContainer: {
|
|
256
|
-
marginBottom: 12,
|
|
257
|
-
},
|
|
258
|
-
hashLabel: {
|
|
259
|
-
color: "#4caf50",
|
|
260
|
-
fontSize: 14,
|
|
261
|
-
fontWeight: "600",
|
|
262
|
-
marginBottom: 4,
|
|
263
|
-
},
|
|
264
|
-
hashButton: {
|
|
265
|
-
backgroundColor: "rgba(76, 175, 80, 0.1)",
|
|
266
|
-
borderRadius: 8,
|
|
267
|
-
padding: 8,
|
|
268
|
-
borderWidth: 1,
|
|
269
|
-
borderColor: "rgba(76, 175, 80, 0.3)",
|
|
270
|
-
},
|
|
271
|
-
hashText: {
|
|
272
|
-
color: "#4caf50",
|
|
273
|
-
fontSize: 12,
|
|
274
|
-
fontFamily: "monospace",
|
|
275
|
-
marginBottom: 4,
|
|
276
|
-
},
|
|
277
|
-
copyHint: {
|
|
278
|
-
color: "#4caf50",
|
|
279
|
-
fontSize: 10,
|
|
280
|
-
fontStyle: "italic",
|
|
281
|
-
textAlign: "center",
|
|
282
|
-
},
|
|
283
|
-
copyableInfo: {
|
|
284
|
-
backgroundColor: "rgba(0, 128, 128, 0.1)",
|
|
285
|
-
borderRadius: 8,
|
|
286
|
-
padding: 12,
|
|
287
|
-
borderWidth: 1,
|
|
288
|
-
borderColor: "rgba(0, 128, 128, 0.3)",
|
|
289
|
-
},
|
|
290
|
-
copyableText: {
|
|
291
|
-
fontSize: 12,
|
|
292
|
-
fontFamily: "monospace",
|
|
293
|
-
color: "#008080",
|
|
294
|
-
textAlign: "center",
|
|
295
|
-
},
|
|
296
|
-
addressCopyHint: {
|
|
297
|
-
fontSize: 10,
|
|
298
|
-
color: "#008080",
|
|
299
|
-
fontStyle: "italic",
|
|
300
|
-
textAlign: "center",
|
|
301
|
-
},
|
|
302
|
-
});
|
|
303
|
-
|
|
304
448
|
export default SmartAccountTransaction;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { TouchableOpacity, Text, StyleSheet, View } from "react-native";
|
|
3
|
+
import { useTheme } from "../theme/ThemeContext";
|
|
4
|
+
import { DarkModeToggleProps } from "../types";
|
|
5
|
+
import { SunMoonIcon } from "./SunMoonIcon";
|
|
6
|
+
|
|
7
|
+
export const DarkModeToggle: React.FC<DarkModeToggleProps> = ({
|
|
8
|
+
style,
|
|
9
|
+
iconStyle,
|
|
10
|
+
showText = false,
|
|
11
|
+
}) => {
|
|
12
|
+
const { isDarkMode, toggleDarkMode, colors } = useTheme();
|
|
13
|
+
|
|
14
|
+
const createStyles = () =>
|
|
15
|
+
StyleSheet.create({
|
|
16
|
+
button: {
|
|
17
|
+
backgroundColor: colors.inputBackground,
|
|
18
|
+
borderWidth: 1,
|
|
19
|
+
borderColor: colors.border,
|
|
20
|
+
borderRadius: showText ? 8 : 20,
|
|
21
|
+
padding: showText ? 15 : 10,
|
|
22
|
+
alignItems: "center",
|
|
23
|
+
flexDirection: showText ? "row" : "column",
|
|
24
|
+
justifyContent: "center",
|
|
25
|
+
...style,
|
|
26
|
+
},
|
|
27
|
+
iconContainer: {
|
|
28
|
+
marginRight: showText ? 8 : 0,
|
|
29
|
+
alignItems: "center",
|
|
30
|
+
justifyContent: "center",
|
|
31
|
+
},
|
|
32
|
+
text: {
|
|
33
|
+
color: colors.text,
|
|
34
|
+
fontSize: 16,
|
|
35
|
+
fontWeight: "500",
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const styles = createStyles();
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<TouchableOpacity style={styles.button} onPress={toggleDarkMode}>
|
|
43
|
+
<View style={styles.iconContainer}>
|
|
44
|
+
<SunMoonIcon isDarkMode={isDarkMode} size={showText ? 18 : 16} color={colors.text} />
|
|
45
|
+
</View>
|
|
46
|
+
{showText && <Text style={styles.text}>{isDarkMode ? "Light Mode" : "Dark Mode"}</Text>}
|
|
47
|
+
</TouchableOpacity>
|
|
48
|
+
);
|
|
49
|
+
};
|