TokenTable Crashcourse
Last updated
Last updated
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.
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:
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(...)
.
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:
Here are some more input parameters for different unlocking curves:
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
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.
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.
The founder can immediately withdraw any unclaimed tokens by calling withdrawDeposit
.
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
.
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.
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 wallet without having to visit TokenTable's website.
Stakeholders have the option to either claim through TokenTable's website or by calling claim
on the block explorer.
If the stakeholder's unlocking schedule was canceled, they can claim any leftover unlocked tokens by calling claim
.