From f2af26b79710c1cc6368fb4bcd8012eff14ed10c Mon Sep 17 00:00:00 2001 From: Chris Hobcroft Date: Wed, 22 May 2019 03:26:43 +0100 Subject: [PATCH] Added everything for a buyer to open lptBuyOrder I'm sure I'm missing a require somewhere... --- contracts/LptOrderBook.sol | 95 +++++++++++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-) diff --git a/contracts/LptOrderBook.sol b/contracts/LptOrderBook.sol index 1970495..fc05090 100644 --- a/contracts/LptOrderBook.sol +++ b/contracts/LptOrderBook.sol @@ -12,6 +12,10 @@ contract LptOrderBook { address private constant ZERO_ADDRESS = address(0); + string internal constant ERROR_BUY_ORDER_COMMITTED_TO = "LPT_ORDER_BUY_ORDER_COMMITTED_TO"; + string internal constant ERROR_BUY_ORDER_NOT_COMMITTED_TO = "LPT_ORDER_BUY_ORDER_NOT_COMMITTED_TO"; + string internal constant ERROR_NOT_SELLER = "LPT_ORDER_NOT_SELLER"; + string internal constant ERROR_DELIVERED_BY_IN_PAST = "LPT_ORDER_DELIVERED_BY_IN_PAST"; string internal constant ERROR_SELL_ORDER_COMMITTED_TO = "LPT_ORDER_SELL_ORDER_COMMITTED_TO"; string internal constant ERROR_SELL_ORDER_NOT_COMMITTED_TO = "LPT_ORDER_SELL_ORDER_NOT_COMMITTED_TO"; @@ -21,6 +25,14 @@ contract LptOrderBook { string internal constant ERROR_NOT_BUYER = "LPT_ORDER_NOT_BUYER"; string internal constant ERROR_STILL_WITHIN_LOCK_PERIOD = "LPT_ORDER_STILL_WITHIN_LOCK_PERIOD"; + struct LptBuyOrder { + uint256 lptBuyValue; + uint256 daiPaymentValue; + uint256 daiCollateralValue; + uint256 deliveredByBlock; + address sellerAddress; + } + struct LptSellOrder { uint256 lptSellValue; uint256 daiPaymentValue; @@ -31,6 +43,8 @@ contract LptOrderBook { IController livepeerController; IERC20 daiToken; + + mapping(address => LptBuyOrder) public lptBuyOrders; // One buy order per address for simplicity mapping(address => LptSellOrder) public lptSellOrders; // One sell order per address for simplicity constructor(address _livepeerController, address _daiToken) public { @@ -89,7 +103,7 @@ contract LptOrderBook { * the block number specified. * @param _sellOrderCreator Address of sell order creator */ - function claimCollateralAndPayment(address _sellOrderCreator) public { + function claimSellOrderCollateralAndPayment(address _sellOrderCreator) public { LptSellOrder storage lptSellOrder = lptSellOrders[_sellOrderCreator]; require(lptSellOrder.buyerAddress == msg.sender, ERROR_NOT_BUYER); @@ -117,6 +131,85 @@ contract LptOrderBook { delete lptSellOrders[msg.sender]; } + /* + * @notice Create an LPT buy order, requires approval for this contract to spend _daiPaymentValue amount of DAI. + * @param _lptBuyValue Value of LPT to buy + * @param _daiPaymentValue Value offered in exchange for LPT + * @param _daiCollateralValue Value required of collateral + * @param _deliveredByBlock Order filled or cancelled by this block or the collateral can be claimed + */ + function createLptBuyOrder(uint256 _lptBuyValue, uint256 _daiPaymentValue, uint256 _daiCollateralValue, uint256 _deliveredByBlock) public { + LptBuyOrder storage lptBuyOrder = lptBuyOrders[msg.sender]; + + require(_deliveredByBlock > block.number, ERROR_DELIVERED_BY_IN_PAST); + require(lptBuyOrder.daiPaymentValue == 0, ERROR_INITIALISED_ORDER); + + daiToken.transferFrom(msg.sender, address(this), _daiPaymentValue); + + lptBuyOrders[msg.sender] = LptBuyOrder(_lptBuyValue, _daiPaymentValue, _daiCollateralValue, _deliveredByBlock, ZERO_ADDRESS); + } + + /* + * @notice Cancel an LPT buy order, must be executed by the buy order creator. + */ + function cancelLptBuyOrder() public { + LptBuyOrder storage lptBuyOrder = lptBuyOrders[msg.sender]; + + require(lptBuyOrder.sellerAddress == ZERO_ADDRESS, ERROR_BUY_ORDER_COMMITTED_TO); + + daiToken.transfer(msg.sender, lptBuyOrder.daiPaymentValue); + delete lptBuyOrders[msg.sender]; + } + + /* + * @notice Commit to sell LPT, requires approval for this contract to spend the collateral amount in DAI. + * @param _buyOrderCreator Address of buy order creator + */ + function commitToSellLpt(address _buyOrderCreator) public { + LptBuyOrder storage lptBuyOrder = lptBuyOrders[_buyOrderCreator]; + + require(lptBuyOrder.lptBuyValue > 0, ERROR_UNINITIALISED_ORDER); + require(lptBuyOrder.sellerAddress == ZERO_ADDRESS, ERROR_BUY_ORDER_COMMITTED_TO); + require(lptBuyOrder.deliveredByBlock.sub(_getUnbondingPeriodLength()) > block.number, ERROR_COMMITMENT_WITHIN_UNBONDING_PERIOD); + + daiToken.transferFrom(msg.sender, address(this), lptBuyOrder.daiCollateralValue); + + lptBuyOrder.sellerAddress = msg.sender; + } + + /* + * @notice Claim collateral and payment after a buy order has been committed to but it hasn't been delivered by + * the block number specified. + */ + function claimBuyOrderPaymentAndCollateral() public { + LptBuyOrder storage lptBuyOrder = lptBuyOrders[msg.sender]; + + require(lptBuyOrder.sellerAddress != ZERO_ADDRESS, ERROR_BUY_ORDER_NOT_COMMITTED_TO); + require(lptBuyOrder.deliveredByBlock < block.number, ERROR_STILL_WITHIN_LOCK_PERIOD); + + uint256 totalValue = lptBuyOrder.daiPaymentValue.add(lptBuyOrder.daiCollateralValue); + daiToken.transfer(msg.sender, totalValue); + } + + /* + * @notice Fulfill buy order, requires approval for this contract spend the order's LPT value from the seller. + * Sends the collateral and payment to the LPT seller. + * @param _buyOrderCreator Address of buy order creator + */ + function fulfillBuyOrder(address _buyOrderCreator) public { + LptBuyOrder storage lptBuyOrder = lptBuyOrders[_buyOrderCreator]; + + require(lptBuyOrder.sellerAddress == msg.sender, ERROR_NOT_SELLER); + + IERC20 livepeerToken = IERC20(_getLivepeerContractAddress("LivepeerToken")); + livepeerToken.transferFrom(msg.sender, _buyOrderCreator, lptBuyOrder.lptBuyValue); + + uint256 totalValue = lptBuyOrder.daiPaymentValue.add(lptBuyOrder.daiCollateralValue); + daiToken.transfer(msg.sender, totalValue); + + delete lptBuyOrders[lptBuyOrder.sellerAddress]; + } + function _getLivepeerContractAddress(string memory _livepeerContract) internal view returns (address) { bytes32 contractId = keccak256(abi.encodePacked(_livepeerContract)); return livepeerController.getContract(contractId);