Skip to content

Commit cf85f0c

Browse files
committed
Linting fixes
1 parent cc27aa5 commit cf85f0c

File tree

5 files changed

+271
-250
lines changed

5 files changed

+271
-250
lines changed

app/api/user/wallet/route.ts

Lines changed: 172 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,164 @@
1-
import { NextResponse } from "next/server";
21
import { Environment, Para as ParaServer } from "@getpara/server-sdk";
3-
import { eq, and } from "drizzle-orm";
2+
import { and, eq } from "drizzle-orm";
3+
import { NextResponse } from "next/server";
44
import { auth } from "@/lib/auth";
55
import { db } from "@/lib/db";
6-
import { paraWallets, integrations } from "@/lib/db/schema";
6+
import { createIntegration } from "@/lib/db/integrations";
7+
import { integrations, paraWallets } from "@/lib/db/schema";
78
import { encryptUserShare } from "@/lib/encryption";
89
import { getUserWallet, userHasWallet } from "@/lib/para/wallet-helpers";
9-
import { createIntegration } from "@/lib/db/integrations";
1010

11-
const PARA_API_KEY = process.env.PARA_API_KEY!;
11+
const PARA_API_KEY = process.env.PARA_API_KEY || "";
1212
const PARA_ENV = process.env.PARA_ENVIRONMENT || "beta";
1313

14+
// Helper: Validate user authentication and email
15+
async function validateUser(request: Request) {
16+
const session = await auth.api.getSession({
17+
headers: request.headers,
18+
});
19+
20+
if (!session?.user) {
21+
return { error: "Unauthorized", status: 401 };
22+
}
23+
24+
const user = session.user;
25+
26+
if (!user.email) {
27+
return { error: "Email required to create wallet", status: 400 };
28+
}
29+
30+
// Check if user is anonymous
31+
if (
32+
user.email.includes("@http://") ||
33+
user.email.includes("@https://") ||
34+
user.email.startsWith("temp-")
35+
) {
36+
return {
37+
error:
38+
"Anonymous users cannot create wallets. Please sign in with a real account.",
39+
status: 400,
40+
};
41+
}
42+
43+
return { user };
44+
}
45+
46+
// Helper: Check if wallet or integration already exists
47+
async function checkExistingWallet(userId: string) {
48+
const hasWallet = await userHasWallet(userId);
49+
if (hasWallet) {
50+
return { error: "Wallet already exists for this user", status: 400 };
51+
}
52+
53+
const existingIntegration = await db
54+
.select()
55+
.from(integrations)
56+
.where(and(eq(integrations.userId, userId), eq(integrations.type, "web3")))
57+
.limit(1);
58+
59+
if (existingIntegration.length > 0) {
60+
return {
61+
error: "Web3 integration already exists for this user",
62+
status: 400,
63+
};
64+
}
65+
66+
return { valid: true };
67+
}
68+
69+
// Helper: Create wallet via Para SDK
70+
async function createParaWallet(email: string) {
71+
if (!PARA_API_KEY) {
72+
console.error("[Para] PARA_API_KEY not configured");
73+
throw new Error("Para API key not configured");
74+
}
75+
76+
const environment = PARA_ENV === "prod" ? Environment.PROD : Environment.BETA;
77+
console.log(
78+
`[Para] Initializing SDK with environment: ${PARA_ENV} (${environment})`
79+
);
80+
console.log(`[Para] API key: ${PARA_API_KEY.slice(0, 8)}...`);
81+
82+
const paraClient = new ParaServer(environment, PARA_API_KEY);
83+
84+
console.log(`[Para] Creating wallet for email: ${email}`);
85+
86+
const wallet = await paraClient.createPregenWallet({
87+
type: "EVM",
88+
pregenId: { email },
89+
});
90+
91+
const userShare = await paraClient.getUserShare();
92+
93+
if (!userShare) {
94+
throw new Error("Failed to get user share from Para");
95+
}
96+
97+
if (!(wallet.id && wallet.address)) {
98+
throw new Error("Invalid wallet data from Para");
99+
}
100+
101+
return { wallet, userShare };
102+
}
103+
104+
// Helper: Get user-friendly error response for wallet creation failures
105+
function getErrorResponse(error: unknown) {
106+
console.error("[Para] Wallet creation failed:", error);
107+
108+
let errorMessage = "Failed to create wallet";
109+
let statusCode = 500;
110+
111+
if (error instanceof Error) {
112+
const message = error.message.toLowerCase();
113+
114+
if (message.includes("already exists")) {
115+
errorMessage = "A wallet already exists for this email address";
116+
statusCode = 409;
117+
} else if (message.includes("invalid email")) {
118+
errorMessage = "Invalid email format";
119+
statusCode = 400;
120+
} else if (message.includes("forbidden") || message.includes("403")) {
121+
errorMessage = "API key authentication failed. Please contact support.";
122+
statusCode = 403;
123+
} else {
124+
errorMessage = error.message;
125+
}
126+
}
127+
128+
return NextResponse.json({ error: errorMessage }, { status: statusCode });
129+
}
130+
131+
// Helper: Store wallet in database and create integration
132+
async function storeWalletAndIntegration(options: {
133+
userId: string;
134+
email: string;
135+
walletId: string;
136+
walletAddress: string;
137+
userShare: string;
138+
}) {
139+
const { userId, email, walletId, walletAddress, userShare } = options;
140+
141+
// Store wallet in para_wallets table
142+
await db.insert(paraWallets).values({
143+
userId,
144+
email,
145+
walletId,
146+
walletAddress,
147+
userShare: encryptUserShare(userShare),
148+
});
149+
150+
console.log(`[Para] ✓ Wallet created: ${walletAddress}`);
151+
152+
// Create Web3 integration record with truncated address as name
153+
const truncatedAddress = `${walletAddress.slice(0, 6)}...${walletAddress.slice(-4)}`;
154+
155+
await createIntegration(userId, truncatedAddress, "web3", {});
156+
157+
console.log(`[Para] ✓ Web3 integration created: ${truncatedAddress}`);
158+
159+
return { walletAddress, walletId, truncatedAddress };
160+
}
161+
14162
export async function GET(request: Request) {
15163
try {
16164
const session = await auth.api.getSession({
@@ -52,123 +200,38 @@ export async function GET(request: Request) {
52200

53201
export async function POST(request: Request) {
54202
try {
55-
// 1. Authenticate user
56-
const session = await auth.api.getSession({
57-
headers: request.headers,
58-
});
59-
60-
if (!session?.user) {
61-
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
62-
}
63-
64-
const user = session.user;
65-
66-
// 2. Check user has valid email (not anonymous)
67-
if (!user.email) {
203+
// 1. Validate user
204+
const userValidation = await validateUser(request);
205+
if ("error" in userValidation) {
68206
return NextResponse.json(
69-
{ error: "Email required to create wallet" },
70-
{ status: 400 }
207+
{ error: userValidation.error },
208+
{ status: userValidation.status }
71209
);
72210
}
211+
const { user } = userValidation;
73212

74-
// Check if user is anonymous (has email like temp-xxx@http://localhost:3000)
75-
if (user.email.includes("@http://") || user.email.includes("@https://") || user.email.startsWith("temp-")) {
213+
// 2. Check if wallet/integration already exists
214+
const existingCheck = await checkExistingWallet(user.id);
215+
if ("error" in existingCheck) {
76216
return NextResponse.json(
77-
{ error: "Anonymous users cannot create wallets. Please sign in with a real account." },
78-
{ status: 400 }
217+
{ error: existingCheck.error },
218+
{ status: existingCheck.status }
79219
);
80220
}
81221

82-
// 3. Check if wallet already exists
83-
const hasWallet = await userHasWallet(user.id);
84-
if (hasWallet) {
85-
return NextResponse.json(
86-
{ error: "Wallet already exists for this user" },
87-
{ status: 400 }
88-
);
89-
}
90-
91-
// 4. Check if Web3 integration already exists (additional safety check)
92-
const existingIntegration = await db
93-
.select()
94-
.from(integrations)
95-
.where(
96-
and(
97-
eq(integrations.userId, user.id),
98-
eq(integrations.type, "web3")
99-
)
100-
)
101-
.limit(1);
102-
103-
if (existingIntegration.length > 0) {
104-
return NextResponse.json(
105-
{ error: "Web3 integration already exists for this user" },
106-
{ status: 400 }
107-
);
108-
}
109-
110-
// 5. Validate Para API key
111-
if (!PARA_API_KEY) {
112-
console.error("[Para] PARA_API_KEY not configured");
113-
return NextResponse.json(
114-
{ error: "Para API key not configured" },
115-
{ status: 500 }
116-
);
117-
}
222+
// 3. Create wallet via Para SDK
223+
const { wallet, userShare } = await createParaWallet(user.email);
118224

119-
// 6. Initialize Para SDK
120-
const environment = PARA_ENV === "prod" ? Environment.PROD : Environment.BETA;
121-
console.log(`[Para] Initializing SDK with environment: ${PARA_ENV} (${environment})`);
122-
console.log(`[Para] API key: ${PARA_API_KEY.slice(0, 8)}...`);
123-
124-
const paraClient = new ParaServer(environment, PARA_API_KEY);
125-
126-
// 7. Skip wallet existence check - might be causing 403
127-
// Note: createPregenWallet should be idempotent anyway
128-
129-
// 8. Create wallet via Para SDK
130-
console.log(`[Para] Creating wallet for user ${user.id} (${user.email})`);
131-
132-
const wallet = await paraClient.createPregenWallet({
133-
type: "EVM",
134-
pregenId: { email: user.email },
135-
});
136-
137-
// 9. Get user share (cryptographic key for signing)
138-
const userShare = await paraClient.getUserShare();
139-
140-
if (!userShare) {
141-
throw new Error("Failed to get user share from Para");
142-
}
143-
144-
if (!(wallet.id && wallet.address)) {
145-
throw new Error("Invalid wallet data from Para");
146-
}
147-
148-
// 10. Store wallet in para_wallets table
149-
await db.insert(paraWallets).values({
225+
// 4. Store wallet and create integration
226+
await storeWalletAndIntegration({
150227
userId: user.id,
151228
email: user.email,
152229
walletId: wallet.id,
153230
walletAddress: wallet.address,
154-
userShare: encryptUserShare(userShare), // Encrypted!
231+
userShare,
155232
});
156233

157-
console.log(`[Para] ✓ Wallet created: ${wallet.address}`);
158-
159-
// 11. Create Web3 integration record with truncated address as name
160-
const truncatedAddress = `${wallet.address.slice(0, 6)}...${wallet.address.slice(-4)}`;
161-
162-
await createIntegration(
163-
user.id,
164-
truncatedAddress,
165-
"web3",
166-
{} // Empty config for web3
167-
);
168-
169-
console.log(`[Para] ✓ Web3 integration created: ${truncatedAddress}`);
170-
171-
// 12. Return success
234+
// 5. Return success
172235
return NextResponse.json({
173236
success: true,
174237
wallet: {
@@ -178,37 +241,7 @@ export async function POST(request: Request) {
178241
},
179242
});
180243
} catch (error) {
181-
console.error("[Para] Wallet creation failed:", error);
182-
183-
// Extract user-friendly error message
184-
let errorMessage = "Failed to create wallet";
185-
let statusCode = 500;
186-
187-
if (error instanceof Error) {
188-
const message = error.message.toLowerCase();
189-
190-
// Check for specific Para API errors
191-
if (message.includes("already exists")) {
192-
errorMessage = "A wallet already exists for this email address";
193-
statusCode = 409;
194-
} else if (message.includes("invalid email")) {
195-
errorMessage = "Invalid email format";
196-
statusCode = 400;
197-
} else if (message.includes("forbidden") || message.includes("403")) {
198-
errorMessage = "API key authentication failed. Please contact support.";
199-
statusCode = 403;
200-
} else {
201-
// Include the actual error message for other errors
202-
errorMessage = error.message;
203-
}
204-
}
205-
206-
return NextResponse.json(
207-
{
208-
error: errorMessage,
209-
},
210-
{ status: statusCode }
211-
);
244+
return getErrorResponse(error);
212245
}
213246
}
214247

@@ -246,10 +279,7 @@ export async function DELETE(request: Request) {
246279
await db
247280
.delete(integrations)
248281
.where(
249-
and(
250-
eq(integrations.userId, user.id),
251-
eq(integrations.type, "web3")
252-
)
282+
and(eq(integrations.userId, user.id), eq(integrations.type, "web3"))
253283
);
254284

255285
console.log(`[Para] Web3 integration deleted for user ${user.id}`);

0 commit comments

Comments
 (0)