npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@finmath.net/dvp

v0.9.0

Published

Solidity Conditional-upon-Transfer-Decryption for DvP and nDvP

Readme

DvP Solidity implementation

Description

The interfaces in this proposal model a functional transaction scheme to establish a secure delivery-versus-payment across two blockchains, where a) no intermediary is required and b) one of the two chains can securely interact with a stateless "decryption oracle". Here, delivery-versus-payment refers to the exchange of, e.g., an asset against a payment; however, the concept is generic to make a transfer of one token on one chain (e.g., the payment) conditional to the successful transfer of another token on another chain (e.g., the asset).

The scheme is realized by two smart contracts, one on each chain. One smart contract implements the ILockingContract interface on one chain (e.g. the "asset chain"), and another smart contract implements the IDecryptionContract interface on the other chain (e.g., the "payment chain"). The smart contract implementing ILockingContract locks a token (e.g., the asset) on its chain until a presented key's hash or other locking representation matches one of two committed values. The smart contract implementing IDecryptionContract, decrypts one of two keys (via the decryption oracle) conditional to the success or failure of the token transfer (e.g., the payment). A stateless decryption oracle is attached to the chain running IDecryptionContract for the decryption.

Provided Contracts

DvP

  • contracts/ILockingContract.sol - Contract locking transfer with given encrypted keys or hashes.
  • contracts/ILockingContractWithKeyGeneration.sol - Optional same-chain locking extension that authorizes a decryption contract as the generated-key source.
  • contracts/IDecryptionContract.sol - Contract performing conditional upon transfer decryption (possibly based on an external oracle).
  • contracts/IDecryptionContractWithKeyGeneration.sol - Optional extension for asynchronous generation of the encrypted success and failure keys.
  • contracts/IDecryptionContractInceptionCallback.sol - Optional on-chain notification when asynchronous inception completes.

ERC-7573 does not standardize an application-level initTransfer method. Before the first ERC-7573 call, the application workflow allocates an identifier for each transfer leg and binds its arbitrary application data as transaction. Each implementation treats that id as lifetime-unique and rejects its reuse. Corresponding locking and decryption contracts may use the same numeric id for the two sides of one DvP operation. A group or multi-party identifier belongs in transaction; distinct legs on one implementation still require distinct IDs.

Every transfer term-bearing call supplies from and to explicitly. msg.sender identifies only the caller and MUST NOT, by itself, determine either participant. Implementations MAY require the caller to be a participant or an authorized operator. Decryption confirmation and cancellation repeat the complete context, including the asynchronous callback (or zero), and both key references. Locking confirmation repeats the transfer context and adds the other party's outcome-key material. These explicit arguments let each contract require exact agreement with its immutable inception, so separate inception and confirmation hashes are unnecessary.

Every successful token lock emits TokenLocked(id) exactly once, after the token has actually been locked. This provides one flow-independent completion signal for both classic confirmation and generated-key completion. Failed, pending, cancelled, and idempotent no-op attempts do not emit it.

The asynchronous extension uses one inceptTransfer signature with an optional callback parameter. After storing the generated keys and emitting TransferIncepted, the decryption contract passes the unique transfer id to a nonzero callback. The callback reads the immutable context and semantically ordered H/E material through getters keyed by id; explicit exists and available values distinguish lifecycle state from empty data. Passing address(0) selects an event-driven workflow, but a generated-key asset lock requires an inception whose callback is that exact asset contract. After terminal key release, a same-chain decryption contract may best-effort relay the key to that locking contract. The released-key event remains the recovery path if the relay fails.

Decryption Oracle

  • contracts/IKeyDecryptionOracle.sol - Interface implemented by a decryption oracle proxy contract.
  • contracts/IKeyDecryptionOracleCallback.sol - Interface to be implemented by a callback receiving the decrypted key.

Oracle request methods return a proxy-scoped requestId, and callbacks use that identifier. The caller-supplied DvP id remains request-event context and is not used to route callbacks.

Key generation and verification are atomic, role-tagged batch operations. A verification request supplies a non-empty EncryptedKey[], where each entry contains a semantic keyId and its encrypted key. A successful callback returns the exact complete set as EncryptedHashedKey[], under one common receiver and transaction; array position has no meaning and partial success is forbidden. A one-element batch covers the singular case. The explicit verification result distinguishes rejection from empty data. Decryption remains single-key because settlement releases exactly one outcome key.

Batch verification is not, by itself, replay protection. Every key reference in the batch must authenticate the same unique, one-use settlement context (for example the chain, decryption contract and lifetime-unique transfer id), the same external transaction/batch id, and its own key role. A verifier needs verification-only access to every reference; this must not grant authority to request or fulfill decryption of the failure key.

Despite the historical encryptedKey name, a reference need not be confidential ciphertext. It may be a publicly readable, versioned and signed byte sequence representing an external settlement. This allows each participant to verify every outcome through its own adapter; possession or readability of the reference must never itself authorize release of the key.

Documentation

  • doc/DvP-Seq-Diag.png - Sequence diagram of the DvP
  • doc/multi-party-dvp.svg - Sequence diagram of a multi-party-dvp.