From f82a048130074c30869c683c8f706a2f48ac8d46 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Tue, 24 Jun 2025 13:49:34 +1200 Subject: [PATCH 01/18] Switch Engine API endpoint to localhost for development --- .../transactions/analytics/tx-table/types.ts | 9 +- .../tx/[id]/transaction-details-ui.tsx | 19 +- packages/engine/openapi-ts.config.ts | 7 +- packages/engine/package.json | 62 +- packages/engine/src/client/client.gen.ts | 20 +- packages/engine/src/client/sdk.gen.ts | 664 +++-- packages/engine/src/client/types.gen.ts | 2581 ++++++++++------- .../src/engine/create-server-wallet.ts | 2 +- packages/thirdweb/src/engine/get-status.ts | 2 +- .../src/engine/list-server-wallets.ts | 2 +- .../src/engine/search-transactions.ts | 2 +- .../thirdweb/src/engine/server-wallet.test.ts | 16 +- packages/thirdweb/src/engine/server-wallet.ts | 102 +- pnpm-lock.yaml | 17 +- 14 files changed, 2074 insertions(+), 1431 deletions(-) diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/analytics/tx-table/types.ts b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/analytics/tx-table/types.ts index 482409932ff..f176f30c35b 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/analytics/tx-table/types.ts +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/analytics/tx-table/types.ts @@ -34,7 +34,14 @@ type ExecutionResult4337Serialized = } | { status: "FAILED"; - error: string; + error: { + stage: string; + message: string; + errorCode: string; + inner_error: object; + nonce_used: string; + account_address: string; + }; } | { status: "SUBMITTED"; diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/tx/[id]/transaction-details-ui.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/tx/[id]/transaction-details-ui.tsx index 951be2deb08..840fb6ac7b3 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/tx/[id]/transaction-details-ui.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/tx/[id]/transaction-details-ui.tsx @@ -43,10 +43,14 @@ export function TransactionDetailsUI({ const status = executionResult?.status as keyof typeof statusDetails; const errorMessage = executionResult && "error" in executionResult - ? executionResult.error + ? executionResult.error.message : executionResult && "revertData" in executionResult ? executionResult.revertData?.revertReason : null; + const errorDetails = + executionResult && "error" in executionResult + ? executionResult.error + : undefined; const chain = chainId ? idToChain.get(Number.parseInt(chainId)) : undefined; const explorer = chain?.explorers?.[0]; @@ -244,9 +248,16 @@ export function TransactionDetailsUI({ -
- {errorMessage} -
+ {errorDetails ? ( + + ) : ( +
+ errorMessage +
+ )}
)} diff --git a/packages/engine/openapi-ts.config.ts b/packages/engine/openapi-ts.config.ts index 385d7ac7cb9..053bab3fe42 100644 --- a/packages/engine/openapi-ts.config.ts +++ b/packages/engine/openapi-ts.config.ts @@ -1,7 +1,8 @@ import { defineConfig } from "@hey-api/openapi-ts"; export default defineConfig({ - input: "https://engine.thirdweb.com/openapi", - output: { format: "biome", lint: "biome", path: "src/client" }, - plugins: ["@hey-api/client-fetch"], + // input: "https://engine.thirdweb.com/openapi", + input: "http://localhost:3009/openapi", + output: { format: "biome", lint: "biome", path: "src/client" }, + plugins: ["@hey-api/client-fetch"], }); diff --git a/packages/engine/package.json b/packages/engine/package.json index 24b05bd3989..0a073b59c56 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,25 +1,25 @@ { - "name": "@thirdweb-dev/engine", - "version": "3.0.3", - "repository": { - "type": "git", - "url": "git+https://github.com/thirdweb-dev/js.git#main" - }, - "license": "Apache-2.0", + "author": "thirdweb eng ", "bugs": { "url": "https://github.com/thirdweb-dev/js/issues" }, - "author": "thirdweb eng ", - "type": "module", - "main": "./dist/cjs/exports/thirdweb.js", - "module": "./dist/esm/exports/thirdweb.js", - "types": "./dist/types/exports/thirdweb.d.ts", - "typings": "./dist/types/exports/thirdweb.d.ts", + "dependencies": { + "@hey-api/client-fetch": "0.10.0" + }, + "devDependencies": { + "@biomejs/biome": "2.0.4", + "@hey-api/openapi-ts": "0.72.1", + "rimraf": "6.0.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=18" + }, "exports": { ".": { - "types": "./dist/types/exports/thirdweb.d.ts", + "default": "./dist/cjs/exports/thirdweb.js", "import": "./dist/esm/exports/thirdweb.js", - "default": "./dist/cjs/exports/thirdweb.js" + "types": "./dist/types/exports/thirdweb.d.ts" }, "./package.json": "./package.json" }, @@ -27,15 +27,10 @@ "dist/*", "src/*" ], - "dependencies": { - "@hey-api/client-fetch": "0.10.0" - }, - "devDependencies": { - "@biomejs/biome": "2.0.4", - "@hey-api/openapi-ts": "0.72.1", - "rimraf": "6.0.1", - "tslib": "^2.8.1" - }, + "license": "Apache-2.0", + "main": "./dist/cjs/exports/thirdweb.js", + "module": "./dist/esm/exports/thirdweb.js", + "name": "@thirdweb-dev/engine", "peerDependencies": { "typescript": ">=5.0.4" }, @@ -44,18 +39,23 @@ "optional": true } }, + "repository": { + "type": "git", + "url": "git+https://github.com/thirdweb-dev/js.git#main" + }, "scripts": { - "format": "biome format ./src --write", - "lint": "biome check ./src", - "fix": "biome check ./src --fix", "build": "pnpm clean && pnpm build:cjs && pnpm build:esm && pnpm build:types", "build:cjs": "tsc --project ./tsconfig.build.json --module commonjs --outDir ./dist/cjs --verbatimModuleSyntax false && printf '{\"type\":\"commonjs\"}' > ./dist/cjs/package.json", "build:esm": "tsc --project ./tsconfig.build.json --module es2020 --outDir ./dist/esm && printf '{\"type\": \"module\",\"sideEffects\":false}' > ./dist/esm/package.json", + "build:generate": "openapi-ts && pnpm format", "build:types": "tsc --project ./tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap", "clean": "rimraf dist", - "build:generate": "openapi-ts && pnpm format" + "fix": "biome check ./src --fix", + "format": "biome format ./src --write", + "lint": "biome check ./src" }, - "engines": { - "node": ">=18" - } + "type": "module", + "types": "./dist/types/exports/thirdweb.d.ts", + "typings": "./dist/types/exports/thirdweb.d.ts", + "version": "3.0.3" } diff --git a/packages/engine/src/client/client.gen.ts b/packages/engine/src/client/client.gen.ts index 2a1dfa5d7a9..926e4ae2bd0 100644 --- a/packages/engine/src/client/client.gen.ts +++ b/packages/engine/src/client/client.gen.ts @@ -1,10 +1,10 @@ // This file is auto-generated by @hey-api/openapi-ts import { - type Config, - createClient, - createConfig, - type ClientOptions as DefaultClientOptions, + type Config, + createClient, + createConfig, + type ClientOptions as DefaultClientOptions, } from "@hey-api/client-fetch"; import type { ClientOptions } from "./types.gen.js"; @@ -17,12 +17,12 @@ import type { ClientOptions } from "./types.gen.js"; * to ensure your client always has the correct values. */ export type CreateClientConfig = - ( - override?: Config, - ) => Config & T>; + ( + override?: Config, + ) => Config & T>; export const client = createClient( - createConfig({ - baseUrl: "https://engine.thirdweb.com", - }), + createConfig({ + baseUrl: "http://localhost:3009", + }), ); diff --git a/packages/engine/src/client/sdk.gen.ts b/packages/engine/src/client/sdk.gen.ts index d5b748b73b3..6f56a6344be 100644 --- a/packages/engine/src/client/sdk.gen.ts +++ b/packages/engine/src/client/sdk.gen.ts @@ -1,55 +1,60 @@ // This file is auto-generated by @hey-api/openapi-ts import type { - Client, - Options as ClientOptions, - TDataShape, + Client, + Options as ClientOptions, + TDataShape, } from "@hey-api/client-fetch"; import { client as _heyApiClient } from "./client.gen.js"; import type { - CreateAccountData, - CreateAccountResponse, - EncodeFunctionDataData, - EncodeFunctionDataResponse, - GetNativeBalanceData, - GetNativeBalanceResponse, - GetTransactionAnalyticsData, - GetTransactionAnalyticsResponse, - GetTransactionAnalyticsSummaryData, - GetTransactionAnalyticsSummaryResponse, - ListAccountsData, - ListAccountsResponse, - ReadContractData, - ReadContractResponse, - SearchTransactionsData, - SearchTransactionsResponse, - SendTransactionData, - SendTransactionResponse, - SignMessageData, - SignMessageResponse, - SignTransactionData, - SignTransactionResponse, - SignTypedDataData, - SignTypedDataResponse, - WriteContractData, - WriteContractResponse, + CreateAccountData, + CreateAccountResponses, + EncodeContractData, + EncodeContractResponses, + GetActivityLogsData, + GetActivityLogsErrors, + GetActivityLogsResponses, + GetTransactionAnalyticsData, + GetTransactionAnalyticsResponses, + GetTransactionAnalyticsSummaryData, + GetTransactionAnalyticsSummaryErrors, + GetTransactionAnalyticsSummaryResponses, + GetTransactionsData, + GetTransactionsResponses, + ListAccountsData, + ListAccountsResponses, + ReadContractData, + ReadContractResponses, + SearchActivityLogsData, + SearchActivityLogsErrors, + SearchActivityLogsResponses, + SearchTransactionsData, + SearchTransactionsResponses, + SignMessageData, + SignMessageResponses, + SignTypedDataData, + SignTypedDataResponses, + WriteContractData, + WriteContractResponses, + WriteTransactionData, + WriteTransactionResponses, } from "./types.gen.js"; export type Options< - TData extends TDataShape = TDataShape, - ThrowOnError extends boolean = boolean, + TData extends TDataShape = TDataShape, + ThrowOnError extends boolean = boolean, > = ClientOptions & { - /** - * You can provide a client instance returned by `createClient()` instead of - * individual options. This might be also useful if you want to implement a - * custom client. - */ - client?: Client; - /** - * You can pass arbitrary values through the `meta` object. This can be - * used to access values that aren't defined as part of the SDK function. - */ - meta?: Record; + /** + * You can provide a client instance returned by `createClient()` instead of + * individual options. This might be also useful if you want to implement a + * custom client. + */ + client?: Client; + /** + * You can pass arbitrary values through the `meta` object. This can be + * used to access values that aren't defined as part of the SDK function. + */ + meta?: Record; }; /** @@ -57,22 +62,22 @@ export type Options< * List all engine server wallets for the current project. Returns an array of EOA addresses with their corresponding predicted smart account addresses. */ export const listAccounts = ( - options?: Options, + options?: Options, ) => { - return (options?.client ?? _heyApiClient).get< - ListAccountsResponse, - unknown, - ThrowOnError - >({ - security: [ - { - name: "x-secret-key", - type: "apiKey", - }, - ], - url: "/v1/accounts", - ...options, - }); + return (options?.client ?? _heyApiClient).get< + ListAccountsResponses, + unknown, + ThrowOnError + >({ + security: [ + { + name: "x-secret-key", + type: "apiKey", + }, + ], + url: "/v1/accounts", + ...options, + }); }; /** @@ -80,323 +85,342 @@ export const listAccounts = ( * Create a new engine server wallet. This is a helper route for creating a new EOA with your KMS provider, provided as a convenient alternative to creating an EOA directly with your KMS provider. Your KMS credentials are not stored, and usage of created accounts require your KMS credentials to be sent with requests. */ export const createAccount = ( - options?: Options, + options?: Options, ) => { - return (options?.client ?? _heyApiClient).post< - CreateAccountResponse, - unknown, - ThrowOnError - >({ - security: [ - { - name: "x-secret-key", - type: "apiKey", - }, - ], - url: "/v1/accounts", - ...options, - headers: { - "Content-Type": "application/json", - ...options?.headers, - }, - }); + return (options?.client ?? _heyApiClient).post< + CreateAccountResponses, + unknown, + ThrowOnError + >({ + security: [ + { + name: "x-secret-key", + type: "apiKey", + }, + ], + url: "/v1/accounts", + ...options, + headers: { + "Content-Type": "application/json", + ...options?.headers, + }, + }); }; /** - * Write Contract - * Call a write function on a contract. + * Get Transactions + * Search transactions with various filters and pagination */ -export const writeContract = ( - options?: Options, +export const getTransactions = ( + options?: Options, ) => { - return (options?.client ?? _heyApiClient).post< - WriteContractResponse, - unknown, - ThrowOnError - >({ - security: [ - { - name: "x-secret-key", - type: "apiKey", - }, - ], - url: "/v1/write/contract", - ...options, - headers: { - "Content-Type": "application/json", - ...options?.headers, - }, - }); + return (options?.client ?? _heyApiClient).get< + GetTransactionsResponses, + unknown, + ThrowOnError + >({ + security: [ + { + name: "x-secret-key", + type: "apiKey", + }, + ], + url: "/v1/transactions", + ...options, + }); }; /** - * Send Transaction - * Send an encoded transaction or a batch of transactions + * Transaction Analytics + * Get transaction count analytics over time with filtering */ -export const sendTransaction = ( - options?: Options, +export const getTransactionAnalytics = ( + options?: Options, ) => { - return (options?.client ?? _heyApiClient).post< - SendTransactionResponse, - unknown, - ThrowOnError - >({ - security: [ - { - name: "x-secret-key", - type: "apiKey", - }, - ], - url: "/v1/write/transaction", - ...options, - headers: { - "Content-Type": "application/json", - ...options?.headers, - }, - }); + return (options?.client ?? _heyApiClient).post< + GetTransactionAnalyticsResponses, + unknown, + ThrowOnError + >({ + security: [ + { + name: "x-secret-key", + type: "apiKey", + }, + ], + url: "/v1/transactions/analytics", + ...options, + headers: { + "Content-Type": "application/json", + ...options?.headers, + }, + }); }; /** - * Sign Transaction - * Sign transactions without sending them. + * Transaction Analytics Summary + * Get a summary (total count and total gas calculation) for transactions within a time range, supporting complex nested filters. */ -export const signTransaction = ( - options?: Options, +export const getTransactionAnalyticsSummary = < + ThrowOnError extends boolean = false, +>( + options?: Options, ) => { - return (options?.client ?? _heyApiClient).post< - SignTransactionResponse, - unknown, - ThrowOnError - >({ - security: [ - { - name: "x-secret-key", - type: "apiKey", - }, - ], - url: "/v1/sign/transaction", - ...options, - headers: { - "Content-Type": "application/json", - ...options?.headers, - }, - }); + return (options?.client ?? _heyApiClient).post< + GetTransactionAnalyticsSummaryResponses, + GetTransactionAnalyticsSummaryErrors, + ThrowOnError + >({ + security: [ + { + name: "x-secret-key", + type: "apiKey", + }, + ], + url: "/v1/transactions/analytics-summary", + ...options, + headers: { + "Content-Type": "application/json", + ...options?.headers, + }, + }); }; /** - * Sign Message - * Sign arbitrary messages. + * Search Transactions + * Advanced search for transactions with complex nested filters */ -export const signMessage = ( - options?: Options, +export const searchTransactions = ( + options?: Options, ) => { - return (options?.client ?? _heyApiClient).post< - SignMessageResponse, - unknown, - ThrowOnError - >({ - security: [ - { - name: "x-secret-key", - type: "apiKey", - }, - ], - url: "/v1/sign/message", - ...options, - headers: { - "Content-Type": "application/json", - ...options?.headers, - }, - }); + return (options?.client ?? _heyApiClient).post< + SearchTransactionsResponses, + unknown, + ThrowOnError + >({ + security: [ + { + name: "x-secret-key", + type: "apiKey", + }, + ], + url: "/v1/transactions/search", + ...options, + headers: { + "Content-Type": "application/json", + ...options?.headers, + }, + }); }; /** - * Sign Typed Data - * Sign EIP-712 typed data. + * Get Activity Logs + * Get paginated activity logs for a specific transaction with tenancy enforcement */ -export const signTypedData = ( - options?: Options, +export const getActivityLogs = ( + options: Options, ) => { - return (options?.client ?? _heyApiClient).post< - SignTypedDataResponse, - unknown, - ThrowOnError - >({ - security: [ - { - name: "x-secret-key", - type: "apiKey", - }, - ], - url: "/v1/sign/typed-data", - ...options, - headers: { - "Content-Type": "application/json", - ...options?.headers, - }, - }); + return (options.client ?? _heyApiClient).get< + GetActivityLogsResponses, + GetActivityLogsErrors, + ThrowOnError + >({ + security: [ + { + name: "x-secret-key", + type: "apiKey", + }, + ], + url: "/v1/transactions/activity-logs", + ...options, + }); }; /** - * Read Contract - * Call read-only contract functions or batch read using multicall. + * Search Activity Logs + * Search activity logs across transactions with advanced filtering and tenancy enforcement */ -export const readContract = ( - options?: Options, +export const searchActivityLogs = ( + options?: Options, ) => { - return (options?.client ?? _heyApiClient).post< - ReadContractResponse, - unknown, - ThrowOnError - >({ - security: [ - { - name: "x-secret-key", - type: "apiKey", - }, - ], - url: "/v1/read/contract", - ...options, - headers: { - "Content-Type": "application/json", - ...options?.headers, - }, - }); + return (options?.client ?? _heyApiClient).post< + SearchActivityLogsResponses, + SearchActivityLogsErrors, + ThrowOnError + >({ + security: [ + { + name: "x-secret-key", + type: "apiKey", + }, + ], + url: "/v1/transactions/activity-logs/search", + ...options, + headers: { + "Content-Type": "application/json", + ...options?.headers, + }, + }); }; /** - * Read Native Balance - * Fetches the native cryptocurrency balance (e.g., ETH, MATIC) for a given address on a specific chain. + * Write Contract + * Call a contract function with a transaction */ -export const getNativeBalance = ( - options?: Options, +export const writeContract = ( + options: Options, ) => { - return (options?.client ?? _heyApiClient).post< - GetNativeBalanceResponse, - unknown, - ThrowOnError - >({ - security: [ - { - name: "x-secret-key", - type: "apiKey", - }, - ], - url: "/v1/read/balance", - ...options, - headers: { - "Content-Type": "application/json", - ...options?.headers, - }, - }); + return (options.client ?? _heyApiClient).post< + WriteContractResponses, + unknown, + ThrowOnError + >({ + security: [ + { + name: "x-secret-key", + type: "apiKey", + }, + ], + url: "/v1/write/contract", + ...options, + headers: { + "Content-Type": "application/json", + ...options.headers, + }, + }); }; /** - * Encode Function Data - * Encode a contract call into transaction parameters (to, data, value). + * Write Transaction + * Execute raw transactions */ -export const encodeFunctionData = ( - options?: Options, +export const writeTransaction = ( + options: Options, ) => { - return (options?.client ?? _heyApiClient).post< - EncodeFunctionDataResponse, - unknown, - ThrowOnError - >({ - security: [ - { - name: "x-secret-key", - type: "apiKey", - }, - ], - url: "/v1/encode/contract", - ...options, - headers: { - "Content-Type": "application/json", - ...options?.headers, - }, - }); + return (options.client ?? _heyApiClient).post< + WriteTransactionResponses, + unknown, + ThrowOnError + >({ + security: [ + { + name: "x-secret-key", + type: "apiKey", + }, + ], + url: "/v1/write/transaction", + ...options, + headers: { + "Content-Type": "application/json", + ...options.headers, + }, + }); }; /** - * Search Transactions - * Advanced search for transactions with complex nested filters + * Sign Message + * Sign messages using either EOA or Smart Account */ -export const searchTransactions = ( - options?: Options, +export const signMessage = ( + options: Options, ) => { - return (options?.client ?? _heyApiClient).post< - SearchTransactionsResponse, - unknown, - ThrowOnError - >({ - security: [ - { - name: "x-secret-key", - type: "apiKey", - }, - ], - url: "/v1/transactions/search", - ...options, - headers: { - "Content-Type": "application/json", - ...options?.headers, - }, - }); + return (options.client ?? _heyApiClient).post< + SignMessageResponses, + unknown, + ThrowOnError + >({ + security: [ + { + name: "x-secret-key", + type: "apiKey", + }, + ], + url: "/v1/sign/message", + ...options, + headers: { + "Content-Type": "application/json", + ...options.headers, + }, + }); }; /** - * Transaction Analytics - * Get transaction count analytics over time with filtering + * Sign Typed Data + * Sign EIP-712 typed data using either EOA or Smart Account */ -export const getTransactionAnalytics = ( - options?: Options, +export const signTypedData = ( + options: Options, ) => { - return (options?.client ?? _heyApiClient).post< - GetTransactionAnalyticsResponse, - unknown, - ThrowOnError - >({ - security: [ - { - name: "x-secret-key", - type: "apiKey", - }, - ], - url: "/v1/transactions/analytics", - ...options, - headers: { - "Content-Type": "application/json", - ...options?.headers, - }, - }); + return (options.client ?? _heyApiClient).post< + SignTypedDataResponses, + unknown, + ThrowOnError + >({ + security: [ + { + name: "x-secret-key", + type: "apiKey", + }, + ], + url: "/v1/sign/typed-data", + ...options, + headers: { + "Content-Type": "application/json", + ...options.headers, + }, + }); }; /** - * Transaction Analytics Summary - * Get a summary (total count and total gas calculation) for transactions within a time range, supporting complex nested filters. + * Read Contract + * Read from multiple smart contracts using multicall */ -export const getTransactionAnalyticsSummary = < - ThrowOnError extends boolean = false, ->( - options?: Options, +export const readContract = ( + options: Options, +) => { + return (options.client ?? _heyApiClient).post< + ReadContractResponses, + unknown, + ThrowOnError + >({ + security: [ + { + name: "x-secret-key", + type: "apiKey", + }, + ], + url: "/v1/read/contract", + ...options, + headers: { + "Content-Type": "application/json", + ...options.headers, + }, + }); +}; + +/** + * Encode Contract + * Encode contract function calls without execution + */ +export const encodeContract = ( + options: Options, ) => { - return (options?.client ?? _heyApiClient).post< - GetTransactionAnalyticsSummaryResponse, - unknown, - ThrowOnError - >({ - security: [ - { - name: "x-secret-key", - type: "apiKey", - }, - ], - url: "/v1/transactions/analytics-summary", - ...options, - headers: { - "Content-Type": "application/json", - ...options?.headers, - }, - }); + return (options.client ?? _heyApiClient).post< + EncodeContractResponses, + unknown, + ThrowOnError + >({ + security: [ + { + name: "x-secret-key", + type: "apiKey", + }, + ], + url: "/v1/encode/contract", + ...options, + headers: { + "Content-Type": "application/json", + ...options.headers, + }, + }); }; diff --git a/packages/engine/src/client/types.gen.ts b/packages/engine/src/client/types.gen.ts index 99a3986e8c5..45ab8c7c8d0 100644 --- a/packages/engine/src/client/types.gen.ts +++ b/packages/engine/src/client/types.gen.ts @@ -1,1086 +1,1635 @@ // This file is auto-generated by @hey-api/openapi-ts export type TransactionsFilterValue = { - field: - | "id" - | "batchIndex" - | "from" - | "signerAddress" - | "smartAccountAddress" - | "chainId"; - values: Array; - operation?: "AND" | "OR"; + field: + | "id" + | "batchIndex" + | "from" + | "signerAddress" + | "smartAccountAddress" + | "chainId"; + values: Array; + operation: "AND" | "OR"; }; export type TransactionsFilterNested = { - operation: "AND" | "OR"; - filters: Array; + operation: "AND" | "OR"; + filters: Array; }; /** - * This is the default execution option. If you do not specify an execution type, and only specify a "from" string, engine will automatically determine the most optimal options for you. If you would like to specify granular options about execution strategy choose one of the other `executionOptions` type and provide them. + * ### Address + * Used to represent an EVM address. This is a string of length 42 with a `0x` prefix. Non-checksummed addresses are also supported, but will be converted to checksummed. + */ +export type AddressDef = string; + +/** + * Extension trait for EngineError to add HTTP response conversion + */ +export type ApiEngineError = EngineError; + +/** + * Auto Determine Execution + * This is the default execution option. + * If you do not specify an execution type, and only specify a "from" string, + * engine will automatically determine the most optimal options for you. + * If you would like to specify granular options about execution strategy + * choose one of the other executionOptions type and provide them. */ export type AutoExecutionOptions = { - /** - * This is the default, a `type` does not need to be specified - */ - type?: "auto"; - /** - * The address of the account to send the transaction from. Can be the address of a smart account or an EOA. - */ - from: string; - /** - * The idempotency key of the transaction. Transaction requests sent with the same idempotency key will be de-duplicated. If not provided, a randomUUID will be generated. This is also used as the ID of a queued/stored transaction. - */ - idempotencyKey?: string; - /** - * The chain id of the transaction - */ - chainId: string; -}; - -export type AaExecutionOptions = { - type: "ERC4337"; - /** - * The address of the engine managed account which can send transactions from your smart account - */ - signerAddress: string; - sponsorGas?: boolean; - /** - * The address of the smart account factory. Defaults to thirdweb default v0.7 Account Factory. Only specify this if you are using a custom account factory. - */ - factoryAddress?: string; - /** - * The address of the entrypoint contract. Defaults to the v0.7 entrypoint for the chain. Only specify this if you want to specify a different version. - */ - entrypointAddress?: string; - /** - * The address of the smart account to send the transaction from. Either specify this, or the salt. If not specified, the inferred smart account will be with null salt. If both are specified, the salt will be ignored. - */ - smartAccountAddress?: string; - /** - * The salt of the smart account to send the transaction from. Only specify this if you want to specify a custom salt. If omitted, and smart account address is not provided, the inferred smart account will be with null salt. If a smart account address is provided, the salt will be ignored. - */ - accountSalt?: string; - /** - * The idempotency key of the transaction. Transaction requests sent with the same idempotency key will be de-duplicated. If not provided, a randomUUID will be generated. This is also used as the ID of a queued/stored transaction. - */ - idempotencyKey?: string; - /** - * The chain id of the transaction - */ - chainId: string; + /** + * The identifier of the entity to send the transaction from. + * Automatically picks best execution strategy based on the identifier. + * - If EOA address, execution uses EIP7702 based smart-wallet execution + * - If 7702 not supported on chain, falls back to smart-contract wallet (ERC4337) with default smart account for this EOA (v0.7) + * - UNLESS this is a zk-chain, in which case, zk-sync native-aa is used + */ + from: string; +}; + +export type BaseExecutionOptions = { + chainId: number; + idempotencyKey?: string; +}; + +/** + * # Bytes + * Used to represent "bytes". This is a 0x prefixed hex string. + */ +export type BytesDef = string; + +export type CancelResult = + | "CANCELLED_IMMEDIATELY" + | "CANCELLATION_PENDING" + | { + CANNOT_CANCEL: { + reason: string; + }; + } + | "NOT_FOUND"; + +/** + * Represents a contract function call with parameters + * + * This is the base type used by all contract interaction endpoints. + * It supports both function names and full function signatures, with + * automatic ABI resolution when needed. + */ +export type ContractCall = { + abi?: null | Value; + /** + * The address of the smart contract to call + */ + contractAddress: AddressDef; + /** + * The function to call - can be a name like "transfer" or full signature like "transfer(address,uint256)" + */ + method: string; + /** + * Array of parameters to pass to the function + */ + params: Array; +}; + +/** + * A serializable contract interaction error type + */ +export type ContractInteractionErrorKind = + | { + /** + * Unknown function referenced. + */ + UnknownFunction: string; + } + | { + /** + * Unknown function selector referenced. + */ + UnknownSelector: string; + } + | "NotADeploymentTransaction" + | "ContractNotDeployed" + | { + /** + * The contract returned no data. + */ + ZeroData: { + function: string; + message: string; + }; + } + | { + /** + * An error occurred ABI encoding or decoding. + */ + AbiError: string; + } + | { + /** + * An error occurred interacting with a contract over RPC. + */ + TransportError: string; + } + | { + /** + * An error occured while waiting for a pending transaction. + */ + PendingTransactionError: string; + } + | { + /** + * Error during contract function preparation (ABI resolution, parameter encoding) + */ + PreparationFailed: string; + } + | { + /** + * Error during multicall execution + */ + MulticallExecutionFailed: string; + } + | { + /** + * Error during result decoding + */ + ResultDecodingFailed: string; + } + | { + /** + * Parameter validation error + */ + ParameterValidationFailed: string; + } + | { + /** + * Function resolution error + */ + FunctionResolutionFailed: string; + }; + +/** + * A contract function call with optional ETH value to send + */ +export type ContractWrite = ContractCall & { + value?: null | U256Def; +}; + +/** + * Options for encoding contract function calls + */ +export type EncodeOptions = { + /** + * The blockchain network ID to encode for + * + * This is used to fetch the correct ABI if not provided inline + */ + chainId: string; +}; + +/** + * Request to encode contract function calls + */ +export type EncodeRequest = { + /** + * Configuration options for encoding + */ + encodeOptions: EncodeOptions; + /** + * List of contract function calls to encode + * + * Each call will be encoded to its raw transaction data + */ + params: Array; +}; + +/** + * Response from the contract encode endpoint + */ +export type EncodeResponse = { + /** + * Container for all encode operation results + */ + result: EncodeResults; +}; + +/** + * Failed result from a contract encode operation + */ +export type EncodeResultFailureItem = { + /** + * Detailed error information describing what went wrong + */ + error: EngineError; + /** + * Always false for failed operations + */ + success: boolean; +}; + +/** + * Result of a single contract encode operation + * + * Each result can either be successful (containing the encoded transaction data) + * or failed (containing detailed error information). + */ +export type EncodeResultItem = + | EncodeResultSuccessItem + | EncodeResultFailureItem; + +/** + * Successful result from a contract encode operation + */ +export type EncodeResultSuccessItem = { + /** + * The encoded function call data + * + * This includes the function selector and encoded parameters, + * ready to be used in a transaction + */ + callData: string; + /** + * The name of the function being called + */ + functionName: string; + /** + * The 4-byte function selector (first 4 bytes of call_data) + */ + functionSelector: string; + /** + * Always true for successful operations + */ + success: boolean; + /** + * The contract address that would be called + */ + target: string; +}; + +/** + * Collection of results from multiple contract encode operations + */ +export type EncodeResults = { + /** + * Array of results, one for each input contract call + */ + results: Array; +}; + +export type EngineError = + | { + RpcError: { + /** + * Detailed RPC error information + */ + chain_id: number; + kind: RpcErrorKind; + message: string; + rpc_url: string; + }; + } + | { + PaymasterError: { + /** + * Detailed RPC error information + */ + chain_id: number; + kind: RpcErrorKind; + message: string; + rpc_url: string; + }; + } + | { + BundlerError: { + /** + * Detailed RPC error information + */ + chain_id: number; + kind: RpcErrorKind; + message: string; + rpc_url: string; + }; + } + | { + VaultError: { + message: string; + }; + } + | { + RpcConfigError: { + message: string; + }; + } + | { + ContractInteractionError: { + /** + * Chain ID + */ + chain_id: number; + contract_address?: null | AddressDef; + /** + * Specific error kind + */ + kind: ContractInteractionErrorKind; + /** + * Human-readable error message + */ + message: string; + }; + } + | { + ValidationError: { + message: string; + }; + } + | { + ThirdwebError: ThirdwebError; + } + | { + InternalError: string; + }; + +export type EntrypointAndFactoryDetailsDeserHelper = { + entrypointAddress?: null | AddressDef; + entrypointVersion?: null | EntrypointVersion; + factoryAddress?: null | AddressDef; +}; + +export type EntrypointVersion = "0.6" | "0.7"; + +/** + * EOA signing options + */ +export type EoaSigningOptions = { + chainId?: null | U64; + /** + * The EOA address to sign with + */ + from: AddressDef; +}; + +/** + * ### ERC-4337 Execution Options + * This struct allows flexible configuration of ERC-4337 execution options, + * with intelligent defaults and inferences based on provided values. + * + * ### Field Inference + * When fields are omitted, the system uses the following inference rules: + * + * 1. Version Inference: + * - If `entrypointVersion` is provided, it's used directly + * - Otherwise, tries to infer from `entrypointAddress` (if provided) + * - If that fails, tries to infer from `factoryAddress` (if provided) + * - Defaults to version 0.7 if no inference is possible + * + * 2. Entrypoint Address Inference: + * - If provided explicitly, it's used as-is + * - Otherwise, uses the default address corresponding to the inferred version: + * - V0.6: 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789 + * - V0.7: 0x0576a174D229E3cFA37253523E645A78A0C91B57 + * + * 3. Factory Address Inference: + * - If provided explicitly, it's used as-is + * - Otherwise, uses the default factory corresponding to the inferred version: + * - V0.6: 0x85e23b94e7F5E9cC1fF78BCe78cfb15B81f0DF00 [DEFAULT_FACTORY_ADDRESS_V0_6] + * - V0.7: 0x4bE0ddfebcA9A5A4a617dee4DeCe99E7c862dceb [DEFAULT_FACTORY_ADDRESS_V0_7] + * + * 4. Account Salt: + * - If provided explicitly, it's used as-is + * - Otherwise, defaults to "0x" (commonly used as the defauult "null" salt for smart accounts) + * + * 5. Smart Account Address: + * - If provided explicitly, it's used as-is + * - Otherwise, it's read from the smart account factory + * + * All optional fields can be omitted for a minimal configuration using version 0.7 defaults. + */ +export type Erc4337ExecutionOptions = EntrypointAndFactoryDetailsDeserHelper & { + accountSalt?: string; + signerAddress: AddressDef; + smartAccountAddress?: null | AddressDef; }; /** - * Uses zkSync native AA for execution. This type of execution is only available on zkSync chains. + * This is the exposed API for execution options + * Base and specific execution options are both flattened together */ -export type AaZksyncExecutionOptions = { - type: "zksync"; - /** - * The EOA address of the account to send the zksync native AA transaction from. - */ - accountAddress: string; - sponsorGas?: boolean; - /** - * The idempotency key of the transaction. Transaction requests sent with the same idempotency key will be de-duplicated. If not provided, a randomUUID will be generated. This is also used as the ID of a queued/stored transaction. - */ - idempotencyKey?: string; - /** - * The chain id of the transaction - */ - chainId: string; +export type ExecutionOptions = BaseExecutionOptions & SpecificExecutionOptions; + +/** + * # InnerTransaction + * This is the actual encoded inner transaction data that will be sent to the blockchain. + */ +export type InnerTransaction = { + data: BytesDef; + to: AddressDef; + value: U256Def; +}; + +export type MessageFormatDef = "text" | "hex"; + +/** + * Individual message to sign + */ +export type MessageInput = { + /** + * Message format (text or hex) + */ + format?: MessageFormatDef; + /** + * The message to sign + */ + message: string; +}; + +/** + * # QueuedTransaction + * Response for any request that queues one or more transactions + */ +export type QueuedTransaction = { + /** + * When multiple transactions are sent together via an execution mode that doesn't support atomic batching, + * each transaction will have a unique batchIndex but the same id (idempotency key) + * This maintains the relationship between different atomically sent blockchain transactions that were queued together + */ + batchIndex: number; + /** + * The fully resolved execution options for this transaction, derived from the resolution of user specific execution options + * Difference in naming is to prevent confusion when response executionParams contain different values than the request executionOptions + */ + executionParams: ExecutionOptions; + /** + * The idempotency key this transaction was queued with + * Either autogenerated UUID or provided by the user + * Multiple queued transactions can have the same idempotency key + * A "blockchain transaction" is uniquely identified by the idempotency key + batchIndex + */ + id: string; + /** + * This is the actual encoded inner transaction data that will be sent to the blockchain. + * For non-atomic transactions, this will be a single transaction + * For atomic transactions, this will be a list of transactions, because they were atomically sent together + */ + transactionParams: Array; +}; + +export type QueuedTransactionsResponse = { + transactions: Array; +}; + +/** + * Options for reading from smart contracts + */ +export type ReadOptions = { + /** + * The blockchain network ID to read from + */ + chainId: string; + from?: null | AddressDef; + /** + * Address of the Multicall3 contract to use for batching calls + * + * Defaults to the standard Multicall3 address: 0xcA11bde05977b3631167028862bE2a173976CA11 + * which is deployed on most networks + */ + multicallAddress?: AddressDef; +}; + +/** + * Request to read from multiple smart contracts + */ +export type ReadRequest = { + /** + * List of contract function calls to execute + * + * All calls will be batched together using Multicall3 for efficiency + */ + params: Array; + /** + * Configuration options for the read operation + */ + readOptions: ReadOptions; +}; + +/** + * Response from the contract read endpoint + */ +export type ReadResponse = { + /** + * Container for all read operation results + */ + result: ReadResults; +}; + +/** + * Failed result from a contract read operation + */ +export type ReadResultFailureItem = { + /** + * Detailed error information describing what went wrong + * + * This includes the error type, chain information, and specific + * failure details to help with debugging + */ + error: EngineError; + /** + * Always false for failed operations + */ + success: boolean; +}; + +/** + * Result of a single contract read operation + * + * Each result can either be successful (containing the function return value) + * or failed (containing detailed error information). The `success` field + * indicates which case applies. + */ +export type ReadResultItem = ReadResultSuccessItem | ReadResultFailureItem; + +/** + * Successful result from a contract read operation + */ +export type ReadResultSuccessItem = { + /** + * The decoded return value from the contract function + * + * For functions returning a single value, this will be that value. + * For functions returning multiple values, this will be an array. + */ + result: Value; + /** + * Always true for successful operations + */ + success: boolean; +}; + +/** + * Collection of results from multiple contract read operations + */ +export type ReadResults = { + /** + * Array of results, one for each input contract call + * + * Results are returned in the same order as the input parameters + */ + results: Array; +}; + +export type RpcErrorKind = + | { + /** + * Server returned an error response. + */ + ErrorResp: RpcErrorResponse; + } + | "NullResp" + | { + /** + * Rpc server returned an unsupported feature. + */ + UnsupportedFeature: string; + } + | { + /** + * Returned when a local pre-processing step fails. This allows custom + * errors from local signers or request pre-processors. + */ + InternalError: string; + } + | { + /** + * JSON serialization error. + */ + SerError: { + /** + * The underlying serde_json error. + */ + message: string; + }; + } + | { + /** + * JSON deserialization error. + */ + DeserError: { + /** + * The underlying serde_json error. + */ + message: string; + /** + * For deser errors, the text that failed to deserialize. + */ + text: string; + }; + } + | { + TransportHttpError: { + body: string; + status: number; + }; + } + | { + OtherTransportError: string; + }; + +export type RpcErrorResponse = { + /** + * The error code. + */ + code: number; + /** + * The error data (if any). + */ + data?: string | null; + /** + * The error message (if any). + */ + message: string; }; +/** + * Incoming transaction request, parsed into InnerTransaction + * Exposed API will have varying `params` but will all parse into InnerTransaction before execution + */ +export type SendTransactionRequest = { + executionOptions: ExecutionOptions; + params: Array; + webhookOptions?: Array | null; +}; + +export type SerializableReqwestError = + | { + Builder: { + message: string; + url?: string | null; + }; + } + | { + Request: { + message: string; + url?: string | null; + }; + } + | { + Timeout: { + message: string; + url?: string | null; + }; + } + | { + Connect: { + message: string; + url?: string | null; + }; + } + | { + Redirect: { + message: string; + url?: string | null; + }; + } + | { + ClientError: { + message: string; + status: number; + url?: string | null; + }; + } + | { + ServerError: { + message: string; + status: number; + url?: string | null; + }; + } + | { + Body: { + message: string; + url?: string | null; + }; + } + | { + Decode: { + message: string; + url?: string | null; + }; + } + | { + Upgrade: { + message: string; + url?: string | null; + }; + } + | { + Unknown: { + message: string; + url?: string | null; + }; + }; + +/** + * Request to sign messages + */ +export type SignMessageRequest = { + /** + * List of messages to sign + */ + params: Array; + /** + * Configuration options for signing + */ + signingOptions: SigningOptions; +}; + +/** + * Response from the sign message endpoint + */ +export type SignMessageResponse = { + /** + * Container for all message signing results + */ + result: SignResults; +}; + +/** + * Configuration options for signing + */ +export type SignOptions = SigningOptions; + +/** + * Data returned from successful signing + */ +export type SignResultData = { + /** + * The resulting signature + */ + signature: string; + /** + * The data that was signed (stringified typed data) + */ + signedData: string; +}; + +/** + * Failed result from a typed data signing operation + */ +export type SignResultFailureItem = { + /** + * Detailed error information describing what went wrong + */ + error: EngineError; + /** + * Always false for failed operations + */ + success: false; +}; + +/** + * Result of a single typed data signing operation + */ +export type SignResultItem = SignResultSuccessItem | SignResultFailureItem; + +/** + * Successful result from a typed data signing operation + */ +export type SignResultSuccessItem = { + /** + * The signing result data + */ + result: SignResultData; + /** + * Always true for successful operations + */ + success: true; +}; + +/** + * Collection of results from multiple typed data signing operations + */ +export type SignResults = { + /** + * Array of results, one for each input typed data + */ + results: Array; +}; + +/** + * Request to sign typed data + */ +export type SignTypedDataRequest = { + /** + * List of typed data to sign + */ + params: Array; + /** + * Configuration options for signing + */ + signOptions: SignOptions; +}; + +/** + * Response from the sign typed data endpoint + */ +export type SignTypedDataResponse = { + /** + * Container for all typed data signing results + */ + result: SignResults; +}; + +/** + * Configuration options for signing operations + */ +export type SigningOptions = + | (EoaSigningOptions & { + type: "eoa"; + }) + | (SmartAccountSigningOptions & { + type: "smart_account"; + }); + +/** + * Smart Account signing options + */ +export type SmartAccountSigningOptions = + EntrypointAndFactoryDetailsDeserHelper & { + /** + * Account salt for deterministic addresses + */ + accountSalt?: string; + /** + * Chain ID for smart account operations + */ + chainId: U64; + /** + * The EOA that controls the smart account + */ + signerAddress: AddressDef; + smartAccountAddress?: null | AddressDef; + }; + +/** + * Execution Option Variants + * All supported specific execution options are contained here + */ +export type SpecificExecutionOptions = + | (AutoExecutionOptions & { + type: "auto"; + }) + | (Erc4337ExecutionOptions & { + type: "ERC4337"; + }); + +export type ThirdwebError = + | { + SerializationError: ThirdwebSerializationError; + } + | { + UrlParseError: { + message: string; + value: string; + }; + } + | { + HttpClientBackendError: string; + } + | { + HttpError: SerializableReqwestError; + }; + +export type ThirdwebSerializationError = { + HeaderValue: { + value: string; + }; +}; + +export type TransactionCancelResponse = { + result: CancelResult; + transactionId: string; +}; + +export type TypedDataDef = { + /** + * Signing domain metadata. The signing domain is the intended context for + * the signature (e.g. the dapp, protocol, etc. that it's intended for). + * This data is used to construct the domain separator of the message. + */ + domain: TypedDataDomainDef; + /** + * The message to be signed. + */ + message: unknown; + /** + * The type of the message. + */ + primaryType: string; + /** + * The custom types used by this message. + */ + types: unknown; +}; + +export type TypedDataDomainDef = { + chain_id?: null | U256Def; + name?: string | null; + /** + * A disambiguating salt for the protocol. This can be used as a domain + * separator of last resort. + */ + salt?: string | null; + verifying_contract?: null | AddressDef; + /** + * The current major version of the signing domain. Signatures from + * different versions are not compatible. + */ + version?: string | null; +}; + +/** + * # U256 + * Used to represent a 256-bit unsigned integer. Engine can parse these from any valid encoding of the Ethereum "quantity" format. + */ +export type U256Def = string; + +export type Value = unknown; + +export type WebhookOptions = { + secret?: string | null; + url: string; +}; + +/** + * Request to execute write transactions to smart contracts + */ +export type WriteContractRequest = { + /** + * Execution configuration including chain, account, and transaction options + */ + executionOptions: ExecutionOptions; + /** + * List of contract function calls to execute + * + * All calls will be executed in a single transaction if possible, + * or as separate transactions if atomic batching is not supported + */ + params: Array; + webhookOptions?: Array | null; +}; + +export type U64 = number; + export type ListAccountsData = { - body?: never; - path?: never; - query?: never; - url: "/v1/accounts"; + body?: never; + path?: never; + query?: never; + url: "/v1/accounts"; }; export type ListAccountsResponses = { - /** - * Accounts retrieved successfully - */ - 200: { - result: Array<{ - /** - * EVM address in hex format - */ - address: string; - /** - * The predicted smart account address for use with the default thirdweb v0.7 AccountFactory - */ - smartAccountAddress?: string; - }>; - }; + /** + * Accounts retrieved successfully + */ + 200: { + result: Array<{ + /** + * EVM address in hex format + */ + address: string; + label?: string; + /** + * The predicted smart account address for use with the default thirdweb v0.7 AccountFactory + */ + smartAccountAddress?: string; + }>; + }; }; export type ListAccountsResponse = - ListAccountsResponses[keyof ListAccountsResponses]; + ListAccountsResponses[keyof ListAccountsResponses]; export type CreateAccountData = { - body?: { - label: string; - }; - headers?: { - /** - * Vault Access Token used to access your EOA - */ - "x-vault-access-token"?: string; - }; - path?: never; - query?: never; - url: "/v1/accounts"; + body?: { + label: string; + }; + headers?: { + /** + * Vault Access Token used to access your EOA + */ + "x-vault-access-token"?: string; + }; + path?: never; + query?: never; + url: "/v1/accounts"; }; export type CreateAccountResponses = { - /** - * Account created successfully - */ - 201: { - result: { - /** - * EVM address in hex format - */ - address: string; - /** - * The predicted smart account address for use with the default thirdweb v0.7 AccountFactory - */ - smartAccountAddress?: string; - }; - }; + /** + * Account created successfully + */ + 201: { + result: { + /** + * EVM address in hex format + */ + address: string; + label?: string; + /** + * The predicted smart account address for use with the default thirdweb v0.7 AccountFactory + */ + smartAccountAddress?: string; + }; + }; }; export type CreateAccountResponse = - CreateAccountResponses[keyof CreateAccountResponses]; + CreateAccountResponses[keyof CreateAccountResponses]; -export type WriteContractData = { - body?: { - /** - * Use a specific execution type and provide options to configure engine's execution strategy. The default execution option is `auto`, (doesn't need to be specified) which will automatically determine the most optimal options for you. If you would like to specify granular options about execution strategy choose one of the other `executionOptions` type and provide them. - */ - executionOptions: - | AutoExecutionOptions - | AaExecutionOptions - | AaZksyncExecutionOptions; - params: Array<{ - /** - * The function to call on the contract - */ - method: string; - /** - * The parameters to pass to the function - */ - params: Array; - /** - * The contract address to call - */ - contractAddress: string; - /** - * The ABI of the contract - */ - abi?: Array; - /** - * The value to send with the transaction - */ - value?: string; - }>; - }; - headers?: { - /** - * Vault Access Token used to access your EOA - */ - "x-vault-access-token"?: string; - }; - path?: never; - query?: never; - url: "/v1/write/contract"; +export type GetTransactionsData = { + body?: never; + path?: never; + query?: { + page?: number; + limit?: number; + id?: string; + batchIndex?: number; + /** + * EVM address in hex format + */ + from?: string; + /** + * EVM address in hex format + */ + signerAddress?: string; + sortBy?: "createdAt" | "confirmedAt"; + sortDirection?: "asc" | "desc"; + }; + url: "/v1/transactions"; }; -export type WriteContractResponses = { - /** - * Transaction sent successfully - */ - 200: { - result: { - transactions: Array<{ - id: string; - batchIndex: number; - clientId: string; - chainId: string; - from: string | null; - transactionParams: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - transactionHash: string | null; - confirmedAt: string | null; - confirmedAtBlockNumber: string | null; - enrichedData: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - executionParams: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - executionResult: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array - | null; - createdAt: string; - errorMessage: string | null; - cancelledAt: string | null; - }>; - }; - }; - /** - * Transaction queued successfully - */ - 202: { - result: { - transactions: Array<{ - id: string; - batchIndex: number; - clientId: string; - chainId: string; - from: string | null; - transactionParams: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - transactionHash: string | null; - confirmedAt: string | null; - confirmedAtBlockNumber: string | null; - enrichedData: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - executionParams: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - executionResult: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array - | null; - createdAt: string; - errorMessage: string | null; - cancelledAt: string | null; - }>; - }; - }; +export type GetTransactionsResponses = { + /** + * Transactions + */ + 200: { + result: { + transactions: Array<{ + id: string; + batchIndex: number; + clientId: string; + chainId: string; + from: string | null; + transactionParams: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array; + transactionHash: string | null; + confirmedAt: string | null; + confirmedAtBlockNumber: string | null; + enrichedData: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array; + executionParams: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array; + executionResult: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array + | null; + createdAt: string; + errorMessage: string | null; + cancelledAt: string | null; + }>; + pagination: { + totalCount: number; + page: number; + limit: number; + }; + }; + }; }; -export type WriteContractResponse = - WriteContractResponses[keyof WriteContractResponses]; - -export type SendTransactionData = { - body?: { - /** - * Use a specific execution type and provide options to configure engine's execution strategy. The default execution option is `auto`, (doesn't need to be specified) which will automatically determine the most optimal options for you. If you would like to specify granular options about execution strategy choose one of the other `executionOptions` type and provide them. - */ - executionOptions: - | AutoExecutionOptions - | AaExecutionOptions - | AaZksyncExecutionOptions; - params: Array<{ - /** - * The address of the contract to send the transaction to - */ - to?: string; - /** - * The data of the transaction - */ - data?: string; - /** - * The value of the transaction - */ - value?: string; - }>; - }; - headers?: { - /** - * Vault Access Token used to access your EOA - */ - "x-vault-access-token"?: string; - }; - path?: never; - query?: never; - url: "/v1/write/transaction"; -}; - -export type SendTransactionResponses = { - /** - * Transaction sent successfully - */ - 200: { - result: { - transactions: Array<{ - id: string; - batchIndex: number; - clientId: string; - chainId: string; - from: string | null; - transactionParams: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - transactionHash: string | null; - confirmedAt: string | null; - confirmedAtBlockNumber: string | null; - enrichedData: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - executionParams: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - executionResult: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array - | null; - createdAt: string; - errorMessage: string | null; - cancelledAt: string | null; - }>; - }; - }; - /** - * Transaction queued successfully - */ - 202: { - result: { - transactions: Array<{ - id: string; - batchIndex: number; - clientId: string; - chainId: string; - from: string | null; - transactionParams: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - transactionHash: string | null; - confirmedAt: string | null; - confirmedAtBlockNumber: string | null; - enrichedData: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - executionParams: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - executionResult: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array - | null; - createdAt: string; - errorMessage: string | null; - cancelledAt: string | null; - }>; - }; - }; -}; - -export type SendTransactionResponse = - SendTransactionResponses[keyof SendTransactionResponses]; - -export type SignTransactionData = { - body?: { - /** - * Use a specific execution type and provide options to configure engine's execution strategy. The default execution option is `auto`, (doesn't need to be specified) which will automatically determine the most optimal options for you. If you would like to specify granular options about execution strategy choose one of the other `executionOptions` type and provide them. - */ - executionOptions: - | AutoExecutionOptions - | AaExecutionOptions - | AaZksyncExecutionOptions; - params: Array<{ - /** - * The recipient address - */ - to: string; - /** - * The transaction data as hex - */ - data?: string; - /** - * The value to send with the transaction - */ - value?: string; - /** - * Transaction nonce - */ - nonce?: number; - /** - * Gas limit - */ - gasLimit?: string; - /** - * Gas price (for legacy transactions) - */ - gasPrice?: string; - /** - * Max fee per gas (for EIP-1559) - */ - maxFeePerGas?: string; - /** - * Max priority fee per gas (for EIP-1559) - */ - maxPriorityFeePerGas?: string; - /** - * Access list for EIP-2930 and later transactions - */ - accessList?: Array<{ - /** - * EVM address in hex format - */ - address: string; - storageKeys: Array; - }>; - /** - * Max fee per blob gas (for EIP-4844) - */ - maxFeePerBlobGas?: string; - /** - * Blob versioned hashes (for EIP-4844) - */ - blobVersionedHashes?: Array; - /** - * Authorization list (for EIP-7702) - */ - authorizationList?: Array<{ - /** - * Authorization address - */ - address: string; - /** - * r value of the signature - */ - r: string; - /** - * s value of the signature - */ - s: string; - /** - * v value of the signature - */ - v?: number | string; - /** - * yParity value (0 or 1) - */ - yParity: number; - /** - * Authorization nonce - */ - nonce: string; - /** - * Authorization chainId - */ - chainId: number; - }>; - }>; - }; - headers?: { - /** - * Vault Access Token used to access your EOA - */ - "x-vault-access-token"?: string; - }; - path?: never; - query?: never; - url: "/v1/sign/transaction"; -}; - -export type SignTransactionResponses = { - /** - * OK - */ - 200: { - result: { - results: Array< - | { - success: true; - result: { - /** - * The resulting signature - */ - signature: string; - /** - * Optional signed data - */ - signedData?: string; - }; - } - | { - success: false; - /** - * Standardized error object - */ - error: { - kind: string; - code: string; - status: number; - message?: string; - /** - * EVM address in hex format - */ - address?: string; - chainId?: string; - }; - } - >; - }; - }; -}; - -export type SignTransactionResponse = - SignTransactionResponses[keyof SignTransactionResponses]; +export type GetTransactionsResponse = + GetTransactionsResponses[keyof GetTransactionsResponses]; -export type SignMessageData = { - body?: { - /** - * Use a specific execution type and provide options to configure engine's execution strategy. The default execution option is `auto`, (doesn't need to be specified) which will automatically determine the most optimal options for you. If you would like to specify granular options about execution strategy choose one of the other `executionOptions` type and provide them. - */ - executionOptions: - | AutoExecutionOptions - | AaExecutionOptions - | AaZksyncExecutionOptions; - params: Array<{ - /** - * The message to sign - */ - message: string; - /** - * Format of the message (text or hex) - */ - messageFormat?: "text" | "hex"; - }>; - }; - headers?: { - /** - * Vault Access Token used to access your EOA - */ - "x-vault-access-token"?: string; - }; - path?: never; - query?: never; - url: "/v1/sign/message"; +export type GetTransactionAnalyticsData = { + body?: { + startDate: string; + endDate: string; + resolution: "hour" | "day" | "week" | "month"; + filters?: Array; + filtersOperation?: "AND" | "OR"; + }; + path?: never; + query?: never; + url: "/v1/transactions/analytics"; }; -export type SignMessageResponses = { - /** - * OK - */ - 200: { - result: { - results: Array< - | { - success: true; - result: { - /** - * The resulting signature - */ - signature: string; - /** - * Optional signed data - */ - signedData?: string; - }; - } - | { - success: false; - /** - * Standardized error object - */ - error: { - kind: string; - code: string; - status: number; - message?: string; - /** - * EVM address in hex format - */ - address?: string; - chainId?: string; - }; - } - >; - }; - }; -}; - -export type SignMessageResponse = - SignMessageResponses[keyof SignMessageResponses]; - -export type SignTypedDataData = { - body?: { - /** - * Use a specific execution type and provide options to configure engine's execution strategy. The default execution option is `auto`, (doesn't need to be specified) which will automatically determine the most optimal options for you. If you would like to specify granular options about execution strategy choose one of the other `executionOptions` type and provide them. - */ - executionOptions: - | AutoExecutionOptions - | AaExecutionOptions - | AaZksyncExecutionOptions; - params: Array<{ - domain: { - chainId?: number | number; - name?: string; - salt?: string; - verifyingContract?: string; - version?: string; - }; - types: { - [key: string]: Array<{ - name: string; - type: string; - }>; - }; - primaryType: string; - message: { - [key: string]: unknown; - }; - }>; - }; - headers?: { - /** - * Vault Access Token used to access your EOA - */ - "x-vault-access-token"?: string; - }; - path?: never; - query?: never; - url: "/v1/sign/typed-data"; +export type GetTransactionAnalyticsResponses = { + /** + * Transaction Analytics + */ + 200: { + result: { + analytics: Array<{ + timeBucket: string; + chainId: string; + count: number; + }>; + metadata: { + resolution: "hour" | "day" | "week" | "month"; + startDate: string; + endDate: string; + }; + }; + }; }; -export type SignTypedDataResponses = { - /** - * OK - */ - 200: { - result: { - results: Array< - | { - success: true; - result: { - /** - * The resulting signature - */ - signature: string; - /** - * Optional signed data - */ - signedData?: string; - }; - } - | { - success: false; - /** - * Standardized error object - */ - error: { - kind: string; - code: string; - status: number; - message?: string; - /** - * EVM address in hex format - */ - address?: string; - chainId?: string; - }; - } - >; - }; - }; -}; - -export type SignTypedDataResponse = - SignTypedDataResponses[keyof SignTypedDataResponses]; +export type GetTransactionAnalyticsResponse = + GetTransactionAnalyticsResponses[keyof GetTransactionAnalyticsResponses]; -export type ReadContractData = { - body?: { - readOptions: { - /** - * Optional multicall address, defaults to the default multicall3 address for the chain - */ - multicallAddress?: string; - /** - * The chain id of the transaction - */ - chainId: string; - /** - * EVM address in hex format - */ - from?: string; - }; - params: Array<{ - /** - * The function to call on the contract - */ - method: string; - /** - * The parameters to pass to the function - */ - params: Array; - /** - * The contract address to call - */ - contractAddress: string; - /** - * The ABI of the contract - */ - abi?: Array; - }>; - }; - path?: never; - query?: never; - url: "/v1/read/contract"; +export type GetTransactionAnalyticsSummaryData = { + body?: { + startDate?: string; + endDate?: string; + filters?: Array; + filtersOperation?: "AND" | "OR"; + }; + path?: never; + query?: never; + url: "/v1/transactions/analytics-summary"; }; -export type ReadContractResponses = { - /** - * OK - */ - 200: { - result: { - results: Array<{ - success: boolean; - result?: null; - }>; - }; - }; +export type GetTransactionAnalyticsSummaryErrors = { + /** + * Bad Request (e.g., invalid date format, filter depth exceeded) + */ + 400: unknown; + /** + * Internal Server Error (e.g., database error) + */ + 500: unknown; }; -export type ReadContractResponse = - ReadContractResponses[keyof ReadContractResponses]; - -export type GetNativeBalanceData = { - body?: { - /** - * The chain ID to query the balance on. - */ - chainId: string; - /** - * The EVM address to get the native balance for. - */ - address: string; - }; - path?: never; - query?: never; - url: "/v1/read/balance"; -}; - -export type GetNativeBalanceErrors = { - /** - * Bad Request - Invalid input - */ - 400: unknown; - /** - * Internal Server Error - */ - 500: unknown; -}; - -export type GetNativeBalanceResponses = { - /** - * OK - Balance fetched successfully. - */ - 200: { - result: { - /** - * The native balance of the address as a stringified integer. - */ - balance: string; - }; - }; -}; - -export type GetNativeBalanceResponse = - GetNativeBalanceResponses[keyof GetNativeBalanceResponses]; - -export type EncodeFunctionDataData = { - body?: { - encodeOptions: { - /** - * The chain id of the transaction - */ - chainId: string; - }; - params: Array<{ - /** - * The function to call on the contract - */ - method: string; - /** - * The parameters to pass to the function - */ - params: Array; - /** - * The contract address to call - */ - contractAddress: string; - /** - * The ABI of the contract - */ - abi?: Array; - /** - * The value to send with the transaction - */ - value?: string; - }>; - }; - path?: never; - query?: never; - url: "/v1/encode/contract"; -}; - -export type EncodeFunctionDataResponses = { - /** - * OK - */ - 200: { - result: { - results: Array< - | { - success: true; - result: { - /** - * EVM address in hex format - */ - to: string; - data: string; - /** - * A string representing an bigint response, safe to parse with BigInt - */ - value: string; - }; - } - | { - success: false; - /** - * Standardized error object - */ - error: { - kind: string; - code: string; - status: number; - message?: string; - /** - * EVM address in hex format - */ - address?: string; - chainId?: string; - }; - } - >; - }; - }; -}; - -export type EncodeFunctionDataResponse = - EncodeFunctionDataResponses[keyof EncodeFunctionDataResponses]; +export type GetTransactionAnalyticsSummaryResponses = { + /** + * Transaction Analytics Summary + */ + 200: { + result: { + summary: { + /** + * Total number of transactions matching the criteria. + */ + totalCount: number; + /** + * Sum of actualGasCost (in wei) for all matching transactions, as a string. + */ + totalGasCostWei: string; + /** + * Sum of actualGasUsed (gas units) for all matching transactions, as a string. + */ + totalGasUnitsUsed: string; + }; + metadata: { + startDate?: string; + endDate?: string; + }; + }; + }; +}; + +export type GetTransactionAnalyticsSummaryResponse = + GetTransactionAnalyticsSummaryResponses[keyof GetTransactionAnalyticsSummaryResponses]; export type SearchTransactionsData = { - body?: { - page?: number; - limit?: number; - filters?: Array; - filtersOperation?: "AND" | "OR"; - sortBy?: "createdAt" | "confirmedAt"; - sortDirection?: "asc" | "desc"; - }; - path?: never; - query?: never; - url: "/v1/transactions/search"; + body?: { + page?: number; + limit?: number; + filters?: Array; + filtersOperation?: "AND" | "OR"; + sortBy?: "createdAt" | "confirmedAt"; + sortDirection?: "asc" | "desc"; + }; + path?: never; + query?: never; + url: "/v1/transactions/search"; }; export type SearchTransactionsResponses = { - /** - * Transactions - */ - 200: { - result: { - transactions: Array<{ - id: string; - batchIndex: number; - clientId: string; - chainId: string; - from: string | null; - transactionParams: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - transactionHash: string | null; - confirmedAt: string | null; - confirmedAtBlockNumber: string | null; - enrichedData: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - executionParams: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - executionResult: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array - | null; - createdAt: string; - errorMessage: string | null; - cancelledAt: string | null; - }>; - pagination: { - totalCount: number; - page: number; - limit: number; - }; - }; - }; + /** + * Transactions + */ + 200: { + result: { + transactions: Array<{ + id: string; + batchIndex: number; + clientId: string; + chainId: string; + from: string | null; + transactionParams: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array; + transactionHash: string | null; + confirmedAt: string | null; + confirmedAtBlockNumber: string | null; + enrichedData: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array; + executionParams: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array; + executionResult: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array + | null; + createdAt: string; + errorMessage: string | null; + cancelledAt: string | null; + }>; + pagination: { + totalCount: number; + page: number; + limit: number; + }; + }; + }; }; export type SearchTransactionsResponse = - SearchTransactionsResponses[keyof SearchTransactionsResponses]; + SearchTransactionsResponses[keyof SearchTransactionsResponses]; -export type GetTransactionAnalyticsData = { - body?: { - startDate: string; - endDate: string; - resolution: "hour" | "day" | "week" | "month"; - filters?: Array; - filtersOperation?: "AND" | "OR"; - }; - path?: never; - query?: never; - url: "/v1/transactions/analytics"; +export type GetActivityLogsData = { + body?: never; + path?: never; + query: { + page?: number; + limit?: number; + transactionId: string; + batchIndex?: number; + eventType?: "SUCCESS" | "FAILURE" | "NACK"; + stageName?: string; + executorName?: string; + sortBy?: "timestamp" | "createdAt"; + sortDirection?: "asc" | "desc"; + }; + url: "/v1/transactions/activity-logs"; }; -export type GetTransactionAnalyticsResponses = { - /** - * Transaction Analytics - */ - 200: { - result: { - analytics: Array<{ - timeBucket: string; - chainId: string; - count: number; - }>; - metadata: { - resolution: "hour" | "day" | "week" | "month"; - startDate: string; - endDate: string; - }; - }; - }; +export type GetActivityLogsErrors = { + /** + * Invalid request parameters + */ + 400: unknown; + /** + * Transaction not found or not accessible + */ + 404: unknown; }; -export type GetTransactionAnalyticsResponse = - GetTransactionAnalyticsResponses[keyof GetTransactionAnalyticsResponses]; +export type GetActivityLogsResponses = { + /** + * Activity Logs + */ + 200: { + result: { + activityLogs: Array<{ + id: string; + transactionId: string; + batchIndex: number; + eventType: string; + stageName: string; + executorName: string; + notificationId: string; + payload: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array; + timestamp: string; + createdAt: string; + }>; + transaction: { + id: string; + batchIndex: number; + clientId: string; + }; + pagination: { + totalCount: number; + page: number; + limit: number; + }; + }; + }; +}; -export type GetTransactionAnalyticsSummaryData = { - body?: { - startDate?: string; - endDate?: string; - filters?: Array; - filtersOperation?: "AND" | "OR"; - }; - path?: never; - query?: never; - url: "/v1/transactions/analytics-summary"; +export type GetActivityLogsResponse = + GetActivityLogsResponses[keyof GetActivityLogsResponses]; + +export type SearchActivityLogsData = { + body?: { + page?: number; + limit?: number; + transactionIds?: Array; + eventType?: "SUCCESS" | "FAILURE" | "NACK"; + stageName?: string; + executorName?: string; + startDate?: string; + endDate?: string; + sortBy?: "timestamp" | "createdAt"; + sortDirection?: "asc" | "desc"; + }; + path?: never; + query?: never; + url: "/v1/transactions/activity-logs/search"; }; -export type GetTransactionAnalyticsSummaryErrors = { - /** - * Bad Request (e.g., invalid date format, filter depth exceeded) - */ - 400: unknown; - /** - * Internal Server Error (e.g., database error) - */ - 500: unknown; +export type SearchActivityLogsErrors = { + /** + * Invalid request parameters + */ + 400: unknown; }; -export type GetTransactionAnalyticsSummaryResponses = { - /** - * Transaction Analytics Summary - */ - 200: { - result: { - summary: { - /** - * Total number of transactions matching the criteria. - */ - totalCount: number; - /** - * Sum of actualGasCost (in wei) for all matching transactions, as a string. - */ - totalGasCostWei: string; - /** - * Sum of actualGasUsed (gas units) for all matching transactions, as a string. - */ - totalGasUnitsUsed: string; - }; - metadata: { - startDate?: string; - endDate?: string; - }; - }; - }; +export type SearchActivityLogsResponses = { + /** + * Activity Logs Search Results + */ + 200: { + result: { + activityLogs: Array<{ + id: string; + transactionId: string; + batchIndex: number; + eventType: string; + stageName: string; + executorName: string; + notificationId: string; + payload: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array; + timestamp: string; + createdAt: string; + }>; + pagination: { + totalCount: number; + page: number; + limit: number; + }; + }; + }; }; -export type GetTransactionAnalyticsSummaryResponse = - GetTransactionAnalyticsSummaryResponses[keyof GetTransactionAnalyticsSummaryResponses]; +export type SearchActivityLogsResponse = + SearchActivityLogsResponses[keyof SearchActivityLogsResponses]; + +export type WriteContractData = { + /** + * Write contract request + */ + body: WriteContractRequest; + headers?: { + /** + * Thirdweb client ID, passed along with the service key + */ + "x-thirdweb-client-id"?: string | null; + /** + * Thirdweb service key, passed when using the client ID + */ + "x-thirdweb-service-key"?: string | null; + /** + * Thirdweb secret key, passed standalone + */ + "x-thirdweb-secret-key"?: string | null; + /** + * Vault access token + */ + "x-vault-access-token"?: string | null; + }; + path?: never; + query?: never; + url: "/v1/write/contract"; +}; + +export type WriteContractResponses = { + /** + * Transaction(s) queued successfully + */ + 202: QueuedTransactionsResponse; +}; + +export type WriteContractResponse = + WriteContractResponses[keyof WriteContractResponses]; + +export type WriteTransactionData = { + /** + * Transaction request + */ + body: SendTransactionRequest; + headers?: { + /** + * Thirdweb client ID, passed along with the service key + */ + "x-thirdweb-client-id"?: string | null; + /** + * Thirdweb service key, passed when using the client ID + */ + "x-thirdweb-service-key"?: string | null; + /** + * Thirdweb secret key, passed standalone + */ + "x-thirdweb-secret-key"?: string | null; + /** + * Vault access token + */ + "x-vault-access-token"?: string | null; + }; + path?: never; + query?: never; + url: "/v1/write/transaction"; +}; + +export type WriteTransactionResponses = { + /** + * Transaction queued successfully + */ + 202: QueuedTransactionsResponse; +}; + +export type WriteTransactionResponse = + WriteTransactionResponses[keyof WriteTransactionResponses]; + +export type SignMessageData = { + /** + * Sign message request + */ + body: SignMessageRequest; + headers?: { + /** + * Thirdweb client ID, passed along with the service key + */ + "x-thirdweb-client-id"?: string | null; + /** + * Thirdweb service key, passed when using the client ID + */ + "x-thirdweb-service-key"?: string | null; + /** + * Thirdweb secret key, passed standalone + */ + "x-thirdweb-secret-key"?: string | null; + /** + * Vault access token + */ + "x-vault-access-token"?: string | null; + }; + path?: never; + query?: never; + url: "/v1/sign/message"; +}; + +export type SignMessageResponses = { + /** + * Successfully signed messages + */ + 200: SignMessageResponse; +}; + +export type SignMessageResponse2 = + SignMessageResponses[keyof SignMessageResponses]; + +export type SignTypedDataData = { + /** + * Sign typed data request + */ + body: SignTypedDataRequest; + headers?: { + /** + * Thirdweb client ID, passed along with the service key + */ + "x-thirdweb-client-id"?: string | null; + /** + * Thirdweb service key, passed when using the client ID + */ + "x-thirdweb-service-key"?: string | null; + /** + * Thirdweb secret key, passed standalone + */ + "x-thirdweb-secret-key"?: string | null; + /** + * Vault access token + */ + "x-vault-access-token"?: string | null; + }; + path?: never; + query?: never; + url: "/v1/sign/typed-data"; +}; + +export type SignTypedDataResponses = { + /** + * Successfully signed typed data + */ + 200: SignTypedDataResponse; +}; + +export type SignTypedDataResponse2 = + SignTypedDataResponses[keyof SignTypedDataResponses]; + +export type ReadContractData = { + /** + * Read contract request + */ + body: ReadRequest; + headers?: { + /** + * Thirdweb client ID, passed along with the service key + */ + "x-thirdweb-client-id"?: string | null; + /** + * Thirdweb service key, passed when using the client ID + */ + "x-thirdweb-service-key"?: string | null; + /** + * Thirdweb secret key, passed standalone + */ + "x-thirdweb-secret-key"?: string | null; + }; + path?: never; + query?: never; + url: "/v1/read/contract"; +}; + +export type ReadContractResponses = { + /** + * Successfully read contract data + */ + 200: ReadResponse; +}; + +export type ReadContractResponse = + ReadContractResponses[keyof ReadContractResponses]; + +export type EncodeContractData = { + /** + * Encode contract request + */ + body: EncodeRequest; + headers?: { + /** + * Thirdweb client ID, passed along with the service key + */ + "x-thirdweb-client-id"?: string | null; + /** + * Thirdweb service key, passed when using the client ID + */ + "x-thirdweb-service-key"?: string | null; + /** + * Thirdweb secret key, passed standalone + */ + "x-thirdweb-secret-key"?: string | null; + }; + path?: never; + query?: never; + url: "/v1/encode/contract"; +}; + +export type EncodeContractResponses = { + /** + * Successfully encoded contract calls + */ + 200: EncodeResponse; +}; + +export type EncodeContractResponse = + EncodeContractResponses[keyof EncodeContractResponses]; export type ClientOptions = { - baseUrl: "https://engine.thirdweb.com" | (string & {}); + baseUrl: "http://localhost:3009" | (string & {}); }; diff --git a/packages/thirdweb/src/engine/create-server-wallet.ts b/packages/thirdweb/src/engine/create-server-wallet.ts index c410b47e9cd..5b2e7d9604b 100644 --- a/packages/thirdweb/src/engine/create-server-wallet.ts +++ b/packages/thirdweb/src/engine/create-server-wallet.ts @@ -47,7 +47,7 @@ export async function createServerWallet(params: CreateServerWalletArgs) { ); } - const data = result.data?.result; + const data = result.data?.[201]?.result; if (!data) { throw new Error(`No server wallet created with label ${label}`); diff --git a/packages/thirdweb/src/engine/get-status.ts b/packages/thirdweb/src/engine/get-status.ts index 88e15459769..b79a2e2bf1d 100644 --- a/packages/thirdweb/src/engine/get-status.ts +++ b/packages/thirdweb/src/engine/get-status.ts @@ -99,7 +99,7 @@ export async function getTransactionStatus(args: { ); } - const data = searchResult.data?.result?.transactions?.[0]; + const data = searchResult.data?.[200]?.result?.transactions?.[0]; if (!data) { throw new Error(`Transaction ${transactionId} not found`); diff --git a/packages/thirdweb/src/engine/list-server-wallets.ts b/packages/thirdweb/src/engine/list-server-wallets.ts index 53e4213ad64..2efe1199b39 100644 --- a/packages/thirdweb/src/engine/list-server-wallets.ts +++ b/packages/thirdweb/src/engine/list-server-wallets.ts @@ -36,7 +36,7 @@ export async function getServerWallets(params: GetServerWalletsArgs) { throw new Error(`Error listing server wallets: ${stringify(result.error)}`); } - const data = result.data?.result; + const data = result.data?.[200]?.result; if (!data) { throw new Error("No server wallets found"); diff --git a/packages/thirdweb/src/engine/search-transactions.ts b/packages/thirdweb/src/engine/search-transactions.ts index be92534bfb7..27c0c765c3f 100644 --- a/packages/thirdweb/src/engine/search-transactions.ts +++ b/packages/thirdweb/src/engine/search-transactions.ts @@ -122,7 +122,7 @@ export async function searchTransactions(args: SearchTransactionsArgs) { ); } - const data = searchResult.data?.result; + const data = searchResult.data?.[200]?.result; if (!data) { throw new Error(`No transactions found with filters ${stringify(filters)}`); diff --git a/packages/thirdweb/src/engine/server-wallet.test.ts b/packages/thirdweb/src/engine/server-wallet.test.ts index ebed81b59b9..468f9b16acf 100644 --- a/packages/thirdweb/src/engine/server-wallet.test.ts +++ b/packages/thirdweb/src/engine/server-wallet.test.ts @@ -11,6 +11,7 @@ import { mintTo } from "../extensions/erc20/write/mintTo.js"; import { claimTo } from "../extensions/erc1155/drops/write/claimTo.js"; import { getAllActiveSigners } from "../extensions/erc4337/__generated__/IAccountPermissions/read/getAllActiveSigners.js"; import { sendTransaction } from "../transaction/actions/send-transaction.js"; +import { setThirdwebDomains } from "../utils/domains.js"; import { DEFAULT_ACCOUNT_FACTORY_V0_6, ENTRYPOINT_ADDRESS_v0_6, @@ -33,12 +34,13 @@ describe.runIf( let serverWallet: Engine.ServerWallet; beforeAll(async () => { - // setThirdwebDomains({ - // rpc: "rpc.thirdweb-dev.com", - // storage: "storage.thirdweb-dev.com", - // bundler: "bundler.thirdweb-dev.com", - // engineCloud: "engine.thirdweb-dev.com", - // }); + setThirdwebDomains({ + bundler: "bundler.thirdweb-dev.com", + // engineCloud: "engine.thirdweb-dev.com", + engineCloud: "localhost:3009", + rpc: "rpc.thirdweb-dev.com", + storage: "storage.thirdweb-dev.com", + }); serverWallet = Engine.serverWallet({ address: process.env.ENGINE_CLOUD_WALLET_ADDRESS as string, chain: arbitrumSepolia, @@ -47,7 +49,7 @@ describe.runIf( }); }); - it("should create a server wallet", async () => { + it.skip("should create a server wallet", async () => { const serverWallet = await Engine.createServerWallet({ client: TEST_CLIENT, label: "My Server Wallet", diff --git a/packages/thirdweb/src/engine/server-wallet.ts b/packages/thirdweb/src/engine/server-wallet.ts index 17f5b1a9836..f076fb0e51d 100644 --- a/packages/thirdweb/src/engine/server-wallet.ts +++ b/packages/thirdweb/src/engine/server-wallet.ts @@ -1,9 +1,8 @@ import { - type AaExecutionOptions, - type AaZksyncExecutionOptions, - sendTransaction, + type ExecutionOptions, signMessage, signTypedData, + writeTransaction, } from "@thirdweb-dev/engine"; import type { Chain } from "../chains/types.js"; import type { ThirdwebClient } from "../client/client.js"; @@ -44,9 +43,7 @@ export type ServerWalletOptions = { /** * Optional custom execution options to use for sending transactions and signing data. */ - executionOptions?: - | Omit - | Omit; + executionOptions?: Omit; }; export type ServerWallet = Account & { @@ -152,16 +149,31 @@ export function serverWallet(options: ServerWalletOptions): ServerWallet { "x-vault-access-token": vaultAccessToken, }; - const getExecutionOptions = (chainId: number) => { - return executionOptions - ? { - ...executionOptions, - chainId: chainId.toString(), - } - : { - chainId: chainId.toString(), + const getExecutionOptions = (chainId: number): ExecutionOptions => { + const options: ExecutionOptions | undefined = executionOptions as + | ExecutionOptions + | undefined; + if (!options) { + return { + chainId, + from: address, + type: "auto", + }; + } + switch (options.type) { + case "auto": + return { + chainId, from: address, + type: "auto", + }; + case "ERC4337": + return { + ...options, + chainId, + type: "ERC4337", }; + } }; const enqueueTx = async (transaction: SendTransactionOption[]) => { @@ -184,13 +196,13 @@ export function serverWallet(options: ServerWalletOptions): ServerWallet { const body = { executionOptions: getExecutionOptions(chainId), params: transaction.map((t) => ({ - data: t.data, - to: t.to ?? undefined, - value: t.value?.toString(), + data: t.data || "0x", + to: t.to ?? "", // TODO this should be allowed to be undefined + value: t.value?.toString() || "0", })), }; - const result = await sendTransaction({ + const result = await writeTransaction({ baseUrl: getThirdwebBaseUrl("engineCloud"), body, bodySerializer: stringify, @@ -202,7 +214,7 @@ export function serverWallet(options: ServerWalletOptions): ServerWallet { throw new Error(`Error sending transaction: ${stringify(result.error)}`); } - const data = result.data?.result; + const data = result.data?.[202]; if (!data) { throw new Error("No data returned from engine"); } @@ -305,17 +317,35 @@ export function serverWallet(options: ServerWalletOptions): ServerWallet { if (!signingChainId) { throw new Error("Chain ID is required for signing messages"); } - + // FIXME + const options = executionOptions as ExecutionOptions | undefined; const signResult = await signMessage({ baseUrl: getThirdwebBaseUrl("engineCloud"), body: { - executionOptions: getExecutionOptions(signingChainId), params: [ { + format: isBytes ? "hex" : "text", message: engineMessage, - messageFormat: isBytes ? "hex" : "text", }, ], + // FIXME + signingOptions: + options?.type === "ERC4337" + ? { + accountSalt: options.accountSalt, + chainId: signingChainId, + entrypointAddress: options.entrypointAddress, + entrypointVersion: options.entrypointVersion, + factoryAddress: options.factoryAddress, + signerAddress: address, + smartAccountAddress: options.smartAccountAddress, + type: "smart_account", + } + : { + chainId: signingChainId, + from: address, + type: "eoa", + }, }, bodySerializer: stringify, fetch: getClientFetch(client), @@ -328,13 +358,13 @@ export function serverWallet(options: ServerWalletOptions): ServerWallet { ); } - const signatureResult = signResult.data?.result.results[0]; + const signatureResult = signResult.data?.[200]?.result.results[0]; if (signatureResult?.success) { return signatureResult.result.signature as Hex; } throw new Error( - `Failed to sign message: ${signatureResult?.error?.message || "Unknown error"}`, + `Failed to sign message: ${signatureResult?.error || "Unknown error"}`, ); }, signTypedData: async (typedData) => { @@ -343,12 +373,30 @@ export function serverWallet(options: ServerWalletOptions): ServerWallet { throw new Error("Chain ID is required for signing messages"); } + const options = executionOptions as ExecutionOptions; const signResult = await signTypedData({ baseUrl: getThirdwebBaseUrl("engineCloud"), body: { - executionOptions: getExecutionOptions(signingChainId), // biome-ignore lint/suspicious/noExplicitAny: TODO: fix ts / hey-api type clash params: [typedData as any], + // FIXME + signOptions: + options?.type === "ERC4337" + ? { + accountSalt: options.accountSalt, + chainId: signingChainId, + entrypointAddress: options.entrypointAddress, + entrypointVersion: options.entrypointVersion, + factoryAddress: options.factoryAddress, + signerAddress: address, + smartAccountAddress: options.smartAccountAddress, + type: "smart_account", + } + : { + chainId: signingChainId, + from: address, + type: "eoa", + }, }, bodySerializer: stringify, fetch: getClientFetch(client), @@ -361,13 +409,13 @@ export function serverWallet(options: ServerWalletOptions): ServerWallet { ); } - const signatureResult = signResult.data?.result.results[0]; + const signatureResult = signResult.data?.[200]?.result.results[0]; if (signatureResult?.success) { return signatureResult.result.signature as Hex; } throw new Error( - `Failed to sign message: ${signatureResult?.error?.message || "Unknown error"}`, + `Failed to sign message: ${signatureResult?.error || "Unknown error"}`, ); }, }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 11c7bd8ed2e..47ac195a0ae 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3429,6 +3429,7 @@ packages: '@hey-api/client-fetch@0.10.0': resolution: {integrity: sha512-C7vzj4t52qPiHCqjn1l8cRTI2p4pZCd7ViLtJDTHr5ZwI4sWOYC1tmv6bd529qqY6HFFbhGCz4TAZSwKAMJncg==} + deprecated: Starting with v0.73.0, this package is bundled directly inside @hey-api/openapi-ts. peerDependencies: '@hey-api/openapi-ts': < 2 @@ -29164,8 +29165,8 @@ snapshots: '@typescript-eslint/parser': 7.14.1(eslint@8.57.0)(typescript@5.8.3) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.0) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.0) eslint-plugin-react: 7.37.5(eslint@8.57.0) eslint-plugin-react-hooks: 5.2.0(eslint@8.57.0) @@ -29184,7 +29185,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.0): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint@8.57.0))(eslint@8.57.0): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.1(supports-color@8.1.1) @@ -29195,7 +29196,7 @@ snapshots: tinyglobby: 0.2.14 unrs-resolver: 1.9.0 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) transitivePeerDependencies: - supports-color @@ -29220,18 +29221,18 @@ snapshots: - bluebird - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 7.14.1(eslint@8.57.0)(typescript@5.8.3) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint@8.57.0))(eslint@8.57.0) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.0): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -29242,7 +29243,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.3))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 From 592b3e23bc5372f378f26c7dee2267e1c289d070 Mon Sep 17 00:00:00 2001 From: Prithvish Baidya Date: Wed, 25 Jun 2025 07:45:32 +0530 Subject: [PATCH 02/18] upgrade hey-api and ServerWallet improvements --- packages/engine/biome.json | 17 +- packages/engine/openapi-ts.config.ts | 3 +- packages/engine/package.json | 8 +- packages/engine/src/client/client.gen.ts | 4 +- packages/engine/src/client/client/client.ts | 193 ++ packages/engine/src/client/client/index.ts | 22 + packages/engine/src/client/client/types.ts | 222 ++ packages/engine/src/client/client/utils.ts | 417 +++ packages/engine/src/client/core/auth.ts | 40 + .../engine/src/client/core/bodySerializer.ts | 84 + packages/engine/src/client/core/params.ts | 141 + .../engine/src/client/core/pathSerializer.ts | 179 ++ packages/engine/src/client/core/types.ts | 104 + packages/engine/src/client/sdk.gen.ts | 273 +- packages/engine/src/client/types.gen.ts | 2632 ++++++++--------- packages/engine/src/configure.ts | 52 +- packages/engine/tsconfig.base.json | 88 +- packages/engine/tsconfig.build.json | 28 +- packages/engine/tsconfig.json | 20 +- .../src/engine/create-server-wallet.ts | 2 +- packages/thirdweb/src/engine/get-status.ts | 2 +- .../src/engine/list-server-wallets.ts | 2 +- .../src/engine/search-transactions.ts | 2 +- packages/thirdweb/src/engine/server-wallet.ts | 131 +- pnpm-lock.yaml | 30 +- 25 files changed, 3084 insertions(+), 1612 deletions(-) create mode 100644 packages/engine/src/client/client/client.ts create mode 100644 packages/engine/src/client/client/index.ts create mode 100644 packages/engine/src/client/client/types.ts create mode 100644 packages/engine/src/client/client/utils.ts create mode 100644 packages/engine/src/client/core/auth.ts create mode 100644 packages/engine/src/client/core/bodySerializer.ts create mode 100644 packages/engine/src/client/core/params.ts create mode 100644 packages/engine/src/client/core/pathSerializer.ts create mode 100644 packages/engine/src/client/core/types.ts diff --git a/packages/engine/biome.json b/packages/engine/biome.json index 780bbdcd1af..dc3633e825e 100644 --- a/packages/engine/biome.json +++ b/packages/engine/biome.json @@ -1,4 +1,17 @@ { - "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json", - "extends": "//" + "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json", + "linter": { + "rules": { + "correctness": { + "useImportExtensions": { + "fix": "safe", + "level": "error", + "options": { + "forceJsExtensions": true + } + } + } + } + }, + "root": true } diff --git a/packages/engine/openapi-ts.config.ts b/packages/engine/openapi-ts.config.ts index 053bab3fe42..b4f78bed7bf 100644 --- a/packages/engine/openapi-ts.config.ts +++ b/packages/engine/openapi-ts.config.ts @@ -2,7 +2,6 @@ import { defineConfig } from "@hey-api/openapi-ts"; export default defineConfig({ // input: "https://engine.thirdweb.com/openapi", - input: "http://localhost:3009/openapi", + input: "http://localhost:3001/openapi", output: { format: "biome", lint: "biome", path: "src/client" }, - plugins: ["@hey-api/client-fetch"], }); diff --git a/packages/engine/package.json b/packages/engine/package.json index 0a073b59c56..f50b03cb827 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -8,7 +8,7 @@ }, "devDependencies": { "@biomejs/biome": "2.0.4", - "@hey-api/openapi-ts": "0.72.1", + "@hey-api/openapi-ts": "0.77.0", "rimraf": "6.0.1", "tslib": "^2.8.1" }, @@ -47,11 +47,11 @@ "build": "pnpm clean && pnpm build:cjs && pnpm build:esm && pnpm build:types", "build:cjs": "tsc --project ./tsconfig.build.json --module commonjs --outDir ./dist/cjs --verbatimModuleSyntax false && printf '{\"type\":\"commonjs\"}' > ./dist/cjs/package.json", "build:esm": "tsc --project ./tsconfig.build.json --module es2020 --outDir ./dist/esm && printf '{\"type\": \"module\",\"sideEffects\":false}' > ./dist/esm/package.json", - "build:generate": "openapi-ts && pnpm format", + "build:generate": "openapi-ts && pnpm format && pnpm fix", "build:types": "tsc --project ./tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap", "clean": "rimraf dist", - "fix": "biome check ./src --fix", - "format": "biome format ./src --write", + "fix": "biome check --write ./src", + "format": "biome format --write ./src", "lint": "biome check ./src" }, "type": "module", diff --git a/packages/engine/src/client/client.gen.ts b/packages/engine/src/client/client.gen.ts index 926e4ae2bd0..973ee7bb3b2 100644 --- a/packages/engine/src/client/client.gen.ts +++ b/packages/engine/src/client/client.gen.ts @@ -5,7 +5,7 @@ import { createClient, createConfig, type ClientOptions as DefaultClientOptions, -} from "@hey-api/client-fetch"; +} from "./client/index.js"; import type { ClientOptions } from "./types.gen.js"; /** @@ -23,6 +23,6 @@ export type CreateClientConfig = export const client = createClient( createConfig({ - baseUrl: "http://localhost:3009", + baseUrl: "http://localhost:3001", }), ); diff --git a/packages/engine/src/client/client/client.ts b/packages/engine/src/client/client/client.ts new file mode 100644 index 00000000000..62280abd079 --- /dev/null +++ b/packages/engine/src/client/client/client.ts @@ -0,0 +1,193 @@ +import type { Client, Config, RequestOptions } from "./types.js"; +import { + buildUrl, + createConfig, + createInterceptors, + getParseAs, + mergeConfigs, + mergeHeaders, + setAuthParams, +} from "./utils.js"; + +type ReqInit = Omit & { + body?: any; + headers: ReturnType; +}; + +export const createClient = (config: Config = {}): Client => { + let _config = mergeConfigs(createConfig(), config); + + const getConfig = (): Config => ({ ..._config }); + + const setConfig = (config: Config): Config => { + _config = mergeConfigs(_config, config); + return getConfig(); + }; + + const interceptors = createInterceptors< + Request, + Response, + unknown, + RequestOptions + >(); + + const request: Client["request"] = async (options) => { + const opts = { + ..._config, + ...options, + fetch: options.fetch ?? _config.fetch ?? globalThis.fetch, + headers: mergeHeaders(_config.headers, options.headers), + }; + + if (opts.security) { + await setAuthParams({ + ...opts, + security: opts.security, + }); + } + + if (opts.requestValidator) { + await opts.requestValidator(opts); + } + + if (opts.body && opts.bodySerializer) { + opts.body = opts.bodySerializer(opts.body); + } + + // remove Content-Type header if body is empty to avoid sending invalid requests + if (opts.body === undefined || opts.body === "") { + opts.headers.delete("Content-Type"); + } + + const url = buildUrl(opts); + const requestInit: ReqInit = { + redirect: "follow", + ...opts, + }; + + let request = new Request(url, requestInit); + + for (const fn of interceptors.request._fns) { + if (fn) { + request = await fn(request, opts); + } + } + + // fetch must be assigned here, otherwise it would throw the error: + // TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation + const _fetch = opts.fetch!; + let response = await _fetch(request); + + for (const fn of interceptors.response._fns) { + if (fn) { + response = await fn(response, request, opts); + } + } + + const result = { + request, + response, + }; + + if (response.ok) { + if ( + response.status === 204 || + response.headers.get("Content-Length") === "0" + ) { + return opts.responseStyle === "data" + ? {} + : { + data: {}, + ...result, + }; + } + + const parseAs = + (opts.parseAs === "auto" + ? getParseAs(response.headers.get("Content-Type")) + : opts.parseAs) ?? "json"; + + let data: any; + switch (parseAs) { + case "arrayBuffer": + case "blob": + case "formData": + case "json": + case "text": + data = await response[parseAs](); + break; + case "stream": + return opts.responseStyle === "data" + ? response.body + : { + data: response.body, + ...result, + }; + } + + if (parseAs === "json") { + if (opts.responseValidator) { + await opts.responseValidator(data); + } + + if (opts.responseTransformer) { + data = await opts.responseTransformer(data); + } + } + + return opts.responseStyle === "data" + ? data + : { + data, + ...result, + }; + } + + let error = await response.text(); + + try { + error = JSON.parse(error); + } catch { + // noop + } + + let finalError = error; + + for (const fn of interceptors.error._fns) { + if (fn) { + finalError = (await fn(error, response, request, opts)) as string; + } + } + + finalError = finalError || ({} as string); + + if (opts.throwOnError) { + throw finalError; + } + + // TODO: we probably want to return error and improve types + return opts.responseStyle === "data" + ? undefined + : { + error: finalError, + ...result, + }; + }; + + return { + buildUrl, + connect: (options) => request({ ...options, method: "CONNECT" }), + delete: (options) => request({ ...options, method: "DELETE" }), + get: (options) => request({ ...options, method: "GET" }), + getConfig, + head: (options) => request({ ...options, method: "HEAD" }), + interceptors, + options: (options) => request({ ...options, method: "OPTIONS" }), + patch: (options) => request({ ...options, method: "PATCH" }), + post: (options) => request({ ...options, method: "POST" }), + put: (options) => request({ ...options, method: "PUT" }), + request, + setConfig, + trace: (options) => request({ ...options, method: "TRACE" }), + }; +}; diff --git a/packages/engine/src/client/client/index.ts b/packages/engine/src/client/client/index.ts new file mode 100644 index 00000000000..c0343af4092 --- /dev/null +++ b/packages/engine/src/client/client/index.ts @@ -0,0 +1,22 @@ +export type { Auth } from "../core/auth.js"; +export type { QuerySerializerOptions } from "../core/bodySerializer.js"; +export { + formDataBodySerializer, + jsonBodySerializer, + urlSearchParamsBodySerializer, +} from "../core/bodySerializer.js"; +export { buildClientParams } from "../core/params.js"; +export { createClient } from "./client.js"; +export type { + Client, + ClientOptions, + Config, + CreateClientConfig, + Options, + OptionsLegacyParser, + RequestOptions, + RequestResult, + ResponseStyle, + TDataShape, +} from "./types.js"; +export { createConfig, mergeHeaders } from "./utils.js"; diff --git a/packages/engine/src/client/client/types.ts b/packages/engine/src/client/client/types.ts new file mode 100644 index 00000000000..ef3d74fd17d --- /dev/null +++ b/packages/engine/src/client/client/types.ts @@ -0,0 +1,222 @@ +import type { Auth } from "../core/auth.js"; +import type { + Client as CoreClient, + Config as CoreConfig, +} from "../core/types.js"; +import type { Middleware } from "./utils.js"; + +export type ResponseStyle = "data" | "fields"; + +export interface Config + extends Omit, + CoreConfig { + /** + * Base URL for all requests made by this client. + */ + baseUrl?: T["baseUrl"]; + /** + * Fetch API implementation. You can use this option to provide a custom + * fetch instance. + * + * @default globalThis.fetch + */ + fetch?: (request: Request) => ReturnType; + /** + * Please don't use the Fetch client for Next.js applications. The `next` + * options won't have any effect. + * + * Install {@link https://www.npmjs.com/package/@hey-api/client-next `@hey-api/client-next`} instead. + */ + next?: never; + /** + * Return the response data parsed in a specified format. By default, `auto` + * will infer the appropriate method from the `Content-Type` response header. + * You can override this behavior with any of the {@link Body} methods. + * Select `stream` if you don't want to parse response data at all. + * + * @default 'auto' + */ + parseAs?: + | "arrayBuffer" + | "auto" + | "blob" + | "formData" + | "json" + | "stream" + | "text"; + /** + * Should we return only data or multiple fields (data, error, response, etc.)? + * + * @default 'fields' + */ + responseStyle?: ResponseStyle; + /** + * Throw an error instead of returning it in the response? + * + * @default false + */ + throwOnError?: T["throwOnError"]; +} + +export interface RequestOptions< + TResponseStyle extends ResponseStyle = "fields", + ThrowOnError extends boolean = boolean, + Url extends string = string, +> extends Config<{ + responseStyle: TResponseStyle; + throwOnError: ThrowOnError; + }> { + /** + * Any body that you want to add to your request. + * + * {@link https://developer.mozilla.org/docs/Web/API/fetch#body} + */ + body?: unknown; + path?: Record; + query?: Record; + /** + * Security mechanism(s) to use for the request. + */ + security?: ReadonlyArray; + url: Url; +} + +export type RequestResult< + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = boolean, + TResponseStyle extends ResponseStyle = "fields", +> = ThrowOnError extends true + ? Promise< + TResponseStyle extends "data" + ? TData extends Record + ? TData[keyof TData] + : TData + : { + data: TData extends Record + ? TData[keyof TData] + : TData; + request: Request; + response: Response; + } + > + : Promise< + TResponseStyle extends "data" + ? + | (TData extends Record + ? TData[keyof TData] + : TData) + | undefined + : ( + | { + data: TData extends Record + ? TData[keyof TData] + : TData; + error: undefined; + } + | { + data: undefined; + error: TError extends Record + ? TError[keyof TError] + : TError; + } + ) & { + request: Request; + response: Response; + } + >; + +export interface ClientOptions { + baseUrl?: string; + responseStyle?: ResponseStyle; + throwOnError?: boolean; +} + +type MethodFn = < + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = false, + TResponseStyle extends ResponseStyle = "fields", +>( + options: Omit, "method">, +) => RequestResult; + +type RequestFn = < + TData = unknown, + TError = unknown, + ThrowOnError extends boolean = false, + TResponseStyle extends ResponseStyle = "fields", +>( + options: Omit, "method"> & + Pick>, "method">, +) => RequestResult; + +type BuildUrlFn = < + TData extends { + body?: unknown; + path?: Record; + query?: Record; + url: string; + }, +>( + options: Pick & Options, +) => string; + +export type Client = CoreClient & { + interceptors: Middleware; +}; + +/** + * The `createClientConfig()` function will be called on client initialization + * and the returned object will become the client's initial configuration. + * + * You may want to initialize your client this way instead of calling + * `setConfig()`. This is useful for example if you're using Next.js + * to ensure your client always has the correct values. + */ +export type CreateClientConfig = ( + override?: Config, +) => Config & T>; + +export interface TDataShape { + body?: unknown; + headers?: unknown; + path?: unknown; + query?: unknown; + url: string; +} + +type OmitKeys = Pick>; + +export type Options< + TData extends TDataShape = TDataShape, + ThrowOnError extends boolean = boolean, + TResponseStyle extends ResponseStyle = "fields", +> = OmitKeys< + RequestOptions, + "body" | "path" | "query" | "url" +> & + Omit; + +export type OptionsLegacyParser< + TData = unknown, + ThrowOnError extends boolean = boolean, + TResponseStyle extends ResponseStyle = "fields", +> = TData extends { body?: any } + ? TData extends { headers?: any } + ? OmitKeys< + RequestOptions, + "body" | "headers" | "url" + > & + TData + : OmitKeys, "body" | "url"> & + TData & + Pick, "headers"> + : TData extends { headers?: any } + ? OmitKeys< + RequestOptions, + "headers" | "url" + > & + TData & + Pick, "body"> + : OmitKeys, "url"> & TData; diff --git a/packages/engine/src/client/client/utils.ts b/packages/engine/src/client/client/utils.ts new file mode 100644 index 00000000000..2b5bb778117 --- /dev/null +++ b/packages/engine/src/client/client/utils.ts @@ -0,0 +1,417 @@ +import { getAuthToken } from "../core/auth.js"; +import type { + QuerySerializer, + QuerySerializerOptions, +} from "../core/bodySerializer.js"; +import { jsonBodySerializer } from "../core/bodySerializer.js"; +import { + serializeArrayParam, + serializeObjectParam, + serializePrimitiveParam, +} from "../core/pathSerializer.js"; +import type { Client, ClientOptions, Config, RequestOptions } from "./types.js"; + +interface PathSerializer { + path: Record; + url: string; +} + +const PATH_PARAM_RE = /\{[^{}]+\}/g; + +type ArrayStyle = "form" | "spaceDelimited" | "pipeDelimited"; +type MatrixStyle = "label" | "matrix" | "simple"; +type ArraySeparatorStyle = ArrayStyle | MatrixStyle; + +const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => { + let url = _url; + const matches = _url.match(PATH_PARAM_RE); + if (matches) { + for (const match of matches) { + let explode = false; + let name = match.substring(1, match.length - 1); + let style: ArraySeparatorStyle = "simple"; + + if (name.endsWith("*")) { + explode = true; + name = name.substring(0, name.length - 1); + } + + if (name.startsWith(".")) { + name = name.substring(1); + style = "label"; + } else if (name.startsWith(";")) { + name = name.substring(1); + style = "matrix"; + } + + const value = path[name]; + + if (value === undefined || value === null) { + continue; + } + + if (Array.isArray(value)) { + url = url.replace( + match, + serializeArrayParam({ explode, name, style, value }), + ); + continue; + } + + if (typeof value === "object") { + url = url.replace( + match, + serializeObjectParam({ + explode, + name, + style, + value: value as Record, + valueOnly: true, + }), + ); + continue; + } + + if (style === "matrix") { + url = url.replace( + match, + `;${serializePrimitiveParam({ + name, + value: value as string, + })}`, + ); + continue; + } + + const replaceValue = encodeURIComponent( + style === "label" ? `.${value as string}` : (value as string), + ); + url = url.replace(match, replaceValue); + } + } + return url; +}; + +export const createQuerySerializer = ({ + allowReserved, + array, + object, +}: QuerySerializerOptions = {}) => { + const querySerializer = (queryParams: T) => { + const search: string[] = []; + if (queryParams && typeof queryParams === "object") { + for (const name in queryParams) { + const value = queryParams[name]; + + if (value === undefined || value === null) { + continue; + } + + if (Array.isArray(value)) { + const serializedArray = serializeArrayParam({ + allowReserved, + explode: true, + name, + style: "form", + value, + ...array, + }); + if (serializedArray) search.push(serializedArray); + } else if (typeof value === "object") { + const serializedObject = serializeObjectParam({ + allowReserved, + explode: true, + name, + style: "deepObject", + value: value as Record, + ...object, + }); + if (serializedObject) search.push(serializedObject); + } else { + const serializedPrimitive = serializePrimitiveParam({ + allowReserved, + name, + value: value as string, + }); + if (serializedPrimitive) search.push(serializedPrimitive); + } + } + } + return search.join("&"); + }; + return querySerializer; +}; + +/** + * Infers parseAs value from provided Content-Type header. + */ +export const getParseAs = ( + contentType: string | null, +): Exclude => { + if (!contentType) { + // If no Content-Type header is provided, the best we can do is return the raw response body, + // which is effectively the same as the 'stream' option. + return "stream"; + } + + const cleanContent = contentType.split(";")[0]?.trim(); + + if (!cleanContent) { + return; + } + + if ( + cleanContent.startsWith("application/json") || + cleanContent.endsWith("+json") + ) { + return "json"; + } + + if (cleanContent === "multipart/form-data") { + return "formData"; + } + + if ( + ["application/", "audio/", "image/", "video/"].some((type) => + cleanContent.startsWith(type), + ) + ) { + return "blob"; + } + + if (cleanContent.startsWith("text/")) { + return "text"; + } + + return; +}; + +export const setAuthParams = async ({ + security, + ...options +}: Pick, "security"> & + Pick & { + headers: Headers; + }) => { + for (const auth of security) { + const token = await getAuthToken(auth, options.auth); + + if (!token) { + continue; + } + + const name = auth.name ?? "Authorization"; + + switch (auth.in) { + case "query": + if (!options.query) { + options.query = {}; + } + options.query[name] = token; + break; + case "cookie": + options.headers.append("Cookie", `${name}=${token}`); + break; + case "header": + default: + options.headers.set(name, token); + break; + } + + return; + } +}; + +export const buildUrl: Client["buildUrl"] = (options) => { + const url = getUrl({ + baseUrl: options.baseUrl as string, + path: options.path, + query: options.query, + querySerializer: + typeof options.querySerializer === "function" + ? options.querySerializer + : createQuerySerializer(options.querySerializer), + url: options.url, + }); + return url; +}; + +export const getUrl = ({ + baseUrl, + path, + query, + querySerializer, + url: _url, +}: { + baseUrl?: string; + path?: Record; + query?: Record; + querySerializer: QuerySerializer; + url: string; +}) => { + const pathUrl = _url.startsWith("/") ? _url : `/${_url}`; + let url = (baseUrl ?? "") + pathUrl; + if (path) { + url = defaultPathSerializer({ path, url }); + } + let search = query ? querySerializer(query) : ""; + if (search.startsWith("?")) { + search = search.substring(1); + } + if (search) { + url += `?${search}`; + } + return url; +}; + +export const mergeConfigs = (a: Config, b: Config): Config => { + const config = { ...a, ...b }; + if (config.baseUrl?.endsWith("/")) { + config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1); + } + config.headers = mergeHeaders(a.headers, b.headers); + return config; +}; + +export const mergeHeaders = ( + ...headers: Array["headers"] | undefined> +): Headers => { + const mergedHeaders = new Headers(); + for (const header of headers) { + if (!header || typeof header !== "object") { + continue; + } + + const iterator = + header instanceof Headers ? header.entries() : Object.entries(header); + + for (const [key, value] of iterator) { + if (value === null) { + mergedHeaders.delete(key); + } else if (Array.isArray(value)) { + for (const v of value) { + mergedHeaders.append(key, v as string); + } + } else if (value !== undefined) { + // assume object headers are meant to be JSON stringified, i.e. their + // content value in OpenAPI specification is 'application/json' + mergedHeaders.set( + key, + typeof value === "object" ? JSON.stringify(value) : (value as string), + ); + } + } + } + return mergedHeaders; +}; + +type ErrInterceptor = ( + error: Err, + response: Res, + request: Req, + options: Options, +) => Err | Promise; + +type ReqInterceptor = ( + request: Req, + options: Options, +) => Req | Promise; + +type ResInterceptor = ( + response: Res, + request: Req, + options: Options, +) => Res | Promise; + +class Interceptors { + _fns: (Interceptor | null)[]; + + constructor() { + this._fns = []; + } + + clear() { + this._fns = []; + } + + getInterceptorIndex(id: number | Interceptor): number { + if (typeof id === "number") { + return this._fns[id] ? id : -1; + } else { + return this._fns.indexOf(id); + } + } + exists(id: number | Interceptor) { + const index = this.getInterceptorIndex(id); + return !!this._fns[index]; + } + + eject(id: number | Interceptor) { + const index = this.getInterceptorIndex(id); + if (this._fns[index]) { + this._fns[index] = null; + } + } + + update(id: number | Interceptor, fn: Interceptor) { + const index = this.getInterceptorIndex(id); + if (this._fns[index]) { + this._fns[index] = fn; + return id; + } else { + return false; + } + } + + use(fn: Interceptor) { + this._fns = [...this._fns, fn]; + return this._fns.length - 1; + } +} + +// `createInterceptors()` response, meant for external use as it does not +// expose internals +export interface Middleware { + error: Pick< + Interceptors>, + "eject" | "use" + >; + request: Pick>, "eject" | "use">; + response: Pick< + Interceptors>, + "eject" | "use" + >; +} + +// do not add `Middleware` as return type so we can use _fns internally +export const createInterceptors = () => ({ + error: new Interceptors>(), + request: new Interceptors>(), + response: new Interceptors>(), +}); + +const defaultQuerySerializer = createQuerySerializer({ + allowReserved: false, + array: { + explode: true, + style: "form", + }, + object: { + explode: true, + style: "deepObject", + }, +}); + +const defaultHeaders = { + "Content-Type": "application/json", +}; + +export const createConfig = ( + override: Config & T> = {}, +): Config & T> => ({ + ...jsonBodySerializer, + headers: defaultHeaders, + parseAs: "auto", + querySerializer: defaultQuerySerializer, + ...override, +}); diff --git a/packages/engine/src/client/core/auth.ts b/packages/engine/src/client/core/auth.ts new file mode 100644 index 00000000000..f9012011fc2 --- /dev/null +++ b/packages/engine/src/client/core/auth.ts @@ -0,0 +1,40 @@ +export type AuthToken = string | undefined; + +export interface Auth { + /** + * Which part of the request do we use to send the auth? + * + * @default 'header' + */ + in?: "header" | "query" | "cookie"; + /** + * Header or query parameter name. + * + * @default 'Authorization' + */ + name?: string; + scheme?: "basic" | "bearer"; + type: "apiKey" | "http"; +} + +export const getAuthToken = async ( + auth: Auth, + callback: ((auth: Auth) => Promise | AuthToken) | AuthToken, +): Promise => { + const token = + typeof callback === "function" ? await callback(auth) : callback; + + if (!token) { + return; + } + + if (auth.scheme === "bearer") { + return `Bearer ${token}`; + } + + if (auth.scheme === "basic") { + return `Basic ${btoa(token)}`; + } + + return token; +}; diff --git a/packages/engine/src/client/core/bodySerializer.ts b/packages/engine/src/client/core/bodySerializer.ts new file mode 100644 index 00000000000..7d254a96ebe --- /dev/null +++ b/packages/engine/src/client/core/bodySerializer.ts @@ -0,0 +1,84 @@ +import type { + ArrayStyle, + ObjectStyle, + SerializerOptions, +} from "./pathSerializer.js"; + +export type QuerySerializer = (query: Record) => string; + +export type BodySerializer = (body: any) => any; + +export interface QuerySerializerOptions { + allowReserved?: boolean; + array?: SerializerOptions; + object?: SerializerOptions; +} + +const serializeFormDataPair = (data: FormData, key: string, value: unknown) => { + if (typeof value === "string" || value instanceof Blob) { + data.append(key, value); + } else { + data.append(key, JSON.stringify(value)); + } +}; + +const serializeUrlSearchParamsPair = ( + data: URLSearchParams, + key: string, + value: unknown, +) => { + if (typeof value === "string") { + data.append(key, value); + } else { + data.append(key, JSON.stringify(value)); + } +}; + +export const formDataBodySerializer = { + bodySerializer: | Array>>( + body: T, + ) => { + const data = new FormData(); + + Object.entries(body).forEach(([key, value]) => { + if (value === undefined || value === null) { + return; + } + if (Array.isArray(value)) { + value.forEach((v) => serializeFormDataPair(data, key, v)); + } else { + serializeFormDataPair(data, key, value); + } + }); + + return data; + }, +}; + +export const jsonBodySerializer = { + bodySerializer: (body: T) => + JSON.stringify(body, (_key, value) => + typeof value === "bigint" ? value.toString() : value, + ), +}; + +export const urlSearchParamsBodySerializer = { + bodySerializer: | Array>>( + body: T, + ) => { + const data = new URLSearchParams(); + + Object.entries(body).forEach(([key, value]) => { + if (value === undefined || value === null) { + return; + } + if (Array.isArray(value)) { + value.forEach((v) => serializeUrlSearchParamsPair(data, key, v)); + } else { + serializeUrlSearchParamsPair(data, key, value); + } + }); + + return data.toString(); + }, +}; diff --git a/packages/engine/src/client/core/params.ts b/packages/engine/src/client/core/params.ts new file mode 100644 index 00000000000..2b3490369bc --- /dev/null +++ b/packages/engine/src/client/core/params.ts @@ -0,0 +1,141 @@ +type Slot = "body" | "headers" | "path" | "query"; + +export type Field = + | { + in: Exclude; + key: string; + map?: string; + } + | { + in: Extract; + key?: string; + map?: string; + }; + +export interface Fields { + allowExtra?: Partial>; + args?: ReadonlyArray; +} + +export type FieldsConfig = ReadonlyArray; + +const extraPrefixesMap: Record = { + $body_: "body", + $headers_: "headers", + $path_: "path", + $query_: "query", +}; +const extraPrefixes = Object.entries(extraPrefixesMap); + +type KeyMap = Map< + string, + { + in: Slot; + map?: string; + } +>; + +const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => { + if (!map) { + map = new Map(); + } + + for (const config of fields) { + if ("in" in config) { + if (config.key) { + map.set(config.key, { + in: config.in, + map: config.map, + }); + } + } else if (config.args) { + buildKeyMap(config.args, map); + } + } + + return map; +}; + +interface Params { + body: unknown; + headers: Record; + path: Record; + query: Record; +} + +const stripEmptySlots = (params: Params) => { + for (const [slot, value] of Object.entries(params)) { + if (value && typeof value === "object" && !Object.keys(value).length) { + delete params[slot as Slot]; + } + } +}; + +export const buildClientParams = ( + args: ReadonlyArray, + fields: FieldsConfig, +) => { + const params: Params = { + body: {}, + headers: {}, + path: {}, + query: {}, + }; + + const map = buildKeyMap(fields); + + let config: FieldsConfig[number] | undefined; + + for (const [index, arg] of args.entries()) { + if (fields[index]) { + config = fields[index]; + } + + if (!config) { + continue; + } + + if ("in" in config) { + if (config.key) { + const field = map.get(config.key)!; + const name = field.map || config.key; + (params[field.in] as Record)[name] = arg; + } else { + params.body = arg; + } + } else { + for (const [key, value] of Object.entries(arg ?? {})) { + const field = map.get(key); + + if (field) { + const name = field.map || key; + (params[field.in] as Record)[name] = value; + } else { + const extra = extraPrefixes.find(([prefix]) => + key.startsWith(prefix), + ); + + if (extra) { + const [prefix, slot] = extra; + (params[slot] as Record)[ + key.slice(prefix.length) + ] = value; + } else { + for (const [slot, allowed] of Object.entries( + config.allowExtra ?? {}, + )) { + if (allowed) { + (params[slot as Slot] as Record)[key] = value; + break; + } + } + } + } + } + } + } + + stripEmptySlots(params); + + return params; +}; diff --git a/packages/engine/src/client/core/pathSerializer.ts b/packages/engine/src/client/core/pathSerializer.ts new file mode 100644 index 00000000000..2f5d1bf4148 --- /dev/null +++ b/packages/engine/src/client/core/pathSerializer.ts @@ -0,0 +1,179 @@ +interface SerializeOptions + extends SerializePrimitiveOptions, + SerializerOptions {} + +interface SerializePrimitiveOptions { + allowReserved?: boolean; + name: string; +} + +export interface SerializerOptions { + /** + * @default true + */ + explode: boolean; + style: T; +} + +export type ArrayStyle = "form" | "spaceDelimited" | "pipeDelimited"; +export type ArraySeparatorStyle = ArrayStyle | MatrixStyle; +type MatrixStyle = "label" | "matrix" | "simple"; +export type ObjectStyle = "form" | "deepObject"; +type ObjectSeparatorStyle = ObjectStyle | MatrixStyle; + +interface SerializePrimitiveParam extends SerializePrimitiveOptions { + value: string; +} + +export const separatorArrayExplode = (style: ArraySeparatorStyle) => { + switch (style) { + case "label": + return "."; + case "matrix": + return ";"; + case "simple": + return ","; + default: + return "&"; + } +}; + +export const separatorArrayNoExplode = (style: ArraySeparatorStyle) => { + switch (style) { + case "form": + return ","; + case "pipeDelimited": + return "|"; + case "spaceDelimited": + return "%20"; + default: + return ","; + } +}; + +export const separatorObjectExplode = (style: ObjectSeparatorStyle) => { + switch (style) { + case "label": + return "."; + case "matrix": + return ";"; + case "simple": + return ","; + default: + return "&"; + } +}; + +export const serializeArrayParam = ({ + allowReserved, + explode, + name, + style, + value, +}: SerializeOptions & { + value: unknown[]; +}) => { + if (!explode) { + const joinedValues = ( + allowReserved ? value : value.map((v) => encodeURIComponent(v as string)) + ).join(separatorArrayNoExplode(style)); + switch (style) { + case "label": + return `.${joinedValues}`; + case "matrix": + return `;${name}=${joinedValues}`; + case "simple": + return joinedValues; + default: + return `${name}=${joinedValues}`; + } + } + + const separator = separatorArrayExplode(style); + const joinedValues = value + .map((v) => { + if (style === "label" || style === "simple") { + return allowReserved ? v : encodeURIComponent(v as string); + } + + return serializePrimitiveParam({ + allowReserved, + name, + value: v as string, + }); + }) + .join(separator); + return style === "label" || style === "matrix" + ? separator + joinedValues + : joinedValues; +}; + +export const serializePrimitiveParam = ({ + allowReserved, + name, + value, +}: SerializePrimitiveParam) => { + if (value === undefined || value === null) { + return ""; + } + + if (typeof value === "object") { + throw new Error( + "Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.", + ); + } + + return `${name}=${allowReserved ? value : encodeURIComponent(value)}`; +}; + +export const serializeObjectParam = ({ + allowReserved, + explode, + name, + style, + value, + valueOnly, +}: SerializeOptions & { + value: Record | Date; + valueOnly?: boolean; +}) => { + if (value instanceof Date) { + return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`; + } + + if (style !== "deepObject" && !explode) { + let values: string[] = []; + Object.entries(value).forEach(([key, v]) => { + values = [ + ...values, + key, + allowReserved ? (v as string) : encodeURIComponent(v as string), + ]; + }); + const joinedValues = values.join(","); + switch (style) { + case "form": + return `${name}=${joinedValues}`; + case "label": + return `.${joinedValues}`; + case "matrix": + return `;${name}=${joinedValues}`; + default: + return joinedValues; + } + } + + const separator = separatorObjectExplode(style); + const joinedValues = Object.entries(value) + .map(([key, v]) => + serializePrimitiveParam({ + allowReserved, + name: style === "deepObject" ? `${name}[${key}]` : key, + value: v as string, + }), + ) + .join(separator); + return style === "label" || style === "matrix" + ? separator + joinedValues + : joinedValues; +}; diff --git a/packages/engine/src/client/core/types.ts b/packages/engine/src/client/core/types.ts new file mode 100644 index 00000000000..dfa9e32739b --- /dev/null +++ b/packages/engine/src/client/core/types.ts @@ -0,0 +1,104 @@ +import type { Auth, AuthToken } from "./auth.js"; +import type { + BodySerializer, + QuerySerializer, + QuerySerializerOptions, +} from "./bodySerializer.js"; + +export interface Client< + RequestFn = never, + Config = unknown, + MethodFn = never, + BuildUrlFn = never, +> { + /** + * Returns the final request URL. + */ + buildUrl: BuildUrlFn; + connect: MethodFn; + delete: MethodFn; + get: MethodFn; + getConfig: () => Config; + head: MethodFn; + options: MethodFn; + patch: MethodFn; + post: MethodFn; + put: MethodFn; + request: RequestFn; + setConfig: (config: Config) => Config; + trace: MethodFn; +} + +export interface Config { + /** + * Auth token or a function returning auth token. The resolved value will be + * added to the request payload as defined by its `security` array. + */ + auth?: ((auth: Auth) => Promise | AuthToken) | AuthToken; + /** + * A function for serializing request body parameter. By default, + * {@link JSON.stringify()} will be used. + */ + bodySerializer?: BodySerializer | null; + /** + * An object containing any HTTP headers that you want to pre-populate your + * `Headers` object with. + * + * {@link https://developer.mozilla.org/docs/Web/API/Headers/Headers#init See more} + */ + headers?: + | RequestInit["headers"] + | Record< + string, + | string + | number + | boolean + | (string | number | boolean)[] + | null + | undefined + | unknown + >; + /** + * The request method. + * + * {@link https://developer.mozilla.org/docs/Web/API/fetch#method See more} + */ + method?: + | "CONNECT" + | "DELETE" + | "GET" + | "HEAD" + | "OPTIONS" + | "PATCH" + | "POST" + | "PUT" + | "TRACE"; + /** + * A function for serializing request query parameters. By default, arrays + * will be exploded in form style, objects will be exploded in deepObject + * style, and reserved characters are percent-encoded. + * + * This method will have no effect if the native `paramsSerializer()` Axios + * API function is used. + * + * {@link https://swagger.io/docs/specification/serialization/#query View examples} + */ + querySerializer?: QuerySerializer | QuerySerializerOptions; + /** + * A function validating request data. This is useful if you want to ensure + * the request conforms to the desired shape, so it can be safely sent to + * the server. + */ + requestValidator?: (data: unknown) => Promise; + /** + * A function transforming response data before it's returned. This is useful + * for post-processing data, e.g. converting ISO strings into Date objects. + */ + responseTransformer?: (data: unknown) => Promise; + /** + * A function validating response data. This is useful if you want to ensure + * the response conforms to the desired shape, so it can be safely passed to + * the transformers and returned to the user. + */ + responseValidator?: (data: unknown) => Promise; +} diff --git a/packages/engine/src/client/sdk.gen.ts b/packages/engine/src/client/sdk.gen.ts index 6f56a6344be..d5d63f1a4b4 100644 --- a/packages/engine/src/client/sdk.gen.ts +++ b/packages/engine/src/client/sdk.gen.ts @@ -4,9 +4,11 @@ import type { Client, Options as ClientOptions, TDataShape, -} from "@hey-api/client-fetch"; +} from "./client/index.js"; import { client as _heyApiClient } from "./client.gen.js"; import type { + CancelTransactionData, + CancelTransactionResponses, CreateAccountData, CreateAccountResponses, EncodeContractData, @@ -30,14 +32,14 @@ import type { SearchActivityLogsResponses, SearchTransactionsData, SearchTransactionsResponses, + SendTransactionData, + SendTransactionResponses, SignMessageData, SignMessageResponses, SignTypedDataData, SignTypedDataResponses, WriteContractData, WriteContractResponses, - WriteTransactionData, - WriteTransactionResponses, } from "./types.gen.js"; export type Options< @@ -58,14 +60,14 @@ export type Options< }; /** - * List Server Wallets - * List all engine server wallets for the current project. Returns an array of EOA addresses with their corresponding predicted smart account addresses. + * Write Contract + * Call a contract function with a transaction */ -export const listAccounts = ( - options?: Options, +export const writeContract = ( + options: Options, ) => { - return (options?.client ?? _heyApiClient).get< - ListAccountsResponses, + return (options.client ?? _heyApiClient).post< + WriteContractResponses, unknown, ThrowOnError >({ @@ -75,20 +77,24 @@ export const listAccounts = ( type: "apiKey", }, ], - url: "/v1/accounts", + url: "/v1/write/contract", ...options, + headers: { + "Content-Type": "application/json", + ...options.headers, + }, }); }; /** - * Create Server Wallet - * Create a new engine server wallet. This is a helper route for creating a new EOA with your KMS provider, provided as a convenient alternative to creating an EOA directly with your KMS provider. Your KMS credentials are not stored, and usage of created accounts require your KMS credentials to be sent with requests. + * Write Transaction + * Execute raw transactions */ -export const createAccount = ( - options?: Options, +export const sendTransaction = ( + options: Options, ) => { - return (options?.client ?? _heyApiClient).post< - CreateAccountResponses, + return (options.client ?? _heyApiClient).post< + SendTransactionResponses, unknown, ThrowOnError >({ @@ -98,24 +104,24 @@ export const createAccount = ( type: "apiKey", }, ], - url: "/v1/accounts", + url: "/v1/write/transaction", ...options, headers: { "Content-Type": "application/json", - ...options?.headers, + ...options.headers, }, }); }; /** - * Get Transactions - * Search transactions with various filters and pagination + * Sign Message + * Sign messages using either EOA or Smart Account */ -export const getTransactions = ( - options?: Options, +export const signMessage = ( + options: Options, ) => { - return (options?.client ?? _heyApiClient).get< - GetTransactionsResponses, + return (options.client ?? _heyApiClient).post< + SignMessageResponses, unknown, ThrowOnError >({ @@ -125,20 +131,24 @@ export const getTransactions = ( type: "apiKey", }, ], - url: "/v1/transactions", + url: "/v1/sign/message", ...options, + headers: { + "Content-Type": "application/json", + ...options.headers, + }, }); }; /** - * Transaction Analytics - * Get transaction count analytics over time with filtering + * Sign Typed Data + * Sign EIP-712 typed data using either EOA or Smart Account */ -export const getTransactionAnalytics = ( - options?: Options, +export const signTypedData = ( + options: Options, ) => { - return (options?.client ?? _heyApiClient).post< - GetTransactionAnalyticsResponses, + return (options.client ?? _heyApiClient).post< + SignTypedDataResponses, unknown, ThrowOnError >({ @@ -148,27 +158,25 @@ export const getTransactionAnalytics = ( type: "apiKey", }, ], - url: "/v1/transactions/analytics", + url: "/v1/sign/typed-data", ...options, headers: { "Content-Type": "application/json", - ...options?.headers, + ...options.headers, }, }); }; /** - * Transaction Analytics Summary - * Get a summary (total count and total gas calculation) for transactions within a time range, supporting complex nested filters. + * Read Contract + * Read from multiple smart contracts using multicall */ -export const getTransactionAnalyticsSummary = < - ThrowOnError extends boolean = false, ->( - options?: Options, +export const readContract = ( + options: Options, ) => { - return (options?.client ?? _heyApiClient).post< - GetTransactionAnalyticsSummaryResponses, - GetTransactionAnalyticsSummaryErrors, + return (options.client ?? _heyApiClient).post< + ReadContractResponses, + unknown, ThrowOnError >({ security: [ @@ -177,24 +185,24 @@ export const getTransactionAnalyticsSummary = < type: "apiKey", }, ], - url: "/v1/transactions/analytics-summary", + url: "/v1/read/contract", ...options, headers: { "Content-Type": "application/json", - ...options?.headers, + ...options.headers, }, }); }; /** - * Search Transactions - * Advanced search for transactions with complex nested filters + * Encode Contract + * Encode contract function calls without execution */ -export const searchTransactions = ( - options?: Options, +export const encodeContract = ( + options: Options, ) => { - return (options?.client ?? _heyApiClient).post< - SearchTransactionsResponses, + return (options.client ?? _heyApiClient).post< + EncodeContractResponses, unknown, ThrowOnError >({ @@ -204,25 +212,25 @@ export const searchTransactions = ( type: "apiKey", }, ], - url: "/v1/transactions/search", + url: "/v1/encode/contract", ...options, headers: { "Content-Type": "application/json", - ...options?.headers, + ...options.headers, }, }); }; /** - * Get Activity Logs - * Get paginated activity logs for a specific transaction with tenancy enforcement + * Cancel Transaction + * Attempt to cancel a queued transaction. Transactions that have been sent and are waiting for mine cannot be cancelled. */ -export const getActivityLogs = ( - options: Options, +export const cancelTransaction = ( + options: Options, ) => { - return (options.client ?? _heyApiClient).get< - GetActivityLogsResponses, - GetActivityLogsErrors, + return (options.client ?? _heyApiClient).post< + CancelTransactionResponses, + unknown, ThrowOnError >({ security: [ @@ -231,21 +239,44 @@ export const getActivityLogs = ( type: "apiKey", }, ], - url: "/v1/transactions/activity-logs", + url: "/v1/transactions/{id}/cancel", ...options, }); }; /** - * Search Activity Logs - * Search activity logs across transactions with advanced filtering and tenancy enforcement + * List Server Wallets + * List all engine server wallets for the current project. Returns an array of EOA addresses with their corresponding predicted smart account addresses. */ -export const searchActivityLogs = ( - options?: Options, +export const listAccounts = ( + options?: Options, +) => { + return (options?.client ?? _heyApiClient).get< + ListAccountsResponses, + unknown, + ThrowOnError + >({ + security: [ + { + name: "x-secret-key", + type: "apiKey", + }, + ], + url: "/v1/accounts", + ...options, + }); +}; + +/** + * Create Server Wallet + * Create a new engine server wallet. This is a helper route for creating a new EOA with your KMS provider, provided as a convenient alternative to creating an EOA directly with your KMS provider. Your KMS credentials are not stored, and usage of created accounts require your KMS credentials to be sent with requests. + */ +export const createAccount = ( + options?: Options, ) => { return (options?.client ?? _heyApiClient).post< - SearchActivityLogsResponses, - SearchActivityLogsErrors, + CreateAccountResponses, + unknown, ThrowOnError >({ security: [ @@ -254,7 +285,7 @@ export const searchActivityLogs = ( type: "apiKey", }, ], - url: "/v1/transactions/activity-logs/search", + url: "/v1/accounts", ...options, headers: { "Content-Type": "application/json", @@ -264,14 +295,14 @@ export const searchActivityLogs = ( }; /** - * Write Contract - * Call a contract function with a transaction + * Get Transactions + * Search transactions with various filters and pagination */ -export const writeContract = ( - options: Options, +export const getTransactions = ( + options?: Options, ) => { - return (options.client ?? _heyApiClient).post< - WriteContractResponses, + return (options?.client ?? _heyApiClient).get< + GetTransactionsResponses, unknown, ThrowOnError >({ @@ -281,24 +312,20 @@ export const writeContract = ( type: "apiKey", }, ], - url: "/v1/write/contract", + url: "/v1/transactions", ...options, - headers: { - "Content-Type": "application/json", - ...options.headers, - }, }); }; /** - * Write Transaction - * Execute raw transactions + * Transaction Analytics + * Get transaction count analytics over time with filtering */ -export const writeTransaction = ( - options: Options, +export const getTransactionAnalytics = ( + options?: Options, ) => { - return (options.client ?? _heyApiClient).post< - WriteTransactionResponses, + return (options?.client ?? _heyApiClient).post< + GetTransactionAnalyticsResponses, unknown, ThrowOnError >({ @@ -308,25 +335,27 @@ export const writeTransaction = ( type: "apiKey", }, ], - url: "/v1/write/transaction", + url: "/v1/transactions/analytics", ...options, headers: { "Content-Type": "application/json", - ...options.headers, + ...options?.headers, }, }); }; /** - * Sign Message - * Sign messages using either EOA or Smart Account + * Transaction Analytics Summary + * Get a summary (total count and total gas calculation) for transactions within a time range, supporting complex nested filters. */ -export const signMessage = ( - options: Options, +export const getTransactionAnalyticsSummary = < + ThrowOnError extends boolean = false, +>( + options?: Options, ) => { - return (options.client ?? _heyApiClient).post< - SignMessageResponses, - unknown, + return (options?.client ?? _heyApiClient).post< + GetTransactionAnalyticsSummaryResponses, + GetTransactionAnalyticsSummaryErrors, ThrowOnError >({ security: [ @@ -335,24 +364,24 @@ export const signMessage = ( type: "apiKey", }, ], - url: "/v1/sign/message", + url: "/v1/transactions/analytics-summary", ...options, headers: { "Content-Type": "application/json", - ...options.headers, + ...options?.headers, }, }); }; /** - * Sign Typed Data - * Sign EIP-712 typed data using either EOA or Smart Account + * Search Transactions + * Advanced search for transactions with complex nested filters */ -export const signTypedData = ( - options: Options, +export const searchTransactions = ( + options?: Options, ) => { - return (options.client ?? _heyApiClient).post< - SignTypedDataResponses, + return (options?.client ?? _heyApiClient).post< + SearchTransactionsResponses, unknown, ThrowOnError >({ @@ -362,25 +391,25 @@ export const signTypedData = ( type: "apiKey", }, ], - url: "/v1/sign/typed-data", + url: "/v1/transactions/search", ...options, headers: { "Content-Type": "application/json", - ...options.headers, + ...options?.headers, }, }); }; /** - * Read Contract - * Read from multiple smart contracts using multicall + * Get Activity Logs + * Get paginated activity logs for a specific transaction with tenancy enforcement */ -export const readContract = ( - options: Options, +export const getActivityLogs = ( + options: Options, ) => { - return (options.client ?? _heyApiClient).post< - ReadContractResponses, - unknown, + return (options.client ?? _heyApiClient).get< + GetActivityLogsResponses, + GetActivityLogsErrors, ThrowOnError >({ security: [ @@ -389,25 +418,21 @@ export const readContract = ( type: "apiKey", }, ], - url: "/v1/read/contract", + url: "/v1/transactions/activity-logs", ...options, - headers: { - "Content-Type": "application/json", - ...options.headers, - }, }); }; /** - * Encode Contract - * Encode contract function calls without execution + * Search Activity Logs + * Search activity logs across transactions with advanced filtering and tenancy enforcement */ -export const encodeContract = ( - options: Options, +export const searchActivityLogs = ( + options?: Options, ) => { - return (options.client ?? _heyApiClient).post< - EncodeContractResponses, - unknown, + return (options?.client ?? _heyApiClient).post< + SearchActivityLogsResponses, + SearchActivityLogsErrors, ThrowOnError >({ security: [ @@ -416,11 +441,11 @@ export const encodeContract = ( type: "apiKey", }, ], - url: "/v1/encode/contract", + url: "/v1/transactions/activity-logs/search", ...options, headers: { "Content-Type": "application/json", - ...options.headers, + ...options?.headers, }, }); }; diff --git a/packages/engine/src/client/types.gen.ts b/packages/engine/src/client/types.gen.ts index 45ab8c7c8d0..c94c4b94b96 100644 --- a/packages/engine/src/client/types.gen.ts +++ b/packages/engine/src/client/types.gen.ts @@ -1,20 +1,20 @@ // This file is auto-generated by @hey-api/openapi-ts export type TransactionsFilterValue = { - field: - | "id" - | "batchIndex" - | "from" - | "signerAddress" - | "smartAccountAddress" - | "chainId"; - values: Array; - operation: "AND" | "OR"; + field: + | "id" + | "batchIndex" + | "from" + | "signerAddress" + | "smartAccountAddress" + | "chainId"; + values: Array; + operation: "AND" | "OR"; }; export type TransactionsFilterNested = { - operation: "AND" | "OR"; - filters: Array; + operation: "AND" | "OR"; + filters: Array; }; /** @@ -23,11 +23,6 @@ export type TransactionsFilterNested = { */ export type AddressDef = string; -/** - * Extension trait for EngineError to add HTTP response conversion - */ -export type ApiEngineError = EngineError; - /** * Auto Determine Execution * This is the default execution option. @@ -37,21 +32,299 @@ export type ApiEngineError = EngineError; * choose one of the other executionOptions type and provide them. */ export type AutoExecutionOptions = { - /** - * The identifier of the entity to send the transaction from. - * Automatically picks best execution strategy based on the identifier. - * - If EOA address, execution uses EIP7702 based smart-wallet execution - * - If 7702 not supported on chain, falls back to smart-contract wallet (ERC4337) with default smart account for this EOA (v0.7) - * - UNLESS this is a zk-chain, in which case, zk-sync native-aa is used - */ - from: string; + /** + * The identifier of the entity to send the transaction from. + * Automatically picks best execution strategy based on the identifier. + * - If EOA address, execution uses EIP7702 based smart-wallet execution + * - If 7702 not supported on chain, falls back to smart-contract wallet (ERC4337) with default smart account for this EOA (v0.7) + * - UNLESS this is a zk-chain, in which case, zk-sync native-aa is used + */ + from: string; }; export type BaseExecutionOptions = { - chainId: number; - idempotencyKey?: string; + chainId: number; + idempotencyKey?: string; }; +/** + * Result of a single contract encode operation + * + * Each result can either be successful (containing the encoded transaction data) + * or failed (containing detailed error information). + */ +export type BatchResultItemEncodeResultSuccessItemEngineError = + | { + /** + * Successful result from a contract encode operation + */ + result: { + /** + * The contract address that would be called + */ + target: string; + /** + * The encoded function call data + * + * This includes the function selector and encoded parameters, + * ready to be used in a transaction + */ + callData: string; + /** + * The 4-byte function selector (first 4 bytes of call_data) + */ + functionSelector: string; + /** + * The name of the function being called + */ + functionName: string; + }; + } + | { + error: + | { + /** + * Detailed RPC error information + */ + chain_id: number; + rpc_url: string; + message: string; + kind: RpcErrorKind; + type: "RPC_ERROR"; + } + | { + /** + * Detailed RPC error information + */ + chain_id: number; + rpc_url: string; + message: string; + kind: RpcErrorKind; + type: "PAYMASTER_ERROR"; + } + | { + /** + * Detailed RPC error information + */ + chain_id: number; + rpc_url: string; + message: string; + kind: RpcErrorKind; + type: "BUNDLER_ERROR"; + } + | { + message: string; + type: "VAULT_ERROR"; + } + | { + message: string; + type: "RPC_CONFIG_ERROR"; + } + | { + contract_address?: null | AddressDef; + /** + * Chain ID + */ + chain_id: number; + /** + * Human-readable error message + */ + message: string; + /** + * Specific error kind + */ + kind: ContractInteractionErrorKind; + type: "CONTRACT_INTERACTION_ERROR"; + } + | { + message: string; + type: "VALIDATION_ERROR"; + } + | { + message: string; + type: "THIRDWEB_ERROR"; + } + | { + message: string; + type: "INTERNAL_ERROR"; + }; + }; + +/** + * Result of a single contract encode operation + * + * Each result can either be successful (containing the encoded transaction data) + * or failed (containing detailed error information). + */ +export type BatchResultItemReadResultSuccessItemEngineError = + | { + /** + * Successful result from a contract read operation + */ + result: Value; + } + | { + error: + | { + /** + * Detailed RPC error information + */ + chain_id: number; + rpc_url: string; + message: string; + kind: RpcErrorKind; + type: "RPC_ERROR"; + } + | { + /** + * Detailed RPC error information + */ + chain_id: number; + rpc_url: string; + message: string; + kind: RpcErrorKind; + type: "PAYMASTER_ERROR"; + } + | { + /** + * Detailed RPC error information + */ + chain_id: number; + rpc_url: string; + message: string; + kind: RpcErrorKind; + type: "BUNDLER_ERROR"; + } + | { + message: string; + type: "VAULT_ERROR"; + } + | { + message: string; + type: "RPC_CONFIG_ERROR"; + } + | { + contract_address?: null | AddressDef; + /** + * Chain ID + */ + chain_id: number; + /** + * Human-readable error message + */ + message: string; + /** + * Specific error kind + */ + kind: ContractInteractionErrorKind; + type: "CONTRACT_INTERACTION_ERROR"; + } + | { + message: string; + type: "VALIDATION_ERROR"; + } + | { + message: string; + type: "THIRDWEB_ERROR"; + } + | { + message: string; + type: "INTERNAL_ERROR"; + }; + }; + +/** + * Result of a single contract encode operation + * + * Each result can either be successful (containing the encoded transaction data) + * or failed (containing detailed error information). + */ +export type BatchResultItemSignResultDataEngineError = + | { + /** + * Data returned from successful signing + */ + result: { + /** + * The resulting signature + */ + signature: string; + /** + * The data that was signed (stringified typed data) + */ + signedData: string; + }; + } + | { + error: + | { + /** + * Detailed RPC error information + */ + chain_id: number; + rpc_url: string; + message: string; + kind: RpcErrorKind; + type: "RPC_ERROR"; + } + | { + /** + * Detailed RPC error information + */ + chain_id: number; + rpc_url: string; + message: string; + kind: RpcErrorKind; + type: "PAYMASTER_ERROR"; + } + | { + /** + * Detailed RPC error information + */ + chain_id: number; + rpc_url: string; + message: string; + kind: RpcErrorKind; + type: "BUNDLER_ERROR"; + } + | { + message: string; + type: "VAULT_ERROR"; + } + | { + message: string; + type: "RPC_CONFIG_ERROR"; + } + | { + contract_address?: null | AddressDef; + /** + * Chain ID + */ + chain_id: number; + /** + * Human-readable error message + */ + message: string; + /** + * Specific error kind + */ + kind: ContractInteractionErrorKind; + type: "CONTRACT_INTERACTION_ERROR"; + } + | { + message: string; + type: "VALIDATION_ERROR"; + } + | { + message: string; + type: "THIRDWEB_ERROR"; + } + | { + message: string; + type: "INTERNAL_ERROR"; + }; + }; + /** * # Bytes * Used to represent "bytes". This is a 0x prefixed hex string. @@ -59,14 +332,14 @@ export type BaseExecutionOptions = { export type BytesDef = string; export type CancelResult = - | "CANCELLED_IMMEDIATELY" - | "CANCELLATION_PENDING" - | { - CANNOT_CANCEL: { - reason: string; - }; - } - | "NOT_FOUND"; + | "CANCELLED_IMMEDIATELY" + | "CANCELLATION_PENDING" + | { + CANNOT_CANCEL: { + reason: string; + }; + } + | "NOT_FOUND"; /** * Represents a contract function call with parameters @@ -76,282 +349,141 @@ export type CancelResult = * automatic ABI resolution when needed. */ export type ContractCall = { - abi?: null | Value; - /** - * The address of the smart contract to call - */ - contractAddress: AddressDef; - /** - * The function to call - can be a name like "transfer" or full signature like "transfer(address,uint256)" - */ - method: string; - /** - * Array of parameters to pass to the function - */ - params: Array; + /** + * The address of the smart contract to call + */ + contractAddress: AddressDef; + /** + * The function to call - can be a name like "transfer" or full signature like "transfer(address,uint256)" + */ + method: string; + /** + * Array of parameters to pass to the function + */ + params: Array; + abi?: null | Value; }; /** * A serializable contract interaction error type */ export type ContractInteractionErrorKind = - | { - /** - * Unknown function referenced. - */ - UnknownFunction: string; - } - | { - /** - * Unknown function selector referenced. - */ - UnknownSelector: string; - } - | "NotADeploymentTransaction" - | "ContractNotDeployed" - | { - /** - * The contract returned no data. - */ - ZeroData: { - function: string; - message: string; - }; - } - | { - /** - * An error occurred ABI encoding or decoding. - */ - AbiError: string; - } - | { - /** - * An error occurred interacting with a contract over RPC. - */ - TransportError: string; - } - | { - /** - * An error occured while waiting for a pending transaction. - */ - PendingTransactionError: string; - } - | { - /** - * Error during contract function preparation (ABI resolution, parameter encoding) - */ - PreparationFailed: string; - } - | { - /** - * Error during multicall execution - */ - MulticallExecutionFailed: string; - } - | { - /** - * Error during result decoding - */ - ResultDecodingFailed: string; - } - | { - /** - * Parameter validation error - */ - ParameterValidationFailed: string; - } - | { - /** - * Function resolution error - */ - FunctionResolutionFailed: string; - }; + | { + functionName: string; + type: "UNKNOWN_FUNCTION"; + } + | { + functionSelector: string; + type: "UNKNOWN_SELECTOR"; + } + | { + type: "NOT_A_DEPLOYMENT_TRANSACTION"; + } + | { + type: "CONTRACT_NOT_DEPLOYED"; + } + | { + function: string; + message: string; + type: "ZERO_DATA"; + } + | { + message: string; + type: "ABI_ERROR"; + } + | { + message: string; + type: "TRANSPORT_ERROR"; + } + | { + message: string; + type: "PENDING_TRANSACTION_ERROR"; + } + | { + message: string; + type: "PREPARATION_FAILED"; + } + | { + message: string; + type: "MULTICALL_EXECUTION_FAILED"; + } + | { + message: string; + type: "RESULT_DECODING_FAILED"; + } + | { + message: string; + type: "PARAMETER_VALIDATION_FAILED"; + } + | { + message: string; + type: "FUNCTION_RESOLUTION_FAILED"; + }; /** * A contract function call with optional ETH value to send */ export type ContractWrite = ContractCall & { - value?: null | U256Def; + value?: null | U256Def; }; /** * Options for encoding contract function calls */ export type EncodeOptions = { - /** - * The blockchain network ID to encode for - * - * This is used to fetch the correct ABI if not provided inline - */ - chainId: string; + /** + * The blockchain network ID to encode for + * + * This is used to fetch the correct ABI if not provided inline + */ + chainId: string; }; /** * Request to encode contract function calls */ export type EncodeRequest = { - /** - * Configuration options for encoding - */ - encodeOptions: EncodeOptions; - /** - * List of contract function calls to encode - * - * Each call will be encoded to its raw transaction data - */ - params: Array; -}; - -/** - * Response from the contract encode endpoint - */ -export type EncodeResponse = { - /** - * Container for all encode operation results - */ - result: EncodeResults; + /** + * Configuration options for encoding + */ + encodeOptions: EncodeOptions; + /** + * List of contract function calls to encode + * + * Each call will be encoded to its raw transaction data + */ + params: Array; }; -/** - * Failed result from a contract encode operation - */ -export type EncodeResultFailureItem = { - /** - * Detailed error information describing what went wrong - */ - error: EngineError; - /** - * Always false for failed operations - */ - success: boolean; -}; - -/** - * Result of a single contract encode operation - * - * Each result can either be successful (containing the encoded transaction data) - * or failed (containing detailed error information). - */ -export type EncodeResultItem = - | EncodeResultSuccessItem - | EncodeResultFailureItem; - /** * Successful result from a contract encode operation */ export type EncodeResultSuccessItem = { - /** - * The encoded function call data - * - * This includes the function selector and encoded parameters, - * ready to be used in a transaction - */ - callData: string; - /** - * The name of the function being called - */ - functionName: string; - /** - * The 4-byte function selector (first 4 bytes of call_data) - */ - functionSelector: string; - /** - * Always true for successful operations - */ - success: boolean; - /** - * The contract address that would be called - */ - target: string; + /** + * The contract address that would be called + */ + target: string; + /** + * The encoded function call data + * + * This includes the function selector and encoded parameters, + * ready to be used in a transaction + */ + callData: string; + /** + * The 4-byte function selector (first 4 bytes of call_data) + */ + functionSelector: string; + /** + * The name of the function being called + */ + functionName: string; }; -/** - * Collection of results from multiple contract encode operations - */ -export type EncodeResults = { - /** - * Array of results, one for each input contract call - */ - results: Array; -}; - -export type EngineError = - | { - RpcError: { - /** - * Detailed RPC error information - */ - chain_id: number; - kind: RpcErrorKind; - message: string; - rpc_url: string; - }; - } - | { - PaymasterError: { - /** - * Detailed RPC error information - */ - chain_id: number; - kind: RpcErrorKind; - message: string; - rpc_url: string; - }; - } - | { - BundlerError: { - /** - * Detailed RPC error information - */ - chain_id: number; - kind: RpcErrorKind; - message: string; - rpc_url: string; - }; - } - | { - VaultError: { - message: string; - }; - } - | { - RpcConfigError: { - message: string; - }; - } - | { - ContractInteractionError: { - /** - * Chain ID - */ - chain_id: number; - contract_address?: null | AddressDef; - /** - * Specific error kind - */ - kind: ContractInteractionErrorKind; - /** - * Human-readable error message - */ - message: string; - }; - } - | { - ValidationError: { - message: string; - }; - } - | { - ThirdwebError: ThirdwebError; - } - | { - InternalError: string; - }; - export type EntrypointAndFactoryDetailsDeserHelper = { - entrypointAddress?: null | AddressDef; - entrypointVersion?: null | EntrypointVersion; - factoryAddress?: null | AddressDef; + entrypointAddress?: null | AddressDef; + entrypointVersion?: null | EntrypointVersion; + factoryAddress?: null | AddressDef; }; export type EntrypointVersion = "0.6" | "0.7"; @@ -360,11 +492,11 @@ export type EntrypointVersion = "0.6" | "0.7"; * EOA signing options */ export type EoaSigningOptions = { - chainId?: null | U64; - /** - * The EOA address to sign with - */ - from: AddressDef; + /** + * The EOA address to sign with + */ + from: AddressDef; + chainId?: null | U64; }; /** @@ -402,11 +534,67 @@ export type EoaSigningOptions = { * - Otherwise, it's read from the smart account factory * * All optional fields can be omitted for a minimal configuration using version 0.7 defaults. + * + * The most minimal usage only requires `signerAddress` + `chainId` */ export type Erc4337ExecutionOptions = EntrypointAndFactoryDetailsDeserHelper & { - accountSalt?: string; - signerAddress: AddressDef; - smartAccountAddress?: null | AddressDef; + signerAddress: AddressDef; + accountSalt?: string; + smartAccountAddress?: null | AddressDef; +}; + +/** + * ### ERC4337 (Smart Account) Signing Options + * This struct allows flexible configuration of ERC-4337 signing options, + * with intelligent defaults and inferences based on provided values. + * + * ### Field Inference + * When fields are omitted, the system uses the following inference rules: + * + * 1. Version Inference: + * - If `entrypointVersion` is provided, it's used directly + * - Otherwise, tries to infer from `entrypointAddress` (if provided) + * - If that fails, tries to infer from `factoryAddress` (if provided) + * - Defaults to version 0.7 if no inference is possible + * + * 2. Entrypoint Address Inference: + * - If provided explicitly, it's used as-is + * - Otherwise, uses the default address corresponding to the inferred version: + * - V0.6: 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789 + * - V0.7: 0x0576a174D229E3cFA37253523E645A78A0C91B57 + * + * 3. Factory Address Inference: + * - If provided explicitly, it's used as-is + * - Otherwise, uses the default factory corresponding to the inferred version: + * - V0.6: 0x85e23b94e7F5E9cC1fF78BCe78cfb15B81f0DF00 [DEFAULT_FACTORY_ADDRESS_V0_6] + * - V0.7: 0x4bE0ddfebcA9A5A4a617dee4DeCe99E7c862dceb [DEFAULT_FACTORY_ADDRESS_V0_7] + * + * 4. Account Salt: + * - If provided explicitly, it's used as-is + * - Otherwise, defaults to "0x" (commonly used as the defauult "null" salt for smart accounts) + * + * 5. Smart Account Address: + * - If provided explicitly, it's used as-is + * - Otherwise, it's read from the smart account factory + * + * All optional fields can be omitted for a minimal configuration using version 0.7 defaults. + * + * The most minimal usage only requires `signerAddress` + `chainId` + */ +export type Erc4337SigningOptions = EntrypointAndFactoryDetailsDeserHelper & { + smartAccountAddress?: null | AddressDef; + /** + * The EOA that controls the smart account + */ + signerAddress: AddressDef; + /** + * Account salt for deterministic addresses + */ + accountSalt?: string; + /** + * Chain ID for smart account operations + */ + chainId: U64; }; /** @@ -420,9 +608,9 @@ export type ExecutionOptions = BaseExecutionOptions & SpecificExecutionOptions; * This is the actual encoded inner transaction data that will be sent to the blockchain. */ export type InnerTransaction = { - data: BytesDef; - to: AddressDef; - value: U256Def; + to: AddressDef; + data?: BytesDef; + value?: U256Def; }; export type MessageFormatDef = "text" | "hex"; @@ -431,14 +619,14 @@ export type MessageFormatDef = "text" | "hex"; * Individual message to sign */ export type MessageInput = { - /** - * Message format (text or hex) - */ - format?: MessageFormatDef; - /** - * The message to sign - */ - message: string; + /** + * The message to sign + */ + message: string; + /** + * Message format (text or hex) + */ + format?: MessageFormatDef; }; /** @@ -446,205 +634,128 @@ export type MessageInput = { * Response for any request that queues one or more transactions */ export type QueuedTransaction = { - /** - * When multiple transactions are sent together via an execution mode that doesn't support atomic batching, - * each transaction will have a unique batchIndex but the same id (idempotency key) - * This maintains the relationship between different atomically sent blockchain transactions that were queued together - */ - batchIndex: number; - /** - * The fully resolved execution options for this transaction, derived from the resolution of user specific execution options - * Difference in naming is to prevent confusion when response executionParams contain different values than the request executionOptions - */ - executionParams: ExecutionOptions; - /** - * The idempotency key this transaction was queued with - * Either autogenerated UUID or provided by the user - * Multiple queued transactions can have the same idempotency key - * A "blockchain transaction" is uniquely identified by the idempotency key + batchIndex - */ - id: string; - /** - * This is the actual encoded inner transaction data that will be sent to the blockchain. - * For non-atomic transactions, this will be a single transaction - * For atomic transactions, this will be a list of transactions, because they were atomically sent together - */ - transactionParams: Array; + /** + * The idempotency key this transaction was queued with + * Either autogenerated UUID or provided by the user + * Multiple queued transactions can have the same idempotency key + * A "blockchain transaction" is uniquely identified by the idempotency key + batchIndex + */ + id: string; + /** + * When multiple transactions are sent together via an execution mode that doesn't support atomic batching, + * each transaction will have a unique batchIndex but the same id (idempotency key) + * This maintains the relationship between different atomically sent blockchain transactions that were queued together + */ + batchIndex: number; + /** + * The fully resolved execution options for this transaction, derived from the resolution of user specific execution options + * Difference in naming is to prevent confusion when response executionParams contain different values than the request executionOptions + */ + executionParams: ExecutionOptions; + /** + * This is the actual encoded inner transaction data that will be sent to the blockchain. + * For non-atomic transactions, this will be a single transaction + * For atomic transactions, this will be a list of transactions, because they were atomically sent together + */ + transactionParams: Array; }; export type QueuedTransactionsResponse = { - transactions: Array; + transactions: Array; }; /** * Options for reading from smart contracts */ export type ReadOptions = { - /** - * The blockchain network ID to read from - */ - chainId: string; - from?: null | AddressDef; - /** - * Address of the Multicall3 contract to use for batching calls - * - * Defaults to the standard Multicall3 address: 0xcA11bde05977b3631167028862bE2a173976CA11 - * which is deployed on most networks - */ - multicallAddress?: AddressDef; + /** + * The blockchain network ID to read from + */ + chainId: string; + /** + * Address of the Multicall3 contract to use for batching calls + * + * Defaults to the standard Multicall3 address: 0xcA11bde05977b3631167028862bE2a173976CA11 + * which is deployed on most networks + */ + multicallAddress?: AddressDef; + from?: null | AddressDef; }; /** * Request to read from multiple smart contracts */ export type ReadRequest = { - /** - * List of contract function calls to execute - * - * All calls will be batched together using Multicall3 for efficiency - */ - params: Array; - /** - * Configuration options for the read operation - */ - readOptions: ReadOptions; + /** + * Configuration options for the read operation + */ + readOptions: ReadOptions; + /** + * List of contract function calls to execute + * + * All calls will be batched together using Multicall3 for efficiency + */ + params: Array; }; -/** - * Response from the contract read endpoint - */ -export type ReadResponse = { - /** - * Container for all read operation results - */ - result: ReadResults; -}; - -/** - * Failed result from a contract read operation - */ -export type ReadResultFailureItem = { - /** - * Detailed error information describing what went wrong - * - * This includes the error type, chain information, and specific - * failure details to help with debugging - */ - error: EngineError; - /** - * Always false for failed operations - */ - success: boolean; -}; - -/** - * Result of a single contract read operation - * - * Each result can either be successful (containing the function return value) - * or failed (containing detailed error information). The `success` field - * indicates which case applies. - */ -export type ReadResultItem = ReadResultSuccessItem | ReadResultFailureItem; - /** * Successful result from a contract read operation */ -export type ReadResultSuccessItem = { - /** - * The decoded return value from the contract function - * - * For functions returning a single value, this will be that value. - * For functions returning multiple values, this will be an array. - */ - result: Value; - /** - * Always true for successful operations - */ - success: boolean; -}; - -/** - * Collection of results from multiple contract read operations - */ -export type ReadResults = { - /** - * Array of results, one for each input contract call - * - * Results are returned in the same order as the input parameters - */ - results: Array; -}; +export type ReadResultSuccessItem = Value; export type RpcErrorKind = - | { - /** - * Server returned an error response. - */ - ErrorResp: RpcErrorResponse; - } - | "NullResp" - | { - /** - * Rpc server returned an unsupported feature. - */ - UnsupportedFeature: string; - } - | { - /** - * Returned when a local pre-processing step fails. This allows custom - * errors from local signers or request pre-processors. - */ - InternalError: string; - } - | { - /** - * JSON serialization error. - */ - SerError: { - /** - * The underlying serde_json error. - */ - message: string; - }; - } - | { - /** - * JSON deserialization error. - */ - DeserError: { - /** - * The underlying serde_json error. - */ - message: string; - /** - * For deser errors, the text that failed to deserialize. - */ - text: string; - }; - } - | { - TransportHttpError: { - body: string; - status: number; - }; - } - | { - OtherTransportError: string; - }; + | (RpcErrorResponse & { + type: "ERROR_RESP"; + }) + | { + type: "NULL_RESP"; + } + | { + type: "UNSUPPORTED_FEATURE"; + } + | { + type: "INTERNAL_ERROR"; + } + | { + /** + * The underlying serde_json error. + */ + message: string; + type: "SER_ERROR"; + } + | { + /** + * The underlying serde_json error. + */ + message: string; + /** + * For deser errors, the text that failed to deserialize. + */ + text: string; + type: "DESER_ERROR"; + } + | { + status: number; + body: string; + type: "TRANSPORT_HTTP_ERROR"; + } + | { + type: "OTHER_TRANSPORT_ERROR"; + }; export type RpcErrorResponse = { - /** - * The error code. - */ - code: number; - /** - * The error data (if any). - */ - data?: string | null; - /** - * The error message (if any). - */ - message: string; + /** + * The error code. + */ + code: number; + /** + * The error message (if any). + */ + message: string; + /** + * The error data (if any). + */ + data?: string | null; }; /** @@ -652,297 +763,158 @@ export type RpcErrorResponse = { * Exposed API will have varying `params` but will all parse into InnerTransaction before execution */ export type SendTransactionRequest = { - executionOptions: ExecutionOptions; - params: Array; - webhookOptions?: Array | null; -}; - -export type SerializableReqwestError = - | { - Builder: { - message: string; - url?: string | null; - }; - } - | { - Request: { - message: string; - url?: string | null; - }; - } - | { - Timeout: { - message: string; - url?: string | null; - }; - } - | { - Connect: { - message: string; - url?: string | null; - }; - } - | { - Redirect: { - message: string; - url?: string | null; - }; - } - | { - ClientError: { - message: string; - status: number; - url?: string | null; - }; - } - | { - ServerError: { - message: string; - status: number; - url?: string | null; - }; - } - | { - Body: { - message: string; - url?: string | null; - }; - } - | { - Decode: { - message: string; - url?: string | null; - }; - } - | { - Upgrade: { - message: string; - url?: string | null; - }; - } - | { - Unknown: { - message: string; - url?: string | null; - }; - }; + executionOptions: ExecutionOptions; + params: Array; + webhookOptions?: Array | null; +}; /** * Request to sign messages */ export type SignMessageRequest = { - /** - * List of messages to sign - */ - params: Array; - /** - * Configuration options for signing - */ - signingOptions: SigningOptions; + /** + * Configuration options for signing + */ + signingOptions: SigningOptions; + /** + * List of messages to sign + */ + params: Array; }; -/** - * Response from the sign message endpoint - */ -export type SignMessageResponse = { - /** - * Container for all message signing results - */ - result: SignResults; -}; - -/** - * Configuration options for signing - */ -export type SignOptions = SigningOptions; - /** * Data returned from successful signing */ export type SignResultData = { - /** - * The resulting signature - */ - signature: string; - /** - * The data that was signed (stringified typed data) - */ - signedData: string; -}; - -/** - * Failed result from a typed data signing operation - */ -export type SignResultFailureItem = { - /** - * Detailed error information describing what went wrong - */ - error: EngineError; - /** - * Always false for failed operations - */ - success: false; -}; - -/** - * Result of a single typed data signing operation - */ -export type SignResultItem = SignResultSuccessItem | SignResultFailureItem; - -/** - * Successful result from a typed data signing operation - */ -export type SignResultSuccessItem = { - /** - * The signing result data - */ - result: SignResultData; - /** - * Always true for successful operations - */ - success: true; -}; - -/** - * Collection of results from multiple typed data signing operations - */ -export type SignResults = { - /** - * Array of results, one for each input typed data - */ - results: Array; + /** + * The resulting signature + */ + signature: string; + /** + * The data that was signed (stringified typed data) + */ + signedData: string; }; /** * Request to sign typed data */ export type SignTypedDataRequest = { - /** - * List of typed data to sign - */ - params: Array; - /** - * Configuration options for signing - */ - signOptions: SignOptions; -}; - -/** - * Response from the sign typed data endpoint - */ -export type SignTypedDataResponse = { - /** - * Container for all typed data signing results - */ - result: SignResults; + /** + * Configuration options for signing + */ + signingOptions: SigningOptions; + /** + * List of typed data to sign + */ + params: Array; }; /** * Configuration options for signing operations */ export type SigningOptions = - | (EoaSigningOptions & { - type: "eoa"; - }) - | (SmartAccountSigningOptions & { - type: "smart_account"; - }); - -/** - * Smart Account signing options - */ -export type SmartAccountSigningOptions = - EntrypointAndFactoryDetailsDeserHelper & { - /** - * Account salt for deterministic addresses - */ - accountSalt?: string; - /** - * Chain ID for smart account operations - */ - chainId: U64; - /** - * The EOA that controls the smart account - */ - signerAddress: AddressDef; - smartAccountAddress?: null | AddressDef; - }; + | (EoaSigningOptions & { + type: "eoa"; + }) + | (Erc4337SigningOptions & { + type: "ERC4337"; + }); /** * Execution Option Variants * All supported specific execution options are contained here */ export type SpecificExecutionOptions = - | (AutoExecutionOptions & { - type: "auto"; - }) - | (Erc4337ExecutionOptions & { - type: "ERC4337"; - }); - -export type ThirdwebError = - | { - SerializationError: ThirdwebSerializationError; - } - | { - UrlParseError: { - message: string; - value: string; - }; - } - | { - HttpClientBackendError: string; - } - | { - HttpError: SerializableReqwestError; - }; - -export type ThirdwebSerializationError = { - HeaderValue: { - value: string; - }; + | ({ + type: "auto"; + } & AutoExecutionOptions) + | ({ + type: "ERC4337"; + } & Erc4337ExecutionOptions); + +export type SuccessResponseBatchResultsEncodeResultSuccessItem = { + /** + * Collection of results from multiple contract encode operations + */ + result: { + /** + * Array of results, one for each input contract call + */ + results: Array; + }; +}; + +export type SuccessResponseBatchResultsReadResultSuccessItem = { + /** + * Collection of results from multiple contract encode operations + */ + result: { + /** + * Array of results, one for each input contract call + */ + results: Array; + }; +}; + +export type SuccessResponseBatchResultsSignResultData = { + /** + * Collection of results from multiple contract encode operations + */ + result: { + /** + * Array of results, one for each input contract call + */ + results: Array; + }; +}; + +export type SuccessResponseQueuedTransactionsResponse = { + result: { + transactions: Array; + }; }; export type TransactionCancelResponse = { - result: CancelResult; - transactionId: string; + transactionId: string; + result: CancelResult; }; export type TypedDataDef = { - /** - * Signing domain metadata. The signing domain is the intended context for - * the signature (e.g. the dapp, protocol, etc. that it's intended for). - * This data is used to construct the domain separator of the message. - */ - domain: TypedDataDomainDef; - /** - * The message to be signed. - */ - message: unknown; - /** - * The type of the message. - */ - primaryType: string; - /** - * The custom types used by this message. - */ - types: unknown; + /** + * Signing domain metadata. The signing domain is the intended context for + * the signature (e.g. the dapp, protocol, etc. that it's intended for). + * This data is used to construct the domain separator of the message. + */ + domain: TypedDataDomainDef; + /** + * The custom types used by this message. + */ + types: unknown; + /** + * The type of the message. + */ + primaryType: string; + /** + * The message to be signed. + */ + message: unknown; }; export type TypedDataDomainDef = { - chain_id?: null | U256Def; - name?: string | null; - /** - * A disambiguating salt for the protocol. This can be used as a domain - * separator of last resort. - */ - salt?: string | null; - verifying_contract?: null | AddressDef; - /** - * The current major version of the signing domain. Signatures from - * different versions are not compatible. - */ - version?: string | null; + name?: string | null; + /** + * The current major version of the signing domain. Signatures from + * different versions are not compatible. + */ + version?: string | null; + chainId?: null | U256Def; + verifyingContract?: null | AddressDef; + /** + * A disambiguating salt for the protocol. This can be used as a domain + * separator of last resort. + */ + salt?: string | null; }; /** @@ -954,682 +926,704 @@ export type U256Def = string; export type Value = unknown; export type WebhookOptions = { - secret?: string | null; - url: string; + url: string; + secret?: string | null; }; /** * Request to execute write transactions to smart contracts */ export type WriteContractRequest = { - /** - * Execution configuration including chain, account, and transaction options - */ - executionOptions: ExecutionOptions; - /** - * List of contract function calls to execute - * - * All calls will be executed in a single transaction if possible, - * or as separate transactions if atomic batching is not supported - */ - params: Array; - webhookOptions?: Array | null; + /** + * Execution configuration including chain, account, and transaction options + */ + executionOptions: ExecutionOptions; + /** + * List of contract function calls to execute + * + * All calls will be executed in a single transaction if possible, + * or as separate transactions if atomic batching is not supported + */ + params: Array; + webhookOptions?: Array | null; }; export type U64 = number; +export type WriteContractData = { + /** + * Write contract request + */ + body: WriteContractRequest; + headers?: { + /** + * Thirdweb client ID, passed along with the service key + */ + "x-thirdweb-client-id"?: string | null; + /** + * Thirdweb service key, passed when using the client ID + */ + "x-thirdweb-service-key"?: string | null; + /** + * Thirdweb secret key, passed standalone + */ + "x-thirdweb-secret-key"?: string | null; + /** + * Vault access token + */ + "x-vault-access-token"?: string | null; + }; + path?: never; + query?: never; + url: "/v1/write/contract"; +}; + +export type WriteContractResponses = { + /** + * Transaction(s) queued successfully + */ + 202: SuccessResponseQueuedTransactionsResponse; +}; + +export type WriteContractResponse = + WriteContractResponses[keyof WriteContractResponses]; + +export type SendTransactionData = { + /** + * Transaction request + */ + body: SendTransactionRequest; + headers?: { + /** + * Thirdweb client ID, passed along with the service key + */ + "x-thirdweb-client-id"?: string | null; + /** + * Thirdweb service key, passed when using the client ID + */ + "x-thirdweb-service-key"?: string | null; + /** + * Thirdweb secret key, passed standalone + */ + "x-thirdweb-secret-key"?: string | null; + /** + * Vault access token + */ + "x-vault-access-token"?: string | null; + }; + path?: never; + query?: never; + url: "/v1/write/transaction"; +}; + +export type SendTransactionResponses = { + /** + * Transaction queued successfully + */ + 202: SuccessResponseQueuedTransactionsResponse; +}; + +export type SendTransactionResponse = + SendTransactionResponses[keyof SendTransactionResponses]; + +export type SignMessageData = { + /** + * Sign message request + */ + body: SignMessageRequest; + headers?: { + /** + * Thirdweb client ID, passed along with the service key + */ + "x-thirdweb-client-id"?: string | null; + /** + * Thirdweb service key, passed when using the client ID + */ + "x-thirdweb-service-key"?: string | null; + /** + * Thirdweb secret key, passed standalone + */ + "x-thirdweb-secret-key"?: string | null; + /** + * Vault access token + */ + "x-vault-access-token"?: string | null; + }; + path?: never; + query?: never; + url: "/v1/sign/message"; +}; + +export type SignMessageResponses = { + /** + * Successfully signed messages + */ + 200: SuccessResponseBatchResultsSignResultData; +}; + +export type SignMessageResponse = + SignMessageResponses[keyof SignMessageResponses]; + +export type SignTypedDataData = { + /** + * Sign typed data request + */ + body: SignTypedDataRequest; + headers?: { + /** + * Thirdweb client ID, passed along with the service key + */ + "x-thirdweb-client-id"?: string | null; + /** + * Thirdweb service key, passed when using the client ID + */ + "x-thirdweb-service-key"?: string | null; + /** + * Thirdweb secret key, passed standalone + */ + "x-thirdweb-secret-key"?: string | null; + /** + * Vault access token + */ + "x-vault-access-token"?: string | null; + }; + path?: never; + query?: never; + url: "/v1/sign/typed-data"; +}; + +export type SignTypedDataResponses = { + /** + * Successfully signed typed data + */ + 200: SuccessResponseBatchResultsSignResultData; +}; + +export type SignTypedDataResponse = + SignTypedDataResponses[keyof SignTypedDataResponses]; + +export type ReadContractData = { + /** + * Read contract request + */ + body: ReadRequest; + headers?: { + /** + * Thirdweb client ID, passed along with the service key + */ + "x-thirdweb-client-id"?: string | null; + /** + * Thirdweb service key, passed when using the client ID + */ + "x-thirdweb-service-key"?: string | null; + /** + * Thirdweb secret key, passed standalone + */ + "x-thirdweb-secret-key"?: string | null; + }; + path?: never; + query?: never; + url: "/v1/read/contract"; +}; + +export type ReadContractResponses = { + /** + * Successfully read contract data + */ + 200: SuccessResponseBatchResultsReadResultSuccessItem; +}; + +export type ReadContractResponse = + ReadContractResponses[keyof ReadContractResponses]; + +export type EncodeContractData = { + /** + * Encode contract request + */ + body: EncodeRequest; + headers?: { + /** + * Thirdweb client ID, passed along with the service key + */ + "x-thirdweb-client-id"?: string | null; + /** + * Thirdweb service key, passed when using the client ID + */ + "x-thirdweb-service-key"?: string | null; + /** + * Thirdweb secret key, passed standalone + */ + "x-thirdweb-secret-key"?: string | null; + }; + path?: never; + query?: never; + url: "/v1/encode/contract"; +}; + +export type EncodeContractResponses = { + /** + * Successfully encoded contract calls + */ + 200: SuccessResponseBatchResultsEncodeResultSuccessItem; +}; + +export type EncodeContractResponse = + EncodeContractResponses[keyof EncodeContractResponses]; + +export type CancelTransactionData = { + body?: never; + path: { + /** + * Transaction ID to cancel + */ + id: string; + }; + query?: never; + url: "/v1/transactions/{id}/cancel"; +}; + +export type CancelTransactionResponses = { + /** + * Transaction cancellation result + */ + 200: TransactionCancelResponse; +}; + +export type CancelTransactionResponse = + CancelTransactionResponses[keyof CancelTransactionResponses]; + export type ListAccountsData = { - body?: never; - path?: never; - query?: never; - url: "/v1/accounts"; + body?: never; + path?: never; + query?: never; + url: "/v1/accounts"; }; export type ListAccountsResponses = { - /** - * Accounts retrieved successfully - */ - 200: { - result: Array<{ - /** - * EVM address in hex format - */ - address: string; - label?: string; - /** - * The predicted smart account address for use with the default thirdweb v0.7 AccountFactory - */ - smartAccountAddress?: string; - }>; - }; + /** + * Accounts retrieved successfully + */ + 200: { + result: Array<{ + /** + * EVM address in hex format + */ + address: string; + label?: string; + /** + * The predicted smart account address for use with the default thirdweb v0.7 AccountFactory + */ + smartAccountAddress?: string; + }>; + }; }; export type ListAccountsResponse = - ListAccountsResponses[keyof ListAccountsResponses]; + ListAccountsResponses[keyof ListAccountsResponses]; export type CreateAccountData = { - body?: { - label: string; - }; - headers?: { - /** - * Vault Access Token used to access your EOA - */ - "x-vault-access-token"?: string; - }; - path?: never; - query?: never; - url: "/v1/accounts"; + body?: { + label: string; + }; + headers?: { + /** + * Vault Access Token used to access your EOA + */ + "x-vault-access-token"?: string; + }; + path?: never; + query?: never; + url: "/v1/accounts"; }; export type CreateAccountResponses = { - /** - * Account created successfully - */ - 201: { - result: { - /** - * EVM address in hex format - */ - address: string; - label?: string; - /** - * The predicted smart account address for use with the default thirdweb v0.7 AccountFactory - */ - smartAccountAddress?: string; - }; - }; + /** + * Account created successfully + */ + 201: { + result: { + /** + * EVM address in hex format + */ + address: string; + label?: string; + /** + * The predicted smart account address for use with the default thirdweb v0.7 AccountFactory + */ + smartAccountAddress?: string; + }; + }; }; export type CreateAccountResponse = - CreateAccountResponses[keyof CreateAccountResponses]; + CreateAccountResponses[keyof CreateAccountResponses]; export type GetTransactionsData = { - body?: never; - path?: never; - query?: { - page?: number; - limit?: number; - id?: string; - batchIndex?: number; - /** - * EVM address in hex format - */ - from?: string; - /** - * EVM address in hex format - */ - signerAddress?: string; - sortBy?: "createdAt" | "confirmedAt"; - sortDirection?: "asc" | "desc"; - }; - url: "/v1/transactions"; + body?: never; + path?: never; + query?: { + page?: number; + limit?: number; + id?: string; + batchIndex?: number; + /** + * EVM address in hex format + */ + from?: string; + /** + * EVM address in hex format + */ + signerAddress?: string; + sortBy?: "createdAt" | "confirmedAt"; + sortDirection?: "asc" | "desc"; + }; + url: "/v1/transactions"; }; export type GetTransactionsResponses = { - /** - * Transactions - */ - 200: { - result: { - transactions: Array<{ - id: string; - batchIndex: number; - clientId: string; - chainId: string; - from: string | null; - transactionParams: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - transactionHash: string | null; - confirmedAt: string | null; - confirmedAtBlockNumber: string | null; - enrichedData: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - executionParams: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - executionResult: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array - | null; - createdAt: string; - errorMessage: string | null; - cancelledAt: string | null; - }>; - pagination: { - totalCount: number; - page: number; - limit: number; - }; - }; - }; + /** + * Transactions + */ + 200: { + result: { + transactions: Array<{ + id: string; + batchIndex: number; + clientId: string; + chainId: string; + from: string | null; + transactionParams: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array; + transactionHash: string | null; + confirmedAt: string | null; + confirmedAtBlockNumber: string | null; + enrichedData: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array; + executionParams: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array; + executionResult: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array + | null; + createdAt: string; + errorMessage: string | null; + cancelledAt: string | null; + }>; + pagination: { + totalCount: number; + page: number; + limit: number; + }; + }; + }; }; export type GetTransactionsResponse = - GetTransactionsResponses[keyof GetTransactionsResponses]; + GetTransactionsResponses[keyof GetTransactionsResponses]; export type GetTransactionAnalyticsData = { - body?: { - startDate: string; - endDate: string; - resolution: "hour" | "day" | "week" | "month"; - filters?: Array; - filtersOperation?: "AND" | "OR"; - }; - path?: never; - query?: never; - url: "/v1/transactions/analytics"; + body?: { + startDate: string; + endDate: string; + resolution: "hour" | "day" | "week" | "month"; + filters?: Array; + filtersOperation?: "AND" | "OR"; + }; + path?: never; + query?: never; + url: "/v1/transactions/analytics"; }; export type GetTransactionAnalyticsResponses = { - /** - * Transaction Analytics - */ - 200: { - result: { - analytics: Array<{ - timeBucket: string; - chainId: string; - count: number; - }>; - metadata: { - resolution: "hour" | "day" | "week" | "month"; - startDate: string; - endDate: string; - }; - }; - }; + /** + * Transaction Analytics + */ + 200: { + result: { + analytics: Array<{ + timeBucket: string; + chainId: string; + count: number; + }>; + metadata: { + resolution: "hour" | "day" | "week" | "month"; + startDate: string; + endDate: string; + }; + }; + }; }; export type GetTransactionAnalyticsResponse = - GetTransactionAnalyticsResponses[keyof GetTransactionAnalyticsResponses]; + GetTransactionAnalyticsResponses[keyof GetTransactionAnalyticsResponses]; export type GetTransactionAnalyticsSummaryData = { - body?: { - startDate?: string; - endDate?: string; - filters?: Array; - filtersOperation?: "AND" | "OR"; - }; - path?: never; - query?: never; - url: "/v1/transactions/analytics-summary"; + body?: { + startDate?: string; + endDate?: string; + filters?: Array; + filtersOperation?: "AND" | "OR"; + }; + path?: never; + query?: never; + url: "/v1/transactions/analytics-summary"; }; export type GetTransactionAnalyticsSummaryErrors = { - /** - * Bad Request (e.g., invalid date format, filter depth exceeded) - */ - 400: unknown; - /** - * Internal Server Error (e.g., database error) - */ - 500: unknown; + /** + * Bad Request (e.g., invalid date format, filter depth exceeded) + */ + 400: unknown; + /** + * Internal Server Error (e.g., database error) + */ + 500: unknown; }; export type GetTransactionAnalyticsSummaryResponses = { - /** - * Transaction Analytics Summary - */ - 200: { - result: { - summary: { - /** - * Total number of transactions matching the criteria. - */ - totalCount: number; - /** - * Sum of actualGasCost (in wei) for all matching transactions, as a string. - */ - totalGasCostWei: string; - /** - * Sum of actualGasUsed (gas units) for all matching transactions, as a string. - */ - totalGasUnitsUsed: string; - }; - metadata: { - startDate?: string; - endDate?: string; - }; - }; - }; + /** + * Transaction Analytics Summary + */ + 200: { + result: { + summary: { + /** + * Total number of transactions matching the criteria. + */ + totalCount: number; + /** + * Sum of actualGasCost (in wei) for all matching transactions, as a string. + */ + totalGasCostWei: string; + /** + * Sum of actualGasUsed (gas units) for all matching transactions, as a string. + */ + totalGasUnitsUsed: string; + }; + metadata: { + startDate?: string; + endDate?: string; + }; + }; + }; }; export type GetTransactionAnalyticsSummaryResponse = - GetTransactionAnalyticsSummaryResponses[keyof GetTransactionAnalyticsSummaryResponses]; + GetTransactionAnalyticsSummaryResponses[keyof GetTransactionAnalyticsSummaryResponses]; export type SearchTransactionsData = { - body?: { - page?: number; - limit?: number; - filters?: Array; - filtersOperation?: "AND" | "OR"; - sortBy?: "createdAt" | "confirmedAt"; - sortDirection?: "asc" | "desc"; - }; - path?: never; - query?: never; - url: "/v1/transactions/search"; + body?: { + page?: number; + limit?: number; + filters?: Array; + filtersOperation?: "AND" | "OR"; + sortBy?: "createdAt" | "confirmedAt"; + sortDirection?: "asc" | "desc"; + }; + path?: never; + query?: never; + url: "/v1/transactions/search"; }; export type SearchTransactionsResponses = { - /** - * Transactions - */ - 200: { - result: { - transactions: Array<{ - id: string; - batchIndex: number; - clientId: string; - chainId: string; - from: string | null; - transactionParams: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - transactionHash: string | null; - confirmedAt: string | null; - confirmedAtBlockNumber: string | null; - enrichedData: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - executionParams: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - executionResult: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array - | null; - createdAt: string; - errorMessage: string | null; - cancelledAt: string | null; - }>; - pagination: { - totalCount: number; - page: number; - limit: number; - }; - }; - }; + /** + * Transactions + */ + 200: { + result: { + transactions: Array<{ + id: string; + batchIndex: number; + clientId: string; + chainId: string; + from: string | null; + transactionParams: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array; + transactionHash: string | null; + confirmedAt: string | null; + confirmedAtBlockNumber: string | null; + enrichedData: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array; + executionParams: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array; + executionResult: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array + | null; + createdAt: string; + errorMessage: string | null; + cancelledAt: string | null; + }>; + pagination: { + totalCount: number; + page: number; + limit: number; + }; + }; + }; }; export type SearchTransactionsResponse = - SearchTransactionsResponses[keyof SearchTransactionsResponses]; + SearchTransactionsResponses[keyof SearchTransactionsResponses]; export type GetActivityLogsData = { - body?: never; - path?: never; - query: { - page?: number; - limit?: number; - transactionId: string; - batchIndex?: number; - eventType?: "SUCCESS" | "FAILURE" | "NACK"; - stageName?: string; - executorName?: string; - sortBy?: "timestamp" | "createdAt"; - sortDirection?: "asc" | "desc"; - }; - url: "/v1/transactions/activity-logs"; + body?: never; + path?: never; + query: { + page?: number; + limit?: number; + transactionId: string; + batchIndex?: number; + eventType?: "SUCCESS" | "FAILURE" | "NACK"; + stageName?: string; + executorName?: string; + sortBy?: "timestamp" | "createdAt"; + sortDirection?: "asc" | "desc"; + }; + url: "/v1/transactions/activity-logs"; }; export type GetActivityLogsErrors = { - /** - * Invalid request parameters - */ - 400: unknown; - /** - * Transaction not found or not accessible - */ - 404: unknown; + /** + * Invalid request parameters + */ + 400: unknown; + /** + * Transaction not found or not accessible + */ + 404: unknown; }; export type GetActivityLogsResponses = { - /** - * Activity Logs - */ - 200: { - result: { - activityLogs: Array<{ - id: string; - transactionId: string; - batchIndex: number; - eventType: string; - stageName: string; - executorName: string; - notificationId: string; - payload: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - timestamp: string; - createdAt: string; - }>; - transaction: { - id: string; - batchIndex: number; - clientId: string; - }; - pagination: { - totalCount: number; - page: number; - limit: number; - }; - }; - }; + /** + * Activity Logs + */ + 200: { + result: { + activityLogs: Array<{ + id: string; + transactionId: string; + batchIndex: number; + eventType: string; + stageName: string; + executorName: string; + notificationId: string; + payload: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array; + timestamp: string; + createdAt: string; + }>; + transaction: { + id: string; + batchIndex: number; + clientId: string; + }; + pagination: { + totalCount: number; + page: number; + limit: number; + }; + }; + }; }; export type GetActivityLogsResponse = - GetActivityLogsResponses[keyof GetActivityLogsResponses]; + GetActivityLogsResponses[keyof GetActivityLogsResponses]; export type SearchActivityLogsData = { - body?: { - page?: number; - limit?: number; - transactionIds?: Array; - eventType?: "SUCCESS" | "FAILURE" | "NACK"; - stageName?: string; - executorName?: string; - startDate?: string; - endDate?: string; - sortBy?: "timestamp" | "createdAt"; - sortDirection?: "asc" | "desc"; - }; - path?: never; - query?: never; - url: "/v1/transactions/activity-logs/search"; + body?: { + page?: number; + limit?: number; + transactionIds?: Array; + eventType?: "SUCCESS" | "FAILURE" | "NACK"; + stageName?: string; + executorName?: string; + startDate?: string; + endDate?: string; + sortBy?: "timestamp" | "createdAt"; + sortDirection?: "asc" | "desc"; + }; + path?: never; + query?: never; + url: "/v1/transactions/activity-logs/search"; }; export type SearchActivityLogsErrors = { - /** - * Invalid request parameters - */ - 400: unknown; + /** + * Invalid request parameters + */ + 400: unknown; }; export type SearchActivityLogsResponses = { - /** - * Activity Logs Search Results - */ - 200: { - result: { - activityLogs: Array<{ - id: string; - transactionId: string; - batchIndex: number; - eventType: string; - stageName: string; - executorName: string; - notificationId: string; - payload: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - timestamp: string; - createdAt: string; - }>; - pagination: { - totalCount: number; - page: number; - limit: number; - }; - }; - }; + /** + * Activity Logs Search Results + */ + 200: { + result: { + activityLogs: Array<{ + id: string; + transactionId: string; + batchIndex: number; + eventType: string; + stageName: string; + executorName: string; + notificationId: string; + payload: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array; + timestamp: string; + createdAt: string; + }>; + pagination: { + totalCount: number; + page: number; + limit: number; + }; + }; + }; }; export type SearchActivityLogsResponse = - SearchActivityLogsResponses[keyof SearchActivityLogsResponses]; - -export type WriteContractData = { - /** - * Write contract request - */ - body: WriteContractRequest; - headers?: { - /** - * Thirdweb client ID, passed along with the service key - */ - "x-thirdweb-client-id"?: string | null; - /** - * Thirdweb service key, passed when using the client ID - */ - "x-thirdweb-service-key"?: string | null; - /** - * Thirdweb secret key, passed standalone - */ - "x-thirdweb-secret-key"?: string | null; - /** - * Vault access token - */ - "x-vault-access-token"?: string | null; - }; - path?: never; - query?: never; - url: "/v1/write/contract"; -}; - -export type WriteContractResponses = { - /** - * Transaction(s) queued successfully - */ - 202: QueuedTransactionsResponse; -}; - -export type WriteContractResponse = - WriteContractResponses[keyof WriteContractResponses]; - -export type WriteTransactionData = { - /** - * Transaction request - */ - body: SendTransactionRequest; - headers?: { - /** - * Thirdweb client ID, passed along with the service key - */ - "x-thirdweb-client-id"?: string | null; - /** - * Thirdweb service key, passed when using the client ID - */ - "x-thirdweb-service-key"?: string | null; - /** - * Thirdweb secret key, passed standalone - */ - "x-thirdweb-secret-key"?: string | null; - /** - * Vault access token - */ - "x-vault-access-token"?: string | null; - }; - path?: never; - query?: never; - url: "/v1/write/transaction"; -}; - -export type WriteTransactionResponses = { - /** - * Transaction queued successfully - */ - 202: QueuedTransactionsResponse; -}; - -export type WriteTransactionResponse = - WriteTransactionResponses[keyof WriteTransactionResponses]; - -export type SignMessageData = { - /** - * Sign message request - */ - body: SignMessageRequest; - headers?: { - /** - * Thirdweb client ID, passed along with the service key - */ - "x-thirdweb-client-id"?: string | null; - /** - * Thirdweb service key, passed when using the client ID - */ - "x-thirdweb-service-key"?: string | null; - /** - * Thirdweb secret key, passed standalone - */ - "x-thirdweb-secret-key"?: string | null; - /** - * Vault access token - */ - "x-vault-access-token"?: string | null; - }; - path?: never; - query?: never; - url: "/v1/sign/message"; -}; - -export type SignMessageResponses = { - /** - * Successfully signed messages - */ - 200: SignMessageResponse; -}; - -export type SignMessageResponse2 = - SignMessageResponses[keyof SignMessageResponses]; - -export type SignTypedDataData = { - /** - * Sign typed data request - */ - body: SignTypedDataRequest; - headers?: { - /** - * Thirdweb client ID, passed along with the service key - */ - "x-thirdweb-client-id"?: string | null; - /** - * Thirdweb service key, passed when using the client ID - */ - "x-thirdweb-service-key"?: string | null; - /** - * Thirdweb secret key, passed standalone - */ - "x-thirdweb-secret-key"?: string | null; - /** - * Vault access token - */ - "x-vault-access-token"?: string | null; - }; - path?: never; - query?: never; - url: "/v1/sign/typed-data"; -}; - -export type SignTypedDataResponses = { - /** - * Successfully signed typed data - */ - 200: SignTypedDataResponse; -}; - -export type SignTypedDataResponse2 = - SignTypedDataResponses[keyof SignTypedDataResponses]; - -export type ReadContractData = { - /** - * Read contract request - */ - body: ReadRequest; - headers?: { - /** - * Thirdweb client ID, passed along with the service key - */ - "x-thirdweb-client-id"?: string | null; - /** - * Thirdweb service key, passed when using the client ID - */ - "x-thirdweb-service-key"?: string | null; - /** - * Thirdweb secret key, passed standalone - */ - "x-thirdweb-secret-key"?: string | null; - }; - path?: never; - query?: never; - url: "/v1/read/contract"; -}; - -export type ReadContractResponses = { - /** - * Successfully read contract data - */ - 200: ReadResponse; -}; - -export type ReadContractResponse = - ReadContractResponses[keyof ReadContractResponses]; - -export type EncodeContractData = { - /** - * Encode contract request - */ - body: EncodeRequest; - headers?: { - /** - * Thirdweb client ID, passed along with the service key - */ - "x-thirdweb-client-id"?: string | null; - /** - * Thirdweb service key, passed when using the client ID - */ - "x-thirdweb-service-key"?: string | null; - /** - * Thirdweb secret key, passed standalone - */ - "x-thirdweb-secret-key"?: string | null; - }; - path?: never; - query?: never; - url: "/v1/encode/contract"; -}; - -export type EncodeContractResponses = { - /** - * Successfully encoded contract calls - */ - 200: EncodeResponse; -}; - -export type EncodeContractResponse = - EncodeContractResponses[keyof EncodeContractResponses]; + SearchActivityLogsResponses[keyof SearchActivityLogsResponses]; export type ClientOptions = { - baseUrl: "http://localhost:3009" | (string & {}); + baseUrl: "http://localhost:3001" | (string & {}); }; diff --git a/packages/engine/src/configure.ts b/packages/engine/src/configure.ts index edc7316dc82..045a86986b5 100644 --- a/packages/engine/src/configure.ts +++ b/packages/engine/src/configure.ts @@ -1,38 +1,38 @@ -import type { Config } from "@hey-api/client-fetch"; +import type { Config } from "./client/client/types.js"; import { client } from "./client/client.gen.js"; export type EngineClientOptions = { - readonly clientId?: string; - readonly secretKey?: string; + readonly clientId?: string; + readonly secretKey?: string; }; export function configure( - options: EngineClientOptions & { override?: Config }, + options: EngineClientOptions & { override?: Config }, ) { - client.setConfig({ - bodySerializer: stringify, - headers: { - ...(options.clientId && { "x-client-id": options.clientId }), - ...(options.secretKey && { "x-secret-key": options.secretKey }), - }, - ...(options.override ?? {}), - }); + client.setConfig({ + bodySerializer: stringify, + headers: { + ...(options.clientId && { "x-client-id": options.clientId }), + ...(options.secretKey && { "x-secret-key": options.secretKey }), + }, + ...(options.override ?? {}), + }); } function stringify( - // biome-ignore lint/suspicious/noExplicitAny: JSON.stringify signature - value: any, - // biome-ignore lint/suspicious/noExplicitAny: JSON.stringify signature - replacer?: ((this: any, key: string, value: any) => any) | null, - space?: string | number, + // biome-ignore lint/suspicious/noExplicitAny: JSON.stringify signature + value: any, + // biome-ignore lint/suspicious/noExplicitAny: JSON.stringify signature + replacer?: ((this: any, key: string, value: any) => any) | null, + space?: string | number, ) { - const res = JSON.stringify( - value, - (key, value_) => { - const value__ = typeof value_ === "bigint" ? value_.toString() : value_; - return typeof replacer === "function" ? replacer(key, value__) : value__; - }, - space, - ); - return res; + const res = JSON.stringify( + value, + (key, value_) => { + const value__ = typeof value_ === "bigint" ? value_.toString() : value_; + return typeof replacer === "function" ? replacer(key, value__) : value__; + }, + space, + ); + return res; } diff --git a/packages/engine/tsconfig.base.json b/packages/engine/tsconfig.base.json index 1dfe1e7b2ce..09a7f9b41de 100644 --- a/packages/engine/tsconfig.base.json +++ b/packages/engine/tsconfig.base.json @@ -1,47 +1,43 @@ { - // This tsconfig file contains the shared config for the build (tsconfig.build.json) and type checking (tsconfig.json) config. - "compilerOptions": { - // Incremental builds - // NOTE: Enabling incremental builds speeds up `tsc`. Keep in mind though that it does not reliably bust the cache when the `tsconfig.json` file changes. - "allowJs": false, - "allowSyntheticDefaultImports": true, - "checkJs": false, - - // Interop constraints - "esModuleInterop": false, - "exactOptionalPropertyTypes": false, - "forceConsistentCasingInFileNames": true, - "importHelpers": true, - // Incremental builds - // NOTE: Enabling incremental builds speeds up `tsc`. Keep in mind though that it does not reliably bust the cache when the `tsconfig.json` file changes. - "incremental": false, - - // jsx for "/react" portion - "jsx": "react-jsx", - "lib": [ - "ES2022", // By using ES2022 we get access to the `.cause` property on `Error` instances. - "DOM" // We are adding `DOM` here to get the `fetch`, etc. types. This should be removed once these types are available via DefinitelyTyped. - ], - "module": "NodeNext", - - // Language and environment - "moduleResolution": "NodeNext", - "noFallthroughCasesInSwitch": true, - "noImplicitOverride": true, - "noImplicitReturns": true, - "noUncheckedIndexedAccess": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - - // Skip type checking for node modules - "skipLibCheck": true, - - // Type checking - "strict": true, - "target": "ES2021", - "useDefineForClassFields": true, - "useUnknownInCatchVariables": true, - "verbatimModuleSyntax": true - }, - "include": [] -} + // This tsconfig file contains the shared config for the build (tsconfig.build.json) and type checking (tsconfig.json) config. + "compilerOptions": { + // Incremental builds + // NOTE: Enabling incremental builds speeds up `tsc`. Keep in mind though that it does not reliably bust the cache when the `tsconfig.json` file changes. + "allowJs": false, + "allowSyntheticDefaultImports": true, + "checkJs": false, + // Interop constraints + "esModuleInterop": false, + "exactOptionalPropertyTypes": false, + "forceConsistentCasingInFileNames": true, + "importHelpers": true, + // Incremental builds + // NOTE: Enabling incremental builds speeds up `tsc`. Keep in mind though that it does not reliably bust the cache when the `tsconfig.json` file changes. + "incremental": false, + // jsx for "/react" portion + "jsx": "react-jsx", + "lib": [ + "ES2022", // By using ES2022 we get access to the `.cause` property on `Error` instances. + "DOM", // We are adding `DOM` here to get the `fetch`, etc. types. This should be removed once these types are available via DefinitelyTyped. + "DOM.Iterable" + ], + "module": "NodeNext", + // Language and environment + "moduleResolution": "NodeNext", + "noFallthroughCasesInSwitch": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + // Skip type checking for node modules + "skipLibCheck": true, + // Type checking + "strict": true, + "target": "ES2021", + "useDefineForClassFields": true, + "useUnknownInCatchVariables": true, + "verbatimModuleSyntax": true + }, + "include": [] +} \ No newline at end of file diff --git a/packages/engine/tsconfig.build.json b/packages/engine/tsconfig.build.json index 63325457c67..03fd851f536 100644 --- a/packages/engine/tsconfig.build.json +++ b/packages/engine/tsconfig.build.json @@ -1,16 +1,16 @@ { - "compilerOptions": { - "moduleResolution": "node", - "rootDir": "./src", - "sourceMap": true - }, - "exclude": [ - "src/**/*.test.ts", - "src/**/*.test.tsx", - "src/**/*.test-d.ts", - "src/**/*.bench.ts", - "src/**/*.macro.ts" - ], - "extends": "./tsconfig.base.json", - "include": ["src"] + "compilerOptions": { + "moduleResolution": "node", + "rootDir": "./src", + "sourceMap": true + }, + "exclude": [ + "src/**/*.test.ts", + "src/**/*.test.tsx", + "src/**/*.test-d.ts", + "src/**/*.bench.ts", + "src/**/*.macro.ts" + ], + "extends": "./tsconfig.base.json", + "include": ["src"] } diff --git a/packages/engine/tsconfig.json b/packages/engine/tsconfig.json index ce67da4c61d..567a39cb1ce 100644 --- a/packages/engine/tsconfig.json +++ b/packages/engine/tsconfig.json @@ -1,12 +1,12 @@ { - // This configuration is used for local development and type checking. - "compilerOptions": { - "baseUrl": ".", - "paths": { - "~test/*": ["./test/src/*"] - } - }, - "exclude": [], - "extends": "./tsconfig.base.json", - "include": ["src", "test"] + // This configuration is used for local development and type checking. + "compilerOptions": { + "baseUrl": ".", + "paths": { + "~test/*": ["./test/src/*"] + } + }, + "exclude": [], + "extends": "./tsconfig.base.json", + "include": ["src", "test"] } diff --git a/packages/thirdweb/src/engine/create-server-wallet.ts b/packages/thirdweb/src/engine/create-server-wallet.ts index 5b2e7d9604b..c410b47e9cd 100644 --- a/packages/thirdweb/src/engine/create-server-wallet.ts +++ b/packages/thirdweb/src/engine/create-server-wallet.ts @@ -47,7 +47,7 @@ export async function createServerWallet(params: CreateServerWalletArgs) { ); } - const data = result.data?.[201]?.result; + const data = result.data?.result; if (!data) { throw new Error(`No server wallet created with label ${label}`); diff --git a/packages/thirdweb/src/engine/get-status.ts b/packages/thirdweb/src/engine/get-status.ts index b79a2e2bf1d..88e15459769 100644 --- a/packages/thirdweb/src/engine/get-status.ts +++ b/packages/thirdweb/src/engine/get-status.ts @@ -99,7 +99,7 @@ export async function getTransactionStatus(args: { ); } - const data = searchResult.data?.[200]?.result?.transactions?.[0]; + const data = searchResult.data?.result?.transactions?.[0]; if (!data) { throw new Error(`Transaction ${transactionId} not found`); diff --git a/packages/thirdweb/src/engine/list-server-wallets.ts b/packages/thirdweb/src/engine/list-server-wallets.ts index 2efe1199b39..53e4213ad64 100644 --- a/packages/thirdweb/src/engine/list-server-wallets.ts +++ b/packages/thirdweb/src/engine/list-server-wallets.ts @@ -36,7 +36,7 @@ export async function getServerWallets(params: GetServerWalletsArgs) { throw new Error(`Error listing server wallets: ${stringify(result.error)}`); } - const data = result.data?.[200]?.result; + const data = result.data?.result; if (!data) { throw new Error("No server wallets found"); diff --git a/packages/thirdweb/src/engine/search-transactions.ts b/packages/thirdweb/src/engine/search-transactions.ts index 27c0c765c3f..be92534bfb7 100644 --- a/packages/thirdweb/src/engine/search-transactions.ts +++ b/packages/thirdweb/src/engine/search-transactions.ts @@ -122,7 +122,7 @@ export async function searchTransactions(args: SearchTransactionsArgs) { ); } - const data = searchResult.data?.[200]?.result; + const data = searchResult.data?.result; if (!data) { throw new Error(`No transactions found with filters ${stringify(filters)}`); diff --git a/packages/thirdweb/src/engine/server-wallet.ts b/packages/thirdweb/src/engine/server-wallet.ts index f076fb0e51d..dafd67d8020 100644 --- a/packages/thirdweb/src/engine/server-wallet.ts +++ b/packages/thirdweb/src/engine/server-wallet.ts @@ -1,8 +1,10 @@ import { - type ExecutionOptions, + type ExecutionOptions as ExecutionOptionsWithChainId, + type SigningOptions, + type SpecificExecutionOptions, + sendTransaction, signMessage, signTypedData, - writeTransaction, } from "@thirdweb-dev/engine"; import type { Chain } from "../chains/types.js"; import type { ThirdwebClient } from "../client/client.js"; @@ -20,6 +22,8 @@ import type { } from "../wallets/interfaces/wallet.js"; import { waitForTransactionHash } from "./wait-for-tx-hash.js"; +type ExecutionOptions = SpecificExecutionOptions; + /** * Options for creating an server wallet. */ @@ -43,7 +47,7 @@ export type ServerWalletOptions = { /** * Optional custom execution options to use for sending transactions and signing data. */ - executionOptions?: Omit; + executionOptions?: ExecutionOptions; }; export type ServerWallet = Account & { @@ -145,22 +149,22 @@ export type ServerWallet = Account & { export function serverWallet(options: ServerWalletOptions): ServerWallet { const { client, vaultAccessToken, address, chain, executionOptions } = options; + const headers: HeadersInit = { "x-vault-access-token": vaultAccessToken, }; - const getExecutionOptions = (chainId: number): ExecutionOptions => { - const options: ExecutionOptions | undefined = executionOptions as - | ExecutionOptions - | undefined; - if (!options) { + const getExecutionOptionsWithChainId = ( + chainId: number, + ): ExecutionOptionsWithChainId => { + if (!executionOptions) { return { chainId, from: address, type: "auto", }; } - switch (options.type) { + switch (executionOptions.type) { case "auto": return { chainId, @@ -169,13 +173,65 @@ export function serverWallet(options: ServerWalletOptions): ServerWallet { }; case "ERC4337": return { - ...options, + ...executionOptions, chainId, type: "ERC4337", }; } }; + const getSigningOptions = (chainId: number | undefined): SigningOptions => { + // if no chainId passed specifically for this signature + // we HAVE TO fallback to EOA signature + if (!chainId) { + return { + from: address, + type: "eoa", + }; + } + + // todo + // ServerWallet needs to have an async initialisation phase + // where it fetches details about the wallet from engine cloud + // engine cloud needs to provide an endpoint to "find" a wallet, by either smart account address or EOA address + // after "inrospection", server wallet always knows both the signer as well as smart account address + // regardless of what address was passed in + if (!executionOptions) { + // let's default to 4337 + return { + chainId, + signerAddress: address, + type: "ERC4337", + }; + } + + switch (executionOptions.type) { + case "ERC4337": { + return { + chainId, + // smartAccountAddress: address, + signerAddress: address, + type: "ERC4337", + }; + } + + case "auto": { + return { + chainId, + // smartAccountAddress: address, + signerAddress: address, + type: "ERC4337", + }; + } + + // case "eoa": { + // return { + // chainId, + // from: address, + // } + } + }; + const enqueueTx = async (transaction: SendTransactionOption[]) => { if (transaction.length === 0) { throw new Error("No transactions to enqueue"); @@ -194,7 +250,7 @@ export function serverWallet(options: ServerWalletOptions): ServerWallet { } } const body = { - executionOptions: getExecutionOptions(chainId), + executionOptions: getExecutionOptionsWithChainId(chainId), params: transaction.map((t) => ({ data: t.data || "0x", to: t.to ?? "", // TODO this should be allowed to be undefined @@ -202,7 +258,7 @@ export function serverWallet(options: ServerWalletOptions): ServerWallet { })), }; - const result = await writeTransaction({ + const result = await sendTransaction({ baseUrl: getThirdwebBaseUrl("engineCloud"), body, bodySerializer: stringify, @@ -214,7 +270,7 @@ export function serverWallet(options: ServerWalletOptions): ServerWallet { throw new Error(`Error sending transaction: ${stringify(result.error)}`); } - const data = result.data?.[202]; + const data = result.data?.result; if (!data) { throw new Error("No data returned from engine"); } @@ -317,8 +373,6 @@ export function serverWallet(options: ServerWalletOptions): ServerWallet { if (!signingChainId) { throw new Error("Chain ID is required for signing messages"); } - // FIXME - const options = executionOptions as ExecutionOptions | undefined; const signResult = await signMessage({ baseUrl: getThirdwebBaseUrl("engineCloud"), body: { @@ -328,24 +382,7 @@ export function serverWallet(options: ServerWalletOptions): ServerWallet { message: engineMessage, }, ], - // FIXME - signingOptions: - options?.type === "ERC4337" - ? { - accountSalt: options.accountSalt, - chainId: signingChainId, - entrypointAddress: options.entrypointAddress, - entrypointVersion: options.entrypointVersion, - factoryAddress: options.factoryAddress, - signerAddress: address, - smartAccountAddress: options.smartAccountAddress, - type: "smart_account", - } - : { - chainId: signingChainId, - from: address, - type: "eoa", - }, + signingOptions: getSigningOptions(signingChainId), }, bodySerializer: stringify, fetch: getClientFetch(client), @@ -358,8 +395,8 @@ export function serverWallet(options: ServerWalletOptions): ServerWallet { ); } - const signatureResult = signResult.data?.[200]?.result.results[0]; - if (signatureResult?.success) { + const signatureResult = signResult.data?.result.results[0]; + if (signatureResult && "result" in signatureResult) { return signatureResult.result.signature as Hex; } @@ -373,30 +410,12 @@ export function serverWallet(options: ServerWalletOptions): ServerWallet { throw new Error("Chain ID is required for signing messages"); } - const options = executionOptions as ExecutionOptions; const signResult = await signTypedData({ baseUrl: getThirdwebBaseUrl("engineCloud"), body: { // biome-ignore lint/suspicious/noExplicitAny: TODO: fix ts / hey-api type clash params: [typedData as any], - // FIXME - signOptions: - options?.type === "ERC4337" - ? { - accountSalt: options.accountSalt, - chainId: signingChainId, - entrypointAddress: options.entrypointAddress, - entrypointVersion: options.entrypointVersion, - factoryAddress: options.factoryAddress, - signerAddress: address, - smartAccountAddress: options.smartAccountAddress, - type: "smart_account", - } - : { - chainId: signingChainId, - from: address, - type: "eoa", - }, + signingOptions: getSigningOptions(signingChainId), }, bodySerializer: stringify, fetch: getClientFetch(client), @@ -409,8 +428,8 @@ export function serverWallet(options: ServerWalletOptions): ServerWallet { ); } - const signatureResult = signResult.data?.[200]?.result.results[0]; - if (signatureResult?.success) { + const signatureResult = signResult.data?.result.results[0]; + if (signatureResult && "result" in signatureResult) { return signatureResult.result.signature as Hex; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 47ac195a0ae..1f87a3e0dd3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1055,7 +1055,7 @@ importers: dependencies: '@hey-api/client-fetch': specifier: 0.10.0 - version: 0.10.0(@hey-api/openapi-ts@0.72.1(magicast@0.3.5)(typescript@5.8.3)) + version: 0.10.0(@hey-api/openapi-ts@0.77.0(magicast@0.3.5)(typescript@5.8.3)) typescript: specifier: '>=5.0.4' version: 5.8.3 @@ -1064,8 +1064,8 @@ importers: specifier: 2.0.4 version: 2.0.4 '@hey-api/openapi-ts': - specifier: 0.72.1 - version: 0.72.1(magicast@0.3.5)(typescript@5.8.3) + specifier: 0.77.0 + version: 0.77.0(magicast@0.3.5)(typescript@5.8.3) rimraf: specifier: 6.0.1 version: 6.0.1 @@ -3444,6 +3444,13 @@ packages: peerDependencies: typescript: ^5.5.3 + '@hey-api/openapi-ts@0.77.0': + resolution: {integrity: sha512-HAJbd8QfxeBPZ788Ghiw7bzzzTKxW+wW+34foleEztyZJnRV20barvevu8YAK1BtyiIGIpEtAfoqO8KUj4VuBw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=22.10.0} + hasBin: true + peerDependencies: + typescript: ^5.5.3 + '@hookform/resolvers@3.10.0': resolution: {integrity: sha512-79Dv+3mDF7i+2ajj7SkypSKHhl1cbln1OGavqrsF7p6mbUv11xpqpacPsGDCTRvCSjEEIez2ef1NveSVL3b0Ag==} peerDependencies: @@ -19353,6 +19360,10 @@ snapshots: dependencies: '@hey-api/openapi-ts': 0.72.1(magicast@0.3.5)(typescript@5.8.3) + '@hey-api/client-fetch@0.10.0(@hey-api/openapi-ts@0.77.0(magicast@0.3.5)(typescript@5.8.3))': + dependencies: + '@hey-api/openapi-ts': 0.77.0(magicast@0.3.5)(typescript@5.8.3) + '@hey-api/json-schema-ref-parser@1.0.6': dependencies: '@jsdevtools/ono': 7.1.3 @@ -19373,6 +19384,19 @@ snapshots: transitivePeerDependencies: - magicast + '@hey-api/openapi-ts@0.77.0(magicast@0.3.5)(typescript@5.8.3)': + dependencies: + '@hey-api/json-schema-ref-parser': 1.0.6 + ansi-colors: 4.1.3 + c12: 2.0.1(magicast@0.3.5) + color-support: 1.1.3 + commander: 13.0.0 + handlebars: 4.7.8 + open: 10.1.2 + typescript: 5.8.3 + transitivePeerDependencies: + - magicast + '@hookform/resolvers@3.10.0(react-hook-form@7.55.0(react@19.1.0))': dependencies: react-hook-form: 7.55.0(react@19.1.0) From 35677ba3a9d16201aef8ed9906db356a88eeacd4 Mon Sep 17 00:00:00 2001 From: Prithvish Baidya Date: Wed, 25 Jun 2025 10:00:48 +0530 Subject: [PATCH 03/18] stringify in error message --- packages/thirdweb/src/engine/server-wallet.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/thirdweb/src/engine/server-wallet.ts b/packages/thirdweb/src/engine/server-wallet.ts index dafd67d8020..8189dfc4342 100644 --- a/packages/thirdweb/src/engine/server-wallet.ts +++ b/packages/thirdweb/src/engine/server-wallet.ts @@ -401,7 +401,7 @@ export function serverWallet(options: ServerWalletOptions): ServerWallet { } throw new Error( - `Failed to sign message: ${signatureResult?.error || "Unknown error"}`, + `Failed to sign message: ${stringify(signatureResult?.error) || "Unknown error"}`, ); }, signTypedData: async (typedData) => { @@ -434,7 +434,7 @@ export function serverWallet(options: ServerWalletOptions): ServerWallet { } throw new Error( - `Failed to sign message: ${signatureResult?.error || "Unknown error"}`, + `Failed to sign message: ${stringify(signatureResult?.error) || "Unknown error"}`, ); }, }; From 1529d256e3368a30c02953b5a4ff791f90429121 Mon Sep 17 00:00:00 2001 From: Prithvish Baidya Date: Wed, 25 Jun 2025 10:17:30 +0530 Subject: [PATCH 04/18] updated engine SDK types --- packages/engine/src/client/types.gen.ts | 2354 +++++++++++------------ 1 file changed, 1177 insertions(+), 1177 deletions(-) diff --git a/packages/engine/src/client/types.gen.ts b/packages/engine/src/client/types.gen.ts index c94c4b94b96..8a563d68a4e 100644 --- a/packages/engine/src/client/types.gen.ts +++ b/packages/engine/src/client/types.gen.ts @@ -1,20 +1,20 @@ // This file is auto-generated by @hey-api/openapi-ts export type TransactionsFilterValue = { - field: - | "id" - | "batchIndex" - | "from" - | "signerAddress" - | "smartAccountAddress" - | "chainId"; - values: Array; - operation: "AND" | "OR"; + field: + | "id" + | "batchIndex" + | "from" + | "signerAddress" + | "smartAccountAddress" + | "chainId"; + values: Array; + operation: "AND" | "OR"; }; export type TransactionsFilterNested = { - operation: "AND" | "OR"; - filters: Array; + operation: "AND" | "OR"; + filters: Array; }; /** @@ -32,19 +32,19 @@ export type AddressDef = string; * choose one of the other executionOptions type and provide them. */ export type AutoExecutionOptions = { - /** - * The identifier of the entity to send the transaction from. - * Automatically picks best execution strategy based on the identifier. - * - If EOA address, execution uses EIP7702 based smart-wallet execution - * - If 7702 not supported on chain, falls back to smart-contract wallet (ERC4337) with default smart account for this EOA (v0.7) - * - UNLESS this is a zk-chain, in which case, zk-sync native-aa is used - */ - from: string; + /** + * The identifier of the entity to send the transaction from. + * Automatically picks best execution strategy based on the identifier. + * - If EOA address, execution uses EIP7702 based smart-wallet execution + * - If 7702 not supported on chain, falls back to smart-contract wallet (ERC4337) with default smart account for this EOA (v0.7) + * - UNLESS this is a zk-chain, in which case, zk-sync native-aa is used + */ + from: string; }; export type BaseExecutionOptions = { - chainId: number; - idempotencyKey?: string; + chainId: number; + idempotencyKey?: string; }; /** @@ -54,101 +54,101 @@ export type BaseExecutionOptions = { * or failed (containing detailed error information). */ export type BatchResultItemEncodeResultSuccessItemEngineError = - | { - /** - * Successful result from a contract encode operation - */ - result: { - /** - * The contract address that would be called - */ - target: string; - /** - * The encoded function call data - * - * This includes the function selector and encoded parameters, - * ready to be used in a transaction - */ - callData: string; - /** - * The 4-byte function selector (first 4 bytes of call_data) - */ - functionSelector: string; - /** - * The name of the function being called - */ - functionName: string; - }; - } - | { - error: - | { - /** - * Detailed RPC error information - */ - chain_id: number; - rpc_url: string; - message: string; - kind: RpcErrorKind; - type: "RPC_ERROR"; - } - | { - /** - * Detailed RPC error information - */ - chain_id: number; - rpc_url: string; - message: string; - kind: RpcErrorKind; - type: "PAYMASTER_ERROR"; - } - | { - /** - * Detailed RPC error information - */ - chain_id: number; - rpc_url: string; - message: string; - kind: RpcErrorKind; - type: "BUNDLER_ERROR"; - } - | { - message: string; - type: "VAULT_ERROR"; - } - | { - message: string; - type: "RPC_CONFIG_ERROR"; - } - | { - contract_address?: null | AddressDef; - /** - * Chain ID - */ - chain_id: number; - /** - * Human-readable error message - */ - message: string; - /** - * Specific error kind - */ - kind: ContractInteractionErrorKind; - type: "CONTRACT_INTERACTION_ERROR"; - } - | { - message: string; - type: "VALIDATION_ERROR"; - } - | { - message: string; - type: "THIRDWEB_ERROR"; - } - | { - message: string; - type: "INTERNAL_ERROR"; - }; - }; + | { + /** + * Successful result from a contract encode operation + */ + result: { + /** + * The contract address that would be called + */ + target: string; + /** + * The encoded function call data + * + * This includes the function selector and encoded parameters, + * ready to be used in a transaction + */ + callData: string; + /** + * The 4-byte function selector (first 4 bytes of call_data) + */ + functionSelector: string; + /** + * The name of the function being called + */ + functionName: string; + }; + } + | { + error: + | { + /** + * Detailed RPC error information + */ + chain_id: number; + rpc_url: string; + message: string; + kind: RpcErrorKind; + type: "RPC_ERROR"; + } + | { + /** + * Detailed RPC error information + */ + chain_id: number; + rpc_url: string; + message: string; + kind: RpcErrorKind; + type: "PAYMASTER_ERROR"; + } + | { + /** + * Detailed RPC error information + */ + chain_id: number; + rpc_url: string; + message: string; + kind: RpcErrorKind; + type: "BUNDLER_ERROR"; + } + | { + message: string; + type: "VAULT_ERROR"; + } + | { + message: string; + type: "RPC_CONFIG_ERROR"; + } + | { + contract_address?: null | AddressDef; + /** + * Chain ID + */ + chain_id: number; + /** + * Human-readable error message + */ + message: string; + /** + * Specific error kind + */ + kind: ContractInteractionErrorKind; + type: "CONTRACT_INTERACTION_ERROR"; + } + | { + message: string; + type: "VALIDATION_ERROR"; + } + | { + message: string; + type: "THIRDWEB_ERROR"; + } + | { + message: string; + type: "INTERNAL_ERROR"; + }; + }; /** * Result of a single contract encode operation @@ -157,81 +157,81 @@ export type BatchResultItemEncodeResultSuccessItemEngineError = * or failed (containing detailed error information). */ export type BatchResultItemReadResultSuccessItemEngineError = - | { - /** - * Successful result from a contract read operation - */ - result: Value; - } - | { - error: - | { - /** - * Detailed RPC error information - */ - chain_id: number; - rpc_url: string; - message: string; - kind: RpcErrorKind; - type: "RPC_ERROR"; - } - | { - /** - * Detailed RPC error information - */ - chain_id: number; - rpc_url: string; - message: string; - kind: RpcErrorKind; - type: "PAYMASTER_ERROR"; - } - | { - /** - * Detailed RPC error information - */ - chain_id: number; - rpc_url: string; - message: string; - kind: RpcErrorKind; - type: "BUNDLER_ERROR"; - } - | { - message: string; - type: "VAULT_ERROR"; - } - | { - message: string; - type: "RPC_CONFIG_ERROR"; - } - | { - contract_address?: null | AddressDef; - /** - * Chain ID - */ - chain_id: number; - /** - * Human-readable error message - */ - message: string; - /** - * Specific error kind - */ - kind: ContractInteractionErrorKind; - type: "CONTRACT_INTERACTION_ERROR"; - } - | { - message: string; - type: "VALIDATION_ERROR"; - } - | { - message: string; - type: "THIRDWEB_ERROR"; - } - | { - message: string; - type: "INTERNAL_ERROR"; - }; - }; + | { + /** + * Successful result from a contract read operation + */ + result: Value; + } + | { + error: + | { + /** + * Detailed RPC error information + */ + chain_id: number; + rpc_url: string; + message: string; + kind: RpcErrorKind; + type: "RPC_ERROR"; + } + | { + /** + * Detailed RPC error information + */ + chain_id: number; + rpc_url: string; + message: string; + kind: RpcErrorKind; + type: "PAYMASTER_ERROR"; + } + | { + /** + * Detailed RPC error information + */ + chain_id: number; + rpc_url: string; + message: string; + kind: RpcErrorKind; + type: "BUNDLER_ERROR"; + } + | { + message: string; + type: "VAULT_ERROR"; + } + | { + message: string; + type: "RPC_CONFIG_ERROR"; + } + | { + contract_address?: null | AddressDef; + /** + * Chain ID + */ + chain_id: number; + /** + * Human-readable error message + */ + message: string; + /** + * Specific error kind + */ + kind: ContractInteractionErrorKind; + type: "CONTRACT_INTERACTION_ERROR"; + } + | { + message: string; + type: "VALIDATION_ERROR"; + } + | { + message: string; + type: "THIRDWEB_ERROR"; + } + | { + message: string; + type: "INTERNAL_ERROR"; + }; + }; /** * Result of a single contract encode operation @@ -240,90 +240,90 @@ export type BatchResultItemReadResultSuccessItemEngineError = * or failed (containing detailed error information). */ export type BatchResultItemSignResultDataEngineError = - | { - /** - * Data returned from successful signing - */ - result: { - /** - * The resulting signature - */ - signature: string; - /** - * The data that was signed (stringified typed data) - */ - signedData: string; - }; - } - | { - error: - | { - /** - * Detailed RPC error information - */ - chain_id: number; - rpc_url: string; - message: string; - kind: RpcErrorKind; - type: "RPC_ERROR"; - } - | { - /** - * Detailed RPC error information - */ - chain_id: number; - rpc_url: string; - message: string; - kind: RpcErrorKind; - type: "PAYMASTER_ERROR"; - } - | { - /** - * Detailed RPC error information - */ - chain_id: number; - rpc_url: string; - message: string; - kind: RpcErrorKind; - type: "BUNDLER_ERROR"; - } - | { - message: string; - type: "VAULT_ERROR"; - } - | { - message: string; - type: "RPC_CONFIG_ERROR"; - } - | { - contract_address?: null | AddressDef; - /** - * Chain ID - */ - chain_id: number; - /** - * Human-readable error message - */ - message: string; - /** - * Specific error kind - */ - kind: ContractInteractionErrorKind; - type: "CONTRACT_INTERACTION_ERROR"; - } - | { - message: string; - type: "VALIDATION_ERROR"; - } - | { - message: string; - type: "THIRDWEB_ERROR"; - } - | { - message: string; - type: "INTERNAL_ERROR"; - }; - }; + | { + /** + * Data returned from successful signing + */ + result: { + /** + * The resulting signature + */ + signature: string; + /** + * The data that was signed (stringified typed data) + */ + signedData: string; + }; + } + | { + error: + | { + /** + * Detailed RPC error information + */ + chain_id: number; + rpc_url: string; + message: string; + kind: RpcErrorKind; + type: "RPC_ERROR"; + } + | { + /** + * Detailed RPC error information + */ + chain_id: number; + rpc_url: string; + message: string; + kind: RpcErrorKind; + type: "PAYMASTER_ERROR"; + } + | { + /** + * Detailed RPC error information + */ + chain_id: number; + rpc_url: string; + message: string; + kind: RpcErrorKind; + type: "BUNDLER_ERROR"; + } + | { + message: string; + type: "VAULT_ERROR"; + } + | { + message: string; + type: "RPC_CONFIG_ERROR"; + } + | { + contract_address?: null | AddressDef; + /** + * Chain ID + */ + chain_id: number; + /** + * Human-readable error message + */ + message: string; + /** + * Specific error kind + */ + kind: ContractInteractionErrorKind; + type: "CONTRACT_INTERACTION_ERROR"; + } + | { + message: string; + type: "VALIDATION_ERROR"; + } + | { + message: string; + type: "THIRDWEB_ERROR"; + } + | { + message: string; + type: "INTERNAL_ERROR"; + }; + }; /** * # Bytes @@ -332,14 +332,14 @@ export type BatchResultItemSignResultDataEngineError = export type BytesDef = string; export type CancelResult = - | "CANCELLED_IMMEDIATELY" - | "CANCELLATION_PENDING" - | { - CANNOT_CANCEL: { - reason: string; - }; - } - | "NOT_FOUND"; + | "CANCELLED_IMMEDIATELY" + | "CANCELLATION_PENDING" + | { + CANNOT_CANCEL: { + reason: string; + }; + } + | "NOT_FOUND"; /** * Represents a contract function call with parameters @@ -349,141 +349,141 @@ export type CancelResult = * automatic ABI resolution when needed. */ export type ContractCall = { - /** - * The address of the smart contract to call - */ - contractAddress: AddressDef; - /** - * The function to call - can be a name like "transfer" or full signature like "transfer(address,uint256)" - */ - method: string; - /** - * Array of parameters to pass to the function - */ - params: Array; - abi?: null | Value; + /** + * The address of the smart contract to call + */ + contractAddress: AddressDef; + /** + * The function to call - can be a name like "transfer" or full signature like "transfer(address,uint256)" + */ + method: string; + /** + * Array of parameters to pass to the function + */ + params: Array; + abi?: null | Value; }; /** * A serializable contract interaction error type */ export type ContractInteractionErrorKind = - | { - functionName: string; - type: "UNKNOWN_FUNCTION"; - } - | { - functionSelector: string; - type: "UNKNOWN_SELECTOR"; - } - | { - type: "NOT_A_DEPLOYMENT_TRANSACTION"; - } - | { - type: "CONTRACT_NOT_DEPLOYED"; - } - | { - function: string; - message: string; - type: "ZERO_DATA"; - } - | { - message: string; - type: "ABI_ERROR"; - } - | { - message: string; - type: "TRANSPORT_ERROR"; - } - | { - message: string; - type: "PENDING_TRANSACTION_ERROR"; - } - | { - message: string; - type: "PREPARATION_FAILED"; - } - | { - message: string; - type: "MULTICALL_EXECUTION_FAILED"; - } - | { - message: string; - type: "RESULT_DECODING_FAILED"; - } - | { - message: string; - type: "PARAMETER_VALIDATION_FAILED"; - } - | { - message: string; - type: "FUNCTION_RESOLUTION_FAILED"; - }; + | { + functionName: string; + type: "UNKNOWN_FUNCTION"; + } + | { + functionSelector: string; + type: "UNKNOWN_SELECTOR"; + } + | { + type: "NOT_A_DEPLOYMENT_TRANSACTION"; + } + | { + type: "CONTRACT_NOT_DEPLOYED"; + } + | { + function: string; + message: string; + type: "ZERO_DATA"; + } + | { + message: string; + type: "ABI_ERROR"; + } + | { + message: string; + type: "TRANSPORT_ERROR"; + } + | { + message: string; + type: "PENDING_TRANSACTION_ERROR"; + } + | { + message: string; + type: "PREPARATION_FAILED"; + } + | { + message: string; + type: "MULTICALL_EXECUTION_FAILED"; + } + | { + message: string; + type: "RESULT_DECODING_FAILED"; + } + | { + message: string; + type: "PARAMETER_VALIDATION_FAILED"; + } + | { + message: string; + type: "FUNCTION_RESOLUTION_FAILED"; + }; /** * A contract function call with optional ETH value to send */ export type ContractWrite = ContractCall & { - value?: null | U256Def; + value?: null | U256Def; }; /** * Options for encoding contract function calls */ export type EncodeOptions = { - /** - * The blockchain network ID to encode for - * - * This is used to fetch the correct ABI if not provided inline - */ - chainId: string; + /** + * The blockchain network ID to encode for + * + * This is used to fetch the correct ABI if not provided inline + */ + chainId: string; }; /** * Request to encode contract function calls */ export type EncodeRequest = { - /** - * Configuration options for encoding - */ - encodeOptions: EncodeOptions; - /** - * List of contract function calls to encode - * - * Each call will be encoded to its raw transaction data - */ - params: Array; + /** + * Configuration options for encoding + */ + encodeOptions: EncodeOptions; + /** + * List of contract function calls to encode + * + * Each call will be encoded to its raw transaction data + */ + params: Array; }; /** * Successful result from a contract encode operation */ export type EncodeResultSuccessItem = { - /** - * The contract address that would be called - */ - target: string; - /** - * The encoded function call data - * - * This includes the function selector and encoded parameters, - * ready to be used in a transaction - */ - callData: string; - /** - * The 4-byte function selector (first 4 bytes of call_data) - */ - functionSelector: string; - /** - * The name of the function being called - */ - functionName: string; + /** + * The contract address that would be called + */ + target: string; + /** + * The encoded function call data + * + * This includes the function selector and encoded parameters, + * ready to be used in a transaction + */ + callData: string; + /** + * The 4-byte function selector (first 4 bytes of call_data) + */ + functionSelector: string; + /** + * The name of the function being called + */ + functionName: string; }; export type EntrypointAndFactoryDetailsDeserHelper = { - entrypointAddress?: null | AddressDef; - entrypointVersion?: null | EntrypointVersion; - factoryAddress?: null | AddressDef; + entrypointAddress?: null | AddressDef; + entrypointVersion?: null | EntrypointVersion; + factoryAddress?: null | AddressDef; }; export type EntrypointVersion = "0.6" | "0.7"; @@ -492,11 +492,11 @@ export type EntrypointVersion = "0.6" | "0.7"; * EOA signing options */ export type EoaSigningOptions = { - /** - * The EOA address to sign with - */ - from: AddressDef; - chainId?: null | U64; + /** + * The EOA address to sign with + */ + from: AddressDef; + chainId?: null | U64; }; /** @@ -538,9 +538,9 @@ export type EoaSigningOptions = { * The most minimal usage only requires `signerAddress` + `chainId` */ export type Erc4337ExecutionOptions = EntrypointAndFactoryDetailsDeserHelper & { - signerAddress: AddressDef; - accountSalt?: string; - smartAccountAddress?: null | AddressDef; + signerAddress: AddressDef; + accountSalt?: string; + smartAccountAddress?: null | AddressDef; }; /** @@ -582,19 +582,19 @@ export type Erc4337ExecutionOptions = EntrypointAndFactoryDetailsDeserHelper & { * The most minimal usage only requires `signerAddress` + `chainId` */ export type Erc4337SigningOptions = EntrypointAndFactoryDetailsDeserHelper & { - smartAccountAddress?: null | AddressDef; - /** - * The EOA that controls the smart account - */ - signerAddress: AddressDef; - /** - * Account salt for deterministic addresses - */ - accountSalt?: string; - /** - * Chain ID for smart account operations - */ - chainId: U64; + smartAccountAddress?: null | AddressDef; + /** + * The EOA that controls the smart account + */ + signerAddress: AddressDef; + /** + * Account salt for deterministic addresses + */ + accountSalt?: string; + /** + * Chain ID for smart account operations + */ + chainId: U64; }; /** @@ -608,9 +608,9 @@ export type ExecutionOptions = BaseExecutionOptions & SpecificExecutionOptions; * This is the actual encoded inner transaction data that will be sent to the blockchain. */ export type InnerTransaction = { - to: AddressDef; - data?: BytesDef; - value?: U256Def; + to?: null | AddressDef; + data?: BytesDef; + value?: U256Def; }; export type MessageFormatDef = "text" | "hex"; @@ -619,14 +619,14 @@ export type MessageFormatDef = "text" | "hex"; * Individual message to sign */ export type MessageInput = { - /** - * The message to sign - */ - message: string; - /** - * Message format (text or hex) - */ - format?: MessageFormatDef; + /** + * The message to sign + */ + message: string; + /** + * Message format (text or hex) + */ + format?: MessageFormatDef; }; /** @@ -634,68 +634,68 @@ export type MessageInput = { * Response for any request that queues one or more transactions */ export type QueuedTransaction = { - /** - * The idempotency key this transaction was queued with - * Either autogenerated UUID or provided by the user - * Multiple queued transactions can have the same idempotency key - * A "blockchain transaction" is uniquely identified by the idempotency key + batchIndex - */ - id: string; - /** - * When multiple transactions are sent together via an execution mode that doesn't support atomic batching, - * each transaction will have a unique batchIndex but the same id (idempotency key) - * This maintains the relationship between different atomically sent blockchain transactions that were queued together - */ - batchIndex: number; - /** - * The fully resolved execution options for this transaction, derived from the resolution of user specific execution options - * Difference in naming is to prevent confusion when response executionParams contain different values than the request executionOptions - */ - executionParams: ExecutionOptions; - /** - * This is the actual encoded inner transaction data that will be sent to the blockchain. - * For non-atomic transactions, this will be a single transaction - * For atomic transactions, this will be a list of transactions, because they were atomically sent together - */ - transactionParams: Array; + /** + * The idempotency key this transaction was queued with + * Either autogenerated UUID or provided by the user + * Multiple queued transactions can have the same idempotency key + * A "blockchain transaction" is uniquely identified by the idempotency key + batchIndex + */ + id: string; + /** + * When multiple transactions are sent together via an execution mode that doesn't support atomic batching, + * each transaction will have a unique batchIndex but the same id (idempotency key) + * This maintains the relationship between different atomically sent blockchain transactions that were queued together + */ + batchIndex: number; + /** + * The fully resolved execution options for this transaction, derived from the resolution of user specific execution options + * Difference in naming is to prevent confusion when response executionParams contain different values than the request executionOptions + */ + executionParams: ExecutionOptions; + /** + * This is the actual encoded inner transaction data that will be sent to the blockchain. + * For non-atomic transactions, this will be a single transaction + * For atomic transactions, this will be a list of transactions, because they were atomically sent together + */ + transactionParams: Array; }; export type QueuedTransactionsResponse = { - transactions: Array; + transactions: Array; }; /** * Options for reading from smart contracts */ export type ReadOptions = { - /** - * The blockchain network ID to read from - */ - chainId: string; - /** - * Address of the Multicall3 contract to use for batching calls - * - * Defaults to the standard Multicall3 address: 0xcA11bde05977b3631167028862bE2a173976CA11 - * which is deployed on most networks - */ - multicallAddress?: AddressDef; - from?: null | AddressDef; + /** + * The blockchain network ID to read from + */ + chainId: string; + /** + * Address of the Multicall3 contract to use for batching calls + * + * Defaults to the standard Multicall3 address: 0xcA11bde05977b3631167028862bE2a173976CA11 + * which is deployed on most networks + */ + multicallAddress?: AddressDef; + from?: null | AddressDef; }; /** * Request to read from multiple smart contracts */ export type ReadRequest = { - /** - * Configuration options for the read operation - */ - readOptions: ReadOptions; - /** - * List of contract function calls to execute - * - * All calls will be batched together using Multicall3 for efficiency - */ - params: Array; + /** + * Configuration options for the read operation + */ + readOptions: ReadOptions; + /** + * List of contract function calls to execute + * + * All calls will be batched together using Multicall3 for efficiency + */ + params: Array; }; /** @@ -704,58 +704,58 @@ export type ReadRequest = { export type ReadResultSuccessItem = Value; export type RpcErrorKind = - | (RpcErrorResponse & { - type: "ERROR_RESP"; - }) - | { - type: "NULL_RESP"; - } - | { - type: "UNSUPPORTED_FEATURE"; - } - | { - type: "INTERNAL_ERROR"; - } - | { - /** - * The underlying serde_json error. - */ - message: string; - type: "SER_ERROR"; - } - | { - /** - * The underlying serde_json error. - */ - message: string; - /** - * For deser errors, the text that failed to deserialize. - */ - text: string; - type: "DESER_ERROR"; - } - | { - status: number; - body: string; - type: "TRANSPORT_HTTP_ERROR"; - } - | { - type: "OTHER_TRANSPORT_ERROR"; - }; + | (RpcErrorResponse & { + type: "ERROR_RESP"; + }) + | { + type: "NULL_RESP"; + } + | { + type: "UNSUPPORTED_FEATURE"; + } + | { + type: "INTERNAL_ERROR"; + } + | { + /** + * The underlying serde_json error. + */ + message: string; + type: "SER_ERROR"; + } + | { + /** + * The underlying serde_json error. + */ + message: string; + /** + * For deser errors, the text that failed to deserialize. + */ + text: string; + type: "DESER_ERROR"; + } + | { + status: number; + body: string; + type: "TRANSPORT_HTTP_ERROR"; + } + | { + type: "OTHER_TRANSPORT_ERROR"; + }; export type RpcErrorResponse = { - /** - * The error code. - */ - code: number; - /** - * The error message (if any). - */ - message: string; - /** - * The error data (if any). - */ - data?: string | null; + /** + * The error code. + */ + code: number; + /** + * The error message (if any). + */ + message: string; + /** + * The error data (if any). + */ + data?: string | null; }; /** @@ -763,158 +763,158 @@ export type RpcErrorResponse = { * Exposed API will have varying `params` but will all parse into InnerTransaction before execution */ export type SendTransactionRequest = { - executionOptions: ExecutionOptions; - params: Array; - webhookOptions?: Array | null; + executionOptions: ExecutionOptions; + params: Array; + webhookOptions?: Array | null; }; /** * Request to sign messages */ export type SignMessageRequest = { - /** - * Configuration options for signing - */ - signingOptions: SigningOptions; - /** - * List of messages to sign - */ - params: Array; + /** + * Configuration options for signing + */ + signingOptions: SigningOptions; + /** + * List of messages to sign + */ + params: Array; }; /** * Data returned from successful signing */ export type SignResultData = { - /** - * The resulting signature - */ - signature: string; - /** - * The data that was signed (stringified typed data) - */ - signedData: string; + /** + * The resulting signature + */ + signature: string; + /** + * The data that was signed (stringified typed data) + */ + signedData: string; }; /** * Request to sign typed data */ export type SignTypedDataRequest = { - /** - * Configuration options for signing - */ - signingOptions: SigningOptions; - /** - * List of typed data to sign - */ - params: Array; + /** + * Configuration options for signing + */ + signingOptions: SigningOptions; + /** + * List of typed data to sign + */ + params: Array; }; /** * Configuration options for signing operations */ export type SigningOptions = - | (EoaSigningOptions & { - type: "eoa"; - }) - | (Erc4337SigningOptions & { - type: "ERC4337"; - }); + | (EoaSigningOptions & { + type: "eoa"; + }) + | (Erc4337SigningOptions & { + type: "ERC4337"; + }); /** * Execution Option Variants * All supported specific execution options are contained here */ export type SpecificExecutionOptions = - | ({ - type: "auto"; - } & AutoExecutionOptions) - | ({ - type: "ERC4337"; - } & Erc4337ExecutionOptions); + | (AutoExecutionOptions & { + type: "auto"; + }) + | (Erc4337ExecutionOptions & { + type: "ERC4337"; + }); export type SuccessResponseBatchResultsEncodeResultSuccessItem = { - /** - * Collection of results from multiple contract encode operations - */ - result: { - /** - * Array of results, one for each input contract call - */ - results: Array; - }; + /** + * Collection of results from multiple contract encode operations + */ + result: { + /** + * Array of results, one for each input contract call + */ + results: Array; + }; }; export type SuccessResponseBatchResultsReadResultSuccessItem = { - /** - * Collection of results from multiple contract encode operations - */ - result: { - /** - * Array of results, one for each input contract call - */ - results: Array; - }; + /** + * Collection of results from multiple contract encode operations + */ + result: { + /** + * Array of results, one for each input contract call + */ + results: Array; + }; }; export type SuccessResponseBatchResultsSignResultData = { - /** - * Collection of results from multiple contract encode operations - */ - result: { - /** - * Array of results, one for each input contract call - */ - results: Array; - }; + /** + * Collection of results from multiple contract encode operations + */ + result: { + /** + * Array of results, one for each input contract call + */ + results: Array; + }; }; export type SuccessResponseQueuedTransactionsResponse = { - result: { - transactions: Array; - }; + result: { + transactions: Array; + }; }; export type TransactionCancelResponse = { - transactionId: string; - result: CancelResult; + transactionId: string; + result: CancelResult; }; export type TypedDataDef = { - /** - * Signing domain metadata. The signing domain is the intended context for - * the signature (e.g. the dapp, protocol, etc. that it's intended for). - * This data is used to construct the domain separator of the message. - */ - domain: TypedDataDomainDef; - /** - * The custom types used by this message. - */ - types: unknown; - /** - * The type of the message. - */ - primaryType: string; - /** - * The message to be signed. - */ - message: unknown; + /** + * Signing domain metadata. The signing domain is the intended context for + * the signature (e.g. the dapp, protocol, etc. that it's intended for). + * This data is used to construct the domain separator of the message. + */ + domain: TypedDataDomainDef; + /** + * The custom types used by this message. + */ + types: unknown; + /** + * The type of the message. + */ + primaryType: string; + /** + * The message to be signed. + */ + message: unknown; }; export type TypedDataDomainDef = { - name?: string | null; - /** - * The current major version of the signing domain. Signatures from - * different versions are not compatible. - */ - version?: string | null; - chainId?: null | U256Def; - verifyingContract?: null | AddressDef; - /** - * A disambiguating salt for the protocol. This can be used as a domain - * separator of last resort. - */ - salt?: string | null; + name?: string | null; + /** + * The current major version of the signing domain. Signatures from + * different versions are not compatible. + */ + version?: string | null; + chainId?: null | U256Def; + verifyingContract?: null | AddressDef; + /** + * A disambiguating salt for the protocol. This can be used as a domain + * separator of last resort. + */ + salt?: string | null; }; /** @@ -926,704 +926,704 @@ export type U256Def = string; export type Value = unknown; export type WebhookOptions = { - url: string; - secret?: string | null; + url: string; + secret?: string | null; }; /** * Request to execute write transactions to smart contracts */ export type WriteContractRequest = { - /** - * Execution configuration including chain, account, and transaction options - */ - executionOptions: ExecutionOptions; - /** - * List of contract function calls to execute - * - * All calls will be executed in a single transaction if possible, - * or as separate transactions if atomic batching is not supported - */ - params: Array; - webhookOptions?: Array | null; + /** + * Execution configuration including chain, account, and transaction options + */ + executionOptions: ExecutionOptions; + /** + * List of contract function calls to execute + * + * All calls will be executed in a single transaction if possible, + * or as separate transactions if atomic batching is not supported + */ + params: Array; + webhookOptions?: Array | null; }; export type U64 = number; export type WriteContractData = { - /** - * Write contract request - */ - body: WriteContractRequest; - headers?: { - /** - * Thirdweb client ID, passed along with the service key - */ - "x-thirdweb-client-id"?: string | null; - /** - * Thirdweb service key, passed when using the client ID - */ - "x-thirdweb-service-key"?: string | null; - /** - * Thirdweb secret key, passed standalone - */ - "x-thirdweb-secret-key"?: string | null; - /** - * Vault access token - */ - "x-vault-access-token"?: string | null; - }; - path?: never; - query?: never; - url: "/v1/write/contract"; + /** + * Write contract request + */ + body: WriteContractRequest; + headers?: { + /** + * Thirdweb client ID, passed along with the service key + */ + "x-thirdweb-client-id"?: string | null; + /** + * Thirdweb service key, passed when using the client ID + */ + "x-thirdweb-service-key"?: string | null; + /** + * Thirdweb secret key, passed standalone + */ + "x-thirdweb-secret-key"?: string | null; + /** + * Vault access token + */ + "x-vault-access-token"?: string | null; + }; + path?: never; + query?: never; + url: "/v1/write/contract"; }; export type WriteContractResponses = { - /** - * Transaction(s) queued successfully - */ - 202: SuccessResponseQueuedTransactionsResponse; + /** + * Transaction(s) queued successfully + */ + 202: SuccessResponseQueuedTransactionsResponse; }; export type WriteContractResponse = - WriteContractResponses[keyof WriteContractResponses]; + WriteContractResponses[keyof WriteContractResponses]; export type SendTransactionData = { - /** - * Transaction request - */ - body: SendTransactionRequest; - headers?: { - /** - * Thirdweb client ID, passed along with the service key - */ - "x-thirdweb-client-id"?: string | null; - /** - * Thirdweb service key, passed when using the client ID - */ - "x-thirdweb-service-key"?: string | null; - /** - * Thirdweb secret key, passed standalone - */ - "x-thirdweb-secret-key"?: string | null; - /** - * Vault access token - */ - "x-vault-access-token"?: string | null; - }; - path?: never; - query?: never; - url: "/v1/write/transaction"; + /** + * Transaction request + */ + body: SendTransactionRequest; + headers?: { + /** + * Thirdweb client ID, passed along with the service key + */ + "x-thirdweb-client-id"?: string | null; + /** + * Thirdweb service key, passed when using the client ID + */ + "x-thirdweb-service-key"?: string | null; + /** + * Thirdweb secret key, passed standalone + */ + "x-thirdweb-secret-key"?: string | null; + /** + * Vault access token + */ + "x-vault-access-token"?: string | null; + }; + path?: never; + query?: never; + url: "/v1/write/transaction"; }; export type SendTransactionResponses = { - /** - * Transaction queued successfully - */ - 202: SuccessResponseQueuedTransactionsResponse; + /** + * Transaction queued successfully + */ + 202: SuccessResponseQueuedTransactionsResponse; }; export type SendTransactionResponse = - SendTransactionResponses[keyof SendTransactionResponses]; + SendTransactionResponses[keyof SendTransactionResponses]; export type SignMessageData = { - /** - * Sign message request - */ - body: SignMessageRequest; - headers?: { - /** - * Thirdweb client ID, passed along with the service key - */ - "x-thirdweb-client-id"?: string | null; - /** - * Thirdweb service key, passed when using the client ID - */ - "x-thirdweb-service-key"?: string | null; - /** - * Thirdweb secret key, passed standalone - */ - "x-thirdweb-secret-key"?: string | null; - /** - * Vault access token - */ - "x-vault-access-token"?: string | null; - }; - path?: never; - query?: never; - url: "/v1/sign/message"; + /** + * Sign message request + */ + body: SignMessageRequest; + headers?: { + /** + * Thirdweb client ID, passed along with the service key + */ + "x-thirdweb-client-id"?: string | null; + /** + * Thirdweb service key, passed when using the client ID + */ + "x-thirdweb-service-key"?: string | null; + /** + * Thirdweb secret key, passed standalone + */ + "x-thirdweb-secret-key"?: string | null; + /** + * Vault access token + */ + "x-vault-access-token"?: string | null; + }; + path?: never; + query?: never; + url: "/v1/sign/message"; }; export type SignMessageResponses = { - /** - * Successfully signed messages - */ - 200: SuccessResponseBatchResultsSignResultData; + /** + * Successfully signed messages + */ + 200: SuccessResponseBatchResultsSignResultData; }; export type SignMessageResponse = - SignMessageResponses[keyof SignMessageResponses]; + SignMessageResponses[keyof SignMessageResponses]; export type SignTypedDataData = { - /** - * Sign typed data request - */ - body: SignTypedDataRequest; - headers?: { - /** - * Thirdweb client ID, passed along with the service key - */ - "x-thirdweb-client-id"?: string | null; - /** - * Thirdweb service key, passed when using the client ID - */ - "x-thirdweb-service-key"?: string | null; - /** - * Thirdweb secret key, passed standalone - */ - "x-thirdweb-secret-key"?: string | null; - /** - * Vault access token - */ - "x-vault-access-token"?: string | null; - }; - path?: never; - query?: never; - url: "/v1/sign/typed-data"; + /** + * Sign typed data request + */ + body: SignTypedDataRequest; + headers?: { + /** + * Thirdweb client ID, passed along with the service key + */ + "x-thirdweb-client-id"?: string | null; + /** + * Thirdweb service key, passed when using the client ID + */ + "x-thirdweb-service-key"?: string | null; + /** + * Thirdweb secret key, passed standalone + */ + "x-thirdweb-secret-key"?: string | null; + /** + * Vault access token + */ + "x-vault-access-token"?: string | null; + }; + path?: never; + query?: never; + url: "/v1/sign/typed-data"; }; export type SignTypedDataResponses = { - /** - * Successfully signed typed data - */ - 200: SuccessResponseBatchResultsSignResultData; + /** + * Successfully signed typed data + */ + 200: SuccessResponseBatchResultsSignResultData; }; export type SignTypedDataResponse = - SignTypedDataResponses[keyof SignTypedDataResponses]; + SignTypedDataResponses[keyof SignTypedDataResponses]; export type ReadContractData = { - /** - * Read contract request - */ - body: ReadRequest; - headers?: { - /** - * Thirdweb client ID, passed along with the service key - */ - "x-thirdweb-client-id"?: string | null; - /** - * Thirdweb service key, passed when using the client ID - */ - "x-thirdweb-service-key"?: string | null; - /** - * Thirdweb secret key, passed standalone - */ - "x-thirdweb-secret-key"?: string | null; - }; - path?: never; - query?: never; - url: "/v1/read/contract"; + /** + * Read contract request + */ + body: ReadRequest; + headers?: { + /** + * Thirdweb client ID, passed along with the service key + */ + "x-thirdweb-client-id"?: string | null; + /** + * Thirdweb service key, passed when using the client ID + */ + "x-thirdweb-service-key"?: string | null; + /** + * Thirdweb secret key, passed standalone + */ + "x-thirdweb-secret-key"?: string | null; + }; + path?: never; + query?: never; + url: "/v1/read/contract"; }; export type ReadContractResponses = { - /** - * Successfully read contract data - */ - 200: SuccessResponseBatchResultsReadResultSuccessItem; + /** + * Successfully read contract data + */ + 200: SuccessResponseBatchResultsReadResultSuccessItem; }; export type ReadContractResponse = - ReadContractResponses[keyof ReadContractResponses]; + ReadContractResponses[keyof ReadContractResponses]; export type EncodeContractData = { - /** - * Encode contract request - */ - body: EncodeRequest; - headers?: { - /** - * Thirdweb client ID, passed along with the service key - */ - "x-thirdweb-client-id"?: string | null; - /** - * Thirdweb service key, passed when using the client ID - */ - "x-thirdweb-service-key"?: string | null; - /** - * Thirdweb secret key, passed standalone - */ - "x-thirdweb-secret-key"?: string | null; - }; - path?: never; - query?: never; - url: "/v1/encode/contract"; + /** + * Encode contract request + */ + body: EncodeRequest; + headers?: { + /** + * Thirdweb client ID, passed along with the service key + */ + "x-thirdweb-client-id"?: string | null; + /** + * Thirdweb service key, passed when using the client ID + */ + "x-thirdweb-service-key"?: string | null; + /** + * Thirdweb secret key, passed standalone + */ + "x-thirdweb-secret-key"?: string | null; + }; + path?: never; + query?: never; + url: "/v1/encode/contract"; }; export type EncodeContractResponses = { - /** - * Successfully encoded contract calls - */ - 200: SuccessResponseBatchResultsEncodeResultSuccessItem; + /** + * Successfully encoded contract calls + */ + 200: SuccessResponseBatchResultsEncodeResultSuccessItem; }; export type EncodeContractResponse = - EncodeContractResponses[keyof EncodeContractResponses]; + EncodeContractResponses[keyof EncodeContractResponses]; export type CancelTransactionData = { - body?: never; - path: { - /** - * Transaction ID to cancel - */ - id: string; - }; - query?: never; - url: "/v1/transactions/{id}/cancel"; + body?: never; + path: { + /** + * Transaction ID to cancel + */ + id: string; + }; + query?: never; + url: "/v1/transactions/{id}/cancel"; }; export type CancelTransactionResponses = { - /** - * Transaction cancellation result - */ - 200: TransactionCancelResponse; + /** + * Transaction cancellation result + */ + 200: TransactionCancelResponse; }; export type CancelTransactionResponse = - CancelTransactionResponses[keyof CancelTransactionResponses]; + CancelTransactionResponses[keyof CancelTransactionResponses]; export type ListAccountsData = { - body?: never; - path?: never; - query?: never; - url: "/v1/accounts"; + body?: never; + path?: never; + query?: never; + url: "/v1/accounts"; }; export type ListAccountsResponses = { - /** - * Accounts retrieved successfully - */ - 200: { - result: Array<{ - /** - * EVM address in hex format - */ - address: string; - label?: string; - /** - * The predicted smart account address for use with the default thirdweb v0.7 AccountFactory - */ - smartAccountAddress?: string; - }>; - }; + /** + * Accounts retrieved successfully + */ + 200: { + result: Array<{ + /** + * EVM address in hex format + */ + address: string; + label?: string; + /** + * The predicted smart account address for use with the default thirdweb v0.7 AccountFactory + */ + smartAccountAddress?: string; + }>; + }; }; export type ListAccountsResponse = - ListAccountsResponses[keyof ListAccountsResponses]; + ListAccountsResponses[keyof ListAccountsResponses]; export type CreateAccountData = { - body?: { - label: string; - }; - headers?: { - /** - * Vault Access Token used to access your EOA - */ - "x-vault-access-token"?: string; - }; - path?: never; - query?: never; - url: "/v1/accounts"; + body?: { + label: string; + }; + headers?: { + /** + * Vault Access Token used to access your EOA + */ + "x-vault-access-token"?: string; + }; + path?: never; + query?: never; + url: "/v1/accounts"; }; export type CreateAccountResponses = { - /** - * Account created successfully - */ - 201: { - result: { - /** - * EVM address in hex format - */ - address: string; - label?: string; - /** - * The predicted smart account address for use with the default thirdweb v0.7 AccountFactory - */ - smartAccountAddress?: string; - }; - }; + /** + * Account created successfully + */ + 201: { + result: { + /** + * EVM address in hex format + */ + address: string; + label?: string; + /** + * The predicted smart account address for use with the default thirdweb v0.7 AccountFactory + */ + smartAccountAddress?: string; + }; + }; }; export type CreateAccountResponse = - CreateAccountResponses[keyof CreateAccountResponses]; + CreateAccountResponses[keyof CreateAccountResponses]; export type GetTransactionsData = { - body?: never; - path?: never; - query?: { - page?: number; - limit?: number; - id?: string; - batchIndex?: number; - /** - * EVM address in hex format - */ - from?: string; - /** - * EVM address in hex format - */ - signerAddress?: string; - sortBy?: "createdAt" | "confirmedAt"; - sortDirection?: "asc" | "desc"; - }; - url: "/v1/transactions"; + body?: never; + path?: never; + query?: { + page?: number; + limit?: number; + id?: string; + batchIndex?: number; + /** + * EVM address in hex format + */ + from?: string; + /** + * EVM address in hex format + */ + signerAddress?: string; + sortBy?: "createdAt" | "confirmedAt"; + sortDirection?: "asc" | "desc"; + }; + url: "/v1/transactions"; }; export type GetTransactionsResponses = { - /** - * Transactions - */ - 200: { - result: { - transactions: Array<{ - id: string; - batchIndex: number; - clientId: string; - chainId: string; - from: string | null; - transactionParams: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - transactionHash: string | null; - confirmedAt: string | null; - confirmedAtBlockNumber: string | null; - enrichedData: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - executionParams: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - executionResult: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array - | null; - createdAt: string; - errorMessage: string | null; - cancelledAt: string | null; - }>; - pagination: { - totalCount: number; - page: number; - limit: number; - }; - }; - }; + /** + * Transactions + */ + 200: { + result: { + transactions: Array<{ + id: string; + batchIndex: number; + clientId: string; + chainId: string; + from: string | null; + transactionParams: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array; + transactionHash: string | null; + confirmedAt: string | null; + confirmedAtBlockNumber: string | null; + enrichedData: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array; + executionParams: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array; + executionResult: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array + | null; + createdAt: string; + errorMessage: string | null; + cancelledAt: string | null; + }>; + pagination: { + totalCount: number; + page: number; + limit: number; + }; + }; + }; }; export type GetTransactionsResponse = - GetTransactionsResponses[keyof GetTransactionsResponses]; + GetTransactionsResponses[keyof GetTransactionsResponses]; export type GetTransactionAnalyticsData = { - body?: { - startDate: string; - endDate: string; - resolution: "hour" | "day" | "week" | "month"; - filters?: Array; - filtersOperation?: "AND" | "OR"; - }; - path?: never; - query?: never; - url: "/v1/transactions/analytics"; + body?: { + startDate: string; + endDate: string; + resolution: "hour" | "day" | "week" | "month"; + filters?: Array; + filtersOperation?: "AND" | "OR"; + }; + path?: never; + query?: never; + url: "/v1/transactions/analytics"; }; export type GetTransactionAnalyticsResponses = { - /** - * Transaction Analytics - */ - 200: { - result: { - analytics: Array<{ - timeBucket: string; - chainId: string; - count: number; - }>; - metadata: { - resolution: "hour" | "day" | "week" | "month"; - startDate: string; - endDate: string; - }; - }; - }; + /** + * Transaction Analytics + */ + 200: { + result: { + analytics: Array<{ + timeBucket: string; + chainId: string; + count: number; + }>; + metadata: { + resolution: "hour" | "day" | "week" | "month"; + startDate: string; + endDate: string; + }; + }; + }; }; export type GetTransactionAnalyticsResponse = - GetTransactionAnalyticsResponses[keyof GetTransactionAnalyticsResponses]; + GetTransactionAnalyticsResponses[keyof GetTransactionAnalyticsResponses]; export type GetTransactionAnalyticsSummaryData = { - body?: { - startDate?: string; - endDate?: string; - filters?: Array; - filtersOperation?: "AND" | "OR"; - }; - path?: never; - query?: never; - url: "/v1/transactions/analytics-summary"; + body?: { + startDate?: string; + endDate?: string; + filters?: Array; + filtersOperation?: "AND" | "OR"; + }; + path?: never; + query?: never; + url: "/v1/transactions/analytics-summary"; }; export type GetTransactionAnalyticsSummaryErrors = { - /** - * Bad Request (e.g., invalid date format, filter depth exceeded) - */ - 400: unknown; - /** - * Internal Server Error (e.g., database error) - */ - 500: unknown; + /** + * Bad Request (e.g., invalid date format, filter depth exceeded) + */ + 400: unknown; + /** + * Internal Server Error (e.g., database error) + */ + 500: unknown; }; export type GetTransactionAnalyticsSummaryResponses = { - /** - * Transaction Analytics Summary - */ - 200: { - result: { - summary: { - /** - * Total number of transactions matching the criteria. - */ - totalCount: number; - /** - * Sum of actualGasCost (in wei) for all matching transactions, as a string. - */ - totalGasCostWei: string; - /** - * Sum of actualGasUsed (gas units) for all matching transactions, as a string. - */ - totalGasUnitsUsed: string; - }; - metadata: { - startDate?: string; - endDate?: string; - }; - }; - }; + /** + * Transaction Analytics Summary + */ + 200: { + result: { + summary: { + /** + * Total number of transactions matching the criteria. + */ + totalCount: number; + /** + * Sum of actualGasCost (in wei) for all matching transactions, as a string. + */ + totalGasCostWei: string; + /** + * Sum of actualGasUsed (gas units) for all matching transactions, as a string. + */ + totalGasUnitsUsed: string; + }; + metadata: { + startDate?: string; + endDate?: string; + }; + }; + }; }; export type GetTransactionAnalyticsSummaryResponse = - GetTransactionAnalyticsSummaryResponses[keyof GetTransactionAnalyticsSummaryResponses]; + GetTransactionAnalyticsSummaryResponses[keyof GetTransactionAnalyticsSummaryResponses]; export type SearchTransactionsData = { - body?: { - page?: number; - limit?: number; - filters?: Array; - filtersOperation?: "AND" | "OR"; - sortBy?: "createdAt" | "confirmedAt"; - sortDirection?: "asc" | "desc"; - }; - path?: never; - query?: never; - url: "/v1/transactions/search"; + body?: { + page?: number; + limit?: number; + filters?: Array; + filtersOperation?: "AND" | "OR"; + sortBy?: "createdAt" | "confirmedAt"; + sortDirection?: "asc" | "desc"; + }; + path?: never; + query?: never; + url: "/v1/transactions/search"; }; export type SearchTransactionsResponses = { - /** - * Transactions - */ - 200: { - result: { - transactions: Array<{ - id: string; - batchIndex: number; - clientId: string; - chainId: string; - from: string | null; - transactionParams: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - transactionHash: string | null; - confirmedAt: string | null; - confirmedAtBlockNumber: string | null; - enrichedData: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - executionParams: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - executionResult: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array - | null; - createdAt: string; - errorMessage: string | null; - cancelledAt: string | null; - }>; - pagination: { - totalCount: number; - page: number; - limit: number; - }; - }; - }; + /** + * Transactions + */ + 200: { + result: { + transactions: Array<{ + id: string; + batchIndex: number; + clientId: string; + chainId: string; + from: string | null; + transactionParams: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array; + transactionHash: string | null; + confirmedAt: string | null; + confirmedAtBlockNumber: string | null; + enrichedData: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array; + executionParams: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array; + executionResult: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array + | null; + createdAt: string; + errorMessage: string | null; + cancelledAt: string | null; + }>; + pagination: { + totalCount: number; + page: number; + limit: number; + }; + }; + }; }; export type SearchTransactionsResponse = - SearchTransactionsResponses[keyof SearchTransactionsResponses]; + SearchTransactionsResponses[keyof SearchTransactionsResponses]; export type GetActivityLogsData = { - body?: never; - path?: never; - query: { - page?: number; - limit?: number; - transactionId: string; - batchIndex?: number; - eventType?: "SUCCESS" | "FAILURE" | "NACK"; - stageName?: string; - executorName?: string; - sortBy?: "timestamp" | "createdAt"; - sortDirection?: "asc" | "desc"; - }; - url: "/v1/transactions/activity-logs"; + body?: never; + path?: never; + query: { + page?: number; + limit?: number; + transactionId: string; + batchIndex?: number; + eventType?: "SUCCESS" | "FAILURE" | "NACK"; + stageName?: string; + executorName?: string; + sortBy?: "timestamp" | "createdAt"; + sortDirection?: "asc" | "desc"; + }; + url: "/v1/transactions/activity-logs"; }; export type GetActivityLogsErrors = { - /** - * Invalid request parameters - */ - 400: unknown; - /** - * Transaction not found or not accessible - */ - 404: unknown; + /** + * Invalid request parameters + */ + 400: unknown; + /** + * Transaction not found or not accessible + */ + 404: unknown; }; export type GetActivityLogsResponses = { - /** - * Activity Logs - */ - 200: { - result: { - activityLogs: Array<{ - id: string; - transactionId: string; - batchIndex: number; - eventType: string; - stageName: string; - executorName: string; - notificationId: string; - payload: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - timestamp: string; - createdAt: string; - }>; - transaction: { - id: string; - batchIndex: number; - clientId: string; - }; - pagination: { - totalCount: number; - page: number; - limit: number; - }; - }; - }; + /** + * Activity Logs + */ + 200: { + result: { + activityLogs: Array<{ + id: string; + transactionId: string; + batchIndex: number; + eventType: string; + stageName: string; + executorName: string; + notificationId: string; + payload: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array; + timestamp: string; + createdAt: string; + }>; + transaction: { + id: string; + batchIndex: number; + clientId: string; + }; + pagination: { + totalCount: number; + page: number; + limit: number; + }; + }; + }; }; export type GetActivityLogsResponse = - GetActivityLogsResponses[keyof GetActivityLogsResponses]; + GetActivityLogsResponses[keyof GetActivityLogsResponses]; export type SearchActivityLogsData = { - body?: { - page?: number; - limit?: number; - transactionIds?: Array; - eventType?: "SUCCESS" | "FAILURE" | "NACK"; - stageName?: string; - executorName?: string; - startDate?: string; - endDate?: string; - sortBy?: "timestamp" | "createdAt"; - sortDirection?: "asc" | "desc"; - }; - path?: never; - query?: never; - url: "/v1/transactions/activity-logs/search"; + body?: { + page?: number; + limit?: number; + transactionIds?: Array; + eventType?: "SUCCESS" | "FAILURE" | "NACK"; + stageName?: string; + executorName?: string; + startDate?: string; + endDate?: string; + sortBy?: "timestamp" | "createdAt"; + sortDirection?: "asc" | "desc"; + }; + path?: never; + query?: never; + url: "/v1/transactions/activity-logs/search"; }; export type SearchActivityLogsErrors = { - /** - * Invalid request parameters - */ - 400: unknown; + /** + * Invalid request parameters + */ + 400: unknown; }; export type SearchActivityLogsResponses = { - /** - * Activity Logs Search Results - */ - 200: { - result: { - activityLogs: Array<{ - id: string; - transactionId: string; - batchIndex: number; - eventType: string; - stageName: string; - executorName: string; - notificationId: string; - payload: - | (string | number | boolean | null) - | { - [key: string]: unknown; - } - | Array; - timestamp: string; - createdAt: string; - }>; - pagination: { - totalCount: number; - page: number; - limit: number; - }; - }; - }; + /** + * Activity Logs Search Results + */ + 200: { + result: { + activityLogs: Array<{ + id: string; + transactionId: string; + batchIndex: number; + eventType: string; + stageName: string; + executorName: string; + notificationId: string; + payload: + | (string | number | boolean | null) + | { + [key: string]: unknown; + } + | Array; + timestamp: string; + createdAt: string; + }>; + pagination: { + totalCount: number; + page: number; + limit: number; + }; + }; + }; }; export type SearchActivityLogsResponse = - SearchActivityLogsResponses[keyof SearchActivityLogsResponses]; + SearchActivityLogsResponses[keyof SearchActivityLogsResponses]; export type ClientOptions = { - baseUrl: "http://localhost:3001" | (string & {}); + baseUrl: "http://localhost:3001" | (string & {}); }; From 56d7dd59d45896405d7016cd460ab8e3cedff5cd Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Thu, 26 Jun 2025 08:37:52 +1200 Subject: [PATCH 05/18] lockfile --- pnpm-lock.yaml | 45 +++------------------------------------------ 1 file changed, 3 insertions(+), 42 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0a5e88a9065..020fdf929a4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1053,12 +1053,9 @@ importers: packages/engine: dependencies: -<<<<<<< HEAD '@hey-api/client-fetch': specifier: 0.10.0 - version: 0.10.0(@hey-api/openapi-ts@0.77.0(magicast@0.3.5)(typescript@5.8.3)) -======= ->>>>>>> origin/main + version: 0.10.0(@hey-api/openapi-ts@0.76.0(magicast@0.3.5)(typescript@5.8.3)) typescript: specifier: '>=5.0.4' version: 5.8.3 @@ -1067,13 +1064,8 @@ importers: specifier: 2.0.4 version: 2.0.4 '@hey-api/openapi-ts': -<<<<<<< HEAD - specifier: 0.77.0 - version: 0.77.0(magicast@0.3.5)(typescript@5.8.3) -======= specifier: 0.76.0 version: 0.76.0(magicast@0.3.5)(typescript@5.8.3) ->>>>>>> origin/main rimraf: specifier: 6.0.1 version: 6.0.1 @@ -3432,15 +3424,12 @@ packages: peerDependencies: react: '>= 16 || ^19.0.0-rc' -<<<<<<< HEAD '@hey-api/client-fetch@0.10.0': resolution: {integrity: sha512-C7vzj4t52qPiHCqjn1l8cRTI2p4pZCd7ViLtJDTHr5ZwI4sWOYC1tmv6bd529qqY6HFFbhGCz4TAZSwKAMJncg==} deprecated: Starting with v0.73.0, this package is bundled directly inside @hey-api/openapi-ts. peerDependencies: '@hey-api/openapi-ts': < 2 -======= ->>>>>>> origin/main '@hey-api/json-schema-ref-parser@1.0.6': resolution: {integrity: sha512-yktiFZoWPtEW8QKS65eqKwA5MTKp88CyiL8q72WynrBs/73SAaxlSWlA2zW/DZlywZ5hX1OYzrCC0wFdvO9c2w==} engines: {node: '>= 16'} @@ -3452,13 +3441,6 @@ packages: peerDependencies: typescript: ^5.5.3 - '@hey-api/openapi-ts@0.77.0': - resolution: {integrity: sha512-HAJbd8QfxeBPZ788Ghiw7bzzzTKxW+wW+34foleEztyZJnRV20barvevu8YAK1BtyiIGIpEtAfoqO8KUj4VuBw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=22.10.0} - hasBin: true - peerDependencies: - typescript: ^5.5.3 - '@hookform/resolvers@3.10.0': resolution: {integrity: sha512-79Dv+3mDF7i+2ajj7SkypSKHhl1cbln1OGavqrsF7p6mbUv11xpqpacPsGDCTRvCSjEEIez2ef1NveSVL3b0Ag==} peerDependencies: @@ -7549,7 +7531,6 @@ packages: '@walletconnect/modal@2.7.0': resolution: {integrity: sha512-RQVt58oJ+rwqnPcIvRFeMGKuXb9qkgSmwz4noF8JZGUym3gUAzVs+uW2NQ1Owm9XOJAV+sANrtJ+VoVq1ftElw==} - deprecated: Please follow the migration guide on https://docs.reown.com/appkit/upgrade/wcm '@walletconnect/react-native-compat@2.17.3': resolution: {integrity: sha512-lHKwXKoB0rdDH1ukxUx7o86xosWbttWIHYMZ8tgAQC1k9VH3CZZCoBcHOAAX8iBzyb0n0UP3/9zRrOcJE5nz7Q==} @@ -19368,17 +19349,10 @@ snapshots: dependencies: react: 19.1.0 -<<<<<<< HEAD - '@hey-api/client-fetch@0.10.0(@hey-api/openapi-ts@0.72.1(magicast@0.3.5)(typescript@5.8.3))': + '@hey-api/client-fetch@0.10.0(@hey-api/openapi-ts@0.76.0(magicast@0.3.5)(typescript@5.8.3))': dependencies: - '@hey-api/openapi-ts': 0.72.1(magicast@0.3.5)(typescript@5.8.3) + '@hey-api/openapi-ts': 0.76.0(magicast@0.3.5)(typescript@5.8.3) - '@hey-api/client-fetch@0.10.0(@hey-api/openapi-ts@0.77.0(magicast@0.3.5)(typescript@5.8.3))': - dependencies: - '@hey-api/openapi-ts': 0.77.0(magicast@0.3.5)(typescript@5.8.3) - -======= ->>>>>>> origin/main '@hey-api/json-schema-ref-parser@1.0.6': dependencies: '@jsdevtools/ono': 7.1.3 @@ -19399,19 +19373,6 @@ snapshots: transitivePeerDependencies: - magicast - '@hey-api/openapi-ts@0.77.0(magicast@0.3.5)(typescript@5.8.3)': - dependencies: - '@hey-api/json-schema-ref-parser': 1.0.6 - ansi-colors: 4.1.3 - c12: 2.0.1(magicast@0.3.5) - color-support: 1.1.3 - commander: 13.0.0 - handlebars: 4.7.8 - open: 10.1.2 - typescript: 5.8.3 - transitivePeerDependencies: - - magicast - '@hookform/resolvers@3.10.0(react-hook-form@7.55.0(react@19.1.0))': dependencies: react-hook-form: 7.55.0(react@19.1.0) From 8d9b5c00e29aef4e335e653903f8943314fb13ab Mon Sep 17 00:00:00 2001 From: Prithvish Baidya Date: Thu, 26 Jun 2025 03:29:30 +0530 Subject: [PATCH 06/18] SDK codegen + signature options --- packages/engine/package.json | 2 +- packages/engine/src/client/client/client.ts | 4 + packages/engine/src/client/core/types.ts | 6 + packages/engine/src/client/types.gen.ts | 13 +- packages/thirdweb/src/engine/server-wallet.ts | 608 +++++++++--------- 5 files changed, 323 insertions(+), 310 deletions(-) diff --git a/packages/engine/package.json b/packages/engine/package.json index 452f88cda6f..642989ed361 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -24,7 +24,7 @@ ], "devDependencies": { "@biomejs/biome": "2.0.4", - "@hey-api/openapi-ts": "0.76.0", + "@hey-api/openapi-ts": "0.77.0", "rimraf": "6.0.1", "tslib": "^2.8.1" }, diff --git a/packages/engine/src/client/client/client.ts b/packages/engine/src/client/client/client.ts index 0b528190390..62280abd079 100644 --- a/packages/engine/src/client/client/client.ts +++ b/packages/engine/src/client/client/client.ts @@ -46,6 +46,10 @@ export const createClient = (config: Config = {}): Client => { }); } + if (opts.requestValidator) { + await opts.requestValidator(opts); + } + if (opts.body && opts.bodySerializer) { opts.body = opts.bodySerializer(opts.body); } diff --git a/packages/engine/src/client/core/types.ts b/packages/engine/src/client/core/types.ts index e5ee754b86e..dfa9e32739b 100644 --- a/packages/engine/src/client/core/types.ts +++ b/packages/engine/src/client/core/types.ts @@ -84,6 +84,12 @@ export interface Config { * {@link https://swagger.io/docs/specification/serialization/#query View examples} */ querySerializer?: QuerySerializer | QuerySerializerOptions; + /** + * A function validating request data. This is useful if you want to ensure + * the request conforms to the desired shape, so it can be safely sent to + * the server. + */ + requestValidator?: (data: unknown) => Promise; /** * A function transforming response data before it's returned. This is useful * for post-processing data, e.g. converting ISO strings into Date objects. diff --git a/packages/engine/src/client/types.gen.ts b/packages/engine/src/client/types.gen.ts index 19b8dfeb281..ec2db556687 100644 --- a/packages/engine/src/client/types.gen.ts +++ b/packages/engine/src/client/types.gen.ts @@ -819,7 +819,18 @@ export type SigningOptions = }) | (Erc4337SigningOptions & { type: "ERC4337"; - }); + }) + | { + type: "auto"; + /** + * The address to sign from + */ + from: string; + /** + * The chain ID for the signing operation + */ + chainId: number; + }; /** * Execution Option Variants diff --git a/packages/thirdweb/src/engine/server-wallet.ts b/packages/thirdweb/src/engine/server-wallet.ts index 3b573826071..f4fd9e3ff49 100644 --- a/packages/thirdweb/src/engine/server-wallet.ts +++ b/packages/thirdweb/src/engine/server-wallet.ts @@ -1,10 +1,10 @@ import { - type SendTransactionData, - type SignMessageData, - type SpecificExecutionOptions, - sendTransaction, - signMessage, - signTypedData, + type SendTransactionData, + type SignMessageData, + type SpecificExecutionOptions, + sendTransaction, + signMessage, + signTypedData, } from "@thirdweb-dev/engine"; import type { Chain } from "../chains/types.js"; import type { ThirdwebClient } from "../client/client.js"; @@ -18,8 +18,8 @@ import { stringify } from "../utils/json.js"; import { resolvePromisedValue } from "../utils/promise/resolve-promised-value.js"; import type { Prettify } from "../utils/type-utils.js"; import type { - Account, - SendTransactionOption, + Account, + SendTransactionOption, } from "../wallets/interfaces/wallet.js"; import { waitForTransactionHash } from "./wait-for-tx-hash.js"; @@ -29,36 +29,36 @@ type ExecutionOptions = Prettify; * Options for creating an server wallet. */ export type ServerWalletOptions = { - /** - * The thirdweb client to use for authentication to thirdweb services. - */ - client: ThirdwebClient; - /** - * The vault access token to use your server wallet. - */ - vaultAccessToken: string; - /** - * The server wallet address to use for sending transactions inside engine. - */ - address: string; - /** - * The chain to use for signing messages and typed data (smart server wallet only). - */ - chain?: Chain; - /** - * Optional custom execution options to use for sending transactions and signing data. - */ - executionOptions?: ExecutionOptions; + /** + * The thirdweb client to use for authentication to thirdweb services. + */ + client: ThirdwebClient; + /** + * The vault access token to use your server wallet. + */ + vaultAccessToken: string; + /** + * The server wallet address to use for sending transactions inside engine. + */ + address: string; + /** + * The chain to use for signing messages and typed data (smart server wallet only). + */ + chain?: Chain; + /** + * Optional custom execution options to use for sending transactions and signing data. + */ + executionOptions?: ExecutionOptions; }; export type ServerWallet = Account & { - enqueueTransaction: (args: { - transaction: PreparedTransaction; - simulate?: boolean; - }) => Promise<{ transactionId: string }>; - enqueueBatchTransaction: (args: { - transactions: PreparedTransaction[]; - }) => Promise<{ transactionId: string }>; + enqueueTransaction: (args: { + transaction: PreparedTransaction; + simulate?: boolean; + }) => Promise<{ transactionId: string }>; + enqueueBatchTransaction: (args: { + transactions: PreparedTransaction[]; + }) => Promise<{ transactionId: string }>; }; /** @@ -148,297 +148,289 @@ export type ServerWallet = Account & { * ``` */ export function serverWallet(options: ServerWalletOptions): ServerWallet { - const { client, vaultAccessToken, address, chain, executionOptions } = - options; + const { client, vaultAccessToken, address, chain, executionOptions } = + options; - const headers: HeadersInit = { - "x-vault-access-token": vaultAccessToken, - }; + const headers: HeadersInit = { + "x-vault-access-token": vaultAccessToken, + }; - const getExecutionOptionsWithChainId = ( - chainId: number, - ): SendTransactionData["body"]["executionOptions"] => { - if (!executionOptions) { - return { - chainId, - from: address, - type: "auto", - }; - } - switch (executionOptions.type) { - case "auto": - return { - chainId, - from: address, - type: "auto", - }; - case "ERC4337": - return { - ...executionOptions, - chainId, - type: "ERC4337", - }; - } - }; + const getExecutionOptionsWithChainId = ( + chainId: number, + ): SendTransactionData["body"]["executionOptions"] => { + if (!executionOptions) { + return { + chainId, + from: address, + type: "auto", + }; + } + switch (executionOptions.type) { + case "auto": + return { + chainId, + from: address, + type: "auto", + }; + case "ERC4337": + return { + ...executionOptions, + chainId, + type: "ERC4337", + }; + } + }; - const getSigningOptions = ( - chainId: number | undefined, - ): SignMessageData["body"]["signingOptions"] => { - // if no chainId passed specifically for this signature - // we HAVE TO fallback to EOA signature - if (!chainId) { - return { - from: address, - type: "eoa", - }; - } + const getSigningOptions = ( + chainId: number | undefined, + ): SignMessageData["body"]["signingOptions"] => { + // if no chainId passed specifically for this signature + // we HAVE TO fallback to EOA signature + if (!chainId) { + return { + from: address, + type: "eoa", + }; + } - // todo - // ServerWallet needs to have an async initialisation phase - // where it fetches details about the wallet from engine cloud - // engine cloud needs to provide an endpoint to "find" a wallet, by either smart account address or EOA address - // after "inrospection", server wallet always knows both the signer as well as smart account address - // regardless of what address was passed in - if (!executionOptions) { - // let's default to 4337 - return { - chainId, - signerAddress: address, - type: "ERC4337", - }; - } + if (!executionOptions) { + return { + chainId, + from: address, + type: "auto", + }; + } - switch (executionOptions.type) { - case "ERC4337": { - return { - chainId, - // smartAccountAddress: address, - signerAddress: address, - type: "ERC4337", - }; - } + switch (executionOptions.type) { + case "ERC4337": { + return { + chainId, + ...executionOptions, + type: "ERC4337", + }; + } - case "auto": { - return { - chainId, - // smartAccountAddress: address, - signerAddress: address, - type: "ERC4337", - }; - } + case "auto": { + return { + chainId, + // smartAccountAddress: address, + from: address, + type: "auto", + }; + } - // case "eoa": { - // return { - // chainId, - // from: address, - // } - } - }; + // case "eoa": { + // return { + // chainId, + // from: address, + // } + } + }; - const enqueueTx = async (transaction: SendTransactionOption[]) => { - if (transaction.length === 0) { - throw new Error("No transactions to enqueue"); - } - const firstTransaction = transaction[0]; - if (!firstTransaction) { - throw new Error("No transactions to enqueue"); - } - const chainId = firstTransaction.chainId; - // Validate all transactions are on the same chain - for (let i = 1; i < transaction.length; i++) { - if (transaction[i]?.chainId !== chainId) { - throw new Error( - `All transactions in batch must be on the same chain. Expected ${chainId}, got ${transaction[i]?.chainId} at index ${i}`, - ); - } - } - const body = { - executionOptions: getExecutionOptionsWithChainId(chainId), - params: transaction.map((t) => ({ - data: t.data || "0x", - to: t.to ?? "", // TODO this should be allowed to be undefined - value: t.value?.toString() || "0", - })), - }; + const enqueueTx = async (transaction: SendTransactionOption[]) => { + if (transaction.length === 0) { + throw new Error("No transactions to enqueue"); + } + const firstTransaction = transaction[0]; + if (!firstTransaction) { + throw new Error("No transactions to enqueue"); + } + const chainId = firstTransaction.chainId; + // Validate all transactions are on the same chain + for (let i = 1; i < transaction.length; i++) { + if (transaction[i]?.chainId !== chainId) { + throw new Error( + `All transactions in batch must be on the same chain. Expected ${chainId}, got ${transaction[i]?.chainId} at index ${i}`, + ); + } + } + const body = { + executionOptions: getExecutionOptionsWithChainId(chainId), + params: transaction.map((t) => ({ + data: t.data || "0x", + to: t.to ?? "", // TODO this should be allowed to be undefined + value: t.value?.toString() || "0", + })), + }; - const result = await sendTransaction({ - baseUrl: getThirdwebBaseUrl("engineCloud"), - body, - bodySerializer: stringify, - fetch: getClientFetch(client), - headers, - }); + const result = await sendTransaction({ + baseUrl: getThirdwebBaseUrl("engineCloud"), + body, + bodySerializer: stringify, + fetch: getClientFetch(client), + headers, + }); - if (result.error) { - throw new Error(`Error sending transaction: ${stringify(result.error)}`); - } + if (result.error) { + throw new Error(`Error sending transaction: ${stringify(result.error)}`); + } - const data = result.data?.result; - if (!data) { - throw new Error("No data returned from engine"); - } - return data.transactions.map((t) => t.id); - }; + const data = result.data?.result; + if (!data) { + throw new Error("No data returned from engine"); + } + return data.transactions.map((t) => t.id); + }; - return { - address, - enqueueBatchTransaction: async (args: { - transactions: PreparedTransaction[]; - }) => { - const serializedTransactions: SendTransactionOption[] = []; - for (const transaction of args.transactions) { - const [to, data, value] = await Promise.all([ - transaction.to ? resolvePromisedValue(transaction.to) : null, - encode(transaction), - transaction.value ? resolvePromisedValue(transaction.value) : null, - ]); - serializedTransactions.push({ - chainId: transaction.chain.id, - data, - to: to ?? undefined, - value: value ?? undefined, - }); - } - const transactionIds = await enqueueTx(serializedTransactions); - const transactionId = transactionIds[0]; - if (!transactionId) { - throw new Error("No transactionId returned from engine"); - } - return { transactionId }; - }, - enqueueTransaction: async (args: { - transaction: PreparedTransaction; - simulate?: boolean; - }) => { - let serializedTransaction: SendTransactionOption; - if (args.simulate) { - serializedTransaction = await toSerializableTransaction({ - transaction: args.transaction, - }); - } else { - const [to, data, value] = await Promise.all([ - args.transaction.to - ? resolvePromisedValue(args.transaction.to) - : null, - encode(args.transaction), - args.transaction.value - ? resolvePromisedValue(args.transaction.value) - : null, - ]); - serializedTransaction = { - chainId: args.transaction.chain.id, - data, - to: to ?? undefined, - value: value ?? undefined, - }; - } - const transactionIds = await enqueueTx([serializedTransaction]); - const transactionId = transactionIds[0]; - if (!transactionId) { - throw new Error("No transactionId returned from engine"); - } - return { transactionId }; - }, - sendBatchTransaction: async (transactions: SendTransactionOption[]) => { - const transactionIds = await enqueueTx(transactions); - const transactionId = transactionIds[0]; - if (!transactionId) { - throw new Error("No transactionId returned from engine"); - } - return waitForTransactionHash({ - client, - transactionId, - }); - }, - sendTransaction: async (transaction: SendTransactionOption) => { - const transactionIds = await enqueueTx([transaction]); - const transactionId = transactionIds[0]; - if (!transactionId) { - throw new Error("No transactionId returned from engine"); - } - return waitForTransactionHash({ - client, - transactionId, - }); - }, - signMessage: async (data) => { - const { message, chainId } = data; - let engineMessage: string | Hex; - let isBytes = false; - if (typeof message === "string") { - engineMessage = message; - } else { - engineMessage = toHex(message.raw); - isBytes = true; - } + return { + address, + enqueueBatchTransaction: async (args: { + transactions: PreparedTransaction[]; + }) => { + const serializedTransactions: SendTransactionOption[] = []; + for (const transaction of args.transactions) { + const [to, data, value] = await Promise.all([ + transaction.to ? resolvePromisedValue(transaction.to) : null, + encode(transaction), + transaction.value ? resolvePromisedValue(transaction.value) : null, + ]); + serializedTransactions.push({ + chainId: transaction.chain.id, + data, + to: to ?? undefined, + value: value ?? undefined, + }); + } + const transactionIds = await enqueueTx(serializedTransactions); + const transactionId = transactionIds[0]; + if (!transactionId) { + throw new Error("No transactionId returned from engine"); + } + return { transactionId }; + }, + enqueueTransaction: async (args: { + transaction: PreparedTransaction; + simulate?: boolean; + }) => { + let serializedTransaction: SendTransactionOption; + if (args.simulate) { + serializedTransaction = await toSerializableTransaction({ + transaction: args.transaction, + }); + } else { + const [to, data, value] = await Promise.all([ + args.transaction.to + ? resolvePromisedValue(args.transaction.to) + : null, + encode(args.transaction), + args.transaction.value + ? resolvePromisedValue(args.transaction.value) + : null, + ]); + serializedTransaction = { + chainId: args.transaction.chain.id, + data, + to: to ?? undefined, + value: value ?? undefined, + }; + } + const transactionIds = await enqueueTx([serializedTransaction]); + const transactionId = transactionIds[0]; + if (!transactionId) { + throw new Error("No transactionId returned from engine"); + } + return { transactionId }; + }, + sendBatchTransaction: async (transactions: SendTransactionOption[]) => { + const transactionIds = await enqueueTx(transactions); + const transactionId = transactionIds[0]; + if (!transactionId) { + throw new Error("No transactionId returned from engine"); + } + return waitForTransactionHash({ + client, + transactionId, + }); + }, + sendTransaction: async (transaction: SendTransactionOption) => { + const transactionIds = await enqueueTx([transaction]); + const transactionId = transactionIds[0]; + if (!transactionId) { + throw new Error("No transactionId returned from engine"); + } + return waitForTransactionHash({ + client, + transactionId, + }); + }, + signMessage: async (data) => { + const { message, chainId } = data; + let engineMessage: string | Hex; + let isBytes = false; + if (typeof message === "string") { + engineMessage = message; + } else { + engineMessage = toHex(message.raw); + isBytes = true; + } - const signingChainId = chainId || chain?.id; - if (!signingChainId) { - throw new Error("Chain ID is required for signing messages"); - } - const signResult = await signMessage({ - baseUrl: getThirdwebBaseUrl("engineCloud"), - body: { - params: [ - { - format: isBytes ? "hex" : "text", - message: engineMessage, - }, - ], - signingOptions: getSigningOptions(signingChainId), - }, - bodySerializer: stringify, - fetch: getClientFetch(client), - headers, - }); + const signingChainId = chainId || chain?.id; + if (!signingChainId) { + throw new Error("Chain ID is required for signing messages"); + } + const signResult = await signMessage({ + baseUrl: getThirdwebBaseUrl("engineCloud"), + body: { + params: [ + { + format: isBytes ? "hex" : "text", + message: engineMessage, + }, + ], + signingOptions: getSigningOptions(signingChainId), + }, + bodySerializer: stringify, + fetch: getClientFetch(client), + headers, + }); - if (signResult.error) { - throw new Error( - `Error signing message: ${stringify(signResult.error)}`, - ); - } + if (signResult.error) { + throw new Error( + `Error signing message: ${stringify(signResult.error)}`, + ); + } - const signatureResult = signResult.data?.result.results[0]; - if (signatureResult && "result" in signatureResult) { - return signatureResult.result.signature as Hex; - } + const signatureResult = signResult.data?.result.results[0]; + if (signatureResult && "result" in signatureResult) { + return signatureResult.result.signature as Hex; + } - throw new Error( - `Failed to sign message: ${stringify(signatureResult?.error) || "Unknown error"}`, - ); - }, - signTypedData: async (typedData) => { - const signingChainId = chain?.id; - if (!signingChainId) { - throw new Error("Chain ID is required for signing messages"); - } + throw new Error( + `Failed to sign message: ${stringify(signatureResult?.error) || "Unknown error"}`, + ); + }, + signTypedData: async (typedData) => { + const signingChainId = chain?.id; + if (!signingChainId) { + throw new Error("Chain ID is required for signing messages"); + } - const signResult = await signTypedData({ - baseUrl: getThirdwebBaseUrl("engineCloud"), - body: { - // biome-ignore lint/suspicious/noExplicitAny: TODO: fix ts / hey-api type clash - params: [typedData as any], - signingOptions: getSigningOptions(signingChainId), - }, - bodySerializer: stringify, - fetch: getClientFetch(client), - headers, - }); + const signResult = await signTypedData({ + baseUrl: getThirdwebBaseUrl("engineCloud"), + body: { + // biome-ignore lint/suspicious/noExplicitAny: TODO: fix ts / hey-api type clash + params: [typedData as any], + signingOptions: getSigningOptions(signingChainId), + }, + bodySerializer: stringify, + fetch: getClientFetch(client), + headers, + }); - if (signResult.error) { - throw new Error( - `Error signing message: ${stringify(signResult.error)}`, - ); - } + if (signResult.error) { + throw new Error( + `Error signing message: ${stringify(signResult.error)}`, + ); + } - const signatureResult = signResult.data?.result.results[0]; - if (signatureResult && "result" in signatureResult) { - return signatureResult.result.signature as Hex; - } + const signatureResult = signResult.data?.result.results[0]; + if (signatureResult && "result" in signatureResult) { + return signatureResult.result.signature as Hex; + } - throw new Error( - `Failed to sign message: ${stringify(signatureResult?.error) || "Unknown error"}`, - ); - }, - }; + throw new Error( + `Failed to sign message: ${stringify(signatureResult?.error) || "Unknown error"}`, + ); + }, + }; } From baec17f18d941b6cc3ecf1dec87fe679963f2a19 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Thu, 26 Jun 2025 11:15:41 +1200 Subject: [PATCH 07/18] lockfile --- pnpm-lock.yaml | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 020fdf929a4..0f48225a361 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1055,7 +1055,7 @@ importers: dependencies: '@hey-api/client-fetch': specifier: 0.10.0 - version: 0.10.0(@hey-api/openapi-ts@0.76.0(magicast@0.3.5)(typescript@5.8.3)) + version: 0.10.0(@hey-api/openapi-ts@0.77.0(magicast@0.3.5)(typescript@5.8.3)) typescript: specifier: '>=5.0.4' version: 5.8.3 @@ -1064,8 +1064,8 @@ importers: specifier: 2.0.4 version: 2.0.4 '@hey-api/openapi-ts': - specifier: 0.76.0 - version: 0.76.0(magicast@0.3.5)(typescript@5.8.3) + specifier: 0.77.0 + version: 0.77.0(magicast@0.3.5)(typescript@5.8.3) rimraf: specifier: 6.0.1 version: 6.0.1 @@ -3441,6 +3441,13 @@ packages: peerDependencies: typescript: ^5.5.3 + '@hey-api/openapi-ts@0.77.0': + resolution: {integrity: sha512-HAJbd8QfxeBPZ788Ghiw7bzzzTKxW+wW+34foleEztyZJnRV20barvevu8YAK1BtyiIGIpEtAfoqO8KUj4VuBw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=22.10.0} + hasBin: true + peerDependencies: + typescript: ^5.5.3 + '@hookform/resolvers@3.10.0': resolution: {integrity: sha512-79Dv+3mDF7i+2ajj7SkypSKHhl1cbln1OGavqrsF7p6mbUv11xpqpacPsGDCTRvCSjEEIez2ef1NveSVL3b0Ag==} peerDependencies: @@ -19349,9 +19356,9 @@ snapshots: dependencies: react: 19.1.0 - '@hey-api/client-fetch@0.10.0(@hey-api/openapi-ts@0.76.0(magicast@0.3.5)(typescript@5.8.3))': + '@hey-api/client-fetch@0.10.0(@hey-api/openapi-ts@0.77.0(magicast@0.3.5)(typescript@5.8.3))': dependencies: - '@hey-api/openapi-ts': 0.76.0(magicast@0.3.5)(typescript@5.8.3) + '@hey-api/openapi-ts': 0.77.0(magicast@0.3.5)(typescript@5.8.3) '@hey-api/json-schema-ref-parser@1.0.6': dependencies: @@ -19373,6 +19380,19 @@ snapshots: transitivePeerDependencies: - magicast + '@hey-api/openapi-ts@0.77.0(magicast@0.3.5)(typescript@5.8.3)': + dependencies: + '@hey-api/json-schema-ref-parser': 1.0.6 + ansi-colors: 4.1.3 + c12: 2.0.1(magicast@0.3.5) + color-support: 1.1.3 + commander: 13.0.0 + handlebars: 4.7.8 + open: 10.1.2 + typescript: 5.8.3 + transitivePeerDependencies: + - magicast + '@hookform/resolvers@3.10.0(react-hook-form@7.55.0(react@19.1.0))': dependencies: react-hook-form: 7.55.0(react@19.1.0) From a02f3bb5db911bd5a9f367daeb2576171f116032 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Thu, 26 Jun 2025 14:13:10 +1200 Subject: [PATCH 08/18] ui fixes, re-enable tests, stringify error --- .../tx/[id]/transaction-details-ui.tsx | 8 +++--- .../thirdweb/src/engine/server-wallet.test.ts | 25 +++++++++++-------- .../thirdweb/src/engine/wait-for-tx-hash.ts | 2 +- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/tx/[id]/transaction-details-ui.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/tx/[id]/transaction-details-ui.tsx index 840fb6ac7b3..637fac8fcec 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/tx/[id]/transaction-details-ui.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/tx/[id]/transaction-details-ui.tsx @@ -3,7 +3,7 @@ import { format, formatDistanceToNowStrict } from "date-fns"; import { ExternalLinkIcon, InfoIcon } from "lucide-react"; import Link from "next/link"; -import { type ThirdwebClient, toEther } from "thirdweb"; +import { hexToNumber, isHex, type ThirdwebClient, toEther } from "thirdweb"; import type { Project } from "@/api/projects"; import { WalletAddress } from "@/components/blocks/wallet-address"; import { Badge } from "@/components/ui/badge"; @@ -68,7 +68,7 @@ export function TransactionDetailsUI({ // Gas information const gasUsed = executionResult && "actualGasUsed" in executionResult - ? `${executionResult.actualGasUsed}` + ? `${isHex(executionResult.actualGasUsed) ? hexToNumber(executionResult.actualGasUsed) : executionResult.actualGasUsed}` : "N/A"; const gasCost = @@ -339,7 +339,9 @@ export function TransactionDetailsUI({ Block Number
- {transaction.confirmedAtBlockNumber} + {isHex(transaction.confirmedAtBlockNumber) + ? hexToNumber(transaction.confirmedAtBlockNumber) + : transaction.confirmedAtBlockNumber}
)} diff --git a/packages/thirdweb/src/engine/server-wallet.test.ts b/packages/thirdweb/src/engine/server-wallet.test.ts index 0b97392c8bc..ac62770339e 100644 --- a/packages/thirdweb/src/engine/server-wallet.test.ts +++ b/packages/thirdweb/src/engine/server-wallet.test.ts @@ -9,6 +9,7 @@ import { sepolia } from "../chains/chain-definitions/sepolia.js"; import { getContract } from "../contract/contract.js"; import { setContractURI } from "../extensions/common/__generated__/IContractMetadata/write/setContractURI.js"; import { mintTo } from "../extensions/erc20/write/mintTo.js"; +import { setApprovalForAll } from "../extensions/erc1155/__generated__/IERC1155/write/setApprovalForAll.js"; import { claimTo } from "../extensions/erc1155/drops/write/claimTo.js"; import { getAllActiveSigners } from "../extensions/erc4337/__generated__/IAccountPermissions/read/getAllActiveSigners.js"; import { sendTransaction } from "../transaction/actions/send-transaction.js"; @@ -44,13 +45,13 @@ describe.runIf( }); serverWallet = Engine.serverWallet({ address: process.env.ENGINE_CLOUD_WALLET_ADDRESS as string, - chain: arbitrumSepolia, + chain: sepolia, client: TEST_CLIENT, vaultAccessToken: process.env.VAULT_TOKEN as string, }); }); - it.skip("should create a server wallet", async () => { + it("should create a server wallet", async () => { const serverWallet = await Engine.createServerWallet({ client: TEST_CLIENT, label: "My Server Wallet", @@ -155,14 +156,14 @@ describe.runIf( it("should send a extension tx", async () => { const tokenContract = getContract({ - address: "0x87C52295891f208459F334975a3beE198fE75244", + address: "0x638263e3eAa3917a53630e61B1fBa685308024fa", chain: baseSepolia, client: TEST_CLIENT, }); - const claimTx = mintTo({ - amount: "0.001", + const claimTx = setApprovalForAll({ + approved: true, contract: tokenContract, - to: serverWallet.address, + operator: "0x4b8ceC1Eb227950F0bfd034449B2781e689242A1", }); const tx = await sendTransaction({ account: serverWallet, @@ -173,19 +174,21 @@ describe.runIf( it("should enqueue a batch of txs", async () => { const tokenContract = getContract({ - address: "0x87C52295891f208459F334975a3beE198fE75244", + address: "0x638263e3eAa3917a53630e61B1fBa685308024fa", chain: baseSepolia, client: TEST_CLIENT, }); - const claimTx1 = mintTo({ - amount: "0.001", + const claimTx1 = claimTo({ contract: tokenContract, + quantity: 1n, to: serverWallet.address, + tokenId: 2n, }); - const claimTx2 = mintTo({ - amount: "0.002", + const claimTx2 = claimTo({ contract: tokenContract, + quantity: 1n, to: serverWallet.address, + tokenId: 2n, }); const tx = await serverWallet.enqueueBatchTransaction({ transactions: [claimTx1, claimTx2], diff --git a/packages/thirdweb/src/engine/wait-for-tx-hash.ts b/packages/thirdweb/src/engine/wait-for-tx-hash.ts index dea317879ee..61ef63aa240 100644 --- a/packages/thirdweb/src/engine/wait-for-tx-hash.ts +++ b/packages/thirdweb/src/engine/wait-for-tx-hash.ts @@ -38,7 +38,7 @@ export async function waitForTransactionHash(args: { switch (status) { case "FAILED": { throw new Error( - `Transaction failed: ${executionResult.error || "Unknown error"}`, + `Transaction failed: ${stringify(executionResult.error) || "Unknown error"}`, ); } case "CONFIRMED": { From d0df911e82f7cc387c8a1f22fc458d26f05d0b37 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Fri, 27 Jun 2025 08:05:31 +1200 Subject: [PATCH 09/18] use entrypoint version --- .../thirdweb/src/engine/server-wallet.test.ts | 472 +++++++++--------- 1 file changed, 233 insertions(+), 239 deletions(-) diff --git a/packages/thirdweb/src/engine/server-wallet.test.ts b/packages/thirdweb/src/engine/server-wallet.test.ts index ac62770339e..9990c18439a 100644 --- a/packages/thirdweb/src/engine/server-wallet.test.ts +++ b/packages/thirdweb/src/engine/server-wallet.test.ts @@ -8,275 +8,269 @@ import { baseSepolia } from "../chains/chain-definitions/base-sepolia.js"; import { sepolia } from "../chains/chain-definitions/sepolia.js"; import { getContract } from "../contract/contract.js"; import { setContractURI } from "../extensions/common/__generated__/IContractMetadata/write/setContractURI.js"; -import { mintTo } from "../extensions/erc20/write/mintTo.js"; import { setApprovalForAll } from "../extensions/erc1155/__generated__/IERC1155/write/setApprovalForAll.js"; import { claimTo } from "../extensions/erc1155/drops/write/claimTo.js"; import { getAllActiveSigners } from "../extensions/erc4337/__generated__/IAccountPermissions/read/getAllActiveSigners.js"; import { sendTransaction } from "../transaction/actions/send-transaction.js"; import { setThirdwebDomains } from "../utils/domains.js"; -import { - DEFAULT_ACCOUNT_FACTORY_V0_6, - ENTRYPOINT_ADDRESS_v0_6, -} from "../wallets/smart/lib/constants.js"; import { smartWallet } from "../wallets/smart/smart-wallet.js"; import { generateAccount } from "../wallets/utils/generateAccount.js"; import * as Engine from "./index.js"; describe.runIf( - process.env.TW_SECRET_KEY && - process.env.VAULT_TOKEN && - process.env.ENGINE_CLOUD_WALLET_ADDRESS && - process.env.ENGINE_CLOUD_WALLET_ADDRESS_EOA, + process.env.TW_SECRET_KEY && + process.env.VAULT_TOKEN && + process.env.ENGINE_CLOUD_WALLET_ADDRESS && + process.env.ENGINE_CLOUD_WALLET_ADDRESS_EOA, )( - "Engine Cloud", - { - retry: 0, - }, - () => { - let serverWallet: Engine.ServerWallet; + "Engine Cloud", + { + retry: 0, + }, + () => { + let serverWallet: Engine.ServerWallet; - beforeAll(async () => { - setThirdwebDomains({ - bundler: "bundler.thirdweb-dev.com", - engineCloud: "engine.thirdweb-dev.com", - // engineCloud: "localhost:3009", - rpc: "rpc.thirdweb-dev.com", - storage: "storage.thirdweb-dev.com", - }); - serverWallet = Engine.serverWallet({ - address: process.env.ENGINE_CLOUD_WALLET_ADDRESS as string, - chain: sepolia, - client: TEST_CLIENT, - vaultAccessToken: process.env.VAULT_TOKEN as string, - }); - }); + beforeAll(async () => { + setThirdwebDomains({ + bundler: "bundler.thirdweb-dev.com", + engineCloud: "engine.thirdweb-dev.com", + // engineCloud: "localhost:3009", + rpc: "rpc.thirdweb-dev.com", + storage: "storage.thirdweb-dev.com", + }); + serverWallet = Engine.serverWallet({ + address: process.env.ENGINE_CLOUD_WALLET_ADDRESS as string, + chain: sepolia, + client: TEST_CLIENT, + vaultAccessToken: process.env.VAULT_TOKEN as string, + }); + }); - it("should create a server wallet", async () => { - const serverWallet = await Engine.createServerWallet({ - client: TEST_CLIENT, - label: "My Server Wallet", - }); - expect(serverWallet).toBeDefined(); + it("should create a server wallet", async () => { + const serverWallet = await Engine.createServerWallet({ + client: TEST_CLIENT, + label: "My Server Wallet", + }); + expect(serverWallet).toBeDefined(); - const serverWallets = await Engine.getServerWallets({ - client: TEST_CLIENT, - }); - expect(serverWallets).toBeDefined(); - expect(serverWallets.length).toBeGreaterThan(0); - expect( - serverWallets.find((s) => s.address === serverWallet.address), - ).toBeDefined(); - }); + const serverWallets = await Engine.getServerWallets({ + client: TEST_CLIENT, + }); + expect(serverWallets).toBeDefined(); + expect(serverWallets.length).toBeGreaterThan(0); + expect( + serverWallets.find((s) => s.address === serverWallet.address), + ).toBeDefined(); + }); - it("should sign a message", async () => { - const signature = await serverWallet.signMessage({ - message: "hello", - }); - expect(signature).toBeDefined(); - }); + it("should sign a message", async () => { + const signature = await serverWallet.signMessage({ + message: "hello", + }); + expect(signature).toBeDefined(); + }); - it("should sign typed data", async () => { - const signature = await serverWallet.signTypedData({ - ...typedData.basic, - }); - expect(signature).toBeDefined(); - }); + it("should sign typed data", async () => { + const signature = await serverWallet.signTypedData({ + ...typedData.basic, + }); + expect(signature).toBeDefined(); + }); - it("should sign typed data for EOA execution options", async () => { - const eoaServerWallet = Engine.serverWallet({ - address: process.env.ENGINE_CLOUD_WALLET_ADDRESS_EOA as string, - chain: arbitrumSepolia, - client: TEST_CLIENT, - vaultAccessToken: process.env.VAULT_TOKEN as string, - }); + it("should sign typed data for EOA execution options", async () => { + const eoaServerWallet = Engine.serverWallet({ + address: process.env.ENGINE_CLOUD_WALLET_ADDRESS_EOA as string, + chain: arbitrumSepolia, + client: TEST_CLIENT, + vaultAccessToken: process.env.VAULT_TOKEN as string, + }); - const signature = await eoaServerWallet.signTypedData({ - ...typedData.basic, - }); + const signature = await eoaServerWallet.signTypedData({ + ...typedData.basic, + }); - expect(signature).toBeDefined(); + expect(signature).toBeDefined(); - const is_valid = await verifyTypedData({ - address: process.env.ENGINE_CLOUD_WALLET_ADDRESS_EOA as string, - chain: arbitrumSepolia, - client: TEST_CLIENT, - ...typedData.basic, + const is_valid = await verifyTypedData({ + address: process.env.ENGINE_CLOUD_WALLET_ADDRESS_EOA as string, + chain: arbitrumSepolia, + client: TEST_CLIENT, + ...typedData.basic, - signature, - }); + signature, + }); - expect(is_valid).toBe(true); - }); + expect(is_valid).toBe(true); + }); - it("should send a tx with regular API", async () => { - const tx = await sendTransaction({ - account: serverWallet, - transaction: { - chain: arbitrumSepolia, - client: TEST_CLIENT, - to: TEST_ACCOUNT_B.address, - value: 0n, - }, - }); - expect(tx).toBeDefined(); - }); + it("should send a tx with regular API", async () => { + const tx = await sendTransaction({ + account: serverWallet, + transaction: { + chain: arbitrumSepolia, + client: TEST_CLIENT, + to: TEST_ACCOUNT_B.address, + value: 0n, + }, + }); + expect(tx).toBeDefined(); + }); - it("should enqueue a tx", async () => { - const nftContract = getContract({ - address: "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8", - chain: sepolia, - client: TEST_CLIENT, - }); - const claimTx = claimTo({ - contract: nftContract, - quantity: 1n, - to: serverWallet.address, - tokenId: 0n, - }); - const result = await serverWallet.enqueueTransaction({ - transaction: claimTx, - }); - expect(result.transactionId).toBeDefined(); - const txHash = await Engine.waitForTransactionHash({ - client: TEST_CLIENT, - transactionId: result.transactionId, - }); - expect(txHash.transactionHash).toBeDefined(); + it("should enqueue a tx", async () => { + const nftContract = getContract({ + address: "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8", + chain: sepolia, + client: TEST_CLIENT, + }); + const claimTx = claimTo({ + contract: nftContract, + quantity: 1n, + to: serverWallet.address, + tokenId: 0n, + }); + const result = await serverWallet.enqueueTransaction({ + transaction: claimTx, + }); + expect(result.transactionId).toBeDefined(); + const txHash = await Engine.waitForTransactionHash({ + client: TEST_CLIENT, + transactionId: result.transactionId, + }); + expect(txHash.transactionHash).toBeDefined(); - const res = await Engine.searchTransactions({ - client: TEST_CLIENT, - filters: [ - { field: "id", operation: "OR", values: [result.transactionId] }, - ], - }); - expect(res).toBeDefined(); - expect(res.transactions.length).toBe(1); - expect(res.transactions[0]?.id).toBe(result.transactionId); - }); + const res = await Engine.searchTransactions({ + client: TEST_CLIENT, + filters: [ + { field: "id", operation: "OR", values: [result.transactionId] }, + ], + }); + expect(res).toBeDefined(); + expect(res.transactions.length).toBe(1); + expect(res.transactions[0]?.id).toBe(result.transactionId); + }); - it("should send a extension tx", async () => { - const tokenContract = getContract({ - address: "0x638263e3eAa3917a53630e61B1fBa685308024fa", - chain: baseSepolia, - client: TEST_CLIENT, - }); - const claimTx = setApprovalForAll({ - approved: true, - contract: tokenContract, - operator: "0x4b8ceC1Eb227950F0bfd034449B2781e689242A1", - }); - const tx = await sendTransaction({ - account: serverWallet, - transaction: claimTx, - }); - expect(tx).toBeDefined(); - }); + it("should send a extension tx", async () => { + const tokenContract = getContract({ + address: "0x638263e3eAa3917a53630e61B1fBa685308024fa", + chain: baseSepolia, + client: TEST_CLIENT, + }); + const claimTx = setApprovalForAll({ + approved: true, + contract: tokenContract, + operator: "0x4b8ceC1Eb227950F0bfd034449B2781e689242A1", + }); + const tx = await sendTransaction({ + account: serverWallet, + transaction: claimTx, + }); + expect(tx).toBeDefined(); + }); - it("should enqueue a batch of txs", async () => { - const tokenContract = getContract({ - address: "0x638263e3eAa3917a53630e61B1fBa685308024fa", - chain: baseSepolia, - client: TEST_CLIENT, - }); - const claimTx1 = claimTo({ - contract: tokenContract, - quantity: 1n, - to: serverWallet.address, - tokenId: 2n, - }); - const claimTx2 = claimTo({ - contract: tokenContract, - quantity: 1n, - to: serverWallet.address, - tokenId: 2n, - }); - const tx = await serverWallet.enqueueBatchTransaction({ - transactions: [claimTx1, claimTx2], - }); - expect(tx.transactionId).toBeDefined(); - const txHash = await Engine.waitForTransactionHash({ - client: TEST_CLIENT, - transactionId: tx.transactionId, - }); - expect(txHash.transactionHash).toBeDefined(); - }); + it("should enqueue a batch of txs", async () => { + const tokenContract = getContract({ + address: "0x638263e3eAa3917a53630e61B1fBa685308024fa", + chain: baseSepolia, + client: TEST_CLIENT, + }); + const claimTx1 = claimTo({ + contract: tokenContract, + quantity: 1n, + to: serverWallet.address, + tokenId: 2n, + }); + const claimTx2 = claimTo({ + contract: tokenContract, + quantity: 1n, + to: serverWallet.address, + tokenId: 2n, + }); + const tx = await serverWallet.enqueueBatchTransaction({ + transactions: [claimTx1, claimTx2], + }); + expect(tx.transactionId).toBeDefined(); + const txHash = await Engine.waitForTransactionHash({ + client: TEST_CLIENT, + transactionId: tx.transactionId, + }); + expect(txHash.transactionHash).toBeDefined(); + }); - it("should get revert reason", async () => { - const nftContract = getContract({ - address: "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8", - chain: sepolia, - client: TEST_CLIENT, - }); - const transaction = setContractURI({ - contract: nftContract, - overrides: { - gas: 1000000n, // skip simulation - }, - uri: "https://example.com", - }); - await expect( - sendTransaction({ - account: serverWallet, - transaction, - }), - ).rejects.toThrow(); - }); + it("should get revert reason", async () => { + const nftContract = getContract({ + address: "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8", + chain: sepolia, + client: TEST_CLIENT, + }); + const transaction = setContractURI({ + contract: nftContract, + overrides: { + gas: 1000000n, // skip simulation + }, + uri: "https://example.com", + }); + await expect( + sendTransaction({ + account: serverWallet, + transaction, + }), + ).rejects.toThrow(); + }); - it("should send a session key tx", async () => { - const sessionKeyAccountAddress = process.env - .ENGINE_CLOUD_WALLET_ADDRESS_EOA as string; - const personalAccount = await generateAccount({ - client: TEST_CLIENT, - }); - const smart = smartWallet({ - chain: sepolia, - sessionKey: { - address: sessionKeyAccountAddress, - permissions: { - approvedTargets: "*", - }, - }, - sponsorGas: true, - }); - const smartAccount = await smart.connect({ - client: TEST_CLIENT, - personalAccount, - }); - expect(smartAccount.address).toBeDefined(); + it("should send a session key tx", async () => { + const sessionKeyAccountAddress = process.env + .ENGINE_CLOUD_WALLET_ADDRESS_EOA as string; + const personalAccount = await generateAccount({ + client: TEST_CLIENT, + }); + const smart = smartWallet({ + chain: sepolia, + sessionKey: { + address: sessionKeyAccountAddress, + permissions: { + approvedTargets: "*", + }, + }, + sponsorGas: true, + }); + const smartAccount = await smart.connect({ + client: TEST_CLIENT, + personalAccount, + }); + expect(smartAccount.address).toBeDefined(); - const signers = await getAllActiveSigners({ - contract: getContract({ - address: smartAccount.address, - chain: sepolia, - client: TEST_CLIENT, - }), - }); - expect(signers.map((s) => s.signer)).toContain(sessionKeyAccountAddress); + const signers = await getAllActiveSigners({ + contract: getContract({ + address: smartAccount.address, + chain: sepolia, + client: TEST_CLIENT, + }), + }); + expect(signers.map((s) => s.signer)).toContain(sessionKeyAccountAddress); - const serverWallet = Engine.serverWallet({ - address: sessionKeyAccountAddress, - chain: sepolia, - client: TEST_CLIENT, - executionOptions: { - entrypointAddress: ENTRYPOINT_ADDRESS_v0_6, - factoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6, - signerAddress: sessionKeyAccountAddress, - smartAccountAddress: smartAccount.address, - type: "ERC4337", - }, - vaultAccessToken: process.env.VAULT_TOKEN as string, - }); + const serverWallet = Engine.serverWallet({ + address: sessionKeyAccountAddress, + chain: sepolia, + client: TEST_CLIENT, + executionOptions: { + entrypointVersion: "0.6", + signerAddress: sessionKeyAccountAddress, + smartAccountAddress: smartAccount.address, + type: "ERC4337", + }, + vaultAccessToken: process.env.VAULT_TOKEN as string, + }); - const tx = await sendTransaction({ - account: serverWallet, - transaction: { - chain: sepolia, - client: TEST_CLIENT, - to: TEST_ACCOUNT_B.address, - value: 0n, - }, - }); - expect(tx).toBeDefined(); - }); - }, + const tx = await sendTransaction({ + account: serverWallet, + transaction: { + chain: sepolia, + client: TEST_CLIENT, + to: TEST_ACCOUNT_B.address, + value: 0n, + }, + }); + expect(tx).toBeDefined(); + }); + }, ); From c0748be243999653075980ab4dca0bd9fa4009eb Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Fri, 27 Jun 2025 08:11:02 +1200 Subject: [PATCH 10/18] 0.76 hey-api --- packages/engine/package.json | 2 +- packages/engine/src/client/client/client.ts | 4 - packages/engine/src/client/core/types.ts | 6 -- packages/engine/src/client/types.gen.ts | 88 ++------------------- pnpm-lock.yaml | 30 ++----- 5 files changed, 12 insertions(+), 118 deletions(-) diff --git a/packages/engine/package.json b/packages/engine/package.json index 642989ed361..452f88cda6f 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -24,7 +24,7 @@ ], "devDependencies": { "@biomejs/biome": "2.0.4", - "@hey-api/openapi-ts": "0.77.0", + "@hey-api/openapi-ts": "0.76.0", "rimraf": "6.0.1", "tslib": "^2.8.1" }, diff --git a/packages/engine/src/client/client/client.ts b/packages/engine/src/client/client/client.ts index 62280abd079..0b528190390 100644 --- a/packages/engine/src/client/client/client.ts +++ b/packages/engine/src/client/client/client.ts @@ -46,10 +46,6 @@ export const createClient = (config: Config = {}): Client => { }); } - if (opts.requestValidator) { - await opts.requestValidator(opts); - } - if (opts.body && opts.bodySerializer) { opts.body = opts.bodySerializer(opts.body); } diff --git a/packages/engine/src/client/core/types.ts b/packages/engine/src/client/core/types.ts index dfa9e32739b..e5ee754b86e 100644 --- a/packages/engine/src/client/core/types.ts +++ b/packages/engine/src/client/core/types.ts @@ -84,12 +84,6 @@ export interface Config { * {@link https://swagger.io/docs/specification/serialization/#query View examples} */ querySerializer?: QuerySerializer | QuerySerializerOptions; - /** - * A function validating request data. This is useful if you want to ensure - * the request conforms to the desired shape, so it can be safely sent to - * the server. - */ - requestValidator?: (data: unknown) => Promise; /** * A function transforming response data before it's returned. This is useful * for post-processing data, e.g. converting ISO strings into Date objects. diff --git a/packages/engine/src/client/types.gen.ts b/packages/engine/src/client/types.gen.ts index ec2db556687..59cc90743e9 100644 --- a/packages/engine/src/client/types.gen.ts +++ b/packages/engine/src/client/types.gen.ts @@ -121,11 +121,11 @@ export type BatchResultItemEncodeResultSuccessItemEngineError = type: "RPC_CONFIG_ERROR"; } | { - contract_address?: null | AddressDef; + contractAddress?: null | AddressDef; /** * Chain ID */ - chain_id: number; + chainId: number; /** * Human-readable error message */ @@ -204,11 +204,11 @@ export type BatchResultItemReadResultSuccessItemEngineError = type: "RPC_CONFIG_ERROR"; } | { - contract_address?: null | AddressDef; + contractAddress?: null | AddressDef; /** * Chain ID */ - chain_id: number; + chainId: number; /** * Human-readable error message */ @@ -296,11 +296,11 @@ export type BatchResultItemSignResultDataEngineError = type: "RPC_CONFIG_ERROR"; } | { - contract_address?: null | AddressDef; + contractAddress?: null | AddressDef; /** * Chain ID */ - chain_id: number; + chainId: number; /** * Human-readable error message */ @@ -967,18 +967,6 @@ export type WriteContractData = { */ body: WriteContractRequest; headers?: { - /** - * Thirdweb client ID, passed along with the service key - */ - "x-thirdweb-client-id"?: string | null; - /** - * Thirdweb service key, passed when using the client ID - */ - "x-thirdweb-service-key"?: string | null; - /** - * Thirdweb secret key, passed standalone - */ - "x-thirdweb-secret-key"?: string | null; /** * Vault access token */ @@ -1005,18 +993,6 @@ export type SendTransactionData = { */ body: SendTransactionRequest; headers?: { - /** - * Thirdweb client ID, passed along with the service key - */ - "x-thirdweb-client-id"?: string | null; - /** - * Thirdweb service key, passed when using the client ID - */ - "x-thirdweb-service-key"?: string | null; - /** - * Thirdweb secret key, passed standalone - */ - "x-thirdweb-secret-key"?: string | null; /** * Vault access token */ @@ -1043,18 +1019,6 @@ export type SignMessageData = { */ body: SignMessageRequest; headers?: { - /** - * Thirdweb client ID, passed along with the service key - */ - "x-thirdweb-client-id"?: string | null; - /** - * Thirdweb service key, passed when using the client ID - */ - "x-thirdweb-service-key"?: string | null; - /** - * Thirdweb secret key, passed standalone - */ - "x-thirdweb-secret-key"?: string | null; /** * Vault access token */ @@ -1081,18 +1045,6 @@ export type SignTypedDataData = { */ body: SignTypedDataRequest; headers?: { - /** - * Thirdweb client ID, passed along with the service key - */ - "x-thirdweb-client-id"?: string | null; - /** - * Thirdweb service key, passed when using the client ID - */ - "x-thirdweb-service-key"?: string | null; - /** - * Thirdweb secret key, passed standalone - */ - "x-thirdweb-secret-key"?: string | null; /** * Vault access token */ @@ -1118,20 +1070,6 @@ export type ReadContractData = { * Read contract request */ body: ReadRequest; - headers?: { - /** - * Thirdweb client ID, passed along with the service key - */ - "x-thirdweb-client-id"?: string | null; - /** - * Thirdweb service key, passed when using the client ID - */ - "x-thirdweb-service-key"?: string | null; - /** - * Thirdweb secret key, passed standalone - */ - "x-thirdweb-secret-key"?: string | null; - }; path?: never; query?: never; url: "/v1/read/contract"; @@ -1152,20 +1090,6 @@ export type EncodeContractData = { * Encode contract request */ body: EncodeRequest; - headers?: { - /** - * Thirdweb client ID, passed along with the service key - */ - "x-thirdweb-client-id"?: string | null; - /** - * Thirdweb service key, passed when using the client ID - */ - "x-thirdweb-service-key"?: string | null; - /** - * Thirdweb secret key, passed standalone - */ - "x-thirdweb-secret-key"?: string | null; - }; path?: never; query?: never; url: "/v1/encode/contract"; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0f48225a361..020fdf929a4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1055,7 +1055,7 @@ importers: dependencies: '@hey-api/client-fetch': specifier: 0.10.0 - version: 0.10.0(@hey-api/openapi-ts@0.77.0(magicast@0.3.5)(typescript@5.8.3)) + version: 0.10.0(@hey-api/openapi-ts@0.76.0(magicast@0.3.5)(typescript@5.8.3)) typescript: specifier: '>=5.0.4' version: 5.8.3 @@ -1064,8 +1064,8 @@ importers: specifier: 2.0.4 version: 2.0.4 '@hey-api/openapi-ts': - specifier: 0.77.0 - version: 0.77.0(magicast@0.3.5)(typescript@5.8.3) + specifier: 0.76.0 + version: 0.76.0(magicast@0.3.5)(typescript@5.8.3) rimraf: specifier: 6.0.1 version: 6.0.1 @@ -3441,13 +3441,6 @@ packages: peerDependencies: typescript: ^5.5.3 - '@hey-api/openapi-ts@0.77.0': - resolution: {integrity: sha512-HAJbd8QfxeBPZ788Ghiw7bzzzTKxW+wW+34foleEztyZJnRV20barvevu8YAK1BtyiIGIpEtAfoqO8KUj4VuBw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=22.10.0} - hasBin: true - peerDependencies: - typescript: ^5.5.3 - '@hookform/resolvers@3.10.0': resolution: {integrity: sha512-79Dv+3mDF7i+2ajj7SkypSKHhl1cbln1OGavqrsF7p6mbUv11xpqpacPsGDCTRvCSjEEIez2ef1NveSVL3b0Ag==} peerDependencies: @@ -19356,9 +19349,9 @@ snapshots: dependencies: react: 19.1.0 - '@hey-api/client-fetch@0.10.0(@hey-api/openapi-ts@0.77.0(magicast@0.3.5)(typescript@5.8.3))': + '@hey-api/client-fetch@0.10.0(@hey-api/openapi-ts@0.76.0(magicast@0.3.5)(typescript@5.8.3))': dependencies: - '@hey-api/openapi-ts': 0.77.0(magicast@0.3.5)(typescript@5.8.3) + '@hey-api/openapi-ts': 0.76.0(magicast@0.3.5)(typescript@5.8.3) '@hey-api/json-schema-ref-parser@1.0.6': dependencies: @@ -19380,19 +19373,6 @@ snapshots: transitivePeerDependencies: - magicast - '@hey-api/openapi-ts@0.77.0(magicast@0.3.5)(typescript@5.8.3)': - dependencies: - '@hey-api/json-schema-ref-parser': 1.0.6 - ansi-colors: 4.1.3 - c12: 2.0.1(magicast@0.3.5) - color-support: 1.1.3 - commander: 13.0.0 - handlebars: 4.7.8 - open: 10.1.2 - typescript: 5.8.3 - transitivePeerDependencies: - - magicast - '@hookform/resolvers@3.10.0(react-hook-form@7.55.0(react@19.1.0))': dependencies: react-hook-form: 7.55.0(react@19.1.0) From 9f38c04eba5031ba26d2535a45f147f05d741afe Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Fri, 27 Jun 2025 08:12:08 +1200 Subject: [PATCH 11/18] lint --- .../thirdweb/src/engine/server-wallet.test.ts | 466 +++++++------- packages/thirdweb/src/engine/server-wallet.ts | 600 +++++++++--------- 2 files changed, 533 insertions(+), 533 deletions(-) diff --git a/packages/thirdweb/src/engine/server-wallet.test.ts b/packages/thirdweb/src/engine/server-wallet.test.ts index 9990c18439a..c4caa7274c1 100644 --- a/packages/thirdweb/src/engine/server-wallet.test.ts +++ b/packages/thirdweb/src/engine/server-wallet.test.ts @@ -18,259 +18,259 @@ import { generateAccount } from "../wallets/utils/generateAccount.js"; import * as Engine from "./index.js"; describe.runIf( - process.env.TW_SECRET_KEY && - process.env.VAULT_TOKEN && - process.env.ENGINE_CLOUD_WALLET_ADDRESS && - process.env.ENGINE_CLOUD_WALLET_ADDRESS_EOA, + process.env.TW_SECRET_KEY && + process.env.VAULT_TOKEN && + process.env.ENGINE_CLOUD_WALLET_ADDRESS && + process.env.ENGINE_CLOUD_WALLET_ADDRESS_EOA, )( - "Engine Cloud", - { - retry: 0, - }, - () => { - let serverWallet: Engine.ServerWallet; + "Engine Cloud", + { + retry: 0, + }, + () => { + let serverWallet: Engine.ServerWallet; - beforeAll(async () => { - setThirdwebDomains({ - bundler: "bundler.thirdweb-dev.com", - engineCloud: "engine.thirdweb-dev.com", - // engineCloud: "localhost:3009", - rpc: "rpc.thirdweb-dev.com", - storage: "storage.thirdweb-dev.com", - }); - serverWallet = Engine.serverWallet({ - address: process.env.ENGINE_CLOUD_WALLET_ADDRESS as string, - chain: sepolia, - client: TEST_CLIENT, - vaultAccessToken: process.env.VAULT_TOKEN as string, - }); - }); + beforeAll(async () => { + setThirdwebDomains({ + bundler: "bundler.thirdweb-dev.com", + engineCloud: "engine.thirdweb-dev.com", + // engineCloud: "localhost:3009", + rpc: "rpc.thirdweb-dev.com", + storage: "storage.thirdweb-dev.com", + }); + serverWallet = Engine.serverWallet({ + address: process.env.ENGINE_CLOUD_WALLET_ADDRESS as string, + chain: sepolia, + client: TEST_CLIENT, + vaultAccessToken: process.env.VAULT_TOKEN as string, + }); + }); - it("should create a server wallet", async () => { - const serverWallet = await Engine.createServerWallet({ - client: TEST_CLIENT, - label: "My Server Wallet", - }); - expect(serverWallet).toBeDefined(); + it("should create a server wallet", async () => { + const serverWallet = await Engine.createServerWallet({ + client: TEST_CLIENT, + label: "My Server Wallet", + }); + expect(serverWallet).toBeDefined(); - const serverWallets = await Engine.getServerWallets({ - client: TEST_CLIENT, - }); - expect(serverWallets).toBeDefined(); - expect(serverWallets.length).toBeGreaterThan(0); - expect( - serverWallets.find((s) => s.address === serverWallet.address), - ).toBeDefined(); - }); + const serverWallets = await Engine.getServerWallets({ + client: TEST_CLIENT, + }); + expect(serverWallets).toBeDefined(); + expect(serverWallets.length).toBeGreaterThan(0); + expect( + serverWallets.find((s) => s.address === serverWallet.address), + ).toBeDefined(); + }); - it("should sign a message", async () => { - const signature = await serverWallet.signMessage({ - message: "hello", - }); - expect(signature).toBeDefined(); - }); + it("should sign a message", async () => { + const signature = await serverWallet.signMessage({ + message: "hello", + }); + expect(signature).toBeDefined(); + }); - it("should sign typed data", async () => { - const signature = await serverWallet.signTypedData({ - ...typedData.basic, - }); - expect(signature).toBeDefined(); - }); + it("should sign typed data", async () => { + const signature = await serverWallet.signTypedData({ + ...typedData.basic, + }); + expect(signature).toBeDefined(); + }); - it("should sign typed data for EOA execution options", async () => { - const eoaServerWallet = Engine.serverWallet({ - address: process.env.ENGINE_CLOUD_WALLET_ADDRESS_EOA as string, - chain: arbitrumSepolia, - client: TEST_CLIENT, - vaultAccessToken: process.env.VAULT_TOKEN as string, - }); + it("should sign typed data for EOA execution options", async () => { + const eoaServerWallet = Engine.serverWallet({ + address: process.env.ENGINE_CLOUD_WALLET_ADDRESS_EOA as string, + chain: arbitrumSepolia, + client: TEST_CLIENT, + vaultAccessToken: process.env.VAULT_TOKEN as string, + }); - const signature = await eoaServerWallet.signTypedData({ - ...typedData.basic, - }); + const signature = await eoaServerWallet.signTypedData({ + ...typedData.basic, + }); - expect(signature).toBeDefined(); + expect(signature).toBeDefined(); - const is_valid = await verifyTypedData({ - address: process.env.ENGINE_CLOUD_WALLET_ADDRESS_EOA as string, - chain: arbitrumSepolia, - client: TEST_CLIENT, - ...typedData.basic, + const is_valid = await verifyTypedData({ + address: process.env.ENGINE_CLOUD_WALLET_ADDRESS_EOA as string, + chain: arbitrumSepolia, + client: TEST_CLIENT, + ...typedData.basic, - signature, - }); + signature, + }); - expect(is_valid).toBe(true); - }); + expect(is_valid).toBe(true); + }); - it("should send a tx with regular API", async () => { - const tx = await sendTransaction({ - account: serverWallet, - transaction: { - chain: arbitrumSepolia, - client: TEST_CLIENT, - to: TEST_ACCOUNT_B.address, - value: 0n, - }, - }); - expect(tx).toBeDefined(); - }); + it("should send a tx with regular API", async () => { + const tx = await sendTransaction({ + account: serverWallet, + transaction: { + chain: arbitrumSepolia, + client: TEST_CLIENT, + to: TEST_ACCOUNT_B.address, + value: 0n, + }, + }); + expect(tx).toBeDefined(); + }); - it("should enqueue a tx", async () => { - const nftContract = getContract({ - address: "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8", - chain: sepolia, - client: TEST_CLIENT, - }); - const claimTx = claimTo({ - contract: nftContract, - quantity: 1n, - to: serverWallet.address, - tokenId: 0n, - }); - const result = await serverWallet.enqueueTransaction({ - transaction: claimTx, - }); - expect(result.transactionId).toBeDefined(); - const txHash = await Engine.waitForTransactionHash({ - client: TEST_CLIENT, - transactionId: result.transactionId, - }); - expect(txHash.transactionHash).toBeDefined(); + it("should enqueue a tx", async () => { + const nftContract = getContract({ + address: "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8", + chain: sepolia, + client: TEST_CLIENT, + }); + const claimTx = claimTo({ + contract: nftContract, + quantity: 1n, + to: serverWallet.address, + tokenId: 0n, + }); + const result = await serverWallet.enqueueTransaction({ + transaction: claimTx, + }); + expect(result.transactionId).toBeDefined(); + const txHash = await Engine.waitForTransactionHash({ + client: TEST_CLIENT, + transactionId: result.transactionId, + }); + expect(txHash.transactionHash).toBeDefined(); - const res = await Engine.searchTransactions({ - client: TEST_CLIENT, - filters: [ - { field: "id", operation: "OR", values: [result.transactionId] }, - ], - }); - expect(res).toBeDefined(); - expect(res.transactions.length).toBe(1); - expect(res.transactions[0]?.id).toBe(result.transactionId); - }); + const res = await Engine.searchTransactions({ + client: TEST_CLIENT, + filters: [ + { field: "id", operation: "OR", values: [result.transactionId] }, + ], + }); + expect(res).toBeDefined(); + expect(res.transactions.length).toBe(1); + expect(res.transactions[0]?.id).toBe(result.transactionId); + }); - it("should send a extension tx", async () => { - const tokenContract = getContract({ - address: "0x638263e3eAa3917a53630e61B1fBa685308024fa", - chain: baseSepolia, - client: TEST_CLIENT, - }); - const claimTx = setApprovalForAll({ - approved: true, - contract: tokenContract, - operator: "0x4b8ceC1Eb227950F0bfd034449B2781e689242A1", - }); - const tx = await sendTransaction({ - account: serverWallet, - transaction: claimTx, - }); - expect(tx).toBeDefined(); - }); + it("should send a extension tx", async () => { + const tokenContract = getContract({ + address: "0x638263e3eAa3917a53630e61B1fBa685308024fa", + chain: baseSepolia, + client: TEST_CLIENT, + }); + const claimTx = setApprovalForAll({ + approved: true, + contract: tokenContract, + operator: "0x4b8ceC1Eb227950F0bfd034449B2781e689242A1", + }); + const tx = await sendTransaction({ + account: serverWallet, + transaction: claimTx, + }); + expect(tx).toBeDefined(); + }); - it("should enqueue a batch of txs", async () => { - const tokenContract = getContract({ - address: "0x638263e3eAa3917a53630e61B1fBa685308024fa", - chain: baseSepolia, - client: TEST_CLIENT, - }); - const claimTx1 = claimTo({ - contract: tokenContract, - quantity: 1n, - to: serverWallet.address, - tokenId: 2n, - }); - const claimTx2 = claimTo({ - contract: tokenContract, - quantity: 1n, - to: serverWallet.address, - tokenId: 2n, - }); - const tx = await serverWallet.enqueueBatchTransaction({ - transactions: [claimTx1, claimTx2], - }); - expect(tx.transactionId).toBeDefined(); - const txHash = await Engine.waitForTransactionHash({ - client: TEST_CLIENT, - transactionId: tx.transactionId, - }); - expect(txHash.transactionHash).toBeDefined(); - }); + it("should enqueue a batch of txs", async () => { + const tokenContract = getContract({ + address: "0x638263e3eAa3917a53630e61B1fBa685308024fa", + chain: baseSepolia, + client: TEST_CLIENT, + }); + const claimTx1 = claimTo({ + contract: tokenContract, + quantity: 1n, + to: serverWallet.address, + tokenId: 2n, + }); + const claimTx2 = claimTo({ + contract: tokenContract, + quantity: 1n, + to: serverWallet.address, + tokenId: 2n, + }); + const tx = await serverWallet.enqueueBatchTransaction({ + transactions: [claimTx1, claimTx2], + }); + expect(tx.transactionId).toBeDefined(); + const txHash = await Engine.waitForTransactionHash({ + client: TEST_CLIENT, + transactionId: tx.transactionId, + }); + expect(txHash.transactionHash).toBeDefined(); + }); - it("should get revert reason", async () => { - const nftContract = getContract({ - address: "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8", - chain: sepolia, - client: TEST_CLIENT, - }); - const transaction = setContractURI({ - contract: nftContract, - overrides: { - gas: 1000000n, // skip simulation - }, - uri: "https://example.com", - }); - await expect( - sendTransaction({ - account: serverWallet, - transaction, - }), - ).rejects.toThrow(); - }); + it("should get revert reason", async () => { + const nftContract = getContract({ + address: "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8", + chain: sepolia, + client: TEST_CLIENT, + }); + const transaction = setContractURI({ + contract: nftContract, + overrides: { + gas: 1000000n, // skip simulation + }, + uri: "https://example.com", + }); + await expect( + sendTransaction({ + account: serverWallet, + transaction, + }), + ).rejects.toThrow(); + }); - it("should send a session key tx", async () => { - const sessionKeyAccountAddress = process.env - .ENGINE_CLOUD_WALLET_ADDRESS_EOA as string; - const personalAccount = await generateAccount({ - client: TEST_CLIENT, - }); - const smart = smartWallet({ - chain: sepolia, - sessionKey: { - address: sessionKeyAccountAddress, - permissions: { - approvedTargets: "*", - }, - }, - sponsorGas: true, - }); - const smartAccount = await smart.connect({ - client: TEST_CLIENT, - personalAccount, - }); - expect(smartAccount.address).toBeDefined(); + it("should send a session key tx", async () => { + const sessionKeyAccountAddress = process.env + .ENGINE_CLOUD_WALLET_ADDRESS_EOA as string; + const personalAccount = await generateAccount({ + client: TEST_CLIENT, + }); + const smart = smartWallet({ + chain: sepolia, + sessionKey: { + address: sessionKeyAccountAddress, + permissions: { + approvedTargets: "*", + }, + }, + sponsorGas: true, + }); + const smartAccount = await smart.connect({ + client: TEST_CLIENT, + personalAccount, + }); + expect(smartAccount.address).toBeDefined(); - const signers = await getAllActiveSigners({ - contract: getContract({ - address: smartAccount.address, - chain: sepolia, - client: TEST_CLIENT, - }), - }); - expect(signers.map((s) => s.signer)).toContain(sessionKeyAccountAddress); + const signers = await getAllActiveSigners({ + contract: getContract({ + address: smartAccount.address, + chain: sepolia, + client: TEST_CLIENT, + }), + }); + expect(signers.map((s) => s.signer)).toContain(sessionKeyAccountAddress); - const serverWallet = Engine.serverWallet({ - address: sessionKeyAccountAddress, - chain: sepolia, - client: TEST_CLIENT, - executionOptions: { - entrypointVersion: "0.6", - signerAddress: sessionKeyAccountAddress, - smartAccountAddress: smartAccount.address, - type: "ERC4337", - }, - vaultAccessToken: process.env.VAULT_TOKEN as string, - }); + const serverWallet = Engine.serverWallet({ + address: sessionKeyAccountAddress, + chain: sepolia, + client: TEST_CLIENT, + executionOptions: { + entrypointVersion: "0.6", + signerAddress: sessionKeyAccountAddress, + smartAccountAddress: smartAccount.address, + type: "ERC4337", + }, + vaultAccessToken: process.env.VAULT_TOKEN as string, + }); - const tx = await sendTransaction({ - account: serverWallet, - transaction: { - chain: sepolia, - client: TEST_CLIENT, - to: TEST_ACCOUNT_B.address, - value: 0n, - }, - }); - expect(tx).toBeDefined(); - }); - }, + const tx = await sendTransaction({ + account: serverWallet, + transaction: { + chain: sepolia, + client: TEST_CLIENT, + to: TEST_ACCOUNT_B.address, + value: 0n, + }, + }); + expect(tx).toBeDefined(); + }); + }, ); diff --git a/packages/thirdweb/src/engine/server-wallet.ts b/packages/thirdweb/src/engine/server-wallet.ts index f4fd9e3ff49..ea1114ad96e 100644 --- a/packages/thirdweb/src/engine/server-wallet.ts +++ b/packages/thirdweb/src/engine/server-wallet.ts @@ -1,10 +1,10 @@ import { - type SendTransactionData, - type SignMessageData, - type SpecificExecutionOptions, - sendTransaction, - signMessage, - signTypedData, + type SendTransactionData, + type SignMessageData, + type SpecificExecutionOptions, + sendTransaction, + signMessage, + signTypedData, } from "@thirdweb-dev/engine"; import type { Chain } from "../chains/types.js"; import type { ThirdwebClient } from "../client/client.js"; @@ -18,8 +18,8 @@ import { stringify } from "../utils/json.js"; import { resolvePromisedValue } from "../utils/promise/resolve-promised-value.js"; import type { Prettify } from "../utils/type-utils.js"; import type { - Account, - SendTransactionOption, + Account, + SendTransactionOption, } from "../wallets/interfaces/wallet.js"; import { waitForTransactionHash } from "./wait-for-tx-hash.js"; @@ -29,36 +29,36 @@ type ExecutionOptions = Prettify; * Options for creating an server wallet. */ export type ServerWalletOptions = { - /** - * The thirdweb client to use for authentication to thirdweb services. - */ - client: ThirdwebClient; - /** - * The vault access token to use your server wallet. - */ - vaultAccessToken: string; - /** - * The server wallet address to use for sending transactions inside engine. - */ - address: string; - /** - * The chain to use for signing messages and typed data (smart server wallet only). - */ - chain?: Chain; - /** - * Optional custom execution options to use for sending transactions and signing data. - */ - executionOptions?: ExecutionOptions; + /** + * The thirdweb client to use for authentication to thirdweb services. + */ + client: ThirdwebClient; + /** + * The vault access token to use your server wallet. + */ + vaultAccessToken: string; + /** + * The server wallet address to use for sending transactions inside engine. + */ + address: string; + /** + * The chain to use for signing messages and typed data (smart server wallet only). + */ + chain?: Chain; + /** + * Optional custom execution options to use for sending transactions and signing data. + */ + executionOptions?: ExecutionOptions; }; export type ServerWallet = Account & { - enqueueTransaction: (args: { - transaction: PreparedTransaction; - simulate?: boolean; - }) => Promise<{ transactionId: string }>; - enqueueBatchTransaction: (args: { - transactions: PreparedTransaction[]; - }) => Promise<{ transactionId: string }>; + enqueueTransaction: (args: { + transaction: PreparedTransaction; + simulate?: boolean; + }) => Promise<{ transactionId: string }>; + enqueueBatchTransaction: (args: { + transactions: PreparedTransaction[]; + }) => Promise<{ transactionId: string }>; }; /** @@ -148,289 +148,289 @@ export type ServerWallet = Account & { * ``` */ export function serverWallet(options: ServerWalletOptions): ServerWallet { - const { client, vaultAccessToken, address, chain, executionOptions } = - options; + const { client, vaultAccessToken, address, chain, executionOptions } = + options; - const headers: HeadersInit = { - "x-vault-access-token": vaultAccessToken, - }; + const headers: HeadersInit = { + "x-vault-access-token": vaultAccessToken, + }; - const getExecutionOptionsWithChainId = ( - chainId: number, - ): SendTransactionData["body"]["executionOptions"] => { - if (!executionOptions) { - return { - chainId, - from: address, - type: "auto", - }; - } - switch (executionOptions.type) { - case "auto": - return { - chainId, - from: address, - type: "auto", - }; - case "ERC4337": - return { - ...executionOptions, - chainId, - type: "ERC4337", - }; - } - }; + const getExecutionOptionsWithChainId = ( + chainId: number, + ): SendTransactionData["body"]["executionOptions"] => { + if (!executionOptions) { + return { + chainId, + from: address, + type: "auto", + }; + } + switch (executionOptions.type) { + case "auto": + return { + chainId, + from: address, + type: "auto", + }; + case "ERC4337": + return { + ...executionOptions, + chainId, + type: "ERC4337", + }; + } + }; - const getSigningOptions = ( - chainId: number | undefined, - ): SignMessageData["body"]["signingOptions"] => { - // if no chainId passed specifically for this signature - // we HAVE TO fallback to EOA signature - if (!chainId) { - return { - from: address, - type: "eoa", - }; - } + const getSigningOptions = ( + chainId: number | undefined, + ): SignMessageData["body"]["signingOptions"] => { + // if no chainId passed specifically for this signature + // we HAVE TO fallback to EOA signature + if (!chainId) { + return { + from: address, + type: "eoa", + }; + } - if (!executionOptions) { - return { - chainId, - from: address, - type: "auto", - }; - } + if (!executionOptions) { + return { + chainId, + from: address, + type: "auto", + }; + } - switch (executionOptions.type) { - case "ERC4337": { - return { - chainId, - ...executionOptions, - type: "ERC4337", - }; - } + switch (executionOptions.type) { + case "ERC4337": { + return { + chainId, + ...executionOptions, + type: "ERC4337", + }; + } - case "auto": { - return { - chainId, - // smartAccountAddress: address, - from: address, - type: "auto", - }; - } + case "auto": { + return { + chainId, + // smartAccountAddress: address, + from: address, + type: "auto", + }; + } - // case "eoa": { - // return { - // chainId, - // from: address, - // } - } - }; + // case "eoa": { + // return { + // chainId, + // from: address, + // } + } + }; - const enqueueTx = async (transaction: SendTransactionOption[]) => { - if (transaction.length === 0) { - throw new Error("No transactions to enqueue"); - } - const firstTransaction = transaction[0]; - if (!firstTransaction) { - throw new Error("No transactions to enqueue"); - } - const chainId = firstTransaction.chainId; - // Validate all transactions are on the same chain - for (let i = 1; i < transaction.length; i++) { - if (transaction[i]?.chainId !== chainId) { - throw new Error( - `All transactions in batch must be on the same chain. Expected ${chainId}, got ${transaction[i]?.chainId} at index ${i}`, - ); - } - } - const body = { - executionOptions: getExecutionOptionsWithChainId(chainId), - params: transaction.map((t) => ({ - data: t.data || "0x", - to: t.to ?? "", // TODO this should be allowed to be undefined - value: t.value?.toString() || "0", - })), - }; + const enqueueTx = async (transaction: SendTransactionOption[]) => { + if (transaction.length === 0) { + throw new Error("No transactions to enqueue"); + } + const firstTransaction = transaction[0]; + if (!firstTransaction) { + throw new Error("No transactions to enqueue"); + } + const chainId = firstTransaction.chainId; + // Validate all transactions are on the same chain + for (let i = 1; i < transaction.length; i++) { + if (transaction[i]?.chainId !== chainId) { + throw new Error( + `All transactions in batch must be on the same chain. Expected ${chainId}, got ${transaction[i]?.chainId} at index ${i}`, + ); + } + } + const body = { + executionOptions: getExecutionOptionsWithChainId(chainId), + params: transaction.map((t) => ({ + data: t.data || "0x", + to: t.to ?? "", // TODO this should be allowed to be undefined + value: t.value?.toString() || "0", + })), + }; - const result = await sendTransaction({ - baseUrl: getThirdwebBaseUrl("engineCloud"), - body, - bodySerializer: stringify, - fetch: getClientFetch(client), - headers, - }); + const result = await sendTransaction({ + baseUrl: getThirdwebBaseUrl("engineCloud"), + body, + bodySerializer: stringify, + fetch: getClientFetch(client), + headers, + }); - if (result.error) { - throw new Error(`Error sending transaction: ${stringify(result.error)}`); - } + if (result.error) { + throw new Error(`Error sending transaction: ${stringify(result.error)}`); + } - const data = result.data?.result; - if (!data) { - throw new Error("No data returned from engine"); - } - return data.transactions.map((t) => t.id); - }; + const data = result.data?.result; + if (!data) { + throw new Error("No data returned from engine"); + } + return data.transactions.map((t) => t.id); + }; - return { - address, - enqueueBatchTransaction: async (args: { - transactions: PreparedTransaction[]; - }) => { - const serializedTransactions: SendTransactionOption[] = []; - for (const transaction of args.transactions) { - const [to, data, value] = await Promise.all([ - transaction.to ? resolvePromisedValue(transaction.to) : null, - encode(transaction), - transaction.value ? resolvePromisedValue(transaction.value) : null, - ]); - serializedTransactions.push({ - chainId: transaction.chain.id, - data, - to: to ?? undefined, - value: value ?? undefined, - }); - } - const transactionIds = await enqueueTx(serializedTransactions); - const transactionId = transactionIds[0]; - if (!transactionId) { - throw new Error("No transactionId returned from engine"); - } - return { transactionId }; - }, - enqueueTransaction: async (args: { - transaction: PreparedTransaction; - simulate?: boolean; - }) => { - let serializedTransaction: SendTransactionOption; - if (args.simulate) { - serializedTransaction = await toSerializableTransaction({ - transaction: args.transaction, - }); - } else { - const [to, data, value] = await Promise.all([ - args.transaction.to - ? resolvePromisedValue(args.transaction.to) - : null, - encode(args.transaction), - args.transaction.value - ? resolvePromisedValue(args.transaction.value) - : null, - ]); - serializedTransaction = { - chainId: args.transaction.chain.id, - data, - to: to ?? undefined, - value: value ?? undefined, - }; - } - const transactionIds = await enqueueTx([serializedTransaction]); - const transactionId = transactionIds[0]; - if (!transactionId) { - throw new Error("No transactionId returned from engine"); - } - return { transactionId }; - }, - sendBatchTransaction: async (transactions: SendTransactionOption[]) => { - const transactionIds = await enqueueTx(transactions); - const transactionId = transactionIds[0]; - if (!transactionId) { - throw new Error("No transactionId returned from engine"); - } - return waitForTransactionHash({ - client, - transactionId, - }); - }, - sendTransaction: async (transaction: SendTransactionOption) => { - const transactionIds = await enqueueTx([transaction]); - const transactionId = transactionIds[0]; - if (!transactionId) { - throw new Error("No transactionId returned from engine"); - } - return waitForTransactionHash({ - client, - transactionId, - }); - }, - signMessage: async (data) => { - const { message, chainId } = data; - let engineMessage: string | Hex; - let isBytes = false; - if (typeof message === "string") { - engineMessage = message; - } else { - engineMessage = toHex(message.raw); - isBytes = true; - } + return { + address, + enqueueBatchTransaction: async (args: { + transactions: PreparedTransaction[]; + }) => { + const serializedTransactions: SendTransactionOption[] = []; + for (const transaction of args.transactions) { + const [to, data, value] = await Promise.all([ + transaction.to ? resolvePromisedValue(transaction.to) : null, + encode(transaction), + transaction.value ? resolvePromisedValue(transaction.value) : null, + ]); + serializedTransactions.push({ + chainId: transaction.chain.id, + data, + to: to ?? undefined, + value: value ?? undefined, + }); + } + const transactionIds = await enqueueTx(serializedTransactions); + const transactionId = transactionIds[0]; + if (!transactionId) { + throw new Error("No transactionId returned from engine"); + } + return { transactionId }; + }, + enqueueTransaction: async (args: { + transaction: PreparedTransaction; + simulate?: boolean; + }) => { + let serializedTransaction: SendTransactionOption; + if (args.simulate) { + serializedTransaction = await toSerializableTransaction({ + transaction: args.transaction, + }); + } else { + const [to, data, value] = await Promise.all([ + args.transaction.to + ? resolvePromisedValue(args.transaction.to) + : null, + encode(args.transaction), + args.transaction.value + ? resolvePromisedValue(args.transaction.value) + : null, + ]); + serializedTransaction = { + chainId: args.transaction.chain.id, + data, + to: to ?? undefined, + value: value ?? undefined, + }; + } + const transactionIds = await enqueueTx([serializedTransaction]); + const transactionId = transactionIds[0]; + if (!transactionId) { + throw new Error("No transactionId returned from engine"); + } + return { transactionId }; + }, + sendBatchTransaction: async (transactions: SendTransactionOption[]) => { + const transactionIds = await enqueueTx(transactions); + const transactionId = transactionIds[0]; + if (!transactionId) { + throw new Error("No transactionId returned from engine"); + } + return waitForTransactionHash({ + client, + transactionId, + }); + }, + sendTransaction: async (transaction: SendTransactionOption) => { + const transactionIds = await enqueueTx([transaction]); + const transactionId = transactionIds[0]; + if (!transactionId) { + throw new Error("No transactionId returned from engine"); + } + return waitForTransactionHash({ + client, + transactionId, + }); + }, + signMessage: async (data) => { + const { message, chainId } = data; + let engineMessage: string | Hex; + let isBytes = false; + if (typeof message === "string") { + engineMessage = message; + } else { + engineMessage = toHex(message.raw); + isBytes = true; + } - const signingChainId = chainId || chain?.id; - if (!signingChainId) { - throw new Error("Chain ID is required for signing messages"); - } - const signResult = await signMessage({ - baseUrl: getThirdwebBaseUrl("engineCloud"), - body: { - params: [ - { - format: isBytes ? "hex" : "text", - message: engineMessage, - }, - ], - signingOptions: getSigningOptions(signingChainId), - }, - bodySerializer: stringify, - fetch: getClientFetch(client), - headers, - }); + const signingChainId = chainId || chain?.id; + if (!signingChainId) { + throw new Error("Chain ID is required for signing messages"); + } + const signResult = await signMessage({ + baseUrl: getThirdwebBaseUrl("engineCloud"), + body: { + params: [ + { + format: isBytes ? "hex" : "text", + message: engineMessage, + }, + ], + signingOptions: getSigningOptions(signingChainId), + }, + bodySerializer: stringify, + fetch: getClientFetch(client), + headers, + }); - if (signResult.error) { - throw new Error( - `Error signing message: ${stringify(signResult.error)}`, - ); - } + if (signResult.error) { + throw new Error( + `Error signing message: ${stringify(signResult.error)}`, + ); + } - const signatureResult = signResult.data?.result.results[0]; - if (signatureResult && "result" in signatureResult) { - return signatureResult.result.signature as Hex; - } + const signatureResult = signResult.data?.result.results[0]; + if (signatureResult && "result" in signatureResult) { + return signatureResult.result.signature as Hex; + } - throw new Error( - `Failed to sign message: ${stringify(signatureResult?.error) || "Unknown error"}`, - ); - }, - signTypedData: async (typedData) => { - const signingChainId = chain?.id; - if (!signingChainId) { - throw new Error("Chain ID is required for signing messages"); - } + throw new Error( + `Failed to sign message: ${stringify(signatureResult?.error) || "Unknown error"}`, + ); + }, + signTypedData: async (typedData) => { + const signingChainId = chain?.id; + if (!signingChainId) { + throw new Error("Chain ID is required for signing messages"); + } - const signResult = await signTypedData({ - baseUrl: getThirdwebBaseUrl("engineCloud"), - body: { - // biome-ignore lint/suspicious/noExplicitAny: TODO: fix ts / hey-api type clash - params: [typedData as any], - signingOptions: getSigningOptions(signingChainId), - }, - bodySerializer: stringify, - fetch: getClientFetch(client), - headers, - }); + const signResult = await signTypedData({ + baseUrl: getThirdwebBaseUrl("engineCloud"), + body: { + // biome-ignore lint/suspicious/noExplicitAny: TODO: fix ts / hey-api type clash + params: [typedData as any], + signingOptions: getSigningOptions(signingChainId), + }, + bodySerializer: stringify, + fetch: getClientFetch(client), + headers, + }); - if (signResult.error) { - throw new Error( - `Error signing message: ${stringify(signResult.error)}`, - ); - } + if (signResult.error) { + throw new Error( + `Error signing message: ${stringify(signResult.error)}`, + ); + } - const signatureResult = signResult.data?.result.results[0]; - if (signatureResult && "result" in signatureResult) { - return signatureResult.result.signature as Hex; - } + const signatureResult = signResult.data?.result.results[0]; + if (signatureResult && "result" in signatureResult) { + return signatureResult.result.signature as Hex; + } - throw new Error( - `Failed to sign message: ${stringify(signatureResult?.error) || "Unknown error"}`, - ); - }, - }; + throw new Error( + `Failed to sign message: ${stringify(signatureResult?.error) || "Unknown error"}`, + ); + }, + }; } From e15b6608107861d31bc43201828b0401ed14151d Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Fri, 27 Jun 2025 08:31:34 +1200 Subject: [PATCH 12/18] update biome schema --- apps/dashboard/biome.json | 2 +- apps/nebula/biome.json | 2 +- apps/playground-web/biome.json | 2 +- apps/portal/biome.json | 2 +- apps/wallet-ui/biome.json | 2 +- biome.json | 2 +- packages/engine/biome.json | 30 ++++++++++++------------ packages/insight/biome.json | 2 +- packages/nebula/biome.json | 2 +- packages/react-native-adapter/biome.json | 2 +- packages/service-utils/biome.json | 2 +- packages/thirdweb/biome.json | 2 +- packages/vault-sdk/biome.json | 2 +- packages/wagmi-adapter/biome.json | 2 +- 14 files changed, 28 insertions(+), 28 deletions(-) diff --git a/apps/dashboard/biome.json b/apps/dashboard/biome.json index 780bbdcd1af..cec0f72abd0 100644 --- a/apps/dashboard/biome.json +++ b/apps/dashboard/biome.json @@ -1,4 +1,4 @@ { - "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json", + "$schema": "https://biomejs.dev/schemas/2.0.4/schema.json", "extends": "//" } diff --git a/apps/nebula/biome.json b/apps/nebula/biome.json index 780bbdcd1af..cec0f72abd0 100644 --- a/apps/nebula/biome.json +++ b/apps/nebula/biome.json @@ -1,4 +1,4 @@ { - "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json", + "$schema": "https://biomejs.dev/schemas/2.0.4/schema.json", "extends": "//" } diff --git a/apps/playground-web/biome.json b/apps/playground-web/biome.json index 780bbdcd1af..cec0f72abd0 100644 --- a/apps/playground-web/biome.json +++ b/apps/playground-web/biome.json @@ -1,4 +1,4 @@ { - "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json", + "$schema": "https://biomejs.dev/schemas/2.0.4/schema.json", "extends": "//" } diff --git a/apps/portal/biome.json b/apps/portal/biome.json index 780bbdcd1af..cec0f72abd0 100644 --- a/apps/portal/biome.json +++ b/apps/portal/biome.json @@ -1,4 +1,4 @@ { - "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json", + "$schema": "https://biomejs.dev/schemas/2.0.4/schema.json", "extends": "//" } diff --git a/apps/wallet-ui/biome.json b/apps/wallet-ui/biome.json index 780bbdcd1af..cec0f72abd0 100644 --- a/apps/wallet-ui/biome.json +++ b/apps/wallet-ui/biome.json @@ -1,4 +1,4 @@ { - "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json", + "$schema": "https://biomejs.dev/schemas/2.0.4/schema.json", "extends": "//" } diff --git a/biome.json b/biome.json index 4ff11ff4f01..52c326583f0 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json", + "$schema": "https://biomejs.dev/schemas/2.0.4/schema.json", "assist": { "actions": { "source": { diff --git a/packages/engine/biome.json b/packages/engine/biome.json index dc3633e825e..c0390d3d0bc 100644 --- a/packages/engine/biome.json +++ b/packages/engine/biome.json @@ -1,17 +1,17 @@ { - "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json", - "linter": { - "rules": { - "correctness": { - "useImportExtensions": { - "fix": "safe", - "level": "error", - "options": { - "forceJsExtensions": true - } - } - } - } - }, - "root": true + "$schema": "https://biomejs.dev/schemas/2.0.4/schema.json", + "linter": { + "rules": { + "correctness": { + "useImportExtensions": { + "fix": "safe", + "level": "error", + "options": { + "forceJsExtensions": true + } + } + } + } + }, + "root": true } diff --git a/packages/insight/biome.json b/packages/insight/biome.json index 780bbdcd1af..cec0f72abd0 100644 --- a/packages/insight/biome.json +++ b/packages/insight/biome.json @@ -1,4 +1,4 @@ { - "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json", + "$schema": "https://biomejs.dev/schemas/2.0.4/schema.json", "extends": "//" } diff --git a/packages/nebula/biome.json b/packages/nebula/biome.json index 780bbdcd1af..cec0f72abd0 100644 --- a/packages/nebula/biome.json +++ b/packages/nebula/biome.json @@ -1,4 +1,4 @@ { - "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json", + "$schema": "https://biomejs.dev/schemas/2.0.4/schema.json", "extends": "//" } diff --git a/packages/react-native-adapter/biome.json b/packages/react-native-adapter/biome.json index 780bbdcd1af..cec0f72abd0 100644 --- a/packages/react-native-adapter/biome.json +++ b/packages/react-native-adapter/biome.json @@ -1,4 +1,4 @@ { - "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json", + "$schema": "https://biomejs.dev/schemas/2.0.4/schema.json", "extends": "//" } diff --git a/packages/service-utils/biome.json b/packages/service-utils/biome.json index 780bbdcd1af..cec0f72abd0 100644 --- a/packages/service-utils/biome.json +++ b/packages/service-utils/biome.json @@ -1,4 +1,4 @@ { - "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json", + "$schema": "https://biomejs.dev/schemas/2.0.4/schema.json", "extends": "//" } diff --git a/packages/thirdweb/biome.json b/packages/thirdweb/biome.json index 780bbdcd1af..cec0f72abd0 100644 --- a/packages/thirdweb/biome.json +++ b/packages/thirdweb/biome.json @@ -1,4 +1,4 @@ { - "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json", + "$schema": "https://biomejs.dev/schemas/2.0.4/schema.json", "extends": "//" } diff --git a/packages/vault-sdk/biome.json b/packages/vault-sdk/biome.json index 780bbdcd1af..cec0f72abd0 100644 --- a/packages/vault-sdk/biome.json +++ b/packages/vault-sdk/biome.json @@ -1,4 +1,4 @@ { - "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json", + "$schema": "https://biomejs.dev/schemas/2.0.4/schema.json", "extends": "//" } diff --git a/packages/wagmi-adapter/biome.json b/packages/wagmi-adapter/biome.json index 780bbdcd1af..cec0f72abd0 100644 --- a/packages/wagmi-adapter/biome.json +++ b/packages/wagmi-adapter/biome.json @@ -1,4 +1,4 @@ { - "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json", + "$schema": "https://biomejs.dev/schemas/2.0.4/schema.json", "extends": "//" } From df909274ed526bf0a6a34b7da28c5a10a84e8915 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Fri, 27 Jun 2025 08:38:54 +1200 Subject: [PATCH 13/18] review --- .../transactions/tx/[id]/transaction-details-ui.tsx | 2 +- packages/thirdweb/src/engine/server-wallet.ts | 13 +++---------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/tx/[id]/transaction-details-ui.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/tx/[id]/transaction-details-ui.tsx index 637fac8fcec..c745eaaf649 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/tx/[id]/transaction-details-ui.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/tx/[id]/transaction-details-ui.tsx @@ -255,7 +255,7 @@ export function TransactionDetailsUI({ /> ) : (
- errorMessage + {errorMessage}
)} diff --git a/packages/thirdweb/src/engine/server-wallet.ts b/packages/thirdweb/src/engine/server-wallet.ts index ea1114ad96e..057827399f1 100644 --- a/packages/thirdweb/src/engine/server-wallet.ts +++ b/packages/thirdweb/src/engine/server-wallet.ts @@ -213,17 +213,10 @@ export function serverWallet(options: ServerWalletOptions): ServerWallet { case "auto": { return { chainId, - // smartAccountAddress: address, from: address, type: "auto", }; } - - // case "eoa": { - // return { - // chainId, - // from: address, - // } } }; @@ -247,9 +240,9 @@ export function serverWallet(options: ServerWalletOptions): ServerWallet { const body = { executionOptions: getExecutionOptionsWithChainId(chainId), params: transaction.map((t) => ({ - data: t.data || "0x", - to: t.to ?? "", // TODO this should be allowed to be undefined - value: t.value?.toString() || "0", + data: t.data, + to: t.to, + value: t.value?.toString(), })), }; From 73bf33c1cabe12ef55ca622ba98a66fb3f50b073 Mon Sep 17 00:00:00 2001 From: Prithvish Baidya Date: Fri, 27 Jun 2025 18:27:55 +0530 Subject: [PATCH 14/18] update SDK --- packages/engine/src/client/types.gen.ts | 214 ++++++++++++++---- packages/engine/src/configure.ts | 64 ++++-- packages/engine/src/exports/thirdweb.ts | 7 +- packages/thirdweb/src/engine/server-wallet.ts | 9 +- 4 files changed, 225 insertions(+), 69 deletions(-) diff --git a/packages/engine/src/client/types.gen.ts b/packages/engine/src/client/types.gen.ts index 59cc90743e9..3628a18ddf0 100644 --- a/packages/engine/src/client/types.gen.ts +++ b/packages/engine/src/client/types.gen.ts @@ -116,6 +116,10 @@ export type BatchResultItemEncodeResultSuccessItemEngineError = message: string; type: "VAULT_ERROR"; } + | { + error: IawError; + type: "IAW_ERROR"; + } | { message: string; type: "RPC_CONFIG_ERROR"; @@ -199,6 +203,10 @@ export type BatchResultItemReadResultSuccessItemEngineError = message: string; type: "VAULT_ERROR"; } + | { + error: IawError; + type: "IAW_ERROR"; + } | { message: string; type: "RPC_CONFIG_ERROR"; @@ -291,6 +299,10 @@ export type BatchResultItemSignResultDataEngineError = message: string; type: "VAULT_ERROR"; } + | { + error: IawError; + type: "IAW_ERROR"; + } | { message: string; type: "RPC_CONFIG_ERROR"; @@ -325,6 +337,36 @@ export type BatchResultItemSignResultDataEngineError = }; }; +/** + * Collection of results from multiple contract encode operations + */ +export type BatchResultsEncodeResultSuccessItem = { + /** + * Array of results, one for each input contract call + */ + result: Array; +}; + +/** + * Collection of results from multiple contract encode operations + */ +export type BatchResultsReadResultSuccessItem = { + /** + * Array of results, one for each input contract call + */ + result: Array; +}; + +/** + * Collection of results from multiple contract encode operations + */ +export type BatchResultsSignResultData = { + /** + * Array of results, one for each input contract call + */ + result: Array; +}; + /** * # Bytes * Used to represent "bytes". This is a 0x prefixed hex string. @@ -603,6 +645,34 @@ export type Erc4337SigningOptions = EntrypointAndFactoryDetailsDeserHelper & { */ export type ExecutionOptions = BaseExecutionOptions & SpecificExecutionOptions; +/** + * Error types for IAW operations + */ +export type IawError = + | { + type: "API_ERROR"; + } + | { + message: string; + type: "SERIALIZATION_ERROR"; + } + | { + error: SerializableReqwestError; + type: "NETWORK_ERROR"; + } + | { + type: "AUTH_ERROR"; + } + | (ThirdwebError & { + type: "THIRDWEB_ERROR"; + }) + | { + type: "UNEXPECTED_ERROR"; + } + | (UserOpError & { + type: "USER_OP_ERROR"; + }); + /** * # InnerTransaction * This is the actual encoded inner transaction data that will be sent to the blockchain. @@ -768,6 +838,76 @@ export type SendTransactionRequest = { webhookOptions?: Array | null; }; +export type SerializableReqwestError = + | { + Builder: { + message: string; + url?: string | null; + }; + } + | { + Request: { + message: string; + url?: string | null; + }; + } + | { + Timeout: { + message: string; + url?: string | null; + }; + } + | { + Connect: { + message: string; + url?: string | null; + }; + } + | { + Redirect: { + message: string; + url?: string | null; + }; + } + | { + ClientError: { + status: number; + message: string; + url?: string | null; + }; + } + | { + ServerError: { + status: number; + message: string; + url?: string | null; + }; + } + | { + Body: { + message: string; + url?: string | null; + }; + } + | { + Decode: { + message: string; + url?: string | null; + }; + } + | { + Upgrade: { + message: string; + url?: string | null; + }; + } + | { + Unknown: { + message: string; + url?: string | null; + }; + }; + /** * Request to sign messages */ @@ -844,45 +984,34 @@ export type SpecificExecutionOptions = type: "ERC4337"; }); -export type SuccessResponseBatchResultsEncodeResultSuccessItem = { - /** - * Collection of results from multiple contract encode operations - */ - result: { - /** - * Array of results, one for each input contract call - */ - results: Array; - }; -}; - -export type SuccessResponseBatchResultsReadResultSuccessItem = { - /** - * Collection of results from multiple contract encode operations - */ +export type SuccessResponseQueuedTransactionsResponse = { result: { - /** - * Array of results, one for each input contract call - */ - results: Array; + transactions: Array; }; }; -export type SuccessResponseBatchResultsSignResultData = { - /** - * Collection of results from multiple contract encode operations - */ - result: { - /** - * Array of results, one for each input contract call - */ - results: Array; - }; -}; +export type ThirdwebError = + | { + error: ThirdwebSerializationError; + type: "SERIALIZATION_ERROR"; + } + | { + value: string; + message: string; + type: "URL_PARSE_ERROR"; + } + | { + message: string; + type: "HTTP_CLIENT_BACKEND_ERROR"; + } + | { + error: SerializableReqwestError; + type: "HTTP_ERROR"; + }; -export type SuccessResponseQueuedTransactionsResponse = { - result: { - transactions: Array; +export type ThirdwebSerializationError = { + HeaderValue: { + value: string; }; }; @@ -934,6 +1063,13 @@ export type TypedDataDomainDef = { */ export type U256Def = string; +/** + * Error type for UserOp operations + */ +export type UserOpError = { + type: "UNEXPECTED_ERROR"; +}; + export type Value = unknown; export type WebhookOptions = { @@ -1033,7 +1169,7 @@ export type SignMessageResponses = { /** * Successfully signed messages */ - 200: SuccessResponseBatchResultsSignResultData; + 200: BatchResultsSignResultData; }; export type SignMessageResponse = @@ -1059,7 +1195,7 @@ export type SignTypedDataResponses = { /** * Successfully signed typed data */ - 200: SuccessResponseBatchResultsSignResultData; + 200: BatchResultsSignResultData; }; export type SignTypedDataResponse = @@ -1079,7 +1215,7 @@ export type ReadContractResponses = { /** * Successfully read contract data */ - 200: SuccessResponseBatchResultsReadResultSuccessItem; + 200: BatchResultsReadResultSuccessItem; }; export type ReadContractResponse = @@ -1099,7 +1235,7 @@ export type EncodeContractResponses = { /** * Successfully encoded contract calls */ - 200: SuccessResponseBatchResultsEncodeResultSuccessItem; + 200: BatchResultsEncodeResultSuccessItem; }; export type EncodeContractResponse = @@ -1560,5 +1696,5 @@ export type SearchActivityLogsResponse = SearchActivityLogsResponses[keyof SearchActivityLogsResponses]; export type ClientOptions = { - baseUrl: "https://engine.thirdweb-dev.com" | (string & {}); + baseUrl: "http://localhost:3001" | (string & {}); }; diff --git a/packages/engine/src/configure.ts b/packages/engine/src/configure.ts index 6998c78db9e..a06b96a2ac2 100644 --- a/packages/engine/src/configure.ts +++ b/packages/engine/src/configure.ts @@ -2,37 +2,51 @@ import type { Config } from "./client/client/index.js"; import { client } from "./client/client.gen.js"; export type EngineClientOptions = { - readonly clientId?: string; - readonly secretKey?: string; + readonly clientId?: string; + readonly secretKey?: string; }; export function configure( - options: EngineClientOptions & { override?: Config }, + options: EngineClientOptions & { override?: Config }, ) { - client.setConfig({ - bodySerializer: stringify, - headers: { - ...(options.clientId && { "x-client-id": options.clientId }), - ...(options.secretKey && { "x-secret-key": options.secretKey }), - }, - ...(options.override ?? {}), - }); + client.setConfig({ + bodySerializer: stringify, + headers: { + ...(options.clientId && { "x-client-id": options.clientId }), + ...(options.secretKey && { "x-secret-key": options.secretKey }), + }, + ...(options.override ?? {}), + }); } function stringify( - // biome-ignore lint/suspicious/noExplicitAny: JSON.stringify signature - value: any, - // biome-ignore lint/suspicious/noExplicitAny: JSON.stringify signature - replacer?: ((this: any, key: string, value: any) => any) | null, - space?: string | number, + // biome-ignore lint/suspicious/noExplicitAny: JSON.stringify signature + value: any, + // biome-ignore lint/suspicious/noExplicitAny: JSON.stringify signature + replacer?: ((this: any, key: string, value: any) => any) | null, + space?: string | number, ) { - const res = JSON.stringify( - value, - (key, value_) => { - const value__ = typeof value_ === "bigint" ? value_.toString() : value_; - return typeof replacer === "function" ? replacer(key, value__) : value__; - }, - space, - ); - return res; + const res = JSON.stringify( + value, + (key, value_) => { + const value__ = typeof value_ === "bigint" ? value_.toString() : value_; + return typeof replacer === "function" ? replacer(key, value__) : value__; + }, + space, + ); + return res; +} + +export type MaybeErrorResponse = { result: D } | { error: E }; + +export function isErrorResponse( + res: MaybeErrorResponse, +): res is { error: E } { + return "error" in res; +} + +export function isSuccessResponse( + res: MaybeErrorResponse, +): res is { result: D } { + return "result" in res; } diff --git a/packages/engine/src/exports/thirdweb.ts b/packages/engine/src/exports/thirdweb.ts index 6bce866bcc7..9733589317a 100644 --- a/packages/engine/src/exports/thirdweb.ts +++ b/packages/engine/src/exports/thirdweb.ts @@ -1,3 +1,8 @@ export type { CreateClientConfig } from "../client/client.gen.js"; export * from "../client/index.js"; -export { configure, type EngineClientOptions } from "../configure.js"; +export { + configure, + type EngineClientOptions, + isErrorResponse, + isSuccessResponse, +} from "../configure.js"; diff --git a/packages/thirdweb/src/engine/server-wallet.ts b/packages/thirdweb/src/engine/server-wallet.ts index 057827399f1..5eb9dafa661 100644 --- a/packages/thirdweb/src/engine/server-wallet.ts +++ b/packages/thirdweb/src/engine/server-wallet.ts @@ -1,4 +1,5 @@ import { + isSuccessResponse, type SendTransactionData, type SignMessageData, type SpecificExecutionOptions, @@ -383,8 +384,8 @@ export function serverWallet(options: ServerWalletOptions): ServerWallet { ); } - const signatureResult = signResult.data?.result.results[0]; - if (signatureResult && "result" in signatureResult) { + const signatureResult = signResult.data?.result[0]; + if (signatureResult && isSuccessResponse(signatureResult)) { return signatureResult.result.signature as Hex; } @@ -416,8 +417,8 @@ export function serverWallet(options: ServerWalletOptions): ServerWallet { ); } - const signatureResult = signResult.data?.result.results[0]; - if (signatureResult && "result" in signatureResult) { + const signatureResult = signResult.data?.result[0]; + if (signatureResult && isSuccessResponse(signatureResult)) { return signatureResult.result.signature as Hex; } From 1098ddf64dcc899f5785c2f0b3be91c2c842dc08 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Sat, 28 Jun 2025 13:10:00 +1200 Subject: [PATCH 15/18] lint --- packages/engine/package.json | 17 ++---- packages/engine/src/configure.ts | 58 +++++++++---------- packages/engine/src/exports/thirdweb.ts | 8 +-- .../Bridge/payment-details/PaymentDetails.tsx | 10 +--- 4 files changed, 42 insertions(+), 51 deletions(-) diff --git a/packages/engine/package.json b/packages/engine/package.json index 5dc776d6f63..4e1482b09ea 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -5,6 +5,9 @@ "type": "git", "url": "git+https://github.com/thirdweb-dev/js.git#main" }, + "type": "module", + "types": "./dist/types/exports/thirdweb.d.ts", + "typings": "./dist/types/exports/thirdweb.d.ts", "license": "Apache-2.0", "bugs": { "url": "https://github.com/thirdweb-dev/js/issues" @@ -17,9 +20,9 @@ }, "exports": { ".": { - "default": "./dist/cjs/exports/thirdweb.js", "import": "./dist/esm/exports/thirdweb.js", - "types": "./dist/types/exports/thirdweb.d.ts" + "types": "./dist/types/exports/thirdweb.d.ts", + "default": "./dist/cjs/exports/thirdweb.js" }, "./package.json": "./package.json" }, @@ -41,10 +44,6 @@ "optional": true } }, - "repository": { - "type": "git", - "url": "git+https://github.com/thirdweb-dev/js.git#main" - }, "scripts": { "build": "pnpm clean && pnpm build:cjs && pnpm build:esm && pnpm build:types", "build:cjs": "tsc --project ./tsconfig.build.json --module commonjs --outDir ./dist/cjs --verbatimModuleSyntax false && printf '{\"type\":\"commonjs\"}' > ./dist/cjs/package.json", @@ -55,9 +54,5 @@ "fix": "biome check --write ./src", "format": "biome format --write ./src", "lint": "biome check ./src" - }, - "type": "module", - "types": "./dist/types/exports/thirdweb.d.ts", - "typings": "./dist/types/exports/thirdweb.d.ts", - "version": "3.0.4" + } } diff --git a/packages/engine/src/configure.ts b/packages/engine/src/configure.ts index a06b96a2ac2..031669957d1 100644 --- a/packages/engine/src/configure.ts +++ b/packages/engine/src/configure.ts @@ -2,51 +2,51 @@ import type { Config } from "./client/client/index.js"; import { client } from "./client/client.gen.js"; export type EngineClientOptions = { - readonly clientId?: string; - readonly secretKey?: string; + readonly clientId?: string; + readonly secretKey?: string; }; export function configure( - options: EngineClientOptions & { override?: Config }, + options: EngineClientOptions & { override?: Config }, ) { - client.setConfig({ - bodySerializer: stringify, - headers: { - ...(options.clientId && { "x-client-id": options.clientId }), - ...(options.secretKey && { "x-secret-key": options.secretKey }), - }, - ...(options.override ?? {}), - }); + client.setConfig({ + bodySerializer: stringify, + headers: { + ...(options.clientId && { "x-client-id": options.clientId }), + ...(options.secretKey && { "x-secret-key": options.secretKey }), + }, + ...(options.override ?? {}), + }); } function stringify( - // biome-ignore lint/suspicious/noExplicitAny: JSON.stringify signature - value: any, - // biome-ignore lint/suspicious/noExplicitAny: JSON.stringify signature - replacer?: ((this: any, key: string, value: any) => any) | null, - space?: string | number, + // biome-ignore lint/suspicious/noExplicitAny: JSON.stringify signature + value: any, + // biome-ignore lint/suspicious/noExplicitAny: JSON.stringify signature + replacer?: ((this: any, key: string, value: any) => any) | null, + space?: string | number, ) { - const res = JSON.stringify( - value, - (key, value_) => { - const value__ = typeof value_ === "bigint" ? value_.toString() : value_; - return typeof replacer === "function" ? replacer(key, value__) : value__; - }, - space, - ); - return res; + const res = JSON.stringify( + value, + (key, value_) => { + const value__ = typeof value_ === "bigint" ? value_.toString() : value_; + return typeof replacer === "function" ? replacer(key, value__) : value__; + }, + space, + ); + return res; } export type MaybeErrorResponse = { result: D } | { error: E }; export function isErrorResponse( - res: MaybeErrorResponse, + res: MaybeErrorResponse, ): res is { error: E } { - return "error" in res; + return "error" in res; } export function isSuccessResponse( - res: MaybeErrorResponse, + res: MaybeErrorResponse, ): res is { result: D } { - return "result" in res; + return "result" in res; } diff --git a/packages/engine/src/exports/thirdweb.ts b/packages/engine/src/exports/thirdweb.ts index 9733589317a..8da457075e5 100644 --- a/packages/engine/src/exports/thirdweb.ts +++ b/packages/engine/src/exports/thirdweb.ts @@ -1,8 +1,8 @@ export type { CreateClientConfig } from "../client/client.gen.js"; export * from "../client/index.js"; export { - configure, - type EngineClientOptions, - isErrorResponse, - isSuccessResponse, + configure, + type EngineClientOptions, + isErrorResponse, + isSuccessResponse, } from "../configure.js"; diff --git a/packages/thirdweb/src/react/web/ui/Bridge/payment-details/PaymentDetails.tsx b/packages/thirdweb/src/react/web/ui/Bridge/payment-details/PaymentDetails.tsx index 4d0bf1fb7f3..008495f6f85 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/payment-details/PaymentDetails.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/payment-details/PaymentDetails.tsx @@ -370,13 +370,9 @@ export function PaymentDetails({ } ) : ( - <> - { - chainsMetadata.find( - (c) => c.chainId === step.originToken.chainId, - )?.name - } - + chainsMetadata.find( + (c) => c.chainId === step.originToken.chainId, + )?.name )} From f544086a07341adc43c6155b12015522de73fab0 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Sat, 28 Jun 2025 13:14:47 +1200 Subject: [PATCH 16/18] fix url --- packages/engine/openapi-ts.config.ts | 3 +-- packages/engine/src/client/client.gen.ts | 2 +- packages/engine/src/client/types.gen.ts | 3 ++- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/engine/openapi-ts.config.ts b/packages/engine/openapi-ts.config.ts index 3a49366c2ba..9633218c073 100644 --- a/packages/engine/openapi-ts.config.ts +++ b/packages/engine/openapi-ts.config.ts @@ -1,7 +1,6 @@ import { defineConfig } from "@hey-api/openapi-ts"; export default defineConfig({ - input: "https://engine.thirdweb-dev.com/openapi", - // input: "http://localhost:3001/openapi", + input: "https://engine.thirdweb.com/openapi", output: { format: "biome", lint: "biome", path: "src/client" }, }); diff --git a/packages/engine/src/client/client.gen.ts b/packages/engine/src/client/client.gen.ts index 378415748cb..805c0b97e50 100644 --- a/packages/engine/src/client/client.gen.ts +++ b/packages/engine/src/client/client.gen.ts @@ -23,6 +23,6 @@ export type CreateClientConfig = export const client = createClient( createConfig({ - baseUrl: "https://engine.thirdweb-dev.com", + baseUrl: "https://engine.thirdweb.com", }), ); diff --git a/packages/engine/src/client/types.gen.ts b/packages/engine/src/client/types.gen.ts index 3628a18ddf0..2dce1b1aae4 100644 --- a/packages/engine/src/client/types.gen.ts +++ b/packages/engine/src/client/types.gen.ts @@ -650,6 +650,7 @@ export type ExecutionOptions = BaseExecutionOptions & SpecificExecutionOptions; */ export type IawError = | { + message: string; type: "API_ERROR"; } | { @@ -1696,5 +1697,5 @@ export type SearchActivityLogsResponse = SearchActivityLogsResponses[keyof SearchActivityLogsResponses]; export type ClientOptions = { - baseUrl: "http://localhost:3001" | (string & {}); + baseUrl: "https://engine.thirdweb.com" | (string & {}); }; From 2547ca02eb59200e6d0c546a25c4ce94ae61ec3f Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Sat, 28 Jun 2025 13:18:56 +1200 Subject: [PATCH 17/18] cleanup --- packages/engine/package.json | 5 +- .../in-app/core/authentication/backend.ts | 3 +- .../in-app/web/lib/in-app-gateway.test.ts | 126 ++++++++++++++++++ 3 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 packages/thirdweb/src/wallets/in-app/web/lib/in-app-gateway.test.ts diff --git a/packages/engine/package.json b/packages/engine/package.json index 4e1482b09ea..2fbd8aaeb1e 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -5,7 +5,10 @@ "type": "git", "url": "git+https://github.com/thirdweb-dev/js.git#main" }, + "author": "thirdweb eng ", "type": "module", + "main": "./dist/cjs/exports/thirdweb.js", + "module": "./dist/esm/exports/thirdweb.js", "types": "./dist/types/exports/thirdweb.d.ts", "typings": "./dist/types/exports/thirdweb.d.ts", "license": "Apache-2.0", @@ -20,8 +23,8 @@ }, "exports": { ".": { - "import": "./dist/esm/exports/thirdweb.js", "types": "./dist/types/exports/thirdweb.d.ts", + "import": "./dist/esm/exports/thirdweb.js", "default": "./dist/cjs/exports/thirdweb.js" }, "./package.json": "./package.json" diff --git a/packages/thirdweb/src/wallets/in-app/core/authentication/backend.ts b/packages/thirdweb/src/wallets/in-app/core/authentication/backend.ts index 16a0a86c27a..b7e81efd36e 100644 --- a/packages/thirdweb/src/wallets/in-app/core/authentication/backend.ts +++ b/packages/thirdweb/src/wallets/in-app/core/authentication/backend.ts @@ -31,7 +31,8 @@ export async function backendAuthenticate(args: { }); if (!res.ok) { - throw new Error("Failed to generate backend account"); + const error = await res.text(); + throw new Error(`Failed to generate backend account: ${error}`); } return (await res.json()) satisfies AuthStoredTokenWithCookieReturnType; diff --git a/packages/thirdweb/src/wallets/in-app/web/lib/in-app-gateway.test.ts b/packages/thirdweb/src/wallets/in-app/web/lib/in-app-gateway.test.ts new file mode 100644 index 00000000000..e48111df520 --- /dev/null +++ b/packages/thirdweb/src/wallets/in-app/web/lib/in-app-gateway.test.ts @@ -0,0 +1,126 @@ +import { sendTransaction, signMessage } from "@thirdweb-dev/engine"; +import { beforeAll, describe, expect, it } from "vitest"; +import { TEST_CLIENT } from "~test/test-clients.js"; +import { sepolia } from "../../../../chains/chain-definitions/sepolia.js"; +import { createThirdwebClient } from "../../../../client/client.js"; +import { waitForTransactionHash } from "../../../../engine/wait-for-tx-hash.js"; +import { + getThirdwebBaseUrl, + setThirdwebDomains, +} from "../../../../utils/domains.js"; +import { getClientFetch } from "../../../../utils/fetch.js"; +import { stringify } from "../../../../utils/json.js"; +import type { Account } from "../../../interfaces/wallet.js"; +import { inAppWallet } from "../in-app.js"; + +// TODO: productionize this test +describe + .runIf(process.env.TW_SECRET_KEY) + .skip("InAppWallet Gateway Tests", () => { + let account: Account; + let authToken: string | null | undefined; + const clientIdFetch = getClientFetch( + createThirdwebClient({ + clientId: TEST_CLIENT.clientId, + }), + ); + + beforeAll(async () => { + setThirdwebDomains({ + bundler: "bundler.thirdweb-dev.com", + engineCloud: "engine.thirdweb-dev.com", + inAppWallet: "embedded-wallet.thirdweb-dev.com", + rpc: "rpc.thirdweb-dev.com", + }); + const wallet = inAppWallet(); + account = await wallet.connect({ + client: TEST_CLIENT, + strategy: "backend", + walletSecret: "test-secret", + }); + authToken = wallet.getAuthToken?.(); + expect(authToken).toBeDefined(); + }); + + it("should sign a message with backend strategy", async () => { + const rawSignature = await account.signMessage({ + message: "Hello, world!", + }); + + // sign via api + const signResult = await signMessage({ + baseUrl: getThirdwebBaseUrl("engineCloud"), + body: { + params: [ + { + format: "text", + message: "Hello, world!", + }, + ], + signingOptions: { + from: account.address, + type: "eoa", + }, + }, + bodySerializer: stringify, + fetch: clientIdFetch, + headers: { + "x-wallet-access-token": authToken, + }, + }); + + const signatureResult = signResult.data?.result?.results[0]; + if (signatureResult && "result" in signatureResult) { + expect(signatureResult.result.signature).toEqual(rawSignature); + } else { + throw new Error( + `Failed to sign message: ${stringify(signatureResult?.error) || "Unknown error"}`, + ); + } + }); + + it("should queue a 4337 transaction", async () => { + const body = { + executionOptions: { + chainId: sepolia.id, + from: account.address, + type: "auto" as const, + }, + params: [ + { + data: "0x", + to: account.address, + value: "0", + }, + ], + }; + const result = await sendTransaction({ + baseUrl: getThirdwebBaseUrl("engineCloud"), + body, + bodySerializer: stringify, + fetch: clientIdFetch, + headers: { + "x-wallet-access-token": authToken, + }, + }); + if (result.error) { + throw new Error( + `Error sending transaction: ${stringify(result.error)}`, + ); + } + + const txId = result.data?.result.transactions[0]?.id; + console.log(txId); + if (!txId) { + throw new Error("No transaction ID found"); + } + + const tx = await waitForTransactionHash({ + client: TEST_CLIENT, + transactionId: txId, + }); + + console.log(tx); + expect(tx.transactionHash).toBeDefined(); + }); + }); From e58d5f7a90c59ee31f6c49c6cf6034811ef7c92c Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Sat, 28 Jun 2025 13:29:15 +1200 Subject: [PATCH 18/18] changeset --- .changeset/heavy-banks-think.md | 5 +++++ .changeset/lovely-brooms-relax.md | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 .changeset/heavy-banks-think.md create mode 100644 .changeset/lovely-brooms-relax.md diff --git a/.changeset/heavy-banks-think.md b/.changeset/heavy-banks-think.md new file mode 100644 index 00000000000..bd67df35d64 --- /dev/null +++ b/.changeset/heavy-banks-think.md @@ -0,0 +1,5 @@ +--- +"@thirdweb-dev/engine": minor +--- + +New engine v3 APIs - see changelog for breaking changes diff --git a/.changeset/lovely-brooms-relax.md b/.changeset/lovely-brooms-relax.md new file mode 100644 index 00000000000..8f0cad5cd7e --- /dev/null +++ b/.changeset/lovely-brooms-relax.md @@ -0,0 +1,5 @@ +--- +"thirdweb": patch +--- + +Support latest engine API