diff --git a/EIPS/eip-1850.md b/EIPS/eip-1850.md new file mode 100644 index 00000000000000..7cb4fa93c69c07 --- /dev/null +++ b/EIPS/eip-1850.md @@ -0,0 +1,389 @@ +--- +eip: 1850 +title: Hashed Time-Locked Principal Contract transactions +author: Matthew Black , Tony Cai , Atomic Loans team +status: Draft +discussions-to: https://github.com/ethereum/EIPs/issues/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’s`locking 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. + +```js +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 + +```js +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. + +```js +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 + +```js +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 + +```js +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` + +```js +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 + +```js +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 + +```js +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` + +```js +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` + +```js +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 + +```js +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 + +```js +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 + +```js +function refundBid () public { +``` + +## Compatibility + +ERC 1850 is compatible with [BIP 197](https://github.com/bitcoin/bips/blob/master/bip-0197.mediawiki) 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 + +```js +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 +1. Atomic Cross-Chain Swaps. https://arxiv.org/pdf/1801.09515.pdf +1. 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 +1. ERC-1630 Hashed Time-Locked Contract Standard (HTLC). https://github.com/ethereum/EIPs/pull/1630 +1. 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](https://creativecommons.org/publicdomain/zero/1.0/).