Skip to content

Commit e3d673b

Browse files
committed
Merge remote-tracking branch 'origin/main' into ph/txWorkerRedis
2 parents 90d013d + 131d57e commit e3d673b

File tree

5 files changed

+104
-46
lines changed

5 files changed

+104
-46
lines changed

.env.example

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@ THIRDWEB_API_SECRET_KEY="<your-thirdweb-api-secret-key>"
66
POSTGRES_CONNECTION_URL="postgresql://postgres:postgres@localhost:5432/postgres?sslmode=disable"
77
# The admin wallet that will be able to connect to Engine from the dashboard
88
ADMIN_WALLET_ADDRESS="<your-admin-wallet-address>"
9+
# Encryption password for the wallet keys
10+
ENCRYPTION_PASSWORD="<your-encryption-password>"
11+
# The connection url for your running redis instance, defaults to localhost redis
12+
REDIS_URL="redis://localhost:6379/0"
913

10-
# =====[ Optional Configuration ]=====
14+
# =====[ Optional Configuration ]=====
1115

1216
# Optional configuration to override server host and port
1317
# PORT="3005"

src/server/middleware/error.ts

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ export const createCustomError = (
2121
code,
2222
});
2323

24-
const ETHERS_ERROR_CODES = [
24+
// https://github.com/ethers-io/ethers.js/blob/main/src.ts/utils/errors.ts
25+
const ETHERS_ERROR_CODES = new Set([
26+
// Generic Errors
2527
"UNKNOWN_ERROR",
2628
"NOT_IMPLEMENTED",
2729
"UNSUPPORTED_OPERATION",
@@ -30,21 +32,40 @@ const ETHERS_ERROR_CODES = [
3032
"TIMEOUT",
3133
"BAD_DATA",
3234
"CANCELLED",
35+
36+
// Operational Errors
3337
"BUFFER_OVERRUN",
3438
"NUMERIC_FAULT",
39+
40+
// Argument Errors
3541
"INVALID_ARGUMENT",
3642
"MISSING_ARGUMENT",
3743
"UNEXPECTED_ARGUMENT",
3844
"VALUE_MISMATCH",
45+
46+
// Blockchain Errors
3947
"CALL_EXCEPTION",
4048
"INSUFFICIENT_FUNDS",
4149
"NONCE_EXPIRED",
4250
"REPLACEMENT_UNDERPRICED",
4351
"TRANSACTION_REPLACED",
4452
"UNCONFIGURED_NAME",
4553
"OFFCHAIN_FAULT",
54+
55+
// User Interaction
4656
"ACTION_REJECTED",
47-
];
57+
]);
58+
59+
export const createCustomDateTimestampError = (key: string): CustomError => {
60+
return createCustomError(
61+
`Invalid ${key} Value. Needs to new Date() / new Date().toISOstring() / new Date().getTime() / Unix Epoch`,
62+
404,
63+
"INVALID_DATE_TIME",
64+
);
65+
};
66+
67+
const flipObject = (data: any) =>
68+
Object.fromEntries(Object.entries(data).map(([key, value]) => [value, key]));
4869

4970
const isZodError = (err: unknown): boolean => {
5071
return Boolean(
@@ -57,21 +78,10 @@ const isEthersError = (error: any): boolean => {
5778
error &&
5879
typeof error === "object" &&
5980
"code" in error &&
60-
ETHERS_ERROR_CODES.includes(error.code)
61-
);
62-
};
63-
64-
export const createCustomDateTimestampError = (key: string): CustomError => {
65-
return createCustomError(
66-
`Invalid ${key} Value. Needs to new Date() / new Date().toISOstring() / new Date().getTime() / Unix Epoch`,
67-
404,
68-
"INVALID_DATE_TIME",
81+
ETHERS_ERROR_CODES.has(error.code)
6982
);
7083
};
7184

72-
const flipObject = (data: any) =>
73-
Object.fromEntries(Object.entries(data).map(([key, value]) => [value, key]));
74-
7585
export const withErrorHandler = async (server: FastifyInstance) => {
7686
server.setErrorHandler(
7787
(error: Error | CustomError | ZodError, request, reply) => {
@@ -87,7 +97,7 @@ export const withErrorHandler = async (server: FastifyInstance) => {
8797
return reply.status(StatusCodes.BAD_REQUEST).send({
8898
error: {
8999
code: "BAD_REQUEST",
90-
message: (error as any).code,
100+
message: "code" in error ? error.code : error.message,
91101
reason: error.message,
92102
statusCode: 400,
93103
stack: env.NODE_ENV !== "production" ? error.stack : undefined,
@@ -121,7 +131,6 @@ export const withErrorHandler = async (server: FastifyInstance) => {
121131
});
122132
}
123133

124-
// Handle Custom Errors
125134
if ("statusCode" in error && "code" in error) {
126135
// Transform unexpected errors into a standard payload
127136
const statusCode =
@@ -132,25 +141,25 @@ export const withErrorHandler = async (server: FastifyInstance) => {
132141
StatusCodes.INTERNAL_SERVER_ERROR;
133142

134143
const message = error.message ?? ReasonPhrases.INTERNAL_SERVER_ERROR;
135-
return reply.status(statusCode).send({
144+
reply.status(statusCode).send({
136145
error: {
137146
code,
138147
message,
139148
statusCode,
140149
stack: env.NODE_ENV !== "production" ? error.stack : undefined,
141150
},
142151
});
152+
} else {
153+
// Handle non-custom errors
154+
reply.status(StatusCodes.INTERNAL_SERVER_ERROR).send({
155+
error: {
156+
statusCode: 500,
157+
code: "INTERNAL_SERVER_ERROR",
158+
message: error.message || ReasonPhrases.INTERNAL_SERVER_ERROR,
159+
stack: env.NODE_ENV !== "production" ? error.stack : undefined,
160+
},
161+
});
143162
}
144-
145-
// Handle non-custom errors
146-
return reply.status(StatusCodes.INTERNAL_SERVER_ERROR).send({
147-
error: {
148-
statusCode: 500,
149-
code: "INTERNAL_SERVER_ERROR",
150-
message: error.message || ReasonPhrases.INTERNAL_SERVER_ERROR,
151-
stack: env.NODE_ENV !== "production" ? error.stack : undefined,
152-
},
153-
});
154163
},
155164
);
156165
};

src/server/routes/contract/extensions/erc721/read/signaturePrepare.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import { checkAndReturnNFTSignaturePayload } from "../../../../../utils/validato
3535

3636
// INPUTS
3737
const requestSchema = erc721ContractParamSchema;
38-
const requestBodySchema = Type.Omit(signature721InputSchema, ["uid"]);
38+
const requestBodySchema = signature721InputSchema;
3939

4040
// OUTPUT
4141
const responseSchema = Type.Object({
@@ -213,6 +213,7 @@ export async function erc721SignaturePrepare(fastify: FastifyInstance) {
213213
quantity,
214214
royaltyBps,
215215
royaltyRecipient,
216+
uid,
216217
} = request.body;
217218

218219
const chainId = await getChainIdFromChain(chain);
@@ -245,7 +246,7 @@ export async function erc721SignaturePrepare(fastify: FastifyInstance) {
245246
const parsed = await Signature721WithQuantityInput.parseAsync(payload);
246247
const mintPayload = {
247248
...parsed,
248-
uid: generateUid(),
249+
uid: uid ?? generateUid(),
249250
uri,
250251
royaltyBps: BigNumber.from(parsed.royaltyBps),
251252
};

src/server/schemas/nft/index.ts

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,63 @@ import { BigNumber } from "ethers";
44
// NFTInput format compatible with v5 SDK
55
export const nftInputSchema = Type.Partial(
66
Type.Object({
7-
name: Type.String(),
8-
description: Type.String(),
9-
image: Type.String(),
10-
animation_url: Type.String(),
11-
external_url: Type.String(),
12-
background_color: Type.String(),
13-
properties: Type.Any(),
7+
name: Type.String({
8+
description: "The name of the NFT",
9+
}),
10+
description: Type.String({
11+
description: "The description of the NFT",
12+
}),
13+
image: Type.String({
14+
description: "The image of the NFT",
15+
}),
16+
animation_url: Type.String({
17+
description: "The animation url of the NFT",
18+
}),
19+
external_url: Type.String({
20+
description: "The external url of the NFT",
21+
}),
22+
background_color: Type.String({
23+
description: "The background color of the NFT",
24+
}),
25+
properties: Type.Any({
26+
description: "The properties of the NFT",
27+
}),
1428
}),
1529
);
1630

1731
export const nftMetadataInputSchema = Type.Object({
18-
name: Type.Optional(Type.Union([Type.String(), Type.Number(), Type.Null()])),
19-
description: Type.Optional(Type.Union([Type.String(), Type.Null()])),
20-
image: Type.Optional(Type.Union([Type.String(), Type.Null()])),
21-
external_url: Type.Optional(Type.Union([Type.String(), Type.Null()])),
22-
animation_url: Type.Optional(Type.Union([Type.String(), Type.Null()])),
23-
properties: Type.Optional(Type.Any()),
24-
attributes: Type.Optional(Type.Any()),
25-
background_color: Type.Optional(Type.Union([Type.String(), Type.Null()])),
32+
name: Type.Optional({
33+
description: "The name of the NFT",
34+
...Type.Union([Type.String(), Type.Number(), Type.Null()]),
35+
}),
36+
description: Type.Optional({
37+
description: "The description of the NFT",
38+
...Type.Union([Type.String(), Type.Null()]),
39+
}),
40+
image: Type.Optional({
41+
...Type.Union([Type.String(), Type.Null()]),
42+
description: "The image of the NFT",
43+
}),
44+
external_url: Type.Optional({
45+
...Type.Union([Type.String(), Type.Null()]),
46+
description: "The external url of the NFT",
47+
}),
48+
animation_url: Type.Optional({
49+
...Type.Union([Type.String(), Type.Null()]),
50+
description: "The animation url of the NFT",
51+
}),
52+
properties: Type.Optional({
53+
...Type.Any(),
54+
description: "The properties of the NFT",
55+
}),
56+
attributes: Type.Optional({
57+
...Type.Any(),
58+
description: "The attributes of the NFT",
59+
}),
60+
background_color: Type.Optional({
61+
...Type.Union([Type.String(), Type.Null()]),
62+
description: "The background color of the NFT",
63+
}),
2664
});
2765

2866
export const nftMetadataSchema = Type.Object(

src/utils/env.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,13 @@ export const env = createEnv({
6161
ENABLE_HTTPS: boolSchema("false"),
6262
HTTPS_PASSPHRASE: z.string().default("thirdweb-engine"),
6363
TRUST_PROXY: z.boolean().default(false),
64-
PRUNE_TRANSACTIONS: boolSchema("true"),
64+
PRUNE_TRANSACTIONS: z
65+
.union([
66+
z.literal("true").transform(() => 7),
67+
z.literal("false").transform(() => 0),
68+
z.coerce.number().int(),
69+
])
70+
.default(7),
6571
CLIENT_ANALYTICS_URL: z
6672
.union([UrlSchema, z.literal("")])
6773
.default("https://c.thirdweb.com/event"),

0 commit comments

Comments
 (0)