From f01ea9cf4e3e079d9c399e3e6acc3dfa2ab66f83 Mon Sep 17 00:00:00 2001 From: maxdesalle Date: Thu, 30 Mar 2023 08:23:55 -0400 Subject: [PATCH] feat: add graphs, faq, redirects, and v1 docs --- docs/concepts/protocol/02-stream-types.md | 18 +- docs/contracts/v1/contracts/_category_.json | 5 + .../v1/contracts/constant-functions.md | 141 +++++++++++++++ .../v1/contracts/non-constant-functions.md | 166 ++++++++++++++++++ docs/contracts/v1/guides/_category_.json | 5 + docs/contracts/v1/guides/chains.md | 57 ++++++ docs/contracts/v1/guides/codebase.mdx | 41 +++++ docs/contracts/v1/guides/gas-costs.md | 15 ++ docs/contracts/v1/guides/getting-started.md | 21 +++ docs/contracts/v1/guides/streams.md | 22 +++ docs/faq/index.md | 58 +++++- docusaurus.config.js | 33 ++++ package.json | 1 + pnpm-lock.yaml | 54 ++++++ 14 files changed, 622 insertions(+), 15 deletions(-) create mode 100644 docs/contracts/v1/contracts/_category_.json create mode 100644 docs/contracts/v1/contracts/constant-functions.md create mode 100644 docs/contracts/v1/contracts/non-constant-functions.md create mode 100644 docs/contracts/v1/guides/_category_.json create mode 100644 docs/contracts/v1/guides/chains.md create mode 100644 docs/contracts/v1/guides/codebase.mdx create mode 100644 docs/contracts/v1/guides/gas-costs.md create mode 100644 docs/contracts/v1/guides/getting-started.md create mode 100644 docs/contracts/v1/guides/streams.md diff --git a/docs/concepts/protocol/02-stream-types.md b/docs/concepts/protocol/02-stream-types.md index 6127a8ef..d568b4f4 100644 --- a/docs/concepts/protocol/02-stream-types.md +++ b/docs/concepts/protocol/02-stream-types.md @@ -7,7 +7,7 @@ title: "Types of Streams" ## Linear Streams Linear streams are the simplest type of stream. They follow a straight line that goes up and to the right on a graph, -which corresponds to the identity function $f(x) = x$. +which corresponds to the identity function $f(x) = x$ ([see on Desmos](https://www.desmos.com/calculator/fqajxzhbx8)). With linear streams, the payment rate remains constant, meaning that the same fraction of the deposit amount is streamed to the recipient every second. This provides greater predictability and is very easy to understand because of how @@ -17,7 +17,7 @@ intuitive it is. Imagine a diagonal line going up and to the right – that's ho It is possible to add a **cliff** to a linear stream, which sets a cut-off point for releasing assets. Prior to the cliff ,the recipient cannot withdraw any assets, although the stream continues to accrue them. After the cliff, the -stream operates like a typical linear stream. +stream operates like a typical linear stream ([see on Desmos](https://www.desmos.com/calculator/mk7422ivwp)). Cliffs a great fit if you are looking to vest ERC-20 assets, as it allows you to, for example, have a 1-year cliff, and then 3 additional years of linear streaming. If the stream is meant for an employee, you can make it cancellable so that @@ -45,17 +45,17 @@ the $f(x) = log(x)$ function. ### Exponential Streams Part of the Sablier Dynamic offering, **exponential streams allow for streams where the recipients receive more and more -tokens as time moves forward**. +tokens as time moves forward** ([see on Desmos](https://www.desmos.com/calculator/xgzguiata7)). -For our math junkies out there, it's somewhat similar to the $f(x) = e^x - 1$ function. This is especially a great fit -if you are looking to airdrop tokens to your community, as instead of receiving the tokens all at once (no streaming) or -in a linear fashion (linear stream), your community members will receive the majority of the tokens towards the end of -the stream. **This incentivizes long-term behavior and a constructive attitude**. +This is especially a great fit if you are looking to airdrop tokens to your community, as instead of receiving the +tokens all at once (no streaming) or in a linear fashion (linear stream), your community members will receive the +majority of the tokens towards the end of the stream. **This incentivizes long-term behavior and a constructive +attitude**. ### Exponential Cliff Streams Part of the Sablier Dynamic offering, the Exponential Cliff streaming curve is a mix between the Cliff Stream and the -Exponential streaming curves. +Exponential streaming curves ([see on Desmos](https://www.desmos.com/calculator/rzoygqlixt)). **The stream starts with a cliff** (however long you want), a specific amount is then instantly unlocked and streamed over to the recipient, and from the rest of the streaming curve is an exponential. @@ -67,7 +67,7 @@ stream ends. ### Traditional Unlock Streams Part of the Sablier Dynamic offering, the Traditional Unlock streaming curve is literally just that: a traditional -vesting contract with periodic unlocks. +vesting contract with periodic unlocks ([see on Desmos](https://www.desmos.com/calculator/wf6uogrwei)). Every month, quarter or year (or an other time setting) depending on how you configure it, a specific amount will be unlocked and sent over to the recipient. diff --git a/docs/contracts/v1/contracts/_category_.json b/docs/contracts/v1/contracts/_category_.json new file mode 100644 index 00000000..c3ee869b --- /dev/null +++ b/docs/contracts/v1/contracts/_category_.json @@ -0,0 +1,5 @@ +{ + "collapsed": true, + "label": "Contracts", + "position": 1 +} diff --git a/docs/contracts/v1/contracts/constant-functions.md b/docs/contracts/v1/contracts/constant-functions.md new file mode 100644 index 00000000..0fa8f92e --- /dev/null +++ b/docs/contracts/v1/contracts/constant-functions.md @@ -0,0 +1,141 @@ +--- +id: constant-functions +title: Constant Functions +sidebar_position: 3 +--- + +## Get Stream + +Returns all properties for the provided stream id. + +```solidity +function getStream(uint256 streamId) view returns (address sender, address recipient, address tokenAddress, uint256 balance, uint256 startTime, uint256 stopTime, uint256 remainingBalance, uint256 ratePerSecond) +``` + +- `streamId`: The id of the stream to query. +- `RETURN` + - `sender`: The address that created and funded the stream. + - `recipient`: The address towards which the tokens are streamed. + - `tokenAddress`: The address of the ERC-20 token used as streaming currency. + - `startTime`: The unix timestamp for when the stream starts, in seconds. + - `stopTime`: The unix timestamp for when the stream stops, in seconds. + - `remainingBalance`: How much tokens are still allocated to this stream, in the smart contract. + - `ratePerSecond`: How much tokens are allocated from the sender to the recipient every second. + +### Solidity + +```solidity +Sablier sablier = Sablier(0xabcd...); +uint256 streamId = 42; +(uint256 sender, uint256 recipient, uint256 deposit, address tokenAddress, uint256 startTime, uint256 stopTime, uint256 remainingBalance, uint256 ratePerSecond) = sablier.getStream(streamId); +``` + +### Ethers.js + +```javascript +const sablier = new ethers.Contract(0xabcd..., sablierABI, signerOrProvider); +const streamId = 42; +const stream = await sablier.getStream(streamId);‌ +``` + +--- + +## Balance Of + +Returns the real-time balance of an account with regards to a specific stream. + +```solidity +function balanceOf(uint256 streamId, address who) view returns (uint256) +``` + +- `streamId`: The id of the stream for which to query the balance. +- `who`: The address for which to query the balance. +- `RETURN`: The available balance in units of the underlying ERC-20 token. + +:::info + +This is the amount of tokens that can be withdrawn from the contract, not the total amount of tokens streamed. If the +contract streamed 1,000 tokens to Bob, but Bob withdrew 400 tokens already, this function will return 600 and not 1,000. + +::: + +### Solidity + +```solidity +Sablier sablier = Sablier(0xabcd...); +uint256 streamId = 42; +uint256 senderAddress = 0xcdef...; +uint256 balance = sablier.balanceOf(streamId, senderAddress); +``` + +### Javascript + +```javascript +const sablier = new ethers.Contract(0xabcd..., sablierABI, signerOrProvider); +const streamId = 42; +const senderAddress = 0xcdef...; +const balance = await sablier.balanceOf(streamId, senderAddress); +``` + +--- + +## Delta of + +Returns either the difference between now and the start time of the stream OR between the stop time and the start time +of the stream, whichever is smaller. However, if the clock did not hit the start time of the stream, the value returned +is 0 instead. + +```solidity +function deltaOf(uint256 streamId) view returns (uint256)‌ +``` + +`streamId`: The id of the stream for which to query the delta. `RETURN`: The time delta in seconds. + +### Solidity + +```solidity +Sablier sablier = Sablier(0xabcd...); +uint256 streamId = 42; +uint256 delta = sablier.deltaOf(streamId);‌ +``` + +### Ethers.js + +```javascript +const sablier = new ethers.Contract(0xabcd..., sablierABI, signerOrProvider); +const streamId = 42; +const delta = await sablier.deltaOf(streamId); +``` + +--- + +## Error Table + +The table below lists all possible reasons for reverting a contract call that creates, withdraws from or cancels a +stream. The "Id" column is just a counter used in this table - the smart contract does not yield error codes, just +strings. + +| Number | Error | Reason | +| ------ | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| 1 | stream does not exist | The provided stream id does not point to a valid stream | +| 2 | caller is not the sender or the recipient of the stream | The contract call originates from an unauthorized third-party | +| 3 | SafeERC20: low-level call failed | Possibly insufficient allowance, but not necessarily so | +| 4 | stream to the zero address | Attempt to stream tokens to the [zero address](https://etherscan.io/address/0x0000000000000000000000000000000000000000) | +| 5 | stream to the contract itself | Attempt to stream tokens to the Sablier contract | +| 6 | stream to the caller | Happens when the caller attempts to stream tokens to herself | +| 7 | deposit is zero | Attempt to stream 0 tokens | +| 8 | start time before block.timestamp | Tokens cannot be streamed retroactively | +| 9 | stop time before the start time | Negative streaming is not allowed | +| 10 | deposit smaller than time delta | The deposit, measured in units of the token, is smaller than the time delta | +| 11 | deposit not multiple of time delta | The deposit has a non-zero remainder when divided by the time delta | +| 12 | amount is zero | Attempt to withdraw 0 tokens | +| 13 | amount exceeds the available balance | Attempt to withdraw more tokens than the available balance | +| 14 | recipient balance calculation error | Happens only when streaming an absurdly high number of tokens (close to 2^256) | + +:::info + +The contract call could revert with [no reason](https://vmexceptionwhileprocessingtransactionrevert.com/) provided. In +this case, you probably did not approve the Sablier contract to spend your token balance, although this is not +necessarily the case. Ping us on [Discord](https://discord.gg/bSwRCwWRsT) if you get stuck. + +::: diff --git a/docs/contracts/v1/contracts/non-constant-functions.md b/docs/contracts/v1/contracts/non-constant-functions.md new file mode 100644 index 00000000..2e8faea1 --- /dev/null +++ b/docs/contracts/v1/contracts/non-constant-functions.md @@ -0,0 +1,166 @@ +--- +id: non-constant-functions +title: Non-Constant Functions +sidebar_position: 2 +--- + +## Create stream + +The create stream function transfers the tokens into the Sablier smart contract, stamping the rules of the stream into +the blockchain. As soon as the chain clock hits the start time of the stream, a small portion of tokens starts getting +"transferred" from the sender to the recipient once every second. + +We used scare quotes because what actually happens is not a transfer, but rather an abstract allocation of funds. Every +second, the in-contract allowance of the sender decreases. while the recipient's allocation increases, even if the +tokens are not transferred to the recipient. Actually transferring the tokens would be excessively expensive in terms of +gas costs. + +```solidity +function createStream(address recipient, uint256 deposit, address tokenAddress, uint256 startTime, uint256 stopTime) returns (uint256) +``` + +- `msg.sender`: The account who funds the stream, and pays the recipient in real-time. +- `recipient`: The account toward which the tokens will be streamed. +- `deposit`: The amount of tokens to be streamed, in units of the streaming currency. +- `tokenAddress`: The address of the ERC-20 token to use as streaming currency. +- `startTime`: The unix timestamp for when the stream starts, in seconds. +- `stopTime`: The unix timestamp for when the stream stops, in seconds. +- `RETURN`: The stream's id as an unsigned integer on success, reverts on error. + +:::caution + +Before creating a stream, users must first [approve](https://eips.ethereum.org/EIPS/eip-20#approve) the Sablier contract +to access their token balance. + +::: + +:::warning + +The transaction must be processed by the Ethereum blockchain before the start time of the stream, or otherwise the +contract will revert with a "start time before block.timestamp" message. + +::: + +### The Deposit Gotcha + +The deposit must be a multiple of the difference between the stop time and the start time, or otherwise the contract +reverts with a "deposit not multiple of time delta" message. In practice, this means that you may not able to always use +exact amounts like 3,000. You may have to divide the fixed deposit by the time delta and subtract the remainder from the +initial number. Thus you may have to stream a value that is very, very close to the fixed deposit, but not quite it. + +For example, if: + +- The token has 18 decimals +- The time delta is 2592000 (30 days) + +You will have to stream 2999999999999998944000 instead of 3000000000000000000000. The former divides evenly by 2592000, +but the latter doesn't. + +### Solidity + +```solidity +Sablier sablier = Sablier(0xabcd...); // get a handle for the Sablier contract +address recipient = 0xcdef...; +uint256 deposit = 2999999999999998944000; // almost 3,000, but not quite +uint256 startTime = block.timestamp + 3600; // 1 hour from now +uint256 stopTime = block.timestamp + 2592000 + 3600; // 30 days and 1 hour from now + +Erc20 token = Erc20(0xcafe...); // get a handle for the token contract +token.approve(address(sablier), deposit); // approve the transfer + +// the stream id is needed later to withdraw from or cancel the stream +uint256 streamId = sablier.createStream(recipient, deposit, address(token), startTime, stopTime); +``` + +### Ethers.js + +```javascript +const sablier = new ethers.Contract(0xabcd..., sablierABI, signerOrProvider); // get a handle for the Sablier contract +const recipient = 0xcdef...; +const deposit = "2999999999999998944000"; // almost 3,000, but not quite +const now = Math.round(new Date().getTime() / 1000); // get seconds since unix epoch +const startTime = now + 3600; // 1 hour from now +const stopTime = now + 2592000 + 3600; // 30 days and 1 hour from now + +const token = new ethers.Contract(0xcafe..., erc20ABI, signerOrProvider); // get a handle for the token contract +const approveTx = await token.approve(sablier.address, deposit); // approve the transfer +await approveTx.wait(); + +const createStreamTx = await sablier.createStream(recipient, deposit, token.address, startTime, stopTime); +await createStreamTx.wait(); +``` + +--- + +## Withdraw from Stream + +The withdraw from stream function transfers an amount of tokens from the Sablier contract to the recipient's account. +The withdrawn amount must be less than or equal to the available [balance](./constant-functions#balance-of). This +function can only be called by the sender or the recipient of the stream, not any third-party. + +```solidity +function withdrawFromStream(uint256 streamId, uint256 amount) returns (bool); +``` + +- `streamId`: The id of the stream to withdraw tokens from. +- `amount`: The amount of tokens to withdraw. +- `RETURN`: True on success, reverts on error. + +:::info + +To be able to call this function, you have to wait until the clock goes past the start time of the stream. + +::: + +### Solidity + +```solidity +Sablier sablier = Sablier(0xabcd...); +uint256 streamId = 42; +uint256 amount = 100; +require(sablier.withdrawFromStream(streamId, amount), "something went wrong");‌ +``` + +### Ethers.js + +```javascript +‌const sablier = new ethers.Contract(0xabcd..., sablierABI, signerOrProvider); +const streamId = 42; +const amount = 100; +const withdrawFromStreamTx = await sablier.withdrawFromStream(streamId, amount); +await withdrawFromStreamTx.wait(); +``` + +--- + +## Cancel Stream + +The cancel stream function revokes a previously created stream and returns the tokens back to the sender and/or the +recipient. If the chain clock did not hit the start time, all the tokens is returned to the sender. If the chain clock +did go past the start time, but not past the stop time, the sender and the recipient each get a pro-rata amount. +Finally, if the chain clock went past the stop time, all the tokens goes the recipient. This function can be called only +by the sender. + +```solidity +function cancelStream(uint256 streamId) returns (bool); +``` + +- `streamId`: The id of the stream to cancel. +- `RETURN`: True on success, reverts on error. + +### Solidity + +```solidity +Sablier sablier = Sablier(0xabcd...); +uint256 streamId = 42; +require(sablier.cancelStream(streamId), "something went wrong"); +``` + +### Ethers.js + +```javascript +const sablier = new ethers.Contract(0xabcd..., sablierABI, signerOrProvider); +const streamId = 42; +const cancelStreamTx = await sablier.cancelStream(streamId); +await cancelStreamTx.wait(); +``` diff --git a/docs/contracts/v1/guides/_category_.json b/docs/contracts/v1/guides/_category_.json new file mode 100644 index 00000000..537bd97b --- /dev/null +++ b/docs/contracts/v1/guides/_category_.json @@ -0,0 +1,5 @@ +{ + "collapsed": true, + "label": "Guides", + "position": 2 +} diff --git a/docs/contracts/v1/guides/chains.md b/docs/contracts/v1/guides/chains.md new file mode 100644 index 00000000..c1932fa4 --- /dev/null +++ b/docs/contracts/v1/guides/chains.md @@ -0,0 +1,57 @@ +--- +id: chains +title: Chains +sidebar_position: 3 +--- + +Depending on what [EVM](https://ethereum.org/en/developers/docs/evm/) chains you want to use Sablier on, you will need +to use a different contract address. Sablier runs on top of one single master contract that manages all streams. + +## Official deployments + +Official deployments are deployments made by the Sablier team and supported in the +[official user interface](https://pay.sablier.finance). + +### Sablier v1.1 + +| Contract | Chain | Address | +| ----------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------ | +| Sablier.sol | Ethereum Mainnet | [0xCD18eAa163733Da39c232722cBC4E8940b1D8888](https://etherscan.io/address/0xCD18eAa163733Da39c232722cBC4E8940b1D8888) | +| Sablier.sol | Arbitrum One | [0xaDB944B478818d95659067E70D2e5Fc43Fa3eDe9](https://arbiscan.io/address/0xaDB944B478818d95659067E70D2e5Fc43Fa3eDe9) | +| Sablier.sol | Avalanche | [0x73f503fad13203C87889c3D5c567550b2d41D7a4](https://snowtrace.io/address/0x73f503fad13203C87889c3D5c567550b2d41D7a4) | +| Sablier.sol | BSC Mainnet | [0x05BC7f5fb7F248d44d38703e5C921A8c16825161](https://bscscan.com/address/0x05BC7f5fb7F248d44d38703e5C921A8c16825161) | +| Sablier.sol | Optimism | [0x6C5927c0679e6d857E87367bb635decbcB20F31c](https://optimistic.etherscan.io/address/0x6C5927c0679e6d857E87367bb635decbcB20F31c) | +| Sablier.sol | Polygon Mainnet | [0xAC18EAB6592F5fF6F9aCf5E0DCE0Df8E49124C06](https://polygonscan.com/address/0xAC18EAB6592F5fF6F9aCf5E0DCE0Df8E49124C06) | +| Sablier.sol | Ronin | [0xDe9dCc27aa1552d591Fc9B9c21881feE43BD8118](https://explorer.roninchain.com/address/ronin:de9dcc27aa1552d591fc9b9c21881fee43bd8118) | +| Sablier.sol | Goerli | [0xFc7E3a3073F88B0f249151192812209117C2014b](https://goerli.etherscan.io/address/0xFc7E3a3073F88B0f249151192812209117C2014b) | + +### Sablier v1.0 + +_This is an outdated deployment_. + +| Contract | Chain | Address | +| ----------- | ---------------- | --------------------------------------------------------------------------------------------------------------------- | +| Payroll.sol | Ethereum Mainnet | [0xbd6a40Bb904aEa5a49c59050B5395f7484A4203d](https://etherscan.io/address/0xbd6a40Bb904aEa5a49c59050B5395f7484A4203d) | +| Sablier.sol | Ethereum Mainnet | [0xA4fc358455Febe425536fd1878bE67FfDBDEC59a](https://etherscan.io/address/0xA4fc358455Febe425536fd1878bE67FfDBDEC59a) | + +## Unofficial deployments + +Unofficial deployments are deployments made by external teams and not supported in the +[official user interface](https://pay.sablier.finance). + +| Chain | Address | Deployer | +| ----- | ---------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | +| IoTeX | [0x93Efd750a7F589f9FE26408a91e15587a88c4E78](https://iotexscout.io/address/0x93Efd750a7F589f9FE26408a91e15587a88c4E78) | [IoTeX team](https://twitter.com/iotex_io) | + +## Testnet Tokens + +If you want to use the Sablier interfaces on a testnet, you need to get some testnet DAI first. To do this, you have to +go to the Etherscan page of the associated token, tap the "Write Contract" tab, connect your Ethereum wallet and call +the `mint` method. + +Note that the testnet token has 18 decimals, so you may want to use a +[unit converter](https://tools.deth.net/token-unit-conversion). + +| Chain | Network | Ethereum address | +| ---------- | ------- | ---------------------------------------------------------------------------------------------------------------------------- | +| TestnetDAI | Goerli | [0x97cb342Cf2F6EcF48c1285Fb8668f5a4237BF862](https://goerli.etherscan.io/address/0x97cb342Cf2F6EcF48c1285Fb8668f5a4237BF862) | diff --git a/docs/contracts/v1/guides/codebase.mdx b/docs/contracts/v1/guides/codebase.mdx new file mode 100644 index 00000000..6757e287 --- /dev/null +++ b/docs/contracts/v1/guides/codebase.mdx @@ -0,0 +1,41 @@ +--- +id: codebase +title: Codebase +sidebar_position: 2 +--- + +import LinkPreview from "../../../../src/components/LinkPreview"; + +## Repository + +The Sablier protocol is hosted on GitHub and the source code for each contract is verified on Etherscan. + + + +## ABIs + +Depending on the web3 library you're working with, you may need to get hold of the Sablier ABIs (application binary +interfaces). The ABI acts as an interface between two program modules, one of which is the smart contract and the other +the Ethereum virtual machine code. + +There are two ways to obtain it:‌ + +1. Copy `Sablier.json` from [sablierhq/sablier-abis](https://github.com/sablierhq/sablier-abis). +2. Clone [sablierhq/sablier](https://github.com/sablierhq/sablier) and compile the contract yourself. + +Here's an example for how to do step 2 with yarn and truffle: + +```bash +$ git clone git@github.com/sablierhq/sablier.git +$ cd ./sablier +$ yarn bootstrap +$ cd ./packages/protocol +$ truffle compile +``` + +The `Sablier.json` artifact should be generated in the relative `build/contracts` folder.‌ diff --git a/docs/contracts/v1/guides/gas-costs.md b/docs/contracts/v1/guides/gas-costs.md new file mode 100644 index 00000000..7b020736 --- /dev/null +++ b/docs/contracts/v1/guides/gas-costs.md @@ -0,0 +1,15 @@ +--- +id: gas-costs +title: Gas Costs +sidebar_position: 5 +--- + +The gas usage of the Sablier protocol is not deterministic and varies by user. Calls to third-party contracts, such as +[ERC-20](https://eips.ethereum.org/EIPS/eip-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: + +| Action | Typical Gas Cost | +| -------------------- | ---------------- | +| Create stream | ~240K | +| Withdraw from stream | ~80K | +| Cancel stream | ~90K | diff --git a/docs/contracts/v1/guides/getting-started.md b/docs/contracts/v1/guides/getting-started.md new file mode 100644 index 00000000..87506309 --- /dev/null +++ b/docs/contracts/v1/guides/getting-started.md @@ -0,0 +1,21 @@ +--- +id: getting-started +title: Getting Started +sidebar_position: 1 +--- + +This is a technical account on how to integrate Sablier into your own application. If you have any questions along the +way, please join the #dev channel in the [Sablier Discord server](https://discord.gg/bSwRCwWRsT); our team, and members +of the community, look forward to helping you. + +What we will cover: + +- Smart contract architecture and ABI. +- Networks and typical gas costs. +- How to create, withdraw from and cancel streams. + +:::info + +If you're looking for a high-level non-technical overview, you may want to read the [FAQ](/faq) first. + +::: diff --git a/docs/contracts/v1/guides/streams.md b/docs/contracts/v1/guides/streams.md new file mode 100644 index 00000000..889a6962 --- /dev/null +++ b/docs/contracts/v1/guides/streams.md @@ -0,0 +1,22 @@ +--- +id: streams +title: Streams +sidebar_position: 4 +--- + +Every interaction with the Sablier protocol is in relation to a specific "token stream". This is how we refer to a +real-time payment. + +A token stream has six properties: + +1. Sender. +2. Recipient. +3. Fixed deposit amount. +4. ERC-20 token used as streaming currency. +5. Start time +6. Stop Time + +## Example + +Imagine a 3,000 DAI salary paid by Alice to Bob over the whole month of January. The start time would be Jan 1 and the +stop time Feb 1. Every second makes Bob richer; on Jan 10, he would have earned approximately 1,000 DAI. diff --git a/docs/faq/index.md b/docs/faq/index.md index c9981718..79784d0f 100644 --- a/docs/faq/index.md +++ b/docs/faq/index.md @@ -53,11 +53,20 @@ A real-time payment, made up of six properties: You can access Sablier through the following web interfaces: -- [app.sablier.finance](https://pay.sablier.finance) (official interface) +- [app.sablier.com](https://pay.sablier.com) (official interface) - [safe.global](https://safe.global/) (multi-signature wallet) We're working with various projects in the DeFi ecosystem to make Sablier accessible through more and more interfaces. +## What is the difference between the Sablier protocol, interface, and Sablier Labs? + +- **The Sablier Protocol:** A collection of persistent, non-upgradeable smart contracts that together create a protocol + which facilitates streaming of ERC-20 assets on Ethereum and other EVM blockchains. +- **The Sablier Interface:** A web interface that allows for easy interaction with the Sablier protocol. The interface + is only one of many ways to interact with the Sablier protocol. +- **Sablier Labs:** the company that developed the Sablier protocol, the user interfaces associated with it, and the + documentation website you are reading now. + ## What is real-time finance? A term coined by us to emphasize the wide-ranging use cases for the Sablier protocol. We like to think about work as an @@ -78,12 +87,54 @@ Imagine Alice wants to make a 3,000 DAI payment to Bob during the whole month of 4. If at any point during January Alice wishes to recover her tokens, she can cancel the stream and recover what has not been streamed yet. +## What are the use cases for streaming? + +There countless way to use the Sablier protocol, but right now the most frequent one are +[vesting](/concepts/use-cases#vesting), [payroll](/concepts/use-cases#payroll) and +[airdrops](/concepts/use-cases#airdrops). + +[This](https://twitter.com/SablierHQ/status/1205533344886411264) discussion on Twitter might also be of interest. + +## Are there different types of streams? + +Yes, there are. We separate streams in two groups: linear streams and dynamic streams. On our interface, you will find +the linear stream and linear stream with cliff being part of the former group, and the traditional unlock stream, +exponential stream and exponential stream with cliff being part of the latter group. + +You can learn more about the various types of streams [here](/concepts/protocol/stream-types). + ## Is the Sablier protocol safe? The security of the Sablier protocol is our outmost priority. Our team, accompanied by external auditors and consultants, has invested considerable effort to create a protocol that is safe and reliable. All contract code is publicly verifiable in our [GitHub repository](https://github.com/sablierhq/v2-core). +## Does the Sablier protocol charge fees? + +Like any user interface providing the ability to interact with the contracts, the protocol also has the ability to +charge fees. Right now, these fees are set to 0% for all ERC-20 tokens. The official Sablier user interface doesn't +charge any fees either. There is an existing fee of 0.05%, however, applied to all flash loans made using the protocol. + +You can learn more about the fee system [here](/concepts/protocol/fees). + +## What are flash loans? + +Flash loans are a unique feature of blockchain systems that allows users to borrow a large amount of cryptocurrency +(typically ERC-20 assets) without providing any collateral. These loans are designed be taken and repaid within the same +blockchain transaction. + +The concept behind flash loans is made possible by the atomic nature of blockchain transactions. In Ethereum, +transactions are either executed entirely or not at all. This allows users to borrow funds, perform actions (like +arbitrage, liquidations, or self-liquidations), and repay the loan along with a small fee, all in a single transaction. +If the transaction fails at any point or if the loan is not repaid, the entire transaction is reverted, ensuring that +the lending protocol doesn't lose any funds. + +Flash loans gained popularity with the emergence of DeFi platforms such as Aave and dYdX, which pioneered these +services. They have enabled developers and traders to get instant access to liquidity. + +You can learn more about how flash loans work in the context of Sablier +[here](/concepts/protocol/flash-loans#flash-loans-in-sablier). + ## Is the Sablier protocol transparent? As transparent as it can be. Verify the smart contracts by yourself on [GitHub](https://github.com/sablierhq/v2-core/) @@ -154,11 +205,6 @@ No. Once a stream is created, it is set in stone on the blockchain. In a future version of the Sablier protocol, we may add the option to refill an active stream and even extend it. -## What can Sablier be used for? - -We came up with a few ideas in [this discussion on Twitter](https://twitter.com/SablierHQ/status/1205533344886411264), -but the sky is the limit. - ## Who can use Sablier? Anyone in the world with an Internet connection and an Ethereum wallet. diff --git a/docusaurus.config.js b/docusaurus.config.js index 8ce3779c..97d24a7a 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -33,6 +33,39 @@ const config = { }), ], ], + plugins: [ + [ + "@docusaurus/plugin-client-redirects", + { + redirects: [ + { + to: "/faq", + from: "/protocol/faq/basics", + }, + { + to: "/contracts/v1/guides/getting-started", + from: "/protocol/guides/getting-started", + }, + { + to: "/contracts/v1/guides/chains", + from: "/protocol/guides/chains", + }, + { + to: "/concepts/what-is-sablier", + from: "/protocol/introduction", + }, + { + to: "/contracts/v1/guides/chains", + from: "/protocol/guides/chains", + }, + { + to: "/api/subgraphs/overview", + from: "/protocol/subgraphs/endpoints", + }, + ], + }, + ], + ], stylesheets: [ { crossorigin: "anonymous", diff --git a/package.json b/package.json index 06ac5b29..5f11d62d 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "dependencies": { "@algolia/client-search": "^4.16.0", "@docusaurus/core": "^2.4.0", + "@docusaurus/plugin-client-redirects": "^2.4.0", "@docusaurus/preset-classic": "^2.4.0", "@docusaurus/theme-classic": "^2.4.0", "@docusaurus/theme-mermaid": "^2.4.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8947e54e..aeaee06e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,6 +7,9 @@ dependencies: '@docusaurus/core': specifier: ^2.4.0 version: 2.4.0(@docusaurus/types@2.4.0)(esbuild@0.16.3)(eslint@8.36.0)(react-dom@17.0.2)(react@17.0.2)(typescript@4.9.5) + '@docusaurus/plugin-client-redirects': + specifier: ^2.4.0 + version: 2.4.0(@docusaurus/types@2.4.0)(esbuild@0.16.3)(eslint@8.36.0)(react-dom@17.0.2)(react@17.0.2)(typescript@4.9.5) '@docusaurus/preset-classic': specifier: ^2.4.0 version: 2.4.0(@algolia/client-search@4.16.0)(esbuild@0.16.3)(eslint@8.36.0)(react-dom@17.0.2)(react@17.0.2)(typescript@4.9.5) @@ -568,6 +571,7 @@ packages: /@babel/parser@7.21.3: resolution: {integrity: sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==} engines: {node: '>=6.0.0'} + hasBin: true dependencies: '@babel/types': 7.21.3 @@ -1624,6 +1628,7 @@ packages: /@docusaurus/core@2.4.0(@docusaurus/types@2.4.0)(esbuild@0.16.3)(eslint@8.36.0)(react-dom@17.0.2)(react@17.0.2)(typescript@4.9.5): resolution: {integrity: sha512-J55/WEoIpRcLf3afO5POHPguVZosKmJEQWKBL+K7TAnfuE7i+Y0NPLlkKtnWCehagGsgTqClfQEexH/UT4kELA==} engines: {node: '>=16.14'} + hasBin: true peerDependencies: react: ^16.8.4 || ^17.0.0 react-dom: ^16.8.4 || ^17.0.0 @@ -1833,6 +1838,43 @@ packages: - webpack-cli dev: false + /@docusaurus/plugin-client-redirects@2.4.0(@docusaurus/types@2.4.0)(esbuild@0.16.3)(eslint@8.36.0)(react-dom@17.0.2)(react@17.0.2)(typescript@4.9.5): + resolution: {integrity: sha512-HsS+Dc2ZLWhfpjYJ5LIrOB/XfXZcElcC7o1iA4yIVtiFz+LHhwP863fhqbwSJ1c6tNDOYBH3HwbskHrc/PIn7Q==} + engines: {node: '>=16.14'} + peerDependencies: + react: ^16.8.4 || ^17.0.0 + react-dom: ^16.8.4 || ^17.0.0 + dependencies: + '@docusaurus/core': 2.4.0(@docusaurus/types@2.4.0)(esbuild@0.16.3)(eslint@8.36.0)(react-dom@17.0.2)(react@17.0.2)(typescript@4.9.5) + '@docusaurus/logger': 2.4.0 + '@docusaurus/utils': 2.4.0(@docusaurus/types@2.4.0)(esbuild@0.16.3) + '@docusaurus/utils-common': 2.4.0(@docusaurus/types@2.4.0) + '@docusaurus/utils-validation': 2.4.0(@docusaurus/types@2.4.0)(esbuild@0.16.3) + eta: 2.0.1 + fs-extra: 10.1.0 + lodash: 4.17.21 + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) + tslib: 2.5.0 + transitivePeerDependencies: + - '@docusaurus/types' + - '@parcel/css' + - '@swc/core' + - '@swc/css' + - bufferutil + - csso + - debug + - esbuild + - eslint + - lightningcss + - supports-color + - typescript + - uglify-js + - utf-8-validate + - vue-template-compiler + - webpack-cli + dev: false + /@docusaurus/plugin-content-blog@2.4.0(esbuild@0.16.3)(eslint@8.36.0)(react-dom@17.0.2)(react@17.0.2)(typescript@4.9.5): resolution: {integrity: sha512-YwkAkVUxtxoBAIj/MCb4ohN0SCtHBs4AS75jMhPpf67qf3j+U/4n33cELq7567hwyZ6fMz2GPJcVmctzlGGThQ==} engines: {node: '>=16.14'} @@ -4623,6 +4665,7 @@ packages: /autoprefixer@10.4.14(postcss@8.4.21): resolution: {integrity: sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==} engines: {node: ^10 || ^12 || >=14} + hasBin: true peerDependencies: postcss: ^8.1.0 dependencies: @@ -6839,6 +6882,7 @@ packages: /esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} + hasBin: true /esquery@1.5.0: resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} @@ -8517,6 +8561,7 @@ packages: /js-yaml@3.14.1: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true dependencies: argparse: 1.0.10 esprima: 4.0.1 @@ -8529,6 +8574,7 @@ packages: /jsesc@0.5.0: resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} + hasBin: true /jsesc@2.5.2: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} @@ -8570,6 +8616,7 @@ packages: /json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} + hasBin: true /jsonc-parser@3.2.0: resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} @@ -9390,6 +9437,7 @@ packages: /mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} + hasBin: true /mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} @@ -11411,6 +11459,7 @@ packages: /semver@5.7.1: resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} + hasBin: true dev: false /semver@6.1.1: @@ -12140,6 +12189,7 @@ packages: /ts-node@10.9.1(@types/node@14.18.33)(typescript@4.3.4): resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} + hasBin: true peerDependencies: '@swc/core': '>=1.2.50' '@swc/wasm': '>=1.2.50' @@ -12478,6 +12528,7 @@ packages: /update-browserslist-db@1.0.10(browserslist@4.21.5): resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==} + hasBin: true peerDependencies: browserslist: '>= 4.21.0' dependencies: @@ -12845,6 +12896,7 @@ packages: /webpack-dev-server@4.13.1(webpack@5.76.3): resolution: {integrity: sha512-5tWg00bnWbYgkN+pd5yISQKDejRBYGEw15RaEEslH+zdbNDxxaZvEAO2WulaSaFKb5n3YG8JXsGaDsut1D0xdA==} engines: {node: '>= 12.13.0'} + hasBin: true peerDependencies: webpack: ^4.37.0 || ^5.0.0 webpack-cli: '*' @@ -12906,6 +12958,7 @@ packages: /webpack@5.76.1(esbuild@0.16.3): resolution: {integrity: sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==} engines: {node: '>=10.13.0'} + hasBin: true peerDependencies: webpack-cli: '*' peerDependenciesMeta: @@ -12944,6 +12997,7 @@ packages: /webpack@5.76.3(esbuild@0.16.3): resolution: {integrity: sha512-18Qv7uGPU8b2vqGeEEObnfICyw2g39CHlDEK4I7NK13LOur1d0HGmGNKGT58Eluwddpn3oEejwvBPoP4M7/KSA==} engines: {node: '>=10.13.0'} + hasBin: true peerDependencies: webpack-cli: '*' peerDependenciesMeta: