35. Discard or resolve a validation
A validation reserves room on the register from the moment it is issued. When the transfer it authorized never executes, or executes on one of two satellites only, that reservation has to be given back, or it blocks other movements indefinitely. Nothing is released automatically. The Validation Keeper discards validations that expired without any report, and resolves transfers between two satellites of which one report never arrived. Both are routine operations of an asset that is active on satellites.
At a glance
Triggered by
Validation Keeper
Actors
Validation Keeper, Issuer, Platform
Contracts
ModularCompliance, Token
Preconditions
The caller holds VALIDATION_KEEPER in the asset's domain (see 25); to discard: the validation is Pending and past its release time; to resolve: the validation has received one of two reports and is a second reconciliation window past its release time
Result
The reservation of the validation is released. For a resolution, the amount held in transit is back on the wallet it left, or issuance is paused for the chain that owes its report
Actors and roles
Validation Keeper
Finds the validations to release and submits the calls. An automated operator, run by the T-REX Network.
VALIDATION_KEEPER on the ModularCompliance, granted by the Issuer
Issuer
Grants the role to the keeper and is informed of resolutions. Does not transact in this flow.
The authority over who holds the role
Platform
Indexes validations and their status for the keeper.
Read access
Sequence
Step by step
Step 1. Find the validations to release
Who: Platform, on behalf of the Validation Keeper
Call: Off-chain, using read calls
Before the call: The Platform indexes TransferValidationIssued and keeps the identifiers of the validations that are not settled.
What happens: For each open validation, the Platform reads ModularCompliance.statusOf(validationId).
statusOf returns
Meaning
Action
Pending
Not past its release time.
None. A settlement is still expected
Expired
Past its release time, and no report arrived.
Discard (step 2)
AwaitingMint, AwaitingBurn
One of two reports arrived.
None until the second window has passed. Then resolve (step 3)
DiscardedAwaitingMint, DiscardedAwaitingBurn
Discarded, then one of two reports arrived late.
Same
For a resolution, the Platform reads ModularCompliance.validationOf(validationId) and computes the earliest time: releaseAt plus the reconciliation window of the validation, which is releaseAt less expiry.
What changes: Nothing on-chain.
Step 2. Discard expired validations
Who: Validation Keeper (VALIDATION_KEEPER)
Call: ModularCompliance.discardExpiredValidations(validationIds)
Before the call: Every identifier in the list reads Expired.
What the contract checks:
The caller holds
VALIDATION_KEEPERin the asset's domain. Otherwise the call reverts withAccessManagedUnauthorized.Each identifier was issued. Otherwise
UnknownValidation.Each validation is stored as
Pending. OtherwiseValidationNotDiscardable, with the status found. A validation that received one report is refused whatever the clock says.The current time is past the
releaseAtof each validation. OtherwiseValidationNotReleasable, with the release time.
The batch is atomic. One refused identifier reverts the whole call.
What changes: For each validation: the status becomes Discarded. The compliance subtracts amountMax from the pending amounts of the two identities, unless both wallets belong to one identity, in which case nothing was reserved for them. The token gives back the reservation on the sending wallet and emits ReleasedFromValidation. The compliance emits ValidationDiscarded(validationId). The next validation is computed as if this one had never been issued. Nothing is undone on the ownership side, because nothing had moved.
Step 3. Resolve a stuck validation
Who: Validation Keeper (VALIDATION_KEEPER)
Call: ModularCompliance.resolveStuckValidation(validationId)
Before the call: The validation is a transfer between two satellites, one report arrived, and the second window has passed. The Issuer is informed: a resolution means a satellite did not report.
What the contract checks:
The caller holds
VALIDATION_KEEPERin the asset's domain. OtherwiseAccessManagedUnauthorized.The identifier was issued. Otherwise
UnknownValidation.The validation is awaiting its other report. Otherwise
ValidationNotStuck, with the status found.The current time is past
releaseAtplus the reconciliation window of the validation. OtherwiseValidationNotYetResolvable, with the earliest time.When the burn was reported: the token is not paused. Otherwise
EnforcedPause.
What changes: It depends on which report arrived.
The burn
The amount held in transit goes back to the bridged position of the wallet it was burned from. The token emits ReturnedInTransit(walletKey, validationId, wallet, amount).
The mint
Nothing on the reference chain can be returned. The compliance pauses the issuance of validations for the sender's chain and emits ValidationIssuancePaused(chainKey).
In both cases the compliance releases whatever the validation still reserves, sets the status to Resolved, and emits ValidationResolved(validationId, returnedAmount). returnedAmount is zero when only the mint was reported. A report that arrives for a Resolved validation halts the token.
State after the flow
After a discard:
ModularCompliance.statusOf(validationId)isDiscarded.ModularCompliance.pendingOutOfandpendingInOfof the two identities, andToken.reservedOf(wallet), no longer count the validation.No balance and no position has changed.
After a resolution:
ModularCompliance.statusOf(validationId)isResolved.When the burn was reported:
Token.inTransitOf(validationId)is zero andToken.bridgedBalanceOf(wallet)has increased by the amount returned. On the satellite, the tokens are burned. The register and the satellite now disagree for that wallet, and the Issuer reconciles them.When the mint was reported:
ModularCompliance.isIssuancePaused(chainKey)is true for the sender's chain. On the receiving satellite, the recipient holds tokens the register does not record as its own.No position of any identity has changed.
Failure modes
Reverts with AccessManagedUnauthorized
The caller does not hold VALIDATION_KEEPER in the asset's domain (check 1 of steps 2 and 3)
Grant the role: 25
Reverts with UnknownValidation
The identifier was never issued by this compliance (check 2 of steps 2 and 3)
Take identifiers from TransferValidationIssued
discardExpiredValidations reverts with ValidationNotDiscardable
One validation of the batch is not Pending: it settled in the meantime, was already discarded, or received one report (step 2, check 3)
Read statusOf again. Remove the identifier and resubmit
discardExpiredValidations reverts with ValidationNotReleasable
One validation of the batch is not past its release time (step 2, check 4)
Wait until the time the error gives
resolveStuckValidation reverts with ValidationNotStuck
The validation is not awaiting a second report (step 3, check 3)
For a validation with no report, discard. For a settled one, nothing to do
resolveStuckValidation reverts with ValidationNotYetResolvable
The second window has not passed (step 3, check 4)
Wait until the time the error gives
resolveStuckValidation reverts with EnforcedPause
The token is paused and an amount held in transit cannot be returned (step 3, check 5)
Lift the pause first: 16
A settlement arrives after its validation was discarded
The satellite executed in time and its report was slower than the window
It is applied as a late reconciliation: 36
The token paused itself after a resolution
The missing report arrived after the validation was resolved
A wallet's available amount stays reduced long after a transfer was abandoned
The validation expired and nobody discarded it
Release is never automatic. Check that the keeper holds VALIDATION_KEEPER for the asset, and report the validation to the T-REX Network
Common misunderstandings
Wrong: "An expired validation releases its reservation by itself."
Right: Past its release time, a validation reads
Expiredand keeps its reservation until the Validation Keeper discards it.Expiredis computed when the status is read. It is not a stored state and it triggers nothing.
Wrong: "Discarding a validation cancels the transfer."
Right: A discard releases the reservation on the register. It cannot stop the satellite, and it does not need to: past
expiry, T-REX Lite refuses to execute. If the satellite did execute in time and its report arrives after the discard, the register applies it late.
Wrong: "Anyone can clean up expired validations."
Right: The keeper is a restricted role, which the Issuer grants. Discarding is what turns a slow settlement into a late one, and a late settlement that breaches a rule stops a chain from issuing. The T-REX Network runs the keeper, so an Issuer does not have to operate one.
Wrong: "A transfer with one report can be discarded like any other."
Right: One report proves that a satellite executed its half, irreversibly. Such a validation is never discarded. It is settled by the second report, or resolved after a second window, with consequences the Issuer has to look into.
Integration notes
The keeper runs on a schedule. Its input is the list of open validations, from
TransferValidationIssuedlessValidationSettled,ValidationDiscardedandValidationResolved.Read
statusOffor every identifier just before submitting. One identifier that settled in the meantime reverts the whole batch.Do not discard at the first second. A margin after
releaseAtcosts little, and it turns fewer slow settlements into late reconciliations.The keeper holds back while the token is paused, and during a known outage of a messaging provider. An Issuer that knows of such an outage tells the T-REX Network. Settlements that cannot be delivered are not abandoned transfers.
Treat every resolution as an incident. Alert the Issuer on
ValidationResolved: a satellite failed to report, and the register and that satellite disagree until the Issuer has reconciled them. What executed on a satellite is final, so the register is brought in line with it: 36.A discard works while the token is paused. A resolution that returns an amount held in transit does not.
Related flows
31 Transfer on a satellite : where a validation comes from
34 Transfer between two satellites : the transfers that can get stuck
36 Handle a late reconciliation or a halt : what follows a late report or a resolution
33 Open an asset on a satellite : where the windows are set
25 Commission a suite and grant roles : granting
VALIDATION_KEEPER
Last updated