Untitled
unknown
plain_text
a year ago
5.8 kB
11
Indexable
// Interface for distribution strategies
interface IDistributionStrategy {
function distribute() external;
}
// MasterVault Contract
contract MasterVault is AccessControl {
IERC20 public ubxToken;
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
struct Subvault {
address vaultAddress;
uint256 allocation;
}
Subvault[] public subvaults;
uint256 public totalAllocations;
event SubvaultRegistered(address indexed vaultAddress, uint256 allocation);
event TokensDistributed(address indexed vaultAddress, uint256 amount);
constructor(IERC20 _ubxToken) {
ubxToken = _ubxToken;
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
_setupRole(ADMIN_ROLE, msg.sender);
}
function registerSubvault(address vaultAddress, uint256 allocation) external onlyRole(ADMIN_ROLE) {
require(vaultAddress != address(0), "Invalid vault address");
require(allocation > 0, "Allocation must be greater than zero");
for (uint256 i = 0; i < subvaults.length; i++) {
require(subvaults[i].vaultAddress != vaultAddress, "Vault already registered");
}
subvaults.push(Subvault(vaultAddress, allocation));
totalAllocations += allocation;
emit SubvaultRegistered(vaultAddress, allocation);
}
function distributeTokens(uint256 amount) external onlyRole(ADMIN_ROLE) {
require(totalAllocations > 0, "No subvaults registered");
for (uint256 i = 0; i < subvaults.length; i++) {
Subvault storage subvault = subvaults[i];
uint256 distributeAmount = (amount * subvault.allocation) / totalAllocations;
require(ubxToken.transfer(subvault.vaultAddress, distributeAmount), "Transfer failed");
IDistributionStrategy(subvault.vaultAddress).distribute();
emit TokensDistributed(subvault.vaultAddress, distributeAmount);
}
}
}
// PrivateSaleVault Contract
contract PrivateSaleVault is IDistributionStrategy, AccessControl {
IERC20 public ubxToken;
uint256 public totalAllocation;
uint256 public initialReleaseAmount;
uint256 public vestingStartTime;
uint256 public vestingDuration;
uint256 public withdrawInterval;
uint256 public totalParticipantAllocation;
struct Participant {
uint256 allocation;
uint256 withdrawn;
uint256 lastWithdrawTime;
}
mapping(address => Participant) private participants;
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
event TokensWithdrawn(address indexed user, uint256 amount);
event ParticipantAdded(address indexed participant, uint256 allocation);
event ParticipantRemoved(address indexed participant);
constructor(
IERC20 _ubxToken,
uint256 _totalAllocation,
uint256 _vestingStartTime,
uint256 _vestingDuration,
uint256 _withdrawInterval
) {
ubxToken = _ubxToken;
totalAllocation = _totalAllocation;
initialReleaseAmount = (_totalAllocation * 10) / 100; // 10% initial release
vestingStartTime = _vestingStartTime;
vestingDuration = _vestingDuration;
withdrawInterval = _withdrawInterval;
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
_setupRole(ADMIN_ROLE, msg.sender);
}
function addParticipant(address participant, uint256 allocation) external onlyRole(ADMIN_ROLE) {
require(participant != address(0), "Invalid participant address");
require(allocation > 0, "Invalid allocation");
require(participants[participant].allocation == 0, "Participant already added");
participants[participant] = Participant({
allocation: allocation,
withdrawn: 0,
lastWithdrawTime: vestingStartTime
});
totalParticipantAllocation += allocation;
emit ParticipantAdded(participant, allocation);
}
function removeParticipant(address participant) external onlyRole(ADMIN_ROLE) {
require(participant != address(0), "Invalid participant address");
require(participants[participant].allocation > 0, "Participant not found");
totalParticipantAllocation -= participants[participant].allocation;
delete participants[participant];
emit ParticipantRemoved(participant);
}
function calculateVestedAmount(address participant) public view returns (uint256) {
if (block.timestamp < vestingStartTime) {
return 0;
}
uint256 initialAmount = (participants[participant].allocation * 10) / 100;
uint256 elapsedTime = block.timestamp - vestingStartTime;
uint256 totalVested = initialAmount + ((participants[participant].allocation * 90 * elapsedTime) / (100 * vestingDuration));
uint256 participantShare = (totalVested * participants[participant].allocation) / totalParticipantAllocation;
return participantShare;
}
function withdrawTokens() external {
require(block.timestamp >= vestingStartTime, "Vesting period not started");
require(block.timestamp >= participants[msg.sender].lastWithdrawTime + withdrawInterval, "Withdraw interval not reached");
uint256 vestedAmount = calculateVestedAmount(msg.sender);
uint256 withdrawableAmount = vestedAmount - participants[msg.sender].withdrawn;
require(withdrawableAmount > 0, "No tokens available for withdrawal");
participants[msg.sender].withdrawn += withdrawableAmount;
participants[msg.sender].lastWithdrawTime = block.timestamp;
require(ubxToken.transfer(msg.sender, withdrawableAmount), "Transfer failed");
emit TokensWithdrawn(msg.sender, withdrawableAmount);
}
}
Editor is loading...
Leave a Comment