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 1850 - Hashed Time-Locked Principal Contract Standard #1850

Closed
wants to merge 9 commits into from

Conversation

matthewjablack
Copy link

@matthewjablack matthewjablack commented Mar 19, 2019


eip: 1850
title: Hashed Time-Locked Principal Contract transactions
author: Matthew Black [email protected], Tony Cai [email protected], Atomic Loans team [email protected]
status: Draft
discussions-to: #1851
type: Standards Track
category: ERC
created: 2019-03-19

Simple Summary

This EIP describes a script for a generalized debt agreement contract based on Hashed Time-Lock Contract (ERC 1630) transactions according to the Atomic Loans specification (https://arxiv.org/pdf/1901.05117.pdf).

Abstract

A Hashed Time-Locked Principal Contract (HTLPC) is a script that permits a designated party (the "lender") to provide ERC20 denominated funds for a debt agreement for a specified amount of time, with collateral locked on another blockchain (denoted as the collateral blockchain for the purposes of this EIP). It also permits a second party (the "borrower") to withdraw the lent funds once their request to borrow has been approved by the lender, repay the loan after the loan period has passed and in the case of default, liquidate the collateral.

Motivation

HTLPC transactions are a safe method for exchanging multiple secrets for the purposes of executing a cross-chain debt agreement, due to the ability to recover a percentage of funds from an uncooperative counterparty.

HLTPC's enable cross-chain atomic loans

Definitions

msg.sender: is always the address where the current function call came from

borrower: entity that locks collateral on another blockchain and receives loan amount from lender following the approval of the borrower’s borrow request

lender: entity that contributes funds to the HTLPC, to be borrowed by the borrower upon the locking of collateral on the collateral chain and the lender’s approval

bidder: entity that bids on the collateral to enable liquidation of the collateral

repay: when the borrower pays back the principal + interest before loanExpiration

default: when the borrower fails to pay back the principal + interest before the loanExpiration

secret: random number chosen by the borrower or lender, revealed to allow the parties to change the state of the debt agreement

secretHash: hash of the secret, used in the construction of HTLPC

now: current block timestamp

principal: the amount borrowed within the loan, upon which interest is calculated

interest: a percentage amount of the loan principal paid by the borrower to the lender, in addition to the repayment of principal

approved: bool state where if true, the request to borrow, as well as the collateral from the borrower has been accepted by the lender

bidding: bool state where if true, third party bidders are able to bid on the collateral in order to liquidate it

currentBid: highest bid on the collateral so far

liquidatedCollateralWidthdrawn: bool state where the borrower and lender have withdrawn their share of the liquidated collateral

SecretA1: secret generated by the borrower, used to prove that the borrower has withdrawn the loan

SecretA2: secret generated by the borrower, used to allow the bidder to withdraw the liquidated collateral funds

SecretB1: secret generated by the lender, used to accept the locking of collateral by borrower, enabling borrower to withdraw the loan amount

SecretB2: secret generated by the lender, used to refund themselves in the event they aren't satisfied with borrower’slocking of collateral. Also used to accept borrower’s repayment of principal plus interest

SecretB3: secret generated by the lender, used to allow the bidder to withdraw the liquidated collateral funds

SecretC: secret generated by the bidder, used to accept the signatures of the borrower and lender for authorizing the liquidation of collateral

ApproveExpiration: timestamp after which the lender can no longer approve the loan by accepting requests to borrow from the borrower

LoanExpiration: timestamp before which the borrower must repay the loan; or otherwise risk the liquidation or seizure of their collateral

AcceptExpiration: timestamp before which the lender must accept the repayment of the loan

BiddingExpiration: timestamp that determines the amount of time allocated to bidding before seizure period occurs

Approve Period:
During this time, the lender deploys the HTLPC. Following this, the borrower locks their collateral on the collateral blockchain in a Hashed Time-Locked Collateral Contract (HTLCC) (Bitcoin version specified here: https://github.com/bitcoin/bips/blob/master/bip-0197.mediawiki). The lender then either reveals secretB1 to signify that they are satisfied with the collateral, and the borrower can withdraw the loan by revealing secretA1. If the lender is not satisfied with the collateral locked by the borrower, the lender can refunds their loan amount by revealing secretB2, which will subsequently allow the borrower to refund the collateral amount they deposited.

Loan Period:
Once the borrower has withdrawn the loan amount, the Loan Period begins. Once the Loan Period is finished, the borrower is expected to repay the loan. If they do, the lender can then accept the repayment by revealing secretB2, enabling the borrower to refund their collateral amount. In the case that the borrower defaults or does not repay the full principal plus interest amount, the lender can choose to not accept the loan repayment, and the parties can opt for liquidation of the collateral in the Bidding Period.

Bidding Period:
In the case of a default or the lender not accepting the borrower repayment, the lender and borrower can opt for liquidation of the collateral through the process of third party bidders bidding on the collateral. The Bidding Period can be initiated by either the lender or the borrower. Once the bidding timeout occurs, the lender and borrower must each provide a signature, followed by secretC revealed by the winning bidder once they have checked that the signature is proper. Finally, the lender and borrower must each reveal secretA2 and secretB3 to allow the collateral to be withdrawn by the winning bidder.

Seizure Period:
In the case that either the lender or borrower don’t accept the bid, the lender can seize a percentage of the collateral. The amount is dependent on the amount of collateral locked in the Seizable Collateral script and Refundable Collateral script as described in the BIP (https://github.com/bitcoin/bips/blob/master/bip-0197.mediawiki). During this period the borrower can also refund the funds locked in the Refundable Collateral script.

Refund Period:
In the case of a default where the lender does not seize the collateral locked in the Seizable Collateral script, then the borrower can refund the funds locked in the Seizable Collateral script described in the BIP (https://github.com/bitcoin/bips/blob/master/bip-0197.mediawiki).

Specification

Constructor

The msg.sender transfers funds to the smart contract during its deployment.

constructor (
        bytes32 _secretHashA1,
        bytes32 _secretHashA2,
        bytes32 _secretHashB1,
        bytes32 _secretHashB2,
        bytes32 _secretHashB3,
        uint256 _approveExpiration,
        uint256 _loanExpiration,
        uint256 _acceptExpiration,
        uint256 _biddingExpiration,
        address _borrower,
        uint256 _principal,
        uint256 _interest,
        uint256 _liquidationFee,
        uint256 _biddingTimeout,
        uint256 _biddingRefund,
        address _tokenAddress
    ) public {
        secretHashA1 = _secretHashA1;
        secretHashA2 = _secretHashA2;
        secretHashB1 = _secretHashB1;
        secretHashB2 = _secretHashB2;
        secretHashB3 = _secretHashB3;
        approveExpiration = _approveExpiration;
        loanExpiration = _loanExpiration;
        acceptExpiration = _acceptExpiration;
        biddingExpiration = _biddingExpiration;
        borrower = _borrower;
        lender = msg.sender;
        principal = _principal;
        interest = _interest;
        liquidationFee = _liquidationFee;
        biddingTimeout = _biddingTimeout;
        biddingRefund = _biddingRefund;
        token = StandardToken(_tokenAddress);
    }

Methods

fund

The msg.sender or lender transfers tokens for the loan amount to the contract

SHOULD throw if funded is true

function fund () public {

approve

The msg.sender or lender approves the locking of collateral done by the Borrower on the collateral blockchain.

SHOULD throw if msg.sender does not equal lender address

SHOULD throw if hash of _secretB1 does not equal secretHashB1

SHOULD throw if now is greater than approveExpiration

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 approve (bytes32 _secretB1) public {

withdraw

The msg.sender or borrower withdraws the loan amount

SHOULD throw if hash of _secretA1 does not equal secretHashA1

SHOULD throw if hash of _secretB1 does not equal secretHashB1

SHOULD throw if approved does not equal true

function withdraw (bytes32 _secretA1, bytes32 _secretB1) public {

acceptOrCancel

The msg.sender or lender accepts the borrower repayment of the principal plus interest

SHOULD throw if hash of _secretB2 does not equal secretHashB2

SHOULD throw if now is less than or equal to withdrawExpiration

SHOULD throw if now is greater than acceptExpiration

SHOULD throw if bidding is true

function acceptOrCancel (bytes32 _secretB2) public {

payback

The msg.sender or borrower repays the loan amount

SHOULD throw if msg.value does not equal principal plus interest

Note that in this version, it is expected that the borrower make just one repayment, which covers the entirety of principal plus interest

function payback () public payable returns (bool success) {

refundPayback

The msg.sender or borrower refunds the repayment amount they put forth in the event their repayment is not accepted by the lender

SHOULD throw if now less than or equal to acceptExpiration

SHOULD throw if repaid is false

SHOULD throw if msg.sender is not the borrower

function refundPayback () public {

startBidding

The msg.sender (either the lender or borrower) initiates the bidding process

SHOULD throw if repaid is true

SHOULD throw if withdrawn is false

SHOULD throw if now is less than or equal to loanExpiration

SHOULD throw if msg.sender is neither a borrower address nor a lender address

function startBidding () public {

bid

The msg.sender (anyone who is interested in bidding on the collateral) bids on the collateral

SHOULD throw if bidding is not true

SHOULD throw if now is less than or equal to loanExpiration

SHOULD throw if now is greater than biddingTimeoutExpiration

SHOULD throw if _bidValue is less than or equal to currentBid

SHOULD throw if token balance of msg.sender is less than _bidValue

function bid (bytes32 _secretHashC, uint256 bidValue) public {

provideSignature

The msg.sender provides a signature for the collateral blockchain enabling the bidder to spend the collateral in the liquidation process

SHOULD throw if now is less than or equal to loanExpiration

function provideSignature (string _signature) public {

provideSecret

The msg.sender provides a secret to enable the bidder to spend the collateral in the liquidation process

SHOULD throw if now is less than or equal to loanExpiration

if msg.sender is the borrower, then SHOULD throw if the hash of _secret does not equal secretHashA2

if msg.sender is the lender, then SHOULD throw if the hash of _secret does not equal secretHashB3

if msg.sender is neither the lender or borrower, it SHOULD throw

function provideSecret (bytes32 _secret) public {

withdrawLiquidatedCollateral

The msg.sender (either borrower or lender) withdraws the liquidated collateral

SHOULD throw if now is less than or equal to biddingTimeoutExpiration

if msg.sender is the borrower, then SHOULD throw if borrowerLiquidatedCollateralWithdrawn is true

if msg.sender is the lender, then SHOULD throw if lenderLiquidatedCollateralWithdraw is true

if msg.sender is neither the lender or borrower, it SHOULD throw

function withdrawLiquidatedCollateral (bytes32 _secretA2, bytes32 _secretB2, bytes32 _secretC) public {

refundBid

The msg.sender or bidder refunds their bid in the case that the borrower and lender do not opt into liquidating the collateral

SHOULD throw if repaid is true

SHOULD throw if now less than or equal to biddingRefundExpiration

SHOULD throw if the hash of secretC equals secretHashC and the hash of secretA2 equals secretHashA2 and the hash of secretB2 equals secretHashB2

SHOULD throw if borrowerLiquidatedCollateralWithdrawn is true

SHOULD throw if lenderLiquidatedCollateralWithdrawn is true

SHOULD throw if currentBid is less than or equal to 0

function refundBid () public {

Compatibility

ERC 1850 is compatible with BIP 197 for atomicloans with Bitcoin and other HTLC compatible chains.

Implementation

This implementation is a simple example of a HTLPC using Solidity

https://github.com/AtomicLoans/ethereum-contracts/blob/master/contracts/AtomicLoan.sol

pragma solidity ^0.5.0;

contract AtomicLoan {
    constructor (
        bytes32 _secretHashA1,
        bytes32 _secretHashA2,
        bytes32 _secretHashB1,
        bytes32 _secretHashB2,
        bytes32 _secretHashB3,
        uint256 _approveExpiration,
        uint256 _loanExpiration,
        uint256 _acceptExpiration,
        uint256 _biddingExpiration,
        address _borrower,
        uint256 _principal,
        uint256 _interest,
        uint256 _liquidationFee,
        uint256 _biddingTimeout,
        uint256 _biddingRefund,
        address _tokenAddress
    );
    function fund () public;
    function approve (bytes32 _secretB1) public;
    function withdraw (bytes32 _secretA1, bytes32 _secretB1);
    function accept_or_cancel (bytes32 _secretB2) public;
    function payback () public;
    function refundPayback () public;
    function startBidding () public;
    function bid (bytes32 _secretHashC, uint256 _bidValue, string _aCoinAddress) public;
    function provideSignature (string memory _signature) public;
    function provideSecret (bytes32 _secret) public;
    function withdrawLiquidatedCollateral (bytes32 _secretA2, bytes32 _secretB3, bytes32 _secretC) public;
    function refundBid () public;
}

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 HTLPC is initialized.

References

Papers

  1. Atomic Loans: Cryptocurrency Debt Instruments Paper. https://arxiv.org/pdf/1901.05117.pdf
  2. Atomic Cross-Chain Swaps. https://arxiv.org/pdf/1801.09515.pdf
  3. Atomic Swaptions: Cryptocurrency Derivatives. https://www.ics.uci.edu/~jamesal1/Swaptions.pdf

Standards

  1. ERC-20 Token Standard. https://eips.ethereum.org/EIPS/eip-20
  2. ERC-1630 Hashed Time-Locked Contract Standard (HTLC). ERC 1630 - Hashed Time-Locked Contract Standard #1630
  3. BIP 197 Hashed Time-Locked Collateral Contract Standard (HTLCC) https://github.com/bitcoin/bips/blob/master/bip-0197.mediawiki

Discussions

  1. Jimmy Song Off Chain HTLCC Q&A: https://youtu.be/ezRDcvkiff0?t=162

Copyright

Copyright and related rights waived via CC0.

@matthewjablack matthewjablack changed the title ERC 1850 ERC 1850 - Hashed Time-Locked Atomic Loan Contracts Standard Mar 19, 2019
EIPS/eip-1850.md Show resolved Hide resolved
EIPS/eip-1850.md Outdated Show resolved Hide resolved
EIPS/eip-1850.md Outdated Show resolved Hide resolved
@matthewjablack matthewjablack changed the title ERC 1850 - Hashed Time-Locked Atomic Loan Contracts Standard ERC 1850 - Hashed Time-Locked Principal Contract Standard Apr 2, 2019
@axic axic added the ERC label May 20, 2019
@github-actions
Copy link

There has been no activity on this pull request 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 Sep 15, 2020
@github-actions
Copy link

This pull request 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 Sep 22, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants