Skip to content

Commit 99cbd84

Browse files
authored
fix: Transaction hash validation (#687)
* fix: more address validation * fix: Add validation to all transaction/userop hashes * stringify bigints
1 parent bc9c6ff commit 99cbd84

File tree

19 files changed

+122
-93
lines changed

19 files changed

+122
-93
lines changed

src/server/routes/contract/events/getContractEventLogs.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { StatusCodes } from "http-status-codes";
44
import { getContractEventLogsByBlockAndTopics } from "../../../../db/contractEventLogs/getContractEventLogs";
55
import { isContractSubscribed } from "../../../../db/contractSubscriptions/getContractSubscriptions";
66
import { createCustomError } from "../../../middleware/error";
7-
import { AddressSchema } from "../../../schemas/address";
7+
import { AddressSchema, TransactionHashSchema } from "../../../schemas/address";
88
import {
99
contractParamSchema,
1010
standardResponseSchema,
@@ -24,7 +24,7 @@ const responseSchema = Type.Object({
2424
chainId: Type.Number(),
2525
contractAddress: AddressSchema,
2626
blockNumber: Type.Number(),
27-
transactionHash: Type.String(),
27+
transactionHash: TransactionHashSchema,
2828
topics: Type.Array(Type.String()),
2929
data: Type.String(),
3030
eventName: Type.Optional(Type.String()),

src/server/routes/contract/extensions/erc1155/write/claimTo.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type { Address } from "thirdweb";
55
import { claimTo } from "thirdweb/extensions/erc1155";
66
import { getContractV5 } from "../../../../../../utils/cache/getContractv5";
77
import { queueTransaction } from "../../../../../../utils/transaction/queueTransation";
8+
import { AddressSchema } from "../../../../../schemas/address";
89
import {
910
erc1155ContractParamSchema,
1011
requestQuerystringSchema,
@@ -22,9 +23,10 @@ import { getChainIdFromChain } from "../../../../../utils/chain";
2223
// INPUTS
2324
const requestSchema = erc1155ContractParamSchema;
2425
const requestBodySchema = Type.Object({
25-
receiver: Type.String({
26+
receiver: {
27+
...AddressSchema,
2628
description: "Address of the wallet to claim the NFT to",
27-
}),
29+
},
2830
tokenId: Type.String({
2931
description: "Token ID of the NFT to claim",
3032
}),

src/server/routes/contract/extensions/erc1155/write/mintAdditionalSupplyTo.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { FastifyInstance } from "fastify";
33
import { StatusCodes } from "http-status-codes";
44
import { queueTx } from "../../../../../../db/transactions/queueTx";
55
import { getContract } from "../../../../../../utils/cache/getContract";
6+
import { AddressSchema } from "../../../../../schemas/address";
67
import {
78
erc1155ContractParamSchema,
89
requestQuerystringSchema,
@@ -16,9 +17,10 @@ import { getChainIdFromChain } from "../../../../../utils/chain";
1617
// INPUTS
1718
const requestSchema = erc1155ContractParamSchema;
1819
const requestBodySchema = Type.Object({
19-
receiver: Type.String({
20+
receiver: {
21+
...AddressSchema,
2022
description: "Address of the wallet to mint the NFT to",
21-
}),
23+
},
2224
tokenId: Type.String({
2325
description: "Token ID to mint additional supply to",
2426
}),

src/server/routes/contract/extensions/erc1155/write/mintBatchTo.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { FastifyInstance } from "fastify";
33
import { StatusCodes } from "http-status-codes";
44
import { queueTx } from "../../../../../../db/transactions/queueTx";
55
import { getContract } from "../../../../../../utils/cache/getContract";
6+
import { AddressSchema } from "../../../../../schemas/address";
67
import { nftAndSupplySchema } from "../../../../../schemas/nft";
78
import {
89
erc1155ContractParamSchema,
@@ -17,9 +18,10 @@ import { getChainIdFromChain } from "../../../../../utils/chain";
1718
// INPUTS
1819
const requestSchema = erc1155ContractParamSchema;
1920
const requestBodySchema = Type.Object({
20-
receiver: Type.String({
21+
receiver: {
22+
...AddressSchema,
2123
description: "Address of the wallet to mint the NFT to",
22-
}),
24+
},
2325
metadataWithSupply: Type.Array(nftAndSupplySchema),
2426
...txOverridesWithValueSchema.properties,
2527
});

src/server/routes/contract/extensions/erc1155/write/mintTo.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { FastifyInstance } from "fastify";
33
import { StatusCodes } from "http-status-codes";
44
import { queueTx } from "../../../../../../db/transactions/queueTx";
55
import { getContract } from "../../../../../../utils/cache/getContract";
6+
import { AddressSchema } from "../../../../../schemas/address";
67
import { nftAndSupplySchema } from "../../../../../schemas/nft";
78
import {
89
erc1155ContractParamSchema,
@@ -17,9 +18,10 @@ import { getChainIdFromChain } from "../../../../../utils/chain";
1718
// INPUTS
1819
const requestSchema = erc1155ContractParamSchema;
1920
const requestBodySchema = Type.Object({
20-
receiver: Type.String({
21+
receiver: {
22+
...AddressSchema,
2123
description: "Address of the wallet to mint the NFT to",
22-
}),
24+
},
2325
metadataWithSupply: nftAndSupplySchema,
2426
...txOverridesWithValueSchema.properties,
2527
});

src/server/routes/contract/extensions/erc721/write/claimTo.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type { Address } from "thirdweb";
55
import { claimTo } from "thirdweb/extensions/erc721";
66
import { getContractV5 } from "../../../../../../utils/cache/getContractv5";
77
import { queueTransaction } from "../../../../../../utils/transaction/queueTransation";
8+
import { AddressSchema } from "../../../../../schemas/address";
89
import {
910
contractParamSchema,
1011
requestQuerystringSchema,
@@ -22,9 +23,10 @@ import { getChainIdFromChain } from "../../../../../utils/chain";
2223
// INPUTS
2324
const requestSchema = contractParamSchema;
2425
const requestBodySchema = Type.Object({
25-
receiver: Type.String({
26+
receiver: {
27+
...AddressSchema,
2628
description: "Address of the wallet to claim the NFT to",
27-
}),
29+
},
2830
quantity: Type.String({
2931
description: "Quantity of NFTs to mint",
3032
}),

src/server/routes/contract/extensions/erc721/write/mintBatchTo.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { FastifyInstance } from "fastify";
33
import { StatusCodes } from "http-status-codes";
44
import { queueTx } from "../../../../../../db/transactions/queueTx";
55
import { getContract } from "../../../../../../utils/cache/getContract";
6+
import { AddressSchema } from "../../../../../schemas/address";
67
import { nftOrInputSchema } from "../../../../../schemas/nft";
78
import {
89
contractParamSchema,
@@ -17,9 +18,10 @@ import { getChainIdFromChain } from "../../../../../utils/chain";
1718
// INPUTS
1819
const requestSchema = contractParamSchema;
1920
const requestBodySchema = Type.Object({
20-
receiver: Type.String({
21+
receiver: {
22+
...AddressSchema,
2123
description: "Address of the wallet to mint the NFT to",
22-
}),
24+
},
2325
metadatas: Type.Array(nftOrInputSchema),
2426
...txOverridesWithValueSchema.properties,
2527
});

src/server/routes/contract/extensions/erc721/write/mintTo.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { FastifyInstance } from "fastify";
33
import { StatusCodes } from "http-status-codes";
44
import { queueTx } from "../../../../../../db/transactions/queueTx";
55
import { getContract } from "../../../../../../utils/cache/getContract";
6+
import { AddressSchema } from "../../../../../schemas/address";
67
import { nftOrInputSchema } from "../../../../../schemas/nft";
78
import {
89
contractParamSchema,
@@ -17,9 +18,10 @@ import { getChainIdFromChain } from "../../../../../utils/chain";
1718
// INPUTS
1819
const requestSchema = contractParamSchema;
1920
const requestBodySchema = Type.Object({
20-
receiver: Type.String({
21+
receiver: {
22+
...AddressSchema,
2123
description: "Address of the wallet to mint the NFT to",
22-
}),
24+
},
2325
metadata: nftOrInputSchema,
2426
...txOverridesWithValueSchema.properties,
2527
});

src/server/routes/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ import { updateRelayer } from "./relayer/update";
9494
import { healthCheck } from "./system/health";
9595
import { queueStatus } from "./system/queue";
9696
import { getTransactionLogs } from "./transaction/blockchain/getLogs";
97-
import { getTxHashReceipt } from "./transaction/blockchain/getTxReceipt";
97+
import { getTransactionReceipt } from "./transaction/blockchain/getReceipt";
9898
import { getUserOpReceipt } from "./transaction/blockchain/getUserOpReceipt";
9999
import { sendSignedTransaction } from "./transaction/blockchain/sendSignedTx";
100100
import { sendSignedUserOp } from "./transaction/blockchain/sendSignedUserOp";
@@ -225,7 +225,7 @@ export const withRoutes = async (fastify: FastifyInstance) => {
225225
await fastify.register(cancelTransaction);
226226
await fastify.register(sendSignedTransaction);
227227
await fastify.register(sendSignedUserOp);
228-
await fastify.register(getTxHashReceipt);
228+
await fastify.register(getTransactionReceipt);
229229
await fastify.register(getUserOpReceipt);
230230
await fastify.register(getTransactionLogs);
231231

src/server/routes/transaction/blockchain/getTxReceipt.ts renamed to src/server/routes/transaction/blockchain/getReceipt.ts

Lines changed: 53 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,31 @@
1-
import { Static, Type } from "@sinclair/typebox";
2-
import { FastifyInstance } from "fastify";
1+
import { Type, type Static } from "@sinclair/typebox";
2+
import type { FastifyInstance } from "fastify";
33
import { StatusCodes } from "http-status-codes";
4-
import { getSdk } from "../../../../utils/cache/getSdk";
5-
import { AddressSchema } from "../../../schemas/address";
4+
import {
5+
eth_getTransactionReceipt,
6+
getRpcClient,
7+
toHex,
8+
type Hex,
9+
} from "thirdweb";
10+
import { stringify } from "thirdweb/utils";
11+
import type { TransactionReceipt } from "viem";
12+
import { getChain } from "../../../../utils/chain";
13+
import {
14+
thirdwebClient,
15+
toTransactionStatus,
16+
toTransactionType,
17+
} from "../../../../utils/sdk";
18+
import { createCustomError } from "../../../middleware/error";
19+
import { AddressSchema, TransactionHashSchema } from "../../../schemas/address";
620
import { standardResponseSchema } from "../../../schemas/sharedApiSchemas";
721
import { getChainIdFromChain } from "../../../utils/chain";
822

923
// INPUT
1024
const requestSchema = Type.Object({
11-
txHash: Type.String({
25+
transactionHash: {
26+
...TransactionHashSchema,
1227
description: "Transaction hash",
13-
examples: [
14-
"0xd9bcba8f5bc4ce5bf4d631b2a0144329c1df3b56ddb9fc64637ed3a4219dd087",
15-
],
16-
pattern: "^0x([A-Fa-f0-9]{64})$",
17-
}),
28+
},
1829
chain: Type.String({
1930
examples: ["80002"],
2031
description: "Chain ID or name",
@@ -34,7 +45,7 @@ export const responseBodySchema = Type.Object({
3445
gasUsed: Type.String(),
3546
logsBloom: Type.String(),
3647
blockHash: Type.String(),
37-
transactionHash: Type.String(),
48+
transactionHash: TransactionHashSchema,
3849
logs: Type.Array(Type.Any()),
3950
blockNumber: Type.Number(),
4051
confirmations: Type.Number(),
@@ -108,40 +119,56 @@ responseBodySchema.example = {
108119
},
109120
};
110121

111-
export async function getTxHashReceipt(fastify: FastifyInstance) {
122+
export async function getTransactionReceipt(fastify: FastifyInstance) {
112123
fastify.route<{
113124
Params: Static<typeof requestSchema>;
114125
Reply: Static<typeof responseBodySchema>;
115126
}>({
116127
method: "GET",
117-
url: "/transaction/:chain/tx-hash/:txHash",
128+
url: "/transaction/:chain/tx-hash/:transactionHash",
118129
schema: {
119-
summary: "Get transaction receipt from transaction hash",
130+
summary: "Get transaction receipt",
120131
description: "Get the transaction receipt from a transaction hash.",
121132
tags: ["Transaction"],
122-
operationId: "txHashReceipt",
133+
operationId: "getTransactionReceipt",
123134
params: requestSchema,
124135
response: {
125136
...standardResponseSchema,
126137
[StatusCodes.OK]: responseBodySchema,
127138
},
128139
},
129140
handler: async (request, reply) => {
130-
const { chain, txHash } = request.params;
141+
const { chain, transactionHash } = request.params;
131142

132143
const chainId = await getChainIdFromChain(chain);
133-
const sdk = await getSdk({ chainId });
134-
const receipt = await sdk.getProvider().getTransactionReceipt(txHash);
144+
const rpcRequest = getRpcClient({
145+
client: thirdwebClient,
146+
chain: await getChain(chainId),
147+
});
148+
149+
let receipt: TransactionReceipt;
150+
try {
151+
receipt = await eth_getTransactionReceipt(rpcRequest, {
152+
hash: transactionHash as Hex,
153+
});
154+
} catch {
155+
throw createCustomError(
156+
"Transaction is not mined.",
157+
StatusCodes.BAD_REQUEST,
158+
"TRANSACTION_NOT_MINED",
159+
);
160+
}
135161

136162
reply.status(StatusCodes.OK).send({
137-
result: receipt
138-
? {
139-
...receipt,
140-
gasUsed: receipt.gasUsed.toHexString(),
141-
cumulativeGasUsed: receipt.cumulativeGasUsed.toHexString(),
142-
effectiveGasPrice: receipt.effectiveGasPrice?.toHexString(),
143-
}
144-
: null,
163+
result: {
164+
...JSON.parse(stringify(receipt)),
165+
gasUsed: toHex(receipt.gasUsed),
166+
cumulativeGasUsed: toHex(receipt.cumulativeGasUsed),
167+
effectiveGasPrice: toHex(receipt.effectiveGasPrice),
168+
blockNumber: Number(receipt.blockNumber),
169+
type: toTransactionType(receipt.type),
170+
status: toTransactionStatus(receipt.status),
171+
},
145172
});
146173
},
147174
});

0 commit comments

Comments
 (0)