# Lockups WARNING: All code related to Lockups is unaudited. Use at your own risk. ## Introduction The **Lockup** program provides a simple mechanism to lockup tokens of any mint, and release those funds over time as defined by a vesting schedule. Although these lockups track a target **beneficiary**, who will eventually receive the funds upon vesting, a proper deployment of the program will ensure this **beneficiary** can never actually retrieve tokens before vesting. Funds are *never* in an SPL token wallet owned by a user, and are completely program controlled. ## Accounts There is a single account type used by the program. * `Vesting` - An account defining a vesting schedule, realization condition, and vault holding the tokens to be released over time. ## Creating a Vesting Account Lockup occurs when tokens are transferred into the program creating a **Vesting** account on behalf of a **beneficiary** via the `CreateVesting` instruction. There are three parameters to specify: * Start timestamp - unix timestamp (in seconds) of the time when vesting begins. * End timestamp - unix timestamp (in seconds) of the time when all tokens will unlock. * Period count - the amount of times vesting should occur. * Deposit amount - the total amount to vest. * Realizer - the program defining if and when vested tokens can be distributed to a beneficiary. Together these parameters form a linearly unlocked vesting schedule. For example, if one wanted to lock 100 SPL tokens that unlocked twice, 50 each time, over the next year, one would use the following parameters (in JavaScript). ```javascript const startTimestamp = Date.now()/1000; const endTimestamp = Date.now()/1000 + 60*60*24*365; const periodCount = 2; const depositAmount = 100 * 10**6; // 6 decimal places. const realizer = null; // No realizer in this example. ``` From these five parameters, one can deduce the total amount vested at any given time. Once created, a **Vesting** account's schedule cannot be mutated. ## Withdrawing from a Vesting Account Withdrawing is straightforward. Simply invoke the `Withdraw` instruction, specifying an amount to withdraw from a **Vesting** account. The **beneficiary** of the **Vesting** account must sign the transaction, but if enough time has passed for an amount to be vested, and, if the funds are indeed held in the lockup program's vault (a point mentioned below) then the program will release the funds. ## Realizing Locked Tokens Optionally, vesting accounts can be created with a `realizer` program, which is a program implementing the lockup program's `RealizeLock` trait. In addition to the vesting schedule, a `realizer` program determines if and when a beneficiary can ever seize control over locked funds. It's effectively a function returning a boolean: is realized or not. The uses cases for a realizer are application specific. For example, in the case of the staking program, when a vesting account is distributed as a reward, the staking program sets itself as the realizor, ensuring that the only way for the vesting account to be realized is if the beneficiary completely unstakes and incurs the unbonding timelock alongside any other consequences of unstaking (e.g., the inability to vote on governance proposals). This implies that, if one never unstakes, one never receives locked token rewards, adding an additional consideration when managing one's stake. If no such `realizer` exists, tokens are realized upon account creation. ## Whitelisted Programs Although funds cannot be freely withdrawn prior to vesting, they can be sent to/from other programs that are part of a **Whitelist**. These programs are completely trusted. Any bug or flaw in the design of a whitelisted program can lead to locked tokens being released ahead of schedule, so it's important to take great care when whitelisting any program. This of course begs the question, who approves the whitelist? The **Lockup** program doesn't care. There simply exists an **authority** key that can, for example, be a democratic multisig, a single admin, or the zero address--in which case the authority ceases to exist, as the program will reject transactions signing from that address. Although the **authority** can never move a **Vesting** account's funds, whoever controls the **authority** key controls the whitelist. So when using the **Lockup** program, one should always be cognizant of it's whitelist governance, which ultimately anchors one's trust in the program, if any at all. ## Creating a Whitelisted Program To create a whitelisted program that receives withdrawals/deposits from/to the Lockup program, one needs to implement the whitelist transfer interface, which assumes nothing about the `instruction_data` but requires accounts to be provided in a specific [order](https://github.com/project-serum/serum-dex/blob/master/registry/program/src/deposit.rs#L18). Take staking locked tokens as a working example. ### Staking Locked Tokens Suppose you have a vesting account with some funds you want to stake. First, one must add the staking **Registry** as a whitelisted program, so that the Lockup program allows the movement of funds. This is done by the `WhitelistAdd` instruction. Once whitelisted, **Vesting** accounts can transfer funds out of the **Lockup** program and into the **Registry** program by invoking the **Lockup** program's `WhitelistWithdraw` instruction, which, other than access control, simply relays the instruction from the **Lockup** program to the **Registry** program along with accounts, signing the Cross-Program-Invocation (CPI) with the **Lockup**'s program-derived-address to allow the transfer of funds, which ultimately is done by the **Registry**. *It is the Registry's responsibility to track where these funds came from, keep them locked, and eventually send them back.* When creating this instruction on the client, there are two parameters to provide: the maximum `amount` available for transfer and the opaque CPI `instruction_data`. In the example, here, it would be the Borsh serialized instruction data for the **Registry**'s `Deposit` instruction. The other direction follows, similarly. One invokes the `WhitelistDeposit` instruction on the **LockupProgram**, relaying the transaction to the **Registry**, which ultimately transfer funds back into the lockup program on behalf of the **Vesting** account. ## Major version upgrades. Assuming the `authority` account is set on the **Lockup** program, one can use this Whitelist mechanism to do major version upgrades of the lockup program. One can whitelist the new **Lockup** program, and then all **Vesting** accounts would invidiually perform the migration by transferring their funds to the new proigram via the `WhitelistWithdraw` instruction.