A time lock contract is a security mechanism in Solidity that delays transaction execution by requiring a minimum waiting period (typically 24 hours to several days) between queuing and executing a transaction, giving users time to verify that potentially dangerous operations (like fund transfers, contract upgrades, or oracle switches) are safe before they are actually performed, thereby preventing malicious owners from executing harmful code immediately.
Solidity Timelock Contract Tutorial: Delaying Transactions Securely
Added:time lock is a contract commonly used in defy and dowse the purpose of this contract is to delay a transaction [Music] first you will broadcast the transaction that you're going to execute and this is done by calling the function queue you're queuing a transaction once a transaction is queued you will have to wait a certain amount of time defined in a timeout contract this is usually anywhere from 24 hours to several days once the time has passed then the function execute can be called to execute the transaction these two steps of publishing a transaction that you're about to execute waiting a few days and then actually executing it gives users some time to make sure that the transaction that you're about to execute is nothing dangerous for example here i have a contract called test time lock and i also have a function called test this function can only be called by the time log contract now this function might execute some code to upgrade the contract transfer funds or switch the price oracle any code that gives a lot of power to the owner of the contract you can replace it with a time lock and this will give the users of your contract more trust than you since any potentially dangerous code will have to be queued wait a few days before it can be executed if the owner of the contract is malicious and they try to steal your funds as long as the function is secured by the time block you'll have some time to withdraw your funds before the owner steals your funds so that's the purpose of a timelock contract delay a transaction so that it gives the user some time to react before the transaction is submitted okay so let's write the function for queue the function key will take in the address of the target contract to call it will also take a unit amount of ether to send i'll name it value the function to call this will be string so string call data func and the data to pass to the function bytes call data data and the timestamp after which this transaction can be executed so i'll say uint time stamp now i only want this function to be called by the owner of this contract timelock so let's set the owner of this contract by saying address public owner and then set it inside the constructor constructor owner is equal to message.sender and then we also define a modifier modifier only owner and then we'll say if message.sender is not equal to the owner then we will rebirth with a customer we'll call it not owner error since we have not defined this error we'll copy this and then define it here error not owner error if message.sender is the owner then we'll execute the rest of the code with the underscore and then attach this only owner modifier to the function queue so external only owner to queue a transaction you'll need to first create the transaction id from these parameters and it has to be unique so i'll put a comment here for now and then we'll later write the function out create tx id and then we'll need to check that the transaction id is unique make sure that it is not queued we also need to make sure that the timestamp that was passed from the input is greater than or equal to the minimum delay from the current time so check timestamp and then that's the real queue the transaction okay so let's write the function to compute the transaction id first i'll name this function get tx id and the parameter are these same parameters as the q function paste it here and we'll make this function public so that we can call this function inside this contract and then the user can also call this contract to compute the transaction id this function will be peer and it's going to return the transaction id that was computed so returns bytes 32 tx id to compute the transaction id we'll use the ketchup 256 and hash all of these values so we'll type return getcheck 256 of abi dot encode and we'll encode all of the parameters target value func data time stamp so back inside the function cube we will get the transaction id by calling bytes 32 tx id is equal to get txid of target value func data time stamp next we'll need to check that this transaction id has not been queued yet so we'll create a mapping from transaction id to a boolean if this transaction id is cubed then the boolean will be true otherwise it will be false so i'm going to scroll up and then declare mapping mapping from bytes 32 to boolean public and i'll name it cued and we'll check if the transaction id is unique or not by checking if it is queued or not by typing if cube t x id then we'll rebirth with the error message already cued error passing in the tx id this customer we have not defined it yet so you'll do that right now scroll up and then define pair already cued error this error will take in a single parameter of bytes 32 the tx id okay what do we have to do next so once the code reaches here we know that the transaction is not yet queued so let's check the timestamp we will say that the current block is over here and we need to make sure that this timestamp fits between block plus min and block plus max so our timestamp will have to be somewhere inside here so to do that we'll say if the timestamp from the input is less than block dot timestamp plus main delay we'll define this constant later or if timestamp is greater than block dot timestamp plus max delay then we'll turn our error message with rebirth and we'll call this error timestamp not in range error we'll log the current timestamp block.
timestamp and the timestamp that was passed from the input underscore time stamp and we'll define this error and these constant min delay and max delay so i'll copy this scroll up and then paste error timestamp not in range error this error takes in two inputs the current timestamp you end block time stamp and the timestamp that was passed from the input you and timestamp next let's define the constants mendyday and max delay so we'll say unit public constant main d-day is equal to 10 seconds we'll use 10 seconds for this example so that i don't have to wait a few days but in practice usually men today will be anywhere from a day to two weeks for max today we'll say you and public constant max delay is equal to 1000 and for most contracts on the main net this will be something like 30 days but here for this example you'll just use 1000 seconds scroll back down so once we did some check the next thing is to queue the transaction that's easy all we have to do is say q of tx id is equal to true and then we'll emit the event emit q and we'll log all of the inputs so that'll be target value func data time step we have not defined the c bank yet so let's do that the inputs are going to be the same so copy this scroll up and then we'll define the event e band cue paste the code from the inputs of the function queue we also want to log the transaction id so we'll say bytes 32 tx id and we'll put an index on this indexed same with the target contract indexed and then rename some of the parameters that are being logged remove the underscores and also the call data and then scroll back down we also log tx id and that completes the function for queueing a transaction let's now write the function to execute the transaction the function execute will execute a transaction that's been queued it's going to take in the same parameter as what we passed in the function queue so i'll copy this and then paste it inside the function execute when we execute a transaction by calling this function execute there's a possibility that we might be sending some meter so we'll make this function payable and then also enable this contract to receive some meter by scrolling up and then defining a fallback or receive function here we'll define a receipt so receive external payable now this contract can directly receive either so scroll back down what else do we need to do this function execute similar to the function q we probably only want the owner to be able to execute this function so we'll say only owner once the transaction is executed we'll return the results so you'll say returns bytes memory the first thing that we'll do is get the transaction id so copy this and then paste it here we'll want to check that the transaction has been queued i'll put it as a comment for now and then we'll fill out the code later check tx is queued we also want to make sure that this transaction has been queued for more than minimum delay when we created the function to queue the transaction the timestamp had to be greater than the current time plus the main delay so by the time we get here this timestamp must be greater than the current block timestamp so we'll do a check that the current time blocked up timestamp is greater than timestamp pass from the input and then we'll delete the transaction from q and then execute the transaction to check that the transaction is queued we simply have to look into the mapping queued so we'll type if not queued tx id then we'll throw an error revert not queued error passing in the tx id we have not defined this error yet so i'll copy it and then we'll define it error not q there takes in a single input invites 32 tx id scroll back down next we'll check that the current time stamp is greater than the timestamp that was passed from the input and if this check passes this means that this transaction has rated more than the minimum delay we'll type if blocked up timestamp is less than the timestamp from the input this means that the current time has not suppressed the minimum waiting period so we'll turn our rebirth time stamp not past error and then into there we'll put the current timestamp block dot timestamp and the timestamp from the input copy the error and then declare it over here error timestamp not passed there takes in two inputs the same as one over here so i'll just copy this and then paste it here then we'll scroll back down you also want to have some logic where the transaction is expired for example once the transaction is queued and the current time has surpassed the timestamp we want to make sure that this timestamp is not a time stamp from like a year ago we want to make sure that the transaction to be executed is not expired yet so we'll introduce what's called a grace period let's say that the time stamp from the input is over here and time stamp plus the grace period is over here the transaction is valid to be executed if blocked out timestamp is within this range if however the blocked out timestamp is over here then this means that the transaction is expired we will put this in code by typing if blocked up timestamp is greater than the timestamp from the input plus grace period we'll define this constant later then we'll revert with the error rebirth time stamp expired error passing game block top time stamp and the timestamp plus the grace period timestamp plus grace period so we'll scroll back up and define the error and the constant grace period error timestamp expired error this will take in two inputs u and block timestamp and uint expires at then we also have to define a grace period this will be a constant so i'll type event public constant grace period is equal to for this example we will just say 1000 seconds so this means that once the transaction that's been queued is ready to be executed we have 1000 seconds before the transaction expires scroll back down next we'll delete the transaction from the queue and that's easy we'll type q dot tx id is equal to false and then finally we'll execute the transaction now to execute the transaction we'll type target dot call passing in the value that was passed from the input value underscore value and then passing in some data however notice that we split the function name from the data to pass to the function so we need some logic to prepare the data to be passed to the target contract we will declare the data to be passed by memory data if this function is empty then we'll just simply pass data otherwise this function is not empty so we'll have to abi encode the function and then append the data so to do that we'll say if bytes of func from input dot length is greater than zero then we'll say data is equal to api dot encode packed from the func you'll need to compute the function selector this will be cat check 256 of bytes of funk and then taking the first four bytes of the hash bytes four and that will be the function selector and to this we'll append the data from the input otherwise if function is empty then we'll just directly send the data so else data to send is equal to data from the input executing the transaction this will return two outputs boolean ok and some kind of response bytes memory i'll name it rest as in response and we'll make sure that we got ok back so if not okay then rebirth with tx failed error we'll define this error later and this response that we got back we all want to return it so return press and we also emit the event for execute emit execute passing in the tx id and all of the inputs target value font data time step let's scroll back up and define the event execute and the air tx error scroll back up and then define there tx failed there and the event execute is very similar to the event queue so i'll copy it paste it here and then rename this to execute and that completes the function to execute a transaction let's say that a transaction's been queued and we don't want to execute it we just want to cancel it so let's now write a function to cancel the transaction so say function cancel this will be external and only the owner should be able to call this only owner to cancel a transaction all we need is the transaction id so we'll say bytes 32 tx id underscore tx id we'll check that the transaction has been queued so we'll type if not queued tx id then we'll rebirth with not queued air passing in tx id and we already defined this snob queue there so we don't have to go back up and define it and just double check i'll hit ctrl s to compile the contract and then compile so that means that we have already defined this error we'll remove the transaction from the queue by typing q dot tx id is equal to false and then lastly we'll emit the event emit cancel with txv we have not defined the cpan yet so scroll back up and define the event event cancel bytes 32 tx id and we'll put an index on it indexed and that completes the contract time lock okay let's now test the timelock contract we'll call the function test and this function can only be called if the caller is the timeline contract so we'll deploy the timelock contract and the testtimelock contract and then we'll cue the transaction to call the function test so inside q we'll pass in the address of the testtime.contract amount of e37 0 function to call test data to pass to this function is empty and the time stamp at which this function can be called we'll get the timestamp from a helper function that i created called get timestamp this will return the current timestamp plus 100 seconds so i'll copy this paste it here and then we'll execute the transaction so for the data instead of an empty string i have to pass 0x000 so we need to wait 30 seconds but let's try to call this transaction before the 30 second passage so i'll copy all the inputs and we'll call the function execute and notice that the transaction fails with the error message timestamp not past error so i'll wait a minute or two and then we'll call the function execute again next time this transaction should be successful i waited a minute or two let's now try calling the function execute again so i'll hit transact and this time the transaction was successful so a timelock contract you publish a transaction that you want to execute and after waiting a certain amount of time you can actually execute the transaction [Music] you
Up Next

Build a DAO From Scratch: React, Python, and Solidity
@MoralisWeb3
11K views•2023-02-25

Torrent File Format & Bencoding: A Technical Deep Dive
@AsliEngineering
12.5K views•2022-08-08

Uniswap V2: A Developer's Guide to Solidity and JavaScript
@EatTheBlocks
83.7K views•2020-08-19

Understanding Ethereum: A Comprehensive Beginner's Overview
@99Bitcoins
3.1M views•2018-06-26
Related Study Plans & Knowledge Roadmaps
Structured learning paths in Blockchain & Crypto






































