Initial commit

This commit is contained in:
bakatrouble 2022-07-25 18:40:16 +03:00
commit 843daad632
21 changed files with 47507 additions and 0 deletions

39
.gitignore vendored Normal file
View File

@ -0,0 +1,39 @@
# directories
.yarn/*
!.yarn/patches
!.yarn/releases
!.yarn/plugins
!.yarn/sdks
!.yarn/versions
**/artifacts
**/build
**/cache
**/coverage
**/.coverage_artifacts
**/.coverage_cache
**/.coverage_contracts
**/dist
**/node_modules
.idea/*
# files
*.env
*.log
.pnp.*
coverage.json
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# types
src/types/*
!src/types/common.ts
!src/types/Greeter.ts
# factories
!src/types/factories
src/types/factories/*
!src/types/factories/Greeter__factory.ts
typechain/*
.vscode/

6
contracts/furnace.sol Normal file
View File

@ -0,0 +1,6 @@
// SPDX-License-Identifier: Unlicensed
pragma solidity ^0.8.14;
contract RedFurnace {}

View File

@ -0,0 +1,7 @@
// SPDX-License-Identifier: Unlicensed
pragma solidity ^0.8.14;
interface INFT {
function raiseRewardPool(uint256 amount) external;
}

View File

@ -0,0 +1,316 @@
// SPDX-License-Identifier: Unlicensed
pragma solidity ^0.8.14;
interface IPancakeSwapPair {
event Approval(address indexed owner, address indexed spender, uint256 value);
event Transfer(address indexed from, address indexed to, uint256 value);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
function totalSupply() external view returns (uint256);
function balanceOf(address owner) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transfer(address to, uint256 value) external returns (bool);
function transferFrom(
address from,
address to,
uint256 value
) external returns (bool);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint256);
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
event Mint(address indexed sender, uint256 amount0, uint256 amount1);
event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to);
event Swap(
address indexed sender,
uint256 amount0In,
uint256 amount1In,
uint256 amount0Out,
uint256 amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint256);
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);
function mint(address to) external returns (uint256 liquidity);
function burn(address to) external returns (uint256 amount0, uint256 amount1);
function swap(
uint256 amount0Out,
uint256 amount1Out,
address to,
bytes calldata data
) external;
function skim(address to) external;
function sync() external;
function initialize(address, address) external;
}
interface IPancakeSwapRouter {
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 removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountA, uint256 amountB);
function removeLiquidityETHWithPermit(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) 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);
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;
}
interface IPancakeSwapFactory {
event PairCreated(address indexed token0, address indexed token1, address pair, uint256);
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function getPair(address tokenA, address tokenB) external view returns (address pair);
function allPairs(uint256) external view returns (address pair);
function allPairsLength() external view returns (uint256);
function createPair(address tokenA, address tokenB) external returns (address pair);
function setFeeTo(address) external;
function setFeeToSetter(address) external;
}

View File

@ -0,0 +1,8 @@
// SPDX-License-Identifier: Unlicensed
pragma solidity ^0.8.14;
interface ITreasury {
function isAdmin(address who) external returns (bool);
function isOperator(address who) external returns (bool);
}

148
contracts/market.sol Normal file
View File

@ -0,0 +1,148 @@
// SPDX-License-Identifier: Unlicensed
//mostly done
//смерть русні
pragma solidity ^0.8.14;
import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "./interfaces/ITreasury.sol";
contract Marketplace is Initializable {
//variables
uint256 currentSaleId;
uint256 fee;
ITreasury treasury;
IERC721Upgradeable nft;
IERC20Upgradeable BoM;
struct Sale {
address payable seller;
uint256 tokenId;
uint256 price;
}
mapping(uint256 => Sale) saleIdToSale;
//events
event SaleCreated(
uint256 indexed saleId,
address indexed seller,
uint256 price,
uint256 indexed tokenId
);
event SaleCancelled(uint256 indexed saleId);
event SaleUpdated(
uint256 indexed saleId,
uint256 oldPrice,
uint256 newPrice
);
event TokenBought(
uint256 indexed saleId,
address indexed buyer,
uint256 indexed tokenId,
uint256 price
);
event FeesChanged(address indexed admin, uint256 oldFee, uint256 newFee);
//modifiers
modifier isExistingSale(uint256 saleId) {
require(saleIdToSale[saleId].price != 0);
_;
}
modifier onlySaleOwner(uint256 saleId) {
require(saleIdToSale[saleId].seller == msg.sender);
_;
}
modifier onlyValidPrice(uint256 price) {
require(price > 0);
_;
}
modifier onlyAdmin() {
require(treasury.isAdmin(msg.sender));
_;
}
// constructor(
// uint256 _fee,
// ITreasury _treasury,
// IERC721Upgradeable _nft,
// IERC20Upgradeable token
// ) {
// fee = _fee;
// treasury = _treasury;
// nft = _nft;
// BoM = token;
// }
function initialize(
uint256 _fee,
ITreasury _treasury,
IERC721Upgradeable _nft,
IERC20Upgradeable token
) public initializer {
fee = _fee;
treasury = _treasury;
nft = _nft;
BoM = token;
}
//internal functions
function _distributeFunds(uint256 amount, address seller) internal {
uint256 _fee = (amount * fee) / 10000;
uint256 goesToSeller = amount - _fee;
BoM.transferFrom(msg.sender, address(this), _fee);
BoM.transferFrom(msg.sender, seller, goesToSeller);
}
//external functions
function createSale(uint256 tokenId, uint256 price)
public
onlyValidPrice(price)
{
currentSaleId++;
Sale memory sale = saleIdToSale[currentSaleId];
sale.seller = payable(msg.sender);
sale.price = price;
sale.tokenId = tokenId;
nft.transferFrom(msg.sender, address(this), tokenId);
emit SaleCreated(currentSaleId, msg.sender, price, tokenId);
}
function cancelSale(uint256 saleId) public onlySaleOwner(saleId) {
Sale memory sale = saleIdToSale[saleId];
nft.transferFrom(address(this), msg.sender, sale.tokenId);
delete sale;
emit SaleCancelled(saleId);
}
function updateSale(uint256 saleId, uint256 price)
public
onlySaleOwner(saleId)
onlyValidPrice(price)
isExistingSale(saleId)
{
Sale memory sale = saleIdToSale[saleId];
uint256 oldPrice = sale.price;
sale.price = price;
emit SaleUpdated(saleId, oldPrice, price);
}
function buyToken(uint256 saleId) public isExistingSale(saleId) {
Sale memory sale = saleIdToSale[saleId];
nft.transferFrom(address(this), msg.sender, sale.tokenId);
_distributeFunds(sale.price, sale.seller);
emit TokenBought(saleId, msg.sender, sale.tokenId, sale.price);
}
//admin functions
function changeFees(uint256 _fee) public onlyAdmin {
require(_fee > 0 && _fee < 2000);
emit FeesChanged(msg.sender, fee, _fee);
fee = _fee;
}
}

View File

@ -0,0 +1,102 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity ^0.8.15;
import "@openzeppelin/contracts-upgradeable/utils/math/SafeMathUpgradeable.sol";
/**
* @title SafeMathInt
* @dev Math operations for int256 with overflow safety checks.
*/
library SafeMathInt {
int256 private constant MIN_INT256 = int256(1) << 255;
int256 private constant MAX_INT256 = ~(int256(1) << 255);
/**
* @dev Multiplies two int256 variables and fails on overflow.
*/
function mul(int256 a, int256 b) internal pure returns (int256) {
int256 c = a * b;
// Detect overflow when multiplying MIN_INT256 with -1
require(c != MIN_INT256 || (a & MIN_INT256) != (b & MIN_INT256));
require((b == 0) || (c / b == a));
return c;
}
/**
* @dev Division of two int256 variables and fails on overflow.
*/
function div(int256 a, int256 b) internal pure returns (int256) {
// Prevent overflow when dividing MIN_INT256 by -1
require(b != -1 || a != MIN_INT256);
// Solidity already throws when dividing by 0.
return a / b;
}
/**
* @dev Subtracts two int256 variables and fails on overflow.
*/
function sub(int256 a, int256 b) internal pure returns (int256) {
int256 c = a - b;
require((b >= 0 && c <= a) || (b < 0 && c > a));
return c;
}
/**
* @dev Adds two int256 variables and fails on overflow.
*/
function add(int256 a, int256 b) internal pure returns (int256) {
int256 c = a + b;
require((b >= 0 && c >= a) || (b < 0 && c < a));
return c;
}
/**
* @dev Converts to absolute value, and fails on overflow.
*/
function abs(int256 a) internal pure returns (int256) {
require(a != MIN_INT256);
return a < 0 ? -a : a;
}
/**
* @dev Computes 2^exp with limited precision where -100 <= exp <= 100 * one
* @param one 1.0 represented in the same fixed point number format as exp
* @param exp The power to raise 2 to -100 <= exp <= 100 * one
* @return 2^exp represented with same number of decimals after the point as one
*/
function twoPower(int256 exp, int256 one) internal pure returns (int256) {
bool reciprocal = false;
if (exp < 0) {
reciprocal = true;
exp = abs(exp);
}
// Precomputed values for 2^(1/2^i) in 18 decimals fixed point numbers
int256[5] memory ks = [
int256(1414213562373095049),
1189207115002721067,
1090507732665257659,
1044273782427413840,
1021897148654116678
];
int256 whole = div(exp, one);
require(whole <= 100);
int256 result = mul(int256(uint256(1) << uint256(whole)), one);
int256 remaining = sub(exp, mul(whole, one));
int256 current = div(one, 2);
for (uint256 i = 0; i < 5; i++) {
if (remaining >= current) {
remaining = sub(remaining, current);
result = div(mul(result, ks[i]), 10**18); // 10**18 to match hardcoded ks values
}
current = div(current, 2);
}
if (reciprocal) {
result = div(mul(one, one), result);
}
return result;
}
}

View File

@ -0,0 +1,40 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity ^0.8.14;
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol";
abstract contract RoleControl is AccessControlUpgradeable {
bytes32 OPERATOR_ROLE = bytes32("OPERATOR_ROLE");
function isAdmin(address account) public view returns(bool) {
return hasRole(DEFAULT_ADMIN_ROLE, account);
}
modifier onlyAdmin() {
require(isAdmin(msg.sender));
_;
}
function grantOperator(address account) public onlyAdmin {
grantRole(OPERATOR_ROLE, account);
}
function isOperator(address account) public view returns(bool) {
return hasRole(OPERATOR_ROLE, account);
}
modifier onlyOperator() {
require(isAdmin(msg.sender));
_;
}
function grantAdminRole(address account) public onlyAdmin {
grantRole(DEFAULT_ADMIN_ROLE, account);
}
}

View File

@ -0,0 +1,31 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity ^0.8.14;
import "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol";
contract SignatureControl {
function _toEthSignedMessage(bytes memory message) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", StringsUpgradeable.toString(message.length), message));
}
function _toAsciiString(address x) internal pure returns (string memory) {
bytes memory s = new bytes(42);
s[0] = "0";
s[1] = "x";
for (uint256 i = 0; i < 20; i++) {
bytes1 b = bytes1(uint8(uint256(uint160(x)) / (2**(8 * (19 - i)))));
bytes1 hi = bytes1(uint8(b) / 16);
bytes1 lo = bytes1(uint8(b) - 16 * uint8(hi));
s[2 * i + 2] = _char(hi);
s[2 * i + 3] = _char(lo);
}
return string(s);
}
function _char(bytes1 b) private pure returns (bytes1 c) {
if (uint8(b) < 10) return bytes1(uint8(b) + 0x30);
else return bytes1(uint8(b) + 0x57);
}
}

711
contracts/nft.sol Normal file
View File

@ -0,0 +1,711 @@
// SPDX-License-Identifier: Unlicensed
pragma solidity ^0.8.14;
import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/utils/Base64Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";
import "./interfaces/ITreasury.sol";
import "./interfaces/IPancake.sol";
import "./mixins/signature-control.sol";
contract NFT is ERC721EnumerableUpgradeable, SignatureControl {
using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
using SafeERC20Upgradeable for IERC20Upgradeable;
//variables
bool pause = true;
uint256 nonce;
ITreasury treasury;
IERC20Upgradeable BoM;
address redTrustFund;
IPancakeSwapPair public pairContract;
IPancakeSwapRouter public swapRouter;
uint256 treasuryFee;
uint256 redTrustFee;
uint256 rewardPoolFee;
uint256 supply;
uint256 wethInRewardPool;
uint256 busdInLotteryPool;
mapping(uint256 => uint256) mintCapOfToken;
mapping(uint256 => address[]) tokenIdToType;
mapping(address => mapping(uint256 => uint256)) tokensOwnedOfType;
mapping(uint256 => bool) usedNonces;
//mint prices, caps, addresses of reward tokens(shiba,floki,doggy,doge)
uint256[4] prices = [
300 * 10**18,
250 * 10**18,
200 * 10**18,
250 * 10**18
];
IERC20Upgradeable BUSD;
IERC20Upgradeable WETH;
mapping(address => uint256) tokenToPrices;
uint256[4] nftCaps = [1000, 1500, 2000, 1500];
address[4] public rewardTokens = [
0x0000000000000000000000000000000000000000,
0x0000000000000000000000000000000000000000,
0x0000000000000000000000000000000000000000,
0x0000000000000000000000000000000000000000
];
mapping(address => uint256) addressToType;
mapping(address => uint256) totalRatesForType;
mapping(address => mapping(address => uint256)) addrerssToRatesForType;
uint256[5] rewardPoolForToken;
uint256[5] rewardsPerShareStored;
uint256[5] lastUpdatePools;
mapping(address => uint256[5]) accountShares;
uint256[5] totalShares;
mapping(address => mapping(uint256 => uint256)) accountRewards;
mapping(address => mapping(uint256 => uint256)) accountRewardsPerTokenPaid;
//whitelist shit
bool public isPresale = true;
uint256 whitelistPrice = 200 ether;
uint256 maxMintPerAddressDuringWhitelist = 5;
uint256 whitelistMintCapPerType = 250;
mapping(address => bool) isWhitelisted;
mapping(address => uint256) mintedOnWhitelist;
mapping(uint256 => uint256) whitelistMintCapOfToken;
EnumerableSetUpgradeable.AddressSet _holders; // TODO: migrate?
uint256 statMultiplier = 100000;
mapping(uint256 => TokenInfo) tokenIdToInfo;
struct TokenInfo {
string image;
address[] tokens;
uint256 rate;
uint256 attack;
uint256 defense;
uint256 health;
uint256 critChance;
uint256 critDmg;
uint256 recover;
}
mapping(address => Tokenomic) addressToToken;
struct Tokenomic {
uint256 stakingRate;
uint256 attack;
uint256 defense;
uint256 health;
uint256 critChance;
uint256 critDmg;
uint256 recovery;
}
event TokenMinted(
address indexed minter,
uint256 tokenId,
address token,
uint256 rate
);
event TokenCombined(
address indexed user,
uint256[] burntTokens,
address[] tokens,
uint256 tokenId,
uint256 rate
);
event RewardPoolRaised(uint256 amount);
event LotteryPoolRaised(uint256 amount);
//modifiers
modifier onlyAdmin() {
require(treasury.isAdmin(msg.sender));
_;
}
modifier isUnpaused() {
require(!pause);
_;
}
modifier isValidWhitelistMint(uint256 amount, uint256 tokenType) {
require(isPresale);
require(isWhitelisted[msg.sender]);
require(
mintedOnWhitelist[msg.sender] + amount <=
maxMintPerAddressDuringWhitelist
);
require(tokenType <= 3);
require(
whitelistMintCapOfToken[tokenType] + amount <=
whitelistMintCapPerType
);
_;
}
modifier isValidMint(uint256 amount, uint256 tokenType) {
require(!isPresale);
require(tokenType <= 3);
require(mintCapOfToken[tokenType] + amount <= nftCaps[tokenType]);
_;
}
modifier isValidCombine(uint256[] memory tokenIds) {
require(tokenIds.length > 1 && tokenIds.length <= 4);
bool hasDupes;
for (uint256 i = 0; i < tokenIds.length; i++) {
require(ownerOf(tokenIds[i]) == msg.sender);
require(tokenIdToType[tokenIds[i]].length == 1);
for (uint256 index = i; index < tokenIds.length; index++) {
if (
index != i &&
tokenIdToType[tokenIds[i]][0] ==
tokenIdToType[tokenIds[index]][0]
) {
hasDupes = true;
}
}
require(!hasDupes);
}
_;
}
function initialize(
string memory name,
string memory symbol,
ITreasury _treasury,
address _redTrustFund,
IERC20Upgradeable token,
uint256 _rewardFee,
uint256 _treasuryFee,
uint256 _redTrustFee,
IPancakeSwapPair _pair,
IPancakeSwapRouter _router,
IERC20Upgradeable _BUSD,
IERC20Upgradeable _WETH
) public initializer {
treasury = _treasury;
BoM = token;
__ERC721_init(name, symbol);
redTrustFund = _redTrustFund;
rewardPoolFee = _rewardFee;
redTrustFee = _redTrustFee;
treasuryFee = _treasuryFee;
uint16[4] memory attack = [1000, 1000, 700, 850];
uint16[4] memory defense = [800, 1000, 850, 1000];
uint16[4] memory health = [800, 800, 1000, 850];
uint16[4] memory critChance = [400, 200, 400, 300];
uint16[4] memory critDmg = [600, 500, 800, 500];
uint16[4] memory recovery = [600, 700, 1000, 900];
for (uint256 i = 0; i < 4; i++) {
addressToToken[rewardTokens[i]].attack = attack[i];
addressToToken[rewardTokens[i]].defense = defense[i];
addressToToken[rewardTokens[i]].health = health[i];
addressToToken[rewardTokens[i]].critChance = critChance[i];
addressToToken[rewardTokens[i]].critDmg = critDmg[i];
addressToToken[rewardTokens[i]].recovery = recovery[i];
tokenToPrices[rewardTokens[i]] = prices[i];
addressToType[rewardTokens[i]] = i;
}
pairContract = _pair;
swapRouter = _router;
BUSD = _BUSD;
WETH = _WETH;
}
function addWhitelist(address[] memory whitelist) public onlyAdmin {
for (uint256 i = 0; i < whitelist.length; i++) {
isWhitelisted[whitelist[i]] = true;
}
}
function mintPresale(uint256 amount, uint256 tokenType)
public
isUnpaused
isValidWhitelistMint(amount, tokenType)
{
for (uint256 i = 0; i < amount; i++) {
supply++;
_mint(msg.sender, supply);
tokenIdToType[supply].push(rewardTokens[tokenType]);
uint256 rate = createTokenStats(supply);
emit TokenMinted(msg.sender, supply, rewardTokens[tokenType], rate);
}
mintedOnWhitelist[msg.sender] += amount;
whitelistMintCapOfToken[tokenType] += amount;
mintCapOfToken[tokenType] += amount;
//TBD: swap to bnb
_distributeFunds(amount * whitelistPrice);
}
function mint(uint256 amount, uint256 tokenType)
public
isUnpaused
isValidMint(amount, tokenType)
{
for (uint256 i = 0; i < amount; i++) {
supply++;
_mint(msg.sender, supply);
tokenIdToInfo[supply].tokens.push(rewardTokens[tokenType]);
uint256 rate = createTokenStats(supply);
emit TokenMinted(msg.sender, supply, rewardTokens[tokenType], rate);
}
mintCapOfToken[tokenType] += amount;
//TBD: swap to bnb
_distributeFunds(amount * prices[tokenType]);
}
function combineTokens(uint256[] memory tokenIds)
public
payable
isUnpaused
{
require(msg.value == 0.05 ether);
supply++;
uint256 price;
_mint(msg.sender, supply);
address[] memory tokens = new address[](tokenIds.length);
for (uint256 i = 0; i < tokenIds.length; i++) {
TokenInfo storage token = tokenIdToInfo[tokenIds[i]];
address intermediateStorageForToken = tokenIdToType[tokenIds[i]][0];
tokenIdToInfo[supply].tokens.push(intermediateStorageForToken);
tokens[i] = intermediateStorageForToken;
_burn(tokenIds[i]);
price += tokenToPrices[tokenIdToType[tokenIds[i]][0]] / 4;
for (uint256 index = 0; index < token.tokens.length; index++) {
totalRatesForType[token.tokens[index]] -= token.rate;
}
}
uint256 rate = createTokenStats(supply);
emit TokenCombined(msg.sender, tokenIds, tokens, supply, rate);
//TBD: calculate price with usd in mind
_distributeFunds(price);
}
function createTokenStats(uint256 tokenId) internal returns (uint256 rate) {
TokenInfo storage token = tokenIdToInfo[tokenId];
uint256[7] memory seeds;
for (uint8 i = 0; i < 7; i++) {
nonce++;
seeds[i] = (
uint256(
keccak256(
abi.encodePacked(msg.sender, block.timestamp, nonce)
)
)
);
}
if (token.tokens.length == 1) {
uint256 rateMod = (seeds[0] % 100) + 1;
if (rateMod == 1) {
token.rate = 2000;
} else if (rateMod <= 3) {
token.rate = 1750;
} else if (rateMod <= 10) {
token.rate = 1500;
} else if (rateMod <= 20) {
token.rate = 1250;
} else {
token.rate = 1000;
}
} else if (token.tokens.length == 2) {
token.rate = 2250;
} else if (token.tokens.length == 3) {
token.rate = 2500;
} else {
token.rate = 3000;
}
rate = token.rate;
for (uint256 i = 0; i < token.tokens.length; i++) {
totalRatesForType[token.tokens[i]] += token.rate;
}
createBattleStats(seeds, token, getStatMultipliers(token));
}
function createBattleStats(
uint256[7] memory seeds,
TokenInfo storage token,
uint256[6] memory statMultipliers
) internal {
token.attack =
(((seeds[1] % 71) + 30) * (token.rate * statMultipliers[0])) /
statMultiplier;
token.defense =
(((seeds[2] % 71) + 30) * (token.rate * statMultipliers[1])) /
statMultiplier;
token.health =
(((seeds[3] % 51) + 50) * (token.rate * statMultipliers[2])) /
statMultiplier;
token.critChance =
(((seeds[4] % 41) + 30) * (token.rate * statMultipliers[3])) /
statMultiplier;
token.critDmg =
(((seeds[5] % 61) + 10) * (token.rate * statMultipliers[4])) /
statMultiplier;
token.recover =
(((seeds[6] % 51) + 50) * (token.rate * statMultipliers[5])) /
statMultiplier;
}
function getStatMultipliers(TokenInfo storage token)
internal
view
returns (uint256[6] memory statMultipliers)
{
uint16[4] memory megaStatMultipliers = [1000, 1250, 1500, 2000];
for (uint8 i = 0; i < token.tokens.length; i++) {
Tokenomic memory tokenomic = addressToToken[token.tokens[i]];
statMultipliers[0] += tokenomic.attack;
statMultipliers[1] += tokenomic.defense;
statMultipliers[2] += tokenomic.health;
statMultipliers[3] += tokenomic.critChance;
statMultipliers[4] += tokenomic.critDmg;
statMultipliers[5] += tokenomic.recovery;
}
for (uint8 i = 0; i < 6; i++) {
statMultipliers[i] =
(statMultipliers[i] / token.tokens.length) *
megaStatMultipliers[token.tokens.length - 1];
}
}
function _distributeFunds(uint256 amount) internal {
uint256[] memory requiredAmountOfTokens = _getAmountsIn(
amount,
address(BoM),
address(WETH)
);
require(
BoM.allowance(msg.sender, address(this)) >=
requiredAmountOfTokens[0],
"allowance too low"
);
BoM.transferFrom(msg.sender, address(this), requiredAmountOfTokens[0]);
uint256 bnbAmount = _swap(
amount,
requiredAmountOfTokens[0],
address(BoM),
address(WETH)
)[0];
uint256 _treasuryFee = (bnbAmount * treasuryFee) / 1000;
uint256 _redTrustFee = (bnbAmount * redTrustFee) / 1000;
uint256 _rewardPoolFee = bnbAmount - _treasuryFee - _redTrustFee;
BoM.transferFrom(msg.sender, address(treasury), _treasuryFee);
BoM.transferFrom(msg.sender, redTrustFund, _redTrustFee);
BoM.transferFrom(msg.sender, address(this), _rewardPoolFee);
_addToPool(_rewardPoolFee);
}
function lottery() public onlyAdmin {
require(busdInLotteryPool > 0, "no funds in lottery pool");
uint256[10] memory seeds;
uint256 holdersCount = _holders.length();
uint256 winnersCount = holdersCount;
if (winnersCount > 10) {
winnersCount = 10;
for (uint8 i = 0; i < winnersCount; i++) {
nonce++;
uint256 idx = (
uint256(
keccak256(
abi.encodePacked(msg.sender, block.timestamp, blockhash(block.number - 1), nonce)
)
)
) % holdersCount;
while (true) {
bool retry = false;
for (uint8 j=0; j < i; j++) {
if (idx == seeds[j]) {
retry = true;
idx = (idx + 1) % holdersCount;
break;
}
}
if (!retry)
break;
}
seeds[i] = idx;
}
} else {
for (uint8 i=0; i < winnersCount; i++) {
seeds[i] = i;
}
}
uint256 winEach = 100 ether;
if (busdInLotteryPool < (100 ether * winnersCount))
winEach = busdInLotteryPool / winnersCount;
for (uint256 i = 0; i < winnersCount; i++) {
BUSD.safeTransfer(_holders.at(seeds[i]), winEach);
}
}
function _getAmountsIn(
uint256 price,
address path0,
address path1
) internal view returns (uint256[] memory) {
address[] memory path;
path[0] = path0;
path[1] = path1;
return swapRouter.getAmountsIn(price, path);
}
function _swap(
uint256 amount,
uint256 price,
address path0,
address path1
) internal returns (uint256[] memory) {
address[] memory path;
path[0] = path0;
path[1] = path1;
return
swapRouter.swapTokensForExactTokens(
amount,
price,
path,
address(this),
block.timestamp
);
// return
// swapRouter.swapTokensForExactETH(
// price,
// amount,
// path,
// address(this),
// block.timestamp
// );
}
// function isValidClaim(
// uint256[] memory tokenAmounts,
// bytes memory signature,
// uint256 userNonce,
// uint256 timestamp
// ) internal returns (bool) {
// bytes memory data = abi.encodePacked(
// _toAsciiString(msg.sender),
// " is authorized to claim ",
// StringsUpgradeable.toString(tokenAmounts[0]),
// " shiba, ",
// StringsUpgradeable.toString(tokenAmounts[1]),
// " floki, ",
// StringsUpgradeable.toString(tokenAmounts[2]),
// " doggy, ",
// StringsUpgradeable.toString(tokenAmounts[3]),
// " doge before ",
// StringsUpgradeable.toString(timestamp),
// ", ",
// StringsUpgradeable.toString(userNonce)
// );
// bytes32 hash = _toEthSignedMessage(data);
// address signer = ECDSAUpgradeable.recover(hash, signature);
// require(treasury.isOperator(signer), "Mint not verified by operator");
// require(block.timestamp <= timestamp, "Outdated signed message");
// require(!usedNonces[userNonce], "Used nonce");
// return true;
// }
//
// function claimRewards(
// uint256[] memory amounts,
// bytes memory signature,
// uint256 userNonce,
// uint256 timestamp
// ) public {
// require(isValidClaim(amounts, signature, userNonce, timestamp), "");
// for (uint256 i = 0; i < 4; i++) {
// if (amounts[i] > 0) {
// address[] memory path;
// path[0] = address(WETH);
// path[1] = rewardTokens[i];
// swapRouter.swapExactTokensForTokens(
// amounts[i],
// 1,
// path,
// msg.sender,
// block.timestamp
// );
// }
// }
// }
function walletOfOwner(address _owner)
public
view
returns (uint256[] memory)
{
uint256 ownerTokenCount = balanceOf(_owner);
uint256[] memory tokenIds = new uint256[](ownerTokenCount);
for (uint256 i; i < ownerTokenCount; i++) {
tokenIds[i] = tokenOfOwnerByIndex(_owner, i);
}
return tokenIds;
}
function tokenURI(uint256 tokenId)
public
view
override
returns (string memory)
{
require(_exists(tokenId), "Non-existant token");
TokenInfo storage token = tokenIdToInfo[tokenId];
return
string(
abi.encodePacked(
"data:application/json;base64,",
Base64Upgradeable.encode(
bytes(
abi.encodePacked(
'{"name": Babies of Mars #',
tokenId,
', "description": "adasdasdasd", "image": ',
token.image,
',{ "attributes": [ {"trait_type": "tokens", "value": ',
token.tokens,
'}, { "trait_type": "attack", "value": ',
token.attack,
'}, { "trait_type": "defense", "value": ',
token.defense,
'}, { "trait_type": "health", "value": ',
token.health,
'}, { "trait_type": "critical rate", "value": ',
token.critChance,
'}, { "trait_type": "critical damage", "value": ',
token.critDmg,
'}, { "trait_type": "recovery", "value": ',
token.recover,
"} ] }"
)
)
)
)
);
}
function raiseRewardPool(uint256 amount) public {
require(
BoM.allowance(msg.sender, address(this)) >= amount,
"Not enough allowance"
);
BoM.transferFrom(msg.sender, address(this), amount);
_addToPool(amount);
}
function _addToPool(uint256 amount) internal {
uint256 lotteryPoolAmount = amount / 10;
address[] memory path;
path[0] = address(BoM);
path[1] = address(BUSD);
uint256 swappedFor = swapRouter.swapExactTokensForTokens(
lotteryPoolAmount, // 10% to lottery
0,
path,
address(this),
block.timestamp
)[0];
busdInLotteryPool += swappedFor;
emit LotteryPoolRaised(swappedFor);
path[1] = address(WETH);
swappedFor = swapRouter.swapExactTokensForTokens(
amount - lotteryPoolAmount,
0,
path,
address(this),
block.timestamp
)[0];
wethInRewardPool += swappedFor;
for (uint8 i=0; i < 4; i++) {
rewardPoolForToken[i] += swappedFor * 2 / 9; // 20% of total each
}
rewardPoolForToken[4] += swappedFor - swappedFor * 8 / 9; // remaining 10%
emit RewardPoolRaised(swappedFor);
}
function _afterTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual override {
super._afterTokenTransfer(from, to, tokenId);
TokenInfo memory info = tokenIdToInfo[tokenId];
if (from != address(0)) {
if (ERC721Upgradeable.balanceOf(from) == 0) {
_holders.remove(from);
}
if (info.tokens.length > 1) {
totalShares[4] -= info.rate;
accountShares[from][4] -= info.rate;
} else {
uint256 idx = addressToType[info.tokens[0]];
totalShares[idx] -= info.rate;
accountShares[from][idx] -= info.rate;
}
}
if (to != address(0)) {
_holders.add(to);
if (info.tokens.length > 1) {
totalShares[4] += info.rate;
accountShares[to][4] += info.rate;
} else {
uint256 idx = addressToType[info.tokens[0]];
totalShares[idx] += info.rate;
accountShares[from][idx] += info.rate;
}
}
}
function pendingReward(uint256 idx, address account) public view returns (uint256) {
return accountShares[account][idx] + (_rewardPerShare(idx) - accountRewardsPerTokenPaid[account][idx]) / 1e18 + accountRewards[account][idx];
}
function _rewardPerShare(uint256 idx) internal view returns (uint256) {
if (totalShares[idx] == 0)
return rewardsPerShareStored[idx];
return rewardsPerShareStored[idx] + (rewardPoolForToken[idx] - lastUpdatePools[idx]) / totalShares[idx];
}
function _updateRewards(address account) internal {
for (uint256 i=0; i < 5; i++) {
rewardsPerShareStored[i] = _rewardPerShare(i);
lastUpdatePools[i] = rewardPoolForToken[i];
if (account != address(0)) {
accountRewards[account][i] = pendingReward(i, account);
accountRewardsPerTokenPaid[account][i] = rewardsPerShareStored[i];
}
}
}
function claimReward(uint256 idx) external {
_updateRewards(msg.sender);
uint256 reward = accountRewards[msg.sender][idx];
require(reward > 0, "nothing to claim");
accountRewards[msg.sender][idx] = 0;
address[] memory path;
path[0] = address(WETH);
path[1] = rewardTokens[idx];
uint256 swappedFor = swapRouter.swapExactTokensForTokens(
reward,
0,
path,
msg.sender,
block.timestamp
)[0];
}
}

View File

@ -0,0 +1,36 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity ^0.8.15;
import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
contract BoMNFTProxy is TransparentUpgradeableProxy {
constructor(
address _logic,
address _admin,
bytes memory _data
) public payable TransparentUpgradeableProxy(_logic, _admin, _data) {}
}
contract BoMMarketProxy is TransparentUpgradeableProxy {
constructor(
address _logic,
address _admin,
bytes memory _data
) public payable TransparentUpgradeableProxy(_logic, _admin, _data) {}
}
contract BoMTreasuryProxy is TransparentUpgradeableProxy {
constructor(
address _logic,
address _admin,
bytes memory _data
) public payable TransparentUpgradeableProxy(_logic, _admin, _data) {}
}
contract BoMTokenProxy is TransparentUpgradeableProxy {
constructor(
address _logic,
address _admin,
bytes memory _data
) public payable TransparentUpgradeableProxy(_logic, _admin, _data) {}
}

View File

@ -0,0 +1,7 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity ^0.8.15;
import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
contract BoMProxyAdmin is ProxyAdmin {
}

View File

@ -0,0 +1,28 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity ^0.8.14;
import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "./mixins/role-control.sol";
contract Treasury is RoleControl {
event TokenWithdraw(
address indexed account,
address indexed token,
uint256 amount
);
function initialize(address admin) public initializer {
_setupRole(DEFAULT_ADMIN_ROLE, admin);
}
function withdrawToken(IERC20Upgradeable token, address to, uint256 amount) public onlyAdmin {
token.transfer(to, amount);
emit TokenWithdraw(to, address(token), amount);
}
}

673
contracts/token.sol Normal file
View File

@ -0,0 +1,673 @@
// SPDX-License-Identifier: Unlicensed
pragma solidity ^0.8.15;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "./interfaces/IPancake.sol";
import "./mixins/SafeMathInt.sol";
import "./interfaces/ITreasury.sol";
import "./interfaces/INFT.sol";
contract BabiesOfMars is ERC20Upgradeable {
using SafeMathUpgradeable for uint256;
using SafeMathInt for int256;
event LogRebase(uint256 indexed epoch, uint256 totalSupply);
string public _name = "BabiesOfMars";
string public _symbol = "BoM";
uint8 public _decimals = 5;
IPancakeSwapPair public pairContract;
mapping(address => bool) _isFeeExempt;
modifier validRecipient(address to) {
require(to != address(0x0));
_;
}
modifier onlyAdmin() {
require(treasury.isAdmin(msg.sender));
_;
}
uint256 public constant DECIMALS = 5;
uint256 public constant MAX_UINT256 = ~uint256(0);
uint8 public constant RATE_DECIMALS = 7;
uint256 public liquidityFee = 300;
uint256 public gameTreasuryFee = 300;
uint256 public redTrustFee = 300;
uint256 public redFurnaceFee = 800;
uint256 public nftRewardFee = 300;
uint256 public totalFee =
liquidityFee
.add(gameTreasuryFee)
.add(redTrustFee)
.add(redFurnaceFee)
.add(nftRewardFee);
uint256 public sellFee = 200;
uint256 public feeDenominator = 10000;
address DEAD = 0x000000000000000000000000000000000000dEaD;
address ZERO = 0x0000000000000000000000000000000000000000;
address public autoLiquidityReceiver;
ITreasury public treasury;
address public redTrustWallet;
address public redFurnace;
address public pairAddress;
INFT public nftRewardPool;
bool public swapEnabled = true;
IPancakeSwapRouter public router;
IPancakeSwapPair public pair;
bool inSwap = false;
uint256 lastPrice;
uint256 defenderTimer;
bool rdStatus;
modifier swapping() {
inSwap = true;
_;
inSwap = false;
}
uint256 private constant TOTAL_GONS =
MAX_UINT256 - (MAX_UINT256 % INITIAL_FRAGMENTS_SUPPLY);
uint256 private constant INITIAL_FRAGMENTS_SUPPLY = 50_000 * 10**DECIMALS;
uint256 private constant MAX_SUPPLY = 500_000 * 10**DECIMALS;
bool public _autoRebase;
bool public _autoAddLiquidity;
uint256 public _initRebaseStartTime;
uint256 public _lastRebasedTime;
uint256 public _lastAddLiquidityTime;
uint256 public _totalSupply;
uint256 private _gonsPerFragment;
uint256 public rebaseInterval = 15 minutes;
mapping(address => uint256) private _gonBalances;
mapping(address => mapping(address => uint256)) private _allowedFragments;
mapping(address => bool) public blacklist;
function initialize(
address _router,
address _owner,
ITreasury _treasury,
address _redTrustWallet,
INFT _nftRewardPool,
address _redFurnace
) public initializer {
__ERC20_init(_name, _symbol);
router = IPancakeSwapRouter(_router);
pair = IPancakeSwapPair(
IPancakeSwapFactory(router.factory()).createPair(
router.WETH(),
address(this)
)
);
autoLiquidityReceiver = DEAD;
treasury = _treasury;
redTrustWallet = _redTrustWallet;
redFurnace = _redFurnace;
nftRewardPool = _nftRewardPool;
_allowedFragments[address(this)][address(router)] = type(uint256).max;
pairContract = IPancakeSwapPair(pair);
_totalSupply = INITIAL_FRAGMENTS_SUPPLY;
_gonBalances[_owner] = TOTAL_GONS;
_gonsPerFragment = TOTAL_GONS.div(_totalSupply);
_initRebaseStartTime = block.timestamp;
_lastRebasedTime = block.timestamp;
_autoRebase = false;
_autoAddLiquidity = true;
_isFeeExempt[_owner] = true;
_isFeeExempt[address(this)] = true;
_isFeeExempt[redTrustWallet] = true;
_isFeeExempt[address(nftRewardPool)] = true;
_isFeeExempt[address(treasury)] = true;
defenderTimer = block.timestamp;
emit Transfer(address(0x0), _owner, _totalSupply);
}
function rebase() internal {
if (inSwap) return;
uint256 rebaseRate;
uint256 deltaTimeFromInit = block.timestamp - _initRebaseStartTime;
uint256 deltaTime = block.timestamp - _lastRebasedTime;
uint256 times = deltaTime.div(rebaseInterval);
uint256 epoch = times.mul(15);
if (deltaTimeFromInit < (365 days)) {
rebaseRate = 2731;
} else if (deltaTimeFromInit >= (365 days)) {
rebaseRate = 211;
} else if (deltaTimeFromInit >= ((15 * 365 days) / 10)) {
rebaseRate = 14;
} else if (deltaTimeFromInit >= (7 * 365 days)) {
rebaseRate = 2;
}
for (uint256 i = 0; i < times; i++) {
_totalSupply = _totalSupply
.mul((10**RATE_DECIMALS).add(rebaseRate))
.div(10**RATE_DECIMALS);
}
_gonsPerFragment = TOTAL_GONS.div(_totalSupply);
_lastRebasedTime = _lastRebasedTime.add(times.mul(rebaseInterval));
pairContract.sync();
emit LogRebase(epoch, _totalSupply);
}
function transfer(address to, uint256 value)
public
override
validRecipient(to)
returns (bool)
{
_transferFrom(msg.sender, to, value);
return true;
}
function transferFrom(
address from,
address to,
uint256 value
) public override validRecipient(to) returns (bool) {
if (_allowedFragments[from][msg.sender] != type(uint256).max) {
_allowedFragments[from][msg.sender] = _allowedFragments[from][
msg.sender
].sub(value, "Insufficient Allowance");
}
_transferFrom(from, to, value);
return true;
}
function _basicTransfer(
address from,
address to,
uint256 amount
) internal returns (bool) {
uint256 gonAmount = amount.mul(_gonsPerFragment);
_gonBalances[from] = _gonBalances[from].sub(gonAmount);
_gonBalances[to] = _gonBalances[to].add(gonAmount);
return true;
}
function _transferFrom(
address sender,
address recipient,
uint256 amount
) internal returns (bool) {
require(!blacklist[sender] && !blacklist[recipient], "in_blacklist");
if (inSwap) {
return _basicTransfer(sender, recipient, amount);
}
if (shouldRebase()) {
rebase();
}
if (shouldAddLiquidity()) {
addLiquidity();
}
if (shouldSwapBack()) {
swapBack();
}
uint256 gonAmount = amount.mul(_gonsPerFragment);
_gonBalances[sender] = _gonBalances[sender].sub(gonAmount);
uint256 gonAmountReceived = shouldTakeFee(sender, recipient)
? takeFee(sender, recipient, gonAmount)
: gonAmount;
_gonBalances[recipient] = _gonBalances[recipient].add(
gonAmountReceived
);
emit Transfer(
sender,
recipient,
gonAmountReceived.div(_gonsPerFragment)
);
return true;
}
function takeFee(
address sender,
address recipient,
uint256 gonAmount
) internal returns (uint256) {
uint256 _totalFee = totalFee;
uint256 _gameTreasuryFee = gameTreasuryFee;
(uint256 impact, uint256 oldPrice, uint256 newPrice) = getImpact(
gonAmount
);
uint256 impactTax = ((gonAmount * impact) / 1000) * 4;
if (rdStatus == true) {
if (block.timestamp - defenderTimer > 0) {
// while (block.timestamp - defenderTimer > 1 hours) {
// defenderTimer += 1 hours;
// }
rdStatus = false;
} else {
runDefender(gonAmount, impactTax, sender, recipient);
}
}
if (recipient == address(pair)) {
if (impact > 100) {
runDefender(gonAmount, impactTax, sender, recipient);
}
_totalFee = totalFee.add(sellFee).add(impactTax);
_gameTreasuryFee = gameTreasuryFee.add(sellFee).add(impactTax);
}
uint256 feeAmount = gonAmount.div(feeDenominator).mul(_totalFee);
_gonBalances[redFurnace] = _gonBalances[redFurnace].add(
gonAmount.div(feeDenominator).mul(redFurnaceFee)
);
_gonBalances[address(treasury)] = _gonBalances[address(treasury)].add(
gonAmount.div(feeDenominator).mul(_gameTreasuryFee)
);
_gonBalances[redTrustWallet] = _gonBalances[redTrustWallet].add(
gonAmount.div(feeDenominator).mul(redTrustFee)
);
_gonBalances[autoLiquidityReceiver] = _gonBalances[
autoLiquidityReceiver
].add(gonAmount.div(feeDenominator).mul(liquidityFee));
approve(address(nftRewardPool), nftRewardFee);
nftRewardPool.raiseRewardPool(nftRewardFee);
emit Transfer(sender, address(treasury), _gameTreasuryFee.div(_gonsPerFragment));
emit Transfer(sender, redTrustWallet, redTrustFee.div(_gonsPerFragment));
emit Transfer(sender, redFurnace, redFurnaceFee.div(_gonsPerFragment));
return gonAmount.sub(feeAmount);
}
function getImpact(uint256 amount)
internal
view
returns (
uint256,
uint256,
uint256
)
{
uint256 price0 = pair.price0CumulativeLast();
(uint256 reserve0, uint256 reserve1, ) = pair.getReserves();
uint256 constProduct = reserve0 * reserve1;
uint256 new1Amount = reserve1 + amount;
uint256 new0Amount = constProduct / new1Amount;
uint256 amountTradedFor = reserve1 - new0Amount;
uint256 new0Price = amount / amountTradedFor;
return (((new0Price - price0) / price0) * 10000, price0, new0Price);
// return (amount*priceImpact/1000)*4;
}
function runDefender(
uint256 amount,
uint256 impact,
address sender,
address recipient
) internal {
rdStatus = true;
uint256 _liquidityFee = 200;
uint256 _redTrustFee = 500;
uint256 _treasuryFee = 300;
if (recipient == address(pair)) {
uint256 hourlyImpact;
require(
impact <= 500,
"selling with price impact of more than 5% is forbidden"
);
if (impact >= 100) {
if(block.timestamp - defenderTimer > 0) {
defenderTimer = block.timestamp;
}
defenderTimer += 1 hours;
}
uint256 impactTax = ((amount * impact) / 1000) * 4;
_treasuryFee.add(impactTax).add(700);
_liquidityFee.add(300);
_redTrustFee.add(500);
}
// uint256 _totalFee = _liquidityFee.add(_redTrustFee).add(_treasuryFee);
// uint256 feeAmount = amount.div(feeDenominator).mul(_totalFee);
_gonBalances[address(treasury)] = _gonBalances[address(treasury)].add(
amount.div(feeDenominator).mul(_treasuryFee)
);
_gonBalances[redTrustWallet] = _gonBalances[redTrustWallet].add(
amount.div(feeDenominator).mul(_redTrustFee)
);
_gonBalances[autoLiquidityReceiver] = _gonBalances[
autoLiquidityReceiver
].add(amount.div(feeDenominator).mul(liquidityFee));
emit Transfer(sender, address(treasury), _treasuryFee.div(_gonsPerFragment));
emit Transfer(sender, redTrustWallet, _redTrustFee.div(_gonsPerFragment));
// emit Transfer(
// sender,
// nftRewardPool,
// nftRewardFee.div(_gonsPerFragment)
// );
return;
}
function addLiquidity() internal swapping {
uint256 autoLiquidityAmount = _gonBalances[autoLiquidityReceiver].div(
_gonsPerFragment
);
_gonBalances[address(this)] = _gonBalances[address(this)].add(
_gonBalances[autoLiquidityReceiver]
);
_gonBalances[autoLiquidityReceiver] = 0;
uint256 amountToLiquify = autoLiquidityAmount.div(2);
uint256 amountToSwap = autoLiquidityAmount.sub(amountToLiquify);
if (amountToSwap == 0) {
return;
}
address[] memory path = new address[](2);
path[0] = address(this);
path[1] = router.WETH();
uint256 balanceBefore = address(this).balance;
router.swapExactTokensForETHSupportingFeeOnTransferTokens(
amountToSwap,
0,
path,
address(this),
block.timestamp
);
uint256 amountETHLiquidity = address(this).balance.sub(balanceBefore);
if (amountToLiquify > 0 && amountETHLiquidity > 0) {
router.addLiquidityETH{value: amountETHLiquidity}(
address(this),
amountToLiquify,
0,
0,
DEAD,
block.timestamp
);
}
_lastAddLiquidityTime = block.timestamp;
}
function swapBack() internal swapping {
uint256 amountToSwap = _gonBalances[address(this)].div(
_gonsPerFragment
);
if (amountToSwap == 0) {
return;
}
uint256 balanceBefore = address(this).balance;
address[] memory path = new address[](2);
path[0] = address(this);
path[1] = router.WETH();
router.swapExactTokensForETHSupportingFeeOnTransferTokens(
amountToSwap,
0,
path,
address(this),
block.timestamp
);
uint256 amountETHTogameTreasuryAndSIF = address(this).balance.sub(
balanceBefore
);
(bool success, ) = address(treasury).call{
value: amountETHTogameTreasuryAndSIF.mul(gameTreasuryFee).div(
gameTreasuryFee.add(redTrustFee)
),
gas: 30000
}("");
(success, ) = payable(redTrustWallet).call{
value: amountETHTogameTreasuryAndSIF.mul(redTrustFee).div(
gameTreasuryFee.add(redTrustFee)
),
gas: 30000
}("");
}
function withdrawAllToTreasury() public swapping onlyAdmin {
uint256 amountToSwap = _gonBalances[address(this)].div(
_gonsPerFragment
);
require(
amountToSwap > 0,
"There is no token deposited in token contract"
);
address[] memory path = new address[](2);
path[0] = address(this);
path[1] = router.WETH();
router.swapExactTokensForETHSupportingFeeOnTransferTokens(
amountToSwap,
0,
path,
address(treasury),
block.timestamp
);
}
function shouldTakeFee(address from, address to)
internal
view
returns (bool)
{
return
(address(pair) == from || address(pair) == to) &&
!_isFeeExempt[from] &&
!_isFeeExempt[to];
}
function shouldRebase() internal view returns (bool) {
return
_autoRebase &&
(_totalSupply < MAX_SUPPLY) &&
msg.sender != address(pair) &&
!inSwap &&
block.timestamp >= (_lastRebasedTime + rebaseInterval);
}
function shouldAddLiquidity() internal view returns (bool) {
return
_autoAddLiquidity &&
!inSwap &&
msg.sender != address(pair) &&
block.timestamp >= (_lastAddLiquidityTime + 48 hours);
}
function shouldSwapBack() internal view returns (bool) {
return !inSwap && msg.sender != address(pair);
}
function setAutoRebase(bool _flag) public onlyAdmin {
if (_flag) {
_autoRebase = _flag;
_lastRebasedTime = block.timestamp;
} else {
_autoRebase = _flag;
}
}
function setAutoAddLiquidity(bool _flag) public onlyAdmin {
if (_flag) {
_autoAddLiquidity = _flag;
_lastAddLiquidityTime = block.timestamp;
} else {
_autoAddLiquidity = _flag;
}
}
function allowance(address owner_, address spender)
public
view
override
returns (uint256)
{
return _allowedFragments[owner_][spender];
}
function decreaseAllowance(address spender, uint256 subtractedValue)
public
override
returns (bool)
{
uint256 oldValue = _allowedFragments[msg.sender][spender];
if (subtractedValue >= oldValue) {
_allowedFragments[msg.sender][spender] = 0;
} else {
_allowedFragments[msg.sender][spender] = oldValue.sub(
subtractedValue
);
}
emit Approval(
msg.sender,
spender,
_allowedFragments[msg.sender][spender]
);
return true;
}
function increaseAllowance(address spender, uint256 addedValue)
public
override
returns (bool)
{
_allowedFragments[msg.sender][spender] = _allowedFragments[msg.sender][
spender
].add(addedValue);
emit Approval(
msg.sender,
spender,
_allowedFragments[msg.sender][spender]
);
return true;
}
function approve(address spender, uint256 value)
public
override
returns (bool)
{
_allowedFragments[msg.sender][spender] = value;
emit Approval(msg.sender, spender, value);
return true;
}
function checkFeeExempt(address _addr) public view returns (bool) {
return _isFeeExempt[_addr];
}
function getCirculatingSupply() public view returns (uint256) {
return
(TOTAL_GONS.sub(_gonBalances[DEAD]).sub(_gonBalances[ZERO])).div(
_gonsPerFragment
);
}
function isNotInSwap() public view returns (bool) {
return !inSwap;
}
function manualSync() public {
IPancakeSwapPair(pair).sync();
}
function setFeeReceivers(
ITreasury _treasury,
address _redTrustWallet,
address _redFurnace
) public onlyAdmin {
treasury = _treasury;
redTrustWallet = _redTrustWallet;
redFurnace = _redFurnace;
}
function setFee(
uint256 _liquidityFee,
uint256 _gameTreasuryFee,
uint256 _redTrustFee,
uint256 _redFurnaceFee,
uint256 _sellFee,
uint256 _nftRewardFee
) public onlyAdmin {
liquidityFee = _liquidityFee;
gameTreasuryFee = _gameTreasuryFee;
redTrustFee = _redTrustFee;
redFurnaceFee = _redFurnaceFee;
nftRewardFee = _nftRewardFee;
totalFee = liquidityFee
.add(gameTreasuryFee)
.add(redTrustFee)
.add(redFurnaceFee)
.add(nftRewardFee);
sellFee = _sellFee;
require(totalFee.add(sellFee) <= 250, "Fee too high!");
}
function getLiquidityBacking(uint256 accuracy)
public
view
returns (uint256)
{
uint256 liquidityBalance = _gonBalances[address(pair)].div(
_gonsPerFragment
);
return
accuracy.mul(liquidityBalance.mul(2)).div(getCirculatingSupply());
}
function setWhitelist(address _addr) public onlyAdmin {
_isFeeExempt[_addr] = true;
}
function setBotBlacklist(address _botAddress, bool _flag) public onlyAdmin {
require(
isContract(_botAddress),
"only contract address, not allowed exteranlly owned account"
);
blacklist[_botAddress] = _flag;
}
function totalSupply() public view override returns (uint256) {
return _totalSupply;
}
function balanceOf(address who) public view override returns (uint256) {
return _gonBalances[who].div(_gonsPerFragment);
}
function isContract(address addr) internal view returns (bool) {
uint256 size;
assembly {
size := extcodesize(addr)
}
return size > 0;
}
function decimals() public view override returns (uint8) {
return _decimals;
}
receive() external payable {}
}

9
deploy/00_treasury.ts Normal file
View File

@ -0,0 +1,9 @@
import { ethers, run } from "hardhat";
import * as crypto from "crypto"
//TBD
//@ts-ignore
module.exports = async ({ getNamedAccounts, deployments, getChainId }) => {
};
module.exports.tags = ['Treasury']

123
hardhat.config.ts Normal file
View File

@ -0,0 +1,123 @@
/**
* @type import('hardhat/config').HardhatUserConfig
*/
import { task } from "hardhat/config";
import "@nomiclabs/hardhat-ethers";
import "@nomiclabs/hardhat-waffle";
import "@nomiclabs/hardhat-etherscan";
import "@openzeppelin/hardhat-upgrades";
import "@typechain/hardhat";
import "hardhat-tracer";
import "hardhat-gas-reporter";
import "hardhat-dependency-compiler";
import "hardhat-deploy";
require('dotenv').config();
let {
ETHERSCAN_TOKEN,
BSCSCAN_TOKEN,
PRIVATE_KEY
} = process.env;
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
task("accounts", "Prints the list of accounts", async (args, { ethers }) => {
const accounts = await ethers.getSigners();
for (const account of accounts) {
console.log(account.address);
}
});
/**
* @type import('hardhat/config').HardhatUserConfig
*/
let networks;
if(PRIVATE_KEY) {
let accounts = [
PRIVATE_KEY
]
networks = {
hardhat: {},
bsc: {
url: "https://bsc-dataseed.binance.org/",
chainId: 56,
gasPrice: 5000000000,
accounts
},
bscTestnet: {
url: "https://data-seed-prebsc-1-s1.binance.org:8545",
chainId: 97,
gasPrice: 10000000000,
accounts
},
rinkeby: {
url: "https://eth-rinkeby.alchemyapi.io/v2/v92DVe9FFvr2lzRB4wjtk-z4DdsQjBhs",
gasPrice: 5000000000,
accounts
},
ropsten: {
url: "https://eth-ropsten.alchemyapi.io/v2/v92DVe9FFvr2lzRB4wjtk-z4DdsQjBhs",
gasPrice: 20000000000,
accounts
},
kovan: {
url: "https://eth-kovan.alchemyapi.io/v2/v92DVe9FFvr2lzRB4wjtk-z4DdsQjBhs",
gasPrice: 20000000000,
accounts
},
goerli: {
url: "https://eth-goerli.alchemyapi.io/v2/v92DVe9FFvr2lzRB4wjtk-z4DdsQjBhs",
gasPrice: 20000000000,
accounts
},
};
} else {
networks = {
hardhat: {},
};
}
module.exports = {
defaultNetwork: "hardhat",
networks: networks,
etherscan: {
apiKey: {
mainnet:ETHERSCAN_TOKEN,
rinkeby:ETHERSCAN_TOKEN,
ropsten:ETHERSCAN_TOKEN,
kovan:ETHERSCAN_TOKEN,
bscTestnet:BSCSCAN_TOKEN,
goerli:ETHERSCAN_TOKEN
}
},
dependencyCompiler: {
},
namedAccounts: {
deployer: 0,
},
abiExporter: {
path: './artifacts/abi',
clear: true,
flat: true,
only: [':Bithotel'],
spacing: 2
},
solidity: {
version: "0.8.15",
settings: {
optimizer: {
enabled: true,
runs: 200
}
}
},
typechain: {
outDir: "typechain",
target: "ethers-v5",
},
};

35813
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

43
package.json Normal file
View File

@ -0,0 +1,43 @@
{
"name": "atech-contracts",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"@metamask/eth-sig-util": "^4.0.0",
"@nomiclabs/hardhat-etherscan": "^3.0.0",
"@openzeppelin/contracts": "^4.6.0",
"@openzeppelin/contracts-upgradeable": "^4.6.0",
"@openzeppelin/hardhat-upgrades": "^1.13.0",
"@remix-project/remixd": "^0.5.5",
"dotenv": "^12.0.3",
"eth-sig-util": "^3.0.1",
"ethereumjs-abi": "^0.6.8",
"hardhat": "^2.8.2",
"hardhat-dependency-compiler": "^1.1.2",
"hardhat-deploy": "^0.9.24",
"hardhat-gas-reporter": "^1.0.7",
"hardhat-tracer": "^1.0.0-alpha.6"
},
"devDependencies": {
"@defi-wonderland/smock": "^2.2.0",
"@nomicfoundation/hardhat-network-helpers": "^1.0.3",
"@nomiclabs/hardhat-ethers": "^2.0.4",
"@nomiclabs/hardhat-waffle": "^2.0.1",
"@typechain/ethers-v5": "^10.1.0",
"@typechain/hardhat": "^6.1.2",
"@types/mocha": "^9.1.1",
"chai": "^4.3.4",
"ethereum-waffle": "^3.4.0",
"ethers": "^5.5.3",
"mocha": "^10.0.0",
"ts-node": "^10.4.0",
"typechain": "^8.1.0",
"typescript": "^4.5.4"
}
}

24
test/nft.ts Normal file
View File

@ -0,0 +1,24 @@
import { MockContract, smock } from '@defi-wonderland/smock';
import { expect, use } from 'chai';
import { NFT, NFT__factory } from '../typechain';
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers';
import { ethers } from 'hardhat';
use(smock.matchers);
describe('nft', async () => {
let nft: MockContract<NFT>;
let admin: SignerWithAddress;
beforeEach(async () => {
[ admin ] = await ethers.getSigners();
const nftMockFactory = await smock.mock<NFT__factory>('NFT');
nft = await nftMockFactory.deploy();
});
it('should initially have isPresale = true', async () => {
expect(await nft.isPresale()).to.be.true;
})
});

9
tsconfig.json Normal file
View File

@ -0,0 +1,9 @@
{
"compilerOptions": {
"target": "es2015",
"module": "commonjs",
"strict": true,
"moduleResolution": "node",
"resolveJsonModule": true
}
}

9334
yarn.lock Normal file

File diff suppressed because it is too large Load Diff