import {z} from 'zod' export type GetApiV2TxStatusArgs = {tx_hash: string, chain_id: string}; export type GetApiV2TxStatusOptions = {baseUrl?: string | undefined, fetch?: typeof fetch | undefined}; export const transactionState = z.enum(["STATE_SUBMITTED", "STATE_PENDING", "STATE_ABANDONED", "STATE_COMPLETED_SUCCESS", "STATE_COMPLETED_ERROR", "STATE_PENDING_ERROR"]); export const chainTransaction = z.object({chain_id: z.string().optional(), explorer_link: z.string(), tx_hash: z.string().optional(), on_chain_at: z.string().optional()}); export const acknowledgementErrorDetails = z.object({code: z.number().optional(), message: z.string().optional()}); export const packetErrorType = z.enum(["PACKET_ERROR_UNKNOWN", "PACKET_ERROR_ACKNOWLEDGEMENT", "PACKET_ERROR_TIMEOUT"]); export const packetError = z.object({details: z.union([z.unknown(), acknowledgementErrorDetails]).optional(), message: z.string().optional(), type: packetErrorType.optional()}); export const packet = z.object({acknowledge_tx: chainTransaction.nullable().optional(), error: packetError.nullable().optional(), receive_tx: chainTransaction.nullable().optional(), send_tx: chainTransaction.nullable().optional(), timeout_tx: chainTransaction.nullable().optional()}); export const transferState = z.enum(["TRANSFER_UNKNOWN", "TRANSFER_PENDING", "TRANSFER_RECEIVED", "TRANSFER_SUCCESS", "TRANSFER_FAILURE"]); export const iBCTransferInfo = z.object({to_chain_id: z.string(), packet_txs: packet, from_chain_id: z.string(), state: transferState}); export const axelarTransferState = z.enum(["AXELAR_TRANSFER_UNKNOWN", "AXELAR_TRANSFER_PENDING_CONFIRMATION", "AXELAR_TRANSFER_PENDING_RECEIPT", "AXELAR_TRANSFER_SUCCESS", "AXELAR_TRANSFER_FAILURE"]); export const contractCallWithTokenErrorType = z.literal("CONTRACT_CALL_WITH_TOKEN_EXECUTION_ERROR"); export const contractCallWithTokenError = z.object({message: z.string().optional(), type: contractCallWithTokenErrorType.optional()}); export const contractCallWithTokenTxs = z.object({approve_tx: chainTransaction.nullable().optional(), confirm_tx: chainTransaction.nullable().optional(), error: contractCallWithTokenError.nullable().optional(), execute_tx: chainTransaction.nullable().optional(), gas_paid_tx: chainTransaction.nullable().optional(), send_tx: chainTransaction.nullable().optional()}); export const sendTokenErrorType = z.literal("SEND_TOKEN_EXECUTION_ERROR"); export const sendTokenError = z.object({message: z.string().optional(), type: sendTokenErrorType.optional()}); export const sendTokenTxs = z.object({confirm_tx: chainTransaction.nullable().optional(), error: sendTokenError.nullable().optional(), execute_tx: chainTransaction.nullable().optional(), send_tx: chainTransaction.nullable().optional()}); export const axelarTransferType = z.enum(["AXELAR_TRANSFER_CONTRACT_CALL_WITH_TOKEN", "AXELAR_TRANSFER_SEND_TOKEN"]); export const axelarTransferInfo = z.object({axelar_scan_link: z.string().optional(), to_chain_id: z.string(), from_chain_id: z.string(), state: axelarTransferState, txs: z.union([z.object({contract_call_with_token_txs: contractCallWithTokenTxs.optional()}), sendTokenTxs]), type: axelarTransferType.optional()}); export const cCTPTransferState = z.enum(["CCTP_TRANSFER_UNKNOWN", "CCTP_TRANSFER_SENT", "CCTP_TRANSFER_PENDING_CONFIRMATION", "CCTP_TRANSFER_CONFIRMED", "CCTP_TRANSFER_RECEIVED"]); export const cCTPTransferTxs = z.object({send_tx: chainTransaction.nullable().optional(), receive_tx: chainTransaction.nullable().optional()}); export const cCTPTransferInfo = z.object({to_chain_id: z.string().optional(), from_chain_id: z.string().optional(), state: cCTPTransferState.optional(), txs: cCTPTransferTxs.optional()}); export const hyperlaneTransferState = z.enum(["HYPERLANE_TRANSFER_UNKNOWN", "HYPERLANE_TRANSFER_SENT", "HYPERLANE_TRANSFER_FAILED", "HYPERLANE_TRANSFER_RECEIVED"]); export const hyperlaneTransferTransactions = z.object({send_tx: chainTransaction.nullable().optional(), receive_tx: chainTransaction.nullable().optional()}); export const hyperlaneTransferInfo = z.object({from_chain_id: z.string(), to_chain_id: z.string(), state: hyperlaneTransferState, txs: hyperlaneTransferTransactions}); export const oPInitTransferState = z.enum(["OPINIT_TRANSFER_UNKNOWN", "OPINIT_TRANSFER_SENT", "OPINIT_TRANSFER_RECEIVED"]); export const oPInitTransferTxs = z.object({send_tx: chainTransaction.nullable().optional(), receive_tx: chainTransaction.nullable().optional()}); export const oPInitTransferInfo = z.object({to_chain_id: z.string(), from_chain_id: z.string(), state: oPInitTransferState, txs: oPInitTransferTxs}); export const stargateTransferState = z.enum(["STARGATE_TRANSFER_UNKNOWN", "STARGATE_TRANSFER_SENT", "STARGATE_TRANSFER_PENDING_CONFIRMATION", "STARGATE_TRANSFER_CONFIRMED", "STARGATE_TRANSFER_RECEIVED", "STARGATE_TRANSFER_FAILED"]); export const stargateTransferTxs = z.object({send_tx: chainTransaction.nullable().optional(), receive_tx: chainTransaction.nullable().optional(), error_tx: chainTransaction.nullable().optional()}); export const stargateTransferInfo = z.object({from_chain_id: z.string().optional(), to_chain_id: z.string().optional(), state: stargateTransferState.optional(), txs: stargateTransferTxs.optional()}); export const goFastTransferState = z.enum(["GO_FAST_TRANSFER_UNKNOWN", "GO_FAST_TRANSFER_SENT", "GO_FAST_POST_ACTION_FAILED", "GO_FAST_TRANSFER_TIMEOUT", "GO_FAST_TRANSFER_FILLED", "GO_FAST_TRANSFER_REFUNDED"]); export const goFastTransferTxs = z.object({order_submitted_tx: chainTransaction.nullable().optional(), order_filled_tx: chainTransaction.nullable().optional(), order_refunded_tx: chainTransaction.nullable().optional(), order_timeout_tx: chainTransaction.nullable().optional()}); export const goFastTransferInfo = z.object({from_chain_id: z.string(), to_chain_id: z.string(), state: goFastTransferState, txs: goFastTransferTxs, error_message: z.string().nullable().optional()}); export const eurekaTransferInfo = z.object({from_chain_id: z.string(), to_chain_id: z.string(), state: transferState, packet_txs: packet}); export const layerZeroTransferState = z.enum(["LAYER_ZERO_TRANSFER_UNKNOWN", "LAYER_ZERO_TRANSFER_SENT", "LAYER_ZERO_TRANSFER_WAITING_FOR_COMPOSE", "LAYER_ZERO_TRANSFER_RECEIVED", "LAYER_ZERO_TRANSFER_FAILED"]); export const layerZeroTransferTransactions = z.object({send_tx: chainTransaction.nullable().optional(), receive_tx: chainTransaction.nullable().optional(), compose_tx: chainTransaction.nullable().optional(), error_tx: chainTransaction.nullable().optional()}); export const layerZeroTransferInfo = z.object({from_chain_id: z.string(), to_chain_id: z.string(), state: layerZeroTransferState, txs: layerZeroTransferTransactions}); export const transferEvent = z.object({ibc_transfer: iBCTransferInfo.optional(), axelar_transfer: axelarTransferInfo.optional(), cctp_transfer: cCTPTransferInfo.optional(), hyperlane_transfer: hyperlaneTransferInfo.optional(), op_init_transfer: oPInitTransferInfo.optional(), stargate_transfer: stargateTransferInfo.optional(), go_fast_transfer: goFastTransferInfo.optional(), eureka_transfer: eurekaTransferInfo.optional(), layer_zero_transfer: layerZeroTransferInfo.optional()}); export const transferAssetRelease = z.object({chain_id: z.string().optional(), denom: z.string().optional(), amount: z.string().nullable().optional(), released: z.boolean().optional()}); export const transactionExecutionErrorDetails = z.object({code: z.number().optional(), message: z.string().optional()}); export const statusErrorType = z.enum(["STATUS_ERROR_UNKNOWN", "STATUS_ERROR_TRANSACTION_EXECUTION", "STATUS_ERROR_INDEXING", "STATUS_ERROR_TRANSFER"]); export const statusError = z.object({details: transactionExecutionErrorDetails.nullable().optional(), message: z.string().optional(), type: statusErrorType.optional()}); export const transferStatus = z.object({state: transactionState.optional(), transfer_sequence: z.array(transferEvent).optional(), next_blocking_transfer: z.object({transfer_sequence_index: z.number().int().optional()}).nullable().optional(), transfer_asset_release: transferAssetRelease.optional(), error: statusError.optional()}); export const statusTxResponse = z.object({transfers: z.array(transferStatus).optional(), state: transactionState, next_blocking_transfer: z.object({transfer_sequence_index: z.number().int().optional()}).nullable().optional(), transfer_asset_release: transferAssetRelease.optional(), error: statusError.nullable().optional(), transfer_sequence: z.array(transferEvent), status: 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 }; /** * Get the status of the specified transaction and any subsequent IBC or Axelar transfers if routing assets cross chain. The transaction must have previously been submitted to either the /submit or /track endpoints. * * GET /v2/tx/status */ export const getApiV2TxStatus = async (args: GetApiV2TxStatusArgs, options?: GetApiV2TxStatusOptions) => { const {baseUrl = "https://api.skip.build", fetch: fetchFn = fetch} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (args.tx_hash != null) query.append("tx_hash", String(args.tx_hash)) if (args.chain_id != null) query.append("chain_id", String(args.chain_id)) const url = `${baseUrl.replace(/\/+$/, '')}/v2/tx/status${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "GET", headers}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(statusTxResponse, await res.json()) };