import {z} from 'zod' export type Action = 'approve' | 'reject'; export type InclutionOperator = 'in' | 'not_in'; export type AssetIDTarget = {type: 'asset_id', identifier: string}; export type AssetTagTarget = {type: 'asset_tag', identifier: string}; export type AssetLabelTarget = {type: 'asset_label', identifier: string}; export type UnknownTarget = {type?: string | undefined} | {[key: string]: unknown}; export type CalledAddressesRule = {operator: InclutionOperator, value: Array}; export type CalledAddressRulesInput = {called_addresses: CalledAddressesRule}; export type CalledAddressPolicyRequest = {type: 'called_address', rules: CalledAddressRulesInput}; export type EqualityOperator = 'eq' | 'ne'; export type Eip712PrimaryTypeRule = {operator: InclutionOperator | EqualityOperator, value: Array | string}; export type Eip712VerifyingContractsRule = {operator: InclutionOperator | EqualityOperator, value: Array | string}; export type Eip712SignatureRulesInput = {primary_type: Eip712PrimaryTypeRule, verifying_contracts?: (Eip712VerifyingContractsRule | null) | undefined}; export type Eip712SignaturePolicyRequest = {rules: Eip712SignatureRulesInput, type: 'eip_712_signature'}; export type EventName = {operator: EqualityOperator, value: string}; export type LessThanComparisonOperator = 'lt' | 'lte'; export type GreaterThanComparisonOperator = 'gt' | 'gte'; export type EventParameter = {operator: EqualityOperator | LessThanComparisonOperator | GreaterThanComparisonOperator, value: string, parameter: string}; export type EventEmittedRulesInput = {event_name: EventName, event_parameters?: (Array | null) | undefined}; export type EventEmittedPolicyRequest = {type: 'event_emitted', rules: EventEmittedRulesInput, target: Array}; export type FunctionName = {operator: EqualityOperator, value: string}; export type FunctionParameter = {operator: EqualityOperator | LessThanComparisonOperator | GreaterThanComparisonOperator, value: string, parameter: string}; export type FunctionCallRulesInput = {function_name: FunctionName, function_parameters?: (Array | null) | undefined}; export type FunctionCallPolicyRequest = {type: 'function_call', rules: FunctionCallRulesInput, target: Array}; export type ApprovedGainingAddresses = {operator: InclutionOperator, value: Array}; export type TransactionFilterValue = 'all_actions' | 'transfers' | 'approvals'; export type TransactionFilter = {operator: 'is', value: TransactionFilterValue}; export type IgnoreThresholdRule = {operator: LessThanComparisonOperator, value: number}; export type NonApprovedGainingPercentage = {operator: LessThanComparisonOperator, value: number}; export type GainingAddressesRulesInput = {approved_gaining_addresses: ApprovedGainingAddresses, transaction_filter: TransactionFilter, ignore_threshold?: (IgnoreThresholdRule | null) | undefined, non_approved_gaining_percentage?: (NonApprovedGainingPercentage | null) | undefined}; export type GainingAddressesPolicyRequest = {type: 'gaining_addresses', rules: GainingAddressesRulesInput}; export type MerklCampaignAction = 'supply_to_vault' | 'supply_to_specific_market' | 'supply_token_to_any_market' | 'borrow_from_specific_market' | 'borrow_token_from_any_market' | 'use_token_as_collateral_on_specific_market'; export type MerklCampaignItem = {action: MerklCampaignAction, amount: number, chain: string, end_time_utc: string, market_token_vault: string, reward_token_address: string, start_time_utc: string}; export type MerklCampaignRulesInput = {campaigns: Array}; export type MerklCampaignPolicyRequest = {rules: MerklCampaignRulesInput, type: 'merkl_campaign'}; export type MovedAssetsDirectionValue = 'outbound_only'; export type MovedAssetsDirection = {operator: 'is', value: MovedAssetsDirectionValue}; export type MovedAssetsRule = {operator: InclutionOperator, value: Array}; export type MovedAssetsRulesInput = {direction?: MovedAssetsDirection | undefined, moved_assets: MovedAssetsRule}; export type MovedAssetsPolicyRequest = {rules: MovedAssetsRulesInput, type: 'moved_assets'}; export type RiskCategory = 'sanctioned_entity' | 'stolen_funds' | 'scam_investment_fraud' | 'mixer' | 'darknet_market' | 'darknet_service' | 'child_abuse_material' | 'terrorism_financing' | 'ransomware' | 'enforcement_action' | 'government_seized_assets' | 'illegal_service' | 'high_risk_unlicensed_exchange' | 'gambling_service' | 'centralized_exchange_regulated' | 'crypto_atm' | 'p2p_exchange_regulated' | 'p2p_exchange_high_risk_unregulated' | 'defi_liquidity_pool_dex_pool' | 'mining_pool_miner' | 'online_marketplace' | 'custodial_wallet_service' | 'payment_processor' | 'uncategorised_service' | 'uncategorized_entity'; export type ThresholdPercentage = {operator: LessThanComparisonOperator | GreaterThanComparisonOperator, value: number}; export type Proximity = 'overall' | 'ownership' | 'counterparty' | 'indirect'; export type CategoryThresholdInput = {category: RiskCategory, threshold_percentage: ThresholdPercentage, proximity?: Proximity | undefined}; export type RiskExposureRulesInput = {category_thresholds: Array, proximity?: Proximity | undefined}; export type RiskExposurePolicyRequest = {rules: RiskExposureRulesInput, type: 'risk_exposure'}; export type MaxUsdValueRule = {operator: 'lte' | 'gte', value: number | number}; export type TimeWindowScale = 'minutes' | 'hours' | 'days'; export type TimeWindowRule = {scale: TimeWindowScale, value: number}; export type RollingUsdLimitRulesInput = {max_usd_value: MaxUsdValueRule, time_window: TimeWindowRule}; export type RollingUsdLimitPolicyRequest = {rules: RollingUsdLimitRulesInput, type: 'rolling_usd_limit'}; export type SafeConfigAction = 'THRESHOLD_CHANGE' | 'OWNERSHIP_CHANGE' | 'MODULE_ENABLED_DISABLED' | 'GUARD_CHANGED'; export type SafeConfigActionRule = {operator: InclutionOperator, value: Array}; export type SafeConfigTransactionRulesInput = {config_action: SafeConfigActionRule}; export type SafeConfigTransactionPolicyRequest = {rules: SafeConfigTransactionRulesInput, type: 'safe_config_transaction'}; export type TokenSpendApprovalAmountRule = {operator: LessThanComparisonOperator | GreaterThanComparisonOperator | EqualityOperator, value: string}; export type TokenSpendApprovalUsdValueRule = {operator: LessThanComparisonOperator | GreaterThanComparisonOperator | EqualityOperator, value: string}; export type TokenSpendApprovalRulesInput = {approval_amount?: (TokenSpendApprovalAmountRule | null) | undefined, approval_usd_value: TokenSpendApprovalUsdValueRule}; export type TokenSpendApprovalPolicyRequest = {rules: TokenSpendApprovalRulesInput, type: 'token_spend_approval'}; export type TransactionUSDValueRule = {operator: LessThanComparisonOperator | GreaterThanComparisonOperator | EqualityOperator, value: string}; export type TransactionUSDValueRulesInput = {transaction_usd_value: TransactionUSDValueRule}; export type TransactionUSDValuePolicyRequest = {type: 'transaction_usd_value', rules: TransactionUSDValueRulesInput}; export type EVMCompositePolicyRequest = {type?: 'composite' | undefined, operator: 'and' | 'or', rules: Array}; export type EVMPolicyRequest = {name: string, action: Action, policy: CalledAddressPolicyRequest | Eip712SignaturePolicyRequest | EventEmittedPolicyRequest | FunctionCallPolicyRequest | GainingAddressesPolicyRequest | MerklCampaignPolicyRequest | MovedAssetsPolicyRequest | RiskExposurePolicyRequest | RollingUsdLimitPolicyRequest | SafeConfigTransactionPolicyRequest | TokenSpendApprovalPolicyRequest | TransactionUSDValuePolicyRequest | EVMCompositePolicyRequest}; export type SquadsConfigAction = 'changeThreshold' | 'addMember' | 'removeMember' | 'changeTimelock'; export type ConfigActionRule = {operator: InclutionOperator, value: Array}; export type SquadsConfigTransactionRulesInput = {squads_config_action: ConfigActionRule}; export type SquadsConfigTransactionPolicyRequest = {rules: SquadsConfigTransactionRulesInput, type: 'squads_config_transaction'}; export type SolanaCompositePolicyRequest = {type?: 'composite' | undefined, operator: 'and' | 'or', rules: Array}; export type SolanaPolicyRequest = {name: string, action: Action, policy: FunctionCallPolicyRequest | GainingAddressesPolicyRequest | RollingUsdLimitPolicyRequest | SquadsConfigTransactionPolicyRequest | TransactionUSDValuePolicyRequest | SolanaCompositePolicyRequest}; export type BitcoinCompositePolicyRequest = {type?: 'composite' | undefined, operator: 'and' | 'or', rules: Array}; export type BitcoinPolicyRequest = {name: string, action: Action, policy: GainingAddressesPolicyRequest | TransactionUSDValuePolicyRequest | BitcoinCompositePolicyRequest}; export type SuiCompositePolicyRequest = {type?: 'composite' | undefined, operator: 'and' | 'or', rules: Array}; export type SuiPolicyRequest = {name: string, action: Action, policy: GainingAddressesPolicyRequest | RollingUsdLimitPolicyRequest | TransactionUSDValuePolicyRequest | SuiCompositePolicyRequest}; export type UnsupportedChainPolicyRequest = {type: 'unsupported_chain'}; export type OtherChainPolicyRequest = {name: string, action: Action, policy: UnsupportedChainPolicyRequest}; export type PoliciesRequest = {evm?: (Array | null) | undefined, solana?: (Array | null) | undefined, bitcoin?: (Array | null) | undefined, sui?: (Array | null) | undefined, other?: (Array | null) | undefined}; export type SetPoliciesRequest = {policies: PoliciesRequest}; export type CreateApiV0PlatformCosignersIdPoliciesArgs = {id: string, body: SetPoliciesRequest}; export type CreateApiV0PlatformCosignersIdPoliciesOptions = {baseUrl?: string | undefined, fetch?: typeof fetch | undefined}; export const action = z.enum(["approve", "reject"]); export const inclutionOperator = z.enum(["in", "not_in"]); export const assetIDTarget = z.object({type: z.literal("asset_id"), identifier: z.string()}); export const assetTagTarget = z.object({type: z.literal("asset_tag"), identifier: z.string()}); export const assetLabelTarget = z.object({type: z.literal("asset_label"), identifier: z.string()}); export const unknownTarget = z.object({type: z.string().optional()}).and(z.record(z.string(), z.unknown())); export const calledAddressesRule = z.object({operator: inclutionOperator, value: z.array(z.union([assetIDTarget, assetTagTarget, assetLabelTarget, unknownTarget]))}); export const calledAddressRulesOutput = z.object({called_addresses: calledAddressesRule}); export const calledAddressPolicyResponse = z.object({type: z.literal("called_address"), rules: calledAddressRulesOutput}); export const equalityOperator = z.enum(["eq", "ne"]); export const eip712PrimaryTypeRule = z.object({operator: z.union([inclutionOperator, equalityOperator]), value: z.union([z.array(z.string()), z.string()])}); export const eip712VerifyingContractsRule = z.object({operator: z.union([inclutionOperator, equalityOperator]), value: z.union([z.array(z.string()), z.string()])}); export const eip712SignatureRulesOutput = z.object({primary_type: eip712PrimaryTypeRule, verifying_contracts: eip712VerifyingContractsRule.nullable().optional()}); export const eip712SignaturePolicyResponse = z.object({rules: eip712SignatureRulesOutput, type: z.literal("eip_712_signature")}); export const eventName = z.object({operator: equalityOperator, value: z.string()}); export const lessThanComparisonOperator = z.enum(["lt", "lte"]); export const greaterThanComparisonOperator = z.enum(["gt", "gte"]); export const eventParameter = z.object({operator: z.union([equalityOperator, lessThanComparisonOperator, greaterThanComparisonOperator]), value: z.string(), parameter: z.string()}); export const eventEmittedRulesOutput = z.object({event_name: eventName, event_parameters: z.array(eventParameter).nullable().optional()}); export const missingAssetIDTarget = z.object({type: z.literal("asset_id"), identifier: z.string(), chain: z.string(), runtime: z.string()}); export const eventEmittedPolicyResponse = z.object({type: z.literal("event_emitted"), rules: eventEmittedRulesOutput, target: z.array(z.union([assetIDTarget, missingAssetIDTarget, unknownTarget]))}); export const functionName = z.object({operator: equalityOperator, value: z.string()}); export const functionParameter = z.object({operator: z.union([equalityOperator, lessThanComparisonOperator, greaterThanComparisonOperator]), value: z.string(), parameter: z.string()}); export const functionCallRulesOutput = z.object({function_name: functionName, function_parameters: z.array(functionParameter).nullable().optional()}); export const functionCallPolicyResponse = z.object({type: z.literal("function_call"), rules: functionCallRulesOutput, target: z.array(z.union([assetIDTarget, missingAssetIDTarget, unknownTarget]))}); export const approvedGainingAddresses = z.object({operator: inclutionOperator, value: z.array(z.union([assetIDTarget, assetTagTarget, assetLabelTarget, unknownTarget]))}); export const transactionFilterValue = z.enum(["all_actions", "transfers", "approvals"]); export const transactionFilter = z.object({operator: z.literal("is"), value: transactionFilterValue}); export const ignoreThresholdRule = z.object({operator: lessThanComparisonOperator, value: z.number().int()}); export const nonApprovedGainingPercentage = z.object({operator: lessThanComparisonOperator, value: z.number()}); export const gainingAddressesRulesOutput = z.object({approved_gaining_addresses: approvedGainingAddresses, transaction_filter: transactionFilter, ignore_threshold: ignoreThresholdRule.nullable().optional(), non_approved_gaining_percentage: nonApprovedGainingPercentage.nullable().optional()}); export const gainingAddressesPolicyResponse = z.object({type: z.literal("gaining_addresses"), rules: gainingAddressesRulesOutput}); export const merklCampaignAction = z.enum(["supply_to_vault", "supply_to_specific_market", "supply_token_to_any_market", "borrow_from_specific_market", "borrow_token_from_any_market", "use_token_as_collateral_on_specific_market"]); export const merklCampaignItem = z.object({action: merklCampaignAction, amount: z.number().gt(0), chain: z.string(), end_time_utc: z.string(), market_token_vault: z.string(), reward_token_address: z.string(), start_time_utc: z.string()}); export const merklCampaignRulesOutput = z.object({campaigns: z.array(merklCampaignItem)}); export const merklCampaignPolicyResponse = z.object({rules: merklCampaignRulesOutput, type: z.literal("merkl_campaign")}); export const movedAssetsDirectionValue = z.literal("outbound_only"); export const movedAssetsDirection = z.object({operator: z.literal("is"), value: movedAssetsDirectionValue}); export const movedAssetsRule = z.object({operator: inclutionOperator, value: z.array(z.union([assetIDTarget, assetTagTarget, assetLabelTarget, unknownTarget]))}); export const movedAssetsRulesOutput = z.object({direction: movedAssetsDirection.optional(), moved_assets: movedAssetsRule}); export const movedAssetsPolicyResponse = z.object({rules: movedAssetsRulesOutput, type: z.literal("moved_assets")}); export const riskCategory = z.enum(["sanctioned_entity", "stolen_funds", "scam_investment_fraud", "mixer", "darknet_market", "darknet_service", "child_abuse_material", "terrorism_financing", "ransomware", "enforcement_action", "government_seized_assets", "illegal_service", "high_risk_unlicensed_exchange", "gambling_service", "centralized_exchange_regulated", "crypto_atm", "p2p_exchange_regulated", "p2p_exchange_high_risk_unregulated", "defi_liquidity_pool_dex_pool", "mining_pool_miner", "online_marketplace", "custodial_wallet_service", "payment_processor", "uncategorised_service", "uncategorized_entity"]); export const thresholdPercentage = z.object({operator: z.union([lessThanComparisonOperator, greaterThanComparisonOperator]), value: z.number().int().gte(0).lte(100)}); export const proximity = z.enum(["overall", "ownership", "counterparty", "indirect"]); export const categoryThresholdOutput = z.object({category: riskCategory, threshold_percentage: thresholdPercentage, proximity: proximity.optional()}); export const riskExposureRulesOutput = z.object({category_thresholds: z.array(categoryThresholdOutput), proximity: proximity.optional()}); export const riskExposurePolicyResponse = z.object({rules: riskExposureRulesOutput, type: z.literal("risk_exposure")}); export const maxUsdValueRule = z.object({operator: z.enum(["lte", "gte"]), value: z.union([z.number().int(), z.number()])}); export const timeWindowScale = z.enum(["minutes", "hours", "days"]); export const timeWindowRule = z.object({scale: timeWindowScale, value: z.number().int().gte(1)}); export const rollingUsdLimitRulesOutput = z.object({max_usd_value: maxUsdValueRule, time_window: timeWindowRule}); export const rollingUsdLimitPolicyResponse = z.object({rules: rollingUsdLimitRulesOutput, type: z.literal("rolling_usd_limit")}); export const safeConfigAction = z.enum(["THRESHOLD_CHANGE", "OWNERSHIP_CHANGE", "MODULE_ENABLED_DISABLED", "GUARD_CHANGED"]); export const safeConfigActionRule = z.object({operator: inclutionOperator, value: z.array(safeConfigAction)}); export const safeConfigTransactionRulesOutput = z.object({config_action: safeConfigActionRule}); export const safeConfigTransactionPolicyResponse = z.object({rules: safeConfigTransactionRulesOutput, type: z.literal("safe_config_transaction")}); export const tokenSpendApprovalAmountRule = z.object({operator: z.union([lessThanComparisonOperator, greaterThanComparisonOperator, equalityOperator]), value: z.string()}); export const tokenSpendApprovalUsdValueRule = z.object({operator: z.union([lessThanComparisonOperator, greaterThanComparisonOperator, equalityOperator]), value: z.string()}); export const tokenSpendApprovalRulesOutput = z.object({approval_amount: tokenSpendApprovalAmountRule.nullable().optional(), approval_usd_value: tokenSpendApprovalUsdValueRule}); export const tokenSpendApprovalPolicyResponse = z.object({rules: tokenSpendApprovalRulesOutput, type: z.literal("token_spend_approval")}); export const transactionUSDValueRule = z.object({operator: z.union([lessThanComparisonOperator, greaterThanComparisonOperator, equalityOperator]), value: z.string()}); export const transactionUSDValueRulesOutput = z.object({transaction_usd_value: transactionUSDValueRule}); export const transactionUSDValuePolicyResponse = z.object({type: z.literal("transaction_usd_value"), rules: transactionUSDValueRulesOutput}); export const baseCompositePolicyResponse = z.object({type: z.literal("composite").optional(), operator: z.enum(["and", "or"]), rules: z.array(z.unknown())}); export const unknownPolicyResponse = z.object({type: z.string(), rules: z.object({}).nullable().optional(), target: z.object({}).nullable().optional()}).and(z.record(z.string(), z.unknown())); export const eVMPolicyResponse = z.object({name: z.string(), action: action, policy: z.union([calledAddressPolicyResponse, eip712SignaturePolicyResponse, eventEmittedPolicyResponse, functionCallPolicyResponse, gainingAddressesPolicyResponse, merklCampaignPolicyResponse, movedAssetsPolicyResponse, riskExposurePolicyResponse, rollingUsdLimitPolicyResponse, safeConfigTransactionPolicyResponse, tokenSpendApprovalPolicyResponse, transactionUSDValuePolicyResponse, baseCompositePolicyResponse, unknownPolicyResponse])}); export const squadsConfigAction = z.enum(["changeThreshold", "addMember", "removeMember", "changeTimelock"]); export const configActionRule = z.object({operator: inclutionOperator, value: z.array(squadsConfigAction)}); export const squadsConfigTransactionRulesOutput = z.object({squads_config_action: configActionRule}); export const squadsConfigTransactionPolicyResponse = z.object({rules: squadsConfigTransactionRulesOutput, type: z.literal("squads_config_transaction")}); export const solanaPolicyResponse = z.object({name: z.string(), action: action, policy: z.union([functionCallPolicyResponse, gainingAddressesPolicyResponse, squadsConfigTransactionPolicyResponse, transactionUSDValuePolicyResponse, rollingUsdLimitPolicyResponse, baseCompositePolicyResponse, unknownPolicyResponse])}); export const bitcoinPolicyResponse = z.object({name: z.string(), action: action, policy: z.union([gainingAddressesPolicyResponse, transactionUSDValuePolicyResponse, baseCompositePolicyResponse, unknownPolicyResponse])}); export const suiPolicyResponse = z.object({name: z.string(), action: action, policy: z.union([gainingAddressesPolicyResponse, transactionUSDValuePolicyResponse, rollingUsdLimitPolicyResponse, baseCompositePolicyResponse, unknownPolicyResponse])}); export const unsupportedChainPolicyResponse = z.object({type: z.literal("unsupported_chain")}); export const otherChainPolicyResponse = z.object({name: z.string(), action: action, policy: unsupportedChainPolicyResponse}); export const policiesResponse = z.object({evm: z.array(eVMPolicyResponse).nullable().optional(), solana: z.array(solanaPolicyResponse).nullable().optional(), bitcoin: z.array(bitcoinPolicyResponse).nullable().optional(), sui: z.array(suiPolicyResponse).nullable().optional(), other: z.array(otherChainPolicyResponse).nullable().optional()}); export const setPoliciesResponse = z.object({policies: policiesResponse}); 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 }; /** * Set Cosigner Policies Route * * POST /v0/platform/cosigners/{id}/policies/ */ export const createApiV0PlatformCosignersIdPolicies = async (args: CreateApiV0PlatformCosignersIdPoliciesArgs, options?: CreateApiV0PlatformCosignersIdPoliciesOptions) => { const {baseUrl = "https://api.blockaid.io", 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(/\/+$/, '')}/v0/platform/cosigners/${encodeURIComponent(String(args.id))}/policies/${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(setPoliciesResponse, await res.json()) };