This commit is contained in:
bakatrouble 2022-10-19 13:05:23 +03:00
parent b8793df4f8
commit cd02184d35
11 changed files with 211 additions and 172 deletions

View File

@ -3,5 +3,17 @@
pragma solidity ^0.8.14;
interface INFT {
struct TokenInfo {
string image;
address[] tokens;
uint256 rate;
uint256 attack;
uint256 defense;
uint256 health;
uint256 critChance;
uint256 critDmg;
uint256 recover;
}
function raiseRewardPool(uint256 amount) external;
}

View File

@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity ^0.8.14;
import "./INFT.sol";
interface INFTMetadata {
function tokenURI(uint256 tokenId, INFT.TokenInfo memory token) external view returns (string memory);
}

View File

@ -11,8 +11,10 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./interfaces/ITreasury.sol";
import "./interfaces/IPancakeSwapPair.sol";
import "./mixins/signature-control.sol";
import "./interfaces/INFT.sol";
import "./interfaces/INFTMetadata.sol";
contract NFT is ERC721EnumerableUpgradeable, SignatureControl {
contract NFT is ERC721EnumerableUpgradeable, SignatureControl, INFT {
using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
using SafeERC20Upgradeable for IERC20Upgradeable;
@ -42,11 +44,15 @@ contract NFT is ERC721EnumerableUpgradeable, SignatureControl {
//mint prices, caps, addresses of reward tokens(shiba,floki,doggy,doge)
uint256[4] prices = [
.001 ether,
.0008 ether,
.0006 ether,
.0004 ether
// 300 * 10**18,
250 * 10**18,
200 * 10**18,
250 * 10**18
// 250 * 10**18,
// 200 * 10**18,
// 250 * 10**18
];
INFTMetadata metadata;
IERC20Upgradeable BUSD;
IERC20Upgradeable WETH;
mapping(address => uint256) tokenToPrices;
@ -69,7 +75,6 @@ contract NFT is ERC721EnumerableUpgradeable, SignatureControl {
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;
@ -82,17 +87,6 @@ contract NFT is ERC721EnumerableUpgradeable, SignatureControl {
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 {
@ -150,7 +144,7 @@ contract NFT is ERC721EnumerableUpgradeable, SignatureControl {
}
modifier isValidMint(uint256 amount, uint256 tokenType) {
require(!isPresale, "(mint) presale");
require(!isPresale, "presale");
require(tokenType <= 3, "!tokenType");
require(mintCapOfToken[tokenType] + amount <= nftCaps[tokenType]);
_;
@ -485,68 +479,8 @@ contract NFT is ERC721EnumerableUpgradeable, SignatureControl {
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
@ -566,39 +500,9 @@ contract NFT is ERC721EnumerableUpgradeable, SignatureControl {
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,
"} ] }"
)
)
)
)
);
require(_exists(tokenId), "Non-existent token");
TokenInfo memory token = tokenIdToInfo[tokenId];
return metadata.tokenURI(tokenId, token);
}
function raiseRewardPool(uint256 amount) public {
@ -645,38 +549,38 @@ contract NFT is ERC721EnumerableUpgradeable, SignatureControl {
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[to][idx] += info.rate;
// }
// }
// }
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 (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[to][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];
@ -726,4 +630,8 @@ contract NFT is ERC721EnumerableUpgradeable, SignatureControl {
require(isPresale, "!presale");
isPresale = false;
}
function updateMetadata(INFTMetadata newValue) external onlyAdmin {
metadata = newValue;
}
}

83
contracts/nftMetadata.sol Normal file
View File

@ -0,0 +1,83 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity ^0.8.14;
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/Base64.sol";
import "./interfaces/INFT.sol";
contract NFTMetadata {
function tokenURI(uint256 tokenId, INFT.TokenInfo calldata token) external view returns (string memory) {
return
string(
abi.encodePacked(
"data:application/json;base64,",
Base64.encode(
bytes(
abi.encodePacked(
'{"name": "Babies of Mars #',
Strings.toString(tokenId),
'", "description": "adasdasdasd", "image": "',
token.image,
'",{ "attributes": [ {"trait_type": "tokens", "value": ',
addressArrayToString(token.tokens),
'}, { "trait_type": "attack", "value": ',
compileStatString(token)
)
)
)
)
);
}
function compileStatString(INFT.TokenInfo calldata token) internal view returns (string memory) {
return string(abi.encodePacked(
'}, { "trait_type": "attack", "value": ',
Strings.toString(token.attack),
'}, { "trait_type": "defense", "value": ',
Strings.toString(token.defense),
'}, { "trait_type": "health", "value": ',
Strings.toString(token.health),
'}, { "trait_type": "critical rate", "value": ',
Strings.toString(token.critChance),
'}, { "trait_type": "critical damage", "value": ',
Strings.toString(token.critDmg),
'}, { "trait_type": "recovery", "value": ',
Strings.toString(token.recover),
"} ] }"
));
}
function addressArrayToString(address[] memory addressArray) internal pure returns (string memory) {
string memory result = "[";
for(uint256 i = 0; i < addressArray.length; i++) {
if(i == addressArray.length-1) {
result = string.concat(result,"'0x",toAsciiString(addressArray[i]),"'");
} else {
result = string.concat(result,"'0x",toAsciiString(addressArray[i]),"',");
}
}
result = string.concat(result,"]");
return result;
}
function toAsciiString(address x) internal pure returns (string memory) {
bytes memory s = new bytes(40);
for (uint i = 0; i < 20; i++) {
bytes1 b = bytes1(uint8(uint(uint160(x)) / (2**(8*(19 - i)))));
bytes1 hi = bytes1(uint8(b) / 16);
bytes1 lo = bytes1(uint8(b) - 16 * uint8(hi));
s[2*i] = char(hi);
s[2*i+1] = char(lo);
}
return string(s);
}
function char(bytes1 b) internal pure returns (bytes1 c) {
if (uint8(b) < 10)
return bytes1(uint8(b) + 0x30);
else
return bytes1(uint8(b) + 0x57);
}
}

View File

@ -16,6 +16,10 @@ contract Treasury is RoleControl {
uint256 amount
);
constructor() {
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
}
function initialize(address admin) public initializer {
_setupRole(DEFAULT_ADMIN_ROLE, admin);
}

16
deploy/05_metadata.ts Normal file
View File

@ -0,0 +1,16 @@
import { DeployFunction } from 'hardhat-deploy/dist/types';
const deployFunc: DeployFunction = async ({ getNamedAccounts, deployments, getChainId }) => {
const { deploy } = deployments;
const { deployer } = await getNamedAccounts();
await deploy('NFTMetadata', {
from: deployer,
args: [],
log: true,
});
};
const tags = ['NFTMetadata'];
export default deployFunc;
export { tags };

View File

@ -10,66 +10,73 @@ const deployFunc: DeployFunction = async ({ getNamedAccounts, deployments, ether
const AddressZero = ethers.constants.AddressZero;
const PancakeRouter = '0xD99D1c33F9fC3444f8101754aBC46c52416550D1';
const Owner = deployer; //'0x22f60E6BD7973c226979B6F57BC92C2d66a8c151';
const Owner = '0x22f60E6BD7973c226979B6F57BC92C2d66a8c151';
const BUSD = '0xB08B32EC7E2Aa60a4C2f4343E7EB638187163415';
const WETH = '0xF1960ee684B173cf6c17fCdA5F1dFC366Aba55d3';
const RedTrustWallet = '0x22f60E6BD7973c226979B6F57BC92C2d66a8c151';
const treasuryAddress = '0x0Cb09553b2d1Da0459577d7027EdA21d40f2a7Cb'; //(await get('Treasury')).address;
const furnaceAddress = '0xe1cCbDFaBc90F15F96A658a6e96c27D0f1DA9Bd4'; //(await get('RedFurnace')).address;
const treasuryAddress = (await get('Treasury')).address;
const furnaceAddress = (await get('RedFurnace')).address;
const nftAddress = (await get('NFT')).address;
const marketAddress = '0x92DE9C3a72d787d16F73e18649139341869f4621'; //(await get('Marketplace')).address;
const tokenAddress = '0x341D28f61ea857C31BAC30302D88a69f5E8c3ed0'; //(await get('BabiesOfMars')).address;
const marketAddress = (await get('Marketplace')).address;
const tokenAddress = (await get('BabiesOfMars')).address;
const nftMetadataAddress = (await get('NFTMetadata')).address;
const token = await ethers.getContractAt('BabiesOfMars', tokenAddress);
const pancake = await ethers.getContractAt('IPancakeSwapRouter', PancakeRouter);
const busd = await ethers.getContractAt('ERC', BUSD);
const weth = await ethers.getContractAt('ERC', WETH);
const nft = await ethers.getContractAt('NFT', nftAddress);
const nftMetadata = await ethers.getContractAt('NFTMetadata', nftMetadataAddress);
// await execute('Treasury', {
// from: deployer,
// log: true,
// }, 'initialize', Owner)
//
// await execute('BabiesOfMars', {
// from: deployer,
// log: true,
// }, 'initialize', PancakeRouter, Owner, treasuryAddress, RedTrustWallet, nftAddress, furnaceAddress, BUSD);
await execute('Treasury', {
from: deployer,
log: true,
}, 'initialize', Owner)
// await execute('NFT', {
// from: deployer,
// log: true,
// }, 'initialize', 'NFT Name', 'NFTS', treasuryAddress, RedTrustWallet, tokenAddress, 200, 200, 200, await token.pair(), PancakeRouter, BUSD, WETH);
await execute('BabiesOfMars', {
from: deployer,
log: true,
}, 'initialize', PancakeRouter, Owner, treasuryAddress, RedTrustWallet, nftAddress, furnaceAddress, BUSD);
// await execute('Marketplace', {
// from: deployer,
// log: true,
// }, 'initialize', 200, treasuryAddress, nftAddress, tokenAddress);
await execute('NFT', {
from: deployer,
log: true,
}, 'initialize', 'NFT Name', 'NFTS', treasuryAddress, RedTrustWallet, tokenAddress, 200, 200, 200, await token.pair(), PancakeRouter, BUSD, WETH);
await execute('Marketplace', {
from: deployer,
log: true,
}, 'initialize', 200, treasuryAddress, nftAddress, tokenAddress);
await execute('NFT', {
from: deployer,
log: true,
}, 'updateMetadata', nftMetadataAddress);
// await busd.mint(deployer, parseEther('100000000'));
// await weth.mint(deployer, parseEther('100000000'));
// await weth.approve(PancakeRouter, parseEther('100000000'));
// await weth.approve(PancakeRouter, parseEther('100000000'));
// await token.approve(PancakeRouter, parseEther('1000000000000000000'));
// await new Promise((approve) => setTimeout(() => approve(null), 5000));
// await pancake.addLiquidity(tokenAddress, WETH, 10000000, parseEther('10'), 0, 0, deployer, getCurrentTimestamp() + 1000);
// await pancake.addLiquidity(tokenAddress, BUSD, 10000000, parseEther('1000'), 0, 0, deployer, getCurrentTimestamp() + 1000);
await token.approve(PancakeRouter, parseEther('1000000000000000000'));
await new Promise((approve) => setTimeout(() => approve(null), 5000));
await pancake.addLiquidity(tokenAddress, WETH, 10000000, parseEther('10'), 0, 0, deployer, getCurrentTimestamp() + 1000);
await pancake.addLiquidity(tokenAddress, BUSD, 10000000, parseEther('1000'), 0, 0, deployer, getCurrentTimestamp() + 1000);
console.log(`Treasury: ${treasuryAddress}\nRedFurnace: ${furnaceAddress}\nNFT: ${nftAddress}\nMarketplace: ${marketAddress}\nBabiesOfMars: ${tokenAddress}`);
// await token.approve(nft.address, constants.MaxUint256);
// await nft.finishPresale();
// await new Promise((approve) => setTimeout(() => approve(null), 5000));
// await nft.mint(10, 0);
// await nft.mint(10, 0, { gasLimit: 5000000 });
// await new Promise((approve) => setTimeout(() => approve(null), 5000));
await nft.combineTokens([1, 2], { value: parseEther('.05'), gasLimit: 5000000 });
// await nft.combineTokens([1, 2], { value: parseEther('.05'), gasLimit: 5000000 });
};
const tags = ['Initialize'];
const dependencies = ['Treasury', 'Furnace', 'NFT', 'Marketplace', 'Token']
const dependencies = ['Treasury', 'Furnace', 'NFT', 'Marketplace', 'Token', 'NFTMetadata'];
export default deployFunc;
export { tags, dependencies };