diff --git a/.gitmodules b/.gitmodules index 2967a522..5a9945ec 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,3 +6,7 @@ branch = "release" path = "repos/lockup/v2-periphery" url = "https://github.com/sablier-labs/v2-periphery" +[submodule "repos/flow"] + branch = "main" + path = "repos/flow" + url = "https://github.com/sablier-labs/flow" diff --git a/docs/apps/features/02-vesting.mdx b/docs/apps/features/02-vesting.mdx index 449278e4..0cc59f96 100644 --- a/docs/apps/features/02-vesting.mdx +++ b/docs/apps/features/02-vesting.mdx @@ -6,7 +6,7 @@ title: "Vesting" # Vesting -import NFTSVG from "@site/static/img/nft.svg"; +import LockupNFTSVG from "@site/static/img/lockup-nft.svg"; The Sablier Interface will showcase [Lockup](/concepts/lockup/overview) streams under the Vesting tab. These are token streams with a fixed duration, predefined amount and strict distribution curve. @@ -66,9 +66,9 @@ Each stream in wrapped in an ERC-721 non-fungible token (NFT), making the stream Thus streams can be transferred, traded, and used as collateral in NFT lending protocols. -| | -| ----------------------------------- | -| | +| | +| ----------------------------------------- | +| | ### Multi-chain experience diff --git a/docs/concepts/06-nft.mdx b/docs/concepts/06-nft.mdx index 0719224b..c7d311d6 100644 --- a/docs/concepts/06-nft.mdx +++ b/docs/concepts/06-nft.mdx @@ -6,13 +6,35 @@ title: "NFTs" import Link from "@docusaurus/Link"; import { links } from "@site/src/constants"; -import NFTGalleryURL from "@site/static/img/nft-gallery.png"; -import NFTSVG from "@site/static/img/nft.svg"; +import FlowNFTSVG from "@site/static/img/flow-nft.svg"; +import LockupNFTGalleryURL from "@site/static/img/lockup-gallery.png"; +import LockupNFTSVG from "@site/static/img/lockup-nft.svg"; Both Lockup and Flow Protocols wrap every stream in an ERC-721 non-fungible token (NFT), making the stream recipient the owner of the NFT. The recipient can transfer the NFT to another address, and this also transfers the right to withdraw funds from the stream, including any funds already streamed. +## Lockup NFT + +Sablier Lockup streams are represented as unique onchain generated hourglass SVGs, which change their color and content +based on user data. Here's an example for a stream that is 42.35% way through: + + + +### Gallery of Multiple Sablier NFT SVGs + + + +If you prefer the granularity of a blockchain explorer, you can also view the stream NFTs on +[Etherscan](https://etherscan.io/token/0xB10daee1FCF62243aE27776D7a92D39dC8740f95). See the +[Deployments](/guides/lockup/deployments) page for the full list of addresses. + +## Flow NFT + +Unlike Lockup streams, the first release of Flow streams are represented by Sablier Logo. + + + ## Integrations The transferability of the NFT makes Sablier streams tradable and usable as collateral in DeFi. Imagine an NFT lending @@ -22,7 +44,7 @@ their future income). Or a decentralized exchange that allows users to trade str :::note Not all Sablier streams are transferable. The stream creator can choose to make the stream non-transferable. You can -find more details on it in the [Lockup guide](/guides/lockup/guides/stream-management/transfer). +find more details on it in the [Transferability](/concepts/transferability) section. ::: @@ -35,6 +57,13 @@ will try to respond as soon as possible. ## Marketplaces +:::caution + +Be careful when buying NFTs that represent cancelable stream. When these streams are canceled, the unstreamed amount is +returned to the sender. + +::: + Thanks to adhering to the ERC-721 standard, Sablier streams can be traded and viewed on any NFT marketplace. Here are some of the marketplaces that support Sablier streams: @@ -44,42 +73,14 @@ some of the marketplaces that support Sablier streams: - [SuperRare](https://superrare.com) - [LooksRare](https://looksrare.org) -## Lockup NFT - -:::caution - -Be careful when buying NFTs that represent cancelable stream. When these streams are canceled, the unstreamed amount is -returned to the sender. - -::: - -### Caching +## Caching The SVG artwork is generated using certain real-time values, such as the current time on the blockchain. However, NFT marketplaces cache the NFT metadata, and this may cause the SVGs might not always be up to date. -The Lockup Protocol triggers [ERC-4906](https://eips.ethereum.org/EIPS/eip-4906) events whenever there's an update in a +Sablier Protocols trigger [ERC-4906](https://eips.ethereum.org/EIPS/eip-4906) events whenever there's an update in a stream (for instance, when a withdrawal is made). However, it's worth noting that some streams might remain unchanged for an extended period. To ensure you're viewing the most recent version of the NFT SVG, it's recommended to check the stream directly via the [Sablier Interface](https://app.sablier.com). - -## Hourglass SVG - -Sablier Lockup streams are represented as unique onchain generated hourglass SVGs, which change their color and content -based on user data. Here's an example for a stream that is 42.35% way through: - - - -### Gallery of Multiple Sablier NFT SVGs - - - -If you prefer the granularity of a blockchain explorer, you can also view the stream NFTs on -[Etherscan](https://etherscan.io/token/0xB10daee1FCF62243aE27776D7a92D39dC8740f95). See the -[Deployments](/guides/lockup/deployments) page for the full list of addresses. - -## Flow NFT - -Coming soon. diff --git a/docs/concepts/08-governance.md b/docs/concepts/08-governance.md index 59ce6008..7f9d1e7f 100644 --- a/docs/concepts/08-governance.md +++ b/docs/concepts/08-governance.md @@ -31,16 +31,21 @@ wallets. Admin has the following permissions on each chain where Lockup is deployed: -| Permission | Function | Contract(s) | -| ------------------ | ------------------ | ---------------------------------------------------------------------------- | -| Allow to Hook | `allowToHook` | `SablierV2LockupLinear`, `SablierV2LockupDynamic`, `SablierV2LockupTranched` | -| Set NFT Descriptor | `setNFTDescriptor` | `SablierV2LockupLinear`, `SablierV2LockupDynamic`, `SablierV2LockupTranched` | +| Permission | Function | +| ------------------ | ------------------------------------------------------------------------------------------------ | +| Allow to Hook | [allowToHook](../reference/lockup/core/abstracts/abstract.SablierV2Lockup#allowtohook) | +| Set NFT Descriptor | [setNFTDescriptor](../reference/lockup/core/abstracts/abstract.SablierV2Lockup#setnftdescriptor) | ## Flow Admin has the following permissions on each chain where Flow is deployed: -Coming soon. +| Permission | Function | +| ------------------------ | --------------------------------------------------------------------------------------------------------------- | +| Collect Protocol Revenue | [collectProtocolRevenue](../reference/flow/contracts/abstracts/abstract.SablierFlowBase#collectprotocolrevenue) | +| Recover ERC20 token | [recover](../reference/flow/contracts/abstracts/abstract.SablierFlowBase#recover) | +| Set NFT Descriptor | [setNFTDescriptor](../reference/flow/contracts/abstracts/abstract.SablierFlowBase#setnftdescriptor) | +| Set Protocol Fee | [setProtocolFee](../reference/flow/contracts/abstracts/abstract.SablierFlowBase#setprotocolfee) | ## Trustlessness diff --git a/docs/concepts/09-fees.mdx b/docs/concepts/09-fees.mdx index 574c6f58..3a3e59b1 100644 --- a/docs/concepts/09-fees.mdx +++ b/docs/concepts/09-fees.mdx @@ -7,24 +7,40 @@ title: "Fees" import Link from "@docusaurus/Link"; import { links } from "@site/src/constants"; -## Lockup +There are two types of fees in the Sablier ecosystem: **Protocol Fee** and **Broker Fee**. -### Protocol fees +## Protocol fee -Lockup protocol is entirely free to use. There is no protocol fee. However, external integrators who manage their own UI -may charge broker free in exchange for providing their services. Broker fees can only be charged when a stream is -created, and is capped at 10%. +This is a fee that can be charged at the protocol level, capped at 10%. Only the protocol admin has the authority to +change it. -### Broker fees +### Lockup -In the Sablier ecosystem, a "broker" is any third-party entity that interacts with the Sablier Protocol on behalf of -other users. These brokers have the ability to charge service fees for facilitating such interactions. +Currently, Lockup doesn't implement protocol fee that means it remains entirely free to use. + +### Flow + +While Flow has the ability to implement a protocol fee, no fee is set at the moment. If a protocol fee is introduced in +the future, users will be notified in advance. When active, the fee will be deducted as a percentage from the withdrawn +amount. + +## Broker fee + +A "broker" is any third-party entity that interacts with the Sablier Protocol on behalf of other users. These brokers +have the ability to charge service fees for facilitating such interactions. Broker fees are particularly useful for front-end applications that integrate the Sablier Protocol. They enable -front-end operators to levy a fee on each Sablier stream created through their platform. +front-end operators to levy a fee on each interaction facilitated through their platform. + +### Lockup -The broker fee is a percentage of the streamed amount, and it cannot be higher than 10%. In the event of cancellation, -broker fee is non-refundable. +The broker fee can be charged as a percentage of the streamed amount, and it cannot be higher than 10%. In the event of +cancellation, broker fee is non-refundable. + +### Flow + +The broker fee can be charged as a percentage of the deposit amount, and it cannot be higher than 10%. In case of +refund, broker fee is non-refundable. :::info @@ -39,10 +55,6 @@ soon as possible. ::: -## Flow - -Coming soon. - ## Gas Fees ### Q: What are gas fees? @@ -60,6 +72,7 @@ A: No. 100% of the gas fee goes to the blockchain validators, which are not affi :::tip -To find how much each function costs, check out these [gas benchmark reports](/guides/lockup/gas-benchmarks). +To find how much gas each function costs, check out these [gas benchmark reports](/guides/lockup/gas-benchmarks) for +Lockup. ::: diff --git a/docs/concepts/10-security.md b/docs/concepts/10-security.md index 1e5ac049..bfd6904c 100644 --- a/docs/concepts/10-security.md +++ b/docs/concepts/10-security.md @@ -7,15 +7,17 @@ title: "Security" Ensuring the security of the Sablier Protocols is our utmost priority. We have dedicated significant efforts towards the design and testing of the protocol to guarantee its safety and reliability. +The Sablier contracts have undergone rigorous audits by leading security experts from [Cantina](https://cantina.xyz/), +[CodeHawks](https://codehawks.cyfrin.io/), and many independent auditors. For a comprehensive list of all audits +conducted, check out [the audit repo](https://github.com/sablier-labs/audits/) + ## Lockup Audits -The codebase has undergone rigorous audits by leading security experts from [Cantina](https://cantina.xyz/), -[CodeHawks](https://codehawks.cyfrin.io/), and many independent auditors. For a comprehensive list of all audits -conducted, check out [this link](https://github.com/sablier-labs/audits). +All the audits of Lockup contracts can be found [here](https://github.com/sablier-labs/audits/tree/main/lockup). ## Flow Audits -Coming soon. +All the audits of Lockup contracts can be found [here](https://github.com/sablier-labs/audits/tree/main/flow). ## Bug Bounty diff --git a/docs/concepts/flow/01-overview.md b/docs/concepts/flow/01-overview.md index 8a8af7f0..917464c2 100644 --- a/docs/concepts/flow/01-overview.md +++ b/docs/concepts/flow/01-overview.md @@ -27,3 +27,53 @@ premiums, loans interest, token ESOPs etc. If you are looking for vesting and ai debt. Either party can void a stream at any time. 6. **Withdraw:** it is publicly callable as long as `to` is set to the recipient. However, a stream’s recipient is allowed to withdraw funds to any address. + +## Key Definitions + +The definitions below will help you understand some terms used in Sablier Flow: + +### Stream balance + +Stream balance is the token balance of a stream. It increases when funds are deposited into a stream, and decreases when +the sender refunds from it or when a withdrawal happens. + +### Total debt + +Total debt is the amount of tokens owed to the recipient. This value is further divided into two sub-categories: + +- **Covered debt:** The part of the total debt that covered by the stream balance. This is the same as the + **withdrawable amount**, which is an alias. +- **Uncovered debt:** The part of the total debt that is not covered by the stream balance. This is what the sender owes + to the stream. + +```math +\text{total debt} = \text{covered debt} + \text{uncovered debt} +``` + +### Snapshot debt and Snapshot time + +A snapshot is an event during which snapshot debt and snapshot time of a Flow stream are updated. **Snapshot debt** is +the debt accumulated since the previous snapshot. The UNIX timestamp at which snapshot debt is updated is called +**Snapshot time**. + +At snapshot, the following calculations are taking place: + +```math +\text{snapshot debt} = \text{previous snapshot debt} + \underbrace{ +rps \cdot (\text{block.timestamp} - \text{snapshot time})}_\text{ongoing debt} +\text{snapshot time} = \text{block.timestamp} +``` + +Therefore, at any point in time, total debt can also be defined as: + +```math +\text{total debt} = \text{snapshot debt} + \text{ongoing debt} +``` + +## Lifecycle + +1. A Flow stream is created with an `rps`, a `sender` and a `recipient` address. +2. During the lifecycle of the stream, all the functions enclosed inside the dotted rectangle (diagram below) can be + called any number of times. There are some limitations though, such as `restart` can only be called if the stream is + `paused`. +3. Any party can call `void` to terminate it. Only withdraw and refund are allowed on a voided stream. diff --git a/docs/concepts/flow/02-statuses.md b/docs/concepts/flow/02-statuses.md new file mode 100644 index 00000000..89d4aa4a --- /dev/null +++ b/docs/concepts/flow/02-statuses.md @@ -0,0 +1,80 @@ +--- +id: "statuses" +sidebar_position: 2 +title: "Statuses" +--- + +# Stream Statuses + +A Flow stream can have one of five distinct statuses: + +| Status | Description | +| ------------------- | ----------------------------------------------------------------------------------- | +| STREAMING_SOLVENT | Active stream with total debt not exceeding stream balance. | +| STREAMING_INSOLVENT | Active stream with total debt exceeding stream balance. | +| PAUSED_SOLVENT | Paused stream with total debt not exceeding stream balance. | +| PAUSED_INSOLVENT | Paused stream with total debt exceeding stream balance. | +| VOIDED | Paused stream that can no longer be restarted and has forfeited its uncovered debt. | + +## Stream characteristics + +A stream can have the following characteristics: + +| Characteristic | Statuses | Description | +| :------------- | :---------------------------------------- | :------------------------------------------------------ | +| Streaming | STREAMING_SOLVENT, STREAMING_INSOLVENT | Non-zero rps. | +| Paused | PAUSED_SOLVENT, PAUSED_INSOLVENT, VOIDED | Zero rps. | +| Solvent | STREAMING_SOLVENT, PAUSED_SOLVENT, VOIDED | Total debt not exceeding the stream balance. | +| Insolvent | STREAMING_INSOLVENT, PAUSED_INSOLVENT | Total debt exceeding the stream balance. | + +## Diagram + +The following diagram illustrates the statuses and the allowed transitions between them: + +```mermaid +flowchart LR + N[NULL] + V[VOIDED] + + subgraph Paused + direction RL + PS[PAUSED_SOLVENT] + PI[PAUSED_INSOLVENT] + PI -- "deposit" --> PS + end + + subgraph Streaming + direction LR + SS[STREAMING_SOLVENT] + SI[STREAMING_INSOLVENT] + SI -- "deposit" --> SS + SS -- "time" --> SI + end + + Streaming -- pause --> Paused + Streaming -- void --> V + Paused -- restart --> Streaming + Paused -- void --> V + + N -- create (rps > 0) --> Streaming + N -- create (rps = 0) --> Paused +``` + +## Q&A + +### Q: What is a null stream? + +A: An id that does not reference a created stream. Trying to interact with a null stream will result in a revert. + +### Q: What to do with a stream status? + +A: Knowing the status of a stream can inform your decision making. For example, if a stream is `STREAMING_INSOLVENT`, +that means the stream is active but has insufficient balance. As a sender, you should deposit into the stream so that +your recipient can withdraw the streamed amount without any hiccups. And if you don't want to continue the stream, you +can pause it. + +### Q: Who can make a stream `VOIDED`? + +A: Both sender and recipient can void the stream. This is especially useful when either party wants to stop the stream +immediately. Once a stream is voided, it cannot be restarted. If there is uncovered debt, it will be reset to 0. So to +ensure that your recipient does not lose on any streamed amount, you can deposit into the stream before voiding it. diff --git a/docs/concepts/lockup/01-overview.md b/docs/concepts/lockup/01-overview.md index 41498df8..4e9968d8 100644 --- a/docs/concepts/lockup/01-overview.md +++ b/docs/concepts/lockup/01-overview.md @@ -5,7 +5,8 @@ title: "Overview" --- Lockup is a token streaming protocol that refers to the requirement that the creator of a stream must lock up a certain -amount of assets in a smart contract. +amount of assets in a smart contract. A lockup stream, therefore, is characterized by the start time, end time, amount +of tokens to be streamed and a [stream shape](./02-stream-shapes.mdx). Let's discuss an example. Imagine Alice wants to stream 3,000 DAI to Bob during the whole month of January. diff --git a/docs/concepts/lockup/07-hooks.md b/docs/concepts/lockup/07-hooks.md index ff5aa58b..31de4770 100644 --- a/docs/concepts/lockup/07-hooks.md +++ b/docs/concepts/lockup/07-hooks.md @@ -48,4 +48,6 @@ flowchart LR ## Next steps -Looking to get on the allowlist? Reach out to us on [Discord](https://discord.sablier.com). +If you are interested into using Sablier hooks into your protocol, please check the +[Hook guide](/guides/lockup/examples/hooks). if you looking to get on the allowlist, reach out to us on +[Discord](https://discord.sablier.com). diff --git a/docs/guides/04-snapshot-voting.md b/docs/guides/04-snapshot-voting.md index 044f1c5a..f1be3998 100644 --- a/docs/guides/04-snapshot-voting.md +++ b/docs/guides/04-snapshot-voting.md @@ -165,7 +165,7 @@ The opposite of `streamed-recipient`, counting amounts that have not been stream available in the future). Subtracts the `streamed` amount from the initial `deposit`. For canceled streams, the unstreamed amount will be `0`. -## Sablier Lockup V1 +## Lockup Legacy V1 - [Snapshot playground](https://snapshot.org/#/playground/sablier-v1-deposit) - test the strategies - [Snapshot code repository](https://github.com/snapshot-labs/snapshot-strategies/tree/master/src/strategies/sablier-v1-deposit) - diff --git a/docs/guides/05-custom-deployments.mdx b/docs/guides/05-custom-deployments.mdx index 63455c58..01575435 100644 --- a/docs/guides/05-custom-deployments.mdx +++ b/docs/guides/05-custom-deployments.mdx @@ -28,7 +28,7 @@ requirements below. The following guidelines apply to you only if you have you been granted a [BUSL license](https://app.ens.domains/lockup-license-grants.sablier.eth?tab=records) to deploy the Lockup Protocol. -### Pre Requisities +### Prerequisites - Check if the deployment is not already made on [your chain](/guides/lockup/deployments) - Follow the [contributing guide](https://github.com/sablier-labs/v2-core/blob/main/CONTRIBUTING.md) @@ -38,7 +38,7 @@ The following guidelines apply to you only if you have you been granted a ### Steps for deploying Core contracts -#### Step 1: Clone the [v2-core repo](https://github.com/sablier-labs/v2-core) and checkout to the latest release tag +#### Step 1: Clone the [Lockup core repo](https://github.com/sablier-labs/v2-core) and checkout to the latest release tag At the time of writing, the latest release tag is `v1.2.0`: @@ -112,7 +112,7 @@ If you are using a mnemonic or a hardware device for your deployer address, refe ### Steps for deploying Periphery contracts -#### Step 1: Clone the [v2-periphery](https://github.com/sablier-labs/v2-periphery) and checkout to the latest release tag +#### Step 1: Clone the [Lockup periphery repo](https://github.com/sablier-labs/v2-periphery) and checkout to the latest release tag At the time of writing, the latest release tag is `v1.2.0`: @@ -190,4 +190,87 @@ Once the contracts are deployed, the final step is to list the deployment addres ## Flow Deployment Guide -Coming soon. +The following guidelines apply to you only if you have you been granted a +[BUSL license](https://app.ens.domains/flow-license-grants.sablier.eth?tab=records) to deploy the Flow Protocol. + +### Prerequisites + +- Check if the deployment is not already made on [your chain](/guides/flow/deployments) +- Follow the [contributing guide](https://github.com/sablier-labs/flow/blob/main/CONTRIBUTING.md) +- RPC endpoint, e.g., a paid Infura account +- Enough ETH in your deployer account +- Etherscan API key (for source code verification) + +### Steps for deploying Flow contracts + +#### Step 1: Clone the [Flow repo](https://github.com/sablier-labs/flow) and checkout to the latest release tag + +At the time of writing, the latest release tag is `v1.0.0`: + +```bash +git checkout v1.0.0 +``` + +#### Step 2: Create an `.env` file + +```bash +touch .env +``` + +Add the following variables to `.env` file: + +``` +EOA="DEPLOYER ADDRESS" +ETHERSCAN_API_KEY="EXPLORER API KEY" +PRIVATE_KEY="PRIVATE KEY OF DEPLOYER ADDRESS" +RPC_URL="RPC ENDPOINT URL" +VERIFIER_URL="EXPLORER VERIFICATION URL" +``` + +Load the environment variables into your shell: + +```bash +source .env +``` + +#### Step 3: Run the following deployment command + +:::warning[Important] + +You must set the protocol admin to the Sablier controlled address 0xD427d37B5F6d33f7D42C4125979361E011FFbfD9. Failure to +do so will result in your deployment not being acknowledged as official. + +::: + +For **deterministic** deployment: + +```bash +FOUNDRY_PROFILE=optimized \ +forge script script/DeployDeterministicFlow.s.sol \ +--broadcast \ +--etherscan-api-key $ETHERSCAN_API_KEY \ +--rpc-url $RPC_URL \ +--private-key $PRIVATE_KEY \ +--sig "run(address)" 0xD427d37B5F6d33f7D42C4125979361E011FFbfD9 \ +--verifier-url $VERIFIER_URL \ +--verify \ +-vvv +``` + +For **non-deterministic** deployment: + +```bash +FOUNDRY_PROFILE=optimized \ +forge script script/DeployFlow.s.sol \ +--broadcast \ +--etherscan-api-key $ETHERSCAN_API_KEY \ +--private-key $PRIVATE_KEY \ +--rpc-url $RPC_URL \ +--sig "run(address)" 0xD427d37B5F6d33f7D42C4125979361E011FFbfD9 \ +--verifier-url $VERIFIER_URL \ +--verify \ +-vvv +``` + +If you are using a mnemonic or a hardware device for your deployer address, refer to `forge-script` page from +[foundry book](https://book.getfoundry.sh/reference/forge/forge-script#forge-script) for different wallet options. diff --git a/docs/guides/flow/01-overview.md b/docs/guides/flow/01-overview.md index 97e2a607..036fdb36 100644 --- a/docs/guides/flow/01-overview.md +++ b/docs/guides/flow/01-overview.md @@ -4,4 +4,26 @@ sidebar_position: 1 title: "Overview" --- -Coming soon. +# Flow Protocol + +Welcome to the Flow Protocol documentation. + +This section contains detailed guides and technical references for the Flow Protocol. These documents offer insight into +the operational nuances of the contracts, providing a valuable resource for building onchain integrations. + +# Guides + +If you are new to Sablier, we recommend you start with the [Concepts](/concepts/what-is-sablier) section first. + +If you want to setup your local environment, head over to [the guide](/guides/flow/examples/local-environment). + +# Reference + +For a deeper dive into the protocol specifications, read through the [technical reference](/reference/flow/diagrams). + +# Resources + +- [Flow Contracts](https://github.com/sablier-labs/flow/tree/release) +- [Flow Integration Templates](https://github.com/sablier-labs/sablier-integration-template) +- [Flow Integration Examples](https://github.com/sablier-labs/examples) +- [Foundry Book](https://book.getfoundry.sh/) diff --git a/docs/guides/flow/03-gas-benchmarks.md b/docs/guides/flow/03-gas-benchmarks.md new file mode 100644 index 00000000..19b33f17 --- /dev/null +++ b/docs/guides/flow/03-gas-benchmarks.md @@ -0,0 +1,33 @@ +--- +label: "Gas benchmarks" +sidebar_position: 3 +title: "Gas Benchmarks" +--- + +The gas usage of the FLow Protocol is not deterministic and varies by user. Calls to third-party contracts, such as +ERC-20 tokens, may use an arbitrary amount of gas. The values in the table below are rough estimations - you shouldn't +take them for granted. + +:::note + +Please refer to the [GitHub repository](https://github.com/sablier-labs/flow/tree/main/benchmark) to view the code that +generates these benchmarks. + +::: + +The following gas benchmarks are generated using a 6-decimal token. + +| Function | Gas Usage | +| ----------------------------- | --------- | +| `adjustRatePerSecond` | 44171 | +| `create` | 113681 | +| `deposit` | 32975 | +| `depositViaBroker` | 22732 | +| `pause` | 7522 | +| `refund` | 11939 | +| `restart` | 7036 | +| `void (solvent stream)` | 10060 | +| `void (insolvent stream)` | 37460 | +| `withdraw (insolvent stream)` | 57688 | +| `withdraw (solvent stream)` | 38156 | +| `withdrawMax` | 51988 | diff --git a/docs/guides/flow/04-deployments.md b/docs/guides/flow/04-deployments.md new file mode 100644 index 00000000..f5f41254 --- /dev/null +++ b/docs/guides/flow/04-deployments.md @@ -0,0 +1,29 @@ +--- +id: "deployments" +sidebar_position: 4 +title: "Deployment Addresses" +--- + +This document contains the deployment addresses for the v1.0.0 release of +[@sablier/flow](https://npmjs.com/package/@sablier/flow/v/1.0.0). + +A few noteworthy details about the deployments: + +- The addresses are final +- All contracts are non-upgradeable +- The source code is verified on Etherscan across all chains + +:::info + +Stay up to date with any new releases by [subscribing](https://x.com/Sablier/status/1821220784661995627) to the official +Sablier repositories on Github. + +::: + +## Mainnets + +Coming soon. + +## Testnets + +Coming soon. diff --git a/docs/guides/flow/examples/01-local-environment.md b/docs/guides/flow/examples/01-local-environment.md new file mode 100644 index 00000000..6d09c81f --- /dev/null +++ b/docs/guides/flow/examples/01-local-environment.md @@ -0,0 +1,140 @@ +--- +id: "local-environment" +sidebar_position: 1 +title: "Configure Your Local Environment" +--- + +In this guide, we will go through the steps to set up a local development environment for building onchain integrations +with Flow. We will use Foundry to install Flow as a dependency, and run a few simple tests. + +At the end, you’ll have a development environment set up that you can use to build the rest of the examples under +"Guides", or start your own integration project. + +## Pre-requisites + +You will need the following software on your machine: + +- [Git](https://git-scm.com/downloads) +- [Foundry](https://github.com/foundry-rs/foundry) +- [Node.js](https://nodejs.org/en/download) +- [Bun](https://bun.sh) + +In addition, familiarity with [Ethereum](https://ethereum.org/) and [Solidity](https://soliditylang.org/) is requisite. + +## Quick start + +We put together a template repository that you can use to get started quickly. This repository features a basic project +structure, pre-configured Flow imports, and a selection of sample contracts and tests. + +:::tip + +Make sure you are using the latest version of Foundry by running `foundryup`. + +::: + +To install the template, simply execute the following commands: + +```shell +$ mkdir sablier-integration-template +$ cd sablier-integration-template +$ forge init --template sablier-labs/sablier-integration-template +$ bun install +``` + +Then, hop to the `Run a Fork Test` section to complete your set up and start developing. + +## Start from scratch + +Foundry is a popular development toolkit for Ethereum projects, which we have used to build the Sablier Protocols. For +the purposes of this guide, Foundry will provide us with the tooling needed to compile and test our contracts. + +Let's use this command to spin up a new Foundry project: + +```shell +$ forge init my-project +$ cd my-project +``` + +:::note + +You might notice that the CLI is `forge` rather than `foundry`. This is because Foundry is a toolkit, and `forge` is +just one of the tools that comes with it. + +::: + +Once the initialization completes, take a look around at what got set up: + +```tree +├── foundry.toml +├── script +├── src +└── test +``` + +The folder structure should be intuitive: + +- `src` is where you'll write Solidity contracts +- `test` is where you'll write tests (also in Solidity) +- `script` is where you'll write scripts to perform actions like deploying contracts (you guessed it, in Solidity) +- `foundry.toml` is where you can configure your Foundry settings, which we will leave as is in this guide + +Let's install the FLow Node.js packages using Bun: + +```shell +$ bun add @sablier/flow +``` + +Bun will download the Flow contracts, along with their dependencies, and put them in the `node_modules` directory. + +Let's remap the package names to point to the installed contracts. This step is required so that the Solidity compiler +can find the Flow contracts when you import them: + +```shell +$ echo "@sablier/flow=node_modules/@sablier/flow/" >> remappings.txt +$ echo "@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/" >> remappings.txt +$ echo "@prb/math/=node_modules/@prb/math/" >> remappings.txt +``` + +That's it! You should now have a functional development environment to start building onchain Flow integrations. Let's +run a quick test to confirm everything is set up properly. + +## Sample contract + +Delete the `src/Counter.sol` and `test/Counter.t.sol` files generated by Forge, and create a new file: +`src/FlowStreamCreator.sol`. + +Paste the following code into `src/FlowStreamCreator.sol`. + +```solidity reference title="Flow Stream Creator" +https://github.com/sablier-labs/examples/blob/main/flow/FlowStreamCreator.sol +``` + +Let's use Forge to compile this contract: + +```shell +$ forge build +``` + +If the contract was compiled correctly, you should see this message: + +```text +[⠢] Compiling... +[⠰] Compiling { number } files with { compiler } +[⠒] Solc { compiler } finished in { time } +Compiler run successful +``` + +:::info + +The minimum Solidity version supported by the Flow contracts is v0.8.13. + +::: + +## Next steps + +Congratulations! Your environment is now configured, and you are prepared to start building. Explore the guides section +to discover various Flow features available for integration. + +As far as Foundry is concerned, there is much more to uncover. If you want to learn more about it, check out the +[Foundry Book](https://book.getfoundry.sh/), which contains numerous examples and tutorials. A deep understanding of +Foundry will enable you to create more sophisticated integrations with Flow. diff --git a/docs/guides/lockup/guides/_category_.json b/docs/guides/flow/examples/_category_.json similarity index 64% rename from docs/guides/lockup/guides/_category_.json rename to docs/guides/flow/examples/_category_.json index fc9a0ff8..4c14cded 100644 --- a/docs/guides/lockup/guides/_category_.json +++ b/docs/guides/flow/examples/_category_.json @@ -1,5 +1,5 @@ { "collapsed": false, - "label": "Guides", + "label": "Examples", "position": 2 } diff --git a/docs/guides/lockup/01-overview.md b/docs/guides/lockup/01-overview.md index 7bd71bdd..35b6cbc0 100644 --- a/docs/guides/lockup/01-overview.md +++ b/docs/guides/lockup/01-overview.md @@ -16,17 +16,17 @@ contracts, providing a valuable resource for building onchain integrations. If you are new to Sablier, we recommend you start with the [Concepts](/concepts/what-is-sablier) section first. -You can then setup your [local environment](./guides/01-local-environment.md) and create your -[first stream](./guides/create-stream/01-lockup-linear.mdx). +You can then setup your [local environment](/guides/lockup/examples/local-environment) and create your +[first stream](/guides/lockup/examples/create-stream/lockup-linear). # Reference -For a deeper dive into the protocol specifications, read through the [technical reference](/reference/overview). +For a deeper dive into the protocol specifications, read through the [technical reference](/reference/lockup/diagrams). # Resources - [Lockup Core](https://github.com/sablier-labs/v2-core/tree/release) - [Lockup Periphery](https://github.com/sablier-labs/v2-periphery/tree/release) -- [Lockup Integration Template](https://github.com/sablier-labs/sablier-v2-integration-template) -- [Lockup Example Integrations](https://github.com/sablier-labs/examples) +- [Lockup Integration Templates](https://github.com/sablier-labs/sablier-v2-integration-template) +- [Lockup Integration Examples](https://github.com/sablier-labs/examples) - [Foundry Book](https://book.getfoundry.sh/) diff --git a/docs/guides/lockup/04-deployments.md b/docs/guides/lockup/04-deployments.md index 0b8e4976..fdd84b1d 100644 --- a/docs/guides/lockup/04-deployments.md +++ b/docs/guides/lockup/04-deployments.md @@ -2,19 +2,18 @@ id: "deployments" sidebar_position: 4 title: "Deployment Addresses" -toc_max_heading_level: 3 --- -This document contains the deployment addresses for the V2.2 release of [@sablier/v2-core][v2-core] and -[@sablier/v2-periphery][v2-periphery]. +This document contains the deployment addresses for the v1.2 release of [@sablier/lockup-core][lockup-core] and +[@sablier/lockup-periphery][lockup-periphery]. -[v2-core]: https://npmjs.com/package/@sablier/v2-core/v/1.2.0 -[v2-periphery]: https://npmjs.com/package/@sablier/v2-periphery/v/1.2.0 +[lockup-core]: https://npmjs.com/package/@sablier/v2-core/v/1.2.0 +[lockup-periphery]: https://npmjs.com/package/@sablier/v2-periphery/v/1.2.0 A few noteworthy details about the deployments: - The addresses are final -- All LockupLinear, LockupDynamic, and LockupTranched contracts are non-upgradeable +- All contracts are non-upgradeable - The source code is verified on Etherscan across all chains ## Previous Versions @@ -24,13 +23,13 @@ Any updates or additional features will call for a new deployment of the protoco Came here looking for the previous Lockup deployments? Click below to see other versions as well as the in-app aliases assigned under our [naming convention](/api/lockup/the-graph/structure#identifying). -| Version | UI Aliases | -| ------------------------------------ | ---------------------------------------------------------------- | -| v2.2 (current) | LD3 (Lockup Dynamic), LL3 (Lockup Linear), LT3 (Lockup Tranched) | -| [v2.1](/guides/lockup/versions/v2.1) | LD2 (Lockup Dynamic), LL2 (Lockup Linear) | -| [v2.0](/guides/lockup/versions/v2.0) | LD (Lockup Dynamic), LL (Lockup Linear) | +| Version | UI Aliases | +| ------------------------------------------------ | ---------------------------------------------------------------- | +| v1.2 (current) | LD3 (Lockup Dynamic), LL3 (Lockup Linear), LT3 (Lockup Tranched) | +| [v1.1](/guides/lockup/previous-deployments/v1.1) | LD2 (Lockup Dynamic), LL2 (Lockup Linear) | +| [v1.0](/guides/lockup/previous-deployments/v1.0) | LD (Lockup Dynamic), LL (Lockup Linear) | -Or maybe you're looking for V1? [Click here](/guides/lockup/versions/v1). +Or maybe you're looking for Legacy protocol? [Click here](/guides/lockup/previous-deployments/legacy). :::info diff --git a/docs/guides/lockup/guides/01-local-environment.md b/docs/guides/lockup/examples/01-local-environment.md similarity index 90% rename from docs/guides/lockup/guides/01-local-environment.md rename to docs/guides/lockup/examples/01-local-environment.md index dcf11d5a..b50c2390 100644 --- a/docs/guides/lockup/guides/01-local-environment.md +++ b/docs/guides/lockup/examples/01-local-environment.md @@ -35,13 +35,14 @@ Make sure you are using the latest version of Foundry by running `foundryup`. To install the template, simply execute the following commands: ```shell -$ mkdir sablier-v2-integration-template -$ cd sablier-v2-integration-template -$ forge init --template sablier-labs/sablier-v2-integration-template +$ mkdir sablier-integration-template +$ cd sablier-integration-template +$ forge init --template sablier-labs/sablier-integration-template $ bun install ``` -Then, hop to the `Run a Fork Test` section to complete your set up and start developing. +Then, hop to the [Run a Fork Test](/guides/lockup/examples/local-environment#run-a-fork-test) section to complete your +set up and start developing. ## Start from scratch @@ -105,10 +106,10 @@ Delete the `src/Counter.sol` and `test/Counter.t.sol` files generated by Forge, `src/StreamCreator.sol` and `test/StreamCreator.t.sol`. Paste the following code into `src/StreamCreator.sol` (a detailed explanation of this contract can be found -[here](/guides/lockup/guides/create-stream/lockup-linear)): +[here](/guides/lockup/examples/create-stream/lockup-linear)): ```solidity reference title="Lockup Linear Stream Creator" -https://github.com/sablier-labs/examples/blob/main/v2/core/LockupLinearStreamCreator.sol +https://github.com/sablier-labs/examples/blob/main/lockup/core/LockupLinearStreamCreator.sol ``` Let's use Forge to compile this contract: @@ -144,7 +145,7 @@ As a prerequisite, you will need an RPC that supports forking. A good solution f Once you have obtained your RPC, you can proceed to run the following test: ```solidity reference title="Stream Creator Test" -https://github.com/sablier-labs/examples/blob/main/v2/core/LockupStreamCreator.t.sol +https://github.com/sablier-labs/examples/blob/main/lockup/core/LockupStreamCreator.t.sol ``` You can run the test using Forge: @@ -156,7 +157,7 @@ $ forge test If the test passed, you should see a message like this: ```text -Ran 2 tests for v2/core/LockupStreamCreator.t.sol:LockupStreamCreatorTest +Ran 2 tests for lockup/core/LockupStreamCreator.t.sol:LockupStreamCreatorTest [PASS] test_LockupDynamicStreamCreator() (gas: 273719) [PASS] test_LockupLinearStreamCreator() (gas: 186388) Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 6.34s (5.80s CPU time) diff --git a/docs/guides/lockup/guides/04-create-airstream.mdx b/docs/guides/lockup/examples/04-create-airstream.mdx similarity index 96% rename from docs/guides/lockup/guides/04-create-airstream.mdx rename to docs/guides/lockup/examples/04-create-airstream.mdx index 40d9a936..56df2d68 100644 --- a/docs/guides/lockup/guides/04-create-airstream.mdx +++ b/docs/guides/lockup/examples/04-create-airstream.mdx @@ -10,10 +10,9 @@ import ConstantsComment from "@site/docs/snippets/ConstantsComment.mdx"; # Create an Airstream In this guide, we will show you how to programmatically create an airstream via the -[Merkle Factory](http://localhost:3000/reference/lockup/periphery/contract.SablierV2MerkleLockupFactory). +[Merkle Factory](/reference/lockup/periphery/contract.SablierV2MerkleLockupFactory). -This guide assumes that you have already gone through the -[Protocol Concepts](http://localhost:3000/concepts/protocol/airstreams) section. +This guide assumes that you have already gone through the [Protocol Concepts](/concepts/lockup/airstreams) section. :::note diff --git a/docs/guides/lockup/guides/06-hooks.md b/docs/guides/lockup/examples/06-hooks.md similarity index 100% rename from docs/guides/lockup/guides/06-hooks.md rename to docs/guides/lockup/examples/06-hooks.md diff --git a/docs/guides/lockup/guides/07-etherscan.md b/docs/guides/lockup/examples/07-etherscan.md similarity index 99% rename from docs/guides/lockup/guides/07-etherscan.md rename to docs/guides/lockup/examples/07-etherscan.md index 91bdb250..453bb1a1 100644 --- a/docs/guides/lockup/guides/07-etherscan.md +++ b/docs/guides/lockup/examples/07-etherscan.md @@ -177,7 +177,7 @@ to have a cliff, fill in the timestamp for the the cliff there. An optional parameter that can be set in order to charge a fee as a percentage of `totalAmount`. -You can set the `broker` field to address zero and `zero` fees. Read more about fees [here](/concepts/fees#broker-fees). +You can set the `broker` field to address zero and `zero` fees. Read more about fees [here](/concepts/fees#broker-fee). :::caution diff --git a/docs/guides/lockup/examples/_category_.json b/docs/guides/lockup/examples/_category_.json new file mode 100644 index 00000000..4c14cded --- /dev/null +++ b/docs/guides/lockup/examples/_category_.json @@ -0,0 +1,5 @@ +{ + "collapsed": false, + "label": "Examples", + "position": 2 +} diff --git a/docs/guides/lockup/guides/batch-create-streams/01-batch-lockup-linear.mdx b/docs/guides/lockup/examples/batch-create-streams/01-batch-lockup-linear.mdx similarity index 100% rename from docs/guides/lockup/guides/batch-create-streams/01-batch-lockup-linear.mdx rename to docs/guides/lockup/examples/batch-create-streams/01-batch-lockup-linear.mdx diff --git a/docs/guides/lockup/guides/batch-create-streams/02-batch-lockup-dynamic.mdx b/docs/guides/lockup/examples/batch-create-streams/02-batch-lockup-dynamic.mdx similarity index 100% rename from docs/guides/lockup/guides/batch-create-streams/02-batch-lockup-dynamic.mdx rename to docs/guides/lockup/examples/batch-create-streams/02-batch-lockup-dynamic.mdx diff --git a/docs/guides/lockup/guides/batch-create-streams/03-batch-lockup-tranched.mdx b/docs/guides/lockup/examples/batch-create-streams/03-batch-lockup-tranched.mdx similarity index 100% rename from docs/guides/lockup/guides/batch-create-streams/03-batch-lockup-tranched.mdx rename to docs/guides/lockup/examples/batch-create-streams/03-batch-lockup-tranched.mdx diff --git a/docs/guides/lockup/guides/batch-create-streams/_category_.json b/docs/guides/lockup/examples/batch-create-streams/_category_.json similarity index 100% rename from docs/guides/lockup/guides/batch-create-streams/_category_.json rename to docs/guides/lockup/examples/batch-create-streams/_category_.json diff --git a/docs/guides/lockup/guides/create-stream/01-lockup-linear.mdx b/docs/guides/lockup/examples/create-stream/01-lockup-linear.mdx similarity index 100% rename from docs/guides/lockup/guides/create-stream/01-lockup-linear.mdx rename to docs/guides/lockup/examples/create-stream/01-lockup-linear.mdx diff --git a/docs/guides/lockup/guides/create-stream/02-lockup-dynamic.mdx b/docs/guides/lockup/examples/create-stream/02-lockup-dynamic.mdx similarity index 100% rename from docs/guides/lockup/guides/create-stream/02-lockup-dynamic.mdx rename to docs/guides/lockup/examples/create-stream/02-lockup-dynamic.mdx diff --git a/docs/guides/lockup/guides/create-stream/03-lockup-tranched.mdx b/docs/guides/lockup/examples/create-stream/03-lockup-tranched.mdx similarity index 100% rename from docs/guides/lockup/guides/create-stream/03-lockup-tranched.mdx rename to docs/guides/lockup/examples/create-stream/03-lockup-tranched.mdx diff --git a/docs/guides/lockup/guides/create-stream/_category_.json b/docs/guides/lockup/examples/create-stream/_category_.json similarity index 100% rename from docs/guides/lockup/guides/create-stream/_category_.json rename to docs/guides/lockup/examples/create-stream/_category_.json diff --git a/docs/guides/lockup/guides/stream-management/01-setup.md b/docs/guides/lockup/examples/stream-management/01-setup.md similarity index 97% rename from docs/guides/lockup/guides/stream-management/01-setup.md rename to docs/guides/lockup/examples/stream-management/01-setup.md index b9141f39..a9c2c8c2 100644 --- a/docs/guides/lockup/guides/stream-management/01-setup.md +++ b/docs/guides/lockup/examples/stream-management/01-setup.md @@ -9,7 +9,7 @@ renounce, and transfer ownership of streams. Before diving in, please note the following: -1. We assume you are already familiar with [creating streams](/guides/lockup/guides/create-stream/lockup-linear). +1. We assume you are already familiar with [creating streams](/guides/lockup/examples/create-stream/lockup-linear). 2. We also assume that the stream management contract is authorized to invoke each respective function. To learn more about access control in Lockup, see the [Access Control](/reference/lockup/access-control) guide. diff --git a/docs/guides/lockup/guides/stream-management/02-withdraw.md b/docs/guides/lockup/examples/stream-management/02-withdraw.md similarity index 90% rename from docs/guides/lockup/guides/stream-management/02-withdraw.md rename to docs/guides/lockup/examples/stream-management/02-withdraw.md index f4a2b9f4..2faa9a53 100644 --- a/docs/guides/lockup/guides/stream-management/02-withdraw.md +++ b/docs/guides/lockup/examples/stream-management/02-withdraw.md @@ -6,7 +6,8 @@ title: "Withdraw from Streams" :::note -This section assumes that you have already gone through the [setup](/guides/lockup/guides/stream-management/setup) part. +This section assumes that you have already gone through the [setup](/guides/lockup/examples/stream-management/setup) +part. ::: @@ -32,8 +33,8 @@ There are four withdrawal functions: amounts of assets from multiple streams at once. To call any of these functions, you need to have created a stream. If you don't have one yet, go back to the -[previous guide](/guides/lockup/guides/create-stream/lockup-linear) and create a stream with a brief duration, assigning -the `StreamManagement` contract as the recipient. Then, you can use the `withdraw` function like this: +[previous guide](/guides/lockup/examples/create-stream/lockup-linear) and create a stream with a brief duration, +assigning the `StreamManagement` contract as the recipient. Then, you can use the `withdraw` function like this: ```solidity reference title="Stream Management: Withdraw" https://github.com/sablier-labs/examples/blob/main/v2/core/StreamManagement.sol#L20-L22 diff --git a/docs/guides/lockup/guides/stream-management/03-cancel.md b/docs/guides/lockup/examples/stream-management/03-cancel.md similarity index 87% rename from docs/guides/lockup/guides/stream-management/03-cancel.md rename to docs/guides/lockup/examples/stream-management/03-cancel.md index 75fedc64..fc175a7f 100644 --- a/docs/guides/lockup/guides/stream-management/03-cancel.md +++ b/docs/guides/lockup/examples/stream-management/03-cancel.md @@ -6,7 +6,8 @@ title: "Cancel Streams" :::note -This section assumes that you have already gone through the [setup](/guides/lockup/guides/stream-management/setup) part. +This section assumes that you have already gone through the [setup](/guides/lockup/examples/stream-management/setup) +part. ::: @@ -27,8 +28,8 @@ There are two functions that can be used to cancel streams: streams at once To call any of these functions, you need to have created a cancelable stream. If you don't have one yet, go back to the -[previous guide](/guides/lockup/guides/create-stream/lockup-linear) and create a stream. Then, you can use the `cancel` -function like this: +[previous guide](/guides/lockup/examples/create-stream/lockup-linear) and create a stream. Then, you can use the +`cancel` function like this: ```solidity reference title="Stream Management: Cancel" https://github.com/sablier-labs/examples/blob/main/v2/core/StreamManagement.sol#L39-L41 diff --git a/docs/guides/lockup/guides/stream-management/04-renounce.md b/docs/guides/lockup/examples/stream-management/04-renounce.md similarity index 93% rename from docs/guides/lockup/guides/stream-management/04-renounce.md rename to docs/guides/lockup/examples/stream-management/04-renounce.md index b1a69d8a..1fc0edd9 100644 --- a/docs/guides/lockup/guides/stream-management/04-renounce.md +++ b/docs/guides/lockup/examples/stream-management/04-renounce.md @@ -6,7 +6,8 @@ title: "Renounce Streams" :::note -This section assumes that you have already gone through the [setup](/guides/lockup/guides/stream-management/setup) part. +This section assumes that you have already gone through the [setup](/guides/lockup/examples/stream-management/setup) +part. ::: diff --git a/docs/guides/lockup/guides/stream-management/05-transfer.md b/docs/guides/lockup/examples/stream-management/05-transfer.md similarity index 97% rename from docs/guides/lockup/guides/stream-management/05-transfer.md rename to docs/guides/lockup/examples/stream-management/05-transfer.md index dfb2f95c..505cf716 100644 --- a/docs/guides/lockup/guides/stream-management/05-transfer.md +++ b/docs/guides/lockup/examples/stream-management/05-transfer.md @@ -6,7 +6,8 @@ title: "Transfer Ownership" :::note -This section assumes that you have already gone through the [setup](/guides/lockup/guides/stream-management/setup) part. +This section assumes that you have already gone through the [setup](/guides/lockup/examples/stream-management/setup) +part. ::: diff --git a/docs/guides/lockup/guides/stream-management/_category_.json b/docs/guides/lockup/examples/stream-management/_category_.json similarity index 100% rename from docs/guides/lockup/guides/stream-management/_category_.json rename to docs/guides/lockup/examples/stream-management/_category_.json diff --git a/docs/guides/lockup/versions/_category_.json b/docs/guides/lockup/previous-deployments/_category_.json similarity index 53% rename from docs/guides/lockup/versions/_category_.json rename to docs/guides/lockup/previous-deployments/_category_.json index 7f72a78c..03fe00d9 100644 --- a/docs/guides/lockup/versions/_category_.json +++ b/docs/guides/lockup/previous-deployments/_category_.json @@ -1,5 +1,5 @@ { "collapsed": true, - "label": "Previous Versions", + "label": "Previous Deployments", "position": 5 } diff --git a/docs/guides/lockup/versions/v1.md b/docs/guides/lockup/previous-deployments/legacy.md similarity index 95% rename from docs/guides/lockup/versions/v1.md rename to docs/guides/lockup/previous-deployments/legacy.md index 72026733..bbcd1de9 100644 --- a/docs/guides/lockup/versions/v1.md +++ b/docs/guides/lockup/previous-deployments/legacy.md @@ -1,12 +1,12 @@ --- -id: "v1" +id: "legacy" sidebar_position: 3 -title: "V1" +title: "Legacy V1" --- -v1.0 and v1.1 deployments are supported in the [official user interface](https://v1-pay.sablier.com). +The deployments of the first version of Lockup are supported in the [v1-pay user interface](https://v1-pay.sablier.com). -### Lockup V1.1 +### Legacy V1.1 | Contract | Chain | Address | | ----------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------ | @@ -19,7 +19,7 @@ v1.0 and v1.1 deployments are supported in the [official user interface](https:/ | Sablier.sol | Ronin | [0xDe9dCc27aa1552d591Fc9B9c21881feE43BD8118](https://explorer.roninchain.com/address/ronin:de9dcc27aa1552d591fc9b9c21881fee43bd8118) | | Sablier.sol | Goerli | [0xFc7E3a3073F88B0f249151192812209117C2014b](https://goerli.etherscan.io/address/0xFc7E3a3073F88B0f249151192812209117C2014b) | -### Lockup V1.0 +### Legacy V1.0 _This is an outdated deployment_. diff --git a/docs/guides/lockup/versions/v2.0.md b/docs/guides/lockup/previous-deployments/v1.0.md similarity index 99% rename from docs/guides/lockup/versions/v2.0.md rename to docs/guides/lockup/previous-deployments/v1.0.md index 0ba37f46..e1a2adf8 100644 --- a/docs/guides/lockup/versions/v2.0.md +++ b/docs/guides/lockup/previous-deployments/v1.0.md @@ -1,10 +1,10 @@ --- -id: "v2.0" +id: "v1.0" sidebar_position: 2 -title: "V2.0" +title: "v1.0" --- -This document contains the deployment addresses for the V2.0 release of [@sablier/v2-core@1.0.2][v2-core] and +This document contains the deployment addresses for the v1.0 release of [@sablier/v2-core@1.0.2][v2-core] and [@sablier/v2-periphery@1.0.3][v2-periphery]. [v2-core]: https://npmjs.com/package/@sablier/v2-core/v/1.0.2 @@ -13,7 +13,7 @@ This document contains the deployment addresses for the V2.0 release of [@sablie A few noteworthy details about the deployments: - The addresses are final -- All LockupLinear and LockupDynamic contracts are non-upgradeable +- All contracts are non-upgradeable - The source code is verified on Etherscan across all chains :::info diff --git a/docs/guides/lockup/versions/v2.1.md b/docs/guides/lockup/previous-deployments/v1.1.md similarity index 99% rename from docs/guides/lockup/versions/v2.1.md rename to docs/guides/lockup/previous-deployments/v1.1.md index b70ee2fe..3bcd71c6 100644 --- a/docs/guides/lockup/versions/v2.1.md +++ b/docs/guides/lockup/previous-deployments/v1.1.md @@ -1,10 +1,10 @@ --- -id: "v2.1" +id: "v1.1" sidebar_position: 1 -title: "V2.1" +title: "v1.1" --- -This document contains the deployment addresses for the V2.1 release of [@sablier/v2-core@1.1.2][v2-core] and +This document contains the deployment addresses for the v1.1 release of [@sablier/v2-core@1.1.2][v2-core] and [@sablier/v2-periphery@1.1.1][v2-periphery]. [v2-core]: https://npmjs.com/package/@sablier/v2-core/v/1.1.2 @@ -13,7 +13,7 @@ This document contains the deployment addresses for the V2.1 release of [@sablie A few noteworthy details about the deployments: - The addresses are final -- All LockupLinear and LockupDynamic contracts are non-upgradeable +- All contracts are non-upgradeable - The source code is verified on Etherscan across all chains :::info diff --git a/docs/reference/04-errors.md b/docs/reference/04-errors.md index 89dad48f..d7b049eb 100644 --- a/docs/reference/04-errors.md +++ b/docs/reference/04-errors.md @@ -24,8 +24,8 @@ bytes4(keccak256(bytes("SablierV2Lockup_Unauthorized(address,uint256)"))) ## Naming Pattern -With the exception of a few generics, all errors in Lockup protocols adhere to the naming pattern -`SablierV2_` whereas in Flow protocol, they adhere to `SablierFlow_`. +With the exception of a few generics, all errors in Sablier protocols adhere to the naming pattern +`_`. Incorporating the contract name as a prefix offers context, making it easier for end users to pinpoint the contract responsible for a reverted transaction. This approach is particularly helpful for complex transactions involving @@ -43,7 +43,7 @@ multiple contracts. ## Flow Error List -Coming soon. +[Click here](flow/contracts/libraries/library.Errors) to see the full error list in Flow. ## Resources diff --git a/docs/reference/flow/01-diagrams.md b/docs/reference/flow/01-diagrams.md new file mode 100644 index 00000000..f576bc51 --- /dev/null +++ b/docs/reference/flow/01-diagrams.md @@ -0,0 +1,112 @@ +--- +id: "diagrams" +sidebar_position: 1 +title: "Diagrams" +--- + +## Flow Storage Layout + +Each Flow contract is a singleton that stores all streams created by that contract's users. The following diagrams +provide insight into the storage layout. To see the list of all storage variables, +[click here](/reference/flow/contracts/types/library.Flow#structs). + +```mermaid +flowchart LR + storage[(Storage)] + bal([Balance - bal]) + rps([RatePerSecond - rps]) + sd([SnapshotDebtScaled - sd]) + st([Snapshot Time - st]) + + storage --> bal + storage --> rps + storage --> sd + storage --> st +``` + +## Token Balance Actions + +```mermaid +flowchart LR + erc_transfers[(ERC20 Transfer Actions)] + dep([Deposit - add]) + ref([Refund - remove]) + wtd([Withdraw - remove]) + + erc_transfers --> dep + erc_transfers --> ref + erc_transfers --> wtd +``` + +$~$ + +## Debts + +### Ongoing Debt + +```mermaid +flowchart TD +rca([Ongoing Debt - od]) +di0{ } +di1{ } +res_00([0 ]) +res_01([0 ]) +res_rca(["rps * elt"]) + +rca --> di0 +di0 -- "rps > 0" --> di1 +di0 -- "rps == 0" --> res_00 +di1 -- "now <= st" --> res_01 +di1 -- "now > st" --> res_rca +``` + +### Uncovered Debt + +**Notes:** A non-zero uncovered debt implies: + +1. `bal < sd` when the status is `PAUSED` +2. `bal < sd + od` when the status is `STREAMING` + +```mermaid +flowchart TD + di0{ }:::red1 + sd([Uncovered Debt - ud]) + res_sd(["td - bal"]) + res_zero([0]) + + sd --> di0 + di0 -- "bal < td" --> res_sd + di0 -- "bal >= td" --> res_zero +``` + +### Covered debt + +```mermaid +flowchart TD + di0{ }:::blue0 + di1{ }:::blue0 + di2{ }:::blue0 + cd([Covered Debt - cd]) + res_0([0 ]) + res_bal([bal]) + res_sd([sd]) + res_sum([td]) + + + cd --> di0 + di0 -- "bal = 0" --> res_0 + di0 -- "bal > 0" --> di1 + di1 -- "ud > 0" --> res_bal + di1 -- "ud = 0" --> di2 + di2 -- "paused" --> res_sd + di2 -- "streaming" --> res_sum +``` + +### Refundable Amount + +```mermaid + flowchart TD + ra([Refundable Amount - ra]) + res_ra([bal - cd]) + ra --> res_ra +``` diff --git a/docs/reference/flow/01-overview.md b/docs/reference/flow/01-overview.md deleted file mode 100644 index 97e2a607..00000000 --- a/docs/reference/flow/01-overview.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -id: "overview" -sidebar_position: 1 -title: "Overview" ---- - -Coming soon. diff --git a/docs/reference/flow/03-access-control.md b/docs/reference/flow/03-access-control.md new file mode 100644 index 00000000..78257585 --- /dev/null +++ b/docs/reference/flow/03-access-control.md @@ -0,0 +1,33 @@ +--- +id: "access-control" +sidebar_position: 3 +title: "Access Control" +--- + +With the exception of the [admin functions](/concepts/governance#flow), all functionalities in Flow can only be +triggered by users. The Protocol Admin has no control over any stream or any part of the protocol. + +This article will provide a comprehensive overview of the actions that can be performed on streams once they are +created, as well as the corresponding user permissions for each action. + +:::note + +Every stream has a sender and a recipient. Recipients can approve third parties to take actions on their behalf. An +'public' caller is any address outside of sender and recipient. + +::: + +## Overview + +The table below offers a quick overview of the access control for each action that can be performed on a stream. + +| Action | Sender | Recipient / Approved third party | Public | +| ----------------------- | :----: | :------------------------------: | :----: | +| Deposit | ✅ | ✅ | ✅ | +| Pause | ✅ | ❌ | ❌ | +| Refund | ✅ | ❌ | ❌ | +| Restart | ✅ | ❌ | ❌ | +| Transfer NFT | ❌ | ✅ | ❌ | +| Withdraw to any address | ❌ | ✅ | ❌ | +| Withdraw to recipient | ✅ | ✅ | ✅ | +| Void | ✅ | ✅ | ❌ | diff --git a/docs/reference/flow/contracts/_category_.json b/docs/reference/flow/contracts/_category_.json new file mode 100644 index 00000000..82f18384 --- /dev/null +++ b/docs/reference/flow/contracts/_category_.json @@ -0,0 +1,5 @@ +{ + "collapsed": true, + "label": "Contracts", + "position": 2 +} diff --git a/docs/reference/flow/contracts/abstracts/abstract.Adminable.md b/docs/reference/flow/contracts/abstracts/abstract.Adminable.md new file mode 100644 index 00000000..79df8d43 --- /dev/null +++ b/docs/reference/flow/contracts/abstracts/abstract.Adminable.md @@ -0,0 +1,48 @@ +# Adminable + +[Git Source](https://github.com/sablier-labs/flow/blob/b01cc2daf6493ae792a858d6179facc6250403e2/src/abstracts/Adminable.sol) + +**Inherits:** [IAdminable](/docs/reference/flow/contracts/interfaces/interface.IAdminable.md) + +See the documentation in [IAdminable](/docs/reference/flow/contracts/interfaces/interface.IAdminable.md). + +## State Variables + +### admin + +The address of the admin account or contract. + +```solidity +address public override admin; +``` + +## Functions + +### onlyAdmin + +Reverts if called by any account other than the admin. + +```solidity +modifier onlyAdmin(); +``` + +### transferAdmin + +Transfers the contract admin to a new address. + +Notes: + +- Does not revert if the admin is the same. +- This function can potentially leave the contract without an admin, thereby removing any functionality that is only + available to the admin. Requirements: +- `msg.sender` must be the contract admin. + +```solidity +function transferAdmin(address newAdmin) public virtual override onlyAdmin; +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ----------------------------- | +| `newAdmin` | `address` | The address of the new admin. | diff --git a/docs/reference/flow/contracts/abstracts/abstract.Batch.md b/docs/reference/flow/contracts/abstracts/abstract.Batch.md new file mode 100644 index 00000000..d0d418c1 --- /dev/null +++ b/docs/reference/flow/contracts/abstracts/abstract.Batch.md @@ -0,0 +1,23 @@ +# Batch + +[Git Source](https://github.com/sablier-labs/flow/blob/b01cc2daf6493ae792a858d6179facc6250403e2/src/abstracts/Batch.sol) + +This contract implements logic to batch call any function. + +_Forked from: https://github.com/boringcrypto/BoringSolidity/blob/master/contracts/BoringBatchable.sol_ + +## Functions + +### batch + +Allows batched call to self, `this` contract. + +```solidity +function batch(bytes[] calldata calls) external; +``` + +**Parameters** + +| Name | Type | Description | +| ------- | --------- | --------------------------------- | +| `calls` | `bytes[]` | An array of inputs for each call. | diff --git a/docs/reference/flow/contracts/abstracts/abstract.NoDelegateCall.md b/docs/reference/flow/contracts/abstracts/abstract.NoDelegateCall.md new file mode 100644 index 00000000..3b7b63b2 --- /dev/null +++ b/docs/reference/flow/contracts/abstracts/abstract.NoDelegateCall.md @@ -0,0 +1,46 @@ +# NoDelegateCall + +[Git Source](https://github.com/sablier-labs/flow/blob/b01cc2daf6493ae792a858d6179facc6250403e2/src/abstracts/NoDelegateCall.sol) + +This contract implements logic to prevent delegate calls. + +## State Variables + +### ORIGINAL + +_The address of the original contract that was deployed._ + +```solidity +address private immutable ORIGINAL; +``` + +## Functions + +### constructor + +_Sets the original contract address._ + +```solidity +constructor(); +``` + +### noDelegateCall + +Prevents delegate calls. + +```solidity +modifier noDelegateCall(); +``` + +### \_preventDelegateCall + +This function checks whether the current call is a delegate call, and reverts if it is. + +- A private function is used instead of inlining this logic in a modifier because Solidity copies modifiers into every + function that uses them. The `ORIGINAL` address would get copied in every place the modifier is used, which would + increase the contract size. By using a function instead, we can avoid this duplication of code and reduce the overall + size of the contract. + +```solidity +function _preventDelegateCall() private view; +``` diff --git a/docs/reference/flow/contracts/abstracts/abstract.SablierFlowBase.md b/docs/reference/flow/contracts/abstracts/abstract.SablierFlowBase.md new file mode 100644 index 00000000..78936fa2 --- /dev/null +++ b/docs/reference/flow/contracts/abstracts/abstract.SablierFlowBase.md @@ -0,0 +1,476 @@ +# SablierFlowBase + +[Git Source](https://github.com/sablier-labs/flow/blob/b01cc2daf6493ae792a858d6179facc6250403e2/src/abstracts/SablierFlowBase.sol) + +**Inherits:** [Adminable](/docs/reference/flow/contracts/abstracts/abstract.Adminable.md), +[ISablierFlowBase](/docs/reference/flow/contracts/interfaces/interface.ISablierFlowBase.md), ERC721 + +See the documentation in [ISablierFlowBase](/docs/reference/flow/contracts/interfaces/interface.ISablierFlowBase.md). + +## State Variables + +### MAX_FEE + +Retrieves the maximum fee that can be charged by the broker and the protocol, denoted as a fixed-point percentage where +1e18 is 100%. + +_This value is hard coded as a constant._ + +```solidity +UD60x18 public constant override MAX_FEE = UD60x18.wrap(0.1e18); +``` + +### aggregateBalance + +Retrieves the sum of balances of all streams. + +```solidity +mapping(IERC20 token => uint256 amount) public override aggregateBalance; +``` + +### nextStreamId + +Counter for stream ids. + +```solidity +uint256 public override nextStreamId; +``` + +### nftDescriptor + +Contract that generates the non-fungible token URI. + +```solidity +IFlowNFTDescriptor public override nftDescriptor; +``` + +### protocolFee + +Protocol fee for the provided ERC-20 token, denoted as a fixed-point percentage where 1e18 is 100%. + +```solidity +mapping(IERC20 token => UD60x18 fee) public override protocolFee; +``` + +### protocolRevenue + +Protocol revenue accrued for the provided ERC-20 token, denoted in token's decimals. + +```solidity +mapping(IERC20 token => uint128 revenue) public override protocolRevenue; +``` + +### \_streams + +_Sablier Flow streams mapped by unsigned integers._ + +```solidity +mapping(uint256 id => Flow.Stream stream) internal _streams; +``` + +## Functions + +### constructor + +_Emits {TransferAdmin} event._ + +```solidity +constructor(address initialAdmin, IFlowNFTDescriptor initialNFTDescriptor); +``` + +**Parameters** + +| Name | Type | Description | +| ---------------------- | -------------------- | ------------------------------------------ | +| `initialAdmin` | `address` | The address of the initial contract admin. | +| `initialNFTDescriptor` | `IFlowNFTDescriptor` | The address of the initial NFT descriptor. | + +### notNull + +_Checks that `streamId` does not reference a null stream._ + +```solidity +modifier notNull(uint256 streamId); +``` + +### notPaused + +_Checks that `streamId` does not reference a paused stream._ + +```solidity +modifier notPaused(uint256 streamId); +``` + +### notVoided + +```solidity +modifier notVoided(uint256 streamId); +``` + +### onlySender + +_Checks the `msg.sender` is the stream's sender._ + +```solidity +modifier onlySender(uint256 streamId); +``` + +### updateMetadata + +_Emits an ERC-4906 event to trigger an update of the NFT metadata._ + +```solidity +modifier updateMetadata(uint256 streamId); +``` + +### getBalance + +Retrieves the balance of the stream, i.e. the total deposited amounts subtracted by the total withdrawn amounts, denoted +in token's decimals. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getBalance(uint256 streamId) external view override notNull(streamId) returns (uint128 balance); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getRatePerSecond + +Retrieves the rate per second of the stream, denoted as a fixed-point number where 1e18 is 1 token per second. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getRatePerSecond(uint256 streamId) external view override notNull(streamId) returns (UD21x18 ratePerSecond); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to make the query for. | + +### getRecipient + +Retrieves the stream's recipient. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getRecipient(uint256 streamId) external view override notNull(streamId) returns (address recipient); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getSender + +Retrieves the stream's sender. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getSender(uint256 streamId) external view override notNull(streamId) returns (address sender); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getSnapshotDebtScaled + +Retrieves the snapshot debt of the stream, denoted as a fixed-point number where 1e18 is 1 token. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getSnapshotDebtScaled(uint256 streamId) + external + view + override + notNull(streamId) + returns (uint256 snapshotDebtScaled); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getSnapshotTime + +Retrieves the snapshot time of the stream, which is a Unix timestamp. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getSnapshotTime(uint256 streamId) external view override notNull(streamId) returns (uint40 snapshotTime); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to make the query for. | + +### getStream + +Retrieves the stream entity. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getStream(uint256 streamId) external view override notNull(streamId) returns (Flow.Stream memory stream); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getToken + +Retrieves the token of the stream. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getToken(uint256 streamId) external view override notNull(streamId) returns (IERC20 token); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to make the query for. | + +### getTokenDecimals + +Retrieves the token decimals of the stream. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getTokenDecimals(uint256 streamId) external view override notNull(streamId) returns (uint8 tokenDecimals); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to make the query for. | + +### isPaused + +Returns whether a stream is paused. + +_Reverts if `streamId` references a null stream._ + +```solidity +function isPaused(uint256 streamId) external view override notNull(streamId) returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### isStream + +Retrieves a flag indicating whether the stream exists. + +_Does not revert if `streamId` references a null stream._ + +```solidity +function isStream(uint256 streamId) external view override returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### isTransferable + +Retrieves a flag indicating whether the stream NFT is transferable. + +_Reverts if `streamId` references a null stream._ + +```solidity +function isTransferable(uint256 streamId) external view override notNull(streamId) returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### isVoided + +Retrieves a flag indicating whether the stream is voided. + +_Reverts if `streamId` references a null stream._ + +```solidity +function isVoided(uint256 streamId) external view override notNull(streamId) returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### tokenURI + +_See {IERC721Metadata-tokenURI}._ + +```solidity +function tokenURI(uint256 streamId) public view override(IERC721Metadata, ERC721) returns (string memory uri); +``` + +### collectProtocolRevenue + +Collect the protocol revenue accrued for the provided ERC-20 token. + +Emits {CollectProtocolRevenue} event. Requirements: + +- `msg.sender` must be the contract admin. +- The accrued protocol revenue must be greater than zero. + +```solidity +function collectProtocolRevenue(IERC20 token, address to) external override onlyAdmin; +``` + +**Parameters** + +| Name | Type | Description | +| ------- | --------- | ----------------------------------------------------------------------------- | +| `token` | `IERC20` | The contract address of the ERC-20 token for which to claim protocol revenue. | +| `to` | `address` | The address to send the protocol revenue. | + +### recover + +Recover the surplus amount of tokens. + +Emits {Recover} event. Notes: + +- The surplus amount is defined as the difference between the total balance of the contract for the provided ERC-20 + token and the sum of balances of all streams created using the same ERC-20 token. Requirements: +- `msg.sender` must be the contract admin. +- The surplus amount must be greater than zero. + +```solidity +function recover(IERC20 token, address to) external override onlyAdmin; +``` + +**Parameters** + +| Name | Type | Description | +| ------- | --------- | -------------------------------------------------------- | +| `token` | `IERC20` | The contract address of the ERC-20 token to recover for. | +| `to` | `address` | The address to send the surplus amount. | + +### setNFTDescriptor + +Sets a new NFT descriptor contract, which produces the URI describing the Sablier stream NFTs. + +Emits {SetNFTDescriptor} and {BatchMetadataUpdate} events. Notes: + +- Does not revert if the NFT descriptor is the same. Requirements: +- `msg.sender` must be the contract admin. + +```solidity +function setNFTDescriptor(IFlowNFTDescriptor newNFTDescriptor) external override onlyAdmin; +``` + +**Parameters** + +| Name | Type | Description | +| ------------------ | -------------------- | ----------------------------------------------- | +| `newNFTDescriptor` | `IFlowNFTDescriptor` | The address of the new NFT descriptor contract. | + +### setProtocolFee + +Sets a new protocol fee that will be charged on all the withdrawals from streams created with the provided ERC-20 token. + +Emits {SetProtocolFee} and {BatchMetadataUpdate} events. Notes: + +- Does not revert if the fee is the same. +- It can be zero. Requirements: +- `msg.sender` must be the contract admin. +- `newProtocolFee` must not be greater than `MAX_FEE`. + +```solidity +function setProtocolFee(IERC20 token, UD60x18 newProtocolFee) external override onlyAdmin; +``` + +**Parameters** + +| Name | Type | Description | +| ---------------- | --------- | ----------------------------------------------------------------------------- | +| `token` | `IERC20` | The contract address of the ERC-20 token to update the fee for. | +| `newProtocolFee` | `UD60x18` | The new protocol fee, denoted as a fixed-point percentage where 1e18 is 100%. | + +### \_isCallerStreamRecipientOrApproved + +Checks whether `msg.sender` is the stream's recipient or an approved third party. + +```solidity +function _isCallerStreamRecipientOrApproved(uint256 streamId) internal view returns (bool); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### \_update + +Overrides the {ERC-721.\_update} function to check that the stream is transferable. + +_The transferable flag is ignored if the current owner is 0, as the update in this case is a mint and is allowed. +Transfers to the zero address are not allowed, preventing accidental burns._ + +```solidity +function _update( + address to, + uint256 streamId, + address auth +) + internal + override + updateMetadata(streamId) + returns (address); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `to` | `address` | The address of the new recipient of the stream. | +| `streamId` | `uint256` | ID of the stream to update. | +| `auth` | `address` | Optional parameter. If the value is not zero, the overridden implementation will check that `auth` is either the recipient of the stream, or an approved third party. | + +**Returns** + +| Name | Type | Description | +| -------- | --------- | ----------------------------------------------------------- | +| `` | `address` | The original recipient of the `streamId` before the update. | diff --git a/docs/reference/flow/contracts/contract.FlowNFTDescriptor.md b/docs/reference/flow/contracts/contract.FlowNFTDescriptor.md new file mode 100644 index 00000000..70e02e42 --- /dev/null +++ b/docs/reference/flow/contracts/contract.FlowNFTDescriptor.md @@ -0,0 +1,37 @@ +--- +sidebar_position: 2 +--- + +# FlowNFTDescriptor + +[Git Source](https://github.com/sablier-labs/flow/blob/b01cc2daf6493ae792a858d6179facc6250403e2/src/FlowNFTDescriptor.sol) + +**Inherits:** [IFlowNFTDescriptor](/docs/reference/flow/contracts/interfaces/interface.IFlowNFTDescriptor.md) + +See the documentation in +[IFlowNFTDescriptor](/docs/reference/flow/contracts/interfaces/interface.IFlowNFTDescriptor.md). + +## Functions + +### tokenURI + +Produces the URI describing a particular stream NFT. + +_Currently it returns the Sablier logo as an SVG. In the future, it will return an NFT SVG._ + +```solidity +function tokenURI(IERC721Metadata, uint256) external pure override returns (string memory uri); +``` + +**Parameters** + +| Name | Type | Description | +| -------- | ----------------- | ----------- | +| `` | `IERC721Metadata` | | +| `` | `uint256` | | + +**Returns** + +| Name | Type | Description | +| ----- | -------- | ----------------------------------------- | +| `uri` | `string` | The URI of the ERC721-compliant metadata. | diff --git a/docs/reference/flow/contracts/contract.SablierFlow.md b/docs/reference/flow/contracts/contract.SablierFlow.md new file mode 100644 index 00000000..57a1a344 --- /dev/null +++ b/docs/reference/flow/contracts/contract.SablierFlow.md @@ -0,0 +1,820 @@ +--- +sidebar_position: 1 +--- + +# SablierFlow + +[Git Source](https://github.com/sablier-labs/flow/blob/b01cc2daf6493ae792a858d6179facc6250403e2/src/SablierFlow.sol) + +**Inherits:** [Batch](/docs/reference/flow/contracts/abstracts/abstract.Batch.md), +[NoDelegateCall](/docs/reference/flow/contracts/abstracts/abstract.NoDelegateCall.md), +[ISablierFlow](/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md), +[SablierFlowBase](/docs/reference/flow/contracts/abstracts/abstract.SablierFlowBase.md) + +See the documentation in [ISablierFlow](/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md). + +## Functions + +### constructor + +_Emits {TransferAdmin} event._ + +```solidity +constructor( + address initialAdmin, + IFlowNFTDescriptor initialNFTDescriptor +) + ERC721("Sablier Flow NFT", "SAB-FLOW") + SablierFlowBase(initialAdmin, initialNFTDescriptor); +``` + +**Parameters** + +| Name | Type | Description | +| ---------------------- | -------------------- | ------------------------------------------ | +| `initialAdmin` | `address` | The address of the initial contract admin. | +| `initialNFTDescriptor` | `IFlowNFTDescriptor` | The address of the initial NFT descriptor. | + +### coveredDebtOf + +Returns the amount of debt covered by the stream balance, denoted in token's decimals. + +_Reverts if `streamId` references a null stream._ + +```solidity +function coveredDebtOf(uint256 streamId) external view override notNull(streamId) returns (uint128 coveredDebt); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### depletionTimeOf + +Returns the time at which the total debt exceeds stream balance. If the total debt is less than or equal to stream +balance, it returns 0. + +_Reverts if `streamId` references a paused or a null stream._ + +```solidity +function depletionTimeOf(uint256 streamId) + external + view + override + notNull(streamId) + notPaused(streamId) + returns (uint256 depletionTime); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### ongoingDebtScaledOf + +Returns the amount of debt accrued since the snapshot time until now, denoted as a fixed-point number where 1e18 is 1 +token. + +_Reverts if `streamId` references a null stream._ + +```solidity +function ongoingDebtScaledOf(uint256 streamId) + external + view + override + notNull(streamId) + returns (uint256 ongoingDebtScaled); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### refundableAmountOf + +Returns the amount that the sender can be refunded from the stream, denoted in token's decimals. + +_Reverts if `streamId` references a null stream._ + +```solidity +function refundableAmountOf(uint256 streamId) + external + view + override + notNull(streamId) + returns (uint128 refundableAmount); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### statusOf + +Returns the stream's status. + +_Reverts if `streamId` references a null stream._ + +```solidity +function statusOf(uint256 streamId) external view override notNull(streamId) returns (Flow.Status status); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### totalDebtOf + +Returns the total amount owed by the sender to the recipient, denoted in token's decimals. + +_Reverts if `streamId` references a null stream._ + +```solidity +function totalDebtOf(uint256 streamId) external view override notNull(streamId) returns (uint256 totalDebt); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### uncoveredDebtOf + +Returns the amount of debt not covered by the stream balance, denoted in token's decimals. + +_Reverts if `streamId` references a null stream._ + +```solidity +function uncoveredDebtOf(uint256 streamId) external view override notNull(streamId) returns (uint256 uncoveredDebt); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### withdrawableAmountOf + +Calculates the amount that the recipient can withdraw from the stream, denoted in token decimals. This is an alias for +`coveredDebtOf`. + +_Reverts if `streamId` references a null stream._ + +```solidity +function withdrawableAmountOf(uint256 streamId) + external + view + override + notNull(streamId) + returns (uint128 withdrawableAmount); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +**Returns** + +| Name | Type | Description | +| -------------------- | --------- | ------------------------------------------- | +| `withdrawableAmount` | `uint128` | The amount that the recipient can withdraw. | + +### adjustRatePerSecond + +Changes the stream's rate per second. + +Emits {AdjustFlowStream} and {MetadataUpdate} events. Notes: + +- Performs a debt snapshot. Requirements: +- Must not be delegate called. +- `streamId` must not reference a null or a paused stream. +- `msg.sender` must be the stream's sender. +- `newRatePerSecond` must not equal to the current rate per second. + +```solidity +function adjustRatePerSecond( + uint256 streamId, + UD21x18 newRatePerSecond +) + external + override + noDelegateCall + notNull(streamId) + notPaused(streamId) + onlySender(streamId) + updateMetadata(streamId); +``` + +**Parameters** + +| Name | Type | Description | +| ------------------ | --------- | ------------------------------------------------------------------------------------------ | +| `streamId` | `uint256` | The ID of the stream to adjust. | +| `newRatePerSecond` | `UD21x18` | The new rate per second, denoted as a fixed-point number where 1e18 is 1 token per second. | + +### create + +Creates a new Flow stream by setting the snapshot time to `block.timestamp` and leaving the balance to zero. The stream +is wrapped in an ERC-721 NFT. + +Emits {CreateFlowStream} event. Requirements: + +- Must not be delegate called. +- `sender` must not be the zero address. +- `recipient` must not be the zero address. +- The `token`'s decimals must be less than or equal to 18. + +```solidity +function create( + address sender, + address recipient, + UD21x18 ratePerSecond, + IERC20 token, + bool transferable +) + external + override + noDelegateCall + returns (uint256 streamId); +``` + +**Parameters** + +| Name | Type | Description | +| --------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------- | +| `sender` | `address` | The address streaming the tokens, which is able to adjust and pause the stream. It doesn't have to be the same as `msg.sender`. | +| `recipient` | `address` | The address receiving the tokens. | +| `ratePerSecond` | `UD21x18` | The amount by which the debt is increasing every second, denoted as a fixed-point number where 1e18 is 1 token per second. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be streamed. | +| `transferable` | `bool` | Boolean indicating if the stream NFT is transferable. | + +**Returns** + +| Name | Type | Description | +| ---------- | --------- | ----------------------------------- | +| `streamId` | `uint256` | The ID of the newly created stream. | + +### createAndDeposit + +Creates a new Flow stream by setting the snapshot time to `block.timestamp` and the balance to `amount`. The stream is +wrapped in an ERC-721 NFT. + +Emits {Transfer}, {CreateFlowStream}, and {DepositFlowStream} events. Notes: + +- Refer to the notes in {deposit}. Requirements: +- Refer to the requirements in {create} and {deposit}. + +```solidity +function createAndDeposit( + address sender, + address recipient, + UD21x18 ratePerSecond, + IERC20 token, + bool transferable, + uint128 amount +) + external + override + noDelegateCall + returns (uint256 streamId); +``` + +**Parameters** + +| Name | Type | Description | +| --------------- | --------- | -------------------------------------------------------------------------------------------------------------------------- | +| `sender` | `address` | The address streaming the tokens. It doesn't have to be the same as `msg.sender`. | +| `recipient` | `address` | The address receiving the tokens. | +| `ratePerSecond` | `UD21x18` | The amount by which the debt is increasing every second, denoted as a fixed-point number where 1e18 is 1 token per second. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be streamed. | +| `transferable` | `bool` | Boolean indicating if the stream NFT is transferable. | +| `amount` | `uint128` | The deposit amount, denoted in token's decimals. | + +**Returns** + +| Name | Type | Description | +| ---------- | --------- | ----------------------------------- | +| `streamId` | `uint256` | The ID of the newly created stream. | + +### deposit + +Makes a deposit in a stream. + +Emits {Transfer} and {DepositFlowStream} events. Requirements: + +- Must not be delegate called. +- `streamId` must not reference a null or a voided stream. +- `amount` must be greater than zero. +- `sender` and `recipient` must match the stream's sender and recipient addresses. + +```solidity +function deposit( + uint256 streamId, + uint128 amount, + address sender, + address recipient +) + external + override + noDelegateCall + notNull(streamId) + notVoided(streamId) + updateMetadata(streamId); +``` + +**Parameters** + +| Name | Type | Description | +| ----------- | --------- | ------------------------------------------------ | +| `streamId` | `uint256` | The ID of the stream to deposit to. | +| `amount` | `uint128` | The deposit amount, denoted in token's decimals. | +| `sender` | `address` | The stream's sender address. | +| `recipient` | `address` | The stream's recipient address. | + +### depositAndPause + +Deposits tokens in a stream and pauses it. + +Emits {Transfer}, {DepositFlowStream} and {PauseFlowStream} events. Notes: + +- Refer to the notes in {deposit} and {pause}. Requirements: +- Refer to the requirements in {deposit} and {pause}. + +```solidity +function depositAndPause( + uint256 streamId, + uint128 amount +) + external + override + noDelegateCall + notNull(streamId) + notPaused(streamId) + onlySender(streamId) + updateMetadata(streamId); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | --------------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to deposit to, and then pause. | +| `amount` | `uint128` | The deposit amount, denoted in token's decimals. | + +### depositViaBroker + +Deposits tokens in a stream. + +Emits {Transfer} and {DepositFlowStream} events. Notes: + +- Refer to the notes in {deposit}. Requirements: +- Must not be delegate called. +- `streamId` must not reference a null stream. +- `totalAmount` must be greater than zero. Otherwise it will revert inside {deposit}. +- `broker.account` must not be 0 address. +- `broker.fee` must not be greater than `MAX_FEE`. It can be zero. + +```solidity +function depositViaBroker( + uint256 streamId, + uint128 totalAmount, + address sender, + address recipient, + Broker calldata broker +) + external + override + noDelegateCall + notNull(streamId) + notVoided(streamId) + updateMetadata(streamId); +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to deposit on. | +| `totalAmount` | `uint128` | The total amount, including the deposit and any broker fee, denoted in token's decimals. | +| `sender` | `address` | The stream's sender address. | +| `recipient` | `address` | The stream's recipient address. | +| `broker` | `Broker` | Struct encapsulating (i) the address of the broker assisting in creating the stream, and (ii) the percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point percentage. | + +### pause + +Pauses the stream. + +Emits {PauseFlowStream} event. Notes: + +- It does not set the snapshot time to the current block timestamp. +- It updates the snapshot debt by adding up ongoing debt. +- It sets the rate per second to zero. Requirements: +- Must not be delegate called. +- `streamId` must not reference a null or an already paused stream. +- `msg.sender` must be the stream's sender. + +```solidity +function pause(uint256 streamId) + external + override + noDelegateCall + notNull(streamId) + notPaused(streamId) + onlySender(streamId) + updateMetadata(streamId); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ------------------------------ | +| `streamId` | `uint256` | The ID of the stream to pause. | + +### refund + +Refunds the provided amount of tokens from the stream to the sender's address. + +Emits {Transfer} and {RefundFromFlowStream} events. Requirements: + +- Must not be delegate called. +- `streamId` must not reference a null stream. +- `msg.sender` must be the sender. +- `amount` must be greater than zero and must not exceed the refundable amount. + +```solidity +function refund( + uint256 streamId, + uint128 amount +) + external + override + noDelegateCall + notNull(streamId) + onlySender(streamId) + updateMetadata(streamId); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | -------------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to refund from. | +| `amount` | `uint128` | The amount to refund, denoted in token's decimals. | + +### refundAndPause + +Refunds the provided amount of tokens from the stream to the sender's address. + +Emits {Transfer}, {RefundFromFlowStream} and {PauseFlowStream} events. Notes: + +- Refer to the notes in {pause}. Requirements: +- Refer to the requirements in {refund} and {pause}. + +```solidity +function refundAndPause( + uint256 streamId, + uint128 amount +) + external + override + noDelegateCall + notNull(streamId) + notPaused(streamId) + onlySender(streamId) + updateMetadata(streamId); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | --------------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to refund from and then pause. | +| `amount` | `uint128` | The amount to refund, denoted in token's decimals. | + +### restart + +Restarts the stream with the provided rate per second. + +Emits {RestartFlowStream} event. + +- This function updates stream's `snapshotTime` to the current block timestamp. Notes: +- It sets the snapshot time to the current block timestamp. Requirements: +- Must not be delegate called. +- `streamId` must not reference a null, or a voided stream. +- `msg.sender` must be the stream's sender. +- `ratePerSecond` must be greater than zero. + +```solidity +function restart( + uint256 streamId, + UD21x18 ratePerSecond +) + external + override + noDelegateCall + notNull(streamId) + notVoided(streamId) + onlySender(streamId) + updateMetadata(streamId); +``` + +**Parameters** + +| Name | Type | Description | +| --------------- | --------- | -------------------------------------------------------------------------------------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to restart. | +| `ratePerSecond` | `UD21x18` | The amount by which the debt is increasing every second, denoted as a fixed-point number where 1e18 is 1 token per second. | + +### restartAndDeposit + +Restarts the stream with the provided rate per second, and makes a deposit. + +Emits {RestartFlowStream}, {Transfer}, and {DepositFlowStream} events. Notes: + +- Refer to the notes in {restart} and {deposit}. Requirements: +- `amount` must be greater than zero. +- Refer to the requirements in {restart}. + +```solidity +function restartAndDeposit( + uint256 streamId, + UD21x18 ratePerSecond, + uint128 amount +) + external + override + noDelegateCall + notNull(streamId) + notVoided(streamId) + onlySender(streamId) + updateMetadata(streamId); +``` + +**Parameters** + +| Name | Type | Description | +| --------------- | --------- | -------------------------------------------------------------------------------------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to restart. | +| `ratePerSecond` | `UD21x18` | The amount by which the debt is increasing every second, denoted as a fixed-point number where 1e18 is 1 token per second. | +| `amount` | `uint128` | The deposit amount, denoted in token's decimals. | + +### void + +Voids a stream. + +Emits {VoidFlowStream} event. Notes: + +- It sets snapshot time to the `block.timestamp` +- Voiding an insolvent stream sets the snapshot debt to the stream's balance making the uncovered debt to become zero. +- Voiding a solvent stream updates the snapshot debt by adding up ongoing debt. +- It sets the rate per second to zero. +- A voided stream cannot be restarted. Requirements: +- Must not be delegate called. +- `streamId` must not reference a null or a voided stream. +- `msg.sender` must either be the stream's sender, recipient or an approved third party. + +```solidity +function void(uint256 streamId) + external + override + noDelegateCall + notNull(streamId) + notVoided(streamId) + updateMetadata(streamId); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ----------------------------- | +| `streamId` | `uint256` | The ID of the stream to void. | + +### withdraw + +Withdraws the provided `amount` minus the protocol fee to the provided `to` address. + +Emits {Transfer} and {WithdrawFromFlowStream} events. Notes: + +- It sets the snapshot time to the `block.timestamp` if `amount` is greater than snapshot debt. +- A protocol fee may be charged on the withdrawn amount if the protocol fee is enabled for the streaming token. + Requirements: +- Must not be delegate called. +- `streamId` must not reference a null stream. +- `to` must not be the zero address. +- `to` must be the recipient if `msg.sender` is not the stream's recipient. +- `amount` must be greater than zero and must not exceed the withdrawable amount. + +```solidity +function withdraw( + uint256 streamId, + address to, + uint128 amount +) + external + override + noDelegateCall + notNull(streamId) + updateMetadata(streamId) + returns (uint128 withdrawnAmount, uint128 protocolFeeAmount); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to withdraw from. | +| `to` | `address` | The address receiving the withdrawn tokens. | +| `amount` | `uint128` | The amount to withdraw, denoted in token's decimals. | + +**Returns** + +| Name | Type | Description | +| ------------------- | --------- | ---------------------------------------------------------------------------------------------------------------- | +| `withdrawnAmount` | `uint128` | The amount withdrawn to the recipient, denoted in token's decimals. This is input amount minus the protocol fee. | +| `protocolFeeAmount` | `uint128` | The protocol fee amount, denoted in the token's decimals. | + +### withdrawMax + +Withdraws the entire withdrawable amount minus the protocol fee to the provided `to` address. + +Emits {Transfer} and {WithdrawFromFlowStream} events. Notes: + +- Refer to the notes in {withdraw}. Requirements: +- Refer to the requirements in {withdraw}. + +```solidity +function withdrawMax( + uint256 streamId, + address to +) + external + override + noDelegateCall + notNull(streamId) + updateMetadata(streamId) + returns (uint128 withdrawnAmount, uint128 protocolFeeAmount); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to withdraw from. | +| `to` | `address` | The address receiving the withdrawn tokens. | + +**Returns** + +| Name | Type | Description | +| ------------------- | --------- | ------------------------------------------------------------------- | +| `withdrawnAmount` | `uint128` | The amount withdrawn to the recipient, denoted in token's decimals. | +| `protocolFeeAmount` | `uint128` | The protocol fee amount, denoted in the token's decimals. | + +### \_coveredDebtOf + +_Calculates the amount of covered debt by the stream balance._ + +```solidity +function _coveredDebtOf(uint256 streamId) internal view returns (uint128); +``` + +### \_ongoingDebtScaledOf + +_Calculates the ongoing debt, as a 18-decimals fixed point number, accrued since last snapshot. Return 0 if the stream +is paused or `block.timestamp` is less than or equal to snapshot time._ + +```solidity +function _ongoingDebtScaledOf(uint256 streamId) internal view returns (uint256); +``` + +### \_refundableAmountOf + +_Calculates the refundable amount._ + +```solidity +function _refundableAmountOf(uint256 streamId) internal view returns (uint128); +``` + +### \_totalDebtOf + +_The total debt is the sum of the snapshot debt and the ongoing debt descaled to token's decimal. This value is +independent of the stream's balance._ + +```solidity +function _totalDebtOf(uint256 streamId) internal view returns (uint256); +``` + +### \_uncoveredDebtOf + +_Calculates the uncovered debt._ + +```solidity +function _uncoveredDebtOf(uint256 streamId) internal view returns (uint256); +``` + +### \_verifyStreamSenderRecipient + +_Checks whether the provided addresses matches stream's sender and recipient._ + +```solidity +function _verifyStreamSenderRecipient(uint256 streamId, address sender, address recipient) internal view; +``` + +### \_adjustRatePerSecond + +_See the documentation for the user-facing functions that call this internal function._ + +```solidity +function _adjustRatePerSecond(uint256 streamId, UD21x18 newRatePerSecond) internal; +``` + +### \_create + +_See the documentation for the user-facing functions that call this internal function._ + +```solidity +function _create( + address sender, + address recipient, + UD21x18 ratePerSecond, + IERC20 token, + bool transferable +) + internal + returns (uint256 streamId); +``` + +### \_deposit + +_See the documentation for the user-facing functions that call this internal function._ + +```solidity +function _deposit(uint256 streamId, uint128 amount) internal; +``` + +### \_depositViaBroker + +_See the documentation for the user-facing functions that call this internal function._ + +```solidity +function _depositViaBroker(uint256 streamId, uint128 totalAmount, Broker memory broker) internal; +``` + +### \_pause + +_See the documentation for the user-facing functions that call this internal function._ + +```solidity +function _pause(uint256 streamId) internal; +``` + +### \_refund + +_See the documentation for the user-facing functions that call this internal function._ + +```solidity +function _refund(uint256 streamId, uint128 amount) internal; +``` + +### \_restart + +_See the documentation for the user-facing functions that call this internal function._ + +```solidity +function _restart(uint256 streamId, UD21x18 ratePerSecond) internal; +``` + +### \_void + +_See the documentation for the user-facing functions that call this internal function._ + +```solidity +function _void(uint256 streamId) internal; +``` + +### \_withdraw + +_See the documentation for the user-facing functions that call this internal function._ + +```solidity +function _withdraw( + uint256 streamId, + address to, + uint128 amount +) + internal + returns (uint128 withdrawnAmount, uint128 protocolFeeAmount); +``` diff --git a/docs/reference/flow/contracts/interfaces/interface.IAdminable.md b/docs/reference/flow/contracts/interfaces/interface.IAdminable.md new file mode 100644 index 00000000..0280bc07 --- /dev/null +++ b/docs/reference/flow/contracts/interfaces/interface.IAdminable.md @@ -0,0 +1,54 @@ +# IAdminable + +[Git Source](https://github.com/sablier-labs/flow/blob/b01cc2daf6493ae792a858d6179facc6250403e2/src/interfaces/IAdminable.sol) + +Contract module that provides a basic access control mechanism, with an admin that can be granted exclusive access to +specific functions. The inheriting contract must set the initial admin in the constructor. + +## Functions + +### admin + +The address of the admin account or contract. + +```solidity +function admin() external view returns (address); +``` + +### transferAdmin + +Transfers the contract admin to a new address. + +Notes: + +- Does not revert if the admin is the same. +- This function can potentially leave the contract without an admin, thereby removing any functionality that is only + available to the admin. Requirements: +- `msg.sender` must be the contract admin. + +```solidity +function transferAdmin(address newAdmin) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ----------------------------- | +| `newAdmin` | `address` | The address of the new admin. | + +## Events + +### TransferAdmin + +Emitted when the admin is transferred. + +```solidity +event TransferAdmin(address indexed oldAdmin, address indexed newAdmin); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ----------------------------- | +| `oldAdmin` | `address` | The address of the old admin. | +| `newAdmin` | `address` | The address of the new admin. | diff --git a/docs/reference/flow/contracts/interfaces/interface.IFlowNFTDescriptor.md b/docs/reference/flow/contracts/interfaces/interface.IFlowNFTDescriptor.md new file mode 100644 index 00000000..1871ecd0 --- /dev/null +++ b/docs/reference/flow/contracts/interfaces/interface.IFlowNFTDescriptor.md @@ -0,0 +1,30 @@ +# IFlowNFTDescriptor + +[Git Source](https://github.com/sablier-labs/flow/blob/b01cc2daf6493ae792a858d6179facc6250403e2/src/interfaces/IFlowNFTDescriptor.sol) + +This contract generates the URI describing the Sablier Flow stream NFTs. + +## Functions + +### tokenURI + +Produces the URI describing a particular stream NFT. + +_Currently it returns the Sablier logo as an SVG. In the future, it will return an NFT SVG._ + +```solidity +function tokenURI(IERC721Metadata sablierFlow, uint256 streamId) external view returns (string memory uri); +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ----------------- | ---------------------------------------------------------- | +| `sablierFlow` | `IERC721Metadata` | The address of the Sablier Flow the stream was created in. | +| `streamId` | `uint256` | The ID of the stream for which to produce a description. | + +**Returns** + +| Name | Type | Description | +| ----- | -------- | ----------------------------------------- | +| `uri` | `string` | The URI of the ERC721-compliant metadata. | diff --git a/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md b/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md new file mode 100644 index 00000000..95964b5d --- /dev/null +++ b/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md @@ -0,0 +1,701 @@ +# ISablierFlow + +[Git Source](https://github.com/sablier-labs/flow/blob/b01cc2daf6493ae792a858d6179facc6250403e2/src/interfaces/ISablierFlow.sol) + +**Inherits:** [ISablierFlowBase](/docs/reference/flow/contracts/interfaces/interface.ISablierFlowBase.md) + +Creates and manages Flow streams with linear streaming functions. + +## Functions + +### coveredDebtOf + +Returns the amount of debt covered by the stream balance, denoted in token's decimals. + +_Reverts if `streamId` references a null stream._ + +```solidity +function coveredDebtOf(uint256 streamId) external view returns (uint128 coveredDebt); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### depletionTimeOf + +Returns the time at which the total debt exceeds stream balance. If the total debt is less than or equal to stream +balance, it returns 0. + +_Reverts if `streamId` references a paused or a null stream._ + +```solidity +function depletionTimeOf(uint256 streamId) external view returns (uint256 depletionTime); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### ongoingDebtScaledOf + +Returns the amount of debt accrued since the snapshot time until now, denoted as a fixed-point number where 1e18 is 1 +token. + +_Reverts if `streamId` references a null stream._ + +```solidity +function ongoingDebtScaledOf(uint256 streamId) external view returns (uint256 ongoingDebtScaled); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### refundableAmountOf + +Returns the amount that the sender can be refunded from the stream, denoted in token's decimals. + +_Reverts if `streamId` references a null stream._ + +```solidity +function refundableAmountOf(uint256 streamId) external view returns (uint128 refundableAmount); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### statusOf + +Returns the stream's status. + +_Reverts if `streamId` references a null stream._ + +```solidity +function statusOf(uint256 streamId) external view returns (Flow.Status status); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### totalDebtOf + +Returns the total amount owed by the sender to the recipient, denoted in token's decimals. + +_Reverts if `streamId` references a null stream._ + +```solidity +function totalDebtOf(uint256 streamId) external view returns (uint256 totalDebt); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### uncoveredDebtOf + +Returns the amount of debt not covered by the stream balance, denoted in token's decimals. + +_Reverts if `streamId` references a null stream._ + +```solidity +function uncoveredDebtOf(uint256 streamId) external view returns (uint256 uncoveredDebt); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### withdrawableAmountOf + +Calculates the amount that the recipient can withdraw from the stream, denoted in token decimals. This is an alias for +`coveredDebtOf`. + +_Reverts if `streamId` references a null stream._ + +```solidity +function withdrawableAmountOf(uint256 streamId) external view returns (uint128 withdrawableAmount); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +**Returns** + +| Name | Type | Description | +| -------------------- | --------- | ------------------------------------------- | +| `withdrawableAmount` | `uint128` | The amount that the recipient can withdraw. | + +### adjustRatePerSecond + +Changes the stream's rate per second. + +Emits [AdjustFlowStream](/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md#adjustflowstream) and +{MetadataUpdate} events. Notes: + +- Performs a debt snapshot. Requirements: +- Must not be delegate called. +- `streamId` must not reference a null or a paused stream. +- `msg.sender` must be the stream's sender. +- `newRatePerSecond` must not equal to the current rate per second. + +```solidity +function adjustRatePerSecond(uint256 streamId, UD21x18 newRatePerSecond) external; +``` + +**Parameters** + +| Name | Type | Description | +| ------------------ | --------- | ------------------------------------------------------------------------------------------ | +| `streamId` | `uint256` | The ID of the stream to adjust. | +| `newRatePerSecond` | `UD21x18` | The new rate per second, denoted as a fixed-point number where 1e18 is 1 token per second. | + +### create + +Creates a new Flow stream by setting the snapshot time to `block.timestamp` and leaving the balance to zero. The stream +is wrapped in an ERC-721 NFT. + +Emits [CreateFlowStream](/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md#createflowstream) event. +Requirements: + +- Must not be delegate called. +- `sender` must not be the zero address. +- `recipient` must not be the zero address. +- The `token`'s decimals must be less than or equal to 18. + +```solidity +function create( + address sender, + address recipient, + UD21x18 ratePerSecond, + IERC20 token, + bool transferable +) + external + returns (uint256 streamId); +``` + +**Parameters** + +| Name | Type | Description | +| --------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------- | +| `sender` | `address` | The address streaming the tokens, which is able to adjust and pause the stream. It doesn't have to be the same as `msg.sender`. | +| `recipient` | `address` | The address receiving the tokens. | +| `ratePerSecond` | `UD21x18` | The amount by which the debt is increasing every second, denoted as a fixed-point number where 1e18 is 1 token per second. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be streamed. | +| `transferable` | `bool` | Boolean indicating if the stream NFT is transferable. | + +**Returns** + +| Name | Type | Description | +| ---------- | --------- | ----------------------------------- | +| `streamId` | `uint256` | The ID of the newly created stream. | + +### createAndDeposit + +Creates a new Flow stream by setting the snapshot time to `block.timestamp` and the balance to `amount`. The stream is +wrapped in an ERC-721 NFT. + +Emits {Transfer}, {CreateFlowStream}, and {DepositFlowStream} events. Notes: + +- Refer to the notes in {deposit}. Requirements: +- Refer to the requirements in {create} and {deposit}. + +```solidity +function createAndDeposit( + address sender, + address recipient, + UD21x18 ratePerSecond, + IERC20 token, + bool transferable, + uint128 amount +) + external + returns (uint256 streamId); +``` + +**Parameters** + +| Name | Type | Description | +| --------------- | --------- | -------------------------------------------------------------------------------------------------------------------------- | +| `sender` | `address` | The address streaming the tokens. It doesn't have to be the same as `msg.sender`. | +| `recipient` | `address` | The address receiving the tokens. | +| `ratePerSecond` | `UD21x18` | The amount by which the debt is increasing every second, denoted as a fixed-point number where 1e18 is 1 token per second. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be streamed. | +| `transferable` | `bool` | Boolean indicating if the stream NFT is transferable. | +| `amount` | `uint128` | The deposit amount, denoted in token's decimals. | + +**Returns** + +| Name | Type | Description | +| ---------- | --------- | ----------------------------------- | +| `streamId` | `uint256` | The ID of the newly created stream. | + +### deposit + +Makes a deposit in a stream. + +Emits {Transfer} and {DepositFlowStream} events. Requirements: + +- Must not be delegate called. +- `streamId` must not reference a null or a voided stream. +- `amount` must be greater than zero. +- `sender` and `recipient` must match the stream's sender and recipient addresses. + +```solidity +function deposit(uint256 streamId, uint128 amount, address sender, address recipient) external; +``` + +**Parameters** + +| Name | Type | Description | +| ----------- | --------- | ------------------------------------------------ | +| `streamId` | `uint256` | The ID of the stream to deposit to. | +| `amount` | `uint128` | The deposit amount, denoted in token's decimals. | +| `sender` | `address` | The stream's sender address. | +| `recipient` | `address` | The stream's recipient address. | + +### depositAndPause + +Deposits tokens in a stream and pauses it. + +Emits {Transfer}, {DepositFlowStream} and {PauseFlowStream} events. Notes: + +- Refer to the notes in {deposit} and {pause}. Requirements: +- Refer to the requirements in {deposit} and {pause}. + +```solidity +function depositAndPause(uint256 streamId, uint128 amount) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | --------------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to deposit to, and then pause. | +| `amount` | `uint128` | The deposit amount, denoted in token's decimals. | + +### depositViaBroker + +Deposits tokens in a stream. + +Emits {Transfer} and {DepositFlowStream} events. Notes: + +- Refer to the notes in {deposit}. Requirements: +- Must not be delegate called. +- `streamId` must not reference a null stream. +- `totalAmount` must be greater than zero. Otherwise it will revert inside {deposit}. +- `broker.account` must not be 0 address. +- `broker.fee` must not be greater than `MAX_FEE`. It can be zero. + +```solidity +function depositViaBroker( + uint256 streamId, + uint128 totalAmount, + address sender, + address recipient, + Broker calldata broker +) + external; +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to deposit on. | +| `totalAmount` | `uint128` | The total amount, including the deposit and any broker fee, denoted in token's decimals. | +| `sender` | `address` | The stream's sender address. | +| `recipient` | `address` | The stream's recipient address. | +| `broker` | `Broker` | Struct encapsulating (i) the address of the broker assisting in creating the stream, and (ii) the percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point percentage. | + +### pause + +Pauses the stream. + +Emits [PauseFlowStream](/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md#pauseflowstream) event. +Notes: + +- It does not set the snapshot time to the current block timestamp. +- It updates the snapshot debt by adding up ongoing debt. +- It sets the rate per second to zero. Requirements: +- Must not be delegate called. +- `streamId` must not reference a null or an already paused stream. +- `msg.sender` must be the stream's sender. + +```solidity +function pause(uint256 streamId) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ------------------------------ | +| `streamId` | `uint256` | The ID of the stream to pause. | + +### refund + +Refunds the provided amount of tokens from the stream to the sender's address. + +Emits {Transfer} and {RefundFromFlowStream} events. Requirements: + +- Must not be delegate called. +- `streamId` must not reference a null stream. +- `msg.sender` must be the sender. +- `amount` must be greater than zero and must not exceed the refundable amount. + +```solidity +function refund(uint256 streamId, uint128 amount) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | -------------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to refund from. | +| `amount` | `uint128` | The amount to refund, denoted in token's decimals. | + +### refundAndPause + +Refunds the provided amount of tokens from the stream to the sender's address. + +Emits {Transfer}, {RefundFromFlowStream} and {PauseFlowStream} events. Notes: + +- Refer to the notes in {pause}. Requirements: +- Refer to the requirements in {refund} and {pause}. + +```solidity +function refundAndPause(uint256 streamId, uint128 amount) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | --------------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to refund from and then pause. | +| `amount` | `uint128` | The amount to refund, denoted in token's decimals. | + +### restart + +Restarts the stream with the provided rate per second. + +Emits [RestartFlowStream](/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md#restartflowstream) event. + +- This function updates stream's `snapshotTime` to the current block timestamp. Notes: +- It sets the snapshot time to the current block timestamp. Requirements: +- Must not be delegate called. +- `streamId` must not reference a null, or a voided stream. +- `msg.sender` must be the stream's sender. +- `ratePerSecond` must be greater than zero. + +```solidity +function restart(uint256 streamId, UD21x18 ratePerSecond) external; +``` + +**Parameters** + +| Name | Type | Description | +| --------------- | --------- | -------------------------------------------------------------------------------------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to restart. | +| `ratePerSecond` | `UD21x18` | The amount by which the debt is increasing every second, denoted as a fixed-point number where 1e18 is 1 token per second. | + +### restartAndDeposit + +Restarts the stream with the provided rate per second, and makes a deposit. + +Emits [RestartFlowStream](/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md#restartflowstream), +{Transfer}, and {DepositFlowStream} events. Notes: + +- Refer to the notes in {restart} and {deposit}. Requirements: +- `amount` must be greater than zero. +- Refer to the requirements in {restart}. + +```solidity +function restartAndDeposit(uint256 streamId, UD21x18 ratePerSecond, uint128 amount) external; +``` + +**Parameters** + +| Name | Type | Description | +| --------------- | --------- | -------------------------------------------------------------------------------------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to restart. | +| `ratePerSecond` | `UD21x18` | The amount by which the debt is increasing every second, denoted as a fixed-point number where 1e18 is 1 token per second. | +| `amount` | `uint128` | The deposit amount, denoted in token's decimals. | + +### void + +Voids a stream. + +Emits [VoidFlowStream](/docs/reference/flow/contracts/interfaces/interface.ISablierFlow.md#voidflowstream) event. Notes: + +- It sets snapshot time to the `block.timestamp` +- Voiding an insolvent stream sets the snapshot debt to the stream's balance making the uncovered debt to become zero. +- Voiding a solvent stream updates the snapshot debt by adding up ongoing debt. +- It sets the rate per second to zero. +- A voided stream cannot be restarted. Requirements: +- Must not be delegate called. +- `streamId` must not reference a null or a voided stream. +- `msg.sender` must either be the stream's sender, recipient or an approved third party. + +```solidity +function void(uint256 streamId) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ----------------------------- | +| `streamId` | `uint256` | The ID of the stream to void. | + +### withdraw + +Withdraws the provided `amount` minus the protocol fee to the provided `to` address. + +Emits {Transfer} and {WithdrawFromFlowStream} events. Notes: + +- It sets the snapshot time to the `block.timestamp` if `amount` is greater than snapshot debt. +- A protocol fee may be charged on the withdrawn amount if the protocol fee is enabled for the streaming token. + Requirements: +- Must not be delegate called. +- `streamId` must not reference a null stream. +- `to` must not be the zero address. +- `to` must be the recipient if `msg.sender` is not the stream's recipient. +- `amount` must be greater than zero and must not exceed the withdrawable amount. + +```solidity +function withdraw( + uint256 streamId, + address to, + uint128 amount +) + external + returns (uint128 withdrawnAmount, uint128 protocolFeeAmount); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to withdraw from. | +| `to` | `address` | The address receiving the withdrawn tokens. | +| `amount` | `uint128` | The amount to withdraw, denoted in token's decimals. | + +**Returns** + +| Name | Type | Description | +| ------------------- | --------- | ---------------------------------------------------------------------------------------------------------------- | +| `withdrawnAmount` | `uint128` | The amount withdrawn to the recipient, denoted in token's decimals. This is input amount minus the protocol fee. | +| `protocolFeeAmount` | `uint128` | The protocol fee amount, denoted in the token's decimals. | + +### withdrawMax + +Withdraws the entire withdrawable amount minus the protocol fee to the provided `to` address. + +Emits {Transfer} and {WithdrawFromFlowStream} events. Notes: + +- Refer to the notes in {withdraw}. Requirements: +- Refer to the requirements in {withdraw}. + +```solidity +function withdrawMax( + uint256 streamId, + address to +) + external + returns (uint128 withdrawnAmount, uint128 protocolFeeAmount); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to withdraw from. | +| `to` | `address` | The address receiving the withdrawn tokens. | + +**Returns** + +| Name | Type | Description | +| ------------------- | --------- | ------------------------------------------------------------------- | +| `withdrawnAmount` | `uint128` | The amount withdrawn to the recipient, denoted in token's decimals. | +| `protocolFeeAmount` | `uint128` | The protocol fee amount, denoted in the token's decimals. | + +## Events + +### AdjustFlowStream + +Emitted when the rate per second is updated by the sender. + +```solidity +event AdjustFlowStream(uint256 indexed streamId, uint256 totalDebt, UD21x18 oldRatePerSecond, UD21x18 newRatePerSecond); +``` + +**Parameters** + +| Name | Type | Description | +| ------------------ | --------- | ------------------------------------------------------------------------------------------ | +| `streamId` | `uint256` | The ID of the stream. | +| `totalDebt` | `uint256` | The total debt at the time of the update, denoted in token's decimals. | +| `oldRatePerSecond` | `UD21x18` | The old rate per second, denoted as a fixed-point number where 1e18 is 1 token per second. | +| `newRatePerSecond` | `UD21x18` | The new rate per second, denoted as a fixed-point number where 1e18 is 1 token per second. | + +### CreateFlowStream + +Emitted when a Flow stream is created. + +```solidity +event CreateFlowStream( + uint256 streamId, + address indexed sender, + address indexed recipient, + UD21x18 ratePerSecond, + IERC20 indexed token, + bool transferable +); +``` + +**Parameters** + +| Name | Type | Description | +| --------------- | --------- | -------------------------------------------------------------------------------------------------------------------------- | +| `streamId` | `uint256` | The ID of the newly created stream. | +| `sender` | `address` | The address streaming the tokens, which is able to adjust and pause the stream. | +| `recipient` | `address` | The address receiving the tokens, as well as the NFT owner. | +| `ratePerSecond` | `UD21x18` | The amount by which the debt is increasing every second, denoted as a fixed-point number where 1e18 is 1 token per second. | +| `token` | `IERC20` | The contract address of the ERC-20 token to be streamed. | +| `transferable` | `bool` | Boolean indicating whether the stream NFT is transferable or not. | + +### DepositFlowStream + +Emitted when a stream is funded. + +```solidity +event DepositFlowStream(uint256 indexed streamId, address indexed funder, uint128 amount); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------------------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream. | +| `funder` | `address` | The address that made the deposit. | +| `amount` | `uint128` | The amount of tokens deposited into the stream, denoted in token's decimals. | + +### PauseFlowStream + +Emitted when a stream is paused by the sender. + +```solidity +event PauseFlowStream(uint256 indexed streamId, address indexed sender, address indexed recipient, uint256 totalDebt); +``` + +**Parameters** + +| Name | Type | Description | +| ----------- | --------- | -------------------------------------------------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream. | +| `sender` | `address` | The stream's sender address. | +| `recipient` | `address` | The stream's recipient address. | +| `totalDebt` | `uint256` | The amount of tokens owed by the sender to the recipient, denoted in token's decimals. | + +### RefundFromFlowStream + +Emitted when a sender is refunded from a stream. + +```solidity +event RefundFromFlowStream(uint256 indexed streamId, address indexed sender, uint128 amount); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ------------------------------------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream. | +| `sender` | `address` | The stream's sender address. | +| `amount` | `uint128` | The amount of tokens refunded to the sender, denoted in token's decimals. | + +### RestartFlowStream + +Emitted when a stream is restarted by the sender. + +```solidity +event RestartFlowStream(uint256 indexed streamId, address indexed sender, UD21x18 ratePerSecond); +``` + +**Parameters** + +| Name | Type | Description | +| --------------- | --------- | -------------------------------------------------------------------------------------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream. | +| `sender` | `address` | The stream's sender address. | +| `ratePerSecond` | `UD21x18` | The amount by which the debt is increasing every second, denoted as a fixed-point number where 1e18 is 1 token per second. | + +### VoidFlowStream + +Emitted when a stream is voided by the sender, recipient or an approved operator. + +```solidity +event VoidFlowStream( + uint256 indexed streamId, + address indexed sender, + address indexed recipient, + address caller, + uint256 newTotalDebt, + uint256 writtenOffDebt +); +``` + +**Parameters** + +| Name | Type | Description | +| ---------------- | --------- | ------------------------------------------------------------------------------------------------ | +| `streamId` | `uint256` | The ID of the stream. | +| `sender` | `address` | The stream's sender address. | +| `recipient` | `address` | The stream's recipient address. | +| `caller` | `address` | The address that performed the void, which can be the sender, recipient or an approved operator. | +| `newTotalDebt` | `uint256` | The new total debt, denoted in token's decimals. | +| `writtenOffDebt` | `uint256` | The amount of debt written off by the caller, denoted in token's decimals. | + +### WithdrawFromFlowStream + +Emitted when tokens are withdrawn from a stream by a recipient or an approved operator. + +```solidity +event WithdrawFromFlowStream( + uint256 indexed streamId, + address indexed to, + IERC20 indexed token, + address caller, + uint128 withdrawAmount, + uint128 protocolFeeAmount +); +``` + +**Parameters** + +| Name | Type | Description | +| ------------------- | --------- | ------------------------------------------------------------------------------------------------------ | +| `streamId` | `uint256` | The ID of the stream. | +| `to` | `address` | The address that received the withdrawn tokens. | +| `token` | `IERC20` | The contract address of the ERC-20 token that was withdrawn. | +| `caller` | `address` | The address that performed the withdrawal, which can be the recipient or an approved operator. | +| `withdrawAmount` | `uint128` | The amount withdrawn to the recipient after subtracting the protocol fee, denoted in token's decimals. | +| `protocolFeeAmount` | `uint128` | The amount of protocol fee deducted from the withdrawn amount, denoted in token's decimals. | diff --git a/docs/reference/flow/contracts/interfaces/interface.ISablierFlowBase.md b/docs/reference/flow/contracts/interfaces/interface.ISablierFlowBase.md new file mode 100644 index 00000000..573105f9 --- /dev/null +++ b/docs/reference/flow/contracts/interfaces/interface.ISablierFlowBase.md @@ -0,0 +1,441 @@ +# ISablierFlowBase + +[Git Source](https://github.com/sablier-labs/flow/blob/b01cc2daf6493ae792a858d6179facc6250403e2/src/interfaces/ISablierFlowBase.sol) + +**Inherits:** IERC4906, IERC721Metadata, [IAdminable](/docs/reference/flow/contracts/interfaces/interface.IAdminable.md) + +Base contract that includes state variables (storage and constants) for the +[SablierFlow](/docs/reference/flow/contracts/contract.SablierFlow.md) contract, their respective getters, helpful +modifiers, and helper functions. + +_This contract also includes admin control functions._ + +## Functions + +### MAX_FEE + +Retrieves the maximum fee that can be charged by the broker and the protocol, denoted as a fixed-point percentage where +1e18 is 100%. + +_This value is hard coded as a constant._ + +```solidity +function MAX_FEE() external view returns (UD60x18 fee); +``` + +### aggregateBalance + +Retrieves the sum of balances of all streams. + +```solidity +function aggregateBalance(IERC20 token) external view returns (uint256); +``` + +**Parameters** + +| Name | Type | Description | +| ------- | -------- | ------------------------------- | +| `token` | `IERC20` | The ERC-20 token for the query. | + +### getBalance + +Retrieves the balance of the stream, i.e. the total deposited amounts subtracted by the total withdrawn amounts, denoted +in token's decimals. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getBalance(uint256 streamId) external view returns (uint128 balance); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getRatePerSecond + +Retrieves the rate per second of the stream, denoted as a fixed-point number where 1e18 is 1 token per second. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getRatePerSecond(uint256 streamId) external view returns (UD21x18 ratePerSecond); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to make the query for. | + +### getRecipient + +Retrieves the stream's recipient. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getRecipient(uint256 streamId) external view returns (address recipient); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getSender + +Retrieves the stream's sender. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getSender(uint256 streamId) external view returns (address sender); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getSnapshotDebtScaled + +Retrieves the snapshot debt of the stream, denoted as a fixed-point number where 1e18 is 1 token. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getSnapshotDebtScaled(uint256 streamId) external view returns (uint256 snapshotDebtScaled); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getSnapshotTime + +Retrieves the snapshot time of the stream, which is a Unix timestamp. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getSnapshotTime(uint256 streamId) external view returns (uint40 snapshotTime); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to make the query for. | + +### getStream + +Retrieves the stream entity. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getStream(uint256 streamId) external view returns (Flow.Stream memory stream); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### getToken + +Retrieves the token of the stream. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getToken(uint256 streamId) external view returns (IERC20 token); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to make the query for. | + +### getTokenDecimals + +Retrieves the token decimals of the stream. + +_Reverts if `streamId` references a null stream._ + +```solidity +function getTokenDecimals(uint256 streamId) external view returns (uint8 tokenDecimals); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ------------------------------------------- | +| `streamId` | `uint256` | The ID of the stream to make the query for. | + +### isPaused + +Returns whether a stream is paused. + +_Reverts if `streamId` references a null stream._ + +```solidity +function isPaused(uint256 streamId) external view returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### isStream + +Retrieves a flag indicating whether the stream exists. + +_Does not revert if `streamId` references a null stream._ + +```solidity +function isStream(uint256 streamId) external view returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### isTransferable + +Retrieves a flag indicating whether the stream NFT is transferable. + +_Reverts if `streamId` references a null stream._ + +```solidity +function isTransferable(uint256 streamId) external view returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### isVoided + +Retrieves a flag indicating whether the stream is voided. + +_Reverts if `streamId` references a null stream._ + +```solidity +function isVoided(uint256 streamId) external view returns (bool result); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | --------- | ---------------------------- | +| `streamId` | `uint256` | The stream ID for the query. | + +### nextStreamId + +Counter for stream ids. + +```solidity +function nextStreamId() external view returns (uint256); +``` + +**Returns** + +| Name | Type | Description | +| -------- | --------- | ------------------- | +| `` | `uint256` | The next stream ID. | + +### nftDescriptor + +Contract that generates the non-fungible token URI. + +```solidity +function nftDescriptor() external view returns (IFlowNFTDescriptor); +``` + +### protocolFee + +Protocol fee for the provided ERC-20 token, denoted as a fixed-point percentage where 1e18 is 100%. + +```solidity +function protocolFee(IERC20 token) external view returns (UD60x18); +``` + +### protocolRevenue + +Protocol revenue accrued for the provided ERC-20 token, denoted in token's decimals. + +```solidity +function protocolRevenue(IERC20 token) external view returns (uint128); +``` + +### collectProtocolRevenue + +Collect the protocol revenue accrued for the provided ERC-20 token. + +Emits +[CollectProtocolRevenue](/docs/reference/flow/contracts/interfaces/interface.ISablierFlowBase.md#collectprotocolrevenue) +event. Requirements: + +- `msg.sender` must be the contract admin. +- The accrued protocol revenue must be greater than zero. + +```solidity +function collectProtocolRevenue(IERC20 token, address to) external; +``` + +**Parameters** + +| Name | Type | Description | +| ------- | --------- | ----------------------------------------------------------------------------- | +| `token` | `IERC20` | The contract address of the ERC-20 token for which to claim protocol revenue. | +| `to` | `address` | The address to send the protocol revenue. | + +### recover + +Recover the surplus amount of tokens. + +Emits [Recover](/docs/reference/flow/contracts/interfaces/interface.ISablierFlowBase.md#recover) event. Notes: + +- The surplus amount is defined as the difference between the total balance of the contract for the provided ERC-20 + token and the sum of balances of all streams created using the same ERC-20 token. Requirements: +- `msg.sender` must be the contract admin. +- The surplus amount must be greater than zero. + +```solidity +function recover(IERC20 token, address to) external; +``` + +**Parameters** + +| Name | Type | Description | +| ------- | --------- | -------------------------------------------------------- | +| `token` | `IERC20` | The contract address of the ERC-20 token to recover for. | +| `to` | `address` | The address to send the surplus amount. | + +### setNFTDescriptor + +Sets a new NFT descriptor contract, which produces the URI describing the Sablier stream NFTs. + +Emits [SetNFTDescriptor](/docs/reference/flow/contracts/interfaces/interface.ISablierFlowBase.md#setnftdescriptor) and +{BatchMetadataUpdate} events. Notes: + +- Does not revert if the NFT descriptor is the same. Requirements: +- `msg.sender` must be the contract admin. + +```solidity +function setNFTDescriptor(IFlowNFTDescriptor newNFTDescriptor) external; +``` + +**Parameters** + +| Name | Type | Description | +| ------------------ | -------------------- | ----------------------------------------------- | +| `newNFTDescriptor` | `IFlowNFTDescriptor` | The address of the new NFT descriptor contract. | + +### setProtocolFee + +Sets a new protocol fee that will be charged on all the withdrawals from streams created with the provided ERC-20 token. + +Emits [SetProtocolFee](/docs/reference/flow/contracts/interfaces/interface.ISablierFlowBase.md#setprotocolfee) and +{BatchMetadataUpdate} events. Notes: + +- Does not revert if the fee is the same. +- It can be zero. Requirements: +- `msg.sender` must be the contract admin. +- `newProtocolFee` must not be greater than `MAX_FEE`. + +```solidity +function setProtocolFee(IERC20 token, UD60x18 newProtocolFee) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---------------- | --------- | ----------------------------------------------------------------------------- | +| `token` | `IERC20` | The contract address of the ERC-20 token to update the fee for. | +| `newProtocolFee` | `UD60x18` | The new protocol fee, denoted as a fixed-point percentage where 1e18 is 100%. | + +## Events + +### CollectProtocolRevenue + +Emitted when the contract admin collects protocol revenue accrued. + +```solidity +event CollectProtocolRevenue(address indexed admin, IERC20 indexed token, address to, uint128 revenue); +``` + +**Parameters** + +| Name | Type | Description | +| --------- | --------- | ---------------------------------------------------------------------------- | +| `admin` | `address` | The address of the contract admin. | +| `token` | `IERC20` | The address of the ERC-20 token the protocol revenue has been collected for. | +| `to` | `address` | The address the protocol revenue has been sent to. | +| `revenue` | `uint128` | The amount of protocol revenue collected. | + +### Recover + +Emitted when the contract admin recovers the surplus amount of token. + +```solidity +event Recover(address indexed admin, IERC20 indexed token, address to, uint256 surplus); +``` + +**Parameters** + +| Name | Type | Description | +| --------- | --------- | -------------------------------------------------------------------------- | +| `admin` | `address` | The address of the contract admin. | +| `token` | `IERC20` | The address of the ERC-20 token the surplus amount has been recovered for. | +| `to` | `address` | The address the surplus amount has been sent to. | +| `surplus` | `uint256` | The amount of surplus tokens recovered. | + +### SetNFTDescriptor + +Emitted when the contract admin sets a new NFT descriptor contract. + +```solidity +event SetNFTDescriptor(address indexed admin, IFlowNFTDescriptor oldNFTDescriptor, IFlowNFTDescriptor newNFTDescriptor); +``` + +**Parameters** + +| Name | Type | Description | +| ------------------ | -------------------- | ----------------------------------------------- | +| `admin` | `address` | The address of the contract admin. | +| `oldNFTDescriptor` | `IFlowNFTDescriptor` | The address of the old NFT descriptor contract. | +| `newNFTDescriptor` | `IFlowNFTDescriptor` | The address of the new NFT descriptor contract. | + +### SetProtocolFee + +Emitted when the contract admin sets a new protocol fee for the provided ERC-20 token. + +```solidity +event SetProtocolFee(address indexed admin, IERC20 indexed token, UD60x18 oldProtocolFee, UD60x18 newProtocolFee); +``` + +**Parameters** + +| Name | Type | Description | +| ---------------- | --------- | ---------------------------------------------------------------------- | +| `admin` | `address` | The address of the contract admin. | +| `token` | `IERC20` | The address of the ERC-20 token the new protocol fee has been set for. | +| `oldProtocolFee` | `UD60x18` | The old protocol fee, denoted as a fixed-point percentage. | +| `newProtocolFee` | `UD60x18` | The new protocol fee, denoted as a fixed-point percentage. | diff --git a/docs/reference/flow/contracts/libraries/library.Errors.md b/docs/reference/flow/contracts/libraries/library.Errors.md new file mode 100644 index 00000000..f07967d5 --- /dev/null +++ b/docs/reference/flow/contracts/libraries/library.Errors.md @@ -0,0 +1,223 @@ +# Errors + +[Git Source](https://github.com/sablier-labs/flow/blob/b01cc2daf6493ae792a858d6179facc6250403e2/src/libraries/Errors.sol) + +Library with custom errors used across the Flow contract. + +## Errors + +### BatchError + +Thrown when an unexpected error occurs during a batch call. + +```solidity +error BatchError(bytes errorData); +``` + +### CallerNotAdmin + +Thrown when `msg.sender` is not the admin. + +```solidity +error CallerNotAdmin(address admin, address caller); +``` + +### DelegateCall + +Thrown when trying to delegate call to a function that disallows delegate calls. + +```solidity +error DelegateCall(); +``` + +### SablierFlow_BrokerAddressZero + +Thrown when trying to create a stream with a broker recipient address as zero. + +```solidity +error SablierFlow_BrokerAddressZero(); +``` + +### SablierFlow_BrokerFeeTooHigh + +Thrown when trying to create a stream with a broker fee more than the allowed. + +```solidity +error SablierFlow_BrokerFeeTooHigh(UD60x18 brokerFee, UD60x18 maxFee); +``` + +### SablierFlow_DepositAmountZero + +Thrown when trying to create a stream with a zero deposit amount. + +```solidity +error SablierFlow_DepositAmountZero(uint256 streamId); +``` + +### SablierFlow_InvalidTokenDecimals + +Thrown when trying to create a stream with an token with no decimals. + +```solidity +error SablierFlow_InvalidTokenDecimals(address token); +``` + +### SablierFlow_InvalidCalculation + +Thrown when an unexpected error occurs during the calculation of an amount. + +```solidity +error SablierFlow_InvalidCalculation(uint256 streamId, uint128 availableAmount, uint128 amount); +``` + +### SablierFlow_NotStreamRecipient + +Thrown when the recipient address does not match the stream's recipient. + +```solidity +error SablierFlow_NotStreamRecipient(address recipient, address streamRecipient); +``` + +### SablierFlow_NotStreamSender + +Thrown when the sender address does not match the stream's sender. + +```solidity +error SablierFlow_NotStreamSender(address sender, address streamSender); +``` + +### SablierFlow_Null + +Thrown when the ID references a null stream. + +```solidity +error SablierFlow_Null(uint256 streamId); +``` + +### SablierFlow_Overdraw + +Thrown when trying to withdraw an amount greater than the withdrawable amount. + +```solidity +error SablierFlow_Overdraw(uint256 streamId, uint128 amount, uint128 withdrawableAmount); +``` + +### SablierFlow_RatePerSecondNotDifferent + +Thrown when trying to change the rate per second with the same rate per second. + +```solidity +error SablierFlow_RatePerSecondNotDifferent(uint256 streamId, UD21x18 ratePerSecond); +``` + +### SablierFlow_RefundAmountZero + +Thrown when trying to refund zero tokens from a stream. + +```solidity +error SablierFlow_RefundAmountZero(uint256 streamId); +``` + +### SablierFlow_RefundOverflow + +Thrown when trying to refund an amount greater than the refundable amount. + +```solidity +error SablierFlow_RefundOverflow(uint256 streamId, uint128 refundAmount, uint128 refundableAmount); +``` + +### SablierFlow_SenderZeroAddress + +Thrown when trying to create a stream with the sender as the zero address. + +```solidity +error SablierFlow_SenderZeroAddress(); +``` + +### SablierFlow_StreamPaused + +Thrown when trying to perform an action with a paused stream. + +```solidity +error SablierFlow_StreamPaused(uint256 streamId); +``` + +### SablierFlow_StreamNotPaused + +Thrown when trying to restart a stream that is not paused. + +```solidity +error SablierFlow_StreamNotPaused(uint256 streamId); +``` + +### SablierFlow_StreamVoided + +Thrown when trying to perform an action with a voided stream. + +```solidity +error SablierFlow_StreamVoided(uint256 streamId); +``` + +### SablierFlow_Unauthorized + +Thrown when `msg.sender` lacks authorization to perform an action. + +```solidity +error SablierFlow_Unauthorized(uint256 streamId, address caller); +``` + +### SablierFlow_WithdrawalAddressNotRecipient + +Thrown when trying to withdraw to an address other than the recipient's. + +```solidity +error SablierFlow_WithdrawalAddressNotRecipient(uint256 streamId, address caller, address to); +``` + +### SablierFlow_WithdrawAmountZero + +Thrown when trying to withdraw zero tokens from a stream. + +```solidity +error SablierFlow_WithdrawAmountZero(uint256 streamId); +``` + +### SablierFlow_WithdrawToZeroAddress + +Thrown when trying to withdraw to the zero address. + +```solidity +error SablierFlow_WithdrawToZeroAddress(uint256 streamId); +``` + +### SablierFlowBase_NoProtocolRevenue + +Thrown when trying to claim protocol revenue when the accrued amount is zero. + +```solidity +error SablierFlowBase_NoProtocolRevenue(address token); +``` + +### SablierFlowBase_NotTransferable + +Thrown when trying to transfer Stream NFT when transferability is disabled. + +```solidity +error SablierFlowBase_NotTransferable(uint256 streamId); +``` + +### SablierFlowBase_ProtocolFeeTooHigh + +Thrown when trying to set protocol fee more than the allowed. + +```solidity +error SablierFlowBase_ProtocolFeeTooHigh(UD60x18 newProtocolFee, UD60x18 maxFee); +``` + +### SablierFlowBase_SurplusZero + +Thrown when trying to recover for a token with zero surplus. + +```solidity +error SablierFlowBase_SurplusZero(address token); +``` diff --git a/docs/reference/flow/contracts/libraries/library.Helpers.md b/docs/reference/flow/contracts/libraries/library.Helpers.md new file mode 100644 index 00000000..929f6bbc --- /dev/null +++ b/docs/reference/flow/contracts/libraries/library.Helpers.md @@ -0,0 +1,52 @@ +# Helpers + +[Git Source](https://github.com/sablier-labs/flow/blob/b01cc2daf6493ae792a858d6179facc6250403e2/src/libraries/Helpers.sol) + +Library with helper functions in [SablierFlow](/docs/reference/flow/contracts/contract.SablierFlow.md) contract. + +## Functions + +### calculateAmountsFromFee + +_Calculate the fee amount and the net amount after subtracting the fee, based on the `fee` percentage._ + +```solidity +function calculateAmountsFromFee( + uint128 totalAmount, + UD60x18 fee +) + internal + pure + returns (uint128 feeAmount, uint128 netAmount); +``` + +### checkAndCalculateBrokerFee + +_Checks the `Broker` parameter, and then calculates the broker fee amount and the deposit amount from the total amount._ + +```solidity +function checkAndCalculateBrokerFee( + uint128 totalAmount, + Broker memory broker, + UD60x18 maxFee +) + internal + pure + returns (uint128 brokerFeeAmount, uint128 depositAmount); +``` + +### descaleAmount + +_Descales the provided `amount` from 18 decimals fixed-point number to token's decimals number._ + +```solidity +function descaleAmount(uint256 amount, uint8 decimals) internal pure returns (uint256); +``` + +### scaleAmount + +_Scales the provided `amount` from token's decimals number to 18 decimals fixed-point number._ + +```solidity +function scaleAmount(uint256 amount, uint8 decimals) internal pure returns (uint256); +``` diff --git a/docs/reference/flow/contracts/types/library.Flow.md b/docs/reference/flow/contracts/types/library.Flow.md new file mode 100644 index 00000000..377e66ab --- /dev/null +++ b/docs/reference/flow/contracts/types/library.Flow.md @@ -0,0 +1,74 @@ +# Flow + +[Git Source](https://github.com/sablier-labs/flow/blob/b01cc2daf6493ae792a858d6179facc6250403e2/src/types/DataTypes.sol) + +## Structs + +### Stream + +Struct representing Flow streams. + +_The fields are arranged like this to save gas via tight variable packing._ + +```solidity +struct Stream { + uint128 balance; + UD21x18 ratePerSecond; + address sender; + uint40 snapshotTime; + bool isStream; + bool isTransferable; + bool isVoided; + IERC20 token; + uint8 tokenDecimals; + uint256 snapshotDebtScaled; +} +``` + +**Properties** + +| Name | Type | Description | +| -------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `balance` | `uint128` | The amount of tokens that are currently available in the stream, denoted in token's decimals. This is the sum of deposited amounts minus the sum of withdrawn amounts. | +| `ratePerSecond` | `UD21x18` | The payment rate per second, denoted as a fixed-point number where 1e18 is 1 token per second. For example, to stream 1000 tokens per week, this parameter would have the value $(1000 * 10^18) / (7 days in seconds)$. | +| `sender` | `address` | The address streaming the tokens, with the ability to pause the stream. | +| `snapshotTime` | `uint40` | The Unix timestamp used for the ongoing debt calculation. | +| `isStream` | `bool` | Boolean indicating if the struct entity exists. | +| `isTransferable` | `bool` | Boolean indicating if the stream NFT is transferable. | +| `isVoided` | `bool` | Boolean indicating if the stream is voided. Voiding any stream is non-reversible and it cannot be restarted. Voiding an insolvent stream sets its uncovered debt to zero. | +| `token` | `IERC20` | The contract address of the ERC-20 token to stream. | +| `tokenDecimals` | `uint8` | The decimals of the ERC-20 token to stream. | +| `snapshotDebtScaled` | `uint256` | The amount of tokens that the sender owed to the recipient at snapshot time, denoted as a 18-decimals fixed-point number. This, along with the ongoing debt, can be used to calculate the total debt at any given point in time. | + +## Enums + +### Status + +Enum representing the different statuses of a stream. + +Explanations for the two types of streams: + +1. Streaming: when the total debt is increasing. +2. Paused: when the total debt is not increasing. + +**Notes:** + +- STREAMING_SOLVENT Streaming stream when there is no uncovered debt. + +- STREAMING_INSOLVENT Streaming stream when there is uncovered debt. + +- PAUSED_SOLVENT Paused stream when there is no uncovered debt. + +- PAUSED_INSOLVENT Paused stream when there is uncovered debt. + +- VOIDED Paused stream with no uncovered debt and it cannot be restarted. + +```solidity +enum Status { + STREAMING_SOLVENT, + STREAMING_INSOLVENT, + PAUSED_SOLVENT, + PAUSED_INSOLVENT, + VOIDED +} +``` diff --git a/docs/reference/flow/contracts/types/struct.Broker.md b/docs/reference/flow/contracts/types/struct.Broker.md new file mode 100644 index 00000000..c52613d5 --- /dev/null +++ b/docs/reference/flow/contracts/types/struct.Broker.md @@ -0,0 +1,19 @@ +# Broker + +[Git Source](https://github.com/sablier-labs/flow/blob/b01cc2daf6493ae792a858d6179facc6250403e2/src/types/DataTypes.sol) + +Struct encapsulating the broker parameters. + +```solidity +struct Broker { + address account; + UD60x18 fee; +} +``` + +**Properties** + +| Name | Type | Description | +| --------- | --------- | -------------------------------------------------------------------------------------------------------------------- | +| `account` | `address` | The address receiving the broker's fee. | +| `fee` | `UD60x18` | The broker's percentage fee charged from the deposit amount, denoted as a fixed-point percentage where 1e18 is 100%. | diff --git a/docs/reference/lockup/01-diagrams.md b/docs/reference/lockup/01-diagrams.md index 9a604914..9abfe19c 100644 --- a/docs/reference/lockup/01-diagrams.md +++ b/docs/reference/lockup/01-diagrams.md @@ -139,9 +139,9 @@ flowchart LR; C --> S1; ``` -## Airstream Flow +## Airstream Campaign -A typical campaign creation flow looks like the following: +A typical Airstream campaign creation flow looks like the following: ```mermaid flowchart LR diff --git a/docs/reference/lockup/04-access-control.md b/docs/reference/lockup/04-access-control.md index b6d070dc..a8e60d37 100644 --- a/docs/reference/lockup/04-access-control.md +++ b/docs/reference/lockup/04-access-control.md @@ -4,7 +4,7 @@ sidebar_position: 4 title: "Access Control" --- -With the exception of the [admin functions](/docs/concepts/08-governance.md), all functionalities in Lockup can only be +With the exception of the [admin functions](/concepts/governance#lockup), all functionalities in Lockup can only be triggered by users. The Protocol Admin has no control over any stream or any part of the protocol. This article will provide a comprehensive overview of the actions that can be performed on streams once they are @@ -13,7 +13,7 @@ created, as well as the corresponding user permissions for each action. :::note Every stream has a sender and a recipient. Recipients can approve third parties to take actions on their behalf. An -'unknown' caller is any address outside of sender and recipient. +'public' caller is any address outside of sender and recipient. ::: @@ -21,16 +21,16 @@ Every stream has a sender and a recipient. Recipients can approve third parties The table below offers a quick overview of the access control for each action that can be performed on a stream. -| Action | Sender | Recipient / Approved third party | Unknown Caller | -| ----------------------- | :----: | :------------------------------: | :------------: | -| Burn NFT | ❌ | ✅ | ❌ | -| Cancel | ✅ | ❌ | ❌ | -| Cancel Multiple | ✅ | ❌ | ❌ | -| Renounce | ✅ | ❌ | ❌ | -| Transfer NFT | ❌ | ✅ | ❌ | -| Withdraw to recipient | ✅ | ✅ | ✅ | -| Withdraw to any address | ❌ | ✅ | ❌ | -| Withdraw Multiple | ✅ | ✅ | ✅ | +| Action | Sender | Recipient / Approved third party | Public | +| ----------------------- | :----: | :------------------------------: | :----: | +| Burn NFT | ❌ | ✅ | ❌ | +| Cancel | ✅ | ❌ | ❌ | +| Cancel Multiple | ✅ | ❌ | ❌ | +| Renounce | ✅ | ❌ | ❌ | +| Transfer NFT | ❌ | ✅ | ❌ | +| Withdraw to any address | ❌ | ✅ | ❌ | +| Withdraw to recipient | ✅ | ✅ | ✅ | +| Withdraw Multiple | ✅ | ✅ | ✅ | ## Burn NFT @@ -104,14 +104,14 @@ Anybody can withdraw assets from multiple streams to the recipients of each stre ```mermaid flowchart LR; - unknown((Unknown caller)); + public((Public)); recipient((Recipient)); operator((Operator)); sender((Sender)); streams[(Stream)]; toAddress[Recipient address]; - unknown -- withdrawMultiple --> streams; + public -- withdrawMultiple --> streams; sender -- withdrawMultiple --->streams; recipient -- withdrawMultiple --->streams recipient -- approve -->operator; @@ -143,14 +143,14 @@ party. ```mermaid flowchart LR; - unknown((Unknown caller)); + public((Public caller)); recipient((Recipient)); operator((Operator)); sender((Sender)); stream[(Stream)]; toAddress[Recipient address]; - unknown -- withdraw ----> stream; + public -- withdraw ----> stream; sender -- withdraw --->stream; recipient -- withdraw -->stream; recipient -- approve -->operator; diff --git a/docs/reference/lockup/v1/_category_.json b/docs/reference/lockup/legacy/_category_.json similarity index 61% rename from docs/reference/lockup/v1/_category_.json rename to docs/reference/lockup/legacy/_category_.json index d1a6ab38..93067a67 100644 --- a/docs/reference/lockup/v1/_category_.json +++ b/docs/reference/lockup/legacy/_category_.json @@ -1,5 +1,5 @@ { "collapsed": true, - "label": "V1 Protocol", + "label": "Legacy V1", "position": 5 } diff --git a/docs/reference/lockup/v1/contracts/_category_.json b/docs/reference/lockup/legacy/contracts/_category_.json similarity index 100% rename from docs/reference/lockup/v1/contracts/_category_.json rename to docs/reference/lockup/legacy/contracts/_category_.json diff --git a/docs/reference/lockup/v1/contracts/constant-functions.md b/docs/reference/lockup/legacy/contracts/constant-functions.md similarity index 100% rename from docs/reference/lockup/v1/contracts/constant-functions.md rename to docs/reference/lockup/legacy/contracts/constant-functions.md diff --git a/docs/reference/lockup/v1/contracts/non-constant-functions.md b/docs/reference/lockup/legacy/contracts/non-constant-functions.md similarity index 100% rename from docs/reference/lockup/v1/contracts/non-constant-functions.md rename to docs/reference/lockup/legacy/contracts/non-constant-functions.md diff --git a/docs/reference/lockup/v1/guides/_category_.json b/docs/reference/lockup/legacy/guides/_category_.json similarity index 100% rename from docs/reference/lockup/v1/guides/_category_.json rename to docs/reference/lockup/legacy/guides/_category_.json diff --git a/docs/reference/lockup/v1/guides/codebase.mdx b/docs/reference/lockup/legacy/guides/codebase.mdx similarity index 94% rename from docs/reference/lockup/v1/guides/codebase.mdx rename to docs/reference/lockup/legacy/guides/codebase.mdx index b7902d07..e43904a9 100644 --- a/docs/reference/lockup/v1/guides/codebase.mdx +++ b/docs/reference/lockup/legacy/guides/codebase.mdx @@ -8,7 +8,7 @@ import LinkPreview from "../../../../../src/components/LinkPreview"; ## Repository -The Lockup V1 Protocol is hosted on GitHub and the source code for each contract is verified on Etherscan. +The Legacy V1 Protocol is hosted on GitHub and the source code for each contract is verified on Etherscan. $contract + +contract=$reference/contract.FlowNFTDescriptor.md +echo "$(echo -en '---\nsidebar_position: 2\n---\n'; cat $contract)" > $contract + +# ---------------------------------------------------------------------------- # +# Final Steps # +# ---------------------------------------------------------------------------- # + +# Format the docs with Prettier +bun prettier --log-level silent --write $reference + +# Remove the italic asterisks added by `forge doc`: https://github.com/foundry-rs/foundry/issues/4540 +sd --string-mode "\*" "" $(find $reference -type f -name "*.md") + +# Re-format the docs with Prettier +bun prettier --log-level silent --write $reference diff --git a/scripts/autogen.sh b/scripts/autogen-lockup.sh similarity index 100% rename from scripts/autogen.sh rename to scripts/autogen-lockup.sh diff --git a/static/img/flow-nft.svg b/static/img/flow-nft.svg new file mode 100644 index 00000000..524e67bf --- /dev/null +++ b/static/img/flow-nft.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/img/nft-gallery.png b/static/img/lockup-gallery.png similarity index 100% rename from static/img/nft-gallery.png rename to static/img/lockup-gallery.png diff --git a/static/img/nft.svg b/static/img/lockup-nft.svg similarity index 100% rename from static/img/nft.svg rename to static/img/lockup-nft.svg