Last active
April 27, 2021 21:05
-
-
Save dumebi/396e61ded8df25146ac23e0f6b5a9ee8 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.6.0; | |
pragma experimental ABIEncoderV2; | |
import "./helpers/Ownable.sol"; | |
import "./libraries/ExchangeStruct.sol"; | |
import "./libraries/ExchangeFunc.sol"; | |
import "@openzeppelin/upgrades/contracts/Initializable.sol"; | |
/** | |
* @title GetEquity Exchange contract | |
* @author Jude Dike | https://github.com/dumebi | |
* @notice Core contract for GetEquity | |
* SPDX-License-Identifier: UNLICENSED | |
*/ | |
contract Exchange is Ownable, Initializable { | |
ExchangeStruct.TokenData tokenData; | |
//////////// | |
// EVENTS // | |
//////////// | |
event DepositForTokenReceived( | |
address indexed _from, | |
uint256 indexed _symbolIndex, | |
uint256 _amount, | |
uint256 _timestamp | |
); | |
event WithdrawalToken( | |
address indexed _to, | |
uint256 indexed _symbolIndex, | |
uint256 _amount, | |
uint256 _timestamp | |
); | |
event DepositForGEUSDReceived( | |
address indexed _from, | |
uint256 _amount, | |
uint256 _timestamp | |
); | |
event WithdrawalGEUSD( | |
address indexed _to, | |
uint256 _amount, | |
uint256 _timestamp | |
); | |
//events for orders | |
event LimitSellOrderCreated( | |
string _symbol, | |
address indexed _who, | |
uint256 _volume, | |
uint256 _price | |
); | |
event SellOrderFulfilled( | |
string _symbol, | |
address indexed _who, | |
uint256 _volume, | |
uint256 _price | |
); | |
event SellOrderCanceled( | |
uint256 indexed _symbolIndex, | |
uint256 _priceInUSD, | |
uint256 _volume, | |
uint256 _orderKey | |
); | |
event LimitBuyOrderCreated( | |
string _symbol, | |
address indexed _who, | |
uint256 _amount, | |
uint256 _price | |
); | |
event BuyOrderFulfilled( | |
string _symbol, | |
address indexed _who, | |
uint256 _amount, | |
uint256 _price | |
); | |
event BuyOrderCanceled( | |
uint256 indexed _symbolIndex, | |
uint256 _priceInUSD, | |
uint256 _volume, | |
uint256 _orderKey | |
); | |
//events for management | |
event TokenAddedToSystem( | |
uint256 _symbolIndex, | |
address _token, | |
uint256 _timestamp | |
); | |
event TokenFound(uint256 _symbolIndex, uint256 number); | |
////////////////////// | |
// TOKEN MANAGEMENT // | |
////////////////////// | |
function initialize() public initializer { | |
Ownable.setOwner(msg.sender); | |
} | |
function createToken( | |
uint256 _id, | |
string memory _symbol, | |
string memory _name, | |
uint256 _supply, | |
uint256 _rate, | |
address _creator | |
) public returns (address) { | |
address token = ExchangeFunc._createToken( | |
tokenData, | |
_id, | |
_symbol, | |
_name, | |
_supply, | |
_rate, | |
_creator | |
); | |
emit TokenAddedToSystem(_id, token, now); | |
} | |
function getToken(uint256 _id) | |
public | |
view | |
returns ( | |
string memory, | |
uint256, | |
uint256, | |
address, | |
uint256 | |
) | |
{ | |
return ExchangeFunc._getToken(tokenData, _id); | |
} | |
function getTokenCount() public view returns (uint256) { | |
return ExchangeFunc._getTokenCount(tokenData); | |
} | |
function getTokenContract(uint256 _id) public view returns (address) { | |
return ExchangeFunc._getTokenContract(tokenData, _id); | |
} | |
function getTokenBalance(uint256 _id, address _user) | |
public | |
view | |
returns (uint256) | |
{ | |
return ExchangeFunc._getTokenBalance(tokenData, _id, _user); | |
} | |
function getTokenEscrow(uint256 _id, address _user) | |
public | |
view | |
returns (uint256) | |
{ | |
return ExchangeFunc._getTokenEscrow(tokenData, _id, _user); | |
} | |
function addTokenEscrow( | |
uint256 _id, | |
uint256 _amount, | |
address _user | |
) public returns (bool) { | |
return ExchangeFunc._addTokenEscrow(tokenData, _id, _amount, _user); | |
} | |
function subTokenEscrow( | |
uint256 _id, | |
uint256 _amount, | |
address _user, | |
address _receiver | |
) public returns (bool) { | |
return | |
ExchangeFunc._subTokenEscrow( | |
tokenData, | |
_id, | |
_amount, | |
_user, | |
_receiver | |
); | |
} | |
function transferToken( | |
uint256 _id, | |
uint256 _amount, | |
address _user, | |
address _receiver | |
) public returns (bool) { | |
return | |
ExchangeFunc._transferToken( | |
tokenData, | |
_id, | |
_amount, | |
_user, | |
_receiver | |
); | |
} | |
function mint( | |
uint256 _id, | |
address _receiver, | |
uint256 _amount | |
) public returns (bool) { | |
return ExchangeFunc._mint(tokenData, _id, _receiver, _amount); | |
} | |
function burn( | |
uint256 _id, | |
address _msgSender, | |
uint256 _amount | |
) public returns (bool) { | |
return ExchangeFunc._burn(tokenData, _id, _msgSender, _amount); | |
} | |
function getContractETHBalance() public view returns (uint256) { | |
return address(this).balance; | |
} | |
function getContractSymbolBalance(uint256 _id) | |
public | |
view | |
returns (uint256) | |
{ | |
return getTokenBalance(_id, address(this)); | |
} | |
receive() external payable { | |
// nothing else to do! | |
} | |
function getCoinbase() public view returns (address) { | |
return owner(); | |
} | |
///////////////////////// | |
// WITHDRAW // | |
///////////////////////// | |
function withdrawSymbolFunds(uint256 _id) | |
external | |
onlyOwner | |
returns (bool) | |
{ | |
uint256 funds = getTokenBalance(_id, address(this)); | |
transferToken(_id, funds, address(this), msg.sender); | |
return true; | |
} | |
function withdrawEthFunds() external onlyOwner returns (bool) { | |
uint256 bal = address(this).balance; | |
payable(owner()).transfer(bal); | |
return true; | |
} | |
// function() external payable {} | |
} |
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.6.0; | |
pragma experimental ABIEncoderV2; | |
import "../Token.sol"; | |
import "./ExchangeStruct.sol"; | |
/** | |
* @title GetEquity Exchange controller contract | |
* @author Jude Dike | https://github.com/dumebi | |
* @notice Core controller contract for GetEquity | |
* SPDX-License-Identifier: UNLICENSED | |
*/ | |
library ExchangeFunc { | |
using SafeMath for uint256; | |
uint256 public constant decimals = 18; | |
//////////// | |
// EVENTS // | |
//////////// | |
//EVENTS for Deposit/withdrawal | |
event DepositToken( | |
address indexed _from, | |
string _symbol, | |
uint256 _amount, | |
uint256 _timestamp | |
); | |
event WithdawToken( | |
address indexed _to, | |
string _symbol, | |
uint256 _amount, | |
uint256 _timestamp | |
); | |
//events for orders | |
event LimitSellOrderCreated( | |
string _symbol, | |
address indexed _who, | |
uint256 _amount, | |
uint256 _price | |
); | |
event SellOrderFulfilled( | |
string _symbol, | |
address indexed _who, | |
uint256 _amount, | |
uint256 _price | |
); | |
event LimitBuyOrderCreated( | |
string _symbol, | |
address indexed _who, | |
uint256 _amount, | |
uint256 _price | |
); | |
event BuyOrderFulfilled( | |
string _symbol, | |
address indexed _who, | |
uint256 _amount, | |
uint256 _price | |
); | |
event TokenCreated( | |
uint256 _tokenIndex, | |
string _symbol, | |
address indexed _creator, | |
uint256 _timestamp | |
); | |
///////////////////// | |
// TOKEN FUNCTIONS // | |
///////////////////// | |
/** | |
* @dev Function to create a token | |
* @param _self TokenData Struct | |
* @param _id the token identifier | |
* @param _symbol The token symbol. | |
* @param _name the token name | |
* @param _supply the total supply of tokens | |
* @param _rate the exchange rate of tokens (to GEUSD) | |
* @return bool | |
*/ | |
function _createToken( | |
ExchangeStruct.TokenData storage _self, | |
uint256 _id, | |
string memory _symbol, | |
string memory _name, | |
uint256 _supply, | |
uint256 _rate, | |
address _creator | |
) internal returns (address) { | |
require(_self.tokens[_id].index != _id, "Token already exists"); | |
require( | |
!_stringsEqual(_self.tokens[_id].symbol, _symbol), | |
"Token already exists" | |
); | |
Token newToken = new Token(_symbol, _name, _supply, _rate, _creator); | |
address tokenContract = address(newToken); | |
_self.tokenIndex++; | |
_self.tokens[_id].index = _id; | |
_self.tokens[_id].tokenIndex = _self.tokenIndex; | |
_self.tokens[_id].tokenContract = tokenContract; | |
_self.tokens[_id].symbol = _symbol; | |
// emit TokenCreated(_self.tokenIndex, _symbol, _creator, now); | |
return tokenContract; | |
} | |
/** | |
* @dev Function to return token details | |
* @param _self TokenData Struct | |
* @param _id The token symbol ID. | |
*/ | |
function _getToken(ExchangeStruct.TokenData storage _self, uint256 _id) | |
internal | |
view | |
returns ( | |
string memory, | |
uint256, | |
uint256, | |
address, | |
uint256 | |
) | |
{ | |
address tokenAddress = _self.tokens[_id].tokenContract; | |
ERC20Interface ERCToken = ERC20Interface(tokenAddress); | |
return ERCToken.details(); | |
} | |
/** | |
* @dev Function to return token details | |
* @param _self TokenData Struct | |
* @param _id The token symbol ID. | |
*/ | |
function _getTokenContract( | |
ExchangeStruct.TokenData storage _self, | |
uint256 _id | |
) internal view returns (address) { | |
address tokenAddress = _self.tokens[_id].tokenContract; | |
return tokenAddress; | |
} | |
/** | |
* @dev Function to return number of tokens in this contract | |
* @param _self TokenData Struct | |
* @return the number of tokens in this contract. | |
*/ | |
function _getTokenCount(ExchangeStruct.TokenData storage _self) | |
internal | |
view | |
returns (uint256) | |
{ | |
return _self.tokenIndex; | |
} | |
/** | |
* @dev Function to return balance of a user of a particular token | |
* @param _self TokenData Struct | |
* @param _id The token symbol ID | |
* @param _user User's address | |
* @return the user's token balance. | |
*/ | |
function _getTokenBalance( | |
ExchangeStruct.TokenData storage _self, | |
uint256 _id, | |
address _user | |
) internal view returns (uint256) { | |
address tokenAddress = _self.tokens[_id].tokenContract; | |
ERC20Interface ERC20Token = ERC20Interface(tokenAddress); | |
return ERC20Token.balanceOf(_user); | |
} | |
/** | |
* @dev Function to return balance of a user of a particular token | |
* @param _self TokenData Struct | |
* @param _id The token symbol ID | |
* @param _user User's address | |
* @return the user's token escrow. | |
*/ | |
function _getTokenEscrow( | |
ExchangeStruct.TokenData storage _self, | |
uint256 _id, | |
address _user | |
) internal view returns (uint256) { | |
address tokenAddress = _self.tokens[_id].tokenContract; | |
ERC20Interface ERC20Token = ERC20Interface(tokenAddress); | |
return ERC20Token.escrowOf(_user); | |
} | |
/** | |
* @dev Function to credit token of a particular user | |
* @param _self TokenData Struct | |
* @param _id The token symbol ID | |
* @param _amount The amount of tokens to be credited | |
* @param _user User's address | |
* @return A boolean to indicate if token escrow was credited. | |
*/ | |
function _addTokenEscrow( | |
ExchangeStruct.TokenData storage _self, | |
uint256 _id, | |
uint256 _amount, | |
address _user | |
) internal returns (bool) { | |
address tokenAddress = _self.tokens[_id].tokenContract; | |
ERC20Interface ERCToken = ERC20Interface(tokenAddress); | |
return ERCToken.addEscrow(_user, _amount); | |
} | |
/** | |
* @dev Function to debit token of a particular user | |
* @param _self TokenData Struct | |
* @param _id The token symbol | |
* @param _amount The amount of tokens to be credited | |
* @param _user User's address | |
* @param _receiver Receiver's address | |
* @return A boolean to indicate if token escrow was transferred. | |
*/ | |
function _subTokenEscrow( | |
ExchangeStruct.TokenData storage _self, | |
uint256 _id, | |
uint256 _amount, | |
address _user, | |
address _receiver | |
) internal returns (bool) { | |
address tokenAddress = _self.tokens[_id].tokenContract; | |
ERC20Interface ERCToken = ERC20Interface(tokenAddress); | |
return ERCToken.subEscrow(_user, _receiver, _amount); | |
} | |
/** | |
* @dev Function to debit token of a particular user | |
* @param _self TokenData Struct | |
* @param _id The token ID | |
* @param _amount The amount of tokens to be credited | |
* @param _user User's address | |
* @param _receiver Receiver's address | |
* @return A boolean to indicate if token was transferred. | |
*/ | |
function _transferToken( | |
ExchangeStruct.TokenData storage _self, | |
uint256 _id, | |
uint256 _amount, | |
address _user, | |
address _receiver | |
) internal returns (bool) { | |
address tokenAddress = _self.tokens[_id].tokenContract; | |
ERC20Interface ERCToken = ERC20Interface(tokenAddress); | |
return ERCToken.transfer(_user, _receiver, _amount); | |
} | |
/** | |
* @dev Function to mint tokens to a user address | |
* @param _self TokenData Struct | |
* @param _id The token ID | |
* @param _receiver Receiver's address | |
* @param _amount The amount of tokens to be credited | |
* @return A boolean to indicate if token was minted to the receiver successfully. | |
*/ | |
function _mint( | |
ExchangeStruct.TokenData storage _self, | |
uint256 _id, | |
address _receiver, | |
uint256 _amount | |
) internal returns (bool) { | |
address tokenAddress = _self.tokens[_id].tokenContract; | |
ERC20Interface ERCToken = ERC20Interface(tokenAddress); | |
return ERCToken.mint(_receiver, _amount); | |
} | |
/** | |
* @dev Function to burn tokens of a user | |
* @param _self TokenData Struct | |
* @param _id The token ID | |
* @param _msgSender the person sending this request | |
* @param _amount The amount of tokens to be credited | |
* @return A boolean to indicate if token was minted to the receiver successfully. | |
*/ | |
function _burn( | |
ExchangeStruct.TokenData storage _self, | |
uint256 _id, | |
address _msgSender, | |
uint256 _amount | |
) internal returns (bool) { | |
address tokenAddress = _self.tokens[_id].tokenContract; | |
ERC20Interface ERCToken = ERC20Interface(tokenAddress); | |
return ERCToken.burn(_msgSender, _amount); | |
} | |
// ///////////////////////// | |
// // EXCHANGE FUNCTIONS // | |
// //////////////////////// | |
// /** | |
// * @dev Function to get all buy orders (Bids) | |
// * @param _self TokenData Struct | |
// * @param _symbol The token symbol | |
// * @return 2 Arrays of prices and volumes. | |
// */ | |
// function _getBuyOrderBook( | |
// ExchangeStruct.TokenData storage _self, | |
// string memory _symbol | |
// ) internal view returns (ExchangeStruct.OrderBookDetails[] memory) { | |
// uint256 tokenNameIndex = _getSymbolIndexOrThrow(_self, _symbol); | |
// ExchangeStruct.OrderBookDetails[] memory buybook | |
// = new ExchangeStruct.OrderBookDetails[](100); | |
// uint256 currentPrice = _self.tokens[tokenNameIndex].lowestBuyPrice; | |
// uint256 counter = 0; | |
// if (_self.tokens[tokenNameIndex].curBuyPrice > 0) { | |
// while (currentPrice <= _self.tokens[tokenNameIndex].curBuyPrice) { | |
// uint256 offers_key = 0; | |
// offers_key = _self.tokens[tokenNameIndex].buyBook[currentPrice] | |
// .offers_key; | |
// while ( | |
// offers_key <= | |
// _self.tokens[tokenNameIndex].buyBook[currentPrice] | |
// .offers_length | |
// ) { | |
// buybook[counter] = ExchangeStruct.OrderBookDetails( | |
// currentPrice, | |
// _self.tokens[tokenNameIndex].buyBook[currentPrice] | |
// .offers[offers_key] | |
// .amount, | |
// offers_key, | |
// _self.tokens[tokenNameIndex].buyBook[currentPrice] | |
// .offers[offers_key] | |
// .who | |
// ); | |
// // volumeAtPrice = volumeAtPrice.add(_self.tokens[tokenNameIndex].buyBook[currentPrice].offers[offers_key].amount); | |
// offers_key++; | |
// counter++; | |
// } | |
// // buyVolumesArray[counter] = volumeAtPrice; | |
// //next currentPrice | |
// if ( | |
// currentPrice == | |
// _self.tokens[tokenNameIndex].buyBook[currentPrice] | |
// .higherPrice | |
// ) { | |
// break; | |
// } else { | |
// currentPrice = _self.tokens[tokenNameIndex] | |
// .buyBook[currentPrice] | |
// .higherPrice; | |
// } | |
// counter++; | |
// } | |
// } | |
// return buybook; | |
// } | |
// /** | |
// * @dev Function to get all buy orders (Bids) | |
// * @param _self TokenData Struct | |
// * @param _symbol The token symbol | |
// * @return 2 Arrays of prices and volumes. | |
// */ | |
// function _getBuyPrice( | |
// ExchangeStruct.TokenData storage _self, | |
// string memory _symbol | |
// ) internal view returns (uint256) { | |
// uint256 tokenNameIndex = _getSymbolIndexOrThrow(_self, _symbol); | |
// uint256 currentPrice = _self.tokens[tokenNameIndex].lowestBuyPrice; | |
// return currentPrice; | |
// } | |
// /** | |
// * @dev Function to get current sell price (Ask) | |
// * @param _self TokenData Struct | |
// * @param _symbol The token symbol | |
// * @return uint sell price | |
// */ | |
// function _getSellPrice( | |
// ExchangeStruct.TokenData storage _self, | |
// string memory _symbol | |
// ) internal view returns (uint256) { | |
// uint256 tokenNameIndex = _getSymbolIndexOrThrow(_self, _symbol); | |
// uint256 currSellPrice = _self.tokens[tokenNameIndex].curSellPrice; | |
// return currSellPrice; | |
// } | |
// /** | |
// * @dev Function to get all sell orders (Asks) | |
// * @param _self TokenData Struct | |
// * @param _symbol The token symbol | |
// * @return An array of struct containing each offer(price, amount_sold, offer_key/id, seller) | |
// */ | |
// function _getSellOrderBook( | |
// ExchangeStruct.TokenData storage _self, | |
// string memory _symbol | |
// ) internal view returns (ExchangeStruct.OrderBookDetails[] memory) { | |
// uint256 tokenNameIndex = _getSymbolIndexOrThrow(_self, _symbol); | |
// uint256 currSellPrice = _self.tokens[tokenNameIndex].curSellPrice; | |
// ExchangeStruct.OrderBookDetails[] memory sellOrderBooks | |
// = new ExchangeStruct.OrderBookDetails[](100); | |
// uint256 counter = 0; | |
// if (_self.tokens[tokenNameIndex].curSellPrice > 0) { | |
// while ( | |
// currSellPrice <= _self.tokens[tokenNameIndex].highestSellPrice | |
// ) { | |
// uint256 total_sell_offers_at_this_price = _self | |
// .tokens[tokenNameIndex] | |
// .sellBook[currSellPrice] | |
// .offers_length; | |
// uint256 key_for_offers_left = _self.tokens[tokenNameIndex] | |
// .sellBook[currSellPrice] | |
// .offers_key; | |
// // We want to get the offers for each price of a token | |
// while (key_for_offers_left <= total_sell_offers_at_this_price) { | |
// // I would need an array of structs | |
// // Each struct would contain the price, volume, key, seller | |
// sellOrderBooks[counter] = ExchangeStruct.OrderBookDetails( | |
// currSellPrice, | |
// _self.tokens[tokenNameIndex].sellBook[currSellPrice] | |
// .offers[key_for_offers_left] | |
// .amount, | |
// key_for_offers_left, | |
// _self.tokens[tokenNameIndex].sellBook[currSellPrice] | |
// .offers[key_for_offers_left] | |
// .who | |
// ); | |
// key_for_offers_left++; | |
// counter++; | |
// } | |
// //next curSellPrice | |
// if ( | |
// _self.tokens[tokenNameIndex].sellBook[currSellPrice] | |
// .higherPrice == 0 | |
// ) { | |
// break; | |
// } else { | |
// currSellPrice = _self.tokens[tokenNameIndex] | |
// .sellBook[currSellPrice] | |
// .higherPrice; | |
// } | |
// counter++; | |
// } | |
// } | |
// //final sell book | |
// return sellOrderBooks; | |
// } | |
// /** | |
// * @dev Function to buy a token (or add to buy orders) | |
// * @param _self TokenData Struct | |
// * @param _symbol The token symbol | |
// * @param _priceInUSD The token price (in GEUSD) | |
// * @param amount The amount of tokens to buy | |
// * @return A boolean to indicate if the transaction was successful. | |
// */ | |
// function _buyToken( | |
// ExchangeStruct.TokenData storage _self, | |
// string memory _symbol, | |
// uint256 _priceInUSD, | |
// uint256 amount, | |
// address _buyer | |
// ) public returns (uint256) { | |
// uint256 tokenNameIndex = _getSymbolIndexOrThrow(_self, _symbol); | |
// // Total amount of ba tokens to buy: price * amount | |
// uint256 total_cost_price_in_ba = 0; | |
// //if there are no sell offers currently or if the current price of the token is higher than what the user offered | |
// if ( | |
// _self.tokens[tokenNameIndex].amountSellPrices == 0 || | |
// _self.tokens[tokenNameIndex].curSellPrice > _priceInUSD | |
// ) { | |
// //if we have enough tokens, we can buy that: | |
// emit TokenAddedToSystem(total_cost_price_in_ba, "first", now); | |
// // address buyer = msg.sender; | |
// // both amount and price are in wei, multiplying both == wei squared. so we divide by the equivalent of wei | |
// total_cost_price_in_ba = amount.mul(_priceInUSD); | |
// total_cost_price_in_ba = total_cost_price_in_ba.div( | |
// uint256(10)**decimals | |
// ); | |
// //first deduct the amount of ba tokens from user's balance | |
// _subTokenBalance(_self, "GEUSD", total_cost_price_in_ba, _buyer); | |
// //limit order: we don't have enough offers to fulfill the amount, add the order to the orderBook | |
// _addBuyOffer(_self, tokenNameIndex, _priceInUSD, amount, _buyer); | |
// //and emit the event. | |
// emit LimitBuyOrderCreated( | |
// tokenNameIndex, | |
// _buyer, | |
// amount, | |
// _priceInUSD, | |
// _self.tokens[tokenNameIndex].buyBook[_priceInUSD].offers_length | |
// ); | |
// return 0; | |
// } else { | |
// // market order: current sell price is smaller or equal to buy price! | |
// //1st: find the "cheapest sell price" that is lower than the buy amount [buy: 60@5000] [sell: 50@4500] [sell: 5@5000] | |
// //2: buy up the volume for 4500 | |
// //3: buy up the volume for 5000 | |
// //if still something remaining -> buyToken | |
// //2: buy up the volume | |
// //2.1 add ether to seller, add symbolName to buyer until offers_key <= offers_length | |
// uint256 curSellPrice = _self.tokens[tokenNameIndex].curSellPrice; | |
// uint256 buyAmount = amount; | |
// uint256 offers_key; | |
// while (curSellPrice <= _priceInUSD && buyAmount > 0) { | |
// //we start with the smallest sell price. | |
// offers_key = _self.tokens[tokenNameIndex].sellBook[curSellPrice] | |
// .offers_key; | |
// // address buyer = msg.sender; | |
// address seller = _self.tokens[tokenNameIndex] | |
// .sellBook[curSellPrice] | |
// .offers[offers_key] | |
// .who; | |
// while ( | |
// offers_key <= | |
// _self.tokens[tokenNameIndex].sellBook[curSellPrice] | |
// .offers_length && | |
// buyAmount > 0 | |
// ) { | |
// //and the first order (FIFO) | |
// uint256 tokenAmountAtPrice = _self.tokens[tokenNameIndex] | |
// .sellBook[curSellPrice] | |
// .offers[offers_key] | |
// .amount; | |
// //Two choices from here: | |
// //1) one person offers not enough volume to fulfill the market order - we use it up completely and move on to the next person who offers the symbolName | |
// //2) else: we make use of parts of what a person is offering - lower his amount, fulfill out order. | |
// if (tokenAmountAtPrice <= buyAmount) { | |
// // total cost price = amount * price (in gwei) | |
// // then divide by decimals to get correct ETH equivalent | |
// // both amount and price are in wei, multiplying both == wei squared. so we divide by the equivalent of wei | |
// total_cost_price_in_ba = tokenAmountAtPrice.mul( | |
// curSellPrice | |
// ); | |
// total_cost_price_in_ba = total_cost_price_in_ba.div( | |
// uint256(10)**decimals | |
// ); | |
// emit TokenAddedToSystem( | |
// total_cost_price_in_ba, | |
// "second", | |
// now | |
// ); | |
// // deduct GEUSD from buyer, add to seller | |
// _subTokenBalance( | |
// _self, | |
// "GEUSD", | |
// total_cost_price_in_ba, | |
// _buyer | |
// ); | |
// _addTokenBalance( | |
// _self, | |
// "GEUSD", | |
// total_cost_price_in_ba, | |
// seller | |
// ); | |
// // Add tokens to buyer | |
// _addTokenBalance( | |
// _self, | |
// _symbol, | |
// tokenAmountAtPrice, | |
// _buyer | |
// ); | |
// _self.tokens[tokenNameIndex].sellBook[curSellPrice] | |
// .offers[offers_key] | |
// .amount = 0; | |
// _self.tokens[tokenNameIndex].sellBook[curSellPrice] | |
// .offers_key++; | |
// emit BuyOrderFulfilled( | |
// tokenNameIndex, | |
// tokenAmountAtPrice, | |
// curSellPrice, | |
// offers_key | |
// ); | |
// // Decrease the amount of tokens just purchased, from tokens to be bought | |
// buyAmount.sub(tokenAmountAtPrice); | |
// } else { | |
// // total cost price = amount * price (in gwei) | |
// // then divide by decimals to get correct ETH equivalent | |
// // both amount and price are in wei, multiplying both == wei squared. so we divide by the equivalent of wei | |
// total_cost_price_in_ba = buyAmount.mul(curSellPrice); | |
// total_cost_price_in_ba = total_cost_price_in_ba.div( | |
// uint256(10)**decimals | |
// ); | |
// //first deduct the amount of GEUSD from our balance | |
// _subTokenBalance( | |
// _self, | |
// "GEUSD", | |
// total_cost_price_in_ba, | |
// _buyer | |
// ); | |
// //this guy offers more than we ask for. We reduce his stack, add the tokens to us and the GEUSD to him. | |
// _self.tokens[tokenNameIndex].sellBook[curSellPrice] | |
// .offers[offers_key] | |
// .amount -= buyAmount; | |
// _addTokenBalance( | |
// _self, | |
// "GEUSD", | |
// total_cost_price_in_ba, | |
// seller | |
// ); | |
// _addTokenBalance(_self, _symbol, buyAmount, _buyer); | |
// // we have bought all we need. set buyAmount to 0 | |
// buyAmount = 0; | |
// //we have fulfilled our order | |
// emit BuyOrderFulfilled( | |
// tokenNameIndex, | |
// buyAmount, | |
// curSellPrice, | |
// offers_key | |
// ); | |
// } | |
// // if it was the last offer for that price, we have to set the curSellPrice now higher. Additionally we have one offer less... | |
// if ( | |
// offers_key == | |
// _self.tokens[tokenNameIndex].sellBook[curSellPrice] | |
// .offers_length && | |
// _self.tokens[tokenNameIndex].sellBook[curSellPrice] | |
// .offers[offers_key] | |
// .amount == | |
// 0 | |
// ) { | |
// // emit TokenAddedToSystem(4, 'fourth', now); | |
// _self.tokens[tokenNameIndex].amountSellPrices--; | |
// //we have one price offer less here... | |
// //next curSellPrice | |
// if ( | |
// curSellPrice == | |
// _self.tokens[tokenNameIndex].sellBook[curSellPrice] | |
// .higherPrice || | |
// _self.tokens[tokenNameIndex].buyBook[curSellPrice] | |
// .higherPrice == | |
// 0 | |
// ) { | |
// // emit TokenAddedToSystem(5, 'fifth', now); | |
// _self.tokens[tokenNameIndex].curSellPrice = 0; | |
// //we have reached the last price | |
// } else { | |
// _self.tokens[tokenNameIndex].curSellPrice = _self | |
// .tokens[tokenNameIndex] | |
// .sellBook[curSellPrice] | |
// .higherPrice; | |
// _self.tokens[tokenNameIndex].sellBook[_self | |
// .tokens[tokenNameIndex] | |
// .buyBook[curSellPrice] | |
// .higherPrice] | |
// .lowerPrice = 0; | |
// } | |
// } | |
// offers_key++; | |
// } | |
// //we set the curSellPrice again, since when the volume is used up for a lowest price the curSellPrice is set there... | |
// curSellPrice = _self.tokens[tokenNameIndex].curSellPrice; | |
// } | |
// if (buyAmount > 0) { | |
// // if our order isn't fulfilled yet | |
// _buyToken(_self, _symbol, _priceInUSD, buyAmount, _buyer); | |
// } | |
// } | |
// return 1; | |
// } | |
// /** | |
// * @dev Function to add to buy orders | |
// * @param _self TokenData Struct | |
// * @param _tokenIndex The token index (replaces the symbol internally) | |
// * @param _priceInUSD The token price (in GEUSD) | |
// * @param _amount The amount of tokens to buy | |
// * @param _who The user placing the bid (reference, for the ability to cancel an order) | |
// */ | |
// function _addBuyOffer( | |
// ExchangeStruct.TokenData storage _self, | |
// uint256 _tokenIndex, | |
// uint256 _priceInUSD, | |
// uint256 _amount, | |
// address _who | |
// ) internal { | |
// _self.tokens[_tokenIndex].buyBook[_priceInUSD].offers_length++; | |
// _self.tokens[_tokenIndex].buyBook[_priceInUSD].offers[_self | |
// .tokens[_tokenIndex] | |
// .buyBook[_priceInUSD] | |
// .offers_length] | |
// .amount = _amount; | |
// _self.tokens[_tokenIndex].buyBook[_priceInUSD].offers[_self | |
// .tokens[_tokenIndex] | |
// .buyBook[_priceInUSD] | |
// .offers_length] | |
// .who = _who; | |
// // If we have just one offer for this token at this price | |
// // We only want to add offers at a certain price once | |
// if (_self.tokens[_tokenIndex].buyBook[_priceInUSD].offers_length == 1) { | |
// _self.tokens[_tokenIndex].buyBook[_priceInUSD].offers_key = 1; | |
// //we have a new buy order - increase the counter, so we can set the getOrderBook array later | |
// _self.tokens[_tokenIndex].amountBuyPrices++; | |
// //lowerPrice and higherPrice have to be set | |
// uint256 curBuyPrice = _self.tokens[_tokenIndex].curBuyPrice; | |
// uint256 lowestBuyPrice = _self.tokens[_tokenIndex].lowestBuyPrice; | |
// if (lowestBuyPrice == 0 || lowestBuyPrice > _priceInUSD) { | |
// if (curBuyPrice == 0) { | |
// //there is no buy order yet, we insert the first one... | |
// _self.tokens[_tokenIndex].curBuyPrice = _priceInUSD; | |
// _self.tokens[_tokenIndex].buyBook[_priceInUSD] | |
// .higherPrice = _priceInUSD; | |
// _self.tokens[_tokenIndex].buyBook[_priceInUSD] | |
// .lowerPrice = 0; | |
// } else { | |
// //or the lowest one | |
// _self.tokens[_tokenIndex].buyBook[lowestBuyPrice] | |
// .lowerPrice = _priceInUSD; | |
// _self.tokens[_tokenIndex].buyBook[_priceInUSD] | |
// .higherPrice = lowestBuyPrice; | |
// _self.tokens[_tokenIndex].buyBook[_priceInUSD] | |
// .lowerPrice = 0; | |
// } | |
// _self.tokens[_tokenIndex].lowestBuyPrice = _priceInUSD; | |
// } else if (curBuyPrice < _priceInUSD) { | |
// //the offer to buy is the highest one, we don't need to find the right spot | |
// _self.tokens[_tokenIndex].buyBook[curBuyPrice] | |
// .higherPrice = _priceInUSD; | |
// _self.tokens[_tokenIndex].buyBook[_priceInUSD] | |
// .higherPrice = _priceInUSD; | |
// _self.tokens[_tokenIndex].buyBook[_priceInUSD] | |
// .lowerPrice = curBuyPrice; | |
// _self.tokens[_tokenIndex].curBuyPrice = _priceInUSD; | |
// } else { | |
// //we are somewhere in the middle, we need to find the right spot first... | |
// bool weFoundIt = false; | |
// while (curBuyPrice > 0 && !weFoundIt) { | |
// if ( | |
// curBuyPrice < _priceInUSD && | |
// _self.tokens[_tokenIndex].buyBook[curBuyPrice] | |
// .higherPrice > | |
// _priceInUSD | |
// ) { | |
// //set the new order-book entry higher/lowerPrice first right | |
// _self.tokens[_tokenIndex].buyBook[_priceInUSD] | |
// .lowerPrice = curBuyPrice; | |
// _self.tokens[_tokenIndex].buyBook[_priceInUSD] | |
// .higherPrice = _self.tokens[_tokenIndex] | |
// .buyBook[curBuyPrice] | |
// .higherPrice; | |
// //set the higherPrice'd order-book entries lowerPrice to the current Price | |
// _self.tokens[_tokenIndex].buyBook[_self | |
// .tokens[_tokenIndex] | |
// .buyBook[curBuyPrice] | |
// .higherPrice] | |
// .lowerPrice = _priceInUSD; | |
// //set the lowerPrice'd order-book entries higherPrice to the current Price | |
// _self.tokens[_tokenIndex].buyBook[curBuyPrice] | |
// .higherPrice = _priceInUSD; | |
// //set we found it. | |
// weFoundIt = true; | |
// } | |
// curBuyPrice = _self.tokens[_tokenIndex].buyBook[curBuyPrice] | |
// .lowerPrice; | |
// } | |
// } | |
// } | |
// } | |
// /** | |
// * @dev Function to sell a token (or add to sell orders) | |
// * @param _self TokenData Struct | |
// * @param _symbol The token symbol | |
// * @param _priceInUSD The token price (in GEUSD) | |
// * @param _amount The amount of tokens to sell | |
// * @return A boolean to indicate if the transaction was successful. | |
// */ | |
// function _sellToken( | |
// ExchangeStruct.TokenData storage _self, | |
// string memory _symbol, | |
// uint256 _priceInUSD, | |
// uint256 _amount, | |
// address _seller | |
// ) public returns (uint256) { | |
// uint256 tokenNameIndex = _getSymbolIndexOrThrow(_self, _symbol); | |
// uint256 total_cost_price_in_ba = 0; | |
// // uint token_cost_price_in_GEUSD = 0; | |
// //If there has been no buy orders for this token or the price it was bid for is higher than the current buying price of the token | |
// // We would like to then add it to the list of sell offers | |
// if ( | |
// _self.tokens[tokenNameIndex].amountBuyPrices == 0 || | |
// _self.tokens[tokenNameIndex].curBuyPrice < _priceInUSD | |
// ) { | |
// // address seller = msg.sender; | |
// //if we have enough ether, we can buy that: | |
// // both amount and price are in wei, multiplying both == wei squared. so we divide by the equivalent of wei | |
// total_cost_price_in_ba = _amount * _priceInUSD; | |
// total_cost_price_in_ba = total_cost_price_in_ba.div( | |
// uint256(10)**decimals | |
// ); | |
// //first subtract the amount of tokens to be sold from the seller's account | |
// _subTokenBalance(_self, _symbol, _amount, _seller); | |
// // limit order: we don't have enough offers to fulfill the amount, add the order to the orderBook | |
// _addSellOffer(_self, tokenNameIndex, _priceInUSD, _amount, _seller); | |
// // and emit the event. | |
// emit LimitSellOrderCreated( | |
// tokenNameIndex, | |
// _seller, | |
// _amount, | |
// _priceInUSD, | |
// _self.tokens[tokenNameIndex].sellBook[_priceInUSD].offers_length | |
// ); | |
// return 0; | |
// } else { | |
// //market order: current buy price is bigger or equal to sell price! | |
// //1st: find the "highest buy price" that is higher than the sell amount [buy: 60@5000] [buy: 50@4500] [sell: 500@4000] | |
// //2: sell up the volume for 5000 | |
// //3: sell up the volume for 4500 | |
// //if still something remaining -> _sellToken limit order | |
// //2: sell up the volume | |
// //2.1 add ether to seller, add _symbol to buyer until offers_key <= offers_length | |
// uint256 curBuyPrice = _self.tokens[tokenNameIndex].curBuyPrice; | |
// uint256 sellAmount = _amount; | |
// uint256 offers_key; | |
// uint256 token_cost_price_in_GEUSD; | |
// while (curBuyPrice >= _priceInUSD && sellAmount > 0) { | |
// //we start with the highest buy price. | |
// offers_key = _self.tokens[tokenNameIndex].buyBook[curBuyPrice] | |
// .offers_key; | |
// while ( | |
// offers_key <= | |
// _self.tokens[tokenNameIndex].buyBook[curBuyPrice] | |
// .offers_length && | |
// sellAmount > 0 | |
// ) { | |
// //and the first order (FIFO) | |
// uint256 tokenAmountAtPrice = _self.tokens[tokenNameIndex] | |
// .buyBook[curBuyPrice] | |
// .offers[offers_key] | |
// .amount; | |
// address buyer = _self.tokens[tokenNameIndex] | |
// .buyBook[curBuyPrice] | |
// .offers[offers_key] | |
// .who; | |
// // address seller = msg.sender; | |
// //Two choices from here: | |
// //1) one person offers not enough volume to fulfill the market order - we use it up completely and move on to the next person who offers the _symbol | |
// //2) else: we make use of parts of what a person is offering - lower his amount, fulfill out order. | |
// if (tokenAmountAtPrice <= sellAmount) { | |
// token_cost_price_in_GEUSD = | |
// tokenAmountAtPrice * | |
// curBuyPrice; | |
// // subtract the amount of tokens that matches the buy order | |
// _subTokenBalance( | |
// _self, | |
// _symbol, | |
// tokenAmountAtPrice * (uint256(10)**decimals), | |
// _seller | |
// ); | |
// //this buyer offers less or equal the volume that the seller posts, so we use it up completely. | |
// _addTokenBalance( | |
// _self, | |
// _symbol, | |
// tokenAmountAtPrice * (uint256(10)**decimals), | |
// buyer | |
// ); | |
// _self.tokens[tokenNameIndex].buyBook[curBuyPrice] | |
// .offers[offers_key] | |
// .amount = 0; | |
// _addTokenBalance( | |
// _self, | |
// "GEUSD", | |
// token_cost_price_in_GEUSD, | |
// _seller | |
// ); | |
// _self.tokens[tokenNameIndex].buyBook[curBuyPrice] | |
// .offers_key++; | |
// sellAmount.sub(tokenAmountAtPrice); | |
// emit SellOrderFulfilled( | |
// tokenNameIndex, | |
// tokenAmountAtPrice, | |
// curBuyPrice, | |
// offers_key | |
// ); | |
// } else { | |
// token_cost_price_in_GEUSD = sellAmount * curBuyPrice; | |
// //we take the rest of the outstanding amount | |
// _subTokenBalance( | |
// _self, | |
// _symbol, | |
// sellAmount * (uint256(10)**decimals), | |
// _seller | |
// ); | |
// //this buyer offers more than we ask for. We reduce his stack, add the GEUSD to buyer and the symbolName to seller. | |
// _self.tokens[tokenNameIndex].buyBook[curBuyPrice] | |
// .offers[offers_key] | |
// .amount | |
// .sub(sellAmount); | |
// _addTokenBalance( | |
// _self, | |
// "GEUSD", | |
// token_cost_price_in_GEUSD, | |
// _seller | |
// ); | |
// _addTokenBalance( | |
// _self, | |
// _symbol, | |
// sellAmount * (uint256(10)**decimals), | |
// buyer | |
// ); | |
// //we have fulfilled our order | |
// sellAmount = 0; | |
// emit SellOrderFulfilled( | |
// tokenNameIndex, | |
// sellAmount, | |
// curBuyPrice, | |
// offers_key | |
// ); | |
// } | |
// // if it was the last offer for that price, and the amount posted to be bought in this last offer at that price was exhausted, | |
// // It means this sell order has burnt through everything in this offer so we should move on to the next offer in line | |
// //Additionally we have one offer less... | |
// if ( | |
// offers_key == | |
// _self.tokens[tokenNameIndex].buyBook[curBuyPrice] | |
// .offers_length && | |
// _self.tokens[tokenNameIndex].buyBook[curBuyPrice] | |
// .offers[offers_key] | |
// .amount == | |
// 0 | |
// ) { | |
// _self.tokens[tokenNameIndex].amountBuyPrices--; | |
// //Reduce the total number of buy prices | |
// //next curBuyPrice | |
// if ( | |
// curBuyPrice == | |
// _self.tokens[tokenNameIndex].buyBook[curBuyPrice] | |
// .lowerPrice || | |
// _self.tokens[tokenNameIndex].buyBook[curBuyPrice] | |
// .lowerPrice == | |
// 0 | |
// ) { | |
// _self.tokens[tokenNameIndex].curBuyPrice = 0; | |
// //we have reached the last price | |
// } else { | |
// _self.tokens[tokenNameIndex].curBuyPrice = _self | |
// .tokens[tokenNameIndex] | |
// .buyBook[curBuyPrice] | |
// .lowerPrice; | |
// // _self.tokens[tokenNameIndex].buyBook[_self.tokens[tokenNameIndex].buyBook[curBuyPrice].lowerPrice].higherPrice = _self.tokens[tokenNameIndex].curBuyPrice; | |
// } | |
// } | |
// offers_key++; | |
// } | |
// //we set the curSellPrice again, since when the volume is used up for a lowest price the curSellPrice is set there... | |
// curBuyPrice = _self.tokens[tokenNameIndex].curBuyPrice; | |
// } | |
// if (sellAmount > 0) { | |
// _sellToken(_self, _symbol, _priceInUSD, sellAmount, _seller); | |
// //add a limit order, we couldn't fulfill all the orders! | |
// } | |
// } | |
// return 1; | |
// } | |
// /** | |
// * @dev Function to add to sell orders | |
// * @param _self TokenData Struct | |
// * @param _tokenIndex The token index (replaces the symbol internally) | |
// * @param _priceInUSD The token price (in GEUSD) | |
// * @param _amount The amount of tokens to buy | |
// * @param _who The user placing the bid (for reference) | |
// * @return A boolean to indicate if the order was added to book. | |
// */ | |
// function _addSellOffer( | |
// ExchangeStruct.TokenData storage _self, | |
// uint256 _tokenIndex, | |
// uint256 _priceInUSD, | |
// uint256 _amount, | |
// address _who | |
// ) internal returns (bool) { | |
// _self.tokens[_tokenIndex].sellBook[_priceInUSD].offers_length++; | |
// _self.tokens[_tokenIndex].sellBook[_priceInUSD].offers[_self | |
// .tokens[_tokenIndex] | |
// .sellBook[_priceInUSD] | |
// .offers_length] | |
// .amount = _amount; | |
// _self.tokens[_tokenIndex].sellBook[_priceInUSD].offers[_self | |
// .tokens[_tokenIndex] | |
// .sellBook[_priceInUSD] | |
// .offers_length] | |
// .who = _who; | |
// if ( | |
// _self.tokens[_tokenIndex].sellBook[_priceInUSD].offers_length == 1 | |
// ) { | |
// _self.tokens[_tokenIndex].sellBook[_priceInUSD].offers_key = 1; | |
// //we have a new sell order - increase the counter, so we can set the getOrderBook array later | |
// _self.tokens[_tokenIndex].amountSellPrices++; | |
// //lowerPrice and higherPrice have to be set | |
// uint256 curSellPrice = _self.tokens[_tokenIndex].curSellPrice; | |
// uint256 highestSellPrice = _self.tokens[_tokenIndex] | |
// .highestSellPrice; | |
// if (highestSellPrice == 0 || highestSellPrice < _priceInUSD) { | |
// if (curSellPrice == 0) { | |
// //there is no sell order yet, we insert the first one... | |
// _self.tokens[_tokenIndex].curSellPrice = _priceInUSD; | |
// _self.tokens[_tokenIndex].sellBook[_priceInUSD] | |
// .higherPrice = 0; | |
// _self.tokens[_tokenIndex].sellBook[_priceInUSD] | |
// .lowerPrice = 0; | |
// } else { | |
// //this is the highest sell order | |
// _self.tokens[_tokenIndex].sellBook[highestSellPrice] | |
// .higherPrice = _priceInUSD; | |
// _self.tokens[_tokenIndex].sellBook[_priceInUSD] | |
// .lowerPrice = highestSellPrice; | |
// _self.tokens[_tokenIndex].sellBook[_priceInUSD] | |
// .higherPrice = 0; | |
// } | |
// _self.tokens[_tokenIndex].highestSellPrice = _priceInUSD; | |
// } else if (curSellPrice > _priceInUSD) { | |
// //the offer to sell is the lowest one, we don't need to find the right spot | |
// _self.tokens[_tokenIndex].sellBook[curSellPrice] | |
// .lowerPrice = _priceInUSD; | |
// _self.tokens[_tokenIndex].sellBook[_priceInUSD] | |
// .higherPrice = curSellPrice; | |
// _self.tokens[_tokenIndex].sellBook[_priceInUSD].lowerPrice = 0; | |
// _self.tokens[_tokenIndex].curSellPrice = _priceInUSD; | |
// } else { | |
// //we are somewhere in the middle, we need to find the right spot first... | |
// uint256 sellPrice = _self.tokens[_tokenIndex].curSellPrice; | |
// bool weFoundIt = false; | |
// while (sellPrice > 0 && !weFoundIt) { | |
// if ( | |
// sellPrice < _priceInUSD && | |
// _self.tokens[_tokenIndex].sellBook[sellPrice] | |
// .higherPrice > | |
// _priceInUSD | |
// ) { | |
// //set the new order-book entry higher/lowerPrice first right | |
// _self.tokens[_tokenIndex].sellBook[_priceInUSD] | |
// .lowerPrice = sellPrice; | |
// _self.tokens[_tokenIndex].sellBook[_priceInUSD] | |
// .higherPrice = _self.tokens[_tokenIndex] | |
// .sellBook[sellPrice] | |
// .higherPrice; | |
// //set the higherPrice'd order-book entries lowerPrice to the current Price | |
// _self.tokens[_tokenIndex].sellBook[_self | |
// .tokens[_tokenIndex] | |
// .sellBook[sellPrice] | |
// .higherPrice] | |
// .lowerPrice = _priceInUSD; | |
// //set the lowerPrice'd order-book entries higherPrice to the current Price | |
// _self.tokens[_tokenIndex].sellBook[sellPrice] | |
// .higherPrice = _priceInUSD; | |
// //set we found it. | |
// weFoundIt = true; | |
// } | |
// sellPrice = _self.tokens[_tokenIndex].sellBook[sellPrice] | |
// .higherPrice; | |
// } | |
// } | |
// } | |
// return true; | |
// } | |
// /** | |
// * @dev Function to cancel a buy or sell order | |
// * @param _self TokenData Struct | |
// * @param _symbol The token symbol | |
// * @param _priceInUSD The token price (in GEUSD) | |
// * @param _isSellOrder A boolean to indicate if order was a buy or sell order | |
// * @return A boolean to indicate if the order was added to book. | |
// */ | |
// function _cancelOrder( | |
// ExchangeStruct.TokenData storage _self, | |
// string memory _symbol, | |
// bool _isSellOrder, | |
// uint256 _priceInUSD, | |
// uint256 _key, | |
// address _user | |
// ) public returns (bool) { | |
// uint256 tokenNameIndex = _getSymbolIndexOrThrow(_self, _symbol); | |
// if (_isSellOrder) { | |
// require( | |
// _self.tokens[tokenNameIndex].sellBook[_priceInUSD].offers[_key] | |
// .who != address(0), | |
// "Order does not exist" | |
// ); | |
// require( | |
// _self.tokens[tokenNameIndex].sellBook[_priceInUSD].offers[_key] | |
// .who == _user, | |
// "Found order does not belong to the provided address." | |
// ); | |
// uint256 tokensAmount = _self.tokens[tokenNameIndex] | |
// .sellBook[_priceInUSD] | |
// .offers[_key] | |
// .amount; | |
// require( | |
// _getTokenBalance(_self, _symbol, _user) + tokensAmount > | |
// _getTokenBalance(_self, _symbol, _user), | |
// "Error crediting user account with token" | |
// ); | |
// _addTokenBalance(_self, _symbol, tokensAmount, _user); | |
// _self.tokens[tokenNameIndex].sellBook[_priceInUSD].offers[_key] | |
// .amount = 0; | |
// emit SellOrderCanceled( | |
// tokenNameIndex, | |
// _priceInUSD, | |
// tokensAmount, | |
// _key | |
// ); | |
// return true; | |
// } else { | |
// require( | |
// _self.tokens[tokenNameIndex].buyBook[_priceInUSD].offers[_key] | |
// .who != address(0), | |
// "Order does not exist" | |
// ); | |
// require( | |
// _self.tokens[tokenNameIndex].buyBook[_priceInUSD].offers[_key] | |
// .who == _user, | |
// "Found order does not belong to the provided address." | |
// ); | |
// uint256 _amount = _self.tokens[tokenNameIndex].buyBook[_priceInUSD] | |
// .offers[_key] | |
// .amount; | |
// uint256 baToRefund = _priceInUSD.mul(_amount); | |
// baToRefund = baToRefund.div((uint256(10)**decimals)); | |
// require( | |
// _getTokenBalance(_self, "GEUSD", _user) + baToRefund > | |
// _getTokenBalance(_self, "GEUSD", _user), | |
// "Error crediting user account with GEUSD" | |
// ); | |
// _addTokenBalance(_self, "GEUSD", baToRefund, _user); | |
// _self.tokens[tokenNameIndex].buyBook[_priceInUSD].offers[_key] | |
// .amount = 0; | |
// emit BuyOrderCanceled( | |
// tokenNameIndex, | |
// _priceInUSD, | |
// baToRefund, | |
// _key | |
// ); | |
// return true; | |
// } | |
// } | |
//////////////////////////////// | |
// STRING COMPARISON FUNCTION // | |
//////////////////////////////// | |
function _stringsEqual(string memory _a, string memory _b) | |
internal | |
pure | |
returns (bool) | |
{ | |
return keccak256(abi.encode(_a)) == keccak256(abi.encode(_b)); | |
} | |
} |
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.6.0; | |
/** | |
* @title GetEquity token | |
* @author Jude Dike | https://github.com/dumebi | |
* @notice Core token contract for GetEquity | |
* SPDX-License-Identifier: UNLICENSED | |
*/ | |
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; | |
import "@openzeppelin/contracts/math/SafeMath.sol"; | |
import "./helpers/Ownable.sol"; | |
// ERC Token Standard #20 Interface | |
// https://github.com/ethereum/EIPs/issues/20 | |
abstract contract ERC20Interface { | |
/** | |
* @dev Function to return specific details of a token | |
*/ | |
function details() | |
public | |
virtual | |
view | |
returns ( | |
string memory, | |
uint256, | |
uint256, | |
address, | |
uint256 | |
); | |
/** | |
* @dev Function to mint tokens | |
*/ | |
function mint(address _to, uint256 _amount) public virtual returns (bool); | |
/** | |
* @dev allows a minter to burn some of its own tokens | |
* Validates that caller is a minter and that sender is not blacklisted | |
* amount is less than or equal to the minter's account balance | |
*/ | |
function burn(address _msgSender, uint256 _amount) | |
public | |
virtual | |
returns (bool); | |
/** | |
* @dev Get token balance of an account | |
*/ | |
function balanceOf(address account) public virtual view returns (uint256); | |
/** | |
* @dev Get token escrow of an account | |
*/ | |
function escrowOf(address account) public virtual view returns (uint256); | |
/** | |
* @dev add specified amount to escrow | |
*/ | |
function addEscrow(address _account, uint256 _value) | |
public | |
virtual | |
returns (bool); | |
/** | |
* @dev transfer token for a specified address | |
*/ | |
function subEscrow( | |
address _account, | |
address _to, | |
uint256 _value | |
) public virtual returns (bool); | |
/** | |
* @dev return total sold amount of a token | |
*/ | |
function sold() public virtual view returns (uint256); | |
/** | |
* @dev transfer token for a specified address | |
*/ | |
function transfer( | |
address _msgSender, | |
address _to, | |
uint256 _value | |
) public virtual returns (bool); | |
/** | |
* @dev Transfer tokens from one address to another. | |
*/ | |
function transferFrom( | |
address _msgSender, | |
address _from, | |
address _to, | |
uint256 _value | |
) public virtual returns (bool); | |
/** | |
* @dev approve a user to spend | |
*/ | |
function approve( | |
address _msgSender, | |
address _spender, | |
uint256 _value | |
) public virtual returns (bool); | |
/** | |
* @dev Get allowed amount for an account | |
*/ | |
function allowance(address owner, address spender) | |
public | |
virtual | |
view | |
returns (uint256); | |
} | |
contract Token is ERC20Interface, Ownable, ReentrancyGuard { | |
using SafeMath for uint256; | |
string public symbol; | |
string public name; | |
uint256 public constant decimals = 18; | |
uint256 public _totalSupply; | |
uint256 public rate; | |
uint256 public totalSold; // Keeps track of the total tokens sold | |
address public creator; | |
// Owner of this contract | |
// address public owner; | |
// Balances for each account | |
mapping(address => uint256) balances; | |
mapping(address => uint256) escrow; | |
// Owner of account approves the transfer of an amount to another account | |
mapping(address => mapping(address => uint256)) allowed; | |
event Transfer(address indexed from, address indexed to, uint256 amount); | |
event Mint(address indexed minter, address indexed to, uint256 amount); | |
event Burn(address indexed burner, uint256 amount); | |
constructor( | |
string memory _symbol, | |
string memory _name, | |
uint256 _supply, | |
uint256 _rate, | |
address _creator | |
) public { | |
symbol = _symbol; | |
name = _name; | |
_totalSupply = _supply; | |
rate = _rate; | |
creator = _creator; | |
balances[creator] = _totalSupply; | |
} | |
/** | |
* @dev Function to return specific details of a token | |
* @return A boolean that indicates if the operation was successful. | |
*/ | |
function details() | |
public | |
override | |
view | |
returns ( | |
string memory, | |
uint256, | |
uint256, | |
address, | |
uint256 | |
) | |
{ | |
return (name, _totalSupply, rate, creator, totalSold); | |
} | |
/** | |
* @dev Function to mint tokens | |
* @param _to The address that will receive the minted tokens. | |
* @param _amount The amount of tokens to mint. Must be less than or equal to the minterAllowance of the caller. | |
* @return A boolean that indicates if the operation was successful. | |
*/ | |
function mint(address _to, uint256 _amount) | |
public | |
override | |
onlyOwner | |
returns (bool) | |
{ | |
require(_to != address(0), "Mint destination adddress is invalid"); | |
require( | |
_to == creator, | |
"Mint destination adddress can only be the token's creator" | |
); | |
require(_amount > 0, "Mint amount has to be greater than one"); | |
_totalSupply = _totalSupply.add(_amount); | |
balances[_to] = balances[_to].add(_amount); | |
emit Mint(msg.sender, _to, _amount); | |
emit Transfer(address(0), _to, _amount); | |
return true; | |
} | |
/** | |
* @dev allows a minter to burn a specified amount of their tokens | |
* Validates that caller is a minter and that sender is not blacklisted | |
* amount is less than or equal to the minter's account balance | |
* @param _amount uint256 the amount of tokens to be burned | |
* @param _msgSender actual address calling the function | |
*/ | |
function burn(address _msgSender, uint256 _amount) | |
public | |
override | |
onlyOwner | |
returns (bool) | |
{ | |
uint256 balance = balances[_msgSender]; | |
require(_amount > 0, "No `amount` to burn"); | |
require(balance >= _amount, "Not enough funds to burn"); | |
_totalSupply = _totalSupply.sub(_amount); | |
balances[_msgSender] = balance.sub(_amount); | |
emit Burn(_msgSender, _amount); | |
emit Transfer(_msgSender, address(0), _amount); | |
return true; | |
} | |
/** | |
* @dev Get token balance of an account | |
* @param account address The account | |
*/ | |
function balanceOf(address account) public override view returns (uint256) { | |
return balances[account]; | |
} | |
/** | |
* @dev Get token escrow of an account | |
* @param account address The account | |
*/ | |
function escrowOf(address account) public override view returns (uint256) { | |
return escrow[account]; | |
} | |
/** | |
* @dev add specified amount to escrow | |
* @param _account owner of escrow account | |
* @param _value The amount to be transferred. | |
* @return bool success | |
*/ | |
function addEscrow(address _account, uint256 _value) | |
public | |
override | |
nonReentrant | |
returns (bool) | |
{ | |
require( | |
balances[_account] >= _value, | |
"Not enough tokens to add to escrow" | |
); | |
balances[_account] = balances[_account].sub(_value); | |
escrow[_account] = escrow[_account].add(_value); | |
return true; | |
} | |
/** | |
* @dev transfer token for a specified address | |
* @param _account owner of escrow account | |
* @param _to The address to transfer to. | |
* @param _value The amount to be transferred. | |
* @return bool success | |
*/ | |
function subEscrow( | |
address _account, | |
address _to, | |
uint256 _value | |
) public override nonReentrant returns (bool) { | |
require( | |
escrow[_account] >= _value, | |
"Not enough tokens to deduct from escrow" | |
); | |
escrow[_account] = escrow[_account].sub(_value); | |
balances[_to] = balances[_to].add(_value); | |
return true; | |
} | |
/** | |
* @dev return total sold amount of a token | |
* @return uint sold | |
*/ | |
function sold() public override view returns (uint256) { | |
return totalSold; | |
} | |
/** | |
* @dev transfer token for a specified address | |
* @param _msgSender actual address calling the function | |
* @param _to The address to transfer to. | |
* @param _value The amount to be transferred. | |
* @return bool success | |
*/ | |
function transfer( | |
address _msgSender, | |
address _to, | |
uint256 _value | |
) public override returns (bool) { | |
require(_to != address(0), "No `to` address"); | |
require( | |
balances[_msgSender] >= _value, | |
"Not enough funds to make this transfer request" | |
); | |
balances[_msgSender] = balances[_msgSender].sub(_value); | |
balances[_to] = balances[_to].add(_value); | |
emit Transfer(_msgSender, _to, _value); | |
return true; | |
} | |
/** | |
* @dev Transfer tokens from one address to another. | |
* @param _msgSender actual address calling the function | |
* @param _from address The address which you want to send tokens from | |
* @param _to address The address which you want to transfer to | |
* @param _value uint256 the amount of tokens to be transferred | |
* @return bool success | |
*/ | |
function transferFrom( | |
address _msgSender, | |
address _from, | |
address _to, | |
uint256 _value | |
) public override returns (bool) { | |
require(_to != address(0), "No `to` address"); | |
require( | |
balances[_from] >= _value, | |
"Not enough funds to make this transfer from request" | |
); | |
require( | |
allowed[_from][_msgSender] >= _value, | |
"you do not have access to transfer this much funds" | |
); | |
balances[_from] = balances[_from].sub(_value); | |
balances[_to] = balances[_to].add(_value); | |
allowed[_from][_msgSender] = allowed[_from][_msgSender].sub(_value); | |
emit Transfer(_from, _to, _value); | |
return true; | |
} | |
/** | |
* @dev approve a user to spend | |
* @return True if the operation was successful. | |
*/ | |
function approve( | |
address _msgSender, | |
address _spender, | |
uint256 _value | |
) public override returns (bool) { | |
allowed[_msgSender][_spender] = _value; | |
// emit Approval(_msgSender, _spender, _value); | |
return true; | |
} | |
/** | |
* @dev Get allowed amount for an account | |
* @param owner address The account owner | |
* @param spender address The account spender | |
*/ | |
function allowance(address owner, address spender) | |
public | |
override | |
view | |
returns (uint256) | |
{ | |
return allowed[owner][spender]; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment