文件 1 的 1:MetallisAirdrop.sol
pragma solidity 0.8.20;
interface ERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address tokenOwner) external view returns (uint256 balance);
function transfer(address recipient, uint256 amount) external returns (bool success);
function approve(address spender, uint256 tokens) external returns (bool success);
function transferFrom(address from, address to, uint256 tokens) external returns (bool success);
function allowance(address sender, address spender) external view returns (uint256 remaining);
}
interface Imultisig {
function pause() external returns (bool);
function unPause() external returns (bool);
function authorizeContract(address _contract) external;
function revokeContract(address _contract) external;
function addMultisigWallet(address _wallet) external;
function removeMultisigWallet(address _wallet) external;
function initiateProposal(
string memory _proposalName,
bytes memory _proposalFunction,
address _proposalContract,
uint _requiredVotes,
uint _duration
) external returns (uint proposalId);
function voteOnProposal(uint _proposalId, bool _vote) external;
}
interface ImetallisMain {
function purchasewMetallis(address _buyer, string memory _tokenName, uint256 _tokenAmount) external returns (bool);
function setMultisigContract(address _multisigContract) external returns (address);
function addToWhitelist(address _address) external;
function updatePurchaseTokens(string memory _tokenName, ERC20 _tokenAddress, uint _decimals, uint _weiDiff, bool _active) external;
function updatewMetallisPrice(string memory _tokenName, ERC20 _tokenAddress, uint256 _wMetallisPrice) external;
function pauseContract(bool _status) external returns (bool);
function getMultisigContract() external view returns (Imultisig, address);
function getwMetallisContract() external view returns(IwMetallis, address);
function getwMetallisPrice(string memory _tokenName) external view returns (uint256);
function isWhitelisted() external view returns (bool);
function isAddressWhitelisted(address _whitelistAddress) external view returns (bool);
function isPurchaseTokenActive(string memory tokenName) external view returns (bool);
function contractTokenBalances(string memory _tokenName) external view returns (uint256, uint256);
function wMetallisMintedBalance() external view returns(uint256);
function withdrawFunds(address tokenAddress, uint256 amount) external payable returns (bool success);
function transferOwnership(address newOwner) external returns (address);
function setTreasuries(string memory _treasuryName, address _treasuryAddress, uint _rate) external;
}
interface IwMetallis {
function distributeTokens(address buyer, uint256 wMetallisAmount) external returns (bool);
function pause() external;
function unPause() external;
function pauseStatus() external view returns (bool);
function setMultisigContract(address _multisigContract) external returns(address multisig);
function contractBalances(string memory _tokenName) external view returns (uint256);
function addTokens(string memory _tokenName, ERC20 _tokenAddress, uint _decimals, bool _active) external;
function removeTokens(string memory _tokenName) external;
function isTokenActive(string memory tokenName) external view returns (bool);
function mintwMetallis(uint256 _mintAmount) external returns (string memory, uint256);
function burnwMetallis(uint256 _burnAmount) external returns (string memory, uint256);
function withdrawFunds(address tokenAddress, uint256 amount) external payable;
function manualTokenTransfer(address tokenAddress, address to, uint256 amount) external returns(bool);
function authorizeContract(address _contract) external returns (address);
function revokeContractAuthorization(address _contract) external returns (address);
function transferOwnership(address newOwner) external;
function wMetallisBalance() external view returns (uint);
function setMetallisMainContract(address _metallisMainAddress) external returns (address);
function getMultisigAddress() external view returns (Imultisig _multisigContract, address _multisig);
}
contract wMetallis is ERC20, IwMetallis {
address internal multisigAddress;
address internal adminAddress;
address internal metallisMainAddress;
address public owner;
bool internal functionLocked;
bool public paused;
Imultisig internal multisigContract;
ImetallisMain internal metallisMainContract;
string public name = 'wMetallis';
string public symbol = 'wMTLIS';
string public logoUrl = "https://metalliscrypta.io/symbollogo.png";
string public _websiteUrl = "https://metalliscrypta.io";
uint public decimals = 18;
uint256 public totalSupply;
uint256 public maxTotalSupply;
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
mapping(address => bool) internal authorizedContracts;
mapping(address => uint256) internal deposits;
mapping(string => TokenInfo) internal erc20Tokens;
mapping(address => mapping (address => uint)) public distributedTokens;
mapping(address => uint) internal mints;
mapping(address => uint) internal burns;
struct TokenInfo {
ERC20 tokenAddress;
uint decimals;
bool active;
}
event InternalTransfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
event AuthorizationChanged(address indexed contractAddress, bool isAuthorized);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
event EtherReceived(address sender, uint256 amount);
event MintSuccess(uint256 mintAmount, uint256 newSupply);
event BurnSuccess(address sender, address zeroAddress, uint256 burnAmount);
event MultisigChanged(address indexed _multisigContract);
event TokenInfoUpdated(string tokenName, address tokenAddress, bool active);
event TokenRemoved(string tokenName, ERC20 tokenAddress);
modifier onlyOwner () {
require(msg.sender == owner, "You are not the owner");
_;
}
modifier onlyMultisig() {
require(msg.sender == multisigAddress, "Caller is not the multisig contract");
_;
}
modifier onlyAdmin() {
require(msg.sender == adminAddress, "Caller is not the multisig contract");
_;
}
modifier onlyAuthorizedContracts() {
require(authorizedContracts[msg.sender], "Caller is not authorized");
_;
}
modifier functionLock() {
require(!functionLocked, "Reentrant call detected");
functionLocked = true;
_;
functionLocked = false;
}
constructor(
address _multisigAddress,
address _metallisMainAddress,
address _adminAddress
) {
multisigContract = Imultisig(_multisigAddress);
metallisMainContract = ImetallisMain(_metallisMainAddress);
adminAddress = _adminAddress;
paused = false;
functionLocked = false;
maxTotalSupply = 5000000 * (10 ** 18);
owner = msg.sender;
uint256 firstMintAmount = 483000 * (10 ** 18);
_balances[address(this)] = firstMintAmount;
totalSupply = firstMintAmount;
}
function balanceOf(address tokenOwner) external view returns (uint256 balance) {
return _balances[tokenOwner];
}
function transfer(address recipient, uint256 amount) external returns (bool) {
require (!paused, "Contract is currently paused");
require(recipient != address(0), "ERC20: transfer to the zero address");
require(_balances[msg.sender] >= amount, "ERC20: transfer amount exceeds balance");
_balances[msg.sender] = _balances[msg.sender] - amount;
_balances[recipient] = _balances[recipient] + amount;
return true;
}
function approve(address spender, uint256 tokens) external returns (bool success) {
require (!paused, "Contract is currently paused");
require(spender != address(0), "Approve to the zero address");
_allowances[msg.sender][spender] = tokens;
emit Approval(msg.sender, spender, tokens);
return true;
}
function transferFrom(address from, address to, uint256 tokens) external returns (bool success) {
require (!paused, "Contract is currently paused");
require(tokens <= _balances[from], "Insufficient balance");
require(tokens <= _allowances[from][msg.sender], "Insufficient allowance");
require(to != address(0), "Transfer to the zero address");
_balances[from] -= tokens;
_balances[to] += tokens;
_allowances[from][msg.sender] -= tokens;
return true;
}
function allowance(address sender, address spender) external view returns (uint256 remaining) {
return _allowances[sender][spender];
}
function isContractAuthorized(address _contract) external view returns (string memory) {
if (authorizedContracts[_contract]) {
return "Contract is authorized";
} else {
return "Contract is not authorized";
}
}
function contractBalances(string memory _tokenName) external view onlyOwner returns (uint256) {
bool _token = erc20Tokens [_tokenName].active;
require(_token == true, "No active token by that name");
uint256 balance = erc20Tokens [_tokenName].tokenAddress.balanceOf(address(this));
return balance / (10**erc20Tokens[_tokenName].decimals);
}
function wMetallisBalance() external view onlyAuthorizedContracts returns (uint){
return totalSupply;
}
function isTokenActive(string memory tokenName) external view returns (bool) {
return erc20Tokens[tokenName].active;
}
function getMultisigAddress() external view onlyAuthorizedContracts returns (Imultisig, address) {
return (multisigContract, multisigAddress);
}
function pause() external onlyOwner {
paused = true;
}
function unPause() external onlyOwner {
paused = false;
}
function pauseStatus() public view returns (bool) {
return paused;
}
function setMultisigContract(address _multisigAddress) external onlyOwner returns(address){
multisigContract = Imultisig(_multisigAddress);
multisigAddress = _multisigAddress;
emit MultisigChanged(multisigAddress);
return multisigAddress;
}
function setMetallisMainContract(address _metallisMainAddress) external onlyOwner returns (address){
metallisMainContract = ImetallisMain(_metallisMainAddress);
metallisMainAddress = _metallisMainAddress;
return metallisMainAddress;
}
function setAdminAddress(address _newAdminAddress) external onlyAdmin returns (address){
adminAddress = _newAdminAddress;
return adminAddress;
}
function addTokens(
string memory _tokenName,
ERC20 _tokenAddress,
uint _decimals,
bool _active) external onlyOwner {
erc20Tokens[_tokenName] = TokenInfo(_tokenAddress, _decimals, _active);
emit TokenInfoUpdated(_tokenName, address(_tokenAddress), _active);
}
function removeTokens(string memory _tokenName) external onlyOwner {
emit TokenRemoved(_tokenName, erc20Tokens[_tokenName].tokenAddress);
delete erc20Tokens[_tokenName];
}
function authorizeContract(address _contract) external onlyOwner returns (address) {
authorizedContracts[_contract] = true;
emit AuthorizationChanged(_contract, true);
return _contract;
}
function revokeContractAuthorization(address _contract) external onlyOwner returns (address) {
authorizedContracts[_contract] = false;
emit AuthorizationChanged(_contract, false);
return _contract;
}
function _transfer(address sender, address recipient, uint256 amount) private returns (bool){
require (!paused, "Contract is currently paused");
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
require(_balances[sender] >= amount, "ERC20: transfer amount exceeds balance");
_balances[sender] = _balances[sender] - amount;
_balances[recipient] = _balances[recipient] + amount;
emit InternalTransfer(sender, recipient, amount);
return true;
}
receive() external payable {
deposits[msg.sender] += msg.value;
emit EtherReceived(msg.sender, msg.value);
}
fallback() external payable {
deposits[msg.sender] += msg.value;
emit EtherReceived(msg.sender, msg.value);
}
function mintwMetallis(uint256 _mintAmount) external onlyMultisig returns (string memory, uint256) {
require(!paused, "Contract is paused");
require(totalSupply + _mintAmount <= maxTotalSupply, "Mint exceeds max supply");
totalSupply += _mintAmount;
mints [address(this)] += _mintAmount;
emit MintSuccess(_mintAmount, totalSupply);
return ("Mint Successful. Tokens Minted: ",_mintAmount);
}
function burnwMetallis(uint256 _burnAmount) external onlyMultisig returns (string memory, uint256) {
require(!paused, "Contract is paused");
require(totalSupply - _burnAmount >= 0, "Burn exceeds total supply");
totalSupply -= _burnAmount;
burns [address(this)] += _burnAmount;
emit BurnSuccess(msg.sender, address(0), _burnAmount);
return ("Burn Successful. Tokens Burned: ", _burnAmount);
}
function withdrawFunds(address tokenAddress, uint256 amount) external onlyAdmin functionLock payable {
require (!paused, "Contract is currently paused");
if (tokenAddress == address(0)) {
require(address(this).balance >= amount, "Insufficient ETH balance");
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "ETH transfer failed");
} else {
require(tokenAddress != address(0), "Invalid token address");
uint256 balance = ERC20(tokenAddress).balanceOf(address(this));
require(balance >= amount, "Insufficient token balance");
require(ERC20(tokenAddress).transfer(msg.sender, amount), "Token transfer failed");
}
}
function manualTokenTransfer(address tokenAddress, address to, uint256 amount) external onlyAdmin functionLock returns(bool){
require (!paused, "Contract is currently paused");
ERC20 tokenContract = ERC20(tokenAddress);
bool success = tokenContract.transfer(to, amount);
require(success, "Token transfer failed");
return success;
}
function distributeTokens(address _buyer, uint256 wMetallisAmount) external onlyAuthorizedContracts functionLock returns (bool) {
require (!paused, "Contract is currently paused");
require(_balances[address(this)] >= wMetallisAmount, "Insufficient wMetallis balance in contract");
bool success =_transfer(address(this), _buyer, wMetallisAmount);
require(success, "Distribute tokens failed");
distributedTokens[msg.sender][_buyer] += wMetallisAmount;
return true;
}
function transferOwnership(address newOwner) external onlyAdmin {
require(newOwner != address(0), "New owner is the zero address");
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
contract metallisMain is ImetallisMain {
address public owner;
address internal multisigAddress;
address internal wMetallisAddress;
address internal adminAddress;
bool internal functionLocked = false;
bool internal paused = false;
IwMetallis internal wMetallisContract;
Imultisig internal multisigContract;
string public name = 'metallisMain';
string public logoUrl = "https://metalliscrypta.io/symbollogo.png";
string public _websiteUrl = "https://metalliscrypta.io";
uint256 public wMetallisAmount;
uint256 public convertedToken;
uint256 public totalSlots = 2000;
uint256 public treasuryCount;
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
mapping(address => bool) internal authorizedContracts;
mapping(address => uint256) internal deposits;
mapping(address => bool) internal whitelisted;
mapping(string => TokenInfo) internal erc20Tokens;
mapping(string => PurchasePrices) internal purchasePrice;
mapping(string => Treasuries) internal treasuries;
mapping(uint => Treasuries) internal treasuryIds;
struct TokenInfo {string tokenName; ERC20 tokenAddress; uint decimals; uint weiDiff; bool active;}
struct PurchasePrices {string tokenName; ERC20 tokenAddress; uint256 wMetallisPrice;}
struct Treasuries {uint treasuryId; string treasuryName; address treasuryAddress; uint rate;}
struct TreasuryAmounts {
uint256 leverageAmount;
uint256 aquisitionAmount;
uint256 maintenanceAmount;
uint256 reserveAmount;
uint256 buyTaxAmount;
uint256 netAmount;
uint256 sellTaxAmount;
}
string[] private treasuryNames;
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
event EtherReceived(address indexed sender, uint256 amount);
event MultisigChanged(address indexed multisigContract);
event TokenInfoUpdated(string tokenName, address tokenAddress, bool active);
event PriceUpdated (string tokenName, ERC20 tokenAddress, uint256 wMetallisPrice);
event WhitelistAdded(address _address);
event TreasuryUpdated(uint treasuryId, string treasuryName, address treasuryAddress, uint rate);
modifier onlyOwner () {
require(msg.sender == owner, "You are not the owner");
_;
}
modifier onlyAdmin () {
require(msg.sender == adminAddress, "You are not the owner");
_;
}
modifier onlyMultisig() {
require(msg.sender == multisigAddress, "Caller is not the multisig contract");
_;
}
modifier onlyAuthorizedContracts() {
require(authorizedContracts[msg.sender], "Caller is not authorized");
_;
}
modifier functionLock() {
require(!functionLocked, "Reentrant call detected");
functionLocked = true;
_;
functionLocked = false;
}
modifier userOnly() {
require (tx.origin == msg.sender, "Only EOAs can purchase wMetallis");
_;
}
constructor(
address _wMetallisAddress,
address _multisigAddress,
address _adminAddress
) {
wMetallisContract = IwMetallis(_wMetallisAddress);
multisigContract = Imultisig(_multisigAddress);
owner = msg.sender;
adminAddress = _adminAddress;
}
function setwMetallisAmount(string memory _tokenName, uint _netAmount) internal {
if(erc20Tokens[_tokenName].decimals != 18){
convertedToken = _netAmount * (10 ** erc20Tokens[_tokenName].weiDiff);
wMetallisAmount = convertedToken / purchasePrice[_tokenName].wMetallisPrice;
} else {
wMetallisAmount = _netAmount / purchasePrice[_tokenName].wMetallisPrice;
}
}
function purchasewMetallis(address _buyer, string memory _tokenName, uint256 _tokenAmount) external userOnly returns (bool) {
isContractPaused();
require(_tokenAmount > 0, "Amount must be greater than 0");
require(erc20Tokens[_tokenName].active, "Unsupported purchase token");
require(purchasePrice[_tokenName].wMetallisPrice != 0,"No purchase price set for token");
if (!whitelisted[_buyer]) {
require(_tokenAmount / purchasePrice[_tokenName].wMetallisPrice >= 3 , "Minimum purchase is 3 wMetallis");
require(totalSlots > 0, "No more available whitelist slots");
whitelisted[_buyer] = true;
totalSlots--;
}
uint256 tokenInWei = _tokenAmount * (10 ** erc20Tokens[_tokenName].decimals);
require(erc20Tokens[_tokenName].tokenAddress.allowance(_buyer, address(this)) >= tokenInWei, "Insufficient token allowance");
TreasuryAmounts memory amounts = calculateTreasuryAmounts(tokenInWei);
setwMetallisAmount(_tokenName, amounts.netAmount);
transferToTreasuries(_buyer, _tokenName, amounts);
bool distributeSuccess = wMetallisContract.distributeTokens(_buyer, wMetallisAmount);
require(distributeSuccess, "wMetallis distribution failed");
return distributeSuccess;
}
receive() external payable {
deposits[msg.sender] += msg.value;
emit EtherReceived(msg.sender, msg.value);
}
fallback() external payable {
deposits[msg.sender] += msg.value;
emit EtherReceived(msg.sender, msg.value);
}
function isContractPaused() internal view {
require(!paused, "Contract is Paused");
}
function setMultisigContract(address _multisigContract) external onlyOwner returns (address){
multisigContract = Imultisig (_multisigContract);
multisigAddress = _multisigContract;
emit MultisigChanged(_multisigContract);
return multisigAddress;
}
function setAdminAddress(address _newAdminAddress) external onlyAdmin returns (address){
adminAddress = (_newAdminAddress);
return adminAddress;
}
function setwMetallisContract(address _wMetallisAddress) external onlyOwner returns(address){
wMetallisContract = IwMetallis(_wMetallisAddress);
wMetallisAddress = _wMetallisAddress;
return wMetallisAddress;
}
function addToWhitelist(address _address) external onlyOwner {
isContractPaused();
require(!whitelisted[_address],"Address already on whitelist");
whitelisted[_address] = true;
emit WhitelistAdded (_address);
}
function updatePurchaseTokens(
string memory _tokenName,
ERC20 _tokenAddress,
uint _decimals,
uint _weiDiff,
bool _active) external onlyAdmin {
erc20Tokens[_tokenName] = TokenInfo(_tokenName,_tokenAddress, _decimals, _weiDiff, _active);
emit TokenInfoUpdated(_tokenName, address(_tokenAddress), _active);
}
function setTreasuries(
string memory _treasuryName,
address _treasuryAddress,
uint _rate) external onlyAdmin{
isContractPaused();
uint treasuryID = ++treasuryCount;
Treasuries storage id = treasuryIds[treasuryID];
Treasuries storage treasury = treasuries[_treasuryName];
if (bytes(treasury.treasuryName).length == 0) {
treasuryNames.push(_treasuryName);
treasury.treasuryName = _treasuryName;
}
treasury.treasuryId = treasuryID;
treasury.treasuryAddress = _treasuryAddress;
treasury.rate = _rate;
id.treasuryId = treasuryID;
id.treasuryName = _treasuryName;
id.treasuryAddress = _treasuryAddress;
id.rate = _rate;
emit TreasuryUpdated(treasuryID, _treasuryName, _treasuryAddress, _rate);
}
function updatewMetallisPrice(string memory _tokenName, ERC20 _tokenAddress, uint256 _wMetallisPrice) external onlyAdmin {
purchasePrice [_tokenName] = PurchasePrices(_tokenName, _tokenAddress, _wMetallisPrice);
emit PriceUpdated (_tokenName, _tokenAddress, _wMetallisPrice);
}
function pauseContract(bool _status) external onlyOwner returns (bool) {
paused = _status;
return paused;
}
function getTreasuryInfo() public view returns (Treasuries[] memory) {
Treasuries[] memory treasuryInfo = new Treasuries[](treasuryNames.length);
for (uint i = 0; i < treasuryNames.length; i++) {
treasuryInfo[i] = treasuries[treasuryNames[i]];
}
return (treasuryInfo);
}
function isAdmin(address _adminAddress) external view returns (bool){
bool admin = adminAddress == _adminAddress;
return admin;
}
function getMultisigContract() external view onlyOwner returns (Imultisig, address){
return (multisigContract, multisigAddress);
}
function getwMetallisContract() external view onlyOwner returns(IwMetallis, address){
return (wMetallisContract, wMetallisAddress);
}
function getwMetallisPrice(string memory _tokenName) external view returns (uint256) {
uint256 price = purchasePrice[_tokenName].wMetallisPrice;
return price;
}
function isWhitelisted() external view returns (bool){
bool onWhitelist = whitelisted[msg.sender];
return onWhitelist;
}
function isAddressWhitelisted(address _whitelistAddress) external onlyOwner view returns (bool){
bool onWhitelist = whitelisted[_whitelistAddress];
return onWhitelist;
}
function isPurchaseTokenActive(string memory tokenName) external view returns (bool) {
return erc20Tokens[tokenName].active;
}
function contractTokenBalances(string memory _tokenName) external view onlyAdmin returns (uint256, uint256) {
bool _token = erc20Tokens [_tokenName].active;
require(_token == true, "No active token by that name");
uint256 balance = erc20Tokens [_tokenName].tokenAddress.balanceOf(address(this));
uint256 ethbalance = address(this).balance;
return (balance / 10**erc20Tokens[_tokenName].decimals, ethbalance);
}
function wMetallisMintedBalance() external view onlyOwner returns(uint256){
return wMetallisContract.wMetallisBalance();
}
function calculateTreasuryAmounts(uint256 tokenInWei) internal view returns (TreasuryAmounts memory) {
TreasuryAmounts memory amounts;
Treasuries memory buyTaxTreasury = treasuries["buyTax"];
require(buyTaxTreasury.treasuryAddress != address(0), "BuyTax treasury not found");
amounts.buyTaxAmount = tokenInWei * buyTaxTreasury.rate / 100;
amounts.netAmount = tokenInWei - amounts.buyTaxAmount;
Treasuries memory leverageTreasury = treasuries["leverage"];
require(leverageTreasury.treasuryAddress != address(0), "Leverage treasury not found");
amounts.leverageAmount = amounts.netAmount * leverageTreasury.rate / 100;
Treasuries memory aquisitionTreasury = treasuries["aquisition"];
require(aquisitionTreasury.treasuryAddress != address(0), "Aquisition treasury not found");
amounts.aquisitionAmount = amounts.netAmount * aquisitionTreasury.rate / 100;
Treasuries memory maintenanceTreasury = treasuries["maintenance"];
require(maintenanceTreasury.treasuryAddress != address(0), "Maintenance treasury not found");
amounts.maintenanceAmount = amounts.netAmount * maintenanceTreasury.rate / 100;
Treasuries memory reserveTreasury = treasuries["reserve"];
require(reserveTreasury.treasuryAddress != address(0), "Reserve treasury not found");
amounts.reserveAmount = amounts.netAmount * reserveTreasury.rate / 100;
return amounts;
}
function transferToTreasuries(address _buyer, string memory _tokenName, TreasuryAmounts memory amounts) internal {
ERC20 token = erc20Tokens[_tokenName].tokenAddress;
Treasuries memory leverageTreasury = treasuries["leverage"];
Treasuries memory aquisitionTreasury = treasuries["aquisition"];
Treasuries memory maintenanceTreasury = treasuries["maintenance"];
Treasuries memory reserveTreasury = treasuries["reserve"];
Treasuries memory buyTaxTreasury = treasuries["buyTax"];
require(token.transferFrom(_buyer, leverageTreasury.treasuryAddress, amounts.leverageAmount), "Leverage transfer failed");
require(token.transferFrom(_buyer, aquisitionTreasury.treasuryAddress, amounts.aquisitionAmount), "Acquisition transfer failed");
require(token.transferFrom(_buyer, maintenanceTreasury.treasuryAddress, amounts.maintenanceAmount), "Maintenance transfer failed");
require(token.transferFrom(_buyer, reserveTreasury.treasuryAddress, amounts.reserveAmount), "Reserve transfer failed");
require(token.transferFrom(_buyer, buyTaxTreasury.treasuryAddress, amounts.buyTaxAmount), "Buy tax transfer failed");
}
function withdrawFunds(address tokenAddress, uint256 amount) external onlyAdmin payable returns (bool success){
if (tokenAddress == address(0)) {
require(address(this).balance >= amount, "Insufficient ETH balance");
(success, ) = msg.sender.call{value: amount}("");
require(success, "ETH transfer failed");
} else {
require(tokenAddress != address(0), "Invalid token address");
uint256 balance = ERC20(tokenAddress).balanceOf(address(this));
require(balance >= amount, "Insufficient token balance");
require(ERC20(tokenAddress).transfer(adminAddress, amount), "Token transfer failed");
return true;
}
}
function transferOwnership(address newOwner) external onlyAdmin returns (address) {
require(newOwner != address(0), "Address must not be zero");
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
return owner;
}
}
contract MetallisAirdrop {
IwMetallis internal wMetallisContract;
ImetallisMain internal metallisMainContract;
string public name = "MetallisAirdrop";
bool public paused;
address internal adminAddress;
address internal wMetallisAddress;
address internal metallisMainAddress;
address public owner;
uint256 public totalSlots = 2000;
uint internal minPurchaseAmount = 1;
uint internal campaignId;
uint internal salt;
address[] internal whitelistedAddressesArray;
address[] internal airdropRecipientsArray;
address[] internal blacklistArray;
address[] internal authorizedContractsArray;
address[] internal marketingAddressesArray;
uint[] internal campaignsArray;
struct AirdropRecipient{
address recipientAddress;
uint airdropAmount;
uint date;
uint campaignId;
bytes32 verificationCode;
bool complete;
}
struct AirdropClaims{
uint date;
uint timesClaimed;
uint verificationCode;
}
struct CampaignId{
uint campaignId;
bytes32 verificationCode;
bool active;
uint airdropAmount;
uint maxUses;
uint timestamp;
uint saltValue;
uint last5;
}
struct WhiteList{
address whitelistedAddress;
uint date;
uint airdropAmount;
}
mapping(address => AirdropRecipient) internal recipients;
mapping(bytes32 => CampaignId) internal campaignCodes;
mapping(uint => CampaignId) internal campaignIds;
mapping(address => WhiteList) internal whitelist;
mapping(address => bool) internal whitelisted;
mapping(address => bool) internal blacklist;
mapping(address => bool) internal authorizedContracts;
mapping(address => bool) internal marketingAddresses;
event EtherReceived(address sender, uint256 amount);
event CampaignCreated(uint campaignId, bytes32 verificationCode);
event DebugClaimAirdrop(bytes32 verificationCode, bool activeBefore, bool activeAfter, uint maxUsesBefore, uint maxUsesAfter);
event DebugCampaignState(uint campaignId, bool active, uint maxUses);
event CampaignIdsUpdate(uint campaignId, bool active, uint maxUses);
constructor() {
paused = false;
owner = msg.sender;
adminAddress = 0xa45570bBE3aA2B313E9c2e2b89738b7f04F9Da54;
wMetallisContract = IwMetallis(payable (0xe358f9571a2c83702DA7D53f1dfD1Ffd01d91cE2));
metallisMainContract = ImetallisMain(payable (0x707A8D0fBA270416bE0B14727a6Ac5F735B590e9));
salt = 3597;
campaignId = 1;
}
modifier onlyOwner () {
require(msg.sender == owner, "You are not the owner");
_;
}
modifier onlyAdmin () {
require(msg.sender == adminAddress, "You are not the admin");
_;
}
modifier onlyAuthorizedContracts () {
require (authorizedContracts[msg.sender], "Contract not authorized");
_;
}
modifier onlyMarketing () {
require (marketingAddresses[msg.sender], "Address not Marketing");
_;
}
modifier onlyUser() {
require (tx.origin == msg.sender, "Only EOAs can purchase wMetallis");
_;
}
modifier contractNotPaused() {
require (paused == false, "Contract is paused");
_;
}
function setAdminAddress(address _newAdminAddress) external onlyAdmin returns (address){
adminAddress = (_newAdminAddress);
return adminAddress;
}
function updateAuthorizedContracts(address _contractAddress, bool _status) external onlyAdmin contractNotPaused {
if (_status) {
if (!authorizedContracts[_contractAddress]) {
authorizedContracts[_contractAddress] = true;
authorizedContractsArray.push(_contractAddress);
}
} else {
if (authorizedContracts[_contractAddress]) {
authorizedContracts[_contractAddress] = false;
for (uint i = 0; i < authorizedContractsArray.length; i++) {
if (authorizedContractsArray[i] == _contractAddress) {
authorizedContractsArray[i] = authorizedContractsArray[authorizedContractsArray.length - 1];
authorizedContractsArray.pop();
break;
}
}
}
}
}
function updateMarketingAddresses(address _marketingAddress, bool _status) external onlyOwner contractNotPaused {
if (_status) {
if (!marketingAddresses[_marketingAddress]) {
marketingAddresses[_marketingAddress] = true;
marketingAddressesArray.push(_marketingAddress);
}
} else {
if (marketingAddresses[_marketingAddress]) {
marketingAddresses[_marketingAddress] = false;
for (uint i = 0; i < marketingAddressesArray.length; i++) {
if (marketingAddressesArray[i] == _marketingAddress) {
marketingAddressesArray[i] = marketingAddressesArray[marketingAddressesArray.length - 1];
marketingAddressesArray.pop();
break;
}
}
}
}
}
function updatewMAddress(address _wMetallisAddress) external onlyAdmin contractNotPaused returns (address){
wMetallisAddress = _wMetallisAddress;
wMetallisContract = IwMetallis(payable (_wMetallisAddress));
return wMetallisAddress;
}
function updatemMAddress(address _MetallisMainAddress) external onlyAdmin contractNotPaused returns (address){
metallisMainAddress = _MetallisMainAddress;
metallisMainContract = ImetallisMain(payable (_MetallisMainAddress));
return metallisMainAddress;
}
function addAddressToWhitelist (address _address) external onlyAdmin returns (bool){
isBlacklisted(_address) == false;
require (totalSlots > 0, "No whitelist slots remaining");
require (!whitelisted[_address], "Address is whitelisted");
WhiteList storage newWL = whitelist[_address];
whitelistedAddressesArray.push(_address);
newWL.whitelistedAddress = _address;
whitelisted[_address] = true;
totalSlots --;
if (metallisMainContract.isAddressWhitelisted(_address) == true){
return true;
} else
metallisMainContract.addToWhitelist(_address);
return true;
}
function addToWhitelist (uint _purchaseAmount) external contractNotPaused returns (bool){
address _address = msg.sender;
require(isBlacklisted(_address) == false, "Address is Blacklisted");
require (_purchaseAmount >= minPurchaseAmount, "Purchase Minimum not met");
require (totalSlots > 0, "No whitelist slots remaining");
require (!whitelisted[_address], "Address is whitelisted");
WhiteList storage newWL = whitelist[_address];
whitelistedAddressesArray.push(_address);
newWL.whitelistedAddress = _address;
whitelisted[_address] = true;
totalSlots --;
if (metallisMainContract.isAddressWhitelisted(_address) == true){
return true;
} else
metallisMainContract.addToWhitelist(_address);
return true;
}
function removeAddressFromWL(address _address) external onlyAdmin returns (bool){
totalSlots++;
whitelisted[_address] = false;
whitelist[_address].whitelistedAddress = address(0);
whitelist[_address].date = 0;
whitelist[_address].airdropAmount = 0;
uint length = whitelistedAddressesArray.length;
for (uint i = 0; i < length; i++) {
if (whitelistedAddressesArray[i] == _address) {
whitelistedAddressesArray[i] = whitelistedAddressesArray[length - 1];
whitelistedAddressesArray.pop();
break;
}
}
return true;
}
function isAdmin() external view returns (bool) {
bool check = msg.sender == adminAddress;
return check;
}
function isMarketing() external view returns (bool) {
bool check = marketingAddresses[msg.sender];
return check;
}
function isOwner() external view returns (bool) {
bool check = msg.sender == owner;
return check;
}
function isAuthorizedContract() external view returns (bool) {
bool check = authorizedContracts[msg.sender];
return check;
}
function isWhitelisted() external view returns (bool){
bool onWhitelist = whitelisted[msg.sender];
return onWhitelist;
}
function isAddressWhitelisted(address _whitelistAddress) external onlyAdmin view returns (bool){
bool onWhitelist = false;
if(whitelisted[_whitelistAddress]){
onWhitelist = true;
}
return onWhitelist;
}
function getWhitelistedAddresses() external onlyAuthorizedContracts view returns (address[] memory) {
return whitelistedAddressesArray;
}
function getBlacklist() external onlyAuthorizedContracts view returns (address[] memory) {
return blacklistArray;
}
function isBlacklisted(address _address) internal view returns(bool) {
require (!blacklist[_address], "Address is blacklisted");
return false;
}
function getAllAuthorizedContracts() external onlyAdmin view returns (address[] memory){
return authorizedContractsArray;
}
function getAllMarketingAddresses() external onlyAuthorizedContracts view returns (address[] memory) {
return marketingAddressesArray;
}
function createNewCampaign(uint _airdropAmount, uint _quantity, uint _maxUses) internal {
uint160 sender = uint160(msg.sender);
uint160 last5Digits = sender % 100000;
for (uint i = 0; i < _quantity; i++) {
bytes32 _verificationCode = generateOneTimeCode(salt);
salt++;
CampaignId memory newCampaign = CampaignId({
campaignId: campaignId,
verificationCode: _verificationCode,
active: true,
airdropAmount: _airdropAmount,
maxUses: _maxUses,
timestamp: block.timestamp,
saltValue: salt,
last5: last5Digits
});
campaignsArray.push(newCampaign.campaignId);
campaignCodes[_verificationCode] = newCampaign;
campaignIds[campaignId] = newCampaign;
emit CampaignCreated(campaignId, _verificationCode);
campaignId++;
}
}
function generateOneTimeCode(uint _salt) internal view returns (bytes32) {
uint160 sender = uint160(msg.sender);
uint160 last5Digits = sender % 100000;
bytes memory input = abi.encodePacked(block.timestamp, last5Digits, _salt);
bytes32 oneTimeCode = sha256(input);
return oneTimeCode;
}
function createNewCampaignPool(uint _airdropAmount, uint _quantity, uint _maxUses) external onlyMarketing contractNotPaused{
createNewCampaign(_airdropAmount, _quantity, _maxUses);
}
function getAllCampaigns() external onlyMarketing view returns (CampaignId[] memory) {
CampaignId[] memory allCampaigns = new CampaignId[](campaignsArray.length);
for (uint i = 0; i < campaignsArray.length; i++) {
uint id = campaignsArray[i];
allCampaigns[i] = campaignIds[id];
}
return allCampaigns;
}
function getCampaignById (uint _campaignId) external onlyMarketing view returns (CampaignId memory) {
return campaignIds[_campaignId];
}
function getVerificationCodeById (uint _campaignId) external onlyMarketing view returns (bytes32) {
require(_campaignId <= campaignId, "No campaign created with that Id");
return campaignIds[_campaignId].verificationCode;
}
function getCampaignIdVar () external onlyMarketing view returns (uint) {
return campaignId;
}
function claimAirdrop(bytes32 _verificationCode) external onlyUser contractNotPaused returns (bool) {
require(checkAirdrop(_verificationCode), "Airdrop failed");
address recipAddress = msg.sender;
require(!isBlacklisted(recipAddress), "Address is blacklisted");
AirdropRecipient storage recipient = recipients[recipAddress];
CampaignId storage redeem = campaignCodes[_verificationCode];
CampaignId storage update = campaignIds[redeem.campaignId];
bool activeBefore = redeem.active;
uint maxUsesBefore = redeem.maxUses;
airdropRecipientsArray.push(recipAddress);
recipient.recipientAddress = recipAddress;
recipient.complete = true;
recipient.airdropAmount = redeem.airdropAmount;
recipient.date = block.timestamp;
recipient.verificationCode = _verificationCode;
uint amount = redeem.airdropAmount;
redeem.maxUses--;
if (redeem.maxUses < 1) {
redeem.active = false;
}
update.active = redeem.active;
update.maxUses = redeem.maxUses;
emit DebugClaimAirdrop(_verificationCode, activeBefore, redeem.active, maxUsesBefore, redeem.maxUses);
emit DebugCampaignState(redeem.campaignId, redeem.active, redeem.maxUses);
emit CampaignIdsUpdate(update.campaignId, update.active, update.maxUses);
createNewCampaign(amount, 1, 1);
bool distributeSuccess = wMetallisContract.distributeTokens(recipient.recipientAddress, recipient.airdropAmount);
require(distributeSuccess, "Airdrop failed");
return distributeSuccess;
}
function checkAirdrop(bytes32 _verificationCode) internal view returns(bool){
bool activeCode = campaignCodes[_verificationCode].active;
require(campaignCodes[_verificationCode].maxUses >= 1, "Verification code has been redeemed");
require (activeCode, "Verification code is expired");
return activeCode;
}
function airdropToWhitelisted(uint _amount) external onlyAdmin {
for (uint i = 0; i < whitelistedAddressesArray.length; i++) {
bool success = wMetallisContract.distributeTokens(whitelistedAddressesArray[i], _amount);
require(success, "Airdrop failed for address");
}
}
function changeMinPurchaseAmount(uint _newMin) external onlyAdmin returns (uint){
minPurchaseAmount = _newMin;
return minPurchaseAmount;
}
function addSlots(uint _addSlots) external onlyAdmin returns (uint){
uint remainingSlots = totalSlots;
totalSlots = remainingSlots + _addSlots;
return totalSlots;
}
function removeSlots(uint _removeSlots) external onlyAdmin returns (uint){
uint remainingSlots = totalSlots;
totalSlots = remainingSlots - _removeSlots;
return totalSlots;
}
function pauseContract(bool _paused) external onlyAdmin returns(bool){
paused = _paused;
return paused;
}
function updateBlacklist(address _address, bool _status) external onlyAuthorizedContracts contractNotPaused returns (bool) {
if (_status) {
if (!blacklist[_address]) {
blacklistArray.push(_address);
blacklist[_address] = true;
}
} else {
if (blacklist[_address]) {
blacklist[_address] = false;
for (uint i = 0; i < blacklistArray.length; i++) {
if (blacklistArray[i] == _address) {
blacklistArray[i] = blacklistArray[blacklistArray.length - 1];
blacklistArray.pop();
break;
}
}
}
}
return true;
}
}