Skip to content

API ReferenceValidationFunction

runValidation()

function runValidation<P>(ctx, rules, params, signal?): Promise<ValidationIssue[]>;

Runs a set of ValidationRules against (possibly partial) operation parameters, without touching a wallet. This is the engine behind sdk.loc.validate* and sdk.vault.validate*; call it directly only when composing your own rule set. Sync checks are pure; async checks read chain and subgraph state through ctx.

Type Parameters

Type Parameter
P

Parameters

ParameterTypeDescription
ctxSDKContextThe SDK context — pass your AnvilSDK instance, which implements SDKContext. Rules read ctx.deps for the RPC client, subgraph, and locConfig.
rulesreadonly ValidationRule<P>[]The rule set to evaluate, normally one of the exported per-operation arrays such as createStaticLOCRules or redeemLOCRules. Rules run in array order; a rule only fires when every dependsOn field is non-nullish.
paramsPartial<P>The operation’s parameters, possibly incomplete — a form’s current values are the intended input. A missing field that is a rule’s own errorField reports FieldRequired for that rule; a missing field that is only a foreign dependency skips the rule silently.
signal?AbortSignalOptional AbortSignal forwarded to async rules. When omitted a no-op signal is used (never aborted). Caller cancellation rejects with the signal’s exact reason, without normalization.

Returns

Promise<ValidationIssue[]>

Remarks

Executes all rules eagerly (no debouncing). For each rule:

  1. If the rule’s own errorField is among its dependsOn and that value is missing, report one FieldRequired issue for that field and skip the rule’s sync/async callbacks entirely — a rule declares a field required by depending on the field it reports on.
  2. Otherwise, if any dependsOn field is missing, skip the rule silently (a foreign dependency isn’t ready yet; that isn’t this field’s verdict).
  3. Run sync. If sync returns issues, skip async.
  4. If sync passes and rule has async, run async with the caller’s signal.
  5. Collect all issues from all rules. Duplicate FieldRequired issues for the same field (e.g. two rule factories composed for one field) collapse to one.

A resolved array means every applicable rule completed: empty is valid, non-empty is domain-invalid. It never carries a partial list — an infrastructure failure rejects instead of resolving. Critically, an empty list never means “nothing could run” — a rule whose own required field is absent reports that absence rather than being silently skipped, so [] unambiguously means checked and valid.

useIncrementalValidation’s field-level dependency gating is unchanged: its per-keystroke path still defers a rule silently while dependencies are incomplete, so a form doesn’t flash unrelated errors mid-entry. Only this eager path and its validateAll submit-time counterpart report the required-field absence. A rule whose errorField is not one of its own dependsOn entries is optional by construction and never reports absence.

A rejected async rule is not a field verdict: this promise rejects with a normalized SDK error and exposes none of the issues collected by the incomplete run. Existing BaseError instances preserve identity; recognizable provider failures become ProviderConnectionError; and unclassifiable failures become ContactSupportError with the original rejection as cause.

Throws

ProviderConnectionError when a rule rejects with a recognizable provider or transport failure.

Throws

ContactSupportError when a rejected rule failure cannot be classified. Existing SDK errors and caller abort reasons propagate unchanged.

Example

// Partial params are safe to call with: a rule whose own required field is
// absent reports `FieldRequired` for that field instead of being silently
// skipped, while a rule missing only a foreign (non-required) dependency
// still defers silently. This draft deliberately omits the required
// `expirationTimestampSeconds`, so that rule reports it instead of being
// silently skipped. `tokenAmount` is well-formed here, so
// `staticLOCCollateralRules`' async checks also run against live chain
// state alongside it -- expect more than just the one field, and a
// rejection instead of a resolved array without a connected wallet.
const draft: Partial<CreateStaticLOCParams> = {
beneficiary: '0x1111111111111111111111111111111111111111',
tokenAmount: {
tokenAddress: testnetProfile.contracts.USDC.address,
amount: 250_000_000n,
},
};
// The SDK instance is the SDKContext; async rules read chain and subgraph
// state through it.
const issues = await runValidation(sdk, createStaticLOCRules, draft);
if (issues.length === 0) return 'ok';
return issues.map(i => `${i.field}: ${getValidationErrorMessage(i)}`);