create-openfort 0.1.8 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/index.js +16 -16
- package/package.json +1 -1
- package/template/backend/package.json +7 -1
- package/template/backend/pnpm-lock.yaml +187 -33
- package/template/backend/src/app.ts +1 -1
- package/template/openfort-templates/firebase/biome.json +3 -3
- package/template/openfort-templates/firebase/package.json +1 -1
- package/template/openfort-templates/firebase/src/App.tsx +10 -10
- package/template/openfort-templates/firebase/src/components/cards/head.tsx +157 -145
- package/template/openfort-templates/firebase/src/components/cards/main.tsx +63 -52
- package/template/openfort-templates/firebase/src/components/ui/Sheet.tsx +14 -16
- package/template/openfort-templates/firebase/src/components/ui/Tabs.tsx +46 -36
- package/template/openfort-templates/firebase/src/components/ui/TruncateData.tsx +14 -8
- package/template/openfort-templates/firebase/src/integrations/firebase/client.ts +6 -6
- package/template/openfort-templates/firebase/src/integrations/firebase/components/FirebaseAuthCard.tsx +74 -46
- package/template/openfort-templates/firebase/src/integrations/firebase/errors.ts +57 -37
- package/template/openfort-templates/firebase/src/integrations/firebase/index.ts +3 -3
- package/template/openfort-templates/firebase/src/integrations/openfort/index.ts +1 -1
- package/template/openfort-templates/firebase/src/integrations/openfort/providers.tsx +23 -11
- package/template/openfort-templates/firebase/src/ui/openfort/blockchain/ActionsCard.tsx +47 -35
- package/template/openfort-templates/firebase/src/ui/openfort/blockchain/SignCard.tsx +30 -28
- package/template/openfort-templates/firebase/src/ui/openfort/index.ts +4 -6
- package/template/openfort-templates/firebase/src/ui/openfort/profile/UserProfileCard.tsx +32 -20
- package/template/openfort-templates/firebase/src/ui/openfort/wallets/WalletCreation.tsx +51 -27
- package/template/openfort-templates/firebase/src/ui/openfort/wallets/WalletListCard.tsx +66 -40
- package/template/openfort-templates/firebase/src/ui/openfort/wallets/WalletPasswordSheets.tsx +65 -41
- package/template/openfort-templates/firebase/vite.config.ts +3 -3
- package/template/openfort-templates/headless/biome.json +3 -3
- package/template/openfort-templates/headless/package.json +1 -1
- package/template/openfort-templates/headless/src/components/cards/auth.tsx +2 -2
- package/template/openfort-templates/headless/src/components/cards/profile.tsx +1 -3
- package/template/openfort-templates/headless/src/components/providers.tsx +4 -1
- package/template/openfort-templates/headless/src/index.css +10 -4
- package/template/openfort-templates/openfort-ui/biome.json +3 -3
- package/template/openfort-templates/openfort-ui/package.json +1 -1
- package/template/openfort-templates/openfort-ui/src/App.tsx +1 -3
- package/template/openfort-templates/openfort-ui/src/components/cards/auth.tsx +9 -11
- package/template/openfort-templates/openfort-ui/src/components/cards/head.tsx +157 -145
- package/template/openfort-templates/openfort-ui/src/components/cards/main.tsx +50 -41
- package/template/openfort-templates/openfort-ui/src/components/cards/profile.tsx +29 -35
- package/template/openfort-templates/openfort-ui/src/components/cards/sign.tsx +35 -49
- package/template/openfort-templates/openfort-ui/src/components/cards/wallets.tsx +51 -37
- package/template/openfort-templates/openfort-ui/src/components/createWallet.tsx +63 -30
- package/template/openfort-templates/openfort-ui/src/components/passwordRecovery.tsx +61 -56
- package/template/openfort-templates/openfort-ui/src/components/providers.tsx +14 -15
- package/template/openfort-templates/openfort-ui/src/components/ui/Sheet.tsx +14 -16
- package/template/openfort-templates/openfort-ui/src/components/ui/Tabs.tsx +46 -36
- package/template/openfort-templates/openfort-ui/src/components/ui/TruncateData.tsx +14 -8
- package/template/openfort-templates/openfort-ui/vite.config.ts +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FirebaseError } from
|
|
1
|
+
import { FirebaseError } from 'firebase/app'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Firebase Auth error codes mapped to user-friendly messages
|
|
@@ -6,12 +6,15 @@ import { FirebaseError } from "firebase/app";
|
|
|
6
6
|
*/
|
|
7
7
|
const AUTH_ERROR_MESSAGES: Record<string, string> = {
|
|
8
8
|
// Operation errors
|
|
9
|
-
'auth/operation-not-allowed':
|
|
10
|
-
|
|
9
|
+
'auth/operation-not-allowed':
|
|
10
|
+
'This sign-in method is not enabled. Please contact support or enable it in Firebase Console.',
|
|
11
|
+
'auth/operation-not-supported-in-this-environment':
|
|
12
|
+
'This operation is not supported in this environment.',
|
|
11
13
|
|
|
12
14
|
// Popup errors
|
|
13
15
|
'auth/popup-closed-by-user': 'Sign-in popup was closed. Please try again.',
|
|
14
|
-
'auth/popup-blocked':
|
|
16
|
+
'auth/popup-blocked':
|
|
17
|
+
'Sign-in popup was blocked by your browser. Please allow popups and try again.',
|
|
15
18
|
'auth/cancelled-popup-request': 'Sign-in was cancelled. Please try again.',
|
|
16
19
|
|
|
17
20
|
// Email/Password errors
|
|
@@ -20,28 +23,34 @@ const AUTH_ERROR_MESSAGES: Record<string, string> = {
|
|
|
20
23
|
'auth/user-not-found': 'No account found with this email.',
|
|
21
24
|
'auth/wrong-password': 'Incorrect password.',
|
|
22
25
|
'auth/email-already-in-use': 'An account with this email already exists.',
|
|
23
|
-
'auth/weak-password':
|
|
24
|
-
|
|
25
|
-
'auth/
|
|
26
|
+
'auth/weak-password':
|
|
27
|
+
'Password is too weak. Please use a stronger password (at least 6 characters).',
|
|
28
|
+
'auth/invalid-credential':
|
|
29
|
+
'Invalid credentials. Please check your email and password.',
|
|
30
|
+
'auth/account-exists-with-different-credential':
|
|
31
|
+
'An account already exists with the same email but different sign-in credentials.',
|
|
26
32
|
|
|
27
33
|
// Network errors
|
|
28
|
-
'auth/network-request-failed':
|
|
34
|
+
'auth/network-request-failed':
|
|
35
|
+
'Network error. Please check your connection and try again.',
|
|
29
36
|
'auth/timeout': 'Request timed out. Please try again.',
|
|
30
37
|
|
|
31
38
|
// Rate limiting
|
|
32
39
|
'auth/too-many-requests': 'Too many failed attempts. Please try again later.',
|
|
33
40
|
|
|
34
41
|
// Token errors
|
|
35
|
-
'auth/invalid-api-key':
|
|
42
|
+
'auth/invalid-api-key':
|
|
43
|
+
'Invalid API key. Please check your Firebase configuration.',
|
|
36
44
|
'auth/app-deleted': 'Firebase app was deleted.',
|
|
37
45
|
'auth/expired-action-code': 'This action code has expired.',
|
|
38
46
|
'auth/invalid-action-code': 'Invalid action code.',
|
|
39
47
|
|
|
40
48
|
// Other common errors
|
|
41
|
-
'auth/unauthorized-domain':
|
|
49
|
+
'auth/unauthorized-domain':
|
|
50
|
+
'This domain is not authorized for OAuth operations.',
|
|
42
51
|
'auth/missing-email': 'Email address is required.',
|
|
43
52
|
'auth/internal-error': 'An internal error occurred. Please try again.',
|
|
44
|
-
}
|
|
53
|
+
}
|
|
45
54
|
|
|
46
55
|
/**
|
|
47
56
|
* Converts a Firebase error to a user-friendly error message
|
|
@@ -51,22 +60,22 @@ const AUTH_ERROR_MESSAGES: Record<string, string> = {
|
|
|
51
60
|
export function getFirebaseErrorMessage(error: unknown): string {
|
|
52
61
|
// Check if it's a Firebase error
|
|
53
62
|
if (error instanceof FirebaseError) {
|
|
54
|
-
const message = AUTH_ERROR_MESSAGES[error.code]
|
|
63
|
+
const message = AUTH_ERROR_MESSAGES[error.code]
|
|
55
64
|
if (message) {
|
|
56
|
-
return message
|
|
65
|
+
return message
|
|
57
66
|
}
|
|
58
67
|
|
|
59
68
|
// If we don't have a specific message, return the Firebase error message
|
|
60
|
-
return error.message || 'An error occurred during authentication.'
|
|
69
|
+
return error.message || 'An error occurred during authentication.'
|
|
61
70
|
}
|
|
62
71
|
|
|
63
72
|
// Handle generic Error objects
|
|
64
73
|
if (error instanceof Error) {
|
|
65
|
-
return error.message
|
|
74
|
+
return error.message
|
|
66
75
|
}
|
|
67
76
|
|
|
68
77
|
// Fallback for unknown error types
|
|
69
|
-
return 'An unexpected error occurred. Please try again.'
|
|
78
|
+
return 'An unexpected error occurred. Please try again.'
|
|
70
79
|
}
|
|
71
80
|
|
|
72
81
|
/**
|
|
@@ -77,7 +86,7 @@ const DEVELOPER_SOLUTIONS: Record<string, string[]> = {
|
|
|
77
86
|
'1. Go to Firebase Console: https://console.firebase.google.com/',
|
|
78
87
|
'2. Select your project',
|
|
79
88
|
'3. Navigate to Authentication > Sign-in method',
|
|
80
|
-
|
|
89
|
+
"4. Enable the authentication provider you're trying to use (Google, Email/Password, etc.)",
|
|
81
90
|
'5. For Google Sign-in: Add a support email and save',
|
|
82
91
|
'6. Refresh your application and try again',
|
|
83
92
|
],
|
|
@@ -88,8 +97,8 @@ const DEVELOPER_SOLUTIONS: Record<string, string[]> = {
|
|
|
88
97
|
],
|
|
89
98
|
'auth/unauthorized-domain': [
|
|
90
99
|
'1. Go to Firebase Console > Authentication > Settings',
|
|
91
|
-
'2. Add your domain to
|
|
92
|
-
'3. For local development, ensure
|
|
100
|
+
'2. Add your domain to "Authorized domains"',
|
|
101
|
+
'3. For local development, ensure "localhost" is added',
|
|
93
102
|
'4. Save changes and try again',
|
|
94
103
|
],
|
|
95
104
|
'auth/invalid-api-key': [
|
|
@@ -104,7 +113,7 @@ const DEVELOPER_SOLUTIONS: Record<string, string[]> = {
|
|
|
104
113
|
'3. Check for CORS issues in browser console',
|
|
105
114
|
'4. Ensure your API key and project configuration are correct',
|
|
106
115
|
],
|
|
107
|
-
}
|
|
116
|
+
}
|
|
108
117
|
|
|
109
118
|
/**
|
|
110
119
|
* Logs a Firebase error with actionable developer guidance
|
|
@@ -113,36 +122,47 @@ const DEVELOPER_SOLUTIONS: Record<string, string[]> = {
|
|
|
113
122
|
*/
|
|
114
123
|
export function logFirebaseError(error: unknown, context?: string): void {
|
|
115
124
|
if (!(error instanceof FirebaseError)) {
|
|
116
|
-
console.error(context ? `${context}:` : 'Error:', error)
|
|
117
|
-
return
|
|
125
|
+
console.error(context ? `${context}:` : 'Error:', error)
|
|
126
|
+
return
|
|
118
127
|
}
|
|
119
128
|
|
|
120
|
-
const errorPrefix = context
|
|
129
|
+
const errorPrefix = context
|
|
130
|
+
? `🔥 Firebase Auth Error (${context})`
|
|
131
|
+
: '🔥 Firebase Auth Error'
|
|
121
132
|
|
|
122
|
-
console.group(
|
|
133
|
+
console.group(
|
|
134
|
+
`%c${errorPrefix}`,
|
|
135
|
+
'color: #ff6b6b; font-weight: bold; font-size: 14px;',
|
|
136
|
+
)
|
|
123
137
|
|
|
124
138
|
// Log the error code and message
|
|
125
|
-
console.error(
|
|
126
|
-
|
|
139
|
+
console.error(
|
|
140
|
+
`%cError Code: ${error.code}`,
|
|
141
|
+
'color: #ff6b6b; font-weight: bold;',
|
|
142
|
+
)
|
|
143
|
+
console.error(`%cError Message: ${error.message}`, 'color: #ff6b6b;')
|
|
127
144
|
|
|
128
145
|
// Log user-friendly message
|
|
129
|
-
const userMessage = AUTH_ERROR_MESSAGES[error.code] || error.message
|
|
130
|
-
console.info(
|
|
146
|
+
const userMessage = AUTH_ERROR_MESSAGES[error.code] || error.message
|
|
147
|
+
console.info(
|
|
148
|
+
`%cUser Message: ${userMessage}`,
|
|
149
|
+
'color: #ffd93d; font-style: italic;',
|
|
150
|
+
)
|
|
131
151
|
|
|
132
152
|
// Log developer solutions if available
|
|
133
|
-
const solutions = DEVELOPER_SOLUTIONS[error.code]
|
|
153
|
+
const solutions = DEVELOPER_SOLUTIONS[error.code]
|
|
134
154
|
if (solutions) {
|
|
135
|
-
console.group('%c💡 How to Fix This:', 'color: #6bcf7f; font-weight: bold;')
|
|
155
|
+
console.group('%c💡 How to Fix This:', 'color: #6bcf7f; font-weight: bold;')
|
|
136
156
|
solutions.forEach((solution) => {
|
|
137
|
-
console.info(`%c${solution}`, 'color: #6bcf7f;')
|
|
138
|
-
})
|
|
139
|
-
console.groupEnd()
|
|
157
|
+
console.info(`%c${solution}`, 'color: #6bcf7f;')
|
|
158
|
+
})
|
|
159
|
+
console.groupEnd()
|
|
140
160
|
}
|
|
141
161
|
|
|
142
162
|
// Log full error object for debugging
|
|
143
|
-
console.group('%c📋 Full Error Details:', 'color: #a29bfe;')
|
|
144
|
-
console.log(error)
|
|
145
|
-
console.groupEnd()
|
|
163
|
+
console.group('%c📋 Full Error Details:', 'color: #a29bfe;')
|
|
164
|
+
console.log(error)
|
|
165
|
+
console.groupEnd()
|
|
146
166
|
|
|
147
|
-
console.groupEnd()
|
|
167
|
+
console.groupEnd()
|
|
148
168
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export
|
|
3
|
-
export
|
|
1
|
+
export * from './client'
|
|
2
|
+
export { FirebaseAuthCard } from './components/FirebaseAuthCard'
|
|
3
|
+
export * from './errors'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { OpenfortProviders
|
|
1
|
+
export { OpenfortProviders } from './providers'
|
|
@@ -1,19 +1,23 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import {
|
|
2
|
+
getDefaultConfig,
|
|
3
|
+
OpenfortProvider,
|
|
4
|
+
ThirdPartyOAuthProvider,
|
|
5
|
+
} from '@openfort/react'
|
|
6
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
7
|
+
import { beamTestnet, polygonAmoy, sepolia } from 'viem/chains'
|
|
8
|
+
import { createConfig, WagmiProvider } from 'wagmi'
|
|
5
9
|
|
|
6
|
-
import { auth } from
|
|
10
|
+
import { auth } from '../firebase'
|
|
7
11
|
|
|
8
12
|
const wagmiConfig = createConfig(
|
|
9
13
|
getDefaultConfig({
|
|
10
|
-
appName:
|
|
14
|
+
appName: 'Openfort React demo',
|
|
11
15
|
chains: [beamTestnet, polygonAmoy, sepolia], // Supported chains
|
|
12
16
|
walletConnectProjectId: import.meta.env.VITE_WALLET_CONNECT_PROJECT_ID, // WalletConnect Project ID
|
|
13
17
|
}),
|
|
14
|
-
)
|
|
18
|
+
)
|
|
15
19
|
|
|
16
|
-
const queryClient = new QueryClient()
|
|
20
|
+
const queryClient = new QueryClient()
|
|
17
21
|
|
|
18
22
|
export function OpenfortProviders({ children }: { children: React.ReactNode }) {
|
|
19
23
|
return (
|
|
@@ -25,12 +29,20 @@ export function OpenfortProviders({ children }: { children: React.ReactNode }) {
|
|
|
25
29
|
walletConfig={{
|
|
26
30
|
shieldPublishableKey: import.meta.env.VITE_SHIELD_PUBLISHABLE_KEY!, // Get it from https://dashboard.openfort.io
|
|
27
31
|
ethereumProviderPolicyId: import.meta.env.VITE_POLICY_ID, // Policy ID for sponsoring transactions
|
|
28
|
-
|
|
32
|
+
// If you want to use AUTOMATIC embedded wallet recovery, an encryption session is required.
|
|
33
|
+
// See: https://www.openfort.io/docs/products/embedded-wallet/react-native/quickstart/automatic
|
|
34
|
+
// For backend setup, check: https://github.com/openfort-xyz/openfort-backend-quickstart
|
|
35
|
+
createEncryptedSessionEndpoint: import.meta.env
|
|
36
|
+
.VITE_CREATE_ENCRYPTED_SESSION_ENDPOINT,
|
|
29
37
|
recoverWalletAutomaticallyAfterAuth: false, // Wallet creation handled manually after auth
|
|
30
38
|
}}
|
|
31
39
|
thirdPartyAuth={{
|
|
32
40
|
getAccessToken: async () => {
|
|
33
|
-
return (
|
|
41
|
+
return (
|
|
42
|
+
(await auth.currentUser?.getIdToken(
|
|
43
|
+
/* forceRefresh */ false,
|
|
44
|
+
)) ?? null
|
|
45
|
+
)
|
|
34
46
|
},
|
|
35
47
|
provider: ThirdPartyOAuthProvider.FIREBASE,
|
|
36
48
|
}}
|
|
@@ -39,5 +51,5 @@ export function OpenfortProviders({ children }: { children: React.ReactNode }) {
|
|
|
39
51
|
</OpenfortProvider>
|
|
40
52
|
</QueryClientProvider>
|
|
41
53
|
</WagmiProvider>
|
|
42
|
-
)
|
|
54
|
+
)
|
|
43
55
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { getAddress, parseAbi } from
|
|
2
|
-
import { useAccount, useReadContract, useWriteContract } from
|
|
1
|
+
import { getAddress, parseAbi } from 'viem'
|
|
2
|
+
import { useAccount, useReadContract, useWriteContract } from 'wagmi'
|
|
3
3
|
|
|
4
|
-
import { TruncateData } from
|
|
4
|
+
import { TruncateData } from '../../../components/ui/TruncateData'
|
|
5
5
|
|
|
6
|
-
const ERC20_ADDRESS =
|
|
6
|
+
const ERC20_ADDRESS = '0xef147ed8bb07a2a0e7df4c1ac09e96dec459ffac'
|
|
7
7
|
|
|
8
8
|
function MintContract() {
|
|
9
|
-
const { address } = useAccount()
|
|
9
|
+
const { address } = useAccount()
|
|
10
10
|
|
|
11
11
|
const {
|
|
12
12
|
data: balance,
|
|
@@ -16,84 +16,96 @@ function MintContract() {
|
|
|
16
16
|
address: ERC20_ADDRESS,
|
|
17
17
|
abi: [
|
|
18
18
|
{
|
|
19
|
-
type:
|
|
20
|
-
name:
|
|
21
|
-
stateMutability:
|
|
22
|
-
inputs: [{ name:
|
|
23
|
-
outputs: [{ type:
|
|
19
|
+
type: 'function',
|
|
20
|
+
name: 'balanceOf',
|
|
21
|
+
stateMutability: 'view',
|
|
22
|
+
inputs: [{ name: 'account', type: 'address' }],
|
|
23
|
+
outputs: [{ type: 'uint256' }],
|
|
24
24
|
},
|
|
25
25
|
],
|
|
26
|
-
functionName:
|
|
26
|
+
functionName: 'balanceOf',
|
|
27
27
|
args: [address!],
|
|
28
|
-
})
|
|
28
|
+
})
|
|
29
29
|
|
|
30
30
|
const { data: tokenSymbol } = useReadContract({
|
|
31
31
|
address: ERC20_ADDRESS,
|
|
32
32
|
abi: [
|
|
33
33
|
{
|
|
34
|
-
type:
|
|
35
|
-
name:
|
|
36
|
-
stateMutability:
|
|
37
|
-
outputs: [{ type:
|
|
34
|
+
type: 'function',
|
|
35
|
+
name: 'symbol',
|
|
36
|
+
stateMutability: 'view',
|
|
37
|
+
outputs: [{ type: 'string' }],
|
|
38
38
|
},
|
|
39
39
|
],
|
|
40
|
-
functionName:
|
|
41
|
-
})
|
|
40
|
+
functionName: 'symbol',
|
|
41
|
+
})
|
|
42
42
|
|
|
43
|
-
const {
|
|
43
|
+
const {
|
|
44
|
+
data: hash,
|
|
45
|
+
isPending,
|
|
46
|
+
writeContract,
|
|
47
|
+
error,
|
|
48
|
+
} = useWriteContract({
|
|
44
49
|
mutation: {
|
|
45
50
|
onSuccess: () => {
|
|
46
51
|
setTimeout(() => {
|
|
47
|
-
refetch()
|
|
48
|
-
}, 100)
|
|
52
|
+
refetch()
|
|
53
|
+
}, 100)
|
|
49
54
|
},
|
|
50
55
|
onSettled: (data, settledError) => {
|
|
51
|
-
console.log(
|
|
56
|
+
console.log('Settled', { data, error: settledError })
|
|
52
57
|
},
|
|
53
58
|
},
|
|
54
|
-
})
|
|
59
|
+
})
|
|
55
60
|
|
|
56
61
|
async function submit({ amount }: { amount: string }) {
|
|
57
62
|
writeContract({
|
|
58
63
|
address: getAddress(ERC20_ADDRESS),
|
|
59
|
-
abi: parseAbi([
|
|
60
|
-
functionName:
|
|
64
|
+
abi: parseAbi(['function mint(address to, uint256 amount)']),
|
|
65
|
+
functionName: 'mint',
|
|
61
66
|
args: [address!, BigInt(amount)],
|
|
62
|
-
})
|
|
67
|
+
})
|
|
63
68
|
}
|
|
64
69
|
|
|
65
70
|
return (
|
|
66
71
|
<div>
|
|
67
72
|
<h2>Mint contract</h2>
|
|
68
73
|
<p className="mb-2 text-zinc-400 text-sm">
|
|
69
|
-
Current balance: {balance?.toString()} {(tokenSymbol as string) ||
|
|
74
|
+
Current balance: {balance?.toString()} {(tokenSymbol as string) || ''}
|
|
70
75
|
</p>
|
|
71
76
|
<form
|
|
72
77
|
className="space-y-4"
|
|
73
78
|
onSubmit={(event) => {
|
|
74
|
-
event.preventDefault()
|
|
75
|
-
const amount = (event.target as HTMLFormElement).amount.value
|
|
76
|
-
submit({ amount })
|
|
79
|
+
event.preventDefault()
|
|
80
|
+
const amount = (event.target as HTMLFormElement).amount.value
|
|
81
|
+
submit({ amount })
|
|
77
82
|
}}
|
|
78
83
|
>
|
|
79
|
-
<input
|
|
84
|
+
<input
|
|
85
|
+
type="number"
|
|
86
|
+
placeholder="Enter amount to mint"
|
|
87
|
+
className="grow peer"
|
|
88
|
+
name="amount"
|
|
89
|
+
/>
|
|
80
90
|
<button className="btn" disabled={isPending || !address}>
|
|
81
|
-
{isPending ?
|
|
91
|
+
{isPending ? 'Minting...' : 'Mint Tokens'}
|
|
82
92
|
</button>
|
|
83
93
|
</form>
|
|
84
94
|
<TruncateData data={hash} />
|
|
85
95
|
<TruncateData data={error?.message} className="text-red-400" />
|
|
86
96
|
<TruncateData data={balanceError?.message} className="text-red-400" />
|
|
87
97
|
</div>
|
|
88
|
-
)
|
|
98
|
+
)
|
|
89
99
|
}
|
|
90
100
|
|
|
91
101
|
export function ActionsCard() {
|
|
92
102
|
return (
|
|
93
103
|
<div className="flex flex-col w-full">
|
|
94
104
|
<h1>Actions</h1>
|
|
95
|
-
<span className="mb-4 text-zinc-400 text-sm">
|
|
105
|
+
<span className="mb-4 text-zinc-400 text-sm">
|
|
106
|
+
Interact with smart contracts on the blockchain.
|
|
107
|
+
</span>
|
|
96
108
|
<MintContract />
|
|
97
109
|
</div>
|
|
98
|
-
)
|
|
110
|
+
)
|
|
99
111
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { useChainId, useSignMessage, useSignTypedData } from
|
|
1
|
+
import { useChainId, useSignMessage, useSignTypedData } from 'wagmi'
|
|
2
2
|
|
|
3
|
-
import { TruncateData } from
|
|
3
|
+
import { TruncateData } from '../../../components/ui/TruncateData'
|
|
4
4
|
|
|
5
5
|
function SignTypedData() {
|
|
6
|
-
const { signTypedData, error, data } = useSignTypedData()
|
|
7
|
-
const chainId = useChainId()
|
|
6
|
+
const { signTypedData, error, data } = useSignTypedData()
|
|
7
|
+
const chainId = useChainId()
|
|
8
8
|
|
|
9
9
|
return (
|
|
10
10
|
<div>
|
|
@@ -12,38 +12,38 @@ function SignTypedData() {
|
|
|
12
12
|
|
|
13
13
|
<form
|
|
14
14
|
onSubmit={async (event) => {
|
|
15
|
-
event.preventDefault()
|
|
15
|
+
event.preventDefault()
|
|
16
16
|
signTypedData({
|
|
17
17
|
domain: {
|
|
18
|
-
name:
|
|
19
|
-
version:
|
|
18
|
+
name: 'Ether Mail',
|
|
19
|
+
version: '1',
|
|
20
20
|
chainId,
|
|
21
|
-
verifyingContract:
|
|
21
|
+
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
|
|
22
22
|
},
|
|
23
23
|
types: {
|
|
24
24
|
Person: [
|
|
25
|
-
{ name:
|
|
26
|
-
{ name:
|
|
25
|
+
{ name: 'name', type: 'string' },
|
|
26
|
+
{ name: 'wallet', type: 'address' },
|
|
27
27
|
],
|
|
28
28
|
Mail: [
|
|
29
|
-
{ name:
|
|
30
|
-
{ name:
|
|
31
|
-
{ name:
|
|
29
|
+
{ name: 'from', type: 'Person' },
|
|
30
|
+
{ name: 'to', type: 'Person' },
|
|
31
|
+
{ name: 'contents', type: 'string' },
|
|
32
32
|
],
|
|
33
33
|
},
|
|
34
|
-
primaryType:
|
|
34
|
+
primaryType: 'Mail',
|
|
35
35
|
message: {
|
|
36
36
|
from: {
|
|
37
|
-
name:
|
|
38
|
-
wallet:
|
|
37
|
+
name: 'Cow',
|
|
38
|
+
wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
|
|
39
39
|
},
|
|
40
40
|
to: {
|
|
41
|
-
name:
|
|
42
|
-
wallet:
|
|
41
|
+
name: 'Bob',
|
|
42
|
+
wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
|
|
43
43
|
},
|
|
44
|
-
contents:
|
|
44
|
+
contents: 'Hello, Bob!',
|
|
45
45
|
},
|
|
46
|
-
})
|
|
46
|
+
})
|
|
47
47
|
}}
|
|
48
48
|
>
|
|
49
49
|
<button type="submit" className="btn">
|
|
@@ -54,11 +54,11 @@ function SignTypedData() {
|
|
|
54
54
|
<TruncateData data={data} />
|
|
55
55
|
<TruncateData data={error?.message} className="text-red-500" />
|
|
56
56
|
</div>
|
|
57
|
-
)
|
|
57
|
+
)
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
function SignMessage() {
|
|
61
|
-
const { data, signMessage, error } = useSignMessage()
|
|
61
|
+
const { data, signMessage, error } = useSignMessage()
|
|
62
62
|
|
|
63
63
|
return (
|
|
64
64
|
<div>
|
|
@@ -66,9 +66,9 @@ function SignMessage() {
|
|
|
66
66
|
<form
|
|
67
67
|
className="space-y-2"
|
|
68
68
|
onSubmit={(event) => {
|
|
69
|
-
event.preventDefault()
|
|
70
|
-
const formData = new FormData(event.target as HTMLFormElement)
|
|
71
|
-
signMessage({ message: formData.get(
|
|
69
|
+
event.preventDefault()
|
|
70
|
+
const formData = new FormData(event.target as HTMLFormElement)
|
|
71
|
+
signMessage({ message: formData.get('message') as string })
|
|
72
72
|
}}
|
|
73
73
|
>
|
|
74
74
|
<input name="message" placeholder="Message to sign" />
|
|
@@ -79,18 +79,20 @@ function SignMessage() {
|
|
|
79
79
|
<TruncateData data={error?.message} className="text-red-500" />
|
|
80
80
|
<TruncateData data={data} />
|
|
81
81
|
</div>
|
|
82
|
-
)
|
|
82
|
+
)
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
export function SignCard() {
|
|
86
86
|
return (
|
|
87
87
|
<div className="flex flex-col w-full">
|
|
88
88
|
<h1>Signatures</h1>
|
|
89
|
-
<p className="mb-4 text-sm text-zinc-400">
|
|
89
|
+
<p className="mb-4 text-sm text-zinc-400">
|
|
90
|
+
Sign messages and typed data with your connected wallet.
|
|
91
|
+
</p>
|
|
90
92
|
<div className="space-y-6">
|
|
91
93
|
<SignMessage />
|
|
92
94
|
<SignTypedData />
|
|
93
95
|
</div>
|
|
94
96
|
</div>
|
|
95
|
-
)
|
|
97
|
+
)
|
|
96
98
|
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
export { ActionsCard } from
|
|
2
|
-
export { SignCard } from
|
|
3
|
-
export { UserProfileCard } from
|
|
4
|
-
export { WalletListCard } from
|
|
5
|
-
;
|
|
6
|
-
;
|
|
1
|
+
export { ActionsCard } from './blockchain/ActionsCard'
|
|
2
|
+
export { SignCard } from './blockchain/SignCard'
|
|
3
|
+
export { UserProfileCard } from './profile/UserProfileCard'
|
|
4
|
+
export { WalletListCard } from './wallets/WalletListCard'
|
|
@@ -1,27 +1,30 @@
|
|
|
1
|
-
import { BookOpenIcon } from
|
|
2
|
-
import { useUser } from
|
|
3
|
-
import { useAccount } from
|
|
1
|
+
import { BookOpenIcon } from '@heroicons/react/24/outline'
|
|
2
|
+
import { useUser } from '@openfort/react'
|
|
3
|
+
import { useAccount } from 'wagmi'
|
|
4
4
|
|
|
5
|
-
import { auth } from
|
|
6
|
-
import { WalletListCard } from
|
|
5
|
+
import { auth } from '../../../integrations/firebase'
|
|
6
|
+
import { WalletListCard } from '../wallets/WalletListCard'
|
|
7
7
|
|
|
8
8
|
type UserProfileCardProps = {
|
|
9
|
-
sampleGithubUrl: string
|
|
10
|
-
description: string
|
|
11
|
-
}
|
|
9
|
+
sampleGithubUrl: string
|
|
10
|
+
description: string
|
|
11
|
+
}
|
|
12
12
|
|
|
13
|
-
export function UserProfileCard({
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
export function UserProfileCard({
|
|
14
|
+
sampleGithubUrl,
|
|
15
|
+
description,
|
|
16
|
+
}: UserProfileCardProps) {
|
|
17
|
+
const { user } = useUser()
|
|
18
|
+
const { isConnected } = useAccount()
|
|
19
|
+
const isLocal = window.location.hostname === 'localhost'
|
|
17
20
|
|
|
18
21
|
if (!isConnected) {
|
|
19
|
-
return <WalletListCard
|
|
22
|
+
return <WalletListCard />
|
|
20
23
|
}
|
|
21
24
|
|
|
22
25
|
return (
|
|
23
26
|
<div className="flex flex-col flex-1 gap-4">
|
|
24
|
-
<h1>Welcome, {user?.
|
|
27
|
+
<h1>Welcome, {user?.name || user?.email}</h1>
|
|
25
28
|
<p className="text-zinc-400 text-sm">
|
|
26
29
|
{description}
|
|
27
30
|
<br />
|
|
@@ -30,13 +33,18 @@ export function UserProfileCard({ sampleGithubUrl, description }: UserProfileCar
|
|
|
30
33
|
|
|
31
34
|
<div className="border border-zinc-700 rounded p-4">
|
|
32
35
|
<h2 className="mb-2">Get started</h2>
|
|
33
|
-
<p className="mb-2 text-zinc-400 text-sm">
|
|
36
|
+
<p className="mb-2 text-zinc-400 text-sm">
|
|
37
|
+
Start by creating a wallet, minting some tokens and signing messages.
|
|
38
|
+
</p>
|
|
34
39
|
{isLocal ? (
|
|
35
40
|
<p className="mb-2 text-sm">
|
|
36
|
-
Edit <code>src/components/cards/main.tsx</code> to customize the
|
|
41
|
+
Edit <code>src/components/cards/main.tsx</code> to customize the
|
|
42
|
+
app.
|
|
37
43
|
</p>
|
|
38
44
|
) : (
|
|
39
|
-
<p className="mb-2 text-sm">
|
|
45
|
+
<p className="mb-2 text-sm">
|
|
46
|
+
Clone this project and test it yourself, it is open source!
|
|
47
|
+
</p>
|
|
40
48
|
)}
|
|
41
49
|
<div className="flex gap-4 mt-4">
|
|
42
50
|
<a
|
|
@@ -45,7 +53,11 @@ export function UserProfileCard({ sampleGithubUrl, description }: UserProfileCar
|
|
|
45
53
|
target="_blank"
|
|
46
54
|
rel="noreferrer"
|
|
47
55
|
>
|
|
48
|
-
<img
|
|
56
|
+
<img
|
|
57
|
+
src="/githubLogo.svg"
|
|
58
|
+
className="w-5 h-5 mr-2"
|
|
59
|
+
alt="GitHub logo"
|
|
60
|
+
/>
|
|
49
61
|
View on github
|
|
50
62
|
</a>
|
|
51
63
|
<a
|
|
@@ -62,12 +74,12 @@ export function UserProfileCard({ sampleGithubUrl, description }: UserProfileCar
|
|
|
62
74
|
|
|
63
75
|
<button
|
|
64
76
|
onClick={() => {
|
|
65
|
-
auth.signOut()
|
|
77
|
+
auth.signOut()
|
|
66
78
|
}}
|
|
67
79
|
className="btn mt-auto"
|
|
68
80
|
>
|
|
69
81
|
Sign Out
|
|
70
82
|
</button>
|
|
71
83
|
</div>
|
|
72
|
-
)
|
|
84
|
+
)
|
|
73
85
|
}
|