import {z} from 'zod' export type SwapVenue = {chain_id?: string | undefined, name?: string | undefined, logo_uri?: (string | null) | undefined}; export type Affiliate = {address?: string | undefined, basis_points_fee?: string | undefined}; export type ChainAffiliates = {affiliates?: Array | undefined}; export type CosmWasmContractMsg = {contract_address?: string | undefined, msg?: string | undefined}; export type CosmWasmContractMsgWrapper = {wasm_msg?: CosmWasmContractMsg | undefined}; export type AutopilotAction = 'LIQUID_STAKE' | 'CLAIM'; export type AutopilotMsg = {action?: AutopilotAction | undefined, receiver?: string | undefined}; export type AutopilotMsgWrapper = {autpilot_msg?: AutopilotMsg | undefined}; export type PostHandler = CosmWasmContractMsgWrapper | AutopilotMsgWrapper; export type BridgeType = 'IBC' | 'AXELAR' | 'CCTP' | 'HYPERLANE' | 'OPINIT' | 'GO_FAST' | 'STARGATE' | 'LAYER_ZERO' | 'EUREKA'; export type SmartSwapOptions = {split_routes?: boolean | undefined, evm_swaps?: boolean | undefined}; export type MsgsDirectRequest = {source_asset_denom?: string | undefined, source_asset_chain_id?: string | undefined, dest_asset_denom?: string | undefined, dest_asset_chain_id?: string | undefined, amount_in?: string | undefined, amount_out?: string | undefined, chain_ids_to_addresses?: {[key: string]: string} | undefined, swap_venues?: Array | undefined, slippage_tolerance_percent?: string | undefined, chain_ids_to_affiliates?: {[key: string]: ChainAffiliates} | undefined, post_route_handler?: PostHandler | undefined, timeout_seconds?: string | undefined, allow_unsafe?: boolean | undefined, experimental_features?: Array | undefined, allow_multi_tx?: boolean | undefined, bridges?: Array | undefined, smart_relay?: boolean | undefined, smart_swap_options?: SmartSwapOptions | undefined, allow_swaps?: boolean | undefined, enable_gas_warnings?: boolean | undefined, go_fast?: boolean | undefined, fee_payer_address?: string | undefined}; export type CreateApiV2FungibleMsgsDirectArgs = {body: MsgsDirectRequest}; export type CreateApiV2FungibleMsgsDirectOptions = {baseUrl?: string | undefined, fetch?: typeof fetch | undefined}; export const multiChainMsg = z.object({chain_id: z.string().optional(), msg: z.string().optional(), msg_type_url: z.string().optional(), path: z.array(z.string()).optional()}); export const multiChainMsgWrapper = z.object({multi_chain_msg: multiChainMsg.optional()}); export const erc20Approval = z.object({amount: z.string(), spender: z.string(), token_contract: z.string()}); export const evmTx = z.object({chain_id: z.string(), data: z.string().optional(), required_erc20_approvals: z.array(erc20Approval).optional(), signer_address: z.string().optional(), to: z.string().optional(), value: z.string().optional()}); export const evmTxWrapper = z.object({evm_tx: evmTx}); export const svmTx = z.object({chain_id: z.string(), signer_address: z.string().optional(), tx: z.string().optional()}); export const svmTxWrapper = z.object({svm_tx: svmTx}); export const msg = z.union([multiChainMsgWrapper, evmTxWrapper, svmTxWrapper]); export const cosmosMsg = z.object({msg: z.string().optional(), msg_type_url: z.string().optional()}); export const cosmosTx = z.object({chain_id: z.string(), path: z.array(z.string()).optional(), signer_address: z.string().optional(), msgs: z.array(cosmosMsg).optional()}); export const tx = z.union([z.object({cosmos_tx: cosmosTx, operations_indices: z.array(z.number().int()).optional()}), z.object({evm_tx: evmTx, operations_indices: z.array(z.number().int()).optional()}), z.object({svm_tx: svmTx, operations_indices: z.array(z.number().int()).optional()})]); export const asset = z.object({denom: z.string(), chain_id: z.string(), origin_denom: z.string(), origin_chain_id: z.string(), trace: z.string(), is_cw20: z.boolean(), is_evm: z.boolean(), is_svm: z.boolean(), symbol: z.string().nullable().optional(), name: z.string().nullable().optional(), logo_uri: z.string().nullable().optional(), decimals: z.number().nullable().optional(), token_contract: z.string().nullable().optional(), description: z.string().nullable().optional(), coingecko_id: z.string().nullable().optional(), recommended_symbol: z.string().nullable().optional()}); export const bridgeType = z.enum(["IBC", "AXELAR", "CCTP", "HYPERLANE", "OPINIT", "GO_FAST", "STARGATE", "LAYER_ZERO", "EUREKA"]); export const transfer = z.object({port: z.string().optional(), channel: z.string().optional(), from_chain_id: z.string().optional(), to_chain_id: z.string().optional(), pfm_enabled: z.boolean().optional(), supports_memo: z.boolean().optional(), denom_in: z.string().optional(), denom_out: z.string().optional(), fee_amount: z.string().nullable().optional(), usd_fee_amount: z.string().nullable().optional(), fee_asset: asset.optional(), bridge_id: bridgeType.optional(), smart_relay: z.boolean().optional(), to_chain_entry_contract_address: z.string().nullable().optional(), to_chain_callback_contract_address: z.string().nullable().optional(), dest_denom: z.string().optional()}); export const swapVenue = z.object({chain_id: z.string().optional(), name: z.string().optional(), logo_uri: z.string().nullable().optional()}); export const swapOperation = z.object({denom_in: z.string().optional(), denom_out: z.string().optional(), pool: z.string().optional(), interface: z.string().nullable().optional()}); export const swapExactCoinIn = z.object({swap_venue: swapVenue.optional(), swap_operations: z.array(swapOperation).optional(), swap_amount_in: z.string().nullable().optional(), price_impact_percent: z.string().nullable().optional(), estimated_amount_out: z.string().nullable().optional()}); export const swapExactCoinOut = z.object({swap_venue: swapVenue.optional(), swap_operations: z.array(swapOperation).optional(), swap_amount_out: z.string().optional(), price_impact_percent: z.string().nullable().optional()}); export const swapRoute = z.object({swap_amount_in: z.string().optional(), denom_in: z.string().optional(), swap_operations: z.array(swapOperation).optional()}); export const smartSwapExactCoinIn = z.object({swap_venue: swapVenue.optional(), swap_routes: z.array(swapRoute).optional(), estimated_amount_out: z.string().nullable().optional()}); export const swap = z.union([z.object({swap_in: swapExactCoinIn.optional(), estimated_affiliate_fee: z.string().optional(), from_chain_id: z.string().optional(), chain_id: z.string().optional(), denom_in: z.string().optional(), denom_out: z.string().optional(), swap_venues: z.array(swapVenue).optional()}), z.object({swap_out: swapExactCoinOut.optional(), estimated_affiliate_fee: z.string().optional(), from_chain_id: z.string().optional(), chain_id: z.string().optional(), denom_in: z.string().optional(), denom_out: z.string().optional(), swap_venues: z.array(swapVenue).optional()}), z.object({smart_swap_in: smartSwapExactCoinIn.optional(), estimated_affiliate_fee: z.string().optional(), from_chain_id: z.string().optional(), chain_id: z.string().optional(), denom_in: z.string().optional(), denom_out: z.string().optional(), swap_venues: z.array(swapVenue).optional()})]); export const axelarTransfer = z.object({from_chain_id: z.string().optional(), to_chain_id: z.string().optional(), asset: z.string().optional(), should_unwrap: z.boolean().optional(), denom_in: z.string().optional(), denom_out: z.string().optional(), fee_amount: z.string().optional(), usd_fee_amount: z.string().optional(), fee_asset: asset.optional(), is_testnet: z.boolean().optional(), ibc_transfer_to_axelar: transfer.optional(), bridge_id: bridgeType.optional(), smart_relay: z.boolean().optional(), from_chain: z.string().optional(), to_chain: z.string().optional()}); export const bankSend = z.object({chain_id: z.string().optional(), denom: z.string().optional()}); export const smartRelayFeeQuote = z.object({fee_amount: z.string().optional(), relayer_address: z.string().optional(), expiration: z.string().optional(), fee_denom: z.string().optional(), fee_payment_address: z.string().nullable().optional()}); export const cCTPTransfer = z.object({from_chain_id: z.string().optional(), to_chain_id: z.string().optional(), burn_token: z.string().optional(), denom_in: z.string().optional(), denom_out: z.string().optional(), bridge_id: bridgeType.optional(), smart_relay: z.boolean().optional(), smart_relay_fee_quote: smartRelayFeeQuote.nullable().optional()}); export const hyperlaneTransfer = z.object({from_chain_id: z.string().optional(), to_chain_id: z.string().optional(), denom_in: z.string().optional(), denom_out: z.string().optional(), hyperlane_contract_address: z.string().optional(), fee_amount: z.string().optional(), usd_fee_amount: z.string().optional(), fee_asset: asset.optional(), bridge_id: bridgeType.optional(), smart_relay: z.boolean().optional()}); export const evmSwap = z.object({input_token: z.string().optional(), amount_in: z.string().optional(), swap_calldata: z.string().optional(), amount_out: z.string().optional(), from_chain_id: z.string().optional(), denom_in: z.string().optional(), denom_out: z.string().optional(), swap_venues: z.array(swapVenue).optional()}); export const oPInitTransfer = z.object({from_chain_id: z.string().optional(), to_chain_id: z.string().optional(), denom_in: z.string().optional(), denom_out: z.string().optional(), op_init_bridge_id: z.unknown(), bridge_id: bridgeType.optional(), smart_relay: z.boolean().optional()}); export const goFastFee = z.object({fee_asset: asset.optional(), bps_fee: z.string().optional(), bps_fee_amount: z.string().optional(), bps_fee_usd: z.string().optional(), source_chain_fee_amount: z.string().optional(), source_chain_fee_usd: z.string().optional(), destination_chain_fee_amount: z.string().optional(), destination_chain_fee_usd: z.string().optional()}); export const goFastTransfer = z.object({from_chain_id: z.string().optional(), to_chain_id: z.string().optional(), fee: goFastFee.optional(), bridge_id: bridgeType.optional(), denom_in: z.string().optional(), denom_out: z.string().optional(), source_domain: z.string().optional(), destination_domain: z.string().optional()}); export const stargateTransfer = z.object({from_chain_id: z.string().optional(), to_chain_id: z.string().optional(), denom_in: z.string().optional(), denom_out: z.string().optional(), pool_address: z.string().optional(), destination_endpoint_id: z.number().optional(), oft_fee_asset: asset.optional(), oft_fee_amount: z.string().optional(), oft_fee_amount_usd: z.string().optional(), messaging_fee_asset: asset.optional(), messaging_fee_amount: z.string().optional(), messaging_fee_amount_usd: z.string().optional(), bridge_id: bridgeType.optional()}); export const layerZeroTransfer = z.object({from_chain_id: z.string(), to_chain_id: z.string(), denom_in: z.string(), denom_out: z.string(), source_oft_contract_address: z.string(), destination_endpoint_id: z.number(), messaging_fee_asset: asset, messaging_fee_amount: z.string(), messaging_fee_amount_usd: z.string(), bridge_id: bridgeType}); export const eurekaTransfer = z.object({destination_port: z.string().optional(), source_client: z.string().optional(), from_chain_id: z.string().optional(), to_chain_id: z.string().optional(), pfm_enabled: z.boolean().optional(), supports_memo: z.boolean().optional(), denom_in: z.string().optional(), denom_out: z.string().optional(), entry_contract_address: z.string().optional(), callback_adapter_contract_address: z.string().nullable().optional(), bridge_id: bridgeType.optional(), smart_relay: z.boolean().optional(), smart_relay_fee_quote: smartRelayFeeQuote.nullable().optional(), to_chain_callback_contract_address: z.string().nullable().optional(), to_chain_entry_contract_address: z.string().nullable().optional()}); export const operation = z.union([z.object({transfer: transfer.optional(), tx_index: z.number().int(), amount_in: z.string(), amount_out: z.string()}), z.object({swap: swap.optional(), tx_index: z.number().int(), amount_in: z.string(), amount_out: z.string()}), z.object({axelar_transfer: axelarTransfer.optional(), tx_index: z.number().int(), amount_in: z.string(), amount_out: z.string()}), z.object({bank_send: bankSend.optional(), tx_index: z.number().int(), amount_in: z.string(), amount_out: z.string()}), z.object({cctp_transfer: cCTPTransfer.optional(), tx_index: z.number().int(), amount_in: z.string(), amount_out: z.string()}), z.object({hyperlane_transfer: hyperlaneTransfer.optional(), tx_index: z.number().int(), amount_in: z.string(), amount_out: z.string()}), z.object({evm_swap: evmSwap.optional(), tx_index: z.number().int(), amount_in: z.string(), amount_out: z.string()}), z.object({op_init_transfer: oPInitTransfer.optional(), tx_index: z.number().int(), amount_in: z.string(), amount_out: z.string()}), z.object({go_fast_transfer: goFastTransfer.optional(), tx_index: z.number().int(), amount_in: z.string(), amount_out: z.string()}), z.object({stargate_transfer: stargateTransfer.optional(), tx_index: z.number().int(), amount_in: z.string(), amount_out: z.string()}), z.object({layer_zero_transfer: layerZeroTransfer.optional(), tx_index: z.number().int(), amount_in: z.string(), amount_out: z.string()}), z.object({eureka_transfer: eurekaTransfer.optional(), tx_index: z.number().int(), amount_in: z.string(), amount_out: z.string()})]); export const routePriceWarningType = z.enum(["LOW_INFO_WARNING", "BAD_PRICE_WARNING"]); export const feeType = z.literal("SMART_RELAY"); export const feeBehavior = z.enum(["FEE_BEHAVIOR_DEDUCTED", "FEE_BEHAVIOR_ADDITIONAL"]); export const fee = z.object({fee_type: feeType.optional(), bridge_id: bridgeType.optional(), amount: z.string().optional(), usd_amount: z.string().optional(), origin_asset: asset.optional(), chain_id: z.string().optional(), tx_index: z.number().int().optional(), operation_index: z.number().int().nullable().optional(), fee_behavior: feeBehavior.optional()}); export const route = z.object({amount_in: z.string(), amount_out: z.string(), chain_ids: z.array(z.string()), required_chain_addresses: z.array(z.string()), dest_asset_chain_id: z.string(), dest_asset_denom: z.string(), does_swap: z.boolean().optional(), estimated_amount_out: z.string(), operations: z.array(operation), source_asset_chain_id: z.string(), source_asset_denom: z.string(), swap_venues: z.array(swapVenue).optional(), txs_required: z.number().int(), usd_amount_in: z.string().optional(), usd_amount_out: z.string().optional(), swap_price_impact_percent: z.string().nullable().optional(), warning: z.object({type: routePriceWarningType.optional(), message: z.string().optional()}).nullable().optional(), estimated_fees: z.array(fee).optional(), estimated_route_duration_seconds: z.number().int()}); export const createApiV2FungibleMsgsDirectResponse = z.object({msgs: z.array(msg).optional(), txs: z.array(tx).optional(), min_amount_out: z.string().optional(), route: route.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 }; /** * This supports cross-chain actions among EVM chains, Cosmos chains, and between them. Returns minimal number of messages required to execute a multi-chain swap or transfer. This is a convenience endpoint that combines /route and /msgs into a single call. * * POST /v2/fungible/msgs_direct */ export const createApiV2FungibleMsgsDirect = async (args: CreateApiV2FungibleMsgsDirectArgs, options?: CreateApiV2FungibleMsgsDirectOptions) => { const {baseUrl = "https://api.skip.build", fetch: fetchFn = fetch} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") const url = `${baseUrl.replace(/\/+$/, '')}/v2/fungible/msgs_direct${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(createApiV2FungibleMsgsDirectResponse, await res.json()) };