import {z} from 'zod' export type GetApiTradingOrdersOrderIdArgs = {orderId: string}; export type GetApiTradingOrdersOrderIdOptions = {baseUrl?: string | undefined, fetch?: typeof fetch | undefined}; export const accountAccessResponse = z.object({type: z.literal("PROVIDER_ACCOUNT"), providerId: z.string().optional(), accountId: z.string()}); export const directAccessResponse = z.object({type: z.literal("PROVIDER"), providerId: z.string(), subProviders: z.array(z.string()).optional()}); export const accessTypeResponse = z.discriminatedUnion("type", [accountAccessResponse, directAccessResponse]); export const orderStatus = z.enum(["CREATED", "AWAITING_PAYMENT", "AWAITING_INFORMATION", "PENDING_USER_ACTION", "PROCESSING", "CANCELED", "COMPLETED", "FAILED"]); export const blockchainTransfer = z.object({type: z.literal("BLOCKCHAIN").optional(), txHash: z.string().optional(), amount: z.string()}); export const fiatTransfer = z.object({type: z.literal("FIAT").optional(), amount: z.string(), referenceId: z.string().optional()}); export const transferReceipt = z.discriminatedUnion("type", [blockchainTransfer, fiatTransfer]); export const feeTypeEnum = z.enum(["ORDER", "NETWORK", "SPREAD", "REBATE"]); export const fixedAmountTypeEnum = z.literal("FIXED"); export const fee = z.union([z.object({feeType: feeTypeEnum, assetId: z.string(), amountType: fixedAmountTypeEnum, amount: z.string()}), z.object({feeType: feeTypeEnum, assetId: z.string(), amountType: z.literal("BPS"), amount: z.number().gte(0).lte(10000)})]); export const executionStepType = z.enum(["APPROVE", "PERMIT", "CONTRACT_CALL", "EXECUTE", "SETTLEMENT", "DELIVERY"]); export const executionStepStatusEnum = z.enum(["WAITING", "PROCESSING", "COMPLETED", "FAILED", "CANCELLED"]); export const executionStepError = z.enum(["INTERNAL_ERROR", "QUOTE_EXPIRED", "INSUFFICIENT_OUTPUT_AMOUNT", "INSUFFICIENT_FUNDS", "LAST_TRANSACTION_FAILED", "SWAP_APPROVAL_FAILED", "PROVIDER_EXECUTION_ERROR"]); export const orderExecutionStep = z.object({type: executionStepType, status: executionStepStatusEnum, fee: fee.optional(), txId: z.string().optional(), txHash: z.string().optional(), error: executionStepError.optional()}); export const marketTypeEnum = z.literal("MARKET"); export const side = z.enum(["BUY", "SELL"]); export const transferRail = z.enum(["BLOCKCHAIN", "INTERNAL", "SWIFT", "IBAN", "US_WIRE", "ACH", "SEPA", "SPEI", "PIX", "LBT", "MOMO", "CHAPS", "PAYID", "INTERAC", "INTERNAL_TRANSFER", "CIPS", "NEQUI", "FPS_UK", "FPS_HK", "INSTA_PAY", "PESONET"]); export const marketExecutionResponseDetails = z.object({type: marketTypeEnum, side: side, baseAmount: z.string(), baseAssetId: z.string(), baseAssetRail: transferRail.optional(), quoteAssetId: z.string(), quoteAssetRail: transferRail.optional()}); export const quoteExecutionTypeEnum = z.literal("QUOTE"); export const marketRequoteTypeEnum = z.literal("MARKET"); export const marketRequoteRequestDetails = z.object({type: marketRequoteTypeEnum}); export const retryRequoteTypeEnum = z.literal("RETRY"); export const retryRequoteRequestDetails = z.object({type: retryRequoteTypeEnum, count: z.number().int().gte(1).lte(10), slippageBps: z.number().int().gte(1).lte(10000).optional()}); export const quoteExecutionWithRequoteResponseDetails = z.object({type: quoteExecutionTypeEnum, quoteId: z.string(), quoteAmount: z.string(), side: side, baseAmount: z.string(), baseAssetId: z.string(), baseAssetRail: transferRail.optional(), quoteAssetId: z.string(), quoteAssetRail: transferRail.optional(), reQuote: z.discriminatedUnion("type", [marketRequoteRequestDetails, retryRequoteRequestDetails]).optional()}); export const limitTypeEnum = z.literal("LIMIT"); export const timeInForce = z.object({type: z.literal("FOK")}); export const limitExecutionResponseDetails = z.object({type: limitTypeEnum, price: z.string(), timeInForce: timeInForce, side: side, baseAmount: z.string(), baseAssetId: z.string(), baseAssetRail: transferRail.optional(), quoteAssetId: z.string(), quoteAssetRail: transferRail.optional()}); export const executionResponseDetails = z.discriminatedUnion("type", [marketExecutionResponseDetails, quoteExecutionWithRequoteResponseDetails, limitExecutionResponseDetails]); export const prefundedSettlementType = z.literal("PREFUNDED"); export const peerType = z.enum(["VAULT_ACCOUNT", "EXCHANGE_ACCOUNT", "UNMANAGED_WALLET", "FIAT_ACCOUNT", "CONNECTED_ACCOUNT"]); export const internalReference = z.object({type: peerType, accountId: z.string()}); export const oneTimeAddressPeerType = z.literal("ONE_TIME_ADDRESS"); export const oneTimeAddressReference = z.object({type: oneTimeAddressPeerType, address: z.string(), tag: z.string().optional()}); export const accountReference = z.discriminatedUnion("type", [internalReference, oneTimeAddressReference]); export const prefundedSettlement = z.object({type: prefundedSettlementType, destinationAccount: accountReference}); export const dVPSettlementType = z.literal("DVP"); export const platformPeerType = z.enum(["VAULT_ACCOUNT", "CONNECTED_ACCOUNT", "FIAT_ACCOUNT"]); export const platformAccount = z.object({type: platformPeerType, accountId: z.string()}); export const externalAccountType = z.literal("EXTERNAL"); export const externalAccountMobileMoneyType = z.literal("MOBILE_MONEY_RAIL"); export const mobilePhoneNumber = z.string(); export const externalAccountMobileMoneyProvider = z.enum(["M_PESA", "AIRTEL", "MTN", "TIGO", "ORANGE"]); export const externalAccountMobileMoney = z.object({type: externalAccountMobileMoneyType, mobilePhoneNumber: mobilePhoneNumber, provider: externalAccountMobileMoneyProvider, email: z.string(), successRedirectUrl: z.string().optional()}); export const externalAccountLocalBankAfrica = z.object({successRedirectUrl: z.string().optional()}); export const externalAccountSenderInformation = z.union([externalAccountMobileMoney, externalAccountLocalBankAfrica]); export const externalAccount = z.object({type: externalAccountType, senderInformation: externalAccountSenderInformation.optional()}); export const settlementSourceAccount = z.discriminatedUnion("type", [platformAccount, externalAccount]); export const dVPSettlement = z.object({type: dVPSettlementType, sourceAccount: settlementSourceAccount, destinationAccount: accountReference}); export const postTradeSettlementType = z.literal("POST_TRADE"); export const postTradeSettlement = z.object({type: postTradeSettlementType}); export const settlement = z.discriminatedUnion("type", [prefundedSettlement, dVPSettlement, postTradeSettlement]); export const personalEntityTypeEnum = z.literal("INDIVIDUAL"); export const participantRelationshipType = z.enum(["FirstParty", "SecondParty", "ThirdParty"]); export const postalAddress = z.object({streetName: z.string(), buildingNumber: z.string(), postalCode: z.string(), city: z.string(), subdivision: z.string(), district: z.string(), country: z.string()}); export const personalIdentificationType = z.enum(["NIN_SLIP_CARD", "BVN", "ID_CARD", "ID_BOOK", "NATIONAL_ID", "ALIEN_CARD", "PASSPORT", "ECOWAS_CARD", "RWANDA_CARD", "DRIVERS_LICENSE", "RESIDENT_CARD", "VOTER_ID", "HEALTH_INSURANCE_ID", "GHANA_CARD", "REFUGEE_ID", "SSNIT", "NON_CITIZEN_ID", "NATIONAL_REGISTRATION_CARD"]); export const personalIdentificationDocument = z.object({id: z.string().optional(), type: personalIdentificationType.optional(), expirationDate: z.string().optional()}); export const personalIdentification = z.object({externalReferenceId: z.string(), entityType: personalEntityTypeEnum, participantRelationshipType: participantRelationshipType, fullName: z.object({firstName: z.string(), lastName: z.string()}), dateOfBirth: z.string(), postalAddress: postalAddress, email: z.string().optional(), phone: mobilePhoneNumber.optional(), idNumber: z.string().optional(), idType: personalIdentificationType.optional(), additionalIdNumber: z.string().optional(), additionalIdType: personalIdentificationType.optional(), nationality: z.string().optional(), identificationDocuments: z.array(personalIdentificationDocument).optional()}); export const businessEntityTypeEnum = z.literal("BUSINESS"); export const businessIdentification = z.object({externalReferenceId: z.string(), entityType: businessEntityTypeEnum, participantRelationshipType: participantRelationshipType, businessName: z.string(), registrationNumber: z.string(), postalAddress: postalAddress, email: z.string().optional(), phone: mobilePhoneNumber.optional(), dateOfRegistration: z.string().optional(), countryOfRegistration: z.string().optional()}); export const identification = z.discriminatedUnion("entityType", [personalIdentification, businessIdentification]); export const participantsIdentification = z.object({originator: identification.optional(), beneficiary: identification.optional()}); export const blockchainAddress = z.object({blockchainAddress: z.string(), tag: z.string().optional()}); export const blockchainDestination = z.object({type: z.literal("BLOCKCHAIN"), address: blockchainAddress}); export const accountHolderDetails = z.object({name: z.string(), city: z.string().optional(), country: z.string().optional(), subdivision: z.string().optional(), address: z.string().optional(), postalCode: z.string().optional()}); export const iban = z.string(); export const ibanAddress = z.object({accountHolder: accountHolderDetails, iban: iban}); export const swiftCode = z.string(); export const swiftAddress = z.object({accountHolder: accountHolderDetails, swiftCode: swiftCode, routingNumber: z.string()}); export const achAccountType = z.enum(["CHECKING", "SAVINGS"]); export const achAddress = z.object({accountHolder: accountHolderDetails, bankName: z.string().optional(), bankAccountNumber: z.string(), routingNumber: z.string(), accountType: achAccountType}); export const bankAddress = z.object({streetName: z.string().optional(), buildingNumber: z.string().optional(), postalCode: z.string().optional(), city: z.string().optional(), subdivision: z.string().optional(), district: z.string().optional(), country: z.string().optional()}); export const uSWireAddress = z.object({accountHolder: accountHolderDetails, bankName: z.string().optional(), bankAccountNumber: z.string(), routingNumber: z.string(), bankAddress: bankAddress.optional()}); export const speiAddress = z.object({accountHolder: accountHolderDetails, bankName: z.string().optional(), bankAccountNumber: z.string()}); export const sEPAAddress = z.object({accountHolder: accountHolderDetails, iban: iban, bic: z.string().optional(), bankName: z.string().optional(), bankBranch: z.string().optional(), bankAddress: z.string().optional(), purposeCode: z.string().optional(), taxId: z.string().optional()}); export const pixAddress = z.object({accountHolder: accountHolderDetails, pixKey: z.string(), keyType: z.enum(["CPF", "CNPJ", "EMAIL", "PHONE", "RANDOM"]), bankName: z.string().optional(), bankCode: z.string().optional(), qrCode: z.string().optional(), expirationDate: z.string().optional()}); export const localBankAfricaAccountNumber = z.string(); export const paymentRedirect = z.object({url: z.string().optional(), expiresAt: z.string().optional()}); export const localBankTransferAfricaAddress = z.object({accountHolder: accountHolderDetails, accountNumber: localBankAfricaAccountNumber, bankName: z.string(), bankCode: z.string(), successPaymentInstructionRedirectUrl: z.string().optional(), paymentRedirect: paymentRedirect.optional()}); export const mobileMoneyAddress = z.object({accountHolder: accountHolderDetails, mobilePhoneNumber: mobilePhoneNumber, provider: z.enum(["m-pesa", "airtel", "mtn", "tigo", "orange"]), beneficiaryDocumentId: z.string().optional(), beneficiaryRelationship: z.string().optional(), successPaymentInstructionRedirectUrl: z.string().optional(), paymentRedirect: paymentRedirect.optional()}); export const europeanSEPAAddress = z.object({accountHolder: accountHolderDetails, iban: iban, bic: z.string().optional(), bankName: z.string().optional(), bankBranch: z.string().optional(), bankAddress: z.string().optional(), purposeCode: z.string().optional(), taxId: z.string().optional()}); export const chapsAddress = z.object({accountHolder: accountHolderDetails, sortCode: z.string(), accountNumber: z.string(), bankName: z.string().optional(), bankAccountCountry: z.string(), bankAccountHolderName: z.string()}); export const recipientHandle = z.object({type: z.literal("EMAIL"), value: z.string()}); export const interacAddress = z.object({accountHolder: accountHolderDetails, recipientHandle: recipientHandle, message: z.string().optional(), autoDeposit: z.boolean(), securityQuestion: z.string().optional(), securityAnswer: z.string().optional()}); export const payidAddress = z.object({accountHolder: accountHolderDetails, value: z.string(), type: z.literal("EMAIL"), bsb: z.string().optional(), accountNumber: z.string().optional()}); export const internalTransferAddress = z.object({externalAccountId: z.string().optional(), accountId: z.string()}); export const cipsAddress = z.object({accountHolder: accountHolderDetails, bankName: z.string(), bankCountry: z.string(), swiftCode: z.string(), accountNumber: z.string()}); export const nequiAddress = z.object({phone: z.string()}); export const fpsUkAddress = z.object({accountHolder: accountHolderDetails, accountNumber: z.string(), sortCode: z.string()}); export const fpsHkAddress = z.object({recipientLegalName: z.string().optional(), accountNumber: z.string().optional(), bankCode: z.string().optional(), phone: z.string().optional(), email: z.string().optional(), fpsId: z.string().optional()}); export const instaPayAddress = z.object({accountHolder: accountHolderDetails, bankName: z.string(), accountNumber: z.string()}); export const pesonetAddress = z.object({accountHolder: accountHolderDetails, bankName: z.string(), accountNumber: z.string()}); export const paymentInstructions = z.union([blockchainDestination, z.object({type: z.literal("IBAN"), address: ibanAddress, referenceId: z.string().optional()}), z.object({type: z.literal("SWIFT"), address: swiftAddress, referenceId: z.string().optional()}), z.object({type: z.literal("ACH"), address: achAddress, referenceId: z.string().optional()}), z.object({type: z.literal("WIRE"), address: uSWireAddress, referenceId: z.string().optional()}), z.object({type: z.literal("SPEI"), address: speiAddress, referenceId: z.string().optional()}), z.object({type: z.literal("SEPA"), address: sEPAAddress, referenceId: z.string().optional()}), z.object({type: z.literal("PIX"), address: pixAddress, referenceId: z.string().optional()}), z.object({type: z.literal("LOCAL_BANK_TRANSFER"), address: localBankTransferAfricaAddress, referenceId: z.string().optional()}), z.object({type: z.literal("MOBILE_MONEY"), address: mobileMoneyAddress, referenceId: z.string().optional()}), z.object({type: z.literal("EUROPEAN_SEPA"), address: europeanSEPAAddress, referenceId: z.string().optional()}), z.object({type: z.literal("CHAPS"), address: chapsAddress, referenceId: z.string().optional()}), z.object({type: z.literal("INTERAC"), address: interacAddress, referenceId: z.string().optional()}), z.object({type: z.literal("PAYID"), address: payidAddress, referenceId: z.string().optional()}), z.object({type: z.literal("INTERNAL_TRANSFER"), address: internalTransferAddress.optional(), referenceId: z.string().optional()}), z.object({type: z.literal("CIPS"), address: cipsAddress, referenceId: z.string().optional()}), z.object({type: z.literal("NEQUI"), address: nequiAddress, referenceId: z.string().optional()}), z.object({type: z.literal("FPS_UK"), address: fpsUkAddress, referenceId: z.string().optional()}), z.object({type: z.literal("FPS_HK"), address: fpsHkAddress, referenceId: z.string().optional()}), z.object({type: z.literal("INSTA_PAY"), address: instaPayAddress, referenceId: z.string().optional()}), z.object({type: z.literal("PESONET"), address: pesonetAddress, referenceId: z.string().optional()})]); export const failureReason = z.enum(["INSUFFICIENT_FUNDS", "UNKNOWN_REASON", "INITIATE_PAYMENT_FAILURE", "POLICY_REJECTION", "TRANSACTION_FAILED", "ACCOUNT_NOT_ACTIVE", "ACCOUNT_NOT_FOUND", "BAD_REQUEST", "QUOTE_NOT_READY", "INVALID_DATA", "UNSUPPORTED_CONVERSION", "UNSUPPORTED_RAMP_METHOD", "REFUNDED", "FAILED_BY_PROVIDER", "ORDER_EXPIRED", "TRANSACTION_CANCELLED", "TRANSACTION_REJECTED", "TRANSACTION_BLOCKED", "PROVIDER_INTERNAL_ERROR", "UNSUPPORTED_SOURCE_ASSET", "UNSUPPORTED_DESTINATION_ASSET", "AMOUNT_BELOW_MINIMUM", "AMOUNT_ABOVE_MAXIMUM", "PII_MISSING", "EXTERNAL_SOURCE_NOT_SUPPORTED", "UNSUPPORTED_REGION", "DESTINATION_NOT_WHITELISTED", "MISSING_DESTINATION_DETAILS", "MISSING_WORKSPACE_DETAILS", "CREDIT_LIMIT_EXCEEDED", "QUOTE_EXPIRED", "DESK_REJECTED", "REQUOTE_WORSE_PRICE", "FOK_KILLED"]); export const failure = z.object({reason: failureReason}); export const orderDetails = z.object({id: z.string(), via: accessTypeResponse, status: orderStatus, createdAt: z.string(), updatedAt: z.string().optional(), receipt: transferReceipt.optional(), generalFees: z.array(fee).optional(), executionSteps: z.array(orderExecutionStep), executionResponseDetails: executionResponseDetails, settlement: settlement, participantsIdentification: participantsIdentification.optional(), paymentInstructions: z.array(paymentInstructions).optional(), createdBy: z.string(), customerInternalReferenceId: z.string().optional(), note: z.string().max(512).optional(), expiresAt: z.string().optional(), failure: failure.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 order details * * GET /trading/orders/{orderId} */ export const getApiTradingOrdersOrderId = async (args: GetApiTradingOrdersOrderIdArgs, options?: GetApiTradingOrdersOrderIdOptions) => { const {baseUrl = "https://api.fireblocks.io/v1", fetch: fetchFn = fetch} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") const url = `${baseUrl.replace(/\/+$/, '')}/trading/orders/${encodeURIComponent(String(args.orderId))}${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(orderDetails, await res.json()) };