Overview

TokenTable smart contracts work together to provide our users with a complete token management and unlocking experience. To best illustrate the entire process, here is an example of the core user workflow which involves all core smart contracts.

Note: all time units are in seconds, including timestamps.

Context

Suppose a startup has fundraised, hired its core team, and uses TokenTable to distribute tokens to its investors and employees. Founders must create and enforce unlocking schedules for their investor/team tokens. Here is a step-by-step guide to accomplish this.

Suppose the unlocking schedule looks like the graph below:

Founder Workflow

1. Deploying a TokenTable Suite

Each startup or organization must deploy its own instance of TokenTable. After deployment, they can use the same instance over multiple unlocking schedules. To deploy, call deployTTSuite(...) .

2. Creating a Preset Unlocking Schedule

A preset contains shared information across all stakeholders within the same unlocking schedule. For example, in the same fundraising round, all investors follow the same unlocking curves and claim intervals. To create a preset, call createPresets(...).

The input parameters to this function are fairly complex:

  • presetId can be set to whatever you want as long as it doesn't exist yet

  • linearStartTimestampsRelative records the start timestamp of the beginning of each linear segment. Cliff releases are treated as linears with a duration of 1 while cliff waiting periods are treated as linears with an unlocking percentage of 0%. In short, everything is a linear segment. Relative means the timestamp is relative to the start time, which isn't specified in the preset.

  • linearEndTimestampRelative is the end timestamp of the final linear segment.

  • linearBips is the number of basis points (bips) each linear segment unlocks. As mentioned above, cliff waiting periods unlock 0 bips. All bips should add up to the hardcoded BIPS_PRECISION variable, which is 10000.

  • numOfUnlocksForEachLinear is the number of unlocks within each linear segment. The minimum value is 1 or else the claim function will always revert. Use 1 for cliff waits and releases.

  • stream determines if unlocked tokens are made available to recipients in discrete unlocks or constant streams.

Here is what the input parameters look like for the unlocking graph above:

linearStartTimestampsRelative: [0, 10, 11, 30, 31, 40, 41, 60, 90],
linearEndTimestampRelative: 130,
linearBips: [0, 1000, 0, 1000, 0, 2000, 0, 2000, 4000],
numOfUnlocksForEachLinear: [1, 1, 1, 1, 1, 1, 1, 3, 4],
stream: false

Here are some more input parameters for different unlocking curves:

3. Creating an Actual Unlocking Schedule

After we create a preset, we can create an actual. An actual is based on a preset but contains information unique to a single token recipient, such as the total locked token amount and start time. To create an actual, call createActuals(...).

An example of input parameters is as follows:

recipients: [0xd8da6bf26964af9d7eed9e03e53415d37aa96045],
actuals: [{presetId: keccak256('seed'), startTimestampAbsolute: 1687263601, amountClaimed: 0, totalAmount: 10000}],
recipientIds: [0],
batchId: 0,
extraData: 0x
  • recipients will receive the unlocking schedules.

  • actuals is an array of Actual structs:

    • presetId is the preset you intend to use (created in the previous step).

    • startTimestampAbsolute is the start time of this actual schedule. This is a standard UNIX timestamp and must be in the future. You can get the current timestamp here: https://www.unixtimestamp.com/

    • amountClaimed indicates how much unlocking this schedule has already done. This is only useful if you are migrating your unlocking system from a different platform. Setting this number allows you to continue the unlocking progress instead of starting over.

    • totalAmount is the total number of tokens to be unlocked.

  • recipientIds: This is only emitted as an event for TokenTable frontend use.

  • batchId: This is only emitted as an event for TokenTable frontend use.

  • extraData: This is passed to the hook directly.

This function safely mints a FutureToken NFT to the recipient's address. The FutureToken determines where the unlocked tokens go to, not the recipient's address. Unlocked tokens are sent to the owner of the corresponding FutureToken and this token can be transferred to a different address by the original recipient.

The token ID (which is the actualId) of the minted FutureToken can be observed through an emitted event in the transaction receipt.

4. Depositing Funds into an Actual Unlocking Schedule

To deposit tokens into the unlocking contract, simply perform a standard ERC-20 transfer(...) with TokenTable Unlocker as to. Partial deposit is supported but if the claimable amount is greater than the amount deposited, the claim action will revert. To prevent this, founders must proactively check the amount deposited is sufficient for recipients to claim and top up accordingly.

5. (Optional) Withdrawing Deposited Funds

The founder can immediately withdraw any unclaimed tokens by calling withdrawDeposit.

6. (Optional) Cancel an Unlocking Schedule

If the founder would like to immediately halt the progress of an unlocking schedule permanently, they can cancel the schedule by calling cancel. Any unlocked but unclaimed tokens are still available for the recipient to withdraw. If the founder created the unlocking schedule by accident and would like to wipe out the recipient's unclaimed claimable tokens, they can do so by setting shouldWipeClaimableBalance: true.

7. (Optional) Enable Delegate Claim

The founder can specify a wallet to act as the claiming delegate and trigger claiming for any recipient. The claimed tokens will go to the recipient's address. This is useful if the recipient is a cold wallet or cannot pay gas.

Stakeholder Workflow

1. Adding FutureToken & TrackerToken to Wallet

By adding the project-specific FutureToken & TrackToken, the stakeholder can interact with their redemption NFT and view the current claimable token amount from the comfort of their own wallet without having to visit TokenTable's website.

2. Claiming Unlocked Tokens

Stakeholders have the option to either claim through TokenTable's website or by calling claim on the block explorer.

3. (Optional) Claiming Unlocked Tokens from a Cancelled Schedule

If the stakeholder's unlocking schedule was canceled, they can claim any leftover unlocked tokens by calling claim.

Last updated