Initial commit
This commit is contained in:
commit
843daad632
39
.gitignore
vendored
Normal file
39
.gitignore
vendored
Normal 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
6
contracts/furnace.sol
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// SPDX-License-Identifier: Unlicensed
|
||||||
|
|
||||||
|
|
||||||
|
pragma solidity ^0.8.14;
|
||||||
|
|
||||||
|
contract RedFurnace {}
|
7
contracts/interfaces/INFT.sol
Normal file
7
contracts/interfaces/INFT.sol
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// SPDX-License-Identifier: Unlicensed
|
||||||
|
|
||||||
|
pragma solidity ^0.8.14;
|
||||||
|
|
||||||
|
interface INFT {
|
||||||
|
function raiseRewardPool(uint256 amount) external;
|
||||||
|
}
|
316
contracts/interfaces/IPancake.sol
Normal file
316
contracts/interfaces/IPancake.sol
Normal 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;
|
||||||
|
}
|
8
contracts/interfaces/ITreasury.sol
Normal file
8
contracts/interfaces/ITreasury.sol
Normal 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
148
contracts/market.sol
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
102
contracts/mixins/SafeMathInt.sol
Normal file
102
contracts/mixins/SafeMathInt.sol
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
40
contracts/mixins/role-control.sol
Normal file
40
contracts/mixins/role-control.sol
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
31
contracts/mixins/signature-control.sol
Normal file
31
contracts/mixins/signature-control.sol
Normal 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
711
contracts/nft.sol
Normal 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];
|
||||||
|
}
|
||||||
|
}
|
36
contracts/proxies/proxies.sol
Normal file
36
contracts/proxies/proxies.sol
Normal 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) {}
|
||||||
|
}
|
7
contracts/proxies/proxyadmin.sol
Normal file
7
contracts/proxies/proxyadmin.sol
Normal 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 {
|
||||||
|
}
|
28
contracts/red_treasury.sol
Normal file
28
contracts/red_treasury.sol
Normal 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
673
contracts/token.sol
Normal 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
9
deploy/00_treasury.ts
Normal 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
123
hardhat.config.ts
Normal 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
35813
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
43
package.json
Normal file
43
package.json
Normal 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
24
test/nft.ts
Normal 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
9
tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es2015",
|
||||||
|
"module": "commonjs",
|
||||||
|
"strict": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user