Skip to content

Instantly share code, notes, and snippets.

@dumebi
Last active April 27, 2021 21:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dumebi/396e61ded8df25146ac23e0f6b5a9ee8 to your computer and use it in GitHub Desktop.
Save dumebi/396e61ded8df25146ac23e0f6b5a9ee8 to your computer and use it in GitHub Desktop.
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 {}
}
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));
}
}
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