# Time-Locked Accounts

> Use time-locking in Mina to implement vesting schedules. Practical examples of setting up a time-lock for MINA tokens using o1js.

Canonical URL: https://docs.minaprotocol.com/zkapps/writing-a-zkapp/feature-overview/time-locked-accounts

Time-locking allows you to pay someone in MINA or other custom tokens subject to a vesting schedule. Tokens are initially locked and become available for withdrawal only after a certain time or gradually according to a specific schedule.

By default, accounts are not time-locked.

The zkApp feature that enables time-locking is the `timing` field that is present on every account:

```ts
type Account = {
  // ...
  timing: {
    isTimed: Bool;
    initialMinimumBalance: UInt64;
    cliffTime: UInt32;
    cliffAmount: UInt64;
    vestingPeriod: UInt32;
    vestingIncrement: UInt64;
  };
};
```

- The `isTimed` field indicates whether this account is time-locked. The default value of `isTimed` is `false`.
- The other fields are parameters with default values that allow you to define a vesting schedule in a very flexible manner.

This graph shows how each of the timing properties affect the vesting schedule:

<figure>
  <img
    src="/img/timelocked.png"
    width="95%"
    alt="Timing parameters"
  />
</figure>

- The red cross on the left marks the point in time where the `timing` field is set.
- `isTimed` switches from `false` to `true`.
- The orange line shows how the amount of unlocked tokens increases over time until it finally reaches its maximum value and stays flat.
- At this point, `isTimed` flips from `true` back to `false` because no tokens remain locked.

As shown, the maximum amount of unlocked tokens is defined by the `initialMinimumBalance`. The property is called `initialMinimumBalance` because, even though the tokens show up in the balance, they can't be withdrawn. The account has a a non-zero _minimum balance_. Initially, that minimum balance is equal to the amount of tokens locked -- so, that amount is the "initial minimum balance". Over time, the minimum balance decreases until it hits zero, which is the condition that makes `isTimed` false again.

The other timing-related properties are:

- `cliffTime`: The initial time period during which all tokens are locked (should be from the current slot onwards). Note that 'time' is measured in Mina by 'slots', where 1 slot is 90 seconds.
- `cliffAmount`: The quantity of tokens to be unlocked when the cliff time has elapsed. If this amount is greater or equal the 'initial minimum balance', all tokens are unlocked after the cliff time elapses.
- `vestingPeriod`: After the cliff time elapses, tokens can be set to unlock periodically at a fixed interval, by a fixed quantity. The vesting period is the length of that interval.
- `vestingIncrement`: The quantity of tokens that are unlocked after each vesting period elapses.

:::note
Only one vesting schedule can be specified per account. The vesting schedule cannot be changed during the vesting period.

Because of this restriction, the values of the timing fields cannot be changed when `isTimed` is set to `true`.
After all tokens are unlocked and `isTimed` flips back to `false`, the account timing becomes mutable again.
:::

### Setting timing in o1js

In o1js, `timing` is one of the account fields that can be updated by using an account update:

```ts
accountUpdate.account.timing.set({ initialMinimumBalance, cliffTime, ...etc });
```

When setting timing, all timing-related properties are required, except for `isTimed` which is automatically set by the protocol.

### Examples

These examples show how to correctly implement several example use cases.

#### Example 1: All tokens unlock after 1 week

If you want all tokens to unlock after a certain time, then the only properties you need to consider are `initialMinimumBalance`, `cliffTime`, and `cliffAmount`.

- Set `cliffAmount` equal to the `initialMinimumBalance` to ensure all tokens are unlocked when the cliff elapses.
- Both `vestingPeriod` and `vestingIncrement` are unused, so set them to their default values, `1` and `0`:

  ```ts
  // example: 10 MINA to lock
  const tokensToLock = UInt64.from(10e9);

  // calculate 1 week in slots
  const cliffPeriod = UInt32.from((60 / 3) * 24 * 7);

  // fetch the current slot from the network
  const currentSlot = this.network.globalSlotSinceGenesis.get();

  accountUpdate.account.timing.set({
    initialMinimumBalance: tokensToLock,
    cliffTime: currentSlot + cliffPeriod,
    cliffAmount: tokensToLock,
    vestingPeriod: UInt32.from(1), // 0 is not allowed; default value is 1
    vestingIncrement: UInt64.from(0),
  });

  this.send({ to: accountUpdate, amount: tokensToLock });
  ```

#### Example 2: Linear vesting over 1 year

This example does not use a cliff, but vests a certain number of tokens linearly over 1 year.

- Set the `vestingPeriod` to equivalent to 1 month defined in slots, so that new tokens are unlocked every month.
- Set the `vestingIncrement` to the total amount divided by 12, so that the total amount is unlocked after 12 months.
- Set both `cliffTime` and `cliffAmount` to 0.

  ```ts
  // example: 100000 MINA to lock
  const tokensToLock = UInt64.from(100000e9);

  // calculate 1 month in slots
  const vestingPeriod = UInt32.from(Math.round(((60 / 3) * 24 * 365) / 12));

  // 1/12th of tokens unlocked every month
  const vestingIncrement = UInt64.from(Math.round(tokensToLock / 12));

  accountUpdate.account.timing.set({
    initialMinimumBalance: tokensToLock,
    cliffTime: UInt32.from(0),
    cliffAmount: UInt64.from(0),
    vestingPeriod,
    vestingIncrement,
  });

  this.send({ to: accountUpdate, amount: tokensToLock });
  ```
