Skip to content

Instantly share code, notes, and snippets.

@ohadnav
Created June 1, 2018 15:47
Show Gist options
  • Save ohadnav/999415027498ad619547d319c34965e9 to your computer and use it in GitHub Desktop.
Save ohadnav/999415027498ad619547d319c34965e9 to your computer and use it in GitHub Desktop.
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