From 6068a1de027cccbbb8df6ee50ef641d3ac3b09ae Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Wed, 4 Dec 2024 19:41:20 +0000 Subject: [PATCH 1/3] docs: adds guide to pull vesting information --- .../guides/lockup/examples/08-vesting-data.md | 158 ++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 docs/guides/lockup/examples/08-vesting-data.md diff --git a/docs/guides/lockup/examples/08-vesting-data.md b/docs/guides/lockup/examples/08-vesting-data.md new file mode 100644 index 00000000..3bff5929 --- /dev/null +++ b/docs/guides/lockup/examples/08-vesting-data.md @@ -0,0 +1,158 @@ +--- +id: "vesting-data" +sidebar_position: 8 +title: "Vesting data" +--- + +This guide explains how you can pull vesting data for a stream. This data can be useful in a variety of use cases +including but not limited to staking, explorers, and dashboards: + +1. **Staking**: Staking of Sablier streams require access to amount of tokens that are still in the stream. You do not + want to distribute rewards for tokens that have already been vested and withdrawn by the user. +2. **Explorers (Etherscan, Coingecko)**: One major feature of the explorers is to show the amount of circulating supply + of a token accurately. When tokens are vesting through Sablier streams, you may want to exclude the amount of + unvested tokens from the circulating supply. This is helpful to accurately calculate the marketcap which depends on + the amount of liquid tokens. +3. **Dashboards (Nansen, Tokenomist, Dune)**: Crypto dashboards are used by investors and traders to make informed + decisions. When tokens are vesting through Sablier streams, you may want to show the amount of liquid tokens and the + amount of illiquid (unvested) tokens. This is helpful to understand the token distribution and the team's commitment + to the long-term success of the project. + +## Amount in stream + +Amount in stream is the amount of tokens are available in the stream. It is the sum of locked tokens and vested tokens +that are not yet withdrawn. It is particularly useful for applications like staking. The following formula can be used +for both cancelable and non-cancelable streams: + +```solidity +uint256 amountInStream = sablierLockup.getDepositedAmount(streamId) + - sablierLockup.getWithdrawnAmount(streamId) + - sablierLockup.getRefundedAmount(streamId); +``` + +For non-cancelable stream, a more efficient way to calculate the amount in stream is: + +```solidity +uint256 amountInStream = sablierLockup.getDepositedAmount(streamId) + - sablierLockup.getWithdrawnAmount(streamId); +``` + +:::info + +If you are building a Staking contract for Sablier stream, you can follow the [staking guide](./staking/setup). + +::: + +## Locked amount + +Locked amount is the amount of tokens that are locked in the stream and can be considered as illiquid. This can be +particularly useful during the calculation of circulating supply. + +```solidity +uint256 lockedAmount = lockup.getDepositedAmount(streamId) + - lockup.streamedAmountOf(streamId) + - sablierLockup.getRefundedAmount(streamId); +``` + +For non-cancelable stream, a more efficient way to calculate locked amount is: + +```solidity +uint256 lockedAmount = lockup.getDepositedAmount(streamId) - lockup.streamedAmountOf(streamId); +``` + +:::info + +While calculating the circulating supply, you can subtract locked amount from your calculations. + +::: + +## Unlocked amount + +As opposed to locked amount, unlocked amount is the amount of tokens that are no longer locked and can be considered as +liquid. + +```solidity +uint256 unlockedAmount = lockup.streamedAmountOf(streamId) + + sablierLockup.getRefundedAmount(streamId); +``` + +For non-cancelable stream, a more efficient way to calculate unlocked amount is: + +```solidity +uint256 unlockedAmount = lockup.streamedAmountOf(streamId); +``` + +## Vested amount not withdrawn + +If you are building an application that requires access to amount of tokens that have been vested but not yet withdrawn, +you can use the following formula: + +```solidity +uint256 vestedAmount = lockup.streamedAmountOf(streamId) - lockup.getWithdrawnAmount(streamId); +``` + +This may be useful for use cases in which you want to reward diamond hands i.e. users who have not withdrawn their share +of airdrops. + +## Cancel on first withdraw + +If you want to cancel streams as soon as the user withdraws their tokens, you can track the withdrawn amount and check +if its value is greater than 0. If it is, you can cancel the stream. + +```solidity +if (lockup.getWithdrawnAmount(streamId) > 0) { + lockup.cancel(streamId); +} +``` + +## Unlock events + +This section is useful if you are building a token unlock dashboard where you want to display the future unlock events. + +To calculate the time at which a stream will be fully unlocked, you can use the following formula: + +```solidity +uint256 unlockTime = lockup.getEndTime(streamId); +``` + +### Linear streams + +For lockup linear stream, you can make a request to `lockup.getTimestamps(streamId)` and then calculate cliff time and +end time as `timestamps.cliff` and `timestamps.end` respectively. + +### Dynamic streams + +For lockup dynamic streams, you may be particularly interested in the unlock amount and time of the current segment. + +```solidity +LockupDynamic.Segment[] memory segments = lockup.getSegments(streamId); + +// Loop over the segments to find the next unlock time. +for (uint i; i < segments.length; ++i) { + if (segments[i].timestamp > block.timestamp) { + nextUnlockAmount = segments[i].amount; + nextUnlockTime = segments[i].timestamp; + break; + } +} +``` + +### Tranched streams + +For lockup tranched streams, you may be particularly interested in the unlock amount and time of the current tranche. + +```solidity +LockupTranched.Tranche[] memory tranches = lockup.getTranches(streamId); + +// Loop over the tranches to find the next unlock time. +for (uint i; i < tranches.length; ++i) { + if (tranches[i].timestamp > block.timestamp) { + nextUnlockAmount = tranches[i].amount; + nextUnlockTime = tranches[i].timestamp; + break; + } +} +``` + +I hope this guide was helpful to you. If you have a use case that is not covered here, please reach out to us on +[Discord](https://discord.sablier.com) and we will be happy to help you with your requirements. From 298e8eb388d3ffea9aa9bac6d055eb59ac2b0a19 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Thu, 5 Dec 2024 15:47:48 +0000 Subject: [PATCH 2/3] refactor: polish vesting data guide --- ...esting-data.md => 08-pull-vesting-data.md} | 109 ++++++++++-------- 1 file changed, 62 insertions(+), 47 deletions(-) rename docs/guides/lockup/examples/{08-vesting-data.md => 08-pull-vesting-data.md} (50%) diff --git a/docs/guides/lockup/examples/08-vesting-data.md b/docs/guides/lockup/examples/08-pull-vesting-data.md similarity index 50% rename from docs/guides/lockup/examples/08-vesting-data.md rename to docs/guides/lockup/examples/08-pull-vesting-data.md index 3bff5929..4debcbb9 100644 --- a/docs/guides/lockup/examples/08-vesting-data.md +++ b/docs/guides/lockup/examples/08-pull-vesting-data.md @@ -1,28 +1,58 @@ --- id: "vesting-data" sidebar_position: 8 -title: "Vesting data" +title: "Pull Vesting Data" --- -This guide explains how you can pull vesting data for a stream. This data can be useful in a variety of use cases -including but not limited to staking, explorers, and dashboards: +This guide explains how you can pull vesting data from Sablier Lockup streams. This data can be useful for a variety of +use cases, including but not limited to staking, explorers, and data dashboards: -1. **Staking**: Staking of Sablier streams require access to amount of tokens that are still in the stream. You do not - want to distribute rewards for tokens that have already been vested and withdrawn by the user. -2. **Explorers (Etherscan, Coingecko)**: One major feature of the explorers is to show the amount of circulating supply - of a token accurately. When tokens are vesting through Sablier streams, you may want to exclude the amount of - unvested tokens from the circulating supply. This is helpful to accurately calculate the marketcap which depends on - the amount of liquid tokens. -3. **Dashboards (Nansen, Tokenomist, Dune)**: Crypto dashboards are used by investors and traders to make informed - decisions. When tokens are vesting through Sablier streams, you may want to show the amount of liquid tokens and the - amount of illiquid (unvested) tokens. This is helpful to understand the token distribution and the team's commitment - to the long-term success of the project. +1. **Staking**: Staking of Sablier streams require access to amount of tokens that are still held by the stream. You do + not want to distribute rewards for tokens that have been withdrawn by the user. +2. **Explorers (Etherscan, Coingecko)**: One major feature of blockchain explorers is to show accurate circulating + supplies. When tokens are vesting through Sablier, you may want to exclude the amount of unvested tokens from the + circulating supply. This is helpful to accurately calculate the market cap, which depends upon the amount of liquid + tokens. +3. **Data Dashboards (Tokenomist, Nansen, Dune)**: Investors and traders use data dashboards to make informed trading + decisions. When Sablier is used, you may want to show the amount of liquid (or vested) tokens and the amount of + illiquid (or unvested) tokens. This is helpful to understand the token distribution and the team's commitment to the + long-term success of the project. -## Amount in stream +:::note -Amount in stream is the amount of tokens are available in the stream. It is the sum of locked tokens and vested tokens -that are not yet withdrawn. It is particularly useful for applications like staking. The following formula can be used -for both cancelable and non-cancelable streams: +Note that 'streamed amount' is synonymous with 'vested amount'. + +::: + +## Frontend Sandbox + +The examples in this guide are written in Solidity, but you may want to interact with the Sablier Lockup contract from +your frontend application. A good starting point for this is the +[Sablier Sandbox](https://github.com/sablier-labs/sandbox). + +For a comprehensive list of all the functions available in the Sablier Lockup contract, visit the +[References](/reference/overview) section of this website. + +## Actions + +### Cancel on first withdraw + +If you want to cancel streams as soon as the user withdraws their tokens, you can track the withdrawn amount and check +if its value is greater than 0. If it is, you can cancel the stream. + +```solidity +if (lockup.getWithdrawnAmount(streamId) > 0) { + lockup.cancel(streamId); +} +``` + +## Calculating Amounts + +### Amount in stream + +This is the amount of tokens held by the stream. It is the sum of locked tokens and vested tokens that have not been +withdrawn. This value is particularly useful for applications like staking. The following formula can be used for both +cancelable and non-cancelable streams: ```solidity uint256 amountInStream = sablierLockup.getDepositedAmount(streamId) @@ -39,14 +69,14 @@ uint256 amountInStream = sablierLockup.getDepositedAmount(streamId) :::info -If you are building a Staking contract for Sablier stream, you can follow the [staking guide](./staking/setup). +If you want to build a Staking contract for Sablier streams, check out the [staking guide](./staking/setup). ::: -## Locked amount +### Locked amount -Locked amount is the amount of tokens that are locked in the stream and can be considered as illiquid. This can be -particularly useful during the calculation of circulating supply. +This is the amount of tokens that are locked in the stream and are effectively illiquid. This is particularly relevant +when calculating the circulating supply of a token. ```solidity uint256 lockedAmount = lockup.getDepositedAmount(streamId) @@ -60,15 +90,11 @@ For non-cancelable stream, a more efficient way to calculate locked amount is: uint256 lockedAmount = lockup.getDepositedAmount(streamId) - lockup.streamedAmountOf(streamId); ``` -:::info - -While calculating the circulating supply, you can subtract locked amount from your calculations. +While calculating the circulating supply, you may want to subtract the locked amount from your calculations. -::: - -## Unlocked amount +### Unlocked amount -As opposed to locked amount, unlocked amount is the amount of tokens that are no longer locked and can be considered as +As opposed to the locked amount, the unlocked amount refers to tokens that are no longer locked and are effectively liquid. ```solidity @@ -91,23 +117,12 @@ you can use the following formula: uint256 vestedAmount = lockup.streamedAmountOf(streamId) - lockup.getWithdrawnAmount(streamId); ``` -This may be useful for use cases in which you want to reward diamond hands i.e. users who have not withdrawn their share -of airdrops. - -## Cancel on first withdraw - -If you want to cancel streams as soon as the user withdraws their tokens, you can track the withdrawn amount and check -if its value is greater than 0. If it is, you can cancel the stream. - -```solidity -if (lockup.getWithdrawnAmount(streamId) > 0) { - lockup.cancel(streamId); -} -``` +This may be useful for use cases in which you want to reward 'diamond hands', i.e., users who have not withdrawn their +share of airdrops. -## Unlock events +## Unlock Events -This section is useful if you are building a token unlock dashboard where you want to display the future unlock events. +This section is useful if you are building a data dashboard where you want index token unlock events. To calculate the time at which a stream will be fully unlocked, you can use the following formula: @@ -117,12 +132,12 @@ uint256 unlockTime = lockup.getEndTime(streamId); ### Linear streams -For lockup linear stream, you can make a request to `lockup.getTimestamps(streamId)` and then calculate cliff time and -end time as `timestamps.cliff` and `timestamps.end` respectively. +For Lockup Linear streams, make a request to `lockup.getTimestamps(streamId)` and then calculate cliff time and end time +as `timestamps.cliff` and `timestamps.end` respectively. ### Dynamic streams -For lockup dynamic streams, you may be particularly interested in the unlock amount and time of the current segment. +For Lockup Dynamic streams, you may be particularly interested in the unlock amount and time of the current segment. ```solidity LockupDynamic.Segment[] memory segments = lockup.getSegments(streamId); @@ -139,7 +154,7 @@ for (uint i; i < segments.length; ++i) { ### Tranched streams -For lockup tranched streams, you may be particularly interested in the unlock amount and time of the current tranche. +For Lockup Tranched streams, you may be particularly interested in the unlock amount and time of the current tranche. ```solidity LockupTranched.Tranche[] memory tranches = lockup.getTranches(streamId); From 1b7b75b7c59826a923d88fa634518a86294562dd Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Thu, 5 Dec 2024 16:02:41 +0000 Subject: [PATCH 3/3] refactor: polish some more --- .../lockup/examples/08-pull-vesting-data.md | 44 +++++++++++-------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/docs/guides/lockup/examples/08-pull-vesting-data.md b/docs/guides/lockup/examples/08-pull-vesting-data.md index 4debcbb9..18a3dc5c 100644 --- a/docs/guides/lockup/examples/08-pull-vesting-data.md +++ b/docs/guides/lockup/examples/08-pull-vesting-data.md @@ -5,18 +5,18 @@ title: "Pull Vesting Data" --- This guide explains how you can pull vesting data from Sablier Lockup streams. This data can be useful for a variety of -use cases, including but not limited to staking, explorers, and data dashboards: +use cases, including but not limited to staking contracts, blockchain explorers, and data dashboards: -1. **Staking**: Staking of Sablier streams require access to amount of tokens that are still held by the stream. You do - not want to distribute rewards for tokens that have been withdrawn by the user. -2. **Explorers (Etherscan, Coingecko)**: One major feature of blockchain explorers is to show accurate circulating - supplies. When tokens are vesting through Sablier, you may want to exclude the amount of unvested tokens from the +1. **Staking**: Staking of Sablier streams require access to the amount of tokens that are held by the stream. You do + not want to distribute rewards for tokens that have been withdrawn by users. +2. **Explorers (e.g., Etherscan, CoinGecko)**: One major feature of blockchain explorers is to show accurate circulating + supplies. When tokens are vested through Sablier, you may want to exclude the amount of unvested tokens from the circulating supply. This is helpful to accurately calculate the market cap, which depends upon the amount of liquid tokens. -3. **Data Dashboards (Tokenomist, Nansen, Dune)**: Investors and traders use data dashboards to make informed trading - decisions. When Sablier is used, you may want to show the amount of liquid (or vested) tokens and the amount of - illiquid (or unvested) tokens. This is helpful to understand the token distribution and the team's commitment to the - long-term success of the project. +3. **Data Dashboards (e.g., Tokenomist, Nansen, Dune)**: Investors and traders use data dashboards to make informed + trading decisions. When Sablier is used, you may want to show the amount of liquid (or vested) tokens and the amount + of illiquid (or unvested) tokens. This is helpful to understand the token distribution and the team's commitment to + the long-term success of the project. :::note @@ -30,15 +30,17 @@ The examples in this guide are written in Solidity, but you may want to interact your frontend application. A good starting point for this is the [Sablier Sandbox](https://github.com/sablier-labs/sandbox). -For a comprehensive list of all the functions available in the Sablier Lockup contract, visit the -[References](/reference/overview) section of this website. +For a comprehensive list of all the functions available in Sablier Lockup, visit the [References](/reference/overview) +section of this website. ## Actions ### Cancel on first withdraw -If you want to cancel streams as soon as the user withdraws their tokens, you can track the withdrawn amount and check -if its value is greater than 0. If it is, you can cancel the stream. +To automatically cancel streams as soon as the user withdraws their tokens, you can use one of two methods: onchain or +offchain. + +The onchain method is to track the withdrawn amount and check if its value is greater than 0: ```solidity if (lockup.getWithdrawnAmount(streamId) > 0) { @@ -46,6 +48,9 @@ if (lockup.getWithdrawnAmount(streamId) > 0) { } ``` +Offchain, you can monitor the [`WithdrawFromLockupStream`](reference/lockup/core/interfaces/interface.ISablierV2Lockup) +events. As soon as a withdrawal event is detected, you can send a transaction to cancel the stream. + ## Calculating Amounts ### Amount in stream @@ -120,16 +125,19 @@ uint256 vestedAmount = lockup.streamedAmountOf(streamId) - lockup.getWithdrawnAm This may be useful for use cases in which you want to reward 'diamond hands', i.e., users who have not withdrawn their share of airdrops. -## Unlock Events +## Unlock Dates -This section is useful if you are building a data dashboard where you want index token unlock events. +This section is useful if you are building a data dashboard and want to index the dates when tokens will be unlocked in +Sablier. -To calculate the time at which a stream will be fully unlocked, you can use the following formula: +To obtain the time at which a stream will be fully unlocked, you can use the following function: ```solidity uint256 unlockTime = lockup.getEndTime(streamId); ``` +Obtaining the earlier unlock times depends on the type of stream. Let's go through each stream type: + ### Linear streams For Lockup Linear streams, make a request to `lockup.getTimestamps(streamId)` and then calculate cliff time and end time @@ -169,5 +177,5 @@ for (uint i; i < tranches.length; ++i) { } ``` -I hope this guide was helpful to you. If you have a use case that is not covered here, please reach out to us on -[Discord](https://discord.sablier.com) and we will be happy to help you with your requirements. +We hope you have found this guide helpful. If you have a use case that is not covered here, please reach out to us on +[Discord](https://discord.sablier.com), and we will assist you.