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 Discussion #1631

Closed
matthewjablack opened this issue Nov 30, 2018 · 7 comments
Closed

ERC 1630 Discussion #1631

matthewjablack opened this issue Nov 30, 2018 · 7 comments
Labels

Comments

@matthewjablack
Copy link

matthewjablack commented Nov 30, 2018


eip: 1630
title: Hashed Time-Locked Contracts
author: Matthew Black matthew.black@consensys.net, TingWei Liu ting.liu@consensys.net, Liquality Team info@liquality.io
status: Draft
discussions-to: #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

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

constructor (bytes32 _secretHash, uint256 _expiration, address _buyer) public payable;

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

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

function refund () public;

Backwards Compatibility

ERC-1630 is compatible with BIP 199 for atomic swaps with Bitcoin and other HTLC compatible chains.

Implementation

This implementation is a simple example of a HTLC using Solidity

pragma solidity ^0.5.10;

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(abi.encodePacked(_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

// Constructor
PUSH1 {contractSize}
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
PUSH ffff // gas units for sha256 execution
CALL

// Validate input size
CALLDATASIZE
PUSH1 20 // (32 bytes)
EQ
AND // (input valid size AND sha256 success)

// Validate with secretHash
PUSH32 {secretHashEncoded}
PUSH1 21
MLOAD
EQ
AND // (input valid size AND sha256 success) AND secret valid
// Redeem if secret is valid
PUSH1 {redeemDestination}
JUMPI

// Validate input size
CALLDATASIZE
ISZERO // (input empty)
// Check time lock
PUSH5 {expirationEncoded}
TIMESTAMP
GT
AND // (input size 0 AND time lock expired)
// Refund if timelock passed
PUSH1 {refundDestination}

INVALID

JUMPDEST
// emit Claim(bytes32 _secret)
PUSH32 8c1d64e3bd87387709175b9ef4e7a1d7a8364559fc0e2ad9d77953909a0d1eb3 // topic Keccak-256(Claim(bytes32))
PUSH1 20 // (log length - 32)
PUSH1 00 // (log offset - 0)
LOG 1
PUSH20 {recipientAddressEncoded}
SELF-DESTRUCT

JUMPDEST
// emit Refund()
PUSH32 5d26862916391bf49478b2f5103b0720a842b45ef145a268f2cd1fb2aed55178 // topic Keccak-256(Refund())
PUSH1 00 // (log length - 0)
DUP 1 // (log offset)
LOG 1
PUSH20 {refundAddressEncoded}
SELF-DESTRUCT

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.

@matthewjablack matthewjablack changed the title EIP 1630 Discussion ERC 1630 Discussion Nov 30, 2018
@monokh
Copy link

monokh commented Feb 19, 2019

I have a suggestion for the optimised version of the contract.

Replace the STOP opcode with INVALID

Reasoning: In the case of the solidity implementation, a failed call to claim or expired will cause the transaction to fail. This is useful as it gives a very clean indication (via the status of the transaction) if a claim or refund has been successful. Using the bytecode implementation, the following scenarios still result in a successful transaction which make it difficult to derive easily whether the transaction was valid or not:

  • Non matching secret
  • Refund before expiration

@matthewjablack
Copy link
Author

Great suggestion @monokh. Added the necessary changes to ERC 1630.

Also fixed an implementation typo, where function claim (bytes32 _secretHash) public should've been function claim (bytes32 _secret) public as well as bytecode 57 which should be JUMPI

@monokh
Copy link

monokh commented Jan 11, 2021

We made another amendment to the bytecode contract that fixes the expiration size and as a result also the size of the contract in total. This makes it less error prone and easier to parse.

See: https://github.com/liquality/chainabstractionlayer/blob/dev/packages/ethereum-swap-provider/lib/EthereumSwapProvider.js#L45

@github-actions
Copy link

There has been no activity on this issue for two months. It will be closed in a week if no further activity occurs. If you would like to move this EIP forward, please respond to any outstanding feedback or add a comment indicating that you have addressed all required feedback and are ready for a review.

@github-actions github-actions bot added the stale label Nov 21, 2021
@matthewjablack
Copy link
Author

We made another amendment to the bytecode contract that fixes the expiration size and as a result also the size of the contract in total. This makes it less error prone and easier to parse.

Updated bytecode contract with fixed expiration size

https://github.com/liquality/chainabstractionlayer/blob/dev/packages/ethereum-swap-provider/lib/EthereumSwapProvider.ts#L27

@github-actions github-actions bot removed the stale label Nov 21, 2021
@github-actions
Copy link

There has been no activity on this issue for two months. It will be closed in a week if no further activity occurs. If you would like to move this EIP forward, please respond to any outstanding feedback or add a comment indicating that you have addressed all required feedback and are ready for a review.

@github-actions
Copy link

github-actions bot commented Jun 3, 2022

This issue was closed due to inactivity. If you are still pursuing it, feel free to reopen it and respond to any feedback or request a review in a comment.

@github-actions github-actions bot closed this as completed Jun 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants