Time-lock contract development: where locking logic breaks
A time-lock contract looks simple: lock tokens for a period and return them on schedule. In practice, time-lock contract development starts not with code but with a rights matrix: who can touch the balance and under what conditions. Most incidents here are not hacks but pre-built opportunities to bypass the restriction.
The first point of failure is delayed withdrawal. Alongside the schedule, an administrative withdrawal function or transfer of ownership often remains: the new owner receives the entire balance, not just the right to manage the schedule. There is one check — funds must have no path out except the deadline fixed in code.
Second is the schedule itself. Errors in locking logic are usually related to a mismatch between the start time and the first tranche, the payment step, share division with rounding, a date in the past.
The result: either the entire amount leaves in a single transfer, or part of the tokens remains inaccessible forever.
Third are roles and keys. A single key leaves no options in case of compromise, but complete freedom to cancel the lock devalues it in the eyes of holders. A working scheme is separation of roles, multisig, and cancellation only in a narrow window, with a public event in the log.
We take proven libraries such as OpenZeppelin as a base and add task-specific logic: we fix rights and schedule before code and cover every branch with tests. The cost of an error is not a UI bug but lost tokens, so we deliver the contract with a report on these four points.
What a time-lock gives treasury and vesting
In treasury, a time-lock contract replaces correspondence, manual signatures, and payment tables with a rule that executes itself. Below is what exactly changes in operations and what effects are visible in metrics.
Payment schedule instead of verbal agreements
Date, share, and recipient are fixed in code before launch, and the transfer occurs only within the specified window. Withdrawing assets early or sending them to another address is technically impossible — the process no longer depends on who exactly runs the payments.
Automatic asset locking removes manual operations
Vesting is executed by the contract, not an employee: there is no need to prepare instructions, collect confirmations, and check dates in a calendar. On long schedules, this removes dozens of manual operations and eliminates standby around unlock dates.
State reconciliation — minutes instead of person-days
How much is locked, how much is available, and when the next unlock is can be read directly from the contract. Accounting, investors, and holders do not need exports and requests: there is a single data source, so no discrepancies arise between parties.
The failure class “paid to the wrong person and at the wrong time” is closed
The recipient address and date are checked at deployment, not after the transfer. For typical scenarios, we use proven OpenZeppelin templates; for non-standard schedules, we write custom logic and cover it with tests.
The residual risk is compromise of the administrator key, and it is closed by multisig with delayed execution.
Implementation options: ready library, custom logic, hybrid
In practice, the choice comes down to three options, and the criterion is one: who owns the rules for locking, accrual, and cancellation — a proven library or your own code.
A time-lock contract rarely exists in a vacuum: nearby are token issuance, an unlock schedule for the team, and treasury payments. Therefore, we compare not by code volume but by predictability of behavior during cancellation, deadline shifts, and early withdrawal.
Reliance on OpenZeppelin covers the typical scenario, but as soon as your own accrual rules appear, it has to be extended — and here the fork begins.
| Option | When it fits | Limitations |
|---|---|---|
| Proven library such as OpenZeppelin | Linear unlock, pause before first release, treasury payments on a fixed schedule | Non-standard accrual and partial cancellation rules require wrapping on top; logic edits are possible only through the upgrade mechanism |
| Fully custom module | Weights, retention bonuses, release date depending on external conditions | Every rule must be covered by tests and audit; an error in term calculation costs more than a ready-made solution |
| Hybrid: library plus custom rules | Standard schedule with custom accrual and cancellation conditions | Part of the state lives in base modules, part in extensions, which makes tracing and audit more complex |
We assemble an upgradeable time-lock so that the schedule is stored separately from logic: then editing the rules does not reset already started locks.
We separate the administrator and cancellation roles, and write all changes to events — from them it is clear why the deadline shifted and who initiated it.
Implementation stages: from locking scheme to code audit
The work order is structured so that the locking scheme is approved before the first line of code: editing logic on paper costs hours, editing in a deployed contract costs weeks, a repeat audit, and a new deployment. Below is the path every time-lock goes through.
- Task analysis. We fix what exactly is locked — tokens, management rights, or liquidity, who the recipient is, by what event access opens, and whether early withdrawal by a third party is allowed.
- Locking scheme on paper. We describe contract states: top-up, waiting, available withdrawal, revocation, emergency stop. We coordinate transitions with the client — at this step most disputed scenarios are removed.
- Implementation. As a base, we take a proven standard library — the current OpenZeppelin branch — and add only what is missing: non-standard unlock schedules, multisig for withdrawal, and binding to an external time source.
- Testing on a test network. We run deployment and all transition branches, including boundary ones: withdrawal exactly at the opening moment, repeated call, top-up after start. We cover edge cases with tests, not with hope for user accuracy.
- Independent contract audit. A separate team that did not write the code reviews it: looking for bypassing time conditions, rounding errors, and the possibility of withdrawing funds early.
- Addressing findings. We close each finding with a fix and re-check — we publish the audit report together with the contract so recipients can see that the issues have been resolved.
- Deployment and support. We deploy to mainnet, hand over addresses, source code, and unlock instructions, and remain available when conditions change.
The key result of the stages is not the code itself but predictable behavior: unlock deadlines are met, and bypassing conditions is closed even before funds appear in the contract.
Delivery scope: code, locking schemes, documentation
Delivery is not an archive with files but a working kit: the client's engineer should have enough materials to deploy the contract, change locking parameters, and investigate an incident without correspondence with us.
Therefore, alongside the code come schemes, policies, and procedures describing the system's behavior over time.
- Source code with explanations for each function: which calls change state, which only read, where funds are stored, and how the build is reproduced from pinned dependencies.
- Timeline scheme: points when the owner removes the lock, when the recipient does, and what happens if the window is missed.
- Role matrix and access policy for administrative functions: who has the right to change the recipient, term, or fee, and which calls are irreversible.
- Explanatory contract documentation: parameters, their permissible bounds, and the consequences of each change for already locked funds.
- Audit report: reviewed paths, findings and their status after fixes, and separately what was deliberately excluded from the audit scope.
- Operations procedure: which events to monitor, who receives a notification about an approaching deadline, and how the history of administrative actions is recorded.
- Failure procedure: lost key, erroneous call, stuck lock — what can be resolved in-house according to instructions, and what requires our involvement.
Transfer of source code is formalized by an act recording the composition and checksums: rights and the repository transfer to the client, and further work does not require our involvement. Documentation is updated together with the code, so the described behavior matches the actual one.
Case: removed manual payments from the treasury
Before: manual payments and a single key
The treasury processed payments manually: a registry in a spreadsheet, checking deadlines by eye, and signing each transaction with one wallet.
At peak, this resulted in about 60 manual operations per month, and a single payment took from two to five days — while the amount was being approved and while the signer was available.
A separate cost of such a scheme was irreversible errors: a wrong recipient address goes to the network without return, and a missed deadline was discovered on the partner's side.
After: schedule and limits in the contract
The schedule, limits, and recipient addresses were moved into a time-lock contract based on OpenZeppelin: we take proven mechanics for locking and releasing funds instead of custom logic that would have to be secured from scratch.
It is impossible to withdraw funds early, and parameter changes go through multiple signatures only. Before launch, the logic was run through an independent audit, and rollback scenarios were rehearsed separately on a network copy.
Manual operations are down to 3-4 per month — only unscheduled payments. A payment that used to take days goes through within 10-15 minutes after the deadline: the contract releases funds itself, and no human is involved in the chain.
A whole class of failures is closed — double payment for one invoice, transfer to an outdated address, and withdrawal before the agreed date. Treasury state is now read from the contract, not from an export, so the registry no longer diverges from reality.
How delayed withdrawal differs from multisig and escrow
Delayed withdrawal (time-lock) is a mechanism in which the disposal of funds is executed not immediately but upon reaching a deadline. The contract accepts a command, queues it, and opens a window during which the payment can be canceled.
The protection is aimed against instant withdrawal: even if the manager's key is compromised, the team still has time to cancel the order before execution.
Multisig closes a different threat — a unilateral decision. An “M of N” threshold means that an operation is valid only when confirmations from different key holders are collected, so theft or loss of one device does not open access to funds.
Escrow ties settlement not to time or signatures but to performance of the transaction. Funds are locked until delivery, acceptance, or an arbitrator's decision is confirmed, and the rules for dispute and return are written into the contract in advance.
In practice, approaches are combined because the threats are different.
In management, a signature threshold and delay are combined: an order is first approved by a qualified majority, then it waits in a queue, and only then is it executed — this closes both collusion and an error in one key.
In settlements, escrow is supplemented with a time-lock: if the second party does not respond, after the deadline the funds are returned to the sender, and the transaction does not get stuck.
Ready libraries, such as OpenZeppelin, provide proven blocks — access roles, a delayed execution queue, threshold confirmations.
But deadlines, threshold size, arbitrator composition, and cancellation rights are set for a specific scheme, and it is these parameters that determine whether the solution will withstand an attack.
Doubts about locking logic: audit, upgrade, access
Doubts about a time-lock are almost always not about unlock arithmetic but about rights management: who can interfere with the schedule and what happens if a key is lost.
Below are five questions we resolve before the audit — the architecture, not the code styling, depends on the answers.
What happens if the administrator key is lost?
We separate the administrator role from the recipient address: the recipient can neither extend nor shorten the term. We assign management to a multisig of several independent custodians — loss of one key does not stop issuance.
Can the schedule be changed after launch?
In the immutable version, no, and this is fixed in code: there are no term-editing functions, and the unlock date is recorded at deployment. The upgradeable version allows shifting, so we restrict it with a controller that has delayed execution.
Why external audit if the logic is on a proven library?
The OpenZeppelin library covers standard roles and depositing, but not your distribution scheme. The audit checks exactly that: call order, issuance rights, and boundary states.
Is the contract upgradeable or immutable?
The choice is set by the storage scheme: in an upgradeable one, data between logic versions is fixed, and initialization is done by a separate call instead of a constructor. By default, we offer an immutable one — fewer attack surfaces.
How does the contract behave at boundaries — the day before unlock and on a repeated call?
Unlocking is possible only after the recorded time and only once: a repeated call reverts, and the transfer follows the “debit first, then send” scheme.
Let's discuss the task: we'll assemble a locking scheme and work plan
To assemble a working locking scheme rather than a universal template, we need initial inputs for your task. Below is what to send; with this scope, we will return with a timeline estimate and a work plan that includes stages, artifacts, and checkpoints.
- Network and environment: where the contract is deployed, whether work in multiple networks is needed, whether there are already issued tokens and related addresses.
- Scope and schedule: how many recipients and shares, how often funds are issued and released, and for what horizon the schedule is built.
- Roles and access: who the owner and operator are, who is allowed to extend or shorten the term, whether multisig and separation of rights are needed.
- Cancellation scenarios: whether early withdrawal is possible, under what conditions, whether there is an emergency stop and who can access it.
- Release logic: linear schedule, steps, or a pause before the first payment; what happens to the undistributed remainder.
- Checks and reporting: whether an external code review is needed, and which events must be visible in external accounting systems.
Describe the task in free form or send the current contract and a description of the share distribution. We will discuss the time-lock contract concretely: where the risks are, what we reuse from proven libraries, what we write separately and why. After that, we will return with a development estimate and work plan.







