NFMExchange Contract
Here you can find all information about the NFM Exchange contract.
Last updated
Here you can find all information about the NFM Exchange contract.
Last updated
This contract is deployed on Polygon at the following address:
This contract is responsible for the advance sale. The contract allows you to set a countdown for the start and a countdown for the presale itself.
The protocol makes it possible to exchange the NFM for countless other ERC-20 tokens without additional trading fees.
The amount of the first advance sale of 40 million NFM is already deposited in the contract. The funds raised in the sale are used for the Uniswap protocol integrated in the NFM.
/**
*Submitted for verification at polygonscan.com on 2022-07-30
*/
//SPDX-License-Identifier:MIT
pragma solidity ^0.8.13;
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// LIBRARIES
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// SAFEMATH its a Openzeppelin Lib. Check out for more info @ https://docs.openzeppelin.com/contracts/2.x/api/math
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
function mod(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// INTERFACES
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// INFMCONTROLLER
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
interface INfmController {
function _checkWLSC(address Controller, address Client)
external
pure
returns (bool);
function _getController() external pure returns (address);
function _getNFM() external pure returns (address);
function _getTimer() external pure returns (address);
function _getDistribute() external pure returns (address);
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// INFMORACLE
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
interface INfmOracle {
function _getLatestPrice(address coin) external view returns (uint256);
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// IERC20
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
function decimals() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender)
external
view
returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// IUNISWAPV2ROUTER01
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
interface IUniswapV2Router01 {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
)
external
returns (
uint256 amountA,
uint256 amountB,
uint256 liquidity
);
function addLiquidityETH(
address token,
uint256 amountTokenDesired,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
)
external
payable
returns (
uint256 amountToken,
uint256 amountETH,
uint256 liquidity
);
function removeLiquidity(
address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB);
function removeLiquidityETH(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountToken, uint256 amountETH);
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapTokensForExactTokens(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapExactETHForTokens(
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external payable returns (uint256[] memory amounts);
function swapTokensForExactETH(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapExactTokensForETH(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapETHForExactTokens(
uint256 amountOut,
address[] calldata path,
address to,
uint256 deadline
) external payable returns (uint256[] memory amounts);
function quote(
uint256 amountA,
uint256 reserveA,
uint256 reserveB
) external pure returns (uint256 amountB);
function getAmountOut(
uint256 amountIn,
uint256 reserveIn,
uint256 reserveOut
) external pure returns (uint256 amountOut);
function getAmountIn(
uint256 amountOut,
uint256 reserveIn,
uint256 reserveOut
) external pure returns (uint256 amountIn);
function getAmountsOut(uint256 amountIn, address[] calldata path)
external
view
returns (uint256[] memory amounts);
function getAmountsIn(uint256 amountOut, address[] calldata path)
external
view
returns (uint256[] memory amounts);
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// IUNISWAPV2ROUTER02
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
interface IUniswapV2Router02 is IUniswapV2Router01 {
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountETH);
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountETH);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external;
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// IUNISWAPV2PAIR
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
interface IUniswapV2Pair {
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves()
external
view
returns (
uint112 reserve0,
uint112 reserve1,
uint32 blockTimestampLast
);
function price0CumulativeLast() external view returns (uint256);
function price1CumulativeLast() external view returns (uint256);
function kLast() external view returns (uint256);
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// IUNISWAPV2FACTORY
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
interface IUniswapV2Factory {
event PairCreated(
address indexed token0,
address indexed token1,
address pair,
uint256
);
function createPair(address tokenA, address tokenB)
external
returns (address pair);
function getPair(address tokenA, address tokenB)
external
view
returns (address pair);
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/// @title NFMExchange.sol
/// @author Fernando Viktor Seidl E-mail: viktorseidl@gmail.com
/// @notice This contract is a decentralized exchange for the NFM token. This contract enables any trading of ERC20 tokens.
/// @dev This DEX is based on the ERC20 standard
/// INFO:
/// In order for this contract to function smoothly, it is necessary to integrate the following interfaces:
///
/// - Controller
/// - IERC20
/// - UniswapV2Router01
/// - UniswapV2Router02
/// - UniswapV2Pair
/// - UniswapV2Factory
///
/// PARTICULARITIES:
/// - Dex allows 2 modes:
/// - Fixed price sale (Presale mode)
/// - Dynamic sale (Price changes based on the markets)
/// - Any number of currencies can be added to the exchange. As long as these currencies have the ERC20 standard
/// - For security reasons (FlashLoan Attack on AMM), this contract uses 3 price oracles:
/// - Uniswap Price
/// - Onchain Oracle
/// - Offchain Oracle
/// - PreSale mode enables:
/// - Fixed Sale Price
/// - Fixed supply
/// - Minimum purchase amount
/// - Maximum purchase amount
/// - Time limit
/// - Trade free of charge
/// - Free from price manipulations
/// - Dynamic mode enables:
/// - Fixed supply
/// - Minimum purchase amount
/// - Maximum purchase amount
/// - Free from price manipulations
/// - Trade free of charge
/// - By exchanging currencies, an integrated onchain oracle in the contract is filled with prices. This oracle can later be used
/// for other interfaces to avoid price manipulations.
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
contract NFMExchange {
//include SafeMath
using SafeMath for uint256;
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
CONTROLLER
OWNER = MSG.SENDER ownership will be handed over to dao
*/
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
INfmController private _Controller;
address private _SController;
address private _Owner;
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
_isFixedPrice => boolean whether the trade should be executed with a fixed price or a dynamic price
_PriceVsUSD => fixed selling price in USD if fixed price mode is set to true
_OracleTimer => Time interval for entering prices into the onchain oracle
_PreSaleMode => Sales mode, whether presale or dynamic
_PreSaleStart => Countdown for presale mode
_PreSaleEnd => Timestamp when the presale ends
_PreSaleDexAmount => PreSale total amount
_CurrencyCounter => currency counter
_CurrencyArray => Address list of all approved ERC20 tokens for exchange
_USDC => Address of the USDC token
_uniswapV2Router => Address of the UniswapV2Router
_MinUSD => Minimum trade amount in USD
_MaxUSD => Maximum trade amount in USD
*/
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
bool private _isFixedPrice = false;
uint256 private _PriceVsUSD;
uint256 private _OracleTimer;
bool private _PreSaleMode = false;
uint256 private _PreSaleStart;
uint256 private _PreSaleEnd;
uint256 private _PreSaleDexAmount;
uint256 private _CurrencyCounter;
address[] private _CurrencyArray;
address private _USDC;
address private _OracleAdr;
address private _uniswapV2Router =
0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff;
uint256 private _MinUSD = 10 * 10**18;
uint256 private _MaxUSD = 500000 * 10**18;
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
MAPPINGS
_isCurrencyAllowed (Currency address, true if allowed false if not allowed);
_Oracle (Currency address, price in USD);
*/
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
mapping(address => bool) public _isCurrencyAllowed;
mapping(address => uint256[]) public _Oracle;
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
CONTRACT EVENTS
Trade(Buyer address, Coin address, Currency amount, NFM amount, Timestamp);
*/
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
event Trade(
address indexed Sender,
address indexed Coin,
uint256 Amount,
uint256 NFM,
uint256 Time
);
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
MODIFIER
onlyOwner => Only Controller listed Contracts and Owner can interact with this contract.
*/
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
modifier onlyOwner() {
require(
_Controller._checkWLSC(_SController, msg.sender) == true ||
_Owner == msg.sender,
"oO"
);
require(msg.sender != address(0), "0A");
_;
}
constructor(
address Controller,
address USDC,
address OracleAdr
) {
_Owner = msg.sender;
INfmController _Cont = INfmController(address(Controller));
_SController = Controller;
_Controller = _Cont;
_USDC = USDC;
_CurrencyArray.push(USDC);
_CurrencyCounter++;
_isCurrencyAllowed[USDC] = true;
_OracleTimer = block.timestamp + 3600;
_OracleAdr = OracleAdr;
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
@setFixedPrice(uint256 FixedUSDPrice, bool OnOff) returns (bool);
This function enables the fixed price mode
USD Price against NFM needs to be in 18 digits format
*/
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function setFixedPrice(uint256 FixedUSDPrice, bool OnOff)
public
onlyOwner
returns (bool)
{
_isFixedPrice = OnOff;
_PriceVsUSD = FixedUSDPrice;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
@returnAllowedCurrencies(address Coin) returns (bool);
This function is for checking a currency if it is eligible for trading
Returns true if Currency is allowed
*/
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function returnAllowedCurrencies(address Coin) public view returns (bool) {
return _isCurrencyAllowed[Coin];
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
@returnCurrenciesArray() returns (address);
This function returns a list of all currencies.
*/
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function returnCurrenciesArray()
public
view
returns (address[] memory Arr)
{
return _CurrencyArray;
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
@onOffPresale(bool Mode, uint256 DaysStart, uint256 DaysEnd, uint256 PresaleAmount) returns (bool);
This function allows you to activate and deactivate the presale mode
*/
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function onOffPresale(
bool Mode,
uint256 DaysStart,
uint256 DaysEnd
) public onlyOwner returns (bool) {
if (Mode == true) {
_PreSaleMode = Mode;
_PreSaleStart = block.timestamp + (3600 * 24 * DaysStart);
_PreSaleEnd = block.timestamp + (3600 * 24 * (DaysEnd + DaysStart));
_PreSaleDexAmount = IERC20(address(_Controller._getNFM()))
.balanceOf(address(this));
} else {
_PreSaleMode = Mode;
_PreSaleStart = 0;
_PreSaleEnd = 0;
_PreSaleDexAmount = 0;
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
@returnRemainPresaleAmount() returns (uint256, bool);
This function returns the remaining presale amount.
*/
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function returnRemainPresaleAmount() public view returns (uint256, bool) {
if (_PreSaleMode == true) {
return (
IERC20(address(_Controller._getNFM())).balanceOf(address(this)),
true
);
} else {
return (0, false);
}
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
@returnInicialandSold() returns (uint256, uint256, bool);
This function returns the inicial presale amount and and the amount sold.
*/
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function returnInicialandSold()
public
view
returns (
uint256 Inicial,
uint256 Sold,
bool
)
{
if (_PreSaleMode == true) {
if (
_PreSaleDexAmount <
IERC20(address(_Controller._getNFM())).balanceOf(address(this))
) {
return (0, 0, true);
} else {
return (
_PreSaleDexAmount,
SafeMath.sub(
_PreSaleDexAmount,
IERC20(address(_Controller._getNFM())).balanceOf(
address(this)
)
),
true
);
}
} else {
return (0, 0, false);
}
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
@returnPresaleTimers() returns (uint256, uint256, bool);
This function returns the timestamp of the presale
*/
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function returnPresaleTimers()
public
view
returns (
uint256 Start,
uint256 End,
bool Check
)
{
if (_PreSaleMode == false) {
return (0, 0, false);
} else {
return (_PreSaleStart, _PreSaleEnd, true);
}
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
@setMinMaxUSD(uint256 Min, uint256 Max) returns (bool);
This function sets the minimum and maximum amount for trading
Amounts must be specified in USD and in 18 digit format
*/
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function setMinMaxUSD(uint256 Min, uint256 Max)
public
onlyOwner
returns (bool)
{
_MinUSD = Min;
_MaxUSD = Max;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
@addOrDisableCoin(address Coin, bool Allow) returns (bool);
This function is responsible for managing the currencies for exchange. New ones can be added or existing ones can be deactivated
Add new Currency => Coin Address, true
Deactivate Currency => Coin Address, false
*/
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function addOrDisableCoin(address Coin, bool Allow)
public
onlyOwner
returns (bool)
{
if (Allow == false) {
_isCurrencyAllowed[Coin] = false;
} else {
_CurrencyArray.push(Coin);
_CurrencyCounter++;
_isCurrencyAllowed[Coin] = true;
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
@createPairUv2(address Coin) returns (bool);
This function is for inicialising or creating the uniswap pairs.
*/
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function createPairUv2(address Coin) public onlyOwner returns (bool) {
IUniswapV2Factory(IUniswapV2Router02(_uniswapV2Router).factory())
.createPair(
address(_Controller._getNFM()),
address(
Coin /*COIN ADDRESS */
)
);
return true;
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
@updateSetFixedPrice() returns (bool);
This function updates the fixed price if the dynamic price mode is activated.
This mode should only be used if all 3 oracles exist. The NFM/USDC pair must exist on Uniswap oracle before it can be used.
*/
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function updateSetFixedPrice() internal onlyOwner returns (bool) {
uint256 O2Price = checkOracle2Price(address(_Controller._getNFM()));
uint256 MinPus = SafeMath.sub(
_PriceVsUSD,
SafeMath.div(SafeMath.mul(_PriceVsUSD, 3), 100)
);
uint256 MaxPus = SafeMath.add(
_PriceVsUSD,
SafeMath.div(SafeMath.mul(_PriceVsUSD, 3), 100)
);
if (O2Price != 0) {
if (O2Price > MaxPus) {
_PriceVsUSD = MaxPus;
} else if (O2Price < MinPus) {
_PriceVsUSD = MinPus;
} else {
_PriceVsUSD = O2Price;
}
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
@checkOracle1Price(address Coin) returns (uint256);
This function checks the current price of the integrated onChain Oracle.
The return value is a USD price in 18 digit format
*/
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function checkOracle1Price(address Coin) public view returns (uint256) {
uint256 Prounds = _Oracle[Coin].length;
uint256 RoundCount = 0;
uint256 sum = 0;
if (Prounds > 10) {
for (uint256 i = Prounds - 10; i < Prounds; i++) {
sum += _Oracle[Coin][i];
RoundCount++;
}
} else {
for (uint256 i = 0; i < Prounds; i++) {
sum += _Oracle[Coin][i];
RoundCount++;
}
}
sum = SafeMath.div(sum, RoundCount);
return sum;
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
@checkOracle2Price(address Coin) returns (uint256);
This function checks the current price of the UniswapV2 Oracle.
The return value is a USD price in 18 digit format
*/
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function checkOracle2Price(address Coin) public view returns (uint256) {
address UniPair = IUniswapV2Factory(
IUniswapV2Router02(address(_uniswapV2Router)).factory()
).getPair(Coin, _USDC);
if (UniPair != address(0)) {
IUniswapV2Pair pair = IUniswapV2Pair(UniPair);
IERC20 token1 = IERC20(pair.token1());
(uint256 Res0, uint256 Res1, ) = pair.getReserves();
// decimals
uint256 res0 = Res0 * (10**token1.decimals());
uint256 make = SafeMath.mul(SafeMath.div(res0, Res1), 10**12);
return make;
} else {
return 0;
}
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
@setPriceOracle(address Coin, uint256[] memory Price) returns (bool);
This function adds new prices to the onChain Oracle.
The prices are saved as USD prices and in 18 digit format
*/
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function setPriceOracle(address Coin, uint256[] memory Price)
public
onlyOwner
returns (bool)
{
if (Price.length > 1) {
_Oracle[Coin] = Price;
} else {
_Oracle[Coin].push(Price[0]);
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
@calcNFMAmount(address Coin,uint256 amount,uint256 offchainOracle) returns (bool,uint256,uint256,bool,bool);
This function calculates the NFM amount to exchange against the trade currency
Amount must be passed in the currency format of the respective trading currency. (Example 10 USDC => 10000000 USDC)
The offchain oracle price must be passed in 6 digit format (Example 125,25 US$ => 125250000 US$). If the price of the offchain
oracle is 0, the median price is automatically determined
*/
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function calcNFMAmount(
address Coin,
uint256 amount,
uint256 offchainOracle
)
public
view
returns (
bool check,
uint256 NFMsAmount,
uint256 MedianPrice,
bool MaxPrice,
bool MinPrice
)
{
uint256 NFMs;
uint256 CoinDecimals = IERC20(address(Coin)).decimals();
if (CoinDecimals < 18) {
amount = amount * 10**(SafeMath.sub(18, CoinDecimals));
}
offchainOracle = offchainOracle * 10**12;
uint256 Oracle2;
if (Coin == _USDC) {
Oracle2 = 1 * 10**18;
} else {
Oracle2 = checkOracle2Price(Coin);
}
uint256 Oracle = checkOracle1Price(Coin);
//Calculate pricerange
uint256 median;
if (offchainOracle == 0 && Oracle2 == 0) {
median = Oracle;
} else if (offchainOracle == 0 && Oracle2 > 0) {
median = SafeMath.div(SafeMath.add(Oracle2, Oracle), 2);
} else {
median = SafeMath.div(
SafeMath.add(SafeMath.add(offchainOracle, Oracle2), Oracle),
3
);
}
//Allow max 3% Price Change downside
uint256 MinRange = SafeMath.sub(
Oracle,
SafeMath.div(SafeMath.mul(Oracle, 3), 100)
);
//Allow max 3% Price Change upside
uint256 MaxRange = SafeMath.add(
Oracle,
SafeMath.div(SafeMath.mul(Oracle, 3), 100)
);
//Check if MedianPrice is in Range
if (median > MaxRange) {
median = MaxRange;
} else if (median < MinRange) {
median = MinRange;
} else {
median = median;
}
uint256 MulAmount = SafeMath.mul(amount, median);
//Calculate NFM Amount on USD Price;
uint256 FullUSDAmount = SafeMath.div(MulAmount, 10**18);
bool MaxVal = true;
bool MinVal = true;
if (FullUSDAmount > _MaxUSD) {
MaxVal = false;
}
if (FullUSDAmount < _MinUSD) {
MinVal = false;
}
NFMs = SafeMath.div(SafeMath.mul(FullUSDAmount, 10**18), _PriceVsUSD);
return (true, NFMs, median, MaxVal, MinVal);
///NOW TRANSFER
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
@SwapCoinVsNFM(address Coin, uint256 amount, uint256 offchainOracle) returns (bool);
This function performs the swap.
Amount must be passed in the currency format of the respective trading currency. (Example 10 USDC => 10000000 USDC)
The offchain oracle price must be passed in 6 digit format (Example 125,25 US$ => 125250000 US$). If the price of the offchain
oracle is 0, the median price is automatically determined
***Before this function can be executed. Buyer must approve the amount to be exchanged to this contract.***
*/
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function SwapCoinVsNFM(
address Coin,
uint256 amount,
uint256 offchainOracle
) public returns (bool) {
require(_isCurrencyAllowed[Coin] == true, "!C");
uint256 latestprice = INfmOracle(_OracleAdr)._getLatestPrice(Coin);
if (latestprice > 0) {
offchainOracle = SafeMath.div(offchainOracle + latestprice, 2);
}
if (_PreSaleMode == true) {
require(
_PreSaleStart < block.timestamp &&
_PreSaleEnd > block.timestamp,
"OoT"
);
}
require(
IERC20(address(Coin)).allowance(msg.sender, address(this)) >=
amount,
"<A"
);
(
,
uint256 NFMsAmount,
uint256 MedianPrice,
bool MaxPrice,
bool MinPrice
) = calcNFMAmount(Coin, amount, offchainOracle);
require(MaxPrice == true, ">EA");
require(MinPrice == true, "<EA");
require(
NFMsAmount <=
IERC20(address(_Controller._getNFM())).balanceOf(address(this)),
"<NFM"
);
if (block.timestamp > _OracleTimer) {
_Oracle[Coin].push(MedianPrice);
_OracleTimer = _OracleTimer + 3600;
if (_isFixedPrice == false) {
updateSetFixedPrice();
}
}
require(
IERC20(address(Coin)).transferFrom(
msg.sender,
address(this),
amount
) == true,
"<A"
);
require(
IERC20(address(_Controller._getNFM())).transfer(
msg.sender,
NFMsAmount
)
);
emit Trade(msg.sender, Coin, amount, NFMsAmount, block.timestamp);
return true;
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/*
@withdraw(address Coin, address To, uint256 amount, bool percent) returns (bool);
This function is responsible for the withdraw.
There are 3 ways to initiate payouts. Either as a fixed amount, the full amount or a percentage of the balance.
Fixed Amount => Address Coin, Address Receiver, Fixed Amount, false
Total Amount => Address Coin, Address Receiver, 0, false
A percentage => Address Coin, Address Receiver, percentage, true
*/
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
function withdraw(
address Coin,
address To,
uint256 amount,
bool percent
) public onlyOwner returns (bool) {
require(To != address(0), "0A");
uint256 CoinAmount = IERC20(address(Coin)).balanceOf(address(this));
if (percent == true) {
//makeCalcs on Percentatge
uint256 AmountToSend = SafeMath.div(
SafeMath.mul(CoinAmount, amount),
100
);
IERC20(address(Coin)).transfer(To, AmountToSend);
return true;
} else {
if (amount == 0) {
IERC20(address(Coin)).transfer(To, CoinAmount);
} else {
IERC20(address(Coin)).transfer(To, amount);
}
return true;
}
}
}