/**
 * TransactionSubmitter, server-side submission orchestrator for the
 * Midnight contract path (deploy + call).
 *
 * Phase 2b: the SDK invocation moved into a `worker_threads` worker (see
 * `srv/midnight/wallet-worker.ts`) so the SDK's Effect.ts microtask saturation
 * stays off the main thread. This class is now an orchestrator:
 *
 *   1. Insert a `pending` row into PendingSubmissions BEFORE invoking the
 *      worker. The row carries our internal UUID; txHash + contractAddress
 *      are filled in once the worker returns. This is the recovery hook for
 *      the "process crashed mid-submission" case.
 *
 *   2. Build a CapDbPrivateStateProvider on the main thread (where the CAP DB
 *      lives) and register it under an ephemeral `proxyId` with the worker
 *      client. The worker creates a thin proxy that round-trips PS CRUD back
 *      to this provider via `private-state-rpc` messages.
 *
 *   3. Invoke the worker (`walletDeployContract` / `walletSubmitContractCall`).
 *      The worker owns the SDK, the compiled contract artifact (cached by
 *      name), and the wallet facade. It returns only primitives
 *      (`txHash`, `contractAddress`, `onChainStatus`) — no SDK object crosses
 *      the thread boundary.
 *
 *   4. On success → UPDATE row with `{ txHash, contractAddress, status }`.
 *      The crawler's BlockProcessor flips it to 'finalized' once the tx hash
 *      appears in a block.
 *
 *   5. On failure → UPDATE row with `{ status='failed', errorCode, errorMessage }`.
 *      Errors are classified (see classifySubmissionError):
 *        - 1014  permanent (invalid tx), no retry
 *        - 1016  on mainnet: deterministic per forum thread 1190 (early May 2026);
 *                fail fast with a known-issue reference. On preprod: retryable.
 *        - TIMEOUT/NETWORK transient, caller may retry
 *        - TxFailedError from SDK, the on-chain status was not SucceedEntirely
 *
 * The submitter does not retry on its own. The OData action callers decide
 * retry policy based on the returned error classification.
 */
import { type ContractProvidersConfig, type WalletMaterial } from '../midnight/providers';
import { walletDeployContract, walletSubmitContractCall } from '../midnight/wallet-worker-client';
export type ActionType = 'DEPLOY' | 'CALL' | 'UPDATE';
export type SubmissionStatus = 'pending' | 'included' | 'finalized' | 'failed';
export interface PendingSubmissionRow {
    ID: string;
    txHash: string | null;
    contractAddress: string | null;
    circuitName: string | null;
    actionType: ActionType;
    submittedAt: string;
    status: SubmissionStatus;
    errorCode?: string;
    errorMessage?: string;
    sessionId?: string;
}
/**
 * Registration meta carried across the thread boundary. The compiled contract
 * object itself does not survive structured-clone, so the worker re-imports
 * the artifact at `artifactPath` and caches the compiled handle by name.
 */
export interface ContractRegistrationMeta {
    artifactPath: string;
    privateStateId: string;
    zkConfigPath: string;
}
export interface DeployArgs<PS = unknown> {
    contractName: string;
    registration: ContractRegistrationMeta;
    initialPrivateState: PS;
    /**
     * Required for worker-routed submissions: the wallet facade is keyed on
     * sessionId inside the worker. Audit-trail role from earlier revisions
     * is unchanged.
     */
    sessionId: string;
}
export interface CallArgs {
    contractAddress: string;
    circuit: string;
    args: unknown[];
    contractName: string;
    registration: ContractRegistrationMeta;
    sessionId: string;
    /**
     * Per-call ZK-predicate witnesses (`commitValue`/`provePredicate`): the
     * hidden value (decimal string) + commitment opening (64-hex salt). Passed
     * to the worker's witness factory; never sent as a circuit arg. Omit for
     * circuits that declare no per-call witnesses.
     */
    witnessValues?: {
        attestedValue: string;
        valueSalt: string;
    };
}
export interface DeployResult {
    submissionId: string;
    txHash: string;
    contractAddress: string;
    status: SubmissionStatus;
}
export interface CallResult {
    submissionId: string;
    txHash: string;
    contractAddress: string;
    status: SubmissionStatus;
}
export interface SubmissionErrorClassification {
    code: string;
    retryable: boolean;
    knownIssueRef?: string;
    message: string;
}
export declare class SubmissionError extends Error {
    readonly submissionId: string;
    readonly classification: SubmissionErrorClassification;
    constructor(submissionId: string, classification: SubmissionErrorClassification, cause?: unknown);
}
export interface TransactionSubmitterDeps {
    /** Provider config: indexer URLs + proof server. Forwarded to the worker. */
    contractProvidersConfig: ContractProvidersConfig;
    /** Wallet material (accountId, password provider, privateStateBackend). */
    walletMaterial: WalletMaterial;
    /** Optional DB handle; defaults to cds.connect.to('db'). Useful for tests. */
    db?: any;
    /**
     * Inject the worker RPC for testing; defaults to the real
     * `walletDeployContract` from wallet-worker-client.
     */
    walletDeployContractImpl?: typeof walletDeployContract;
    /** Same idea for `walletSubmitContractCall`. */
    walletSubmitContractCallImpl?: typeof walletSubmitContractCall;
    /** Network, used by classifySubmissionError to decide if 1016 is fail-fast. */
    network: 'preprod' | 'testnet' | 'mainnet';
}
export declare class TransactionSubmitter {
    private readonly deps;
    private db;
    constructor(deps: TransactionSubmitterDeps);
    deploy<PS = unknown>(args: DeployArgs<PS>): Promise<DeployResult>;
    call(args: CallArgs): Promise<CallResult>;
    /**
     * Build a CapDbPrivateStateProvider for this submission and register it
     * under a fresh `proxyId`. The worker's PS proxy will round-trip CRUD
     * calls back to the matching main-side instance. `release()` unregisters
     * the provider; it's safe to call exactly once after the worker RPC
     * resolves or rejects.
     *
     * Throws if the configured private-state backend is anything other than
     * 'cap-db' — the legacy LevelDB path is incompatible with worker-routed
     * submissions (the SDK's LevelDB provider doesn't survive a thread
     * boundary, and its on-disk format is dev-only per the SDK docs).
     */
    private registerPrivateStateProxy;
    /**
     * The worker stores facades keyed on `accountId` (deterministic per
     * viewing key), set by the pre-warm in connectWalletForSigning. We must
     * use the same key when looking up the facade for deploy/call — the OData
     * user-session UUID would miss. `args.sessionId` is preserved on the
     * PendingSubmissions row for audit.
     */
    private makeDeployRpcArgs;
    private makeCallRpcArgs;
    private getDb;
    private insertPending;
    private updateAfterSdk;
    private markFailed;
}
/**
 * Classifies a thrown error into a stable code + retryability decision.
 * Used by the OData callers and internally to populate
 * PendingSubmissions.errorCode/errorMessage.
 */
export declare function classifySubmissionError(err: unknown, network: 'preprod' | 'testnet' | 'mainnet'): SubmissionErrorClassification;
/**
 * Called by BlockProcessor when a transaction is persisted. If a
 * PendingSubmissions row exists with the same txHash, mark it 'finalized'
 * and attach a JSON snapshot of the indexed tx.
 *
 * No-op if no pending row matches (most txs are not ours).
 */
export declare function reconcilePendingSubmission(db: any, txHash: string, indexedTxSnapshot: Record<string, unknown>): Promise<void>;
