Skip to content

Commit bfd7400

Browse files
authored
Merge branch 'main' into ph/userOpsTimeout
2 parents 449e455 + 2c61ede commit bfd7400

File tree

9 files changed

+115
-12
lines changed

9 files changed

+115
-12
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ Host Engine on your own instructure for free. [View self-host instructions](http
4646

4747
Other deployment options:
4848

49-
- [Deploy on Railway](https://railway.app/template/EASlyJ)
49+
[![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/template/fcEVay)
5050

5151
### Cloud-host
5252

@@ -58,6 +58,7 @@ We welcome contributions! See [How to contribute](./contributing.md).
5858

5959
## Get in touch
6060

61-
- Support: [Join the Discord](https://discord.gg/thirdweb)
61+
- Community: [Join us on Discord](https://discord.gg/thirdweb)
62+
- Support: <https://thirdweb.com/support>
6263
- Twitter: [@thirdweb](https://twitter.com/thirdweb)
6364
- Report a vulnerability: security@thirdweb.com

src/db/transactions/queueTx.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ interface QueueTxParams {
1515
deployedContractType?: string;
1616
simulateTx?: boolean;
1717
idempotencyKey?: string;
18+
txOverrides?: {
19+
gas?: string;
20+
maxFeePerGas?: string;
21+
maxPriorityFeePerGas?: string;
22+
};
1823
}
1924

2025
export const queueTx = async ({
@@ -26,6 +31,7 @@ export const queueTx = async ({
2631
deployedContractType,
2732
simulateTx,
2833
idempotencyKey,
34+
txOverrides,
2935
}: QueueTxParams) => {
3036
// TODO: We need a much safer way of detecting if the transaction should be a user operation
3137
const isUserOp = !!(tx.getSigner as ERC4337EthersSigner).erc4337provider;
@@ -38,6 +44,7 @@ export const queueTx = async ({
3844
deployedContractType: deployedContractType,
3945
data: tx.encode(),
4046
value: BigNumber.from(await tx.getValue()).toHexString(),
47+
...txOverrides,
4148
};
4249

4350
if (isUserOp) {
@@ -60,7 +67,12 @@ export const queueTx = async ({
6067
return queueId;
6168
} else {
6269
const fromAddress = await tx.getSignerAddress();
63-
const toAddress = tx.getTarget();
70+
const toAddress =
71+
tx.getTarget() === "0x0000000000000000000000000000000000000000" &&
72+
txData.functionName === "deploy" &&
73+
extension === "deploy-published"
74+
? null
75+
: tx.getTarget();
6476

6577
const { id: queueId } = await queueTxRaw({
6678
pgtx,

src/db/transactions/queueTxRaw.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ type QueueTxRawParams = Omit<
2525
pgtx?: PrismaTransaction;
2626
simulateTx?: boolean;
2727
idempotencyKey?: string;
28+
gas?: string;
2829
};
2930

3031
export const queueTxRaw = async ({
@@ -60,6 +61,8 @@ export const queueTxRaw = async ({
6061
target: tx.target?.toLowerCase(),
6162
signerAddress: tx.signerAddress?.toLowerCase(),
6263
accountAddress: tx.accountAddress?.toLowerCase(),
64+
gasLimit: tx.gas,
65+
gas: undefined,
6366
};
6467

6568
let txRow: Transactions;

src/db/transactions/updateTx.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ type UpdateTxData =
2424
res: ethers.providers.TransactionRequest;
2525
sentAtBlockNumber: number;
2626
retryCount?: number;
27+
deployedContractAddress?: string;
2728
}
2829
| {
2930
status: TransactionStatus.UserOpSent;
@@ -84,6 +85,7 @@ export const updateTx = async ({ pgtx, queueId, data }: UpdateTxParams) => {
8485
maxFeePerGas: data.res?.maxFeePerGas?.toString(),
8586
maxPriorityFeePerGas: data.res?.maxPriorityFeePerGas?.toString(),
8687
value: data.res?.value?.toString(),
88+
deployedContractAddress: data.deployedContractAddress,
8789
},
8890
});
8991
break;

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,14 +85,22 @@ export async function writeToContract(fastify: FastifyInstance) {
8585
walletAddress,
8686
accountAddress,
8787
});
88-
const tx = await contract.prepare(functionName, args, txOverrides);
88+
const tx = contract.prepare(functionName, args, {
89+
value: txOverrides?.value,
90+
gasLimit: txOverrides?.gas,
91+
maxFeePerGas: txOverrides?.maxFeePerGas,
92+
maxPriorityFeePerGas: txOverrides?.maxPriorityFeePerGas,
93+
});
8994

9095
const queueId = await queueTx({
9196
tx,
9297
chainId,
9398
simulateTx,
9499
extension: "none",
95100
idempotencyKey,
101+
txOverrides: {
102+
...txOverrides,
103+
},
96104
});
97105

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

src/server/routes/deploy/published.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
import { txOverrides } from "../../schemas/txOverrides";
1111
import { walletHeaderSchema } from "../../schemas/wallet";
1212
import { getChainIdFromChain } from "../../utils/chain";
13+
import { isAddress } from "thirdweb";
1314

1415
// INPUTS
1516
const requestSchema = publishedDeployParamSchema;
@@ -35,7 +36,12 @@ requestBodySchema.examples = [
3536
// OUTPUT
3637
const responseSchema = Type.Object({
3738
queueId: Type.Optional(Type.String()),
38-
deployedAddress: Type.Optional(Type.String()),
39+
deployedAddress: Type.Optional(
40+
Type.String({
41+
description: "Not all contracts return a deployed address.",
42+
}),
43+
),
44+
message: Type.Optional(Type.String()),
3945
});
4046

4147
export async function deployPublished(fastify: FastifyInstance) {
@@ -76,7 +82,10 @@ export async function deployPublished(fastify: FastifyInstance) {
7682
constructorParams,
7783
version,
7884
);
79-
const deployedAddress = await tx.simulate();
85+
const _deployedAddress = await tx.simulate();
86+
const deployedAddress = isAddress(_deployedAddress)
87+
? _deployedAddress
88+
: undefined;
8089

8190
const queueId = await queueTx({
8291
tx,
@@ -90,6 +99,9 @@ export async function deployPublished(fastify: FastifyInstance) {
9099
reply.status(StatusCodes.OK).send({
91100
deployedAddress,
92101
queueId,
102+
message: !deployedAddress
103+
? `To retrieve the deployed contract address, use the endpoint '/transaction/status/${queueId}' and check the value of the 'deployedContractAddress' field`
104+
: undefined,
93105
});
94106
},
95107
});

src/server/schemas/txOverrides.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,28 @@ export const txOverrides = Type.Object({
55
Type.Object({
66
value: Type.Optional(
77
Type.String({
8-
examples: ["0"],
8+
examples: ["10000000000"],
99
description: "Amount of native currency to send",
1010
}),
1111
),
12+
gas: Type.Optional(
13+
Type.String({
14+
examples: ["530000"],
15+
description: "Gas limit for the transaction",
16+
}),
17+
),
18+
maxFeePerGas: Type.Optional(
19+
Type.String({
20+
examples: ["1000000000"],
21+
description: "Maximum fee per gas",
22+
}),
23+
),
24+
maxPriorityFeePerGas: Type.Optional(
25+
Type.String({
26+
examples: ["1000000000"],
27+
description: "Maximum priority fee per gas",
28+
}),
29+
),
1230
}),
1331
),
1432
});

src/utils/crypto.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import crypto from "crypto";
2+
import CryptoJS from "crypto-js";
23
import { env } from "./env";
34

45
export const encrypt = (data: string): string => {

src/worker/tasks/processTx.ts

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import {
3535
} from "../../utils/webhook";
3636
import { randomNonce } from "../utils/nonce";
3737
import { getWithdrawValue } from "../utils/withdraw";
38+
import { getContractAddress } from "ethers/lib/utils";
3839

3940
type RpcResponseData = {
4041
tx: Transactions;
@@ -170,11 +171,27 @@ export const processTx = async () => {
170171
...gasOverrides,
171172
});
172173

173-
// TODO: We need to target specific cases
174-
// Bump gas limit to avoid occasional out of gas errors
175-
txRequest.gasLimit = txRequest.gasLimit
176-
? BigNumber.from(txRequest.gasLimit).mul(120).div(100)
177-
: undefined;
174+
// Gas limit override
175+
if (tx.gasLimit) {
176+
txRequest.gasLimit = BigNumber.from(tx.gasLimit);
177+
} else {
178+
// TODO: We need to target specific cases
179+
// Bump gas limit to avoid occasional out of gas errors
180+
txRequest.gasLimit = txRequest.gasLimit
181+
? BigNumber.from(txRequest.gasLimit).mul(120).div(100)
182+
: undefined;
183+
}
184+
185+
// Gas price overrides
186+
if (tx.maxFeePerGas) {
187+
txRequest.maxFeePerGas = BigNumber.from(tx.maxFeePerGas);
188+
}
189+
190+
if (tx.maxPriorityFeePerGas) {
191+
txRequest.maxPriorityFeePerGas = BigNumber.from(
192+
tx.maxPriorityFeePerGas,
193+
);
194+
}
178195

179196
const signature = await signer.signTransaction(txRequest);
180197
const rpcRequest = {
@@ -288,6 +305,16 @@ export const processTx = async () => {
288305
if (rpcResponse.result) {
289306
// Transaction was successful.
290307
const transactionHash = rpcResponse.result;
308+
let contractAddress: string | undefined;
309+
if (
310+
tx.extension === "deploy-published" &&
311+
tx.functionName === "deploy"
312+
) {
313+
contractAddress = getContractAddress({
314+
from: txRequest.from!,
315+
nonce: BigNumber.from(txRequest.nonce!),
316+
});
317+
}
291318
await updateTx({
292319
pgtx,
293320
queueId: tx.id,
@@ -297,6 +324,7 @@ export const processTx = async () => {
297324
res: txRequest,
298325
sentAt: new Date(),
299326
sentAtBlockNumber: sentAtBlockNumber!,
327+
deployedContractAddress: contractAddress,
300328
},
301329
});
302330
reportUsageForQueueIds.push({
@@ -366,6 +394,24 @@ export const processTx = async () => {
366394
nonce,
367395
},
368396
);
397+
398+
// Temporary fix untill SDK allows us to do this
399+
if (tx.gasLimit) {
400+
unsignedOp.callGasLimit = BigNumber.from(tx.gasLimit);
401+
unsignedOp.paymasterAndData = "0x";
402+
const DUMMY_SIGNATURE =
403+
"0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c";
404+
unsignedOp.signature = DUMMY_SIGNATURE;
405+
const paymasterResult =
406+
await signer.smartAccountAPI.paymasterAPI.getPaymasterAndData(
407+
unsignedOp,
408+
);
409+
const paymasterAndData = paymasterResult.paymasterAndData;
410+
if (paymasterAndData && paymasterAndData !== "0x") {
411+
unsignedOp.paymasterAndData = paymasterAndData;
412+
}
413+
}
414+
369415
const userOp = await signer.smartAccountAPI.signUserOp(unsignedOp);
370416
const userOpHash = await signer.smartAccountAPI.getUserOpHash(
371417
userOp,

0 commit comments

Comments
 (0)