Theoretical Background
Introduction
The decryption oracle solves the problem of observing parameters of a function prior to function execution.
A function may consume two encrypted parameters and decide upon internal state (e.g. success of a transfer) which of the two parameters is exposed.
This enables a secure cross chain delivery-versus-payment and even a multi-party (and possibly multi-chain) delivery-versus-payment.
Multi-Party Delivery versus Payment
For details see ssrn.com/abstract=4628811.
Locking is a Feature
In Delivery-versus-Payment (DvP) protocols like ERC-7573, at least one token must be locked to ensure atomicity, even if only for a short period during the transaction.
While locking may appear as an inconvenient necessity, it is in fact a feature that becomes valuable in the construction of conditional trades or multi-party DvPs.
If n parties wish to perform bilateral transactions atomically, there are at least m := 2 • (n - 1) transactions, of which m-1 require locking. The last one can operate directly, and its success or failure decides whether the other locks are released or reverted.
A multi-party delivery versus payment is a valuable trade feature. Consider, for example, the case where counterparty A wishes to buy a token Y (e.g., a bond) from counterparty C, but in order to fund this transaction, counterparty A wishes to sell a token X (e.g., another bond) to counterparty B. However, A does not want to sell bond X if the purchase of Y fails. A multi-party DvP allows these two transactions to be bound into a single atomic unit.
While for a two-party DvP with two tokens only one token requires locking—and hence a DvP can be constructed without locking on the cash chain—a three-party DvP with three tokens in general requires the ability to lock all three tokens.
This highlights that locking is not just a constraint, but a required feature to enable advanced and economically meaningful protocols.
The sequence diagram below shows a DvP between two contracts on two different chains, secured by an encrypted-hashed key. The key is generated by the key decryption oracle internally binding to the eligible contract. Upon successful transfer of the first token (e.g. delivery) it is conditionally decrypted allowing to unlock the other token (e.g. payment).
N-DvP with ERC-7573
A multi-party DvP can be created elegantly by combining multiple two-party DvPs, for example based on the ERC-7573 protocol.
Before the first ERC-7573 call, the application allocates each leg's id and binds
the application-specific transaction; ERC-7573 does not standardize that initialization.
Every payment leg uses its own lifetime-unique ERC-7573 id. A common group
identifier and any frozen group definition are encoded in the immutable
transaction data of each leg. Instead of finalizing the respective two-party
DvP immediately, each completed payment leg is first confirmed by repeating its
complete context, including the callback binding (or zero), and both key references,
leaving group finalization open.
For asynchronous key generation, a contract that requires an on-chain continuation
can supply a callback to inceptTransfer. Once both keys are stored and
TransferIncepted is emitted, the decryption contract calls onInceptionCompleted
with the transfer id. The receiver then reads the immutable context and
success/failure H/E material through the standardized inception getters keyed by that
id.
Passing address(0) disables callback delivery for workflows driven by the existing
event. A generated-key asset lock instead requires the inception to bind that exact
asset as callback; completeLock cannot consume a callback-zero or differently bound
inception.
Before finalization, an authorized submitter can call cancelAndDecrypt with the
leg's complete matching context, callback binding, and both key references to release the failure key
and revert all lockings.
Before accepting the first confirmation, the contract freezes the expected legs and finalizer policy. Every leg must use the same group outcome, either through one shared success/failure key pair or a frozen complete set of per-leg outcome keys.
Once all legs in that frozen set are confirmed, a single call to transferAndDecrypt(id)
performs locking of the token implementing the IDecryptionContract and requests all
success keys on success or all failure keys on failure.
Initiation and Finalization
The frozen group definition establishes which submitters may finalize via
transferAndDecrypt(id). That authorization is separate from the explicit transfer
participants; neither from nor to is inferred from msg.sender. An authorized
submitter may cancel via cancelAndDecrypt with the complete immutable leg context.
Sequence Diagram
Below we depict the corresponding sequence diagram of a multi-party DvP via ERC-7573.
Note that the individual DvP may come in two different flavors depending on which counterparty is the receiver of the token on the IDecryptionContract.
The diagram depicts a multi-party dvp with n+1 counterparties trading n+1 tokens out of which the DvPs are bound by the contract on token 0.
The method signatures above are normative. This historical diagram is illustrative and predates the current explicit-argument ABI.
Note: The more general case of N counterparties trading M tokens is just a special case where we enumerate all combination as new counterparties and new tokens.
