@coinbase/create-cdp-app 0.0.35 → 0.0.37
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/README.md +22 -9
- package/dist/index.js +168 -42
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/template-nextjs/README.md +3 -2
- package/template-nextjs/env.example +4 -2
- package/template-nextjs/package.json +3 -1
- package/template-nextjs/public/sol.svg +13 -0
- package/template-nextjs/src/app/globals.css +6 -0
- package/template-nextjs/src/components/Header.tsx +2 -1
- package/template-nextjs/src/components/Providers.tsx +32 -12
- package/template-nextjs/src/components/SignedInScreen.tsx +63 -15
- package/template-nextjs/src/components/SignedInScreenWithOnramp.tsx +22 -3
- package/template-nextjs/src/components/SolanaTransaction.tsx +157 -0
- package/template-nextjs/src/components/UserBalance.tsx +5 -3
- package/template-react/README.md +2 -1
- package/template-react/env.example +4 -2
- package/template-react/package.json +3 -1
- package/template-react/public/sol.svg +13 -0
- package/template-react/src/Header.tsx +21 -9
- package/template-react/src/SignedInScreen.tsx +66 -13
- package/template-react/src/SolanaTransaction.tsx +158 -0
- package/template-react/src/UserBalance.tsx +29 -10
- package/template-react/src/config.ts +31 -11
- package/template-react/src/index.css +6 -0
- package/template-react/src/main.tsx +2 -2
- package/template-react-native/App.tsx +83 -63
- package/template-react-native/EOATransaction.tsx +35 -22
- package/template-react-native/SmartAccountTransaction.tsx +9 -9
- package/template-react-native/components/SignInForm.tsx +433 -0
- package/template-react-native/env.example +1 -1
- package/template-react-native/types.ts +0 -22
- package/template-react-native/components/SignInModal.tsx +0 -342
|
@@ -1,14 +1,34 @@
|
|
|
1
|
-
import { type Config } from "@coinbase/cdp-
|
|
2
|
-
import { type AppConfig } from "@coinbase/cdp-react";
|
|
1
|
+
import { type Config } from "@coinbase/cdp-react";
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
const ethereumAccountType = import.meta.env.VITE_CDP_CREATE_ETHEREUM_ACCOUNT_TYPE
|
|
4
|
+
? import.meta.env.VITE_CDP_CREATE_ETHEREUM_ACCOUNT_TYPE === "smart"
|
|
5
|
+
? "smart"
|
|
6
|
+
: "eoa"
|
|
7
|
+
: undefined;
|
|
8
|
+
|
|
9
|
+
const solanaAccountType = import.meta.env.VITE_CDP_CREATE_SOLANA_ACCOUNT
|
|
10
|
+
? import.meta.env.VITE_CDP_CREATE_SOLANA_ACCOUNT === "true"
|
|
11
|
+
: undefined;
|
|
9
12
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
if (!ethereumAccountType && !solanaAccountType) {
|
|
14
|
+
throw new Error(
|
|
15
|
+
"Either VITE_CDP_CREATE_ETHEREUM_ACCOUNT_TYPE or VITE_CDP_CREATE_SOLANA_ACCOUNT must be defined",
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const CDP_CONFIG = {
|
|
20
|
+
projectId: import.meta.env.VITE_CDP_PROJECT_ID,
|
|
21
|
+
...(ethereumAccountType && {
|
|
22
|
+
ethereum: {
|
|
23
|
+
createOnLogin: ethereumAccountType,
|
|
24
|
+
},
|
|
25
|
+
}),
|
|
26
|
+
...(solanaAccountType && {
|
|
27
|
+
solana: {
|
|
28
|
+
createOnLogin: solanaAccountType,
|
|
29
|
+
},
|
|
30
|
+
}),
|
|
31
|
+
appName: "CDP React StarterKit",
|
|
32
|
+
appLogoUrl: "http://localhost:3000/logo.svg",
|
|
13
33
|
authMethods: ["email", "sms"],
|
|
14
|
-
};
|
|
34
|
+
} as Config;
|
|
@@ -3,13 +3,13 @@ import { StrictMode } from "react";
|
|
|
3
3
|
import { createRoot } from "react-dom/client";
|
|
4
4
|
|
|
5
5
|
import App from "./App.tsx";
|
|
6
|
-
import {
|
|
6
|
+
import { CDP_CONFIG } from "./config.ts";
|
|
7
7
|
import { theme } from "./theme.ts";
|
|
8
8
|
import "./index.css";
|
|
9
9
|
|
|
10
10
|
createRoot(document.getElementById("root")!).render(
|
|
11
11
|
<StrictMode>
|
|
12
|
-
<CDPReactProvider config={CDP_CONFIG}
|
|
12
|
+
<CDPReactProvider config={CDP_CONFIG} theme={theme}>
|
|
13
13
|
<App />
|
|
14
14
|
</CDPReactProvider>
|
|
15
15
|
</StrictMode>,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CDPHooksProvider,
|
|
3
|
-
useConfig,
|
|
4
3
|
useIsInitialized,
|
|
5
4
|
useSignInWithEmail,
|
|
6
5
|
useVerifyEmailOTP,
|
|
@@ -8,27 +7,15 @@ import {
|
|
|
8
7
|
useVerifySmsOTP,
|
|
9
8
|
useIsSignedIn,
|
|
10
9
|
useSignOut,
|
|
11
|
-
useCurrentUser,
|
|
12
10
|
Config,
|
|
13
11
|
} from "@coinbase/cdp-hooks";
|
|
14
12
|
import { StatusBar } from "expo-status-bar";
|
|
15
13
|
import { useState } from "react";
|
|
16
|
-
import {
|
|
17
|
-
StyleSheet,
|
|
18
|
-
Text,
|
|
19
|
-
View,
|
|
20
|
-
TouchableOpacity,
|
|
21
|
-
Alert,
|
|
22
|
-
ScrollView,
|
|
23
|
-
SafeAreaView,
|
|
24
|
-
Animated,
|
|
25
|
-
Dimensions,
|
|
26
|
-
} from "react-native";
|
|
14
|
+
import { StyleSheet, Text, View, Alert, ScrollView, SafeAreaView } from "react-native";
|
|
27
15
|
|
|
28
16
|
import Transaction from "./Transaction";
|
|
29
17
|
import { ThemeProvider, useTheme } from "./theme/ThemeContext";
|
|
30
|
-
import {
|
|
31
|
-
import { SignInModal } from "./components/SignInModal";
|
|
18
|
+
import { SignInForm } from "./components/SignInForm";
|
|
32
19
|
import { DarkModeToggle } from "./components/DarkModeToggle";
|
|
33
20
|
import { WalletHeader } from "./components/WalletHeader";
|
|
34
21
|
import { AuthMethod } from "./types";
|
|
@@ -36,7 +23,10 @@ import { AuthMethod } from "./types";
|
|
|
36
23
|
const cdpConfig: Config = {
|
|
37
24
|
projectId: process.env.EXPO_PUBLIC_CDP_PROJECT_ID,
|
|
38
25
|
basePath: process.env.EXPO_PUBLIC_CDP_BASE_PATH,
|
|
39
|
-
|
|
26
|
+
ethereum: {
|
|
27
|
+
createOnLogin:
|
|
28
|
+
process.env.EXPO_PUBLIC_CDP_CREATE_ETHEREUM_ACCOUNT_TYPE === "smart" ? "smart" : "eoa",
|
|
29
|
+
},
|
|
40
30
|
useMock: process.env.EXPO_PUBLIC_CDP_USE_MOCK === "true",
|
|
41
31
|
};
|
|
42
32
|
|
|
@@ -66,9 +56,7 @@ function CDPApp() {
|
|
|
66
56
|
const { signInWithSms } = useSignInWithSms();
|
|
67
57
|
const { verifySmsOTP } = useVerifySmsOTP();
|
|
68
58
|
const { signOut } = useSignOut();
|
|
69
|
-
const { config } = useConfig();
|
|
70
59
|
const { colors, isDarkMode } = useTheme();
|
|
71
|
-
const { currentUser } = useCurrentUser();
|
|
72
60
|
|
|
73
61
|
const [authMethod, setAuthMethod] = useState<AuthMethod>("email");
|
|
74
62
|
const [email, setEmail] = useState("");
|
|
@@ -76,8 +64,6 @@ function CDPApp() {
|
|
|
76
64
|
const [otp, setOtp] = useState("");
|
|
77
65
|
const [flowId, setFlowId] = useState("");
|
|
78
66
|
const [isLoading, setIsLoading] = useState(false);
|
|
79
|
-
const [showSignInModal, setShowSignInModal] = useState(false);
|
|
80
|
-
const [slideAnim] = useState(new Animated.Value(Dimensions.get("window").height));
|
|
81
67
|
|
|
82
68
|
const handleSignIn = async () => {
|
|
83
69
|
if (authMethod === "email") {
|
|
@@ -132,7 +118,6 @@ function CDPApp() {
|
|
|
132
118
|
}
|
|
133
119
|
setOtp("");
|
|
134
120
|
setFlowId("");
|
|
135
|
-
closeSignInModal();
|
|
136
121
|
} catch (error) {
|
|
137
122
|
Alert.alert("Error", error instanceof Error ? error.message : "Failed to verify OTP.");
|
|
138
123
|
} finally {
|
|
@@ -156,31 +141,11 @@ function CDPApp() {
|
|
|
156
141
|
setAuthMethod(authMethod === "email" ? "sms" : "email");
|
|
157
142
|
setEmail("");
|
|
158
143
|
setPhoneNumber("");
|
|
159
|
-
setOtp("");
|
|
160
|
-
setFlowId("");
|
|
161
144
|
};
|
|
162
145
|
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
toValue: 0,
|
|
167
|
-
duration: 300,
|
|
168
|
-
useNativeDriver: true,
|
|
169
|
-
}).start();
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
const closeSignInModal = () => {
|
|
173
|
-
Animated.timing(slideAnim, {
|
|
174
|
-
toValue: Dimensions.get("window").height,
|
|
175
|
-
duration: 300,
|
|
176
|
-
useNativeDriver: true,
|
|
177
|
-
}).start(() => {
|
|
178
|
-
setShowSignInModal(false);
|
|
179
|
-
setEmail("");
|
|
180
|
-
setPhoneNumber("");
|
|
181
|
-
setOtp("");
|
|
182
|
-
setFlowId("");
|
|
183
|
-
});
|
|
146
|
+
const handleBack = () => {
|
|
147
|
+
setOtp("");
|
|
148
|
+
setFlowId("");
|
|
184
149
|
};
|
|
185
150
|
|
|
186
151
|
const createStyles = () =>
|
|
@@ -266,7 +231,21 @@ function CDPApp() {
|
|
|
266
231
|
|
|
267
232
|
<View style={styles.content}>
|
|
268
233
|
{!isSignedIn ? (
|
|
269
|
-
<
|
|
234
|
+
<SignInForm
|
|
235
|
+
authMethod={authMethod}
|
|
236
|
+
onAuthMethodToggle={handleAuthMethodToggle}
|
|
237
|
+
email={email}
|
|
238
|
+
setEmail={setEmail}
|
|
239
|
+
phoneNumber={phoneNumber}
|
|
240
|
+
setPhoneNumber={setPhoneNumber}
|
|
241
|
+
otp={otp}
|
|
242
|
+
setOtp={setOtp}
|
|
243
|
+
flowId={flowId}
|
|
244
|
+
isLoading={isLoading}
|
|
245
|
+
onSignIn={handleSignIn}
|
|
246
|
+
onVerifyOTP={handleVerifyOTP}
|
|
247
|
+
onBack={handleBack}
|
|
248
|
+
/>
|
|
270
249
|
) : (
|
|
271
250
|
<>
|
|
272
251
|
<WalletHeader onSignOut={handleSignOut} />
|
|
@@ -283,24 +262,6 @@ function CDPApp() {
|
|
|
283
262
|
)}
|
|
284
263
|
</View>
|
|
285
264
|
|
|
286
|
-
<SignInModal
|
|
287
|
-
visible={showSignInModal}
|
|
288
|
-
onClose={closeSignInModal}
|
|
289
|
-
authMethod={authMethod}
|
|
290
|
-
onAuthMethodToggle={handleAuthMethodToggle}
|
|
291
|
-
email={email}
|
|
292
|
-
setEmail={setEmail}
|
|
293
|
-
phoneNumber={phoneNumber}
|
|
294
|
-
setPhoneNumber={setPhoneNumber}
|
|
295
|
-
otp={otp}
|
|
296
|
-
setOtp={setOtp}
|
|
297
|
-
flowId={flowId}
|
|
298
|
-
isLoading={isLoading}
|
|
299
|
-
onSignIn={handleSignIn}
|
|
300
|
-
onVerifyOTP={handleVerifyOTP}
|
|
301
|
-
slideAnim={slideAnim}
|
|
302
|
-
/>
|
|
303
|
-
|
|
304
265
|
<StatusBar style={isDarkMode ? "light" : "dark"} />
|
|
305
266
|
</SafeAreaView>
|
|
306
267
|
);
|
|
@@ -312,6 +273,65 @@ function CDPApp() {
|
|
|
312
273
|
* @returns {JSX.Element} The rendered main component
|
|
313
274
|
*/
|
|
314
275
|
export default function App() {
|
|
276
|
+
// Check if project ID is empty or the placeholder value
|
|
277
|
+
const projectId = process.env.EXPO_PUBLIC_CDP_PROJECT_ID;
|
|
278
|
+
const isPlaceholderProjectId = !projectId || projectId === "your-project-id-here";
|
|
279
|
+
|
|
280
|
+
if (isPlaceholderProjectId) {
|
|
281
|
+
return (
|
|
282
|
+
<ThemeProvider>
|
|
283
|
+
<SafeAreaView
|
|
284
|
+
style={{
|
|
285
|
+
flex: 1,
|
|
286
|
+
backgroundColor: "#f5f5f5",
|
|
287
|
+
justifyContent: "center",
|
|
288
|
+
alignItems: "center",
|
|
289
|
+
padding: 20,
|
|
290
|
+
}}
|
|
291
|
+
>
|
|
292
|
+
<Text
|
|
293
|
+
style={{
|
|
294
|
+
fontSize: 24,
|
|
295
|
+
fontWeight: "bold",
|
|
296
|
+
color: "#333",
|
|
297
|
+
textAlign: "center",
|
|
298
|
+
marginBottom: 16,
|
|
299
|
+
}}
|
|
300
|
+
>
|
|
301
|
+
⚠️ CDP Project ID Required
|
|
302
|
+
</Text>
|
|
303
|
+
<Text
|
|
304
|
+
style={{
|
|
305
|
+
fontSize: 16,
|
|
306
|
+
color: "#666",
|
|
307
|
+
textAlign: "center",
|
|
308
|
+
lineHeight: 24,
|
|
309
|
+
marginBottom: 24,
|
|
310
|
+
}}
|
|
311
|
+
>
|
|
312
|
+
Please configure your CDP project ID in the .env file. Create a .env file in the project
|
|
313
|
+
root and add your CDP project ID.
|
|
314
|
+
</Text>
|
|
315
|
+
<View
|
|
316
|
+
style={{
|
|
317
|
+
backgroundColor: "#f0f0f0",
|
|
318
|
+
padding: 16,
|
|
319
|
+
borderRadius: 8,
|
|
320
|
+
borderWidth: 1,
|
|
321
|
+
borderColor: "#ddd",
|
|
322
|
+
}}
|
|
323
|
+
>
|
|
324
|
+
<Text
|
|
325
|
+
style={{ fontFamily: "monospace", fontSize: 14, color: "#333", textAlign: "center" }}
|
|
326
|
+
>
|
|
327
|
+
EXPO_PUBLIC_CDP_PROJECT_ID=your-actual-project-id
|
|
328
|
+
</Text>
|
|
329
|
+
</View>
|
|
330
|
+
</SafeAreaView>
|
|
331
|
+
</ThemeProvider>
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
|
|
315
335
|
return (
|
|
316
336
|
<CDPHooksProvider config={cdpConfig}>
|
|
317
337
|
<ThemeProvider>
|
|
@@ -23,6 +23,9 @@ interface Props {
|
|
|
23
23
|
onSuccess?: () => void;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
// ETH Faucet contract address on Base Sepolia
|
|
27
|
+
const FAUCET_ADDRESS = "0x3e4ed2D6d6235f9D26707fd5d5AF476fb9C91B0F" as const;
|
|
28
|
+
|
|
26
29
|
function EOATransaction(props: Props) {
|
|
27
30
|
const { onSuccess } = props;
|
|
28
31
|
const { colors } = useTheme();
|
|
@@ -69,7 +72,7 @@ function EOATransaction(props: Props) {
|
|
|
69
72
|
network: "base-sepolia",
|
|
70
73
|
evmAccount: evmAddress,
|
|
71
74
|
transaction: {
|
|
72
|
-
to:
|
|
75
|
+
to: FAUCET_ADDRESS,
|
|
73
76
|
value: 1000000000n,
|
|
74
77
|
gas: 21000n,
|
|
75
78
|
chainId: 84532,
|
|
@@ -97,6 +100,27 @@ function EOATransaction(props: Props) {
|
|
|
97
100
|
}
|
|
98
101
|
};
|
|
99
102
|
|
|
103
|
+
const openFaucet = () => {
|
|
104
|
+
const ethFaucetUrl = `https://portal.cdp.coinbase.com/products/faucet?token=ETH&address=${evmAddress}`;
|
|
105
|
+
Alert.alert(
|
|
106
|
+
"Get testnet ETH",
|
|
107
|
+
"",
|
|
108
|
+
[
|
|
109
|
+
{
|
|
110
|
+
text: "Copy ETH Faucet Link",
|
|
111
|
+
onPress: () => copyToClipboard(ethFaucetUrl, "ETH Faucet Link"),
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
text: "Open ETH Faucet",
|
|
115
|
+
onPress: () => Linking.openURL(ethFaucetUrl),
|
|
116
|
+
style: "default",
|
|
117
|
+
},
|
|
118
|
+
{ text: "Cancel", style: "cancel" },
|
|
119
|
+
],
|
|
120
|
+
{ cancelable: true },
|
|
121
|
+
);
|
|
122
|
+
};
|
|
123
|
+
|
|
100
124
|
const createStyles = () =>
|
|
101
125
|
StyleSheet.create({
|
|
102
126
|
container: {
|
|
@@ -226,6 +250,10 @@ function EOATransaction(props: Props) {
|
|
|
226
250
|
fontStyle: "italic",
|
|
227
251
|
textAlign: "center",
|
|
228
252
|
},
|
|
253
|
+
faucetLink: {
|
|
254
|
+
color: colors.accent,
|
|
255
|
+
textDecorationLine: "underline",
|
|
256
|
+
},
|
|
229
257
|
});
|
|
230
258
|
|
|
231
259
|
const styles = createStyles();
|
|
@@ -241,24 +269,7 @@ function EOATransaction(props: Props) {
|
|
|
241
269
|
: `${parseFloat(formattedBalance).toFixed(8)} ETH`}
|
|
242
270
|
</Text>
|
|
243
271
|
{!hasBalance && (
|
|
244
|
-
<TouchableOpacity
|
|
245
|
-
style={styles.faucetButton}
|
|
246
|
-
onPress={() => {
|
|
247
|
-
const ethFaucetUrl = `https://portal.cdp.coinbase.com/products/faucet?token=ETH&address=${evmAddress}`;
|
|
248
|
-
Alert.alert("Get testnet ETH", "", [
|
|
249
|
-
{
|
|
250
|
-
text: "Copy ETH Faucet Link",
|
|
251
|
-
onPress: () => copyToClipboard(ethFaucetUrl, "ETH Faucet Link"),
|
|
252
|
-
},
|
|
253
|
-
{
|
|
254
|
-
text: "Open ETH Faucet",
|
|
255
|
-
onPress: () => Linking.openURL(ethFaucetUrl),
|
|
256
|
-
style: "default",
|
|
257
|
-
},
|
|
258
|
-
{ text: "Cancel", style: "cancel" },
|
|
259
|
-
]);
|
|
260
|
-
}}
|
|
261
|
-
>
|
|
272
|
+
<TouchableOpacity style={styles.faucetButton} onPress={openFaucet}>
|
|
262
273
|
<Text style={styles.faucetButtonText}>Get funds from faucet</Text>
|
|
263
274
|
</TouchableOpacity>
|
|
264
275
|
)}
|
|
@@ -268,9 +279,11 @@ function EOATransaction(props: Props) {
|
|
|
268
279
|
<View style={styles.transactionSection}>
|
|
269
280
|
<Text style={styles.sectionTitle}>Transfer ETH</Text>
|
|
270
281
|
<Text style={styles.sectionDescription}>
|
|
271
|
-
This example transaction sends a tiny amount of ETH from your wallet to
|
|
272
|
-
|
|
273
|
-
|
|
282
|
+
This example transaction sends a tiny amount of ETH from your wallet to the{" "}
|
|
283
|
+
<Text style={styles.faucetLink} onPress={openFaucet}>
|
|
284
|
+
CDP Faucet
|
|
285
|
+
</Text>
|
|
286
|
+
.
|
|
274
287
|
</Text>
|
|
275
288
|
|
|
276
289
|
<TouchableOpacity
|
|
@@ -24,6 +24,9 @@ import { useTheme } from "./theme/ThemeContext";
|
|
|
24
24
|
// USDC contract address on Base Sepolia
|
|
25
25
|
const USDC_ADDRESS = "0x036CbD53842c5426634e7929541eC2318f3dCF7e" as const;
|
|
26
26
|
|
|
27
|
+
// USDC Faucet contract address on Base Sepolia
|
|
28
|
+
const FAUCET_ADDRESS = "0x8fDDcc0c5C993A1968B46787919Cc34577d6dC5c" as const;
|
|
29
|
+
|
|
27
30
|
// ERC20 ABI for balance and transfer
|
|
28
31
|
const ERC20_ABI = [
|
|
29
32
|
{
|
|
@@ -72,11 +75,6 @@ function SmartAccountTransaction(props: Props) {
|
|
|
72
75
|
|
|
73
76
|
const smartAccount = currentUser?.evmSmartAccounts?.[0];
|
|
74
77
|
|
|
75
|
-
const formattedBalance = useMemo(() => {
|
|
76
|
-
if (balance === undefined) return undefined;
|
|
77
|
-
return formatEther(balance);
|
|
78
|
-
}, [balance]);
|
|
79
|
-
|
|
80
78
|
const formattedUsdcBalance = useMemo(() => {
|
|
81
79
|
if (usdcBalance === undefined) return undefined;
|
|
82
80
|
return formatUnits(usdcBalance, 6); // USDC has 6 decimals
|
|
@@ -120,13 +118,13 @@ function SmartAccountTransaction(props: Props) {
|
|
|
120
118
|
setErrorMessage("");
|
|
121
119
|
|
|
122
120
|
try {
|
|
123
|
-
// Send 1 USDC to
|
|
121
|
+
// Send 1 USDC to the faucet
|
|
124
122
|
const usdcAmount = parseUnits("1", 6); // USDC has 6 decimals
|
|
125
123
|
|
|
126
124
|
const transferData = encodeFunctionData({
|
|
127
125
|
abi: ERC20_ABI,
|
|
128
126
|
functionName: "transfer",
|
|
129
|
-
args: [
|
|
127
|
+
args: [FAUCET_ADDRESS, usdcAmount],
|
|
130
128
|
});
|
|
131
129
|
|
|
132
130
|
const result = await sendUserOperation({
|
|
@@ -189,7 +187,6 @@ function SmartAccountTransaction(props: Props) {
|
|
|
189
187
|
);
|
|
190
188
|
};
|
|
191
189
|
|
|
192
|
-
const hasBalance = balance && balance > 0n; // Still check ETH for gas
|
|
193
190
|
const hasUsdcBalance = usdcBalance && usdcBalance > 0n;
|
|
194
191
|
|
|
195
192
|
const createStyles = () =>
|
|
@@ -378,7 +375,10 @@ function SmartAccountTransaction(props: Props) {
|
|
|
378
375
|
<View style={styles.transactionSection}>
|
|
379
376
|
<Text style={styles.sectionTitle}>Transfer 1 USDC</Text>
|
|
380
377
|
<Text style={styles.sectionSubtitle}>
|
|
381
|
-
This example transaction sends 1 USDC from your wallet to
|
|
378
|
+
This example transaction sends 1 USDC from your wallet to the{" "}
|
|
379
|
+
<Text style={styles.faucetLink} onPress={openFaucet}>
|
|
380
|
+
CDP Faucet
|
|
381
|
+
</Text>
|
|
382
382
|
</Text>
|
|
383
383
|
|
|
384
384
|
{!hasUsdcBalance && (
|