slogan3

Implementeer Veilige Time-Locked Functies in Solidity Smart Contracts

description

Met deze prompt kun je robuuste tijdscontrolemechanismen implementeren in je Solidity smart contracts, waardoor de veiligheid wordt verhoogd door te voorkomen dat functies te vroeg worden uitgevoerd. Je leert meerdere time-locked functies te beheren en kwetsbaarheden door timestampmanipulatie te voorkomen, wat je contracten veiliger en betrouwbaarder maakt dan basisimplementaties.

prompt

Help me met het ontwerpen en implementeren van veilige time-locked functies in mijn Solidity smart contract. Ik wil bepaalde functies beperken zodat ze pas na een specifieke tijd of timestamp uitgevoerd mogen worden. Geef voorbeelden van hoe ik time locks kan instellen, meerdere time-locked functies kan beheren en het contract kan bescherm ...

try_prompt

generate_helper
disclaimerOnPageApi

ai_answers

provider: openai
model: gpt-4.1-nano
Natuurlijk! Hieronder vind je een gedetailleerde uitleg en voorbeelden over het implementeren van veilige time-locked functies in Solidity, inclusief best practices voor beveiliging en gasoptimalisatie. ### 1. Basisprincipes van Time-lock in Solidity Een time-lock zorgt ervoor dat bepaalde functies pas kunnen worden uitgevoerd nadat een bepaalde tijd (timestamp of duur) verstreken is. Dit wordt meestal gedaan door een variabele op te slaan met de unlock-tijd, en in de functie te controleren of de huidige block.timestamp gelijk of groter is dan die waarde. ### 2. Voorbeeldimplementatie Hieronder staat een voorbeeldcontract dat de functies `withdrawFunds` en `changeOwner` time-lockt: ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract TimeLockExample { address public owner; uint256 public withdrawUnlockTime; uint256 public changeOwnerUnlockTime; // Constructor constructor(address _initialOwner) { owner = _initialOwner; // Stel de unlock tijden in withdrawUnlockTime = 1672531200; // 1 januari 2023 00:00:00 UTC changeOwnerUnlockTime = block.timestamp + 7 days; // 7 dagen vanaf nu } // Modifier om te controleren of de functie pas mag worden uitgevoerd modifier onlyAfter(uint256 _time) { require(block.timestamp >= _time, "Time lock niet verstreken"); _; } // Functie om funds te withdrawen, pas na 1 januari 2023 function withdrawFunds() external onlyAfter(withdrawUnlockTime) { // Logica voor withdrawal // Bijvoorbeeld: transfer funds } // Functie om eigenaar te veranderen, pas na 7 dagen function changeOwner(address _newOwner) external onlyAfter(changeOwnerUnlockTime) { require(msg.sender == owner, "Alleen eigenaar kan veranderen"); owner = _newOwner; } // Mogelijkheid om de unlock tijden aan te passen (optioneel, met extra beveiliging) function setWithdrawUnlockTime(uint256 _timestamp) external { require(msg.sender == owner, "Alleen eigenaar"); require(_timestamp > block.timestamp, "Tijd moet in de toekomst liggen"); withdrawUnlockTime = _timestamp; } function setChangeOwnerUnlockTime(uint256 _timestamp) external { require(msg.sender == owner, "Alleen eigenaar"); require(_timestamp > block.timestamp, "Tijd moet in de toekomst liggen"); changeOwnerUnlockTime = _timestamp; } } ``` --- ### 3. Beheer van meerdere time-locked functies Je kunt voor elke functie een aparte variabele gebruiken, zoals hierboven. Als je meerdere functies hebt die verschillende tijden hebben, is het overzichtelijk om een mapping of struct te gebruiken: ```solidity struct TimeLocks { uint256 withdrawTime; uint256 changeOwnerTime; // Voeg meer locks toe indien nodig } mapping(address => TimeLocks) public userLocks; ``` ### 4. Bescherming tegen randgevallen - **Tijdmanipulatie door miner/minimaal risico**: `block.timestamp` kan door miners worden gemanipuleerd met een marge van enkele seconden tot minuten. Voor kritieke functies is het verstandig om een marge te accepteren of meerdere tijdsbronnen te gebruiken. - **Inconsistenties in timestamps**: Zorg dat je nooit op basis van een enkele timestamp vertrouwt zonder extra controles. Bij grote bedragen of belangrijke functies kun je overwegen om een orakel of externe tijdsbron te gebruiken. - **Herhaald gebruiken van dezelfde unlock-tijd**: Voorkom dat iemand de tijd kan aanpassen of resetten nadat de lock is verstreken, tenzij dat de bedoeling is. ### 5. Best practices voor beveiliging - **Gebruik van require**: Controleer altijd of de tijd verstreken is voordat je de functie uitvoert. - **Role-based access control**: Beperk wie de unlock-tijden kan aanpassen. - **Immutable variables**: Overweeg het gebruik van `immutable` voor tijden die niet meer gewijzigd mogen worden na contractdeploy. - **Audit en testen**: Test het contract uitgebreid, vooral de tijdscontroles en randgevallen. ### 6. Gasoptimalisatie tips - **Gebruik van `uint256`**: Dit is standaard en kost het minste gas. - **Minimize state writes**: Minimaliseer het aantal wijzigingen aan de opslag, bijvoorbeeld door enkel de benodigde variabelen te updaten. - **Gebruik van `require` met korte voorwaarden**: De eerste `require` die faalt, voorkomt verdere gasverbruik. --- ### Samenvatting - Gebruik `block.timestamp` met `require` om functies te time-locken. - Stel per functie een specifieke unlock-tijd in. - Beheer meerdere time-locks mogelijk via struct en mappings. - Beveilig tijdmanipulatie door gebruik van marges en controles. - Pas op dat je niet onnodig veel opslag gebruikt om gas te besparen. - Test uitgebreid op randgevallen zoals manipulatie en onverwachte timestamps. --- Heeft u verdere vragen of wilt u dat ik een specifiek voorbeeld uitwerk?
provider: deepseek
model: deepseek-chat
Hier is een complete implementatie van veilige time-locked functies in Solidity: ## Basis TimeLock Contract Structuur ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; contract SecureTimeLock { address public owner; uint256 public constant WITHDRAW_TIMESTAMP = 1672531200; uint256 public constant OWNER_CHANGE_DELAY = 7 days; // Timestamp wanneer changeOwner werd aangevraagd uint256 public ownerChangeRequestTime; // Nieuwe eigenaar adres voor changeOwner functie address public pendingOwner; // Events voor transparantie event WithdrawExecuted(address indexed user, uint256 amount); event OwnerChangeRequested(address indexed newOwner, uint256 unlockTime); event OwnerChanged(address indexed oldOwner, address indexed newOwner); modifier onlyOwner() { require(msg.sender == owner, "Alleen eigenaar"); _; } modifier onlyAfterTimestamp(uint256 timestamp) { require(block.timestamp >= timestamp, "Functie nog niet unlocked"); _; } modifier onlyAfterDelay(uint256 delay) { require(block.timestamp >= delay, "Wachttijd niet verstreken"); _; } constructor() { owner = msg.sender; } // Ontvang ETH (voor testdoeleinden) receive() external payable {} ``` ## Time-Locked Functie Implementaties ```solidity // withdrawFunds - unlocked op specifieke timestamp function withdrawFunds(uint256 amount) external onlyOwner onlyAfterTimestamp(WITHDRAW_TIMESTAMP) { require(amount <= address(this).balance, "Onvoldoende saldo"); // Best practice: gebruik transfer i.p.v. send voor veiligheid payable(owner).transfer(amount); emit WithdrawExecuted(owner, amount); } // changeOwner - unlocked na 7 dagen delay function requestOwnerChange(address newOwner) external onlyOwner { require(newOwner != address(0), "Ongeldig adres"); require(newOwner != owner, "Zelfde als huidige eigenaar"); pendingOwner = newOwner; ownerChangeRequestTime = block.timestamp; emit OwnerChangeRequested(newOwner, block.timestamp + OWNER_CHANGE_DELAY); } function confirmOwnerChange() external onlyAfterDelay(ownerChangeRequestTime + OWNER_CHANGE_DELAY) { require(msg.sender == pendingOwner, "Alleen pending owner"); require(pendingOwner != address(0), "Geen pending owner"); address oldOwner = owner; owner = pendingOwner; pendingOwner = address(0); ownerChangeRequestTime = 0; emit OwnerChanged(oldOwner, owner); } ``` ## Geavanceerde Beveiligingsfuncties ```solidity // Beveiliging tegen timestamp manipulatie modifier reasonableTimestamp() { // Controleer dat block timestamp niet te ver in toekomst of verleden ligt require(block.timestamp <= block.timestamp + 900, "Ongeldige timestamp"); // Max 15 min tolerantie _; } // Emergency stop functie (alleen voor noodgevallen) bool public emergencyStop = false; modifier notStopped() { require(!emergencyStop, "Contract gestopt"); _; } function toggleEmergencyStop() external onlyOwner { emergencyStop = !emergencyStop; } // View functies voor frontend integratie function getWithdrawUnlockTime() external pure returns (uint256) { return WITHDRAW_TIMESTAMP; } function getOwnerChangeUnlockTime() external view returns (uint256) { return ownerChangeRequestTime + OWNER_CHANGE_DELAY; } function isWithdrawUnlocked() external view returns (bool) { return block.timestamp >= WITHDRAW_TIMESTAMP; } function isOwnerChangeUnlocked() external view returns (bool) { return block.timestamp >= (ownerChangeRequestTime + OWNER_CHANGE_DELAY); } } ``` ## Best Practices voor Beveiliging en Optimalisatie ### 1. **Tijdmanipulatie Bescherming** ```solidity // Gebruik block.timestamp i.p.v. block.number voor precieze tijd // Block timestamp heeft ±15 seconden tolerantie function _safeTimestampCheck(uint256 requiredTime) internal view returns (bool) { return block.timestamp >= requiredTime; } ``` ### 2. **Gas Optimalisatie Technieken** ```solidity // Gebruik constanten voor vaste waardes uint256 public constant WITHDRAW_TIMESTAMP = 1672531200; // Pack kleine variabelen samen voor storage optimalisatie struct TimeLockData { uint64 requestTime; uint64 unlockTime; address lockedAddress; } // Gebruik view functies voor read-only operaties function timeUntilUnlock() external view returns (uint256) { if (block.timestamp >= WITHDRAW_TIMESTAMP) return 0; return WITHDRAW_TIMESTAMP - block.timestamp; } ``` ### 3. **Multi-tier TimeLock Systeem** ```solidity // Voor complexere scenario's met meerdere time locks enum FunctionType { WITHDRAW, CHANGE_OWNER, UPGRADE } mapping(FunctionType => uint256) public unlockTimes; mapping(FunctionType => bool) public functionLocked; function setUnlockTime(FunctionType funcType, uint256 unlockTime) external onlyOwner { require(unlockTime > block.timestamp, "Unlock tijd moet in toekomst liggen"); unlockTimes[funcType] = unlockTime; functionLocked[funcType] = true; } function executeFunction(FunctionType funcType) external onlyOwner { require(!functionLocked[funcType] || block.timestamp >= unlockTimes[funcType], "Functie nog gelocked"); // Uitvoeren functie logica } ``` ## Belangrijke Beveiligingsprincipes ### **1. Timestamp Veiligheid** - `block.timestamp` kan door miners met ±15 seconden worden gemanipuleerd - Gebruik `>=` i.p.v. `==` voor timestamp checks - Voeg buffer tijd toe voor kritieke operaties ### **2. Access Control** - Combineer time locks met eigenaar checks - Gebruik multi-signature voor zeer kritieke functies - Implementeer emergency stop mechanisme ### **3. Frontrunning Bescherming** ```solidity // Gebruik commit-reveal pattern voor gevoelige operaties mapping(bytes32 => bool) public commitments; function commit(bytes32 commitment) external payable { commitments[commitment] = true; } function reveal(bytes32 secret) external { bytes32 commitment = keccak256(abi.encodePacked(secret, msg.sender)); require(commitments[commitment], "Ongeldige commitment"); // Uitvoeren actie } ``` ### **4. Test Strategie** ```solidity // Gebruik time-based tests in test suite function testWithdrawAfterUnlockTime() public { vm.warp(WITHDRAW_TIMESTAMP + 1); // Foundry cheatcode contract.withdrawFunds(1 ether); } ``` Deze implementatie biedt een robuust time-lock systeem met aandacht voor beveiliging, gasoptimalisatie en gebruiksgemak. Zorg voor uitgebreide testing en overweeg een audit voor productie-implementaties.