Documentación técnica del contrato Optipool
/**
*Submitted for verification at BscScan.com on 2026-02-11
*/
/**
*Submitted for verification at testnet.bscscan.com on 2026-02-11
*/
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IBEP20 {
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function transfer(address to, uint256 amount) external returns (bool);
function balanceOf(address owner) external view returns (uint256);
function decimals() external view returns (uint8);
}
contract Optipool {
struct Participant {
uint256 referrerId;
}
struct Investment {
uint256 amount;
uint256 startTimestamp;
uint256 duration;
uint256 reward;
bool active;
uint8 poolId;
}
address public immutable owner;
IBEP20 public immutable usdt;
uint8 public immutable usdtDecimals;
// 👉 NUEVO
address public immutable marketplaceWallet;
uint256 public nextId = 2;
mapping(address => uint256) public walletToId;
mapping(uint256 => address) public idToWallet;
mapping(address => Participant) public participants;
mapping(address => uint256) public userReferrer;
mapping(address => mapping(uint256 => address)) public directReferrals;
mapping(address => uint256) public directReferralCount;
uint8 public constant POOLS = 4;
struct PoolConfig {
uint256 duration;
uint16 userRewardBP;
}
mapping(uint8 => PoolConfig) public pools;
uint256 public investmentCounter;
// usuario => investmentId => data
mapping(address => mapping(uint256 => Investment)) public userInvestments;
// capital activo por usuario
mapping(address => uint256) public totalActiveDeposits;
bool private locked;
event Deposit(
address indexed user,
uint256 indexed investmentId,
uint256 amount,
uint8 poolId,
uint256 reward,
uint256 referrerId
);
event Withdraw(
address indexed user,
uint256 indexed investmentId,
uint256 amountWithdrawn
);
event ReferralBonus(
address indexed referrer,
address indexed referee,
uint256 amount,
uint8 poolId
);
// 👉 opcional, solo informativo para frontend
event MarketplaceFunded(uint256 amount);
modifier nonReentrant() {
require(!locked, "Reentrancy");
locked = true;
_;
locked = false;
}
// 👉 constructor con wallet del marketplace
constructor(address _usdt, address _marketplaceWallet) {
require(_usdt != address(0), "USDT required");
require(_marketplaceWallet != address(0), "MARKETPLACE required");
owner = msg.sender;
usdt = IBEP20(_usdt);
usdtDecimals = IBEP20(_usdt).decimals();
marketplaceWallet = _marketplaceWallet;
walletToId[msg.sender] = 1;
idToWallet[1] = msg.sender;
participants[msg.sender] = Participant(1);
pools[0] = PoolConfig(7 days, 200);
pools[1] = PoolConfig(14 days, 400);
pools[2] = PoolConfig(21 days, 700);
pools[3] = PoolConfig(30 days, 1000);
}
function _safeTransferFrom(address token, address from, address to, uint256 amount) private {
(bool success, bytes memory data) =
token.call(abi.encodeWithSelector(IBEP20.transferFrom.selector, from, to, amount));
require(success && (data.length == 0 || abi.decode(data,(bool))), "transferFrom failed");
}
function _safeTransfer(address token, address to, uint256 amount) private {
(bool success, bytes memory data) =
token.call(abi.encodeWithSelector(IBEP20.transfer.selector, to, amount));
require(success && (data.length == 0 || abi.decode(data,(bool))), "transfer failed");
}
function _register(address user, uint256 referrerId) internal returns(uint256,uint256) {
if(walletToId[user] != 0){
return (walletToId[user], participants[user].referrerId);
}
uint256 refId = referrerId;
if(refId == 0 || idToWallet[refId] == address(0) || refId == nextId){
refId = 1;
}
address refAddr = idToWallet[refId];
if(refAddr == user){
refId = 1;
refAddr = idToWallet[1];
}
uint256 newId = nextId++;
walletToId[user] = newId;
idToWallet[newId] = user;
participants[user] = Participant(refId);
userReferrer[user] = refId;
uint256 idx = directReferralCount[refAddr];
directReferrals[refAddr][idx] = user;
directReferralCount[refAddr] = idx + 1;
return (newId, refId);
}
function _getReferralPercent(address referrer) internal view returns(uint16) {
uint256 total = totalActiveDeposits[referrer];
uint256 d = 10 ** usdtDecimals;
if (total >= 5000 * d) return 1000;
if (total >= 2500 * d) return 800;
if (total >= 1000 * d) return 600;
if (total >= 500 * d) return 400;
if (total >= 250 * d) return 300;
if (total >= 50 * d) return 200;
return 0;
}
function deposit(uint256 amount, uint8 poolId, uint256 referrerId) external nonReentrant {
require(poolId < POOLS, "Invalid pool");
uint256 d = 10 ** usdtDecimals;
require(amount >= 1 * d, "Min 1 USDT");
require(amount <= 7000 * d, "Max 7000");
require(totalActiveDeposits[msg.sender] + amount <= 7000 * d, "User limit");
(, uint256 assignedRefId) = _register(msg.sender, referrerId);
PoolConfig memory pool = pools[poolId];
uint256 userReward = amount * pool.userRewardBP / 10000;
address referrer = idToWallet[assignedRefId];
uint16 refBP = _getReferralPercent(referrer);
uint256 refBonus = amount * refBP / 10000;
_safeTransferFrom(address(usdt), msg.sender, address(this), amount);
investmentCounter++;
uint256 invId = investmentCounter;
userInvestments[msg.sender][invId] = Investment({
amount: amount,
startTimestamp: block.timestamp,
duration: pool.duration,
reward: userReward,
active: true,
poolId: poolId
});
totalActiveDeposits[msg.sender] += amount;
if(refBonus > 0){
require(usdt.balanceOf(address(this)) >= refBonus, "No referral funds");
_safeTransfer(address(usdt), referrer, refBonus);
emit ReferralBonus(referrer, msg.sender, refBonus, poolId);
}
emit Deposit(
msg.sender,
invId,
amount,
poolId,
userReward,
assignedRefId
);
}
function withdraw(uint256 investmentId) external nonReentrant {
Investment storage inv = userInvestments[msg.sender][investmentId];
require(inv.active, "Not active");
require(block.timestamp >= inv.startTimestamp + inv.duration, "Locked");
uint256 totalOut = inv.amount + inv.reward;
require(usdt.balanceOf(address(this)) >= totalOut, "No balance");
inv.active = false;
totalActiveDeposits[msg.sender] -= inv.amount;
_safeTransfer(address(usdt), msg.sender, totalOut);
emit Withdraw(msg.sender, investmentId, totalOut);
}
/* -------------------------------------------------
👉 FUNCIÓN PARA EL MARKETPLACE
La wallet autorizada transfiere USDT al contrato
(no altera participaciones ni rewards fijos)
------------------------------------------------- */
function fundFromMarketplace(uint256 amount) external nonReentrant {
require(msg.sender == marketplaceWallet, "ONLY_MARKETPLACE");
require(amount > 0, "ZERO_AMOUNT");
_safeTransferFrom(address(usdt), msg.sender, address(this), amount);
emit MarketplaceFunded(amount);
}
function getTimeToUnlock(address user, uint256 investmentId) external view returns(uint256){
Investment memory inv = userInvestments[user][investmentId];
if(!inv.active) return 0;
if(block.timestamp >= inv.startTimestamp + inv.duration) return 0;
return (inv.startTimestamp + inv.duration) - block.timestamp;
}
function getCurrentReferralBonusPercent(address referrer) external view returns(uint16){
return _getReferralPercent(referrer);
}
function getTotalContractBalance() external view returns(uint256){
return usdt.balanceOf(address(this));
}
receive() external payable { revert(); }
fallback() external payable { revert(); }
}Interface IBEP20
2️⃣ Structs
🔹 Participant
🔹 Investment
3️⃣ Sistema de IDs y referidos
4️⃣ Variables globales principales
5️⃣ Pools
6️⃣ Inversiones
7️⃣ Reentrancy guard
8️⃣ Gestión de wallets de liquidez
9️⃣ Acumulador de depósitos activos
🔟 Eventos
1️⃣1️⃣ Constructor
1️⃣2️⃣ Modifiers
onlyOwner
nonReentrant
onlyLiquidityWallet
1️⃣3️⃣ Funciones internas de transferencia
1️⃣4️⃣ Administración de wallets de liquidez
authorizeLiquidityAddress
revokeLiquidityAddress
1️⃣5️⃣ Registro de usuarios
1️⃣6️⃣ Funciones de lectura
1️⃣7️⃣ Porcentaje dinámico de referidos
1️⃣8️⃣ Depósito de usuarios
1️⃣9️⃣ Inyección de fondos del marketplace
2️⃣0️⃣ Retiro de usuarios
2️⃣1️⃣ Funciones de consulta
getActiveInvestment
getTotalContractBalance
getTimeToUnlock
getCurrentReferralBonusPercent
2️⃣2️⃣ receive / fallback
❓ ¿El owner puede drenar los fondos del contrato?
👉 Respuesta directa y honesta:
Verificación técnica
¿Puede el owner drenar los fondos indirectamente?
🔴 No.
¿Puede el owner crear una wallet de liquidez y luego retirar?
🔴 Tampoco.
⚠️ Única forma en la que los fondos salen del contrato
✅ Conclusión final
✔ El owner NO puede drenar los fondos.
✔ No existe función de emergencia para retirar.
✔ No existe puerta trasera administrativa.
✔ No existe privilegio de extracción.
PreviousMitos y Verdades de BNBFund.ioNextChecklist de Seguridad y Buenas Prácticas de Auditoría — BNBFund
Last updated


