/** * Adapter for the on-chain FeeRegistry contract — the source of truth the * gateway re-reads on every /v1/escrow/pay to size the payment amount. * * The registry stores per-operation `{amount, asset, payee, enabled}` * records keyed on `keccak256(name)`. SDK consumers (builders sizing * payments) MUST read fees from this contract rather than hardcoding * them, or the signed `amount` won't match the gateway's expected total * and /v1/escrow/pay returns 400. * * Five operation kinds are wired up; each kind's name matches the * corresponding `payments.kind` column value on the gateway: * * - 'grant_registration' — one-time fee when a grant is first registered * (POST /v1/grants). * - 'data_access' — per-access surcharge on grant payments * (every accessRecord posted against a grant). * - 'data_registration' — one-time fee for registering a data point * (POST /v1/data → addDataWithSignature). * - 'server_registration' — one-time fee for registering a personal server * (POST /v1/servers). * - 'builder_registration' — one-time fee for registering a builder * (POST /v1/builders; gateway-only, no on-chain * submission). * * Disabled or unregistered fees skip enforcement: the corresponding * operation settles WITHOUT requiring a payment from escrow. `getFee` * surfaces this via `enabled: false` rather than throwing — the gateway * itself treats a disabled fee as a steady state, not a misconfig. * * Deployers can override the on-chain operation strings via * `FEE_REGISTRY__OP` env vars on the gateway side; the matching * SDK escape hatch is the `opts.OpName` arguments. * * This module is signer/transport-agnostic — callers pass in their own * `PublicClient` for the contract reads. No caching here; long-running * service consumers should wrap with their own TTL. Mirrors * data-gateway/lib/fee-registry.ts byte-for-byte. * * @category Protocol */ import { type Address, type PublicClient } from "viem"; import type { DataPortabilityGatewayConfig } from "./eip712.js"; export declare const FEE_REGISTRY_ABI: readonly [{ readonly name: "fees"; readonly type: "function"; readonly stateMutability: "view"; readonly inputs: readonly [{ readonly type: "bytes32"; readonly name: "operation"; }]; readonly outputs: readonly [{ readonly type: "tuple"; readonly components: readonly [{ readonly type: "uint256"; readonly name: "amount"; }, { readonly type: "address"; readonly name: "asset"; }, { readonly type: "address"; readonly name: "payee"; }, { readonly type: "bool"; readonly name: "enabled"; }]; }]; }, { readonly name: "operationKey"; readonly type: "function"; readonly stateMutability: "pure"; readonly inputs: readonly [{ readonly type: "string"; readonly name: "name"; }]; readonly outputs: readonly [{ readonly type: "bytes32"; }]; }]; export type FeeKind = "grant_registration" | "data_access" | "data_registration" | "server_registration" | "builder_registration"; /** * Map from a user-facing opType (POST /v1/escrow/pay body field, matches * the gateway's `payments.op_type` column) to the FeeKind that gates its * one-time registration fee. * * Data access is a per-call surcharge on grants only — it's not a * registration fee for any op, so it lives outside this map. */ export declare const REGISTRATION_KIND_FOR_OP: Record; export interface FeeEntry { amount: bigint; asset: Address; payee: Address; enabled: boolean; } /** * Compound fee schedule for one op type, mirroring the gateway's * lib/op-fees.ts `OpFee`. For ANY op type, `registrationFee` is the * one-time fee charged at registration. For `'grant'` only, `dataAccessFee` * is the per-access surcharge — for any other op type it's always 0n with * `dataAccessEnabled: false`. * * `xxxEnabled` reflects the on-chain `Fee.enabled` flag. When OFF, the * corresponding amount is 0 and the pay handler should NOT require * payment for that kind. When both are off (for a grant) or registration * is off (for any other op type), the entire payment flow is skipped — * the op settles directly via the no-payment path. */ export interface OpFee { asset: Address; registrationFee: bigint; dataAccessFee: bigint; registrationEnabled: boolean; dataAccessEnabled: boolean; registrationPayee: Address; dataAccessPayee: Address; } export interface FeeRegistryOptions { grantRegistrationOpName?: string; dataAccessOpName?: string; dataRegistrationOpName?: string; serverRegistrationOpName?: string; builderRegistrationOpName?: string; } /** * Reads one fee kind from the FeeRegistry. Calls the contract's * `operationKey(name)` first to derive the bytes32 key — matches the * gateway's approach exactly (could compute locally via keccak256, but * going through the contract eliminates any chance of encoding drift). * * Returns `{enabled: false}` entries WITHOUT throwing — disabled is a * valid steady state on the gateway. The only validation is the * zero-payee check, and that only fires when the fee is enabled * (a disabled fee never lands as a SettleOp `to`). */ export declare function getFee(client: PublicClient, config: DataPortabilityGatewayConfig, kind: FeeKind, opts?: FeeRegistryOptions): Promise; /** * Convenience: combine the FeeRegistry reads for one op type into the * compound shape the pay handler validates against. * * For 'grant' opType the result includes both registration + data_access * components; for other op types data_access is always disabled with * amount=0. Disabled components contribute 0 to the signed total — * callers compute `amount = registrationFee + dataAccessFee` and the pay * handler accepts (or short-circuits with 'Payment not required' when * both are 0). * * Throws on asset mismatch ONLY when both components are enabled — a * disabled fee never lands as a SettleOp, so its asset is moot. */ export declare function getOpFee(client: PublicClient, config: DataPortabilityGatewayConfig, opType: string, opts?: FeeRegistryOptions): Promise;