Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ERC 1630 - Hashed Time-Locked Contract Standard #1630

Closed
wants to merge 12 commits into from
265 changes: 265 additions & 0 deletions EIPS/eip-1630.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
---
eip: 1630
title: Hashed Time-Locked Contracts
author: Matthew Black <[email protected]>, TingWei Liu <[email protected]>, Liquality Team <[email protected]>
status: Draft
discussions-to: https://github.com/ethereum/EIPs/issues/1631
type: Standards Track
category: ERC
created: 2018-11-28
---

## Simple Summary

A standard EVM script for generalized payments that acknowledges receiving the payment prior to a deadline.

## Abstract

A Hashed Time-Lock Contract (HTLC) is a script that permits a designated party (the "seller") to spend funds by disclosing the preimage of a hash. It also permits a second party (the "buyer") to spend the funds after a timeout is reached, in a refund situation.

## Motivation

HTLC transactions are a safe and cheap method of exchanging secrets for money over the blockchain, due to the ability to recover funds from an uncooperative counterparty, and the opportunity that the possessor of a secret has to receive the funds before such a refund can occur.

HTLC's enable cross-chain [atomic swaps](https://en.bitcoin.it/wiki/Atomic_swap)

## Definitions

`msg.sender`: is always the address where the current (external) function call came from.
`buyer`: entity that receives funds from `seller` once the `seller` reveals the `secret`
`seller`: entity that contributes funds to the `buyer` by revealing the `secret` or refunds after `expiration`
`secret`: random number chosen by the `seller`, revealed to allow the `buyer` to redeem the funds
`secretHash`: hash of the `secret`, used in the construction of HTLC
`expiration`: timestamp the determines when `seller` and `buyer` can redeem
`now`: current block timestamp

## Specification

### Constructor

The `msg.sender`, transfers funds to the smart contract while deploying

```js
matthewjablack marked this conversation as resolved.
Show resolved Hide resolved
constructor (bytes32 _secretHash, uint256 _expiration, address _buyer) public payable {
matthewjablack marked this conversation as resolved.
Show resolved Hide resolved
```

### Methods

#### claim

The `msg.sender`, transfer funds from the contract to the `buyer`

SHOULD throw if hash of `secret`

SHOULD throw if `now` is greater than `expiration`

Note `secret` can be any bytesize, but that should be specified by the two parties before the HTLC is initiated. The recommended size is 32 bytes

```js
function claim (bytes32 _secret) public {
```

#### refund

The `msg.sender`, transfer funds from the contract to the `seller`

SHOULD throw if `now` less than or equal to `expiration`

```js
function refund () public {
```

## Compatibility
matthewjablack marked this conversation as resolved.
Show resolved Hide resolved

ERC 1630 is compatible with [BIP 199](https://github.com/bitcoin/bips/blob/master/bip-0199.mediawiki) for [atomic swaps](https://en.bitcoin.it/wiki/Atomic_swap) with Bitcoin and other HTLC compatible chains.
matthewjablack marked this conversation as resolved.
Show resolved Hide resolved

## Implementation

This implementation is a simple example of a HTLC using Solidity

```js
matthewjablack marked this conversation as resolved.
Show resolved Hide resolved
matthewjablack marked this conversation as resolved.
Show resolved Hide resolved
contract ETHSwap {
bytes32 secretHash;
uint256 expiration;
address buyer;
address seller;

constructor (bytes32 _secretHash, uint256 _expiration, address _buyer) public payable {
secretHash = _secretHash;
expiration = _expiration;
buyer = _buyer;
seller = msg.sender;
}

function claim (bytes32 _secret) public {
require(sha256(_secret) == secretHash);
require(now <= expiration);
buyer.transfer(address(this).balance);
}

function refund () public {
require(now > expiration);
seller.transfer(address(this).balance);
}
}
```

Note other hash functions can also be used, such as `keccak256`, `ripemd160`. However both parties should specify the hash function to be used before the HTLC is initialized.

Also if the HTLC is being used for the purpose of atomic swaps, both parties should ensure that the hash function specified is available on both chains (i.e. `keccak256` is not available on Bitcoin)

## Optimized Implementation

This is an optimized HTLC with significant gas saving features

[Liquality Atomic Swaps](https://github.com/liquality/chainabstractionlayer/blob/master/src/providers/ethereum/EthereumSwapProvider.js#L8)

```
// Constructor
PUSH1 {dataSize}
DUP1
PUSH1 0b
PUSH1 00
CODECOPY
PUSH1 00
RETURN

// Contract
PUSH1 20

// Get secret
DUP1
PUSH1 00
DUP1
CALLDATACOPY

// SHA256
PUSH1 21
DUP2
PUSH1 00
DUP1
PUSH1 02
PUSH1 48
CALL

// Validate with secretHash
PUSH32 {secretHashEncoded}
PUSH1 21
MLOAD
EQ
AND (to make sure CALL succeeded)
// Redeem if secret is valid
PUSH1 {redeemDestinationEncoded}
JUMPI

// Check time lock
PUSH{expirationSize}
{expirationEncoded}
TIMESTAMP
GT
// Refund if timelock passed
PUSH1 {refundDestinationEncoded}
JUMPI

INVALID

// Redeem self destruct
JUMPDEST
PUSH20 {recipientAddressEncoded}
SELFDESTRUCT

// Refund self destruct
JUMPDEST
PUSH20 {refundAddressEncoded}
SELFDESTRUCT
```

***
matthewjablack marked this conversation as resolved.
Show resolved Hide resolved

### Optimized Implementation Definitions

#### dataSize

`112` + expiration size

`112` is the size of the contract in bytes after the constructor

#### secretHash

hash of secret generated by seller

#### redeemDestination

66 + expiration size

66 is the number of bytes between Contract and Redeem self destruct

#### refundDestination

89 + expiration size

89 is the number of bytes between Contract and Refund self destruct

#### expirationSize

bytecode length of expiration

#### expiration

expiration time encoded hex

#### recipientAddress

buyer address

#### refundAddress

seller address

***

### Optimized Implementation Rationale

#### Constructor

deploys the contract, using the datasize which is the bytecode size of the rest of the contract

#### Contract

compute (Keccak-256) hash of contract address

#### Get secret

copy input data of secret in the current environment to memory

#### SHA 256

hashes the secret in memory

#### Validate with SecretHash

checks if secretHash is equal to hash of secret provided

#### Redeem if secret is valid

jump to the redeem self destruct section of the contract

#### Check timelock

check block's timestamp is greater than expiration

#### Refund if timelock passed

jump to the refund self destruct section of the contract

#### Redeem self destruct

pushes buyer address to the stack, which is passed to SELFDESTRUCT which sends funds to the buyer, and destroys the contract

#### Refund self destruct

pushes seller address to the stack, which is passed to SELFDESTRUCT which sends funds to the seller, and destroys the contractal


## Copyright
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).