// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
importar "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contrato PhilanthropyToken es ERC20, Ownable {
uint256 public constant MAX_TOTAL_SUPPLY = 500 * 10 ** 6 * 10 ** 18; // Suministro máximo total de 500 millones de tokens
uint256 public constant MARKET_CAP = 10 * 10 ** 6 * 10 ** 18; // Capitalización de mercado por defecto de 10 millones de tokens
uint256 public INVESTOR_ALLOCATION = 4 * 10 ** 6 * 10 ** 18; // 4 millones de tokens para inversores
uint256 public constant GENERAL_PUBLIC_ALLOCATION = 5 * 10 ** 6 * 10 ** 18; // 5 millones de fichas para el público en general
uint256 public CHARITY_ALLOCATION = 4 * 10 ** 6 * 10 ** 18; // 4 millones de fichas para organizaciones benéficas
uint256 public constant PRESALE_ALLOCATION = 5 * 10 ** 6 * 10 ** 18; // 5 millones de fichas para la preventa
uint256 public PRESALE_TOTAL_SOLD = 0;
uint256 public constant INVESTOR_LOCK_PERIOD = 730 días; // 2 años Periodo de bloqueo para inversores
uint256 public constant PRESALE_LOCK_PERIOD = 365 días; // 1 año Periodo de bloqueo para la preventa
uint256 public TOTAL_INITIAL_RELEASED = 0;
uint256 public TOTAL_INVESTOR_CLAIMED = 0;
uint256 public constant PREVENTA_PRECIO = 50 * 10 ** 15; // $0.50 en wei
uint256 public constant TRANSACTION_THRESHOLD = 1 * 10 ** 6 * 10 ** 18; // 1m Umbral de transacción para requerir un código secreto
uint256 public presaleStartTime;
// Mapping to track buyer purchase timestamps
mapping(address => uint256) public lastPurchaseTimestamp;
string public secretCode;
mapping(dirección => bool) public admins;
/**
* Sólo modificador admin
*/
modificador onlyAdmin() {
require(admins[msg.sender] || msg.sender == owner(), "No es un admin");
_;
}
/**
* constructor
*/
constructor() ERC20("PhilanthropyToken", "PTPH") {
// Mint the initial supply to the contract owner
_mint(msg.sender, MARKET_CAP);
presaleStartTime = block.timestamp;
// Transfer ownership to the contract deployer!
transferOwnership(msg.sender);
}
// Function to add or remove admins
function setAdmin(dirección _admin, bool _estado) external onlyOwner {
admins[_admin] = _estado;
}
/**
* Función que permite a los usuarios comprar fichas de preventa.
* @param amount uint256
*/
function buyPresaleTokens(uint256 amount) external payable {
require(importe > 0, "Importe de compra no válido");
requerir(
block.timestamp >= presaleStartTime,
"La preventa aún no ha comenzado"
);
requerir(
block.timestamp <= presaleStartTime + 182.5 days,
"La preventa ha finalizado"
);
uint256 totalPrice = importe * PRESALE_PRICE;
require(msg.value >= totalPrice, "Envío de fondos insuficientes");
// Calculate and check remaining presale allocation
uint256 remainingPresaleAllocation = PRESALE_TOTAL_SOLD;
requerir(
amount <= remainingPresaleAllocation,
"No hay suficientes fichas disponibles para comprar"
);
// Transfer tokens to the buyer
_transfer(address(this), msg.sender, amount);
// Update the buyer's last purchase timestamp
lastPurchaseTimestamp[msg.sender] = block.timestamp;
// Refund any excess funds sent
if (msg.value > totalPrice) {
pagable(msg.sender).transfer(msg.value - totalPrice);
}
PRESALE_TOTAL_SOLD += importe;
}
/**
* Función de aumentar la capitalización bursátil
* @param amount uint256
*/
function increaseMarketCap(uint256 amount) external onlyAdmin {
uint256 suministroactual = suministrototal();
requerir(
currentSupply + amount <= MAX_TOTAL_SUPPLY,
"Supera el suministro total máximo"
);
_mint(propietario(), importe);
}
/**
* Función para distribuir CHARITY_ALLOCATION a múltiples direcciones
* @param recipients string<addresses>
* @param amounts uint256
*/
función initialRelease(
dirección[] receptores de memoria,
uint256[] cantidades de memoria
) externo onlyAdmin {
requerir(
destinatarios.longitud == importes.longitud,
"Las longitudes de las matrices no coinciden"
);
requerir(
block.timestamp >= presaleStartTime + PRESALE_LOCK_PERIOD,
"El periodo de bloqueo no ha terminado"
);
for (uint256 i = 0; i < recipients.length; i++) {
dirección destinatario = destinatarios[i];
uint256 importe = importes[i];
require(destinatario != dirección(0), "Dirección de destinatario no válida");
require(importe > 0, "Importe no válido");
TOTAL_INITIAL_RELEASED += importe;
requerir(
TOTAL_INITIAL_RELEASED <= CHARITY_ALLOCATION,
"La distribución total excede CHARITY_ALLOCATION"
);
// Transfer tokens to the recipient
_transfer(address(this), recipient, amount);
}
}
/**
* Función para distribuir INVESTOR_ALLOCATION a múltiples inversores.
* @param dirección del inversor
* @param amounts uint256
*/
función claimInvestorTokens(
dirección[] inversores de memoria,
uint256[] cantidades de memoria
) externo onlyAdmin {
requerir(
inversores.longitud == cantidades.longitud,
"Las longitudes de las matrices no coinciden"
);
requerir(
block.timestamp >= presaleStartTime + INVESTOR_LOCK_PERIOD,
"El periodo de bloqueo no ha terminado"
);
for (uint256 i = 0; i < investors.length; i++) {
dirección inversor = inversores[i];
uint256 importe = importes[i];
require(inversor != dirección(0), "Dirección del inversor no válida");
require(importe > 0, "Importe no válido");
TOTAL_INVESTOR_CLAIMED += importe;
// Check if totalDistribution exceeds INVESTOR_ALLOCATION
requerir(
TOTAL_INVESTOR_CLAIMED <= INVESTOR_ALLOCATION,
"La distribución total excede INVESTOR_ALLOCATION"
);
// Transfer tokens to the investor
_transfer(address(this), investor, amount);
}
}
// Function to set a secret code for transactions above the threshold
function setSecretCode(cadena codigo memoria) external onlyAdmin {
secretCode = código;
}
// Function to perform a transaction above the threshold with the correct secret code
función transferencia(
dirección del destinatario,
uint256 cantidad,
código de memoria de cadena
) externo {
require(amount <= TRANSACTION_THRESHOLD, "Amount exceeds threshold");
requerir(
keccak256(abi.encodePacked(code)) ==
keccak256(abi.encodePacked(secretCode)),
"Código secreto incorrecto"
);
_transfer(msg.remitente, destinatario, importe);
}
/**
* Función para mostrar el valor de TOTAL_INITIAL_RELEASED
* @return uint256
*/
function getTotalIInvestorAllocation() external view returns (uint256) {
return INVESTOR_ALLOCATION;
}
/**
* Función para mostrar el valor de TOTAL_INVESTOR_CLAIMED
* @return uint256
*/
function getTotalInitialAllocation() external view returns (uint256) {
devuelva CHARITY_ALLOCATION;
}
/**
* Función para mostrar el valor de TOTAL_INITIAL_RELEASED
* @return uint256
*/
function getTotalInitialReleased() external view returns (uint256) {
return TOTAL_INITIAL_RELEASED;
}
/**
* Función para mostrar el valor de TOTAL_INVESTOR_CLAIMED
* @return uint256
*/
function getTotalInvestorClaimed() external view returns (uint256) {
return TOTAL_INVESTOR_CLAIMED;
}
/**
* Función para transferir fichas entre TOTAL_INITIAL_RELEASED y TOTAL_INVESTOR_CLAIMED
* @param amount uint256
* @param fromInitialToInvestor boolean
*/
función transferirEntreCategorías(
uint256 cantidad,
bool fromInitialToInvestor
) externo onlyAdmin {
requerir(
fromInitialToInvestor || TOTAL_INITIAL_RELEASED >= importe,
"Tokens insuficientes en INITIAL_RELEASED"
);
requerir(
!fromInitialToInvestor || TOTAL_INVESTOR_CLAIMED >= importe,
"Fichas insuficientes en INVESTOR_CLAIMED"
);
if (fromInitialToInvestor) {
CHARITY_ALLOCATION -= importe;
INVESTOR_ALLOCATION += importe;
} else {
INVESTOR_ALLOCATION -= importe;
Asignación_de_caridad += importe;
}
_transfer(address(this), msg.sender, amount);
}
/**
* Función para transferir fichas entre TOTAL_INITIAL_RELEASED y TOTAL_INVESTOR_CLAIMED
* @param amount uint256
* @param fromInitialToInvestor boolean
*/
función topupCategories(
uint256 cantidad,
bool fromInitialToInvestor
) externo onlyAdmin {
requerir(
fromInitialToInvestor || CHARITY_ALLOCATION >= importe,
"Tokens insuficientes en INITIAL_RELEASED"
);
requerir(
!fromInitialToInvestor || TOTAL_INVESTOR_CLAIMED >= importe,
"Fichas insuficientes en INVESTOR_CLAIMED"
);
if (fromInitialToInvestor) {
CHARITY_ALLOCATION -= importe;
INVESTOR_ALLOCATION += importe;
} else {
INVESTOR_ALLOCATION -= importe;
Asignación_de_caridad += importe;
}
_transfer(address(this), msg.sender, amount);
}
/**
* Función para recargar CHARITY_ALLOCATION del saldo disponible del contrato.
* @param amount uint256
*/
function topUpCharityAllocation(uint256 amount) external onlyAdmin {
uint256 availableBalance = balanceOf(address(this));
require(amount <= availableBalance, "Exceeds available balance");
Asignación_de_caridad += importe;
_transfer(address(this), owner(), amount);
}
/**
* Función para recargar INVESTOR_ALLOCATION a partir del saldo disponible del contrato.
* @param amount uint256
*/
function topUpInvestorAllocation(uint256 amount) external onlyAdmin {
uint256 availableBalance = balanceOf(address(this));
require(amount <= availableBalance, "Exceeds available balance");
INVESTOR_ALLOCATION += importe;
_transfer(address(this), owner(), amount);
}
}