Skip to content

Commit faecf22

Browse files
authored
Add queueTxRaw (#341)
1 parent afd03a3 commit faecf22

File tree

7 files changed

+116
-115
lines changed

7 files changed

+116
-115
lines changed

src/db/transactions/queueNativeTokenTransferTx.ts

Lines changed: 0 additions & 45 deletions
This file was deleted.

src/db/transactions/queueTx.ts

Lines changed: 28 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ import { ERC4337EthersSigner } from "@thirdweb-dev/wallets/dist/declarations/src
77
import { BigNumber } from "ethers";
88
import type { ContractExtension } from "../../schema/extension";
99
import { PrismaTransaction } from "../../schema/prisma";
10-
import { getPrismaWithPostgresTx } from "../client";
11-
import { getWalletDetails } from "../wallets/getWalletDetails";
10+
import { queueTxRaw } from "./queueTxRaw";
1211

1312
interface QueueTxParams {
1413
pgtx?: PrismaTransaction;
@@ -29,31 +28,21 @@ export const queueTx = async ({
2928
deployedContractAddress,
3029
deployedContractType,
3130
}: QueueTxParams) => {
32-
// Simulate transaction
3331
try {
3432
if (!deployedContractAddress) {
3533
await tx.simulate();
3634
}
37-
} catch (e) {
38-
const message = (e as TransactionError)?.reason || (e as any).message || e;
39-
throw new Error(`Transaction simulation failed with reason: ${message}`);
40-
}
41-
42-
const prisma = getPrismaWithPostgresTx(pgtx);
43-
44-
const fromAddress = (await tx.getSignerAddress()).toLowerCase();
45-
const walletDetails = await getWalletDetails({
46-
pgtx,
47-
address: fromAddress,
48-
});
49-
50-
if (!walletDetails) {
51-
throw new Error(`No configured wallet found with address ${fromAddress}`);
35+
} catch (err: any) {
36+
const errorMessage =
37+
(err as TransactionError)?.reason || (err as any).message || err;
38+
throw new Error(
39+
`Transaction simulation failed with reason: ${errorMessage}`,
40+
);
5241
}
5342

5443
// TODO: We need a much safer way of detecting if the transaction should be a user operation
5544
const isUserOp = !!(tx.getSigner as ERC4337EthersSigner).erc4337provider;
56-
const txTableData = {
45+
const txData = {
5746
chainId: chainId.toString(),
5847
functionName: tx.getMethod(),
5948
functionArgs: JSON.stringify(tx.getArgs()),
@@ -65,28 +54,30 @@ export const queueTx = async ({
6554
};
6655

6756
if (isUserOp) {
68-
const { id: queueId } = await prisma.transactions.create({
69-
data: {
70-
...txTableData,
71-
// Fields needed to get smart wallet signer in worker
72-
signerAddress: await (
73-
tx.getSigner as ERC4337EthersSigner
74-
).originalSigner.getAddress(),
75-
accountAddress: fromAddress,
76-
// Fields needed to send user operation
77-
target: tx.getTarget().toLowerCase(),
78-
},
57+
const signerAddress = await (
58+
tx.getSigner as ERC4337EthersSigner
59+
).originalSigner.getAddress();
60+
const accountAddress = await tx.getSignerAddress();
61+
const target = tx.getTarget();
62+
63+
const { id: queueId } = await queueTxRaw({
64+
pgtx,
65+
...txData,
66+
signerAddress,
67+
accountAddress,
68+
target,
7969
});
8070

8171
return queueId;
8272
} else {
83-
const { id: queueId } = await prisma.transactions.create({
84-
data: {
85-
...txTableData,
86-
// Fields needed to send transaction
87-
fromAddress,
88-
toAddress: tx.getTarget().toLowerCase(),
89-
},
73+
const fromAddress = await tx.getSignerAddress();
74+
const toAddress = tx.getTarget();
75+
76+
const { id: queueId } = await queueTxRaw({
77+
pgtx,
78+
...txData,
79+
fromAddress,
80+
toAddress,
9081
});
9182

9283
return queueId;

src/db/transactions/queueTxRaw.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import type { Prisma } from "@prisma/client";
2+
import { PrismaTransaction } from "../../schema/prisma";
3+
import { getPrismaWithPostgresTx } from "../client";
4+
import { getWalletDetails } from "../wallets/getWalletDetails";
5+
6+
type QueueTxRawParams = Omit<
7+
Prisma.TransactionsCreateInput,
8+
"fromAddress" | "signerAddress"
9+
> & {
10+
pgtx?: PrismaTransaction;
11+
} & (
12+
| {
13+
fromAddress: string;
14+
signerAddress?: never;
15+
}
16+
| {
17+
fromAddress?: never;
18+
signerAddress: string;
19+
}
20+
);
21+
22+
// TODO: Simulation should be moved to this function
23+
export const queueTxRaw = async ({ pgtx, ...tx }: QueueTxRawParams) => {
24+
const prisma = getPrismaWithPostgresTx(pgtx);
25+
26+
const walletDetails = await getWalletDetails({
27+
pgtx,
28+
address: (tx.fromAddress || tx.signerAddress) as string,
29+
});
30+
31+
if (!walletDetails) {
32+
throw new Error(
33+
`No backend wallet found with address ${
34+
tx.fromAddress || tx.signerAddress
35+
}`,
36+
);
37+
}
38+
39+
return prisma.transactions.create({
40+
data: {
41+
...tx,
42+
fromAddress: tx.fromAddress?.toLowerCase(),
43+
toAddress: tx.toAddress?.toLowerCase(),
44+
target: tx.target?.toLowerCase(),
45+
signerAddress: tx.signerAddress?.toLowerCase(),
46+
accountAddress: tx.accountAddress?.toLowerCase(),
47+
},
48+
});
49+
};

src/server/routes/backend-wallet/sendTransaction.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Static, Type } from "@sinclair/typebox";
22
import { FastifyInstance } from "fastify";
33
import { StatusCodes } from "http-status-codes";
4-
import { prisma } from "../../../db/client";
4+
import { queueTxRaw } from "../../../db/transactions/queueTxRaw";
55
import {
66
standardResponseSchema,
77
transactionWritesResponseSchema,
@@ -62,16 +62,12 @@ export async function sendTransaction(fastify: FastifyInstance) {
6262
const fromAddress = request.headers["x-backend-wallet-address"] as string;
6363
const chainId = await getChainIdFromChain(chain);
6464

65-
// TODO: At some point we should simulate this first
66-
// For now, it's okay not to since its a raw transaction
67-
const { id: queueId } = await prisma.transactions.create({
68-
data: {
69-
chainId: chainId.toString(),
70-
fromAddress,
71-
toAddress,
72-
data,
73-
value,
74-
},
65+
const { id: queueId } = await queueTxRaw({
66+
chainId: chainId.toString(),
67+
fromAddress,
68+
toAddress,
69+
data,
70+
value,
7571
});
7672

7773
reply.status(StatusCodes.OK).send({

src/server/routes/backend-wallet/sendTransactionBatch.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,12 @@ export async function sendTransactionBatch(fastify: FastifyInstance) {
6767
groupId,
6868
id: uuidv4(),
6969
chainId: chainId.toString(),
70-
fromAddress,
71-
toAddress: tx.toAddress,
70+
fromAddress: fromAddress.toLowerCase(),
71+
toAddress: tx.toAddress?.toLowerCase(),
7272
data: tx.data,
7373
value: tx.value,
7474
}));
75+
7576
await prisma.transactions.createMany({
7677
data,
7778
});

src/server/routes/backend-wallet/transfer.ts

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import {
77
import { constants } from "ethers";
88
import { FastifyInstance } from "fastify";
99
import { StatusCodes } from "http-status-codes";
10-
import { queueNativeTokenTransferTx } from "../../../db/transactions/queueNativeTokenTransferTx";
1110
import { queueTx } from "../../../db/transactions/queueTx";
11+
import { queueTxRaw } from "../../../db/transactions/queueTxRaw";
1212
import { getContract } from "../../../utils/cache/getContract";
1313
import { getSdk } from "../../../utils/cache/getSdk";
1414
import {
@@ -85,16 +85,27 @@ export async function transfer(fastify: FastifyInstance) {
8585
throw new Error("Insufficient balance");
8686
}
8787

88-
queueId = await queueNativeTokenTransferTx({
89-
chainId,
88+
const params = {
89+
toAddress: to,
90+
fromAddress: walletAddress,
91+
currencyAddress,
92+
value: normalizedValue.toHexString(),
93+
};
94+
95+
({ id: queueId } = await queueTxRaw({
96+
chainId: chainId.toString(),
97+
functionName: "transfer",
98+
functionArgs: JSON.stringify([
99+
params.toAddress,
100+
params.value,
101+
params.currencyAddress,
102+
]),
90103
extension: "none",
91-
transferParams: {
92-
toAddress: to,
93-
fromAddress: walletAddress,
94-
value: normalizedValue.toHexString(),
95-
currencyAddress: currencyAddress,
96-
},
97-
});
104+
fromAddress: params.fromAddress,
105+
toAddress: params.toAddress,
106+
value: params.value,
107+
data: "0x",
108+
}));
98109
} else {
99110
const contract = await getContract({
100111
chainId,

src/server/routes/backend-wallet/withdraw.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Static, Type } from "@sinclair/typebox";
22
import { FastifyInstance } from "fastify";
33
import { StatusCodes } from "http-status-codes";
4-
import { prisma } from "../../../db/client";
4+
import { queueTxRaw } from "../../../db/transactions/queueTxRaw";
55
import {
66
standardResponseSchema,
77
transactionWritesResponseSchema,
@@ -45,15 +45,13 @@ export async function withdraw(fastify: FastifyInstance) {
4545

4646
const chainId = await getChainIdFromChain(chain);
4747

48-
const { id: queueId } = await prisma.transactions.create({
49-
data: {
50-
chainId: chainId.toString(),
51-
extension: "withdraw",
52-
functionName: "transfer",
53-
fromAddress: walletAddress,
54-
toAddress,
55-
data: "0x",
56-
},
48+
const { id: queueId } = await queueTxRaw({
49+
chainId: chainId.toString(),
50+
extension: "withdraw",
51+
functionName: "transfer",
52+
fromAddress: walletAddress,
53+
toAddress,
54+
data: "0x",
5755
});
5856

5957
res.status(StatusCodes.OK).send({

0 commit comments

Comments
 (0)