Skip to content

Commit d614d18

Browse files
Refactor transaction handling with prepareTransaction and queueTransaction (#866)
1 parent a8d32fb commit d614d18

File tree

4 files changed

+78
-59
lines changed

4 files changed

+78
-59
lines changed

src/server/routes/backend-wallet/send-transaction.ts

Lines changed: 38 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,29 @@
1-
import { Type, type Static } from "@sinclair/typebox";
1+
import { type Static, Type } from "@sinclair/typebox";
22
import type { FastifyInstance } from "fastify";
33
import { StatusCodes } from "http-status-codes";
4-
import type { Address, Hex } from "thirdweb";
5-
import { insertTransaction } from "../../../shared/utils/transaction/insert-transaction";
4+
import { type Hex, prepareTransaction } from "thirdweb";
5+
import { getChain } from "../../../shared/utils/chain";
6+
import { thirdwebClient } from "../../../shared/utils/sdk";
7+
import { queueTransaction } from "../../../shared/utils/transaction/queue-transation";
68
import { AddressSchema } from "../../schemas/address";
79
import {
810
requestQuerystringSchema,
911
standardResponseSchema,
1012
transactionWritesResponseSchema,
1113
} from "../../schemas/shared-api-schemas";
14+
import {
15+
authorizationListSchema,
16+
toParsedAuthorization,
17+
} from "../../schemas/transaction/authorization";
1218
import { txOverridesSchema } from "../../schemas/tx-overrides";
1319
import {
1420
maybeAddress,
21+
requiredAddress,
1522
walletChainParamSchema,
1623
walletWithAAHeaderSchema,
1724
} from "../../schemas/wallet";
1825
import { getChainIdFromChain } from "../../utils/chain";
1926
import { parseTransactionOverrides } from "../../utils/transaction-overrides";
20-
import {
21-
authorizationListSchema,
22-
toParsedAuthorization,
23-
} from "../../schemas/transaction/authorization";
2427

2528
const requestBodySchema = Type.Object({
2629
toAddress: Type.Optional(AddressSchema),
@@ -78,51 +81,39 @@ export async function sendTransaction(fastify: FastifyInstance) {
7881
"x-idempotency-key": idempotencyKey,
7982
"x-account-address": accountAddress,
8083
"x-account-factory-address": accountFactoryAddress,
84+
"x-account-salt": accountSalt,
8185
"x-transaction-mode": transactionMode,
8286
} = request.headers as Static<typeof walletWithAAHeaderSchema>;
8387

8488
const chainId = await getChainIdFromChain(chain);
89+
const chainObject = await getChain(chainId);
90+
const { value: valueOverride, overrides } =
91+
parseTransactionOverrides(txOverrides);
92+
const transaction = prepareTransaction({
93+
client: thirdwebClient,
94+
chain: chainObject,
95+
to: toAddress,
96+
data: data as Hex,
97+
value: BigInt(value) || valueOverride,
98+
authorizationList: authorizationList?.map(toParsedAuthorization),
99+
...overrides,
100+
});
85101

86-
let queueId: string;
87-
if (accountAddress) {
88-
queueId = await insertTransaction({
89-
insertedTransaction: {
90-
isUserOp: true,
91-
chainId,
92-
from: fromAddress as Address,
93-
to: toAddress as Address | undefined,
94-
data: data as Hex,
95-
value: BigInt(value),
96-
accountAddress: accountAddress as Address,
97-
signerAddress: fromAddress as Address,
98-
target: toAddress as Address | undefined,
99-
transactionMode: undefined,
100-
accountFactoryAddress: maybeAddress(
101-
accountFactoryAddress,
102-
"x-account-factory-address",
103-
),
104-
...parseTransactionOverrides(txOverrides),
105-
},
106-
shouldSimulate: simulateTx,
107-
idempotencyKey,
108-
});
109-
} else {
110-
queueId = await insertTransaction({
111-
insertedTransaction: {
112-
isUserOp: false,
113-
chainId,
114-
from: fromAddress as Address,
115-
to: toAddress as Address | undefined,
116-
data: data as Hex,
117-
transactionMode: transactionMode,
118-
value: BigInt(value),
119-
authorizationList: authorizationList?.map(toParsedAuthorization),
120-
...parseTransactionOverrides(txOverrides),
121-
},
122-
shouldSimulate: simulateTx,
123-
idempotencyKey,
124-
});
125-
}
102+
const queueId = await queueTransaction({
103+
transaction,
104+
fromAddress: requiredAddress(fromAddress, "x-backend-wallet-address"),
105+
toAddress: maybeAddress(toAddress, "to"),
106+
accountAddress: maybeAddress(accountAddress, "x-account-address"),
107+
accountFactoryAddress: maybeAddress(
108+
accountFactoryAddress,
109+
"x-account-factory-address",
110+
),
111+
accountSalt,
112+
txOverrides,
113+
idempotencyKey,
114+
transactionMode,
115+
shouldSimulate: simulateTx,
116+
});
126117

127118
reply.status(StatusCodes.OK).send({
128119
result: {

src/server/routes/backend-wallet/sign-typed-data.ts

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
1-
import type { TypedDataSigner } from "@ethersproject/abstract-signer";
21
import { type Static, Type } from "@sinclair/typebox";
32
import type { FastifyInstance } from "fastify";
43
import { StatusCodes } from "http-status-codes";
5-
import { getWallet } from "../../../shared/utils/cache/get-wallet";
4+
import { arbitrumSepolia } from "thirdweb/chains";
5+
import { isSmartBackendWallet } from "../../../shared/db/wallets/get-wallet-details";
6+
import { getWalletDetails } from "../../../shared/db/wallets/get-wallet-details";
7+
import { walletDetailsToAccount } from "../../../shared/utils/account";
8+
import { getChain } from "../../../shared/utils/chain";
9+
import { createCustomError } from "../../middleware/error";
610
import { standardResponseSchema } from "../../schemas/shared-api-schemas";
711
import { walletHeaderSchema } from "../../schemas/wallet";
812

913
const requestBodySchema = Type.Object({
1014
domain: Type.Object({}, { additionalProperties: true }),
1115
types: Type.Object({}, { additionalProperties: true }),
1216
value: Type.Object({}, { additionalProperties: true }),
17+
primaryType: Type.Optional(Type.String()),
18+
chainId: Type.Optional(Type.Number()),
1319
});
1420

1521
const responseBodySchema = Type.Object({
@@ -36,14 +42,35 @@ export async function signTypedData(fastify: FastifyInstance) {
3642
},
3743
},
3844
handler: async (request, reply) => {
39-
const { domain, value, types } = request.body;
45+
const { domain, value, types, chainId, primaryType } = request.body;
4046
const { "x-backend-wallet-address": walletAddress } =
4147
request.headers as Static<typeof walletHeaderSchema>;
4248

43-
const wallet = await getWallet({ chainId: 1, walletAddress });
49+
const walletDetails = await getWalletDetails({
50+
address: walletAddress,
51+
});
52+
53+
if (isSmartBackendWallet(walletDetails) && !chainId) {
54+
throw createCustomError(
55+
"Chain ID is required for signing messages with smart wallets.",
56+
StatusCodes.BAD_REQUEST,
57+
"CHAIN_ID_REQUIRED",
58+
);
59+
}
60+
61+
const chain = chainId ? await getChain(chainId) : arbitrumSepolia;
62+
63+
const { account } = await walletDetailsToAccount({
64+
walletDetails,
65+
chain,
66+
});
4467

45-
const signer = (await wallet.getSigner()) as unknown as TypedDataSigner;
46-
const result = await signer._signTypedData(domain, types, value);
68+
const result = await account.signTypedData({
69+
domain,
70+
types,
71+
primaryType,
72+
message: value,
73+
} as never);
4774

4875
reply.status(StatusCodes.OK).send({
4976
result: result,

src/server/routes/contract/write/write.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,13 @@ export async function writeToContract(fastify: FastifyInstance) {
110110
);
111111
}
112112

113+
const { value, overrides } = parseTransactionOverrides(txOverrides);
113114
const transaction = prepareContractCall({
114115
contract,
115116
method,
116117
params,
117-
...parseTransactionOverrides(txOverrides),
118+
value,
119+
...overrides,
118120
});
119121

120122
const queueId = await queueTransaction({

src/shared/utils/transaction/types.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import {
2-
signAuthorization,
1+
import type {
2+
Address,
3+
Hex,
34
SignedAuthorization,
4-
type Address,
5-
type Hex,
6-
type toSerializableTransaction,
5+
toSerializableTransaction,
76
} from "thirdweb";
87
import type { TransactionType } from "viem";
98

0 commit comments

Comments
 (0)