import {z} from 'zod' export type PolicyMethod = 'eth_sendTransaction' | 'eth_signTransaction' | 'eth_signUserOperation' | 'eth_signTypedData_v4' | 'personal_sign' | 'eth_sign7702Authorization' | 'wallet_sendCalls' | 'signTransaction' | 'signAndSendTransaction' | 'signMessage' | 'exportPrivateKey' | 'exportSeedPhrase' | 'signTransactionBytes' | 'signRawMessageBytes' | 'tron_sendTransaction' | 'tron_signTransaction' | 'xrpl_signTransaction' | 'earn_deposit' | 'earn_withdraw' | 'earn_incentive_claim' | 'transfer' | '*'; export type EthereumTransactionConditionField = 'to' | 'value' | 'chain_id' | 'data_byte_length'; export type ConditionOperator = 'eq' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'in_condition_set' | 'contains' | 'starts_with' | 'ends_with'; export type ConditionValue = string | Array; export type AbiParameter = {name?: string | undefined, type: string, components?: Array<{[key: string]: unknown}> | undefined, indexed?: boolean | undefined, internalType?: string | undefined}; export type AbiSchema = Array<{type: 'function' | 'constructor' | 'event' | 'fallback' | 'receive', name?: string | undefined, inputs?: Array | undefined, outputs?: Array | undefined, stateMutability?: ('pure' | 'view' | 'nonpayable' | 'payable') | undefined, anonymous?: boolean | undefined}>; export type EthereumTypedDataDomainConditionField = 'chainId' | 'verifyingContract' | 'chain_id' | 'verifying_contract'; export type TypedDataTypeFieldInput = {name: string, type: string}; export type TypedDataTypesInputParams = {[key: string]: Array}; export type TypedDataInput = {types: TypedDataTypesInputParams, primary_type: string}; export type TempoTransactionConditionField = 'fee_token' | 'fee_payer_signature' | 'nonce_key' | 'valid_before' | 'valid_after'; export type SolanaIdl = {[key: string]: unknown}; export type SolanaSystemProgramInstructionConditionField = 'instructionName' | 'Transfer.from' | 'Transfer.to' | 'Transfer.lamports'; export type SolanaTokenProgramInstructionConditionField = 'instructionName' | 'Transfer.source' | 'Transfer.destination' | 'Transfer.authority' | 'Transfer.amount' | 'TransferChecked.source' | 'TransferChecked.destination' | 'TransferChecked.authority' | 'TransferChecked.amount' | 'TransferChecked.mint' | 'Burn.account' | 'Burn.mint' | 'Burn.authority' | 'Burn.amount' | 'MintTo.mint' | 'MintTo.account' | 'MintTo.authority' | 'MintTo.amount' | 'CloseAccount.account' | 'CloseAccount.destination' | 'CloseAccount.authority' | 'InitializeAccount3.account' | 'InitializeAccount3.mint' | 'InitializeAccount3.owner'; export type TronTransactionConditionField = 'TransferContract.to_address' | 'TransferContract.amount' | 'TriggerSmartContract.contract_address' | 'TriggerSmartContract.call_value' | 'TriggerSmartContract.token_id' | 'TriggerSmartContract.call_token_value'; export type XrplTransactionConditionField = 'TransactionType' | 'Payment.Destination' | 'Payment.DestinationTag' | 'Payment.Amount.drops' | 'Payment.Amount.value' | 'Payment.Amount.currency' | 'Payment.Amount.issuer' | 'Payment.SendMax.drops' | 'Payment.SendMax.value' | 'Payment.SendMax.currency' | 'Payment.SendMax.issuer' | 'Payment.DeliverMin.drops' | 'Payment.DeliverMin.value' | 'Payment.DeliverMin.currency' | 'Payment.DeliverMin.issuer' | 'OfferCreate.TakerPays.drops' | 'OfferCreate.TakerPays.value' | 'OfferCreate.TakerPays.currency' | 'OfferCreate.TakerPays.issuer' | 'OfferCreate.TakerGets.drops' | 'OfferCreate.TakerGets.value' | 'OfferCreate.TakerGets.currency' | 'OfferCreate.TakerGets.issuer' | 'OfferCreate.Expiration' | 'TrustSet.LimitAmount.value' | 'TrustSet.LimitAmount.currency' | 'TrustSet.LimitAmount.issuer' | 'TrustSet.QualityIn' | 'TrustSet.QualityOut'; export type SuiTransactionCommandOperator = 'eq' | 'in'; export type SuiCommandName = 'TransferObjects' | 'SplitCoins' | 'MergeCoins'; export type SuiTransferObjectsCommandField = 'recipient' | 'amount'; export type MessageSigningField = 'content' | 'byte_length'; export type PolicyCondition = {field_source: 'ethereum_transaction', field: EthereumTransactionConditionField, operator: ConditionOperator, value: ConditionValue} | {field_source: 'ethereum_calldata', field: string, abi: AbiSchema, operator: ConditionOperator, value: ConditionValue} | {field_source: 'ethereum_typed_data_domain', field: EthereumTypedDataDomainConditionField, operator: ConditionOperator, value: ConditionValue} | {field_source: 'ethereum_typed_data_message', field: string, typed_data: TypedDataInput, operator: ConditionOperator, value: ConditionValue} | {field_source: 'ethereum_7702_authorization', field: 'contract', operator: ConditionOperator, value: ConditionValue} | {field_source: 'tempo_transaction', field: TempoTransactionConditionField, operator: ConditionOperator, value: ConditionValue} | {field_source: 'solana_program_instruction', field: 'programId', operator: ConditionOperator, value: ConditionValue} | {field_source: 'solana_instruction_data', field: string, idl: SolanaIdl, operator: ConditionOperator, value: ConditionValue} | {field_source: 'solana_system_program_instruction', field: SolanaSystemProgramInstructionConditionField, operator: ConditionOperator, value: ConditionValue} | {field_source: 'solana_token_program_instruction', field: SolanaTokenProgramInstructionConditionField, operator: ConditionOperator, value: ConditionValue} | {field_source: 'system', field: 'current_unix_timestamp', operator: ConditionOperator, value: ConditionValue} | {field_source: 'tron_transaction', field: TronTransactionConditionField, operator: ConditionOperator, value: ConditionValue} | {field_source: 'tron_trigger_smart_contract_data', field: string, abi: AbiSchema, operator: ConditionOperator, value: ConditionValue} | {field_source: 'xrpl_transaction', field: XrplTransactionConditionField, operator: ConditionOperator, value: ConditionValue} | {field_source: 'sui_transaction_command', field: 'commandName', operator: SuiTransactionCommandOperator, value: SuiCommandName | Array} | {field_source: 'sui_transfer_objects_command', field: SuiTransferObjectsCommandField, operator: ConditionOperator, value: ConditionValue} | {field_source: 'action_request_body', field: string, operator: ConditionOperator, value: ConditionValue} | {field_source: 'reference', field: string, operator: ConditionOperator, value: ConditionValue} | {field_source: 'message', field: MessageSigningField, operator: ConditionOperator, value: ConditionValue}; export type PolicyAction = 'ALLOW' | 'DENY' | 'ALLOW_WITH_MFA'; export type PolicyRuleRequestBody = {name: string, method: PolicyMethod, conditions: Array, action: PolicyAction}; export type CreateApiV1PoliciesPolicyIdRulesArgs = {policy_id: string, 'privy-app-id': string, 'privy-authorization-signature'?: string | undefined, 'privy-request-expiry'?: string | undefined, body: PolicyRuleRequestBody}; export type CreateApiV1PoliciesPolicyIdRulesOptions = {baseUrl?: string | undefined, appSecretAuth?: {username: string, password: string} | undefined, fetch?: typeof fetch | undefined}; export const policyMethod = z.enum(["eth_sendTransaction", "eth_signTransaction", "eth_signUserOperation", "eth_signTypedData_v4", "personal_sign", "eth_sign7702Authorization", "wallet_sendCalls", "signTransaction", "signAndSendTransaction", "signMessage", "exportPrivateKey", "exportSeedPhrase", "signTransactionBytes", "signRawMessageBytes", "tron_sendTransaction", "tron_signTransaction", "xrpl_signTransaction", "earn_deposit", "earn_withdraw", "earn_incentive_claim", "transfer", "*"]); export const ethereumTransactionConditionField = z.enum(["to", "value", "chain_id", "data_byte_length"]); export const conditionOperator = z.enum(["eq", "gt", "gte", "lt", "lte", "in", "in_condition_set", "contains", "starts_with", "ends_with"]); export const conditionValue = z.union([z.string(), z.array(z.string())]); export const abiParameter = z.object({name: z.string().optional(), type: z.string(), components: z.array(z.record(z.string(), z.unknown())).optional(), indexed: z.boolean().optional(), internalType: z.string().optional()}); export const abiSchema = z.array(z.object({type: z.enum(["function", "constructor", "event", "fallback", "receive"]), name: z.string().optional(), inputs: z.array(abiParameter).optional(), outputs: z.array(abiParameter).optional(), stateMutability: z.enum(["pure", "view", "nonpayable", "payable"]).optional(), anonymous: z.boolean().optional()})); export const ethereumTypedDataDomainConditionField = z.enum(["chainId", "verifyingContract", "chain_id", "verifying_contract"]); export const typedDataTypeFieldInput = z.object({name: z.string(), type: z.string()}); export const typedDataTypesInputParams = z.record(z.string(), z.array(typedDataTypeFieldInput)); export const typedDataInput = z.object({types: typedDataTypesInputParams, primary_type: z.string()}); export const tempoTransactionConditionField = z.enum(["fee_token", "fee_payer_signature", "nonce_key", "valid_before", "valid_after"]); export const solanaIdl = z.record(z.string(), z.unknown()); export const solanaSystemProgramInstructionConditionField = z.enum(["instructionName", "Transfer.from", "Transfer.to", "Transfer.lamports"]); export const solanaTokenProgramInstructionConditionField = z.enum(["instructionName", "Transfer.source", "Transfer.destination", "Transfer.authority", "Transfer.amount", "TransferChecked.source", "TransferChecked.destination", "TransferChecked.authority", "TransferChecked.amount", "TransferChecked.mint", "Burn.account", "Burn.mint", "Burn.authority", "Burn.amount", "MintTo.mint", "MintTo.account", "MintTo.authority", "MintTo.amount", "CloseAccount.account", "CloseAccount.destination", "CloseAccount.authority", "InitializeAccount3.account", "InitializeAccount3.mint", "InitializeAccount3.owner"]); export const tronTransactionConditionField = z.enum(["TransferContract.to_address", "TransferContract.amount", "TriggerSmartContract.contract_address", "TriggerSmartContract.call_value", "TriggerSmartContract.token_id", "TriggerSmartContract.call_token_value"]); export const xrplTransactionConditionField = z.enum(["TransactionType", "Payment.Destination", "Payment.DestinationTag", "Payment.Amount.drops", "Payment.Amount.value", "Payment.Amount.currency", "Payment.Amount.issuer", "Payment.SendMax.drops", "Payment.SendMax.value", "Payment.SendMax.currency", "Payment.SendMax.issuer", "Payment.DeliverMin.drops", "Payment.DeliverMin.value", "Payment.DeliverMin.currency", "Payment.DeliverMin.issuer", "OfferCreate.TakerPays.drops", "OfferCreate.TakerPays.value", "OfferCreate.TakerPays.currency", "OfferCreate.TakerPays.issuer", "OfferCreate.TakerGets.drops", "OfferCreate.TakerGets.value", "OfferCreate.TakerGets.currency", "OfferCreate.TakerGets.issuer", "OfferCreate.Expiration", "TrustSet.LimitAmount.value", "TrustSet.LimitAmount.currency", "TrustSet.LimitAmount.issuer", "TrustSet.QualityIn", "TrustSet.QualityOut"]); export const suiTransactionCommandOperator = z.union([z.literal("eq"), z.literal("in")]); export const suiCommandName = z.enum(["TransferObjects", "SplitCoins", "MergeCoins"]); export const suiTransferObjectsCommandField = z.enum(["recipient", "amount"]); export const messageSigningField = z.enum(["content", "byte_length"]); export const policyCondition = z.discriminatedUnion("field_source", [z.object({field_source: z.literal("ethereum_transaction"), field: ethereumTransactionConditionField, operator: conditionOperator, value: conditionValue}), z.object({field_source: z.literal("ethereum_calldata"), field: z.string(), abi: abiSchema, operator: conditionOperator, value: conditionValue}), z.object({field_source: z.literal("ethereum_typed_data_domain"), field: ethereumTypedDataDomainConditionField, operator: conditionOperator, value: conditionValue}), z.object({field_source: z.literal("ethereum_typed_data_message"), field: z.string(), typed_data: typedDataInput, operator: conditionOperator, value: conditionValue}), z.object({field_source: z.literal("ethereum_7702_authorization"), field: z.literal("contract"), operator: conditionOperator, value: conditionValue}), z.object({field_source: z.literal("tempo_transaction"), field: tempoTransactionConditionField, operator: conditionOperator, value: conditionValue}), z.object({field_source: z.literal("solana_program_instruction"), field: z.literal("programId"), operator: conditionOperator, value: conditionValue}), z.object({field_source: z.literal("solana_instruction_data"), field: z.string(), idl: solanaIdl, operator: conditionOperator, value: conditionValue}), z.object({field_source: z.literal("solana_system_program_instruction"), field: solanaSystemProgramInstructionConditionField, operator: conditionOperator, value: conditionValue}), z.object({field_source: z.literal("solana_token_program_instruction"), field: solanaTokenProgramInstructionConditionField, operator: conditionOperator, value: conditionValue}), z.object({field_source: z.literal("system"), field: z.literal("current_unix_timestamp"), operator: conditionOperator, value: conditionValue}), z.object({field_source: z.literal("tron_transaction"), field: tronTransactionConditionField, operator: conditionOperator, value: conditionValue}), z.object({field_source: z.literal("tron_trigger_smart_contract_data"), field: z.string(), abi: abiSchema, operator: conditionOperator, value: conditionValue}), z.object({field_source: z.literal("xrpl_transaction"), field: xrplTransactionConditionField, operator: conditionOperator, value: conditionValue}), z.object({field_source: z.literal("sui_transaction_command"), field: z.literal("commandName"), operator: suiTransactionCommandOperator, value: z.union([suiCommandName, z.array(suiCommandName)])}), z.object({field_source: z.literal("sui_transfer_objects_command"), field: suiTransferObjectsCommandField, operator: conditionOperator, value: conditionValue}), z.object({field_source: z.literal("action_request_body"), field: z.string(), operator: conditionOperator, value: conditionValue}), z.object({field_source: z.literal("reference"), field: z.string(), operator: conditionOperator, value: conditionValue}), z.object({field_source: z.literal("message"), field: messageSigningField, operator: conditionOperator, value: conditionValue})]); export const policyAction = z.enum(["ALLOW", "DENY", "ALLOW_WITH_MFA"]); export const policyRuleResponse = z.object({name: z.string().min(1).max(50), method: policyMethod, conditions: z.array(policyCondition), action: policyAction, id: z.string()}); 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 }; /** * Create Policy Rule * * POST /v1/policies/{policy_id}/rules */ export const createApiV1PoliciesPolicyIdRules = async (args: CreateApiV1PoliciesPolicyIdRulesArgs, options?: CreateApiV1PoliciesPolicyIdRulesOptions) => { const {baseUrl = "https://api.privy.io", fetch: fetchFn = fetch, appSecretAuth} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (args['privy-app-id'] != null) headers.set("privy-app-id", String(args['privy-app-id'])) if (args['privy-authorization-signature'] != null) headers.set("privy-authorization-signature", String(args['privy-authorization-signature'])) if (args['privy-request-expiry'] != null) headers.set("privy-request-expiry", String(args['privy-request-expiry'])) if (appSecretAuth !== undefined) headers.set('authorization', `Basic ${btoa(`${appSecretAuth.username}:${appSecretAuth.password}`)}`) const url = `${baseUrl.replace(/\/+$/, '')}/v1/policies/${encodeURIComponent(String(args.policy_id))}/rules${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(policyRuleResponse, await res.json()) };