import {z} from 'zod' export type RoutersTronModelsValidationOptions = 'validation' | 'simulation' | 'events'; export type RoutersTronModelsMetadataNonDapp = {non_dapp?: true | undefined}; export type RoutersTronModelsMetadataDapp = {domain: string}; export type RoutersTronModelsAddressStateOverride = {balance?: string | undefined, nonce?: string | undefined, code?: string | undefined, state?: {[key: string]: string} | undefined, stateDiff?: {[key: string]: string} | undefined, movePrecompileToAddress?: string | undefined}; export type RoutersTronTransactionModelsTransaction = {from: string, to?: string | undefined, data?: string | undefined, value?: string | undefined}; export type RoutersTronTransactionModelsTransactionRequest = {options?: Array | undefined, metadata: RoutersTronModelsMetadataNonDapp | RoutersTronModelsMetadataDapp, state_override?: {[key: string]: RoutersTronModelsAddressStateOverride} | undefined, simulate_with_estimated_gas?: boolean | undefined, account_address: string, data: RoutersTronTransactionModelsTransaction}; export type CreateApiV0TronTransactionScanArgs = {body: RoutersTronTransactionModelsTransactionRequest}; export type CreateApiV0TronTransactionScanOptions = {baseUrl?: string | undefined, APIKey?: string | undefined, fetch?: typeof fetch | undefined}; export const routersTronResponseTransactionValidationSuccessResultType = z.enum(["Benign", "Warning", "Malicious"]); export const routersTronResponseTransactionScanFeatureType = z.enum(["Malicious", "Warning", "Benign", "Info"]); export const routersTronResponseTransactionScanFeature = z.object({type: routersTronResponseTransactionScanFeatureType, feature_id: z.string(), description: z.string(), address: z.string().optional(), metadata: z.object({}).optional()}); export const routersTronResponseTransactionValidation = z.object({status: z.literal("Success"), result_type: routersTronResponseTransactionValidationSuccessResultType, description: z.string().optional(), reason: z.string().optional(), classification: z.string().optional(), features: z.array(routersTronResponseTransactionScanFeature)}); export const routersTronResponseTransactionValidationError = z.object({status: z.literal("Success"), result_type: z.literal("Error"), description: z.literal(""), reason: z.literal(""), classification: z.literal(""), features: z.array(routersTronResponseTransactionScanFeature), error: z.string()}); export const routersTronTokenDetailsERC20TokenDetails = z.object({name: z.string().optional(), symbol: z.string().optional(), address: z.string(), logo_url: z.string().optional(), type: z.literal("ERC20"), decimals: z.number().int()}); export const routersTronTokenDetailsNONERCTokenDetails = z.object({name: z.string().optional(), symbol: z.string().optional(), address: z.string(), logo_url: z.string().optional(), type: z.literal("NONERC")}); export const routersTronResponseERC20Diff = z.object({usd_price: z.string().optional(), summary: z.string().optional(), value: z.string().optional(), raw_value: z.string()}); export const routersTronResponseERC20AddressAssetDiff = z.object({asset_type: z.literal("ERC20"), asset: z.union([routersTronTokenDetailsERC20TokenDetails, routersTronTokenDetailsNONERCTokenDetails]), in: z.array(routersTronResponseERC20Diff), out: z.array(routersTronResponseERC20Diff)}); export const routersTronTokenDetailsERC721TokenDetails = z.object({name: z.string().optional(), symbol: z.string().optional(), address: z.string(), logo_url: z.string().optional(), type: z.literal("ERC721")}); export const routersTronResponseERC721Diff = z.object({usd_price: z.string().optional(), summary: z.string().optional(), token_id: z.string(), arbitrary_collection_token: z.boolean(), logo_url: z.string().optional()}); export const routersTronResponseERC721AddressAssetDiff = z.object({asset_type: z.literal("ERC721"), asset: z.union([routersTronTokenDetailsERC721TokenDetails, routersTronTokenDetailsNONERCTokenDetails]), in: z.array(routersTronResponseERC721Diff), out: z.array(routersTronResponseERC721Diff)}); export const routersTronTokenDetailsERC1155TokenDetails = z.object({name: z.string().optional(), symbol: z.string().optional(), address: z.string(), logo_url: z.string().optional(), type: z.literal("ERC1155")}); export const routersTronResponseERC1155Diff = z.object({usd_price: z.string().optional(), summary: z.string().optional(), token_id: z.string(), value: z.string(), arbitrary_collection_token: z.boolean(), logo_url: z.string().optional()}); export const routersTronResponseERC1155AddressAssetDiff = z.object({asset_type: z.literal("ERC1155"), asset: z.union([routersTronTokenDetailsERC1155TokenDetails, routersTronTokenDetailsNONERCTokenDetails]), in: z.array(routersTronResponseERC1155Diff), out: z.array(routersTronResponseERC1155Diff)}); export const routersTronTokenDetailsNativeAssetDetails = z.object({type: z.literal("NATIVE"), name: z.string().optional(), symbol: z.string().optional(), chain_name: z.string(), chain_id: z.number().int(), decimals: z.number().int(), logo_url: z.string()}); export const routersTronResponseNativeDiff = z.object({usd_price: z.string().optional(), summary: z.string().optional(), value: z.string().optional(), raw_value: z.string()}); export const routersTronResponseNativeAddressAssetDiff = z.object({asset_type: z.literal("NATIVE"), asset: routersTronTokenDetailsNativeAssetDetails, in: z.array(routersTronResponseNativeDiff), out: z.array(routersTronResponseNativeDiff)}); export const routersTronResponseTransactionAction = z.enum(["mint", "stake", "swap", "native_transfer", "token_transfer", "approval", "set_code_account", "proxy_upgrade", "ownership_change"]); export const routersTronResponseUSDDiff = z.object({in: z.string(), out: z.string(), total: z.string()}); export const routersTronResponseAssetDiffResponse = z.union([routersTronResponseERC1155Diff, routersTronResponseERC721Diff, routersTronResponseERC20Diff, routersTronResponseNativeDiff]); export const routersTronResponseERC20Exposure = z.object({exposure: z.array(routersTronResponseAssetDiffResponse), summary: z.string().optional(), approval: z.string(), approval_usd_price: z.string().optional(), expiration: z.string().optional()}); export const routersTronResponseERC20AddressExposure = z.object({asset_type: z.literal("ERC20"), asset: z.union([routersTronTokenDetailsERC20TokenDetails, routersTronTokenDetailsNONERCTokenDetails]), spenders: z.record(z.string(), routersTronResponseERC20Exposure)}); export const routersTronResponseERC721Exposure = z.object({exposure: z.array(routersTronResponseAssetDiffResponse), summary: z.string().optional(), is_approved_for_all: z.boolean()}); export const routersTronResponseERC721AddressExposure = z.object({asset_type: z.literal("ERC721"), asset: z.union([routersTronTokenDetailsERC721TokenDetails, routersTronTokenDetailsNONERCTokenDetails]), spenders: z.record(z.string(), routersTronResponseERC721Exposure)}); export const routersTronResponseERC1155Exposure = z.object({exposure: z.array(routersTronResponseAssetDiffResponse), summary: z.string().optional(), is_approved_for_all: z.boolean()}); export const routersTronResponseERC1155AddressExposure = z.object({asset_type: z.literal("ERC1155"), asset: z.union([routersTronTokenDetailsERC1155TokenDetails, routersTronTokenDetailsNONERCTokenDetails]), spenders: z.record(z.string(), routersTronResponseERC1155Exposure)}); export const routersTronResponseAddressDetails = z.object({name_tag: z.string().optional(), contract_name: z.string().optional(), is_eoa: z.boolean().optional()}); export const routersTronResponseERC20BalanceChanges = z.object({before: routersTronResponseERC20Diff, after: routersTronResponseERC20Diff}); export const routersTronResponseERC20AddressAssetBalanceChangeDiff = z.object({asset_type: z.literal("ERC20"), asset: z.union([routersTronTokenDetailsERC20TokenDetails, routersTronTokenDetailsNONERCTokenDetails]), in: z.array(routersTronResponseERC20Diff), out: z.array(routersTronResponseERC20Diff), balance_changes: routersTronResponseERC20BalanceChanges.optional()}); export const routersTronResponseERC721BalanceChanges = z.object({before: routersTronResponseERC721Diff, after: routersTronResponseERC721Diff}); export const routersTronResponseERC721AddressAssetBalanceChangeDiff = z.object({asset_type: z.literal("ERC721"), asset: z.union([routersTronTokenDetailsERC721TokenDetails, routersTronTokenDetailsNONERCTokenDetails]), in: z.array(routersTronResponseERC721Diff), out: z.array(routersTronResponseERC721Diff), balance_changes: routersTronResponseERC721BalanceChanges.optional()}); export const routersTronResponseERC1155BalanceChanges = z.object({before: routersTronResponseERC1155Diff, after: routersTronResponseERC1155Diff}); export const routersTronResponseERC1155AddressAssetBalanceChangeDiff = z.object({asset_type: z.literal("ERC1155"), asset: z.union([routersTronTokenDetailsERC1155TokenDetails, routersTronTokenDetailsNONERCTokenDetails]), in: z.array(routersTronResponseERC1155Diff), out: z.array(routersTronResponseERC1155Diff), balance_changes: routersTronResponseERC1155BalanceChanges.optional()}); export const routersTronResponseNativeBalanceChanges = z.object({before: routersTronResponseNativeDiff, after: routersTronResponseNativeDiff}); export const routersTronResponseNativeAddressAssetBalanceChangeDiff = z.object({asset_type: z.literal("NATIVE"), asset: routersTronTokenDetailsNativeAssetDetails, in: z.array(routersTronResponseNativeDiff), out: z.array(routersTronResponseNativeDiff), balance_changes: routersTronResponseNativeBalanceChanges.optional()}); export const routersTronResponseTraceLabels = z.literal("GAS_FEE"); export const routersTronResponseERC20AssetTrace = z.object({trace_type: z.literal("AssetTrace"), from_address: z.string(), to_address: z.string(), labels: z.array(z.union([routersTronResponseTraceLabels, z.string()])).optional(), type: z.literal("ERC20AssetTrace"), asset: z.union([routersTronTokenDetailsERC20TokenDetails, routersTronTokenDetailsNONERCTokenDetails]), diff: routersTronResponseERC20Diff}); export const routersTronResponseERC721AssetTrace = z.object({trace_type: z.literal("AssetTrace"), from_address: z.string(), to_address: z.string(), labels: z.array(z.union([routersTronResponseTraceLabels, z.string()])).optional(), type: z.literal("ERC721AssetTrace"), asset: z.union([routersTronTokenDetailsERC721TokenDetails, routersTronTokenDetailsNONERCTokenDetails]), diff: routersTronResponseERC721Diff}); export const routersTronResponseERC1155AssetTrace = z.object({trace_type: z.literal("AssetTrace"), from_address: z.string(), to_address: z.string(), labels: z.array(z.union([routersTronResponseTraceLabels, z.string()])).optional(), type: z.literal("ERC1155AssetTrace"), asset: z.union([routersTronTokenDetailsERC1155TokenDetails, routersTronTokenDetailsNONERCTokenDetails]), diff: routersTronResponseERC1155Diff}); export const routersTronResponseNativeAssetTrace = z.object({trace_type: z.literal("AssetTrace"), from_address: z.string(), to_address: z.string(), labels: z.array(z.union([routersTronResponseTraceLabels, z.string()])).optional(), type: z.literal("NativeAssetTrace"), asset: routersTronTokenDetailsNativeAssetDetails, diff: routersTronResponseNativeDiff}); export const routersTronResponseFungibleTokenBalance = z.object({raw_value: z.string(), value: z.number().optional(), usd_price: z.number().optional()}); export const routersTronResponseERC20ExposureTrace = z.object({trace_type: z.literal("ExposureTrace"), owner: z.string(), spender: z.string(), type: z.literal("ERC20ExposureTrace"), exposed: routersTronResponseFungibleTokenBalance, asset: z.union([routersTronTokenDetailsERC20TokenDetails, routersTronTokenDetailsNONERCTokenDetails])}); export const routersTronResponseNonFungibleTokenBalance = z.object({token_id: z.string(), amount: z.number().int(), usd_price: z.number().optional(), is_mint: z.boolean().optional(), logo_url: z.string().optional()}); export const routersTronResponseERC721ExposureTrace = z.object({trace_type: z.literal("ExposureTrace"), owner: z.string(), spender: z.string(), type: z.literal("ERC721ExposureTrace"), exposed: routersTronResponseNonFungibleTokenBalance.optional(), asset: z.union([routersTronTokenDetailsERC721TokenDetails, routersTronTokenDetailsNONERCTokenDetails])}); export const routersTronResponseERC1155ExposureTrace = z.object({trace_type: z.literal("ExposureTrace"), owner: z.string(), spender: z.string(), type: z.literal("ERC1155ExposureTrace"), asset: z.union([routersTronTokenDetailsERC1155TokenDetails, routersTronTokenDetailsNONERCTokenDetails])}); export const routersTronResponseAccountSummary = z.object({assets_diffs: z.array(z.union([routersTronResponseERC20AddressAssetBalanceChangeDiff, routersTronResponseERC721AddressAssetBalanceChangeDiff, routersTronResponseERC1155AddressAssetBalanceChangeDiff, routersTronResponseNativeAddressAssetBalanceChangeDiff])), traces: z.array(z.union([routersTronResponseERC20AssetTrace, routersTronResponseERC721AssetTrace, routersTronResponseERC1155AssetTrace, routersTronResponseNativeAssetTrace, routersTronResponseERC20ExposureTrace, routersTronResponseERC721ExposureTrace, routersTronResponseERC1155ExposureTrace])), total_usd_diff: routersTronResponseUSDDiff, exposures: z.array(z.union([routersTronResponseERC20AddressExposure, routersTronResponseERC721AddressExposure, routersTronResponseERC1155AddressExposure])), total_usd_exposure: z.record(z.string(), z.string())}); export const routersTronResponseCallData = z.object({function_selector: z.string(), function_signature: z.string().optional(), function_declaration: z.string().optional()}); export const routersTronResponseJsonRPCParams = z.object({from: z.string().optional(), to: z.string().optional(), value: z.string().optional(), data: z.string().optional(), gas: z.string().optional(), gas_price: z.string().optional(), block_tag: z.string().optional(), chain: z.string().optional(), calldata: routersTronResponseCallData.optional(), user_operation_calldata: routersTronResponseCallData.optional()}); export const routersTronResponseAddressChange = z.object({address: z.string()}); export const routersTronResponseProxyUpgradeManagement = z.object({type: z.literal("PROXY_UPGRADE"), before: routersTronResponseAddressChange, after: routersTronResponseAddressChange}); export const routersTronResponseOwnershipChange = z.object({owners: z.array(z.string())}); export const routersTronResponseOwnershipChangeManagement = z.object({type: z.literal("OWNERSHIP_CHANGE"), before: routersTronResponseOwnershipChange, after: routersTronResponseOwnershipChange}); export const routersTronResponseModulesChange = z.object({modules: z.array(z.string())}); export const routersTronResponseModulesChangeManagement = z.object({type: z.literal("MODULE_CHANGE"), before: routersTronResponseModulesChange, after: routersTronResponseModulesChange}); export const routersTronResponseSetCodeAccountManagement = z.object({type: z.literal("SET_CODE_ACCOUNT"), delegated_address: z.string()}); export const routersTronResponseContractCreation = z.object({type: z.literal("CONTRACT_CREATION"), deployer: z.string()}); export const routersTronSessionKeysTransferPolicy = z.object({type: z.literal("TRANSFER_POLICY").optional(), asset_details: z.union([routersTronTokenDetailsNativeAssetDetails, routersTronTokenDetailsERC20TokenDetails]), value_limit: z.string().optional(), recipient: z.string().optional()}); export const routersTronSessionKeysCondition = z.enum(["UNCONSTRAINED", "EQUAL", "GREATER", "LESS", "GREATER_OR_EQUAL", "LESS_OR_EQUAL", "NOT_EQUAL"]); export const routersTronSessionKeysArgumentCondition = z.object({index: z.number().int(), condition: routersTronSessionKeysCondition, value: z.string()}); export const routersTronSessionKeysCallPolicy = z.object({type: z.literal("CALL_POLICY").optional(), to_address: z.string(), method: z.string().optional(), value_limit: z.string().optional(), args: z.array(routersTronSessionKeysArgumentCondition).optional()}); export const routersTronSessionKeysGasPolicy = z.object({type: z.literal("GAS_POLICY").optional(), value_limit: z.string()}); export const routersTronSessionKeysExpirationPolicy = z.object({type: z.literal("EXPIRATION_POLICY").optional(), start_time: z.string().optional(), end_time: z.string().optional()}); export const routersTronSessionKeysSessionKey = z.object({key: z.string(), signer: z.string(), policies: z.array(z.union([routersTronSessionKeysTransferPolicy, routersTronSessionKeysCallPolicy, routersTronSessionKeysGasPolicy, routersTronSessionKeysExpirationPolicy]))}); export const routersTronResponseBalance = z.object({raw_value: z.string(), value: z.string().optional()}); export const routersTronResponseMissingBalance = z.object({asset: z.union([routersTronTokenDetailsERC20TokenDetails, routersTronTokenDetailsNativeAssetDetails]), required_balance: routersTronResponseBalance, current_balance: routersTronResponseBalance, missing_balance: routersTronResponseBalance}); export const routersTronResponseTransactionSimulation = z.object({status: z.literal("Success"), assets_diffs: z.record(z.string(), z.array(z.union([routersTronResponseERC20AddressAssetDiff, routersTronResponseERC721AddressAssetDiff, routersTronResponseERC1155AddressAssetDiff, routersTronResponseNativeAddressAssetDiff]))), transaction_actions: z.array(z.union([routersTronResponseTransactionAction, z.string()])), total_usd_diff: z.record(z.string(), routersTronResponseUSDDiff), exposures: z.record(z.string(), z.array(z.union([routersTronResponseERC20AddressExposure, routersTronResponseERC721AddressExposure, routersTronResponseERC1155AddressExposure]))), total_usd_exposure: z.record(z.string(), z.record(z.string(), z.string())), address_details: z.record(z.string(), routersTronResponseAddressDetails), account_summary: routersTronResponseAccountSummary, params: routersTronResponseJsonRPCParams.optional(), contract_management: z.record(z.string(), z.array(z.union([routersTronResponseProxyUpgradeManagement, routersTronResponseOwnershipChangeManagement, routersTronResponseModulesChangeManagement, routersTronResponseSetCodeAccountManagement, routersTronResponseContractCreation]))).optional(), session_key: z.record(z.string(), z.array(routersTronSessionKeysSessionKey)), missing_balances: z.array(routersTronResponseMissingBalance).optional(), simulation_run_count: z.number().int().optional()}); export const routersTronResponseNativeAsset = z.object({type: z.literal("NATIVE"), details: routersTronTokenDetailsNativeAssetDetails}); export const routersTronResponseERC20Asset = z.object({type: z.literal("ERC20"), details: routersTronTokenDetailsERC20TokenDetails}); export const routersTronResponseERC721Asset = z.object({type: z.literal("ERC721"), token_id: z.number().int(), details: routersTronTokenDetailsERC1155TokenDetails}); export const routersTronResponseERC1155Asset = z.object({type: z.literal("ERC1155"), token_id: z.number().int(), details: routersTronTokenDetailsERC1155TokenDetails}); export const routersTronResponseGeneralInsufficientFundsErrorDetails = z.object({code: z.literal("GENERAL_INSUFFICIENT_FUNDS"), category: z.literal("REVERT").optional(), account_address: z.string(), current_balance: z.string().optional(), required_balance: z.string().optional(), asset: z.union([routersTronResponseNativeAsset, routersTronResponseERC20Asset, routersTronResponseERC721Asset, routersTronResponseERC1155Asset])}); export const routersTronResponseGeneralInvalidAddressErrorDetails = z.object({code: z.literal("GENERAL_INVALID_ADDRESS"), category: z.literal("INVALID_INPUT").optional(), address: z.string()}); export const routersTronResponseGenericErrorDetails = z.object({code: z.string(), category: z.string()}); export const routersTronResponseUnsupportedEIP712MessageErrorDetails = z.object({code: z.literal("UNSUPPORTED_EIP712_MESSAGE"), category: z.literal("INVALID_INPUT").optional(), domain_name: z.string(), message_type: z.string()}); export const routersTronResponseTransactionSimulationError = z.object({status: z.literal("Error"), error: z.string(), error_details: z.union([routersTronResponseGeneralInsufficientFundsErrorDetails, routersTronResponseGeneralInvalidAddressErrorDetails, routersTronResponseGenericErrorDetails, routersTronResponseUnsupportedEIP712MessageErrorDetails]).optional(), description: z.string()}); export const routersTronModelsTransactionScanLogParamInfo = z.object({type: z.string(), value: z.union([z.string(), z.object({}), z.array(z.unknown())]), internalType: z.string().optional(), name: z.string().optional()}); export const routersTronModelsTransactionScanEvent = z.object({emitter_address: z.string(), emitter_name: z.string().optional(), name: z.string().optional(), params: z.array(routersTronModelsTransactionScanLogParamInfo).optional(), topics: z.array(z.string()), data: z.string()}); export const routersTronModelsTransactionScanGasEstimation = z.object({status: z.literal("Success"), used: z.string(), estimate: z.string()}); export const routersTronModelsTransactionScanGasEstimationError = z.object({status: z.literal("Error"), error: z.string()}); export const routersTronModelsUserOperationV6GasEstimation = z.object({status: z.literal("Success"), pre_verification_gas_estimate: z.string(), verification_gas_estimate: z.string(), call_gas_estimate: z.string()}); export const routersTronModelsUserOperationV7GasEstimation = z.object({status: z.literal("Success"), pre_verification_gas_estimate: z.string(), verification_gas_estimate: z.string(), call_gas_estimate: z.string(), paymaster_verification_gas_estimate: z.string()}); export const routersTronResponseTransactionScanResponse = z.object({validation: z.union([routersTronResponseTransactionValidation, routersTronResponseTransactionValidationError]).optional(), simulation: z.union([routersTronResponseTransactionSimulation, routersTronResponseTransactionSimulationError]).optional(), events: z.array(routersTronModelsTransactionScanEvent).optional(), gas_estimation: z.union([routersTronModelsTransactionScanGasEstimation, routersTronModelsTransactionScanGasEstimationError]).optional(), user_operation_gas_estimation: z.union([routersTronModelsUserOperationV6GasEstimation, routersTronModelsUserOperationV7GasEstimation, routersTronModelsTransactionScanGasEstimationError]).optional(), features: z.object({}).optional(), block: z.string(), chain: z.string(), account_address: z.string().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 }; /** * Scan Transaction * * POST /v0/tron/transaction/scan * * Also accepts auth: ClientID */ export const createApiV0TronTransactionScan = async (args: CreateApiV0TronTransactionScanArgs, options?: CreateApiV0TronTransactionScanOptions) => { const {baseUrl = "https://api.blockaid.io", fetch: fetchFn = fetch, APIKey} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (APIKey !== undefined) headers.set("X-API-Key", APIKey) const url = `${baseUrl.replace(/\/+$/, '')}/v0/tron/transaction/scan${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(routersTronResponseTransactionScanResponse, await res.json()) };