Skip to content

Commit

Permalink
Merge branch 'main' into ph/userOpsTimeout
Browse files Browse the repository at this point in the history
  • Loading branch information
farhanW3 authored Apr 23, 2024
2 parents 449e455 + 2c61ede commit bfd7400
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 12 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Host Engine on your own instructure for free. [View self-host instructions](http

Other deployment options:

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

### Cloud-host

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

## Get in touch

- Support: [Join the Discord](https://discord.gg/thirdweb)
- Community: [Join us on Discord](https://discord.gg/thirdweb)
- Support: <https://thirdweb.com/support>
- Twitter: [@thirdweb](https://twitter.com/thirdweb)
- Report a vulnerability: [email protected]
14 changes: 13 additions & 1 deletion src/db/transactions/queueTx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ interface QueueTxParams {
deployedContractType?: string;
simulateTx?: boolean;
idempotencyKey?: string;
txOverrides?: {
gas?: string;
maxFeePerGas?: string;
maxPriorityFeePerGas?: string;
};
}

export const queueTx = async ({
Expand All @@ -26,6 +31,7 @@ export const queueTx = async ({
deployedContractType,
simulateTx,
idempotencyKey,
txOverrides,
}: QueueTxParams) => {
// TODO: We need a much safer way of detecting if the transaction should be a user operation
const isUserOp = !!(tx.getSigner as ERC4337EthersSigner).erc4337provider;
Expand All @@ -38,6 +44,7 @@ export const queueTx = async ({
deployedContractType: deployedContractType,
data: tx.encode(),
value: BigNumber.from(await tx.getValue()).toHexString(),
...txOverrides,
};

if (isUserOp) {
Expand All @@ -60,7 +67,12 @@ export const queueTx = async ({
return queueId;
} else {
const fromAddress = await tx.getSignerAddress();
const toAddress = tx.getTarget();
const toAddress =
tx.getTarget() === "0x0000000000000000000000000000000000000000" &&
txData.functionName === "deploy" &&
extension === "deploy-published"
? null
: tx.getTarget();

const { id: queueId } = await queueTxRaw({
pgtx,
Expand Down
3 changes: 3 additions & 0 deletions src/db/transactions/queueTxRaw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type QueueTxRawParams = Omit<
pgtx?: PrismaTransaction;
simulateTx?: boolean;
idempotencyKey?: string;
gas?: string;
};

export const queueTxRaw = async ({
Expand Down Expand Up @@ -60,6 +61,8 @@ export const queueTxRaw = async ({
target: tx.target?.toLowerCase(),
signerAddress: tx.signerAddress?.toLowerCase(),
accountAddress: tx.accountAddress?.toLowerCase(),
gasLimit: tx.gas,
gas: undefined,
};

let txRow: Transactions;
Expand Down
2 changes: 2 additions & 0 deletions src/db/transactions/updateTx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type UpdateTxData =
res: ethers.providers.TransactionRequest;
sentAtBlockNumber: number;
retryCount?: number;
deployedContractAddress?: string;
}
| {
status: TransactionStatus.UserOpSent;
Expand Down Expand Up @@ -84,6 +85,7 @@ export const updateTx = async ({ pgtx, queueId, data }: UpdateTxParams) => {
maxFeePerGas: data.res?.maxFeePerGas?.toString(),
maxPriorityFeePerGas: data.res?.maxPriorityFeePerGas?.toString(),
value: data.res?.value?.toString(),
deployedContractAddress: data.deployedContractAddress,
},
});
break;
Expand Down
10 changes: 9 additions & 1 deletion src/server/routes/contract/write/write.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,22 @@ export async function writeToContract(fastify: FastifyInstance) {
walletAddress,
accountAddress,
});
const tx = await contract.prepare(functionName, args, txOverrides);
const tx = contract.prepare(functionName, args, {
value: txOverrides?.value,
gasLimit: txOverrides?.gas,
maxFeePerGas: txOverrides?.maxFeePerGas,
maxPriorityFeePerGas: txOverrides?.maxPriorityFeePerGas,
});

const queueId = await queueTx({
tx,
chainId,
simulateTx,
extension: "none",
idempotencyKey,
txOverrides: {
...txOverrides,
},
});

reply.status(StatusCodes.OK).send({
Expand Down
16 changes: 14 additions & 2 deletions src/server/routes/deploy/published.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
import { txOverrides } from "../../schemas/txOverrides";
import { walletHeaderSchema } from "../../schemas/wallet";
import { getChainIdFromChain } from "../../utils/chain";
import { isAddress } from "thirdweb";

// INPUTS
const requestSchema = publishedDeployParamSchema;
Expand All @@ -35,7 +36,12 @@ requestBodySchema.examples = [
// OUTPUT
const responseSchema = Type.Object({
queueId: Type.Optional(Type.String()),
deployedAddress: Type.Optional(Type.String()),
deployedAddress: Type.Optional(
Type.String({
description: "Not all contracts return a deployed address.",
}),
),
message: Type.Optional(Type.String()),
});

export async function deployPublished(fastify: FastifyInstance) {
Expand Down Expand Up @@ -76,7 +82,10 @@ export async function deployPublished(fastify: FastifyInstance) {
constructorParams,
version,
);
const deployedAddress = await tx.simulate();
const _deployedAddress = await tx.simulate();
const deployedAddress = isAddress(_deployedAddress)
? _deployedAddress
: undefined;

const queueId = await queueTx({
tx,
Expand All @@ -90,6 +99,9 @@ export async function deployPublished(fastify: FastifyInstance) {
reply.status(StatusCodes.OK).send({
deployedAddress,
queueId,
message: !deployedAddress
? `To retrieve the deployed contract address, use the endpoint '/transaction/status/${queueId}' and check the value of the 'deployedContractAddress' field`
: undefined,
});
},
});
Expand Down
20 changes: 19 additions & 1 deletion src/server/schemas/txOverrides.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,28 @@ export const txOverrides = Type.Object({
Type.Object({
value: Type.Optional(
Type.String({
examples: ["0"],
examples: ["10000000000"],
description: "Amount of native currency to send",
}),
),
gas: Type.Optional(
Type.String({
examples: ["530000"],
description: "Gas limit for the transaction",
}),
),
maxFeePerGas: Type.Optional(
Type.String({
examples: ["1000000000"],
description: "Maximum fee per gas",
}),
),
maxPriorityFeePerGas: Type.Optional(
Type.String({
examples: ["1000000000"],
description: "Maximum priority fee per gas",
}),
),
}),
),
});
1 change: 1 addition & 0 deletions src/utils/crypto.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import crypto from "crypto";
import CryptoJS from "crypto-js";
import { env } from "./env";

export const encrypt = (data: string): string => {
Expand Down
56 changes: 51 additions & 5 deletions src/worker/tasks/processTx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
} from "../../utils/webhook";
import { randomNonce } from "../utils/nonce";
import { getWithdrawValue } from "../utils/withdraw";
import { getContractAddress } from "ethers/lib/utils";

type RpcResponseData = {
tx: Transactions;
Expand Down Expand Up @@ -170,11 +171,27 @@ export const processTx = async () => {
...gasOverrides,
});

// TODO: We need to target specific cases
// Bump gas limit to avoid occasional out of gas errors
txRequest.gasLimit = txRequest.gasLimit
? BigNumber.from(txRequest.gasLimit).mul(120).div(100)
: undefined;
// Gas limit override
if (tx.gasLimit) {
txRequest.gasLimit = BigNumber.from(tx.gasLimit);
} else {
// TODO: We need to target specific cases
// Bump gas limit to avoid occasional out of gas errors
txRequest.gasLimit = txRequest.gasLimit
? BigNumber.from(txRequest.gasLimit).mul(120).div(100)
: undefined;
}

// Gas price overrides
if (tx.maxFeePerGas) {
txRequest.maxFeePerGas = BigNumber.from(tx.maxFeePerGas);
}

if (tx.maxPriorityFeePerGas) {
txRequest.maxPriorityFeePerGas = BigNumber.from(
tx.maxPriorityFeePerGas,
);
}

const signature = await signer.signTransaction(txRequest);
const rpcRequest = {
Expand Down Expand Up @@ -288,6 +305,16 @@ export const processTx = async () => {
if (rpcResponse.result) {
// Transaction was successful.
const transactionHash = rpcResponse.result;
let contractAddress: string | undefined;
if (
tx.extension === "deploy-published" &&
tx.functionName === "deploy"
) {
contractAddress = getContractAddress({
from: txRequest.from!,
nonce: BigNumber.from(txRequest.nonce!),
});
}
await updateTx({
pgtx,
queueId: tx.id,
Expand All @@ -297,6 +324,7 @@ export const processTx = async () => {
res: txRequest,
sentAt: new Date(),
sentAtBlockNumber: sentAtBlockNumber!,
deployedContractAddress: contractAddress,
},
});
reportUsageForQueueIds.push({
Expand Down Expand Up @@ -366,6 +394,24 @@ export const processTx = async () => {
nonce,
},
);

// Temporary fix untill SDK allows us to do this
if (tx.gasLimit) {
unsignedOp.callGasLimit = BigNumber.from(tx.gasLimit);
unsignedOp.paymasterAndData = "0x";
const DUMMY_SIGNATURE =
"0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c";
unsignedOp.signature = DUMMY_SIGNATURE;
const paymasterResult =
await signer.smartAccountAPI.paymasterAPI.getPaymasterAndData(
unsignedOp,
);
const paymasterAndData = paymasterResult.paymasterAndData;
if (paymasterAndData && paymasterAndData !== "0x") {
unsignedOp.paymasterAndData = paymasterAndData;
}
}

const userOp = await signer.smartAccountAPI.signUserOp(unsignedOp);
const userOpHash = await signer.smartAccountAPI.getUserOpHash(
userOp,
Expand Down

0 comments on commit bfd7400

Please sign in to comment.