Created
June 1, 2018 15:47
-
-
Save ohadnav/999415027498ad619547d319c34965e9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.20; | |
import { ERC20Token } from "./ERC20Token.sol"; | |
contract Exchange { | |
enum Status{ | |
readyToBorrow, | |
readyToLend, | |
fulfilledByBorrower, | |
fulfilledByLender, | |
executed, | |
marginCall, | |
collateralAdded, | |
liquidated | |
} | |
struct Loan { | |
uint id; | |
address borrower; | |
address lender; | |
address collateral_token; | |
address loan_token; | |
uint collateral_amount; | |
uint loan_amount; | |
bool hasValue; | |
Status status; | |
uint lastMarginCall; | |
uint sinceLastMarginCall; | |
} | |
/* This creates an array with all balances */ | |
address public owner; | |
mapping (uint => Loan) public loans; | |
uint loanNum; | |
event MarginCall(uint id, uint fromRate, uint toRate); | |
event LiquidateNotice(uint id, uint fromRate, uint toRate, uint lastMarginCall); | |
/* Initializes contract with initial supply tokens to the creator of the contract */ | |
constructor() public { | |
owner = msg.sender; | |
} | |
function getLoanInfo(uint loan_id) public view returns (uint, address, address, address, address, uint, uint, bool, Status, uint, uint){ | |
Loan memory loan = loans[loan_id]; | |
return ( | |
loan.id, | |
loan.borrower, | |
loan.lender, | |
loan.collateral_token, | |
loan.loan_token, | |
loan.collateral_amount, | |
loan.loan_amount, | |
loan.hasValue, | |
loan.status, | |
loan.lastMarginCall, | |
loan.sinceLastMarginCall | |
); | |
} | |
function getLoanCount() public view returns (uint){ | |
return loanNum; | |
} | |
function createLoan(address col_token, uint col_amount, address loan_token, uint loan_amount) internal returns (uint loan_Num){ | |
loanNum ++; | |
loans[loanNum].id = loanNum; | |
loans[loanNum].borrower = msg.sender; | |
loans[loanNum].collateral_token = col_token; | |
loans[loanNum].collateral_amount = col_amount; | |
loans[loanNum].loan_token = loan_token; | |
loans[loanNum].loan_amount = loan_amount; | |
loans[loanNum].hasValue = true; | |
return loanNum; | |
} | |
function createByBorrower(address col_token, uint col_amount, address loan_token, uint loan_amount) public{ | |
require(col_token != address(0) && col_amount > 0 && loan_token != address(0) && loan_amount > 0); | |
uint loanNumber = createLoan(col_token, col_amount, loan_token, loan_amount); | |
ERC20Token(col_token).transferFrom(msg.sender, this, col_amount); | |
loans[loanNumber].status = Status.readyToBorrow; | |
} | |
function fulfillByBorrower(uint loanId) public{ | |
require(loanId > 0); | |
Loan storage loan = loans[loanId]; | |
require(loan.hasValue); | |
ERC20Token(loan.collateral_token).transferFrom(msg.sender, this, loan.collateral_amount); | |
ERC20Token(loan.loan_token).transferFrom(loan.lender, loan.borrower, loan.loan_amount); | |
loans[loanId].status = Status.fulfilledByBorrower; | |
} | |
function createByLender(address col_token, uint col_amount, address loan_token, uint loan_amount) public{ | |
require(col_token != address(0) && col_amount > 0 && loan_token != address(0) && loan_amount > 0); | |
uint loanNumber = createLoan(col_token, col_amount, loan_token, loan_amount); | |
// ERC20Token(loan_token).transferFrom(msg.sender, this, loan_amount); | |
loans[loanNumber].status = Status.readyToLend; | |
} | |
function fulfillByLender(uint loanId) public{ | |
require(loanId > 0); | |
Loan storage loan = loans[loanId]; | |
require(loan.hasValue); | |
ERC20Token(loan.loan_token).transferFrom(msg.sender, loan.borrower, loan.loan_amount); | |
loan.lender = msg.sender; | |
loan.status = Status.fulfilledByLender; | |
} | |
/* Send coins */ | |
function addCollateral(uint loanId, uint amount) public { | |
Loan storage loan = loans[loanId]; | |
require(amount > 0); // Check for overflows | |
require(loan.hasValue); | |
ERC20Token(loan.collateral_token).transferFrom(msg.sender, this, amount); | |
loans[loanId].status = Status.collateralAdded; | |
} | |
function setRate(address fromToken, address toToken, uint fromRate, uint toRate, uint date) public { | |
require(msg.sender == owner); | |
require(fromToken != address(0) && toToken != address(0) && fromRate > 0 && toRate > 0); | |
for (uint i = 1; i <= loanNum; i++){ | |
Loan storage loan = loans[i]; | |
if (loan.collateral_token == fromToken && loan.loan_token == toToken){ | |
if (loan.collateral_amount * toRate / fromRate < loan.loan_amount * 2){ | |
loan.sinceLastMarginCall = date - loan.lastMarginCall; | |
if (loan.lastMarginCall > 0 && (date - loan.lastMarginCall) > 3000 ){ | |
emit LiquidateNotice(loan.id, fromRate, toRate, loan.lastMarginCall); | |
uint liquidateAmount = loan.loan_amount * fromRate / toRate; | |
uint fundToLender = liquidateAmount; | |
uint fundToBorrower = loan.collateral_amount - liquidateAmount; | |
if (loan.collateral_amount < liquidateAmount){ | |
fundToLender = loan.collateral_amount; | |
fundToBorrower = 0; | |
} | |
if (fundToLender > 0){ | |
ERC20Token(loan.collateral_token).transfer(loan.lender, fundToLender); | |
} | |
if (fundToBorrower > 0){ | |
ERC20Token(loan.collateral_token).transfer(loan.borrower, fundToBorrower); | |
} | |
loan.status = Status.liquidated; | |
} | |
else{ | |
emit MarginCall(loan.id, fromRate, toRate); | |
loan.status = Status.marginCall; | |
loan.lastMarginCall = date; | |
} | |
} | |
} | |
} | |
} | |
function transferFrom(address token, address from, address to, uint amount) public returns (bool){ | |
require(msg.sender == owner); | |
ERC20Token(token).transferFrom(from, to, amount); | |
return true; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment