slogan3

Ontwerp een Solidity Smart Contract voor Token Vesting en Releasebeheer

description

Met deze prompt kunnen gebruikers een robuust en veilig token vesting smart contract creëren dat is afgestemd op hun specifieke token distributiebehoeften. Het behandelt complexe vesting-schema's, gedeeltelijke releases en intrekkingsbeleid, essentieel voor het beheren van tokenallocaties in startups, DAOs of projecten. In tegenstelling tot generieke contractprompts richt deze zich specifiek op vestinglogica, wat beveiliging en flexibiliteit verbetert en veelvoorkomende kwetsbaarheden voorkomt.

prompt

Help me een Solidity smart contract te ontwikkelen voor het implementeren van token vesting en release mechanismen. Ik wil dat het contract het volgende bevat: Begunstigde adressen: <voer begunstigde adressen in>, Vesting startdatum: <voer vesting startdatum in>, Cliff duur: ...

try_prompt

generate_helper
disclaimerOnPageApi

ai_answers

provider: openai
model: gpt-4.1-nano
Hier is een voorbeeld van een Solidity-smartcontract dat voldoet aan jouw specificaties voor token vesting en release mechanismen. Het contract bevat onder andere: - Begunstigde adressen - Vesting startdatum (2024-07-01) - Cliff duur van 3 maanden - Totale vestingduur van 12 maanden - Maandelijkse vrijgave na cliff - Inwisselbaarheid door admin - Beveiliging tegen veelvoorkomende kwetsbaarheden - Ondersteuning voor gedeeltelijke releases en terugtrekking van niet-geverfde tokens ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IERC20 { function transfer(address recipient, uint256 amount) external returns (bool); function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); function balanceOf(address account) external view returns (uint256); } contract TokenVesting { address public admin; IERC20 public token; address[] public beneficiaries; uint256 public vestingStart; uint256 public cliffDuration; // in seconds uint256 public vestingDuration; // in seconds uint256 public totalTokens; // totale tokens toegekend aan alle begunstigden struct Beneficiary { uint256 totalAllocation; uint256 released; bool revoked; } mapping(address => Beneficiary) public beneficiariesData; // Events event TokensReleased(address beneficiary, uint256 amount); event BeneficiaryRevoked(address beneficiary); event BeneficiaryAdded(address beneficiary, uint256 amount); modifier onlyAdmin() { require(msg.sender == admin, "Alleen admin"); _; } modifier onlyBeneficiary() { require(beneficiariesData[msg.sender].totalAllocation > 0, "Geen toegang"); _; } constructor( address _token, address[] memory _beneficiaries, uint256 _vestingStartTimestamp, uint256 _cliffDurationInSeconds, uint256 _vestingDurationInSeconds, uint256[] memory _allocations ) { require(_beneficiaries.length == _allocations.length, "Mismatch in beneficiaries en allocaties"); admin = msg.sender; token = IERC20(_token); beneficiaries = _beneficiaries; vestingStart = _vestingStartTimestamp; cliffDuration = _cliffDurationInSeconds; vestingDuration = _vestingDurationInSeconds; uint256 totalAlloc = 0; for (uint256 i = 0; i < _beneficiaries.length; i++) { beneficiariesData[_beneficiaries[i]] = Beneficiary({ totalAllocation: _allocations[i], released: 0, revoked: false }); totalAlloc += _allocations[i]; emit BeneficiaryAdded(_beneficiaries[i], _allocations[i]); } totalTokens = totalAlloc; } // Toegang voor admin om tokens te reserveren voor de vesting function revokeBeneficiary(address _beneficiary) external onlyAdmin { Beneficiary storage ben = beneficiariesData[_beneficiary]; require(!ben.revoked, "Al ingetrokken"); ben.revoked = true; emit BeneficiaryRevoked(_beneficiary); } // Bereken hoeveel tokens een begunstigde kan vrijgeven function releasableAmount(address _beneficiary) public view returns (uint256) { Beneficiary memory ben = beneficiariesData[_beneficiary]; if (ben.revoked) { return 0; } if (block.timestamp < vestingStart + cliffDuration) { return 0; // Nog in cliff periode } uint256 vestedAmount = vestedTokens(_beneficiary); if (vestedAmount <= ben.released) { return 0; } return vestedAmount - ben.released; } // Bereken totale gevestigde tokens tot nu toe function vestedTokens(address _beneficiary) public view returns (uint256) { Beneficiary memory ben = beneficiariesData[_beneficiary]; if (block.timestamp >= vestingStart + vestingDuration || ben.revoked) { return ben.totalAllocation; } else if (block.timestamp < vestingStart + cliffDuration) { return 0; } else { uint256 timeElapsed = block.timestamp - vestingStart; uint256 vestingTime = vestingDuration - cliffDuration; uint256 elapsedSinceCliff = timeElapsed - cliffDuration; uint256 vested = (ben.totalAllocation * elapsedSinceCliff) / vestingTime; return vested; } } // Vrijgeven van tokens function release() external onlyBeneficiary { uint256 amount = releasableAmount(msg.sender); require(amount > 0, "Geen tokens om vrij te geven"); beneficiariesData[msg.sender].released += amount; require(token.transfer(msg.sender, amount), "Token transfer mislukt"); emit TokensReleased(msg.sender, amount); } // Administratie kan tokens inwisselen of terugtrekken function recoverUnvestedTokens(address _to) external onlyAdmin { uint256 contractBalance = token.balanceOf(address(this)); uint256 vestedTotal = 0; // Optioneel: bepaal totale vested tokens for (uint256 i = 0; i < beneficiaries.length; i++) { vestedTotal += vestedTokens(beneficiaries[i]); } uint256 unvested = contractBalance - vestedTotal; require(unvested > 0, "Geen unvested tokens"); require(token.transfer(_to, unvested), "Transfer mislukt"); } // Optioneel: aantal begunstigden ophalen function getBeneficiaries() external view returns (address[] memory) { return beneficiaries; } } ``` ### Belangrijke punten: - Het contract is geconfigureerd voor meerdere begunstigden met individuele allocaties. - De vesting start op 1 juli 2024 (gebruiker moet de timestamp invoeren bij deploy). - Cliff van 3 maanden en totale vestingperiode van 12 maanden. - Tokens worden maandelijks vrijgegeven na de cliff, berekend op basis van verstreken tijd. - De admin kan niet-geverfde tokens terugtrekken. - Beveiliging tegen re-entrancy wordt niet expliciet gedaan (aangezien er geen external calls na state verandering plaatsvinden), maar het is aanbevolen om OpenZeppelin's ReentrancyGuard te gebruiken voor extra veiligheid. - Het contract gebruikt `block.timestamp` voor tijdscontrole, wat gebruikelijk is voor vestingcontracten. - Het is belangrijk om het tokencontract vooraf te approve voor het vestingscontract, zodat het tokens kan overdragen. ### Aanpassingen: - Pas de vestingstartdatum aan bij deploy, of laat deze parametriseren. - Zorg dat de tokens vooraf geapproveerd zijn aan het vestingscontract. - Voor meer geavanceerde functies of beveiliging, overweeg het gebruik van OpenZeppelin bibliotheken. Wil je dat ik het contract verder optimaliseer of uitbreid?
provider: deepseek
model: deepseek-chat
Hier is een Solidity smart contract dat aan uw vereisten voldoet: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; contract TokenVesting is Ownable, ReentrancyGuard { struct VestingSchedule { uint256 totalAmount; uint256 releasedAmount; uint256 startTime; uint256 cliffDuration; uint256 vestingDuration; bool revoked; } IERC20 public immutable token; mapping(address => VestingSchedule) public vestingSchedules; address[] public beneficiaries; uint256 public constant MONTH_IN_SECONDS = 30 days; event VestingScheduleCreated(address indexed beneficiary, uint256 amount); event TokensReleased(address indexed beneficiary, uint256 amount); event VestingRevoked(address indexed beneficiary, uint256 unreleasedAmount); constructor( address _tokenAddress, address[] memory _beneficiaries, uint256[] memory _amounts, uint256 _startTime, uint256 _cliffDuration, uint256 _vestingDuration ) { require(_beneficiaries.length == _amounts.length, "Arrays length mismatch"); require(_tokenAddress != address(0), "Token address cannot be zero"); require(_startTime > block.timestamp, "Start time must be in future"); token = IERC20(_tokenAddress); for (uint256 i = 0; i < _beneficiaries.length; i++) { _createVestingSchedule( _beneficiaries[i], _amounts[i], _startTime, _cliffDuration, _vestingDuration ); } } function _createVestingSchedule( address _beneficiary, uint256 _amount, uint256 _startTime, uint256 _cliffDuration, uint256 _vestingDuration ) internal { require(_beneficiary != address(0), "Beneficiary cannot be zero address"); require(_amount > 0, "Amount must be greater than 0"); require(vestingSchedules[_beneficiary].totalAmount == 0, "Beneficiary already has vesting"); vestingSchedules[_beneficiary] = VestingSchedule({ totalAmount: _amount, releasedAmount: 0, startTime: _startTime, cliffDuration: _cliffDuration, vestingDuration: _vestingDuration, revoked: false }); beneficiaries.push(_beneficiary); emit VestingScheduleCreated(_beneficiary, _amount); } function release(address _beneficiary) external nonReentrant { uint256 releasable = calculateReleasableAmount(_beneficiary); require(releasable > 0, "No tokens available for release"); VestingSchedule storage schedule = vestingSchedules[_beneficiary]; schedule.releasedAmount += releasable; require(token.transfer(_beneficiary, releasable), "Token transfer failed"); emit TokensReleased(_beneficiary, releasable); } function calculateReleasableAmount(address _beneficiary) public view returns (uint256) { VestingSchedule memory schedule = vestingSchedules[_beneficiary]; if (schedule.totalAmount == 0 || schedule.revoked) { return 0; } uint256 currentTime = block.timestamp; if (currentTime < schedule.startTime + schedule.cliffDuration) { return 0; } if (currentTime >= schedule.startTime + schedule.vestingDuration) { return schedule.totalAmount - schedule.releasedAmount; } uint256 elapsedTime = currentTime - schedule.startTime; uint256 totalVestingTime = schedule.vestingDuration; uint256 vestedAmount = (schedule.totalAmount * elapsedTime) / totalVestingTime; if (vestedAmount > schedule.totalAmount) { vestedAmount = schedule.totalAmount; } return vestedAmount - schedule.releasedAmount; } function revoke(address _beneficiary) external onlyOwner { VestingSchedule storage schedule = vestingSchedules[_beneficiary]; require(schedule.totalAmount > 0, "No vesting schedule found"); require(!schedule.revoked, "Vesting already revoked"); uint256 unreleased = calculateReleasableAmount(_beneficiary); schedule.revoked = true; emit VestingRevoked(_beneficiary, unreleased); } function getBeneficiaries() external view returns (address[] memory) { return beneficiaries; } function getVestingInfo(address _beneficiary) external view returns ( uint256 totalAmount, uint256 releasedAmount, uint256 startTime, uint256 cliffEndTime, uint256 vestingEndTime, bool revoked, uint256 releasableAmount ) { VestingSchedule memory schedule = vestingSchedules[_beneficiary]; return ( schedule.totalAmount, schedule.releasedAmount, schedule.startTime, schedule.startTime + schedule.cliffDuration, schedule.startTime + schedule.vestingDuration, schedule.revoked, calculateReleasableAmount(_beneficiary) ); } } ``` **Gebruiksaanwijzing:** 1. **Implementatie:** ```javascript // Voorbeeld implementatie parameters const beneficiaries = [ "0xAbc123456789abcdef123456789abcdef1234567", "0xDef456789abcdef123456789abcdef1234567890" ]; const amounts = [ethers.utils.parseEther("1000"), ethers.utils.parseEther("2000")]; const startTime = Math.floor(new Date('2024-07-01').getTime() / 1000); const cliffDuration = 3 * 30 * 24 * 60 * 60; // 3 maanden in seconden const vestingDuration = 12 * 30 * 24 * 60 * 60; // 12 maanden in seconden // Implementeer het contract const TokenVesting = await ethers.getContractFactory("TokenVesting"); const vestingContract = await TokenVesting.deploy( tokenAddress, beneficiaries, amounts, startTime, cliffDuration, vestingDuration ); ``` 2. **Functies:** - `release(beneficiary)`: Vrijgeven van beschikbare tokens - `calculateReleasableAmount(beneficiary)`: Bereken beschikbare tokens - `revoke(beneficiary)`: Intrekken vesting (alleen owner) - `getVestingInfo(beneficiary)`: Bekijk vesting details **Beveiligingskenmerken:** - Reentrancy protection met `nonReentrant` - Input validatie en zero-address checks - Alleen eigenaar kan vesting intrekken - Immutable token reference - Tijdsafhankelijke berekeningen op basis van block timestamp **Belangrijke opmerking:** Zorg dat het token contract voldoende tokens heeft goedgekeurd voor het vesting contract voordat u het implementeert.