### Install Dependencies and Build Lockup Contracts Source: https://docs.sablier.com/guides/custom-deployments These commands are used to install project dependencies using `bun` and then build the optimized contracts for deployment. This step ensures all necessary packages are installed and the contracts are compiled. ```bash bun install --frozen-lockfile ``` ```bash bun run build-optimized ``` -------------------------------- ### Initialize and Install Project Template (Bash) Source: https://docs.sablier.com/guides/flow/examples/local-environment Initializes a new project using the Sablier integration template and installs dependencies using Bun. This sets up a basic project structure with pre-configured imports. ```bash $ mkdir sablier-integration-template $ cd sablier-integration-template $ forge init --template sablier-labs/sablier-integration-template $ bun install ``` -------------------------------- ### Install Dependencies and Build Contracts Source: https://docs.sablier.com/guides/custom-deployments Installs project dependencies using Bun and builds the optimized version of the contracts. This step is crucial before deployment. ```bash bun install --frozen-lockfile bun run build-optimized ``` -------------------------------- ### Install Sablier npm Package Source: https://docs.sablier.com/guides/airdrops/examples/local-environment Installs the Sablier Node.js package using Bun, which downloads the Sablier contracts and their dependencies into the node_modules directory. ```bash $ bun add @sablier/sablier ``` -------------------------------- ### Basic Warp Server Setup in Rust Source: https://github.com/seanmonstar/warp This snippet demonstrates the fundamental setup of a Warp web server in Rust. It defines a simple route for '/hello/{name}' that responds with a personalized greeting. It requires the 'warp' and 'tokio' crates, with 'tokio' enabled for asynchronous operations and 'warp' with the 'server' feature. ```rust use warp::Filter; #[tokio::main] async fn main() { // GET /hello/warp => 200 OK with body "Hello, warp!" let hello = warp::path!("hello" / String) .map(|name| format!("Hello, {}!", name)); warp::serve(hello) .run(([127, 0, 0, 1], 3030)) .await; } ``` -------------------------------- ### Full Code Example: Batch Stream Creator Source: https://docs.sablier.com/guides/lockup/examples/batch-create-streams/batch-lockup-dynamic Provides the complete Solidity code for the `BatchLDStreamCreator` contract, demonstrating the entire process of defining stream parameters, populating a batch, and invoking the batch creation function. This serves as a comprehensive example for implementing dynamic timestamped streams in batches. ```solidity pragma solidity ^0.8.19; import { BatchLockup, LockupDynamic } from "@sablier/core/contracts/Lockup.sol"; import { Broker } from "@sablier/core/contracts/Broker.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ud2x18, ud60x18 } from "@sablier/core/contracts/Math.sol"; contract BatchLDStreamCreator { address public immutable BATCH_LOCKUP; address public immutable LOCKUP_DYNAMIC; IERC20 public immutable DAI; constructor(address _batchLockup, address _lockupDynamic, address _dai) { BATCH_LOCKUP = _batchLockup; LOCKUP_DYNAMIC = _lockupDynamic; DAI = IERC20(_dai); } function createStreams(uint256 batchSize, uint128 perStreamAmount) external returns (uint64[] memory streamIds) { // Declare the first stream in the batch BatchLockup.CreateWithTimestampsLD memory stream0; stream0.sender = address(0xABCD); // The sender to stream the tokens, he will be able to cancel the stream stream0.recipient = address(0xCAFE); // The recipient of the streamed tokens stream0.totalAmount = perStreamAmount; // The total amount of each stream, inclusive of all fees stream0.cancelable = true; // Whether the stream will be cancelable or not stream0.transferable = false; // Whether the recipient can transfer the NFT or not stream0.startTime = uint40(block.timestamp); // Set the start time to block timestamp // Declare some dummy segments stream0.segments = new LockupDynamic.Segment[](2); stream0.segments[0] = LockupDynamic.Segment({ amount: uint128(perStreamAmount / 2), exponent: ud2x18(0.25e18), timestamp: uint40(block.timestamp + 1 weeks) }); stream0.segments[1] = ( LockupDynamic.Segment({ amount: uint128(perStreamAmount - stream0.segments[0].amount), exponent: ud2x18(2.71e18), timestamp: uint40(block.timestamp + 24 weeks) }) ); stream0.broker = Broker(address(0), ud60x18(0)); // Optional parameter left undefined // Declare the second stream in the batch BatchLockup.CreateWithTimestampsLD memory stream1; stream1.sender = address(0xABCD); // The sender to stream the tokens, he will be able to cancel the stream stream1.recipient = address(0xBEEF); // The recipient of the streamed tokens stream1.totalAmount = uint128(perStreamAmount); // The total amount of each stream, inclusive of all fees stream1.cancelable = false; // Whether the stream will be cancelable or not stream1.transferable = false; // Whether the recipient can transfer the NFT or not stream1.startTime = uint40(block.timestamp); // Set the start time to block timestamp // Declare some dummy segments stream1.segments = new LockupDynamic.Segment[](2); stream1.segments[0] = LockupDynamic.Segment({ amount: uint128(perStreamAmount / 4), exponent: ud2x18(1e18), timestamp: uint40(block.timestamp + 4 weeks) }); stream1.segments[1] = ( LockupDynamic.Segment({ amount: uint128(perStreamAmount - stream1.segments[0].amount), exponent: ud2x18(3.14e18), timestamp: uint40(block.timestamp + 52 weeks) }) ); stream1.broker = Broker(address(0), ud60x18(0)); // Optional parameter left undefined // Fill the batch array BatchLockup.CreateWithTimestampsLD[] memory batch = new BatchLockup.CreateWithTimestampsLD[](batchSize); batch[0] = stream0; batch[1] = stream1; streamIds = BATCH_LOCKUP.createWithTimestampsLD(LOCKUP_DYNAMIC, DAI, batch); } } ``` -------------------------------- ### Importing CodeBlock and Link Components for Sablier Guides Source: https://context7_llms Illustrates importing Docusaurus components like CodeBlock and Link. These are commonly used in guides for displaying code examples and creating links. ```javascript import Link from "@docusaurus/Link"; import CodeBlock from "@theme/CodeBlock"; ``` -------------------------------- ### Build Optimized Contracts with Foundry Source: https://docs.sablier.com/guides/airdrops/verify-campaign This command sequence clones the airdrop repository, checks out a specific version, installs dependencies, and builds the contracts. It requires Foundry to be installed and uses `bun` for package management and script execution. The output is an optimized build ready for deployment or verification. ```bash git clone git@github.com:sablier-labs/airdrops.git git checkout v1.3.0 bun install --frozen-lockfile bun run build-optimized ``` -------------------------------- ### Sablier V2 Lockup Strategy Example Setup Source: https://docs.sablier.com/guides/snapshot-voting This JSON configuration demonstrates how to set up a Sablier V2 Lockup strategy for Snapshot. It includes essential parameters like the token address, symbol, decimals, and the chosen policy, recommending 'withdrawable-recipient' for optimal results. ```json { "address": "0x97cb342cf2f6ecf48c1285fb8668f5a4237bf862", "symbol": "DAI", "decimals": 18, "policy": "withdrawable-recipient" // recommended, } ``` -------------------------------- ### Full Flow Stream Creator Contract Example Source: https://docs.sablier.com/guides/flow/examples/create-stream This is the complete Solidity contract for creating a Flow stream. It includes all necessary imports, constants, and a function to create a stream with specified parameters such as sender, recipient, rate per second, token, and transferability. This example is for educational purposes and not production-ready. ```solidity pragma solidity >=0.8.22; import { IERC20 } from "@sablier/core/src/interfaces/IERC20.sol"; import { ISablierFlow } from "@sablier/flow/src/interfaces/ISablierFlow.sol"; import { FlowUtilities } from "@sablier/flow/src/libraries/FlowUtilities.sol"; contract FlowStreamCreator { IERC20 public constant USDC = IERC20(0xf08A50178dfcDe18524640EA6618a1f965821715); ISablierFlow public constant FLOW = ISablierFlow(0x52ab22e769E31564E17D524b683264B65662A014); function createStream_1K_PerMonth() external returns (uint256) { uint256 streamId; streamId = FLOW.create({ sender: msg.sender, recipient: address(0xCAFE), ratePerSecond: FlowUtilities.ratePerSecondWithDuration({ token: address(USDC), amount: 1000e6, duration: 30 days }), token: USDC, transferable: true }); return streamId; } } ``` -------------------------------- ### Solidity Contract Setup for Lockup Dynamic Stream Source: https://docs.sablier.com/guides/lockup/examples/create-stream/lockup-dynamic This snippet demonstrates the initial setup for a Solidity contract intended to create dynamic lockup streams. It includes the SPDX license identifier, pragma directive for the Solidity version, and the declaration of constants for ERC20 token and Sablier Lockup contract addresses. Note that these addresses are hardcoded for demonstration and should be handled dynamically in production. ```solidity // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22; contract LockupDynamicStreamCreator { IERC20 public constant DAI = IERC20(0x68194a729C2450ad26072b3D33ADaCbcef39D574); ISablierLockup public constant LOCKUP = ISablierLockup(0xC2Da366fD67423b500cDF4712BdB41d0995b0794); } ``` -------------------------------- ### Retrieve Vesting Schedule Details (Solidity) Source: https://docs.sablier.com/reference/airdrops/contracts/interfaces/interface.ISablierMerkleLL Fetches the parameters defining the linear vesting schedule. This includes start time, initial unlock percentage, cliff duration, cliff unlock percentage, and total duration. A start time of zero defaults to the current block timestamp. The schedule is used in `Lockup.CreateWithTimestampsLL`. ```solidity function getSchedule() external view returns (MerkleLL.Schedule memory); ``` -------------------------------- ### Check if Campaign Has Started (Rust) Source: https://docs.sablier.com/solana/program-reference/merkle-instant/merkle-instant Indicates whether a campaign has commenced its operation. This function requires the 'campaign' account to verify the campaign's start status. ```rust pub fn has_campaign_started(ctx: Context) -> Result ``` -------------------------------- ### SablierMerkleLT Internal Function: _calculateStartTimeAndTranches Source: https://docs.sablier.com/reference/airdrops/contracts/contract.SablierMerkleLT An internal view function that calculates the start time and the vesting tranches based on the provided claim amount and the unlock percentages defined for each tranche. It returns the calculated start time and an array of `LockupTranched.Tranche`. ```solidity function _calculateStartTimeAndTranches( uint128 claimAmount ) internal view returns (uint40 startTime, LockupTranched.Tranche[] memory tranches); ``` -------------------------------- ### Get Stream Properties with Solidity and Ethers.js Source: https://docs.sablier.com/reference/legacy/contracts/constant-functions Retrieves all properties for a given stream ID. This includes sender, recipient, token address, start and stop times, remaining balance, and rate per second. It is implemented in Solidity and provides examples for both Solidity and Ethers.js. ```Solidity function getStream(uint256 streamId) view returns (address sender, address recipient, address tokenAddress, uint256 balance, uint256 startTime, uint256 stopTime, uint256 remainingBalance, uint256 ratePerSecond) ``` ```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); ``` ```javascript const sablier = new ethers.Contract(0xabcd..., sablierABI, signerOrProvider); const streamId = 42; const stream = await sablier.getStream(streamId); ``` -------------------------------- ### Initialize Project with Protocol Integration Template Source: https://docs.sablier.com/guides/lockup/examples/local-environment Initializes a new project directory, navigates into it, and sets up a Foundry project using a specific integration template for the protocol. It then installs project dependencies using Bun. ```bash $ mkdir ${props.protocol.toLowerCase()}-integration-template $ cd ${props.protocol.toLowerCase()}-integration-template $ forge init --template sablier-labs/${props.protocol.toLowerCase()}-integration-template $ bun install ``` -------------------------------- ### Get Stream Start Time - Solidity Source: https://docs.sablier.com/reference/lockup/contracts/abstracts/abstract.SablierLockupBase Retrieves the start time of a stream as a Unix timestamp. Reverts if the streamId references a null stream. It accepts a uint256 streamId and returns a uint40 representing the start time. ```solidity function getStartTime(uint256 streamId) external view override notNull(streamId) returns (uint40 startTime); ``` -------------------------------- ### Get Delta Of API Source: https://docs.sablier.com/reference/legacy/contracts/constant-functions 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. ```APIDOC ## GET /deltaOf ### Description 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. ### Method GET ### Endpoint `/deltaOf` ### Parameters #### Query Parameters - **streamId** (uint256) - Required - The id of the stream for which to query the delta. ### Response #### Success Response (200) - **delta** (uint256) - The time delta in seconds. #### Response Example ```json { "delta": 86400 } ``` ``` -------------------------------- ### Initialize Foundry Project (Bash) Source: https://docs.sablier.com/guides/flow/examples/local-environment Creates a new Foundry project and navigates into its directory. Foundry is a development toolkit for Ethereum projects used for compiling and testing contracts. ```bash forge init my-project cd my-project ``` -------------------------------- ### Calculate Stream Time Delta with Solidity and Ethers.js Source: https://docs.sablier.com/reference/legacy/contracts/constant-functions Calculates the time delta for a stream, returning the smaller of the difference between now and the start time, or the stop time and the start time. If the stream has not started, it returns 0. Examples are provided for Solidity and Ethers.js. ```Solidity function deltaOf(uint256 streamId) view returns (uint256) ``` ```Solidity Sablier sablier = Sablier(0xabcd...); uint256 streamId = 42; uint256 delta = sablier.deltaOf(streamId); ``` ```javascript const sablier = new ethers.Contract(0xabcd..., sablierABI, signerOrProvider); const streamId = 42; const delta = await sablier.deltaOf(streamId); ``` -------------------------------- ### Get Start Time - ISablierLockupBase Solidity Source: https://docs.sablier.com/reference/lockup/contracts/interfaces/interface.ISablierLockupBase Retrieves the start time of a specific stream as a Unix timestamp. This function reverts if the provided streamId does not correspond to an existing stream. ```Solidity function getStartTime(uint256 streamId) external view returns (uint40 startTime); ``` -------------------------------- ### Create and Compile StreamCreator.sol Contract (Solidity) Source: https://docs.sablier.com/guides/flow/examples/local-environment This snippet outlines the process of creating the `StreamCreator.sol` contract file and compiling it using the Forge build tool. It assumes the user has already set up their project structure and has Forge installed. The compilation step verifies the contract's syntax and readiness for deployment or testing. ```solidity https://github.com/sablier-labs/sablier-integration-template/blob/main/src/SablierStreamCreator.sol ``` ```bash $ forge build ``` -------------------------------- ### Initialize Foundry Project Source: https://docs.sablier.com/guides/airdrops/examples/local-environment Initializes a new Foundry project and navigates into the project directory. Foundry provides tooling for compiling and testing Ethereum contracts. ```bash $ forge init my-project $ cd my-project ``` -------------------------------- ### GET /getStartTime Source: https://docs.sablier.com/reference/lockup/contracts/abstracts/abstract.SablierLockupBase Retrieves the start time of a stream as a Unix timestamp. This function reverts if the provided streamId references a null stream. ```APIDOC ## GET /getStartTime ### Description Retrieves the start time of a stream as a Unix timestamp. This function reverts if the provided streamId references a null stream. ### Method GET ### Endpoint /getStartTime ### Parameters #### Query Parameters - **streamId** (uint256) - Required - The stream ID for the query. ### Response #### Success Response (200) - **startTime** (uint40) - The start time of the stream as a Unix timestamp. #### Response Example { "startTime": 1678886400 } ``` -------------------------------- ### Initialize Stream Management Contract Source: https://docs.sablier.com/guides/lockup/examples/stream-management/setup Sets up the StreamManagement contract by declaring an immutable reference to the ISablierLockup interface and initializing it with the provided Sablier Lockup contract address in the constructor. ```solidity contract StreamManagement { ISablierLockup public immutable sablier; constructor(ISablierLockup sablier_) { sablier = sablier_; } } ``` -------------------------------- ### Creating a Sablier Flow Stream Source: https://context7_llms Provides a JavaScript code example for creating a stream using the Sablier Flow protocol. This snippet is part of the Flow guides and demonstrates a core functionality. ```javascript import CodeBlock from "@theme/CodeBlock"; ``` -------------------------------- ### Create and Load .env for Lockup Deployment Source: https://docs.sablier.com/guides/custom-deployments This section covers creating a `.env` file with essential deployment variables such as deployer address, Etherscan API key, private key, RPC URL, and verifier URL. It also includes the command to load these variables into the shell environment. ```bash touch .env ``` ```bash 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" ``` ```bash source .env ``` -------------------------------- ### Get Account Balance for a Stream with Solidity and Javascript Source: https://docs.sablier.com/reference/legacy/contracts/constant-functions Returns the real-time balance of an account for a specific stream. This function indicates the amount of tokens that can be withdrawn from the contract. Examples are provided for both Solidity and Javascript. ```Solidity function balanceOf(uint256 streamId, address who) view returns (uint256) ``` ```Solidity Sablier sablier = Sablier(0xabcd...); uint256 streamId = 42; uint256 senderAddress = 0xcdef...; uint256 balance = sablier.balanceOf(streamId, senderAddress); ``` ```javascript const sablier = new ethers.Contract(0xabcd..., sablierABI, signerOrProvider); const streamId = 42; const senderAddress = 0xcdef...; const balance = await sablier.balanceOf(streamId, senderAddress); ``` -------------------------------- ### Get Token ID after Claim using The Graph/Envio GraphQL Source: https://docs.sablier.com/api/airdrops/merkle-api/examples This snippet demonstrates how to retrieve the `tokenId` associated with a user's claim. It includes GraphQL queries for both The Graph and Envio indexers, filtering by campaign ID and recipient address. ```graphql query getClaimForRecipient($campaignId: String!, $recipient: String) { actions(where: { campaign: $campaignId, category: Claim, claimRecipient: $recipient }) { campaign { id lockup } claimTokenId claimRecipient claimIndex } } ``` ```graphql query getClaimForRecipient($campaignId: String!, $recipient: String) { Action( where: { _and: [{ campaign: { _eq: $campaignId } }, { category: { _eq: Claim } }, { claimRecipient: { _eq: $recipient } }] } ) { campaignObject { id lockup } claimTokenId claimRecipient claimIndex } } ``` -------------------------------- ### Successful Test Execution Output Source: https://docs.sablier.com/guides/lockup/examples/local-environment Example output indicating that tests for the StreamCreator contract have passed successfully. This message confirms that the integration logic works as expected on a forked network. ```bash Ran 2 tests for test/YOUR_PROTOCOL_StreamCreator.t.sol:YOUR_PROTOCOL_StreamCreatorTest [PASS] test_CreateYOUR_PROTOCOL_Stream() (gas: 246830) Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 626.58ms (500.67µs CPU time) ``` -------------------------------- ### Get Campaign IPFS CID using The Graph/Envio GraphQL Source: https://docs.sablier.com/api/airdrops/merkle-api/examples This snippet shows how to query for a campaign's IPFS CID using GraphQL. It provides queries for both The Graph and Envio indexers. These queries fetch campaign details including the ipfsCID. ```graphql query getCampaignData($campaignId: String!){ campaign(id: $campaignId){ id lockup root ipfsCID aggregateAmount totalRecipients } } ``` ```graphql query getCampaignData($campaignId: String!){ Campaign(where: {id: {_eq: $campaignId}} ){ id lockup root ipfsCID aggregateAmount totalRecipients } } ``` -------------------------------- ### CreateCampaign Instruction Accounts (Rust) Source: https://docs.sablier.com/solana/program-reference/merkle-instant/context%20accounts Lists the accounts necessary for creating a new campaign. This includes the creator, token mint, new campaign account, campaign's ATA, and system/token programs. ```rust pub creator: Signer<'info>, pub airdrop_token_mint: Box>, pub campaign: Box>, pub campaign_ata: Box>, pub airdrop_token_program: Interface<'info, TokenInterface>, pub associated_token_program: Program<'info, AssociatedToken>, pub system_program: Program<'info, System> ``` -------------------------------- ### Declare Second Stream Structure for BatchLockup Source: https://docs.sablier.com/guides/lockup/examples/batch-create-streams/batch-lockup-dynamic Declares and initializes the second stream structure (`stream1`) with different parameters than the first. It sets sender, recipient, total amount, cancelable/transferable flags, start time, and defines two distinct segments. This example showcases how to vary stream configurations within a batch. Optional broker parameter is also initialized. ```solidity BatchLockup.CreateWithTimestampsLD memory stream1; s t ream1.sender = address(0xABCD); // The sender to stream the tokens, he will be able to cancel the stream s t ream1.recipient = address(0xBEEF); // The recipient of the streamed tokens s t ream1.totalAmount = uint128(perStreamAmount); // The total amount of each stream, inclusive of all fees s t ream1.cancelable = false; // Whether the stream will be cancelable or not s t ream1.transferable = false; // Whether the recipient can transfer the NFT or not s t ream1.startTime = uint40(block.timestamp); // Set the start time to block timestamp // Declare some dummy segments s t ream1.segments = new LockupDynamic.Segment[](2); s t ream1.segments[0] = LockupDynamic.Segment({ amount: uint128(perStreamAmount / 4), exponent: ud2x18(1e18), timestamp: uint40(block.timestamp + 4 weeks) }); s t ream1.segments[1] = ( LockupDynamic.Segment({ amount: uint128(perStreamAmount - stream1.segments[0].amount), exponent: ud2x18(3.14e18), timestamp: uint40(block.timestamp + 52 weeks) }) ); s t ream1.broker = Broker(address(0), ud60x18(0)); // Optional parameter left undefined ``` -------------------------------- ### Initialize Instruction Accounts (Rust) Source: https://docs.sablier.com/solana/program-reference/merkle-instant/context%20accounts Specifies the accounts for the Initialize instruction, which sets up the program's treasury. Requires an initializer, the treasury account, and the system program. ```rust pub initializer: Signer<'info>, pub treasury: Box>, pub system_program: Program<'info, System> ``` -------------------------------- ### Build Project with Forge Source: https://docs.sablier.com/guides/lockup/examples/local-environment Executes the build command for a Solidity project using Forge. This compiles all contracts in the project, checks for errors, and generates build artifacts. It's a fundamental step before testing or deploying. ```bash forge build ``` -------------------------------- ### Sablier Search URL Examples Source: https://docs.sablier.com/apps/guides/url-schemes Examples of constructing URLs to filter Sablier streams by sender address or by specific stream IDs. These examples demonstrate how to append different query parameters to the base URL for targeted searches. ```text https://app.sablier.com/?t=search&c=1&s=0x0aAeF7BbC21c627f14caD904E283e199cA2b72cC ``` ```text https://app.sablier.com/?t=search&c=1&i=LL2-1-2,LL-1-29 ``` -------------------------------- ### Execute Tests with Forge Source: https://docs.sablier.com/guides/lockup/examples/local-environment Executes all tests within the specified Solidity file using Forge. This command is used to verify the correctness of smart contracts by running them against various scenarios, including forked network states. ```bash forge test ``` -------------------------------- ### Solidity Contract Setup for Flow Streams Source: https://docs.sablier.com/guides/flow/examples/create-stream This snippet shows the basic contract structure for creating a Flow stream in Solidity. It includes setting the Solidity version, importing necessary libraries, and declaring constants for ERC-20 tokens and the Sablier Flow contract. Addresses are hard-coded for demonstration but should be flexible in production. ```solidity pragma solidity >=0.8.22; import { IERC20 } from "@sablier/core/src/interfaces/IERC20.sol"; import { ISablierFlow } from "@sablier/flow/src/interfaces/ISablierFlow.sol"; import { FlowUtilities } from "@sablier/flow/src/libraries/FlowUtilities.sol"; contract FlowStreamCreator { IERC20 public constant USDC = IERC20(0xf08A50178dfcDe18524640EA6618a1f965821715); ISablierFlow public constant FLOW = ISablierFlow(0x52ab22e769E31564E17D524b683264B65662A014); function createStream_1K_PerMonth() external returns (uint256) { // ... implementation details ... uint256 streamId; streamId = FLOW.create({ sender: msg.sender, recipient: address(0xCAFE), ratePerSecond: FlowUtilities.ratePerSecondWithDuration({ token: address(USDC), amount: 1000e6, duration: 30 days }), token: USDC, transferable: true }); return streamId; } } ``` -------------------------------- ### Create and Load Environment Variables Source: https://docs.sablier.com/guides/custom-deployments Creates a .env file to store deployment-related environment variables and then sources the file to load them into the current shell session. Variables include API keys, private keys, and RPC endpoints. ```bash touch .env # Add the following variables to .env file: # ETH_FROM="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" source .env ``` -------------------------------- ### Solidity: Set up Contract for Batch Stream Creation Source: https://docs.sablier.com/guides/lockup/examples/batch-create-streams/batch-lockup-dynamic Declares the Solidity version, imports necessary interfaces, and defines constants for ERC20 token and Sablier lockup contracts. Contract addresses are hardcoded for demonstration and should be parameterized in production. ```solidity // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22; interface IERC20 { function transferFrom(address, address, uint256) external returns (bool); function approve(address, uint256) external returns (bool); } interface ISablierLockup { // ... (other functions) } interface ISablierBatchLockup { // ... (other functions) function createWithTimestampsLD( address token, address recipient, uint128 amount, uint64 startTime, uint64 endTime ) external returns (uint256); } contract BatchLDStreamCreator { IERC20 public constant DAI = IERC20(0x68194a729C2450ad26072b3D33ADaCbcef39D574); ISablierLockup public constant LOCKUP = ISablierLockup(0xC2Da366fD67423b500cDF4712BdB41d0995b0794); ISablierBatchLockup public constant BATCH_LOCKUP = ISablierBatchLockup(0xd4294579236eE290668c8FdaE9403c4F00D914f0); function batchCreateStreams(uint128 perStreamAmount) public returns (uint256[] memory streamIds) { uint256 batchSize = 2; // Example batch size uint256 transferAmount = perStreamAmount * batchSize; // Transfer DAI tokens to this contract DAI.transferFrom(msg.sender, address(this), transferAmount); // Approve the Batch contract to spend DAI DAI.approve(address(BATCH_LOCKUP), transferAmount); // Example: Creating two streams with fixed start and end times // In a real scenario, these would likely be dynamic based on inputs uint64 startTime = uint64(block.timestamp); uint64 endTime = uint64(block.timestamp) + 86400; // 1 day duration // Note: This is a simplified example. The createWithTimestampsLD function from ISablierBatchLockup // would be called here, likely in a loop or with dynamic parameters for each stream. // The actual implementation of calling createWithTimestampsLD for multiple streams // would depend on the exact requirements and how the 'streamIds' are populated. // For demonstration, we'll simulate the return of stream IDs. // Placeholder for actual stream creation logic // streamIds = new uint256[](batchSize); // for (uint256 i = 0; i < batchSize; i++) { // // Call createWithTimestampsLD for each stream and store the ID // // streamIds[i] = BATCH_LOCKUP.createWithTimestampsLD(address(DAI), msg.sender, perStreamAmount, startTime, endTime); // } // Returning dummy IDs for structure illustration streamIds = new uint256[](batchSize); streamIds[0] = 1; streamIds[1] = 2; return streamIds; } } ``` -------------------------------- ### Define UnlockAmounts Struct in Solidity Source: https://docs.sablier.com/reference/lockup/contracts/types/library.LockupLinear The UnlockAmounts struct defines the amounts to be unlocked at the start and at the cliff time. The sum of these amounts must not exceed the total deposit amount. Both start and cliff are represented as uint128. ```solidity struct UnlockAmounts { uint128 start; uint128 cliff; } ``` -------------------------------- ### Add Protocol Package via Bun Source: https://docs.sablier.com/guides/lockup/examples/local-environment Adds the specified protocol's Node.js package as a dependency to the project using Bun. This makes the protocol's contracts and their dependencies available within the project's node_modules directory. ```bash $ bun add @sablier/${props.protocol.toLowerCase()} ``` -------------------------------- ### Snapshot Voting Power Calculation Example Source: https://docs.sablier.com/guides/snapshot-voting This text-based example illustrates how different Snapshot voting power policies are applied to a Lockup stream. It shows the calculated power for various policies based on deposited, withdrawn, and streamed amounts at a specific snapshot time. ```text Lockup Stream #000001 --- Deposited: TKN 1000 for 30 days Withdrawn: TKN 450 before snapshot Snapshot: Day 15 (midway) with a streamed amount of TKN 500 +------------------------+----------+ | POLICY | POWER | +------------------------+----------+ | erc20-balance-of | TKN 450 | +------------------------+----------+ | withdrawable-recipient | TKN 50 | +------------------------+----------+ | reserved-recipient | TKN 550 | +------------------------+----------+ | deposited-recipient | TKN 1000 | +------------------------+----------+ | deposited-sender | TKN 1000 | +------------------------+----------+ | streamed-recipient | TKN 500 | +------------------------+----------+ | unstreamed-recipient | TKN 500 | +------------------------+----------+ ``` -------------------------------- ### Set up Solidity Contract for Batch Stream Creation Source: https://docs.sablier.com/guides/lockup/examples/batch-create-streams/batch-lockup-linear Declares the Solidity version and imports necessary symbols. It defines constants for DAI, ISablierLockup, and ISablierBatchLockup contracts, initializing them with hardcoded addresses for demonstration on Ethereum Sepolia. ```solidity // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22; // Import interfaces if they are not already imported in the current scope // interface IERC20 { ... } // interface ISablierLockup { ... } // interface ISablierBatchLockup { ... } contract BatchLLStreamCreator { IERC20 public constant DAI = IERC20(0x68194a729C2450ad26072b3D33ADaCbcef39D574); ISablierLockup public constant LOCKUP = ISablierLockup(0xC2Da366fD67423b500cDF4712BdB41d0995b0794); ISablierBatchLockup public constant BATCH_LOCKUP = ISablierBatchLockup(0xd4294579236eE290668c8FdaE9403c4F00D914f0); } ``` -------------------------------- ### Initialize Merkle Creator Contract Source: https://docs.sablier.com/guides/airdrops/examples/create-campaign Sets up the MerkleCreator contract by declaring constants for DAI, Lockup, and the Merkle Factory. The contract addresses are hard-coded for demonstration; in production, use input parameters for flexibility. These addresses are specific to Ethereum Sepolia. ```solidity contract MerkleCreator { IERC20 public constant DAI = IERC20(0x68194a729C2450ad26072b3D33ADaCbcef39D574); ISablierMerkleFactory public constant FACTORY = ISablierMerkleFactory(0x4ECd5A688b0365e61c1a764E8BF96A7C5dF5d35F); ISablierLockup public constant LOCKUP = ISablierLockup(0xC2Da366fD67423b500cDF4712BdB41d0995b0794); } ``` -------------------------------- ### Configure Vesting Schedule for MerkleLL Campaign Source: https://docs.sablier.com/guides/airdrops/examples/create-campaign Sets up the vesting schedule for a MerkleLL campaign, including start time, initial unlock percentages, cliff duration, and total vesting duration. Uses a custom `ud2x18` type for percentage calculations. ```solidity MerkleLL.Schedule memory schedule = MerkleLL.Schedule({ startTime: 0, startPercentage: ud2x18(0.01e18), cliffDuration: 30 days, cliffPercentage: ud2x18(0.01e18), totalDuration: 90 days }); ``` -------------------------------- ### Define Stream Start and End Timestamps Source: https://docs.sablier.com/guides/lockup/examples/create-stream/lockup-dynamic This snippet illustrates setting the start and end timestamps for a token stream using Solidity's block timestamp. The end timestamp must align with the last segment's timestamp for accurate stream finalization. Units are in seconds. ```solidity params.timestamps.start = uint40(block.timestamp + 100 seconds); params.timestamps.end = uint40(block.timestamp + 52 weeks); ``` -------------------------------- ### SablierMerkleBase Constructor (Solidity) Source: https://docs.sablier.com/reference/airdrops/contracts/abstracts/abstract.SablierMerkleBase Initializes the SablierMerkleBase contract by setting up immutable state variables and assigning an initial administrator using the provided constructor parameters and campaign creator address. ```solidity constructor(MerkleBase.ConstructorParams memory params, address campaignCreator) Adminable(params.initialAdmin); ``` -------------------------------- ### Solidity: StakeSablierNFT Contract Constructor Source: https://docs.sablier.com/guides/lockup/examples/staking/setup Initializes the StakeSablierNFT contract, setting the admin address, the reward token, and the Sablier lockup contract instance. This constructor is essential for setting up the core dependencies of the staking contract. ```solidity contract StakeSablierNFT is Adminable, ERC721Holder, ISablierLockupRecipient // Required to implement hooks { constructor(address initialAdmin, IERC20 rewardERC20Token_, ISablierLockup sablierLockup_) { admin = initialAdmin; rewardERC20Token = rewardERC20Token_; sablierLockup = sablierLockup_; } } ``` -------------------------------- ### Compile StreamCreator Contract Source: https://docs.sablier.com/guides/lockup/examples/local-environment Compiles the StreamCreator.sol contract using Forge. This command ensures the contract is syntactically correct and ready for deployment or testing. It requires a Solidity environment configured with Forge. ```solidity https://github.com/sablier-labs/YOUR_PROTOCOL_LOWERCASE-integration-template/blob/main/src/YOUR_PROTOCOL_StreamCreator.sol ``` -------------------------------- ### Create Dynamic Stream with Durations (Solidity) Source: https://docs.sablier.com/reference/lockup/contracts/interfaces/interface.ISablierLockup Creates a stream with a dynamic unlock schedule based on provided durations. The stream starts at `block.timestamp`, and its end time is calculated by summing the start time with all specified durations. Segment timestamps are derived from these durations. The stream is funded by `msg.sender` and is wrapped as an ERC-721 NFT. Requires all conditions from `createWithTimestampsLD` to be met. ```Solidity function createWithDurationsLD( Lockup.CreateWithDurations calldata params, LockupDynamic.SegmentWithDuration[] calldata segmentsWithDuration ) external payable returns (uint256 streamId); ``` -------------------------------- ### Run StreamCreator Contract Test (Solidity/Bash) Source: https://docs.sablier.com/guides/flow/examples/local-environment This section details how to run tests for the `StreamCreator.sol` contract using Foundry's fork testing capabilities. It requires an RPC endpoint (e.g., from Alchemy) to fork the Ethereum Mainnet. The tests verify the contract's functionality against deployed Sablier contracts. ```solidity https://github.com/sablier-labs/sablier-integration-template/blob/main/test/SablierStreamCreator.t.sol ``` ```bash $ forge test ``` ```bash Ran 2 tests for test/SablierStreamCreator.t.sol:SablierStreamCreatorTest [PASS] test_CreateSablierStream() (gas: 246830) Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 626.58ms (500.67µs CPU time) ``` -------------------------------- ### GET /RevenueTransaction_by_pk Source: https://docs.sablier.com/api/airdrops/graphql/envio/queries/revenue-transaction-by-pk Fetches a single RevenueTransaction record by its primary key (id). ```APIDOC ## GET /RevenueTransaction_by_pk ### Description Retrieves a specific revenue transaction from the 'RevenueTransaction' table using its primary key. ### Method GET ### Endpoint `/RevenueTransaction_by_pk` ### Parameters #### Query Parameters - **id** (String!) - Required - The unique identifier of the revenue transaction to retrieve. ### Request Example ```json { "query": "query RevenueTransactionById($id: String!) { RevenueTransaction_by_pk(id: $id) { ... } }", "variables": { "id": "your_transaction_id_here" } } ``` ### Response #### Success Response (200) - **RevenueTransaction** (object) - The details of the requested revenue transaction. #### Response Example ```json { "data": { "RevenueTransaction_by_pk": { "id": "txn_12345", "amount": 100.50, "currency": "USD", "timestamp": "2023-10-27T10:00:00Z" // ... other fields of RevenueTransaction } } } ``` ``` -------------------------------- ### GraphQL Input: dynamic_contract_registry_stream_cursor_value_input Source: https://docs.sablier.com/api/airdrops/graphql/envio/inputs/dynamic-contract-registry-stream-cursor-value-input Defines the input structure for specifying a cursor value to start streaming contract registry data. This input type includes fields for chain ID, contract address, contract type, and specific event details to pinpoint the starting point of the stream. It is used in GraphQL mutations or queries related to dynamic contract registration. ```graphql input dynamic_contract_registry_stream_cursor_value_input { chain_id: Int contract_address: String contract_type: contract_type id: String registering_event_block_number: Int registering_event_block_timestamp: Int registering_event_contract_name: String registering_event_log_index: Int registering_event_name: String registering_event_src_address: String } ``` -------------------------------- ### Segment_stream_cursor_value_input Source: https://docs.sablier.com/api/lockup/graphql/envio/inputs/segment-stream-cursor-value-input The Segment_stream_cursor_value_input defines the initial value of the column from where the streaming should start. ```APIDOC ## graphql input Segment_stream_cursor_value_input ### Description Initial value of the column from where the streaming should start ### Fields - **amount** (numeric) - Optional - The amount of the segment. - **db_write_timestamp** (timestamp) - Optional - The database write timestamp for the segment. - **endAmount** (numeric) - Optional - The end amount of the stream segment. - **endTime** (numeric) - Optional - The end time of the stream segment. - **exponent** (numeric) - Optional - The exponent value for numeric precision. - **id** (String) - Optional - The unique identifier for the segment. - **position** (numeric) - Optional - The position of the segment in the stream. - **startAmount** (numeric) - Optional - The starting amount of the stream segment. - **startTime** (numeric) - Optional - The start time of the stream segment. - **stream_id** (String) - Optional - The identifier of the stream. ``` -------------------------------- ### Solidity LockupDynamic Stream Parameter Initialization Source: https://docs.sablier.com/guides/lockup/examples/create-stream/lockup-dynamic Initializes the parameters required for creating a dynamic lockup stream using `createWithTimestampsLD`. It declares memory variables for `LockupDynamic.CreateWithTimestamps` and an array of `LockupDynamic.Segment`. This setup prepares the struct for populating stream details. ```solidity LockupDynamic.CreateWithTimestamps memory params; LockupDynamic.Segment[] memory segments = new LockupDynamic.Segment[](2); ``` -------------------------------- ### Initialize Batch Lockup Creator Contract Source: https://docs.sablier.com/guides/lockup/examples/batch-create-streams/batch-lockup-tranched Sets up the BatchLTStreamCreator contract by declaring constants for DAI, SablierLockup, and SablierBatchLockup contracts. Addresses are hardcoded for demonstration and should be parameterized for production. These addresses are for Ethereum Sepolia. ```solidity contract BatchLTStreamCreator { IERC20 public constant DAI = IERC20(0x68194a729C2450ad26072b3D33ADaCbcef39D574); ISablierLockup public constant LOCKUP = ISablierLockup(0xC2Da366fD67423b500cDF4712BdB41d0995b0794); ISablierBatchLockup public constant BATCH_LOCKUP = ISablierBatchLockup(0xd4294579236eE290668c8FdaE9403c4F00D914f0); } ``` -------------------------------- ### chain_metadata_stream_cursor_value_input Source: https://docs.sablier.com/api/lockup/graphql/envio/inputs/chain-metadata-stream-cursor-value-input The chain_metadata_stream_cursor_value_input is used to define the starting point and parameters for streaming chain metadata. ```APIDOC ## chain_metadata_stream_cursor_value_input ### Description Input type for specifying the cursor value when streaming chain metadata. It allows for defining the starting block, chain ID, and other parameters to control the stream. ### Method Not Applicable (GraphQL Input Type) ### Endpoint Not Applicable (GraphQL Input Type) ### Parameters #### Input Fields - **block_height** (Int) - Optional - The block height to start streaming from. - **chain_id** (Int) - Optional - The ID of the chain to stream data from. - **end_block** (Int) - Optional - The block height at which to end the stream. - **first_event_block_number** (Int) - Optional - The block number of the first event. - **is_hyper_sync** (Boolean) - Optional - Flag to indicate if hyper sync is enabled. - **latest_fetched_block_number** (Int) - Optional - The latest block number that has been fetched. - **latest_processed_block** (Int) - Optional - The latest block number that has been processed. - **num_batches_fetched** (Int) - Optional - The number of batches fetched. - **num_events_processed** (Int) - Optional - The number of events processed. - **start_block** (Int) - Optional - The specific block number to start streaming from. - **timestamp_caught_up_to_head_or_endblock** (timestamptz) - Optional - The timestamp when the stream caught up to the head or end block. ### Request Example ```json { "block_height": 12345, "chain_id": 1, "end_block": 13000, "is_hyper_sync": true, "start_block": 12000, "timestamp_caught_up_to_head_or_endblock": "2023-10-27T10:00:00Z" } ``` ### Response #### Success Response (N/A for Input Type) This is an input type, so it does not have a direct success response. Its fields are used in mutations or queries. #### Response Example (N/A for Input Type) N/A ```