import {z} from 'zod' export type StateOverride = {[key: string]: {nonce?: number | undefined, code?: unknown | undefined, balance?: (string | number) | undefined, storage?: {[key: string]: string} | undefined}}; export type SimulationPayload = {network_id: string, from: string, to: string, input: string, gas?: number | undefined, block_number?: number | undefined, transaction_index?: number | undefined, gas_price?: string | undefined, max_fee_per_gas?: string | undefined, max_priority_fee_per_gas?: string | undefined, nonce?: number | undefined, estimate_gas?: boolean | undefined, value?: string | undefined, generate_access_list?: boolean | undefined, access_list?: Array | undefined, save?: boolean | undefined, save_if_fails?: boolean | undefined, simulation_type?: ('full' | 'quick' | 'abi') | undefined, block_header?: Record | undefined, state_objects?: StateOverride | undefined, l1_block_number?: number | undefined, l1_timestamp?: number | undefined, l1_message_sender?: string | undefined, deposit_tx?: boolean | undefined, system_tx?: boolean | undefined, mint?: number | undefined, amount_to_mint?: string | undefined}; export type CreateApiV1AccountAccountSlugProjectProjectSlugSimulateArgs = {accountSlug: string, projectSlug: string, body: SimulationPayload}; export type CreateApiV1AccountAccountSlugProjectProjectSlugSimulateOptions = {baseUrl?: string | undefined, ApiKeyAuth?: string | undefined, fetch?: typeof fetch | undefined}; export const simulationResponse = z.object({transaction: z.object({hash: z.string().optional(), block_hash: z.string().optional(), block_number: z.number().optional(), from: z.string().optional(), gas: z.number().optional(), gas_price: z.number().optional(), gas_fee_cap: z.number().optional(), gas_tip_cap: z.number().optional(), cumulative_gas_used: z.number().optional(), gas_used: z.number().optional(), effective_gas_price: z.number().optional(), input: z.string().optional(), nonce: z.number().optional(), to: z.string().optional(), index: z.number().optional(), value: z.string().optional(), access_list: z.array(z.unknown()).nullable().optional(), status: z.boolean().optional(), addresses: z.array(z.string()).optional(), contract_ids: z.array(z.string()).optional(), network_id: z.string().optional(), timestamp: z.string().optional(), function_selector: z.string().optional(), l1_block_number: z.number().optional(), l1_timestamp: z.number().optional(), deposit_tx: z.boolean().optional(), system_tx: z.boolean().optional(), sig: z.object({v: z.string().optional(), r: z.string().optional(), s: z.string().optional()}).optional(), transaction_info: z.object({contract_id: z.string().optional(), block_number: z.number().optional(), transaction_id: z.string().optional(), contract_address: z.string().optional(), method: z.string().optional(), parameters: z.array(z.unknown()).nullable().optional(), intrinsic_gas: z.number().optional(), refund_gas: z.number().optional(), call_trace: z.object({}).optional(), stack_trace: z.array(z.unknown()).nullable().optional(), logs: z.array(z.unknown()).nullable().optional(), state_diff: z.array(z.unknown()).nullable().optional(), raw_state_diff: z.array(z.unknown()).nullable().optional(), console_logs: z.array(z.unknown()).nullable().optional(), created_at: z.string().optional(), asset_changes: z.array(z.unknown()).nullable().optional(), balance_changes: z.array(z.unknown()).nullable().optional(), exposure_changes: z.array(z.unknown()).nullable().optional()}).optional(), error_message: z.string().optional(), error_info: z.object({error_message: z.string().optional(), address: z.string().optional()}).nullable().optional(), method: z.string().optional(), decoded_input: z.array(z.unknown()).nullable().optional()}).optional(), simulation: z.object({id: z.string().optional(), project_id: z.string().optional(), owner_id: z.string().optional(), network_id: z.string().optional(), block_number: z.number().optional(), transaction_index: z.number().optional(), from: z.string().optional(), to: z.string().optional(), input: z.string().optional(), gas: z.number().optional(), gas_price: z.string().optional(), gas_used: z.number().optional(), value: z.string().optional(), method: z.string().optional(), status: z.boolean().optional(), access_list: z.array(z.unknown()).nullable().optional(), queue_origin: z.string().optional(), block_header: z.object({}).optional(), deposit_tx: z.boolean().optional(), system_tx: z.boolean().optional(), error_message: z.string().optional(), nonce: z.number().optional(), addresses: z.array(z.string()).optional(), contract_ids: z.array(z.string()).optional(), shared: z.boolean().optional(), created_at: z.string().optional()}).optional(), contracts: z.array(z.object({id: z.string().optional(), contract_id: z.string().optional(), balance: z.string().optional(), network_id: z.string().optional(), public: z.boolean().optional(), verified_by: z.string().optional(), verification_date: z.string().optional(), address: z.string().optional(), contract_name: z.string().optional(), ens_domain: z.array(z.string()).nullable().optional(), type: z.enum(["wallet", "contract", "unverified_contract"]).optional(), standard: z.string().optional(), standards: z.array(z.string()).optional(), token_data: z.object({symbol: z.string().optional(), name: z.string().optional(), decimals: z.number().optional(), main: z.boolean().optional()}).nullable().optional(), evm_version: z.string().optional(), compiler_version: z.string().optional(), optimizations_used: z.boolean().optional(), optimization_runs: z.number().optional(), libraries: z.object({}).nullable().optional(), compiler_settings: z.object({}).optional(), deployed_bytecode: z.string().optional(), creation_bytecode: z.string().optional(), data: z.object({main_contract: z.string().optional(), contract_info: z.array(z.object({id: z.number().optional(), path: z.string().optional(), name: z.string().optional(), source: z.string().optional()})).optional(), abi: z.array(z.unknown()).optional()}).nullable().optional(), src_map: z.string().optional(), creation_block: z.number().optional(), creation_tx: z.string().optional(), creator_address: z.string().optional(), language: z.enum(["solidity", "vyper"]).optional(), in_project: z.boolean().optional(), token_info: z.object({}).nullable().optional()})).optional(), generated_access_list: z.array(z.object({address: z.string().optional(), storage_keys: z.array(z.string()).optional()})).optional()}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * Simulate transaction * * POST /v1/account/{accountSlug}/project/{projectSlug}/simulate * * Also accepts auth: BearerAuth */ export const createApiV1AccountAccountSlugProjectProjectSlugSimulate = async (args: CreateApiV1AccountAccountSlugProjectProjectSlugSimulateArgs, options?: CreateApiV1AccountAccountSlugProjectProjectSlugSimulateOptions) => { const {baseUrl = "https://api.tenderly.co/api", fetch: fetchFn = fetch, ApiKeyAuth} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (ApiKeyAuth !== undefined) headers.set("X-Access-Key", ApiKeyAuth) const url = `${baseUrl.replace(/\/+$/, '')}/v1/account/${encodeURIComponent(String(args.accountSlug))}/project/${encodeURIComponent(String(args.projectSlug))}/simulate${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "POST", headers, body: JSON.stringify(args.body)}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(simulationResponse, await res.json()) };