Skip to content

Commit

Permalink
Update ERC-7573: Update erc 7573 - add optional key hashed
Browse files Browse the repository at this point in the history
Merged by EIP-Bot.
  • Loading branch information
cfries authored Mar 8, 2025
1 parent f74260f commit 93d3353
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 33 deletions.
44 changes: 26 additions & 18 deletions ERCS/erc-7573.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,22 +47,26 @@ documentation [`ILockingContract.sol`](../assets/eip-7573/contracts/ILockingCont
##### Initiation of Transfer: `inceptTransfer`

```solidity
function inceptTransfer(bytes32 id, int amount, address from, string memory keyEncryptedSeller) external;
function inceptTransfer(bytes32 id, int amount, address from, string keyHashedSeller, string memory keyEncryptedSeller) external;
```

Called from the buyer of the token to initiate token transfer. Emits a `TransferIncepted` event.
The parameter `id` is an identifier of the trade. The parameter `from` is the address of the seller (the address of the buyer is `msg.sender`).
The parameter `keyEncryptedSeller` is an encryption (or, alternatively, hash) of the key that can be used by the seller to (re-)claim the token. See below on "encryption".
The parameter `keyHashedSeller` is a hash of the key that can be used by the seller to (re-)claim the token.
The parameter `keyEncryptedSeller` is an encryption of the key that can be used by the buyer to claim the token.
It is possibly to implement the protocol in a way where the hashing method agrees with the encryption method. See below on "encryption".

##### Initiation of Transfer: `confirmTransfer`

```solidity
function confirmTransfer(bytes32 id, int amount, address to, string memory keyEncryptedBuyer) external;
function confirmTransfer(bytes32 id, int amount, address to, string keyHashedBuyer, string memory keyEncryptedBuyer) external;
```

Called from the seller of the token to confirm token transfer. Emits a `TransferConfirmed` event.
The parameter `id` is an identifier of the trade. The parameter `to` is the address of the buyer (the address of the seller is `msg.sender`).
The parameter `keyEncryptedBuyer` is an encryption (or, alternatively, hash) of the key that can be used by the buyer to claim the token.
The parameter `keyHashedBuyer` is a hash of the key that can be used by the buyer to (re-)claim the token.
The parameter `keyEncryptedBuyer` is an encryption of the key that can be used by the buyer to (re-)claim the token.
It is possibly to implement the protocol in a way where the hashing method agrees with the encryption method. See below on "encryption".

If the trade specification, that is, the quadruppel (`id`, `amount`, `from`, `to`), in a call to `confirmTransfer`
matches that of a previous call to `inceptTransfer`, and the balance is sufficient, the corresponding `amount`
Expand All @@ -77,10 +81,10 @@ function transferWithKey(bytes32 id, string memory key) external;
Called from either the buyer or the seller of the token
of the trade with id `id`.

If the method is called from the buyer (`to`) *and* the encryption of `key` matches `keyEncryptedBuyer`,
If the method is called from the buyer (`to`) *and* the hashing of `key` matches `keyHashedBuyer`,
then the locked tokens are transferred to the buyer (`to`). This emits `TokenClaimed`.

If the method is called from the seller (`from`) *and* the encryption of `key` matches `keyEncryptedSeller`,
If the method is called from the seller (`from`) *and* the hashing of `key` matches `keyHashedSeller`,
then the locked tokens are transferred (back) to the seller (`to`). This emits `TokenReclaimed`.

##### Summary
Expand All @@ -89,13 +93,13 @@ The interface `ILockingContract`:

```solidity
interface ILockingContract {
event TransferIncepted(bytes32 id, int amount, address from, address to, string keyEncryptedSeller);
event TransferConfirmed(bytes32 id, int amount, address from, address to, string keyEncryptedBuyer);
event TransferIncepted(bytes32 id, int amount, address from, address to, string keyHashedSeller, string keyEncryptedSeller);
event TransferConfirmed(bytes32 id, int amount, address from, address to, string keyHashedBuyer, string keyEncryptedBuyer);
event TokenClaimed(bytes32 id, string key);
event TokenReclaimed(bytes32 id, string key);
function inceptTransfer(bytes32 id, int amount, address from, string memory keyEncryptedSeller) external;
function confirmTransfer(bytes32 id, int amount, address to, string memory keyEncryptedBuyer) external;
function inceptTransfer(bytes32 id, int amount, address from, string memory keyHashedSeller, string memory keyEncryptedSeller) external;
function confirmTransfer(bytes32 id, int amount, address to, string memory keyHashedBuyer, string memory keyEncryptedBuyer) external;
function transferWithKey(bytes32 id, string memory key) external;
}
```
Expand All @@ -112,7 +116,7 @@ documentation [`IDecryptionContract.sol`](../assets/eip-7573/contracts/IDecrypti
function inceptTransfer(bytes32 id, int amount, address from, string memory keyEncryptedSuccess, string memory keyEncryptedFailure) external;
```

Called from the receiver of the amount to initiate payment transfer. Emits a `PaymentTransferIncepted`.
Called from the receiver of the amount to initiate payment transfer. Emits a `TransferIncepted`.
The parameter `id` is an identifier of the trade. The parameter `from` is the address of the sender of the payment (the address of the receiver is `msg.sender`).
The parameter `keyEncryptedSuccess` is an encryption of a key and will be decrypted if the transfer is successful in a call to `transferAndDecrypt`.
The parameter `keyEncryptedFailure` is an encryption of a key and will be decrypted if the transfer fails in a call to `transferAndDecrypt` or if `cancelAndDecrypt` is successful.
Expand Down Expand Up @@ -174,21 +178,25 @@ interface IDecryptionContract {

### Encryption and Decryption

The linkage of the two smart contract relies on use of a `key` and `encryptedKey`.
The linkage of the two smart contract relies on use of a `key`, `encryptedKey` and `hashedKey`.
The implementation is free to support several encryption methods for
as long as the decryption oracle supports it.

The encryption is performed with the public key of
the decryption oracle, which is known to both parties.
The encryption is performed with the public key of the decryption oracle.
Either the encryption oracle offer a method performing encryption, in which
case the encryption method isn't even required to be known, or both parties
know the public key of the decryption oracle and can perform the generation
of the key and its encryption.

It is implicitly assumed that the two parties may check that
the strings `keyEncryptedBuyer` and `keyEncryptedSeller` are
in a valid format.

To avoid on-chain encryption in the `ILockingContract`, it is possible to use a simpler hashing algorithm
on the `ILockingContract`. In that case, the decryption oracle has
to provide a method that allows to obtain the hash *H(K)* for an
encrypted key *E(K)* without exposing the key *K*, cf. [^2].
To avoid on-chain encryption in the `ILockingContract`, it is possible to use a
simpler hashing algorithm on the `ILockingContract`. In that case, the decryption oracle has
to provide a method that allows to obtain the hash *H(K)* (``keyHashed`) for an
encrypted key *E(K)* (``keyEncrypted`) without exposing the key *K* (``key`), cf. [^2].


### Sequence diagram of delivery versus payment

Expand Down
9 changes: 9 additions & 0 deletions assets/erc-7573/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# DvP Solidity implementation

## Description

### Provided Contracts and Tests

- `contracts/ILockingContract.sol` - Contract locking transfer with given encrypted keys or hashes.
- `contracts/IDecryptionContract.sol` - Contract performing conditional upon transfer decryption (possibly based on an external oracle).

2 changes: 1 addition & 1 deletion assets/erc-7573/contracts/IDecryptionContract.sol
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ interface IDecryptionContract {

/**
* @notice Called from the receiver of the amount to initiate payment transfer.
* @dev emits a {PaymentTransferIncepted}
* @dev emits a {TransferIncepted}
* @param id the trade identifier of the trade.
* @param amount the amount to be transferred.
* @param from The address of the sender of the payment (the receiver ('to') is message.sender).
Expand Down
44 changes: 30 additions & 14 deletions assets/erc-7573/contracts/ILockingContract.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ pragma solidity >=0.7.0;
* The rationale is that the token is locked with two encrypted keys
* or hashes of keys associated with two different adresses (buyer/seller).
*
* The asset is transfered to the address of the buyer, if the buyer's key is presented.
* The asset is transferred to the address of the buyer, if the buyer's key is presented.
*
* The asset in (re-)transfered to the address of the seller, if the seller's key is presented.
* The asset in (re-)transferred to the address of the seller, if the seller's key is presented.
*/
interface ILockingContract {

Expand All @@ -29,21 +29,24 @@ interface ILockingContract {
/**
* @dev Emitted when the transfer for the token is incepted
* @param id the trade identifier of the trade.
* @param amount the number of tokens to be transferred.
* @param from The address of the seller.
* @param to The address of the buyer.
* @param keyEncryptedSeller Encryption (or, alternatively, hash) of the key that can be used by the seller to (re-)claim the token.
* @param keyHashedSeller Hashing (or, alternatively, encryption) of the key that can be used by the seller to (re-)claim the token.
* @param keyEncryptedSeller Encryption of the key that can be used by the seller to (re-)claim the token, if it was provided to inceptTransfer.
*/
event TransferIncepted(bytes32 id, int amount, address from, address to, string keyEncryptedSeller);
event TransferIncepted(bytes32 id, int amount, address from, address to, string keyHashedSeller, string keyEncryptedSeller);

/**
* @dev Emitted when the transfer for the token is incepted
* @dev Emitted when the transfer for the token is confirmed
* @param id the trade identifier of the trade.
* @param amount the number of tokens to be transfered.
* @param amount the number of tokens to be transferred.
* @param from The address of the seller.
* @param to The address of the buyer.
* @param keyEncryptedBuyer Encryption (or, alternatively, hash) of the key that can be used by the buyer to claim the token.
* @param keyHashedBuyer Hashing (or, alternatively, encryption) of the key that can be used by the buyer to claim the token.
* @param keyEncryptedBuyer Encryption of the key that can be used by the buyer to claim the token, if it was provided to confirmTransfer.
*/
event TransferConfirmed(bytes32 id, int amount, address from, address to, string keyEncryptedBuyer);
event TransferConfirmed(bytes32 id, int amount, address from, address to, string keyHashedBuyer, string keyEncryptedBuyer);

/**
* @dev Emitted when the token was successfully claimed (forwarded to the buyer).
Expand All @@ -65,21 +68,34 @@ interface ILockingContract {
* @notice Called from the buyer of the token to initiate the token transfer.
* @dev emits a {TransferIncepted}
* @param id the trade identifier of the trade.
* @param amount the number of tokens to be transfered.
* @param amount the number of tokens to be transferred.
* @param from The address of the seller (the address of the buyer is message.sender).
* @param keyEncryptedSeller Encryption (or, alternatively, hash) of the key that can be used by the seller to (re-)claim the token.
* @param keyHashedSeller Hashing (or, alternatively, encryption) of the key that can be used by the seller to (re-)claim the token.
* @param keyEncryptedSeller Encryption of the key that can be used by the seller to (re-)claim the token. This parameter is optional if keyHashedSeller and keyEncryptedSeller agree. If they not agree, the method will emit both, to allow observing the pair.
*/
function inceptTransfer(bytes32 id, int amount, address from, string memory keyEncryptedSeller) external;
function inceptTransfer(bytes32 id, int amount, address from, string memory keyHashedSeller, string memory keyEncryptedSeller) external;

/**
* @notice Called from the seller of the token to confirm the token transfer. Locks the token.
* @dev emits a {TransferConfirmed}
* @param id the trade identifier of the trade.
* @param amount the number of tokens to be transfered.
* @param amount the number of tokens to be transferred.
* @param to The address of the buyer (the address of the seller is message.sender).
* @param keyEncryptedBuyer Encryption (or, alternatively, hash) of the key that can be used by the buyer to claim the token.
* @param keyHashedBuyer Hashing (or, alternatively, encryption) of the key that can be used by the buyer to claim the token.
* @param keyEncryptedBuyer Encryption of the key that can be used by the buyer to claim the token. This parameter is optional if keyHashedSeller and keyEncryptedSeller agree. If they not agree, the method will emit both, to allow observing the pair.
*/
function confirmTransfer(bytes32 id, int amount, address to, string memory keyHashedBuyer, string memory keyEncryptedBuyer) external;

/**
* @notice Called from the buyer of the token to cancel token transfer (cancels the incept transfer).
* @dev emits a {TransferKeyRequested}
* @param id the trade identifier of the trade.
* @param amount the number of tokens to be transfered.
* @param from The address of the seller (the address of the buyer is message.sender).
* @param keyHashedSeller Hashing (or, alternatively, encryption) of the key that can be used by the seller to (re-)claim the token.
* @param keyEncryptedSeller Encryption of the key that can be used by the seller to (re-)claim the token. This parameter is optional if keyHashedSeller and keyEncryptedSeller agree. If they not agree, the method will emit both, to allow observing the pair.
*/
function confirmTransfer(bytes32 id, int amount, address to, string memory keyEncryptedBuyer) external;
function cancelTransfer(bytes32 id, int amount, address from, string memory keyHashedSeller, string memory keyEncryptedSeller) external;

/**
* @notice Called from the buyer or seller to claim or (re-)claim the token. Unlocks the token.
Expand Down
Binary file not shown.
Binary file added assets/erc-7573/doc/DvP-Seq-Diag.pdf
Binary file not shown.
Binary file modified assets/erc-7573/doc/DvP-Seq-Diag.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 41 additions & 0 deletions assets/erc-7573/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"name": "@finmath.net/dvp",
"version": "0.2.0",
"description": "Solidity Conditional-upon-Transfer-Decryption for DvP",
"author": "Christian Fries, Peter Kohl-Landgraf",
"license": "ISC",
"homepage": "https://github.com/finmath/finmath-smart-derivative-contract#readme",
"main": "index.js",
"scripts": {
"build": "hardhat compile",
"test": "hardhat test",
"coverage": "hardhat coverage"
},
"devDependencies": {
"@nomiclabs/hardhat-ethers": "^2.2.3",
"@nomiclabs/hardhat-waffle": "^2.0.6",
"chai": "^4.3.10",
"ethereum-waffle": "^4.0.10",
"ethers": "^5.7.2",
"hardhat": "^2.18.1",
"solidity-coverage": "^0.8.5"
},
"dependencies": {
"@openzeppelin/contracts": "^5.0.0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/finmath/finmath-smart-derivative-contract.git"
},
"keywords": [
"Delivery versus Payment",
"HTLC",
"EIP-7573"
],
"bugs": {
"url": "https://github.com/finmath/finmath-smart-derivative-contract/issues"
},
"publishConfig": {
"access": "public"
}
}

0 comments on commit 93d3353

Please sign in to comment.