Skip to content

Commit

Permalink
Merge pull request #817 from sablier-labs/feat/lockup-tranched
Browse files Browse the repository at this point in the history
LockupTranched contract
  • Loading branch information
andreivladbrg authored Mar 6, 2024
2 parents 9194e81 + afb4127 commit 34fee6b
Show file tree
Hide file tree
Showing 91 changed files with 4,855 additions and 532 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@ contract MyContract {

## Architecture

V2 Core uses a singleton-style architecture, where all streams are managed in the `LockupLinear` and `LockupDynamic`
contracts. That is, Sablier does not deploy a new contract for each stream. It bundles all streams into a single
contract, which is more gas-efficient and easier to maintain.
V2 Core uses a singleton-style architecture, where all streams are managed in the `LockupLinear`, `LockupDynamic` and
`LockupTranched` contracts. That is, Sablier does not deploy a new contract for each stream. It bundles all streams into
a single contract, which is more gas-efficient and easier to maintain.

For more information, see the [Technical Overview](https://docs.sablier.com/contracts/v2/reference/overview) in our
docs, as well as these [diagrams](https://docs.sablier.com/contracts/v2/reference/diagrams).
Expand Down
2 changes: 2 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"SablierV2Comptroller",
"SablierV2LockupDynamic",
"SablierV2LockupLinear",
"SablierV2LockupTranched",
"SablierV2NFTDescriptor",
]
optimizer = true
Expand Down Expand Up @@ -68,6 +69,7 @@
[profile.smt.model_checker.contracts]
"src/SablierV2LockupDynamic.sol" = ["SablierV2LockupDynamic"]
"src/SablierV2LockupLinear.sol" = ["SablierV2LockupLinear"]
"src/SablierV2LockupTranched.sol" = ["SablierV2LockupTranched"]
"src/SablierV2NFTDescriptor.sol" = ["SablierV2NFTDescriptor"]

# Test the optimized contracts without re-compiling them
Expand Down
4 changes: 4 additions & 0 deletions script/DeployCore.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity >=0.8.22 <0.9.0;
import { SablierV2Comptroller } from "../src/SablierV2Comptroller.sol";
import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol";
import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol";
import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol";
import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol";

import { BaseScript } from "./Base.s.sol";
Expand All @@ -14,6 +15,7 @@ import { BaseScript } from "./Base.s.sol";
/// 2. {SablierV2NFTDescriptor}
/// 3. {SablierV2LockupDynamic}
/// 4. {SablierV2LockupLinear}
/// 5. {SablierV2LockupTranched}
contract DeployCore is BaseScript {
function run(address initialAdmin)
public
Expand All @@ -23,12 +25,14 @@ contract DeployCore is BaseScript {
SablierV2Comptroller comptroller,
SablierV2LockupDynamic lockupDynamic,
SablierV2LockupLinear lockupLinear,
SablierV2LockupTranched lockupTranched,
SablierV2NFTDescriptor nftDescriptor
)
{
comptroller = new SablierV2Comptroller(initialAdmin);
nftDescriptor = new SablierV2NFTDescriptor();
lockupDynamic = new SablierV2LockupDynamic(initialAdmin, comptroller, nftDescriptor, maxCount);
lockupLinear = new SablierV2LockupLinear(initialAdmin, comptroller, nftDescriptor);
lockupTranched = new SablierV2LockupTranched(initialAdmin, comptroller, nftDescriptor, maxCount);
}
}
6 changes: 5 additions & 1 deletion script/DeployCore2.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescript
import { SablierV2Comptroller } from "../src/SablierV2Comptroller.sol";
import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol";
import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol";
import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol";

import { BaseScript } from "./Base.s.sol";

Expand All @@ -13,6 +14,7 @@ import { BaseScript } from "./Base.s.sol";
/// 1. {SablierV2Comptroller}
/// 2. {SablierV2LockupDynamic}
/// 3. {SablierV2LockupLinear}
/// 4. {SablierV2LockupTranched}
contract DeployCore2 is BaseScript {
function run(
address initialAdmin,
Expand All @@ -24,11 +26,13 @@ contract DeployCore2 is BaseScript {
returns (
SablierV2Comptroller comptroller,
SablierV2LockupDynamic lockupDynamic,
SablierV2LockupLinear lockupLinear
SablierV2LockupLinear lockupLinear,
SablierV2LockupTranched lockupTranched
)
{
comptroller = new SablierV2Comptroller(initialAdmin);
lockupDynamic = new SablierV2LockupDynamic(initialAdmin, comptroller, nftDescriptor, maxCount);
lockupLinear = new SablierV2LockupLinear(initialAdmin, comptroller, nftDescriptor);
lockupTranched = new SablierV2LockupTranched(initialAdmin, comptroller, nftDescriptor, maxCount);
}
}
8 changes: 6 additions & 2 deletions script/DeployCore3.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
pragma solidity >=0.8.22 <0.9.0;

import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol";
import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol";
import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol";
import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol";
import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol";
import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol";

import { BaseScript } from "./Base.s.sol";

Expand All @@ -13,6 +14,7 @@ import { BaseScript } from "./Base.s.sol";
/// 1. {SablierV2NFTDescriptor}
/// 2. {SablierV2LockupDynamic}
/// 3. {SablierV2LockupLinear}
/// 4. {SablierV2LockupTranched}
contract DeployCore3 is BaseScript {
function run(
address initialAdmin,
Expand All @@ -24,11 +26,13 @@ contract DeployCore3 is BaseScript {
returns (
SablierV2NFTDescriptor nftDescriptor,
SablierV2LockupDynamic lockupDynamic,
SablierV2LockupLinear lockupLinear
SablierV2LockupLinear lockupLinear,
SablierV2LockupTranched lockupTranched
)
{
nftDescriptor = new SablierV2NFTDescriptor();
lockupDynamic = new SablierV2LockupDynamic(initialAdmin, comptroller, nftDescriptor, maxCount);
lockupLinear = new SablierV2LockupLinear(initialAdmin, comptroller, nftDescriptor);
lockupTranched = new SablierV2LockupTranched(initialAdmin, comptroller, nftDescriptor, maxCount);
}
}
4 changes: 4 additions & 0 deletions script/DeployDeterministicCore.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity >=0.8.22 <0.9.0;
import { SablierV2Comptroller } from "../src/SablierV2Comptroller.sol";
import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol";
import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol";
import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol";
import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol";

import { BaseScript } from "./Base.s.sol";
Expand All @@ -14,6 +15,7 @@ import { BaseScript } from "./Base.s.sol";
/// 2. {SablierV2NFTDescriptor}
/// 3. {SablierV2LockupDynamic}
/// 4. {SablierV2LockupLinear}
/// 5. {SablierV2LockupTranched}
///
/// @dev Reverts if any contract has already been deployed.
contract DeployDeterministicCore is BaseScript {
Expand All @@ -25,6 +27,7 @@ contract DeployDeterministicCore is BaseScript {
SablierV2Comptroller comptroller,
SablierV2LockupDynamic lockupDynamic,
SablierV2LockupLinear lockupLinear,
SablierV2LockupTranched lockupTranched,
SablierV2NFTDescriptor nftDescriptor
)
{
Expand All @@ -33,5 +36,6 @@ contract DeployDeterministicCore is BaseScript {
nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }();
lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxCount);
lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, comptroller, nftDescriptor);
lockupTranched = new SablierV2LockupTranched{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxCount);
}
}
6 changes: 5 additions & 1 deletion script/DeployDeterministicCore2.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescript
import { SablierV2Comptroller } from "../src/SablierV2Comptroller.sol";
import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol";
import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol";
import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol";

import { BaseScript } from "./Base.s.sol";

Expand All @@ -13,6 +14,7 @@ import { BaseScript } from "./Base.s.sol";
/// 1. {SablierV2Comptroller}
/// 2. {SablierV2LockupDynamic}
/// 3. {SablierV2LockupLinear}
/// 4. {SablierV2LockupTranched}
///
/// @dev Reverts if any contract has already been deployed.
contract DeployDeterministicCore2 is BaseScript {
Expand All @@ -26,12 +28,14 @@ contract DeployDeterministicCore2 is BaseScript {
returns (
SablierV2Comptroller comptroller,
SablierV2LockupDynamic lockupDynamic,
SablierV2LockupLinear lockupLinear
SablierV2LockupLinear lockupLinear,
SablierV2LockupTranched lockupTranched
)
{
bytes32 salt = constructCreate2Salt();
comptroller = new SablierV2Comptroller{ salt: salt }(initialAdmin);
lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxCount);
lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, comptroller, nftDescriptor);
lockupTranched = new SablierV2LockupTranched{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxCount);
}
}
8 changes: 6 additions & 2 deletions script/DeployDeterministicCore3.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
pragma solidity >=0.8.22 <0.9.0;

import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol";
import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol";
import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol";
import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol";
import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol";
import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol";

import { BaseScript } from "./Base.s.sol";

Expand All @@ -13,6 +14,7 @@ import { BaseScript } from "./Base.s.sol";
/// 1. {SablierV2NFTDescriptor}
/// 2. {SablierV2LockupDynamic}
/// 3. {SablierV2LockupLinear}
/// 4. {SablierV2LockupTranched}
///
/// @dev Reverts if any contract has already been deployed.
contract DeployDeterministicCore3 is BaseScript {
Expand All @@ -26,12 +28,14 @@ contract DeployDeterministicCore3 is BaseScript {
returns (
SablierV2NFTDescriptor nftDescriptor,
SablierV2LockupDynamic lockupDynamic,
SablierV2LockupLinear lockupLinear
SablierV2LockupLinear lockupLinear,
SablierV2LockupTranched lockupTranched
)
{
bytes32 salt = constructCreate2Salt();
nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }();
lockupDynamic = new SablierV2LockupDynamic{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxCount);
lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, comptroller, nftDescriptor);
lockupTranched = new SablierV2LockupTranched{ salt: salt }(initialAdmin, comptroller, nftDescriptor, maxCount);
}
}
27 changes: 27 additions & 0 deletions script/DeployDeterministicLockupTranched.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.22 <0.9.0;

import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol";
import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol";
import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol";

import { BaseScript } from "./Base.s.sol";

/// @dev Deploys {SablierV2LockupTranched} at a deterministic address across chains.
/// @dev Reverts if the contract has already been deployed.
contract DeployDeterministicLockupTranched is BaseScript {
function run(
address initialAdmin,
ISablierV2Comptroller initialComptroller,
ISablierV2NFTDescriptor initialNFTDescriptor
)
public
virtual
broadcast
returns (SablierV2LockupTranched lockupTranched)
{
bytes32 salt = constructCreate2Salt();
lockupTranched =
new SablierV2LockupTranched{ salt: salt }(initialAdmin, initialComptroller, initialNFTDescriptor, maxCount);
}
}
23 changes: 23 additions & 0 deletions script/DeployLockupTranched.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.22 <0.9.0;

import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol";
import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol";
import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol";

import { BaseScript } from "./Base.s.sol";

contract DeployLockupTranched is BaseScript {
function run(
address initialAdmin,
ISablierV2Comptroller initialComptroller,
ISablierV2NFTDescriptor initialNFTDescriptor
)
public
virtual
broadcast
returns (SablierV2LockupTranched lockupTranched)
{
lockupTranched = new SablierV2LockupTranched(initialAdmin, initialComptroller, initialNFTDescriptor, maxCount);
}
}
20 changes: 11 additions & 9 deletions shell/deploy-multi-chain.sh
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ else
# load values from the terminal prompt
echo -e "${WC}Missing '.env.deployment'. Provide details below: ${NC}\n"

# initialize chains with chain id and comptroller
# initialize chains with comptroller
initialize_interactive

fi
Expand Down Expand Up @@ -199,10 +199,10 @@ for ((i=1; i<=$#; i++)); do
# Sort the names
sorted_names=($(printf "%s\n" "${names[@]}" | sort))
# Print the header
printf "\nSupported chains: \n%-20s %-20s\n" "Chain Name" "Chain ID"
printf "%-20s %-20s\n" "-----------" "-----------"
printf "\nSupported chains: \n%-20s %-20s\n" "Chain Name"
printf "%-20s %-20s\n" "-----------"

# Print the chains and their Chain IDs
# Print the supported chains
for chain in "${sorted_names[@]}"; do
IFS=' ' read -r rpc_url api_key admin comptroller <<< "${chains[$chain]}"

Expand All @@ -217,7 +217,7 @@ for ((i=1; i<=$#; i++)); do
INTERACTIVE=true
echo -e "Interactive mode activated. Provide details below: \n"

# initialize only chain id and comptroller
# initialize only comptroller
initialize_interactive
fi

Expand Down Expand Up @@ -330,9 +330,9 @@ for chain in "${provided_chains[@]}"; do
# echo removes single quotes
####################################################################
if [[ ${READ_ONLY} == true ]]; then
deployment_command+=("--sig" "'run(address,address,uint256)'")
deployment_command+=("--sig" "'run(address,address)'")
else
deployment_command+=("--sig" "run(address,address,uint256)")
deployment_command+=("--sig" "run(address,address)")
fi
else
# Construct the command
Expand All @@ -344,9 +344,9 @@ for chain in "${provided_chains[@]}"; do
deployment_command+=("--rpc-url" "${rpc_url}")

if [[ ${READ_ONLY} == true ]]; then
deployment_command+=("--sig" "'run(address,address,uint256)'")
deployment_command+=("--sig" "'run(address,address)'")
else
deployment_command+=("--sig" "run(address,address,uint256)")
deployment_command+=("--sig" "run(address,address)")
fi
fi

Expand Down Expand Up @@ -389,12 +389,14 @@ for chain in "${provided_chains[@]}"; do
# Extract and save contract addresses
lockupDynamic_address=$(echo "${output}" | awk '/lockupDynamic: contract/{print $NF}')
lockupLinear_address=$(echo "${output}" | awk '/lockupLinear: contract/{print $NF}')
lockupTranched_address=$(echo "${output}" | awk '/lockupTranched: contract/{print $NF}')
nftDescriptor_address=$(echo "${output}" | awk '/nftDescriptor: contract/{print $NF}')

# Save to the chain file
{
echo "SablierV2LockupDynamic = ${lockupDynamic_address}"
echo "SablierV2LockupLinear = ${lockupLinear_address}"
echo "SablierV2LockupTranched = ${lockupTranched_address}"
echo "SablierV2NFTDescriptor = ${nftDescriptor_address}"
} >> "$chain_file"

Expand Down
2 changes: 2 additions & 0 deletions shell/prepare-artifacts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ FOUNDRY_PROFILE=optimized forge build
cp out-optimized/SablierV2Comptroller.sol/SablierV2Comptroller.json $artifacts
cp out-optimized/SablierV2LockupDynamic.sol/SablierV2LockupDynamic.json $artifacts
cp out-optimized/SablierV2LockupLinear.sol/SablierV2LockupLinear.json $artifacts
cp out-optimized/SablierV2LockupTranched.sol/SablierV2LockupTranched.json $artifacts
cp out-optimized/SablierV2NFTDescriptor.sol/SablierV2NFTDescriptor.json $artifacts

interfaces=./artifacts/interfaces
Expand All @@ -34,6 +35,7 @@ cp out-optimized/ISablierV2Comptroller.sol/ISablierV2Comptroller.json $interface
cp out-optimized/ISablierV2Lockup.sol/ISablierV2Lockup.json $interfaces
cp out-optimized/ISablierV2LockupDynamic.sol/ISablierV2LockupDynamic.json $interfaces
cp out-optimized/ISablierV2LockupLinear.sol/ISablierV2LockupLinear.json $interfaces
cp out-optimized/ISablierV2LockupTranched.sol/ISablierV2LockupTranched.json $interfaces
cp out-optimized/ISablierV2NFTDescriptor.sol/ISablierV2NFTDescriptor.json $interfaces

erc20=./artifacts/interfaces/erc20
Expand Down
2 changes: 2 additions & 0 deletions shell/update-precompiles.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ FOUNDRY_PROFILE=optimized forge build
comptroller=$(cat out-optimized/SablierV2Comptroller.sol/SablierV2Comptroller.json | jq -r '.bytecode.object' | cut -c 3-)
lockup_dynamic=$(cat out-optimized/SablierV2LockupDynamic.sol/SablierV2LockupDynamic.json | jq -r '.bytecode.object' | cut -c 3-)
lockup_linear=$(cat out-optimized/SablierV2LockupLinear.sol/SablierV2LockupLinear.json | jq -r '.bytecode.object' | cut -c 3-)
lockup_tranched=$(cat out-optimized/SablierV2LockupTranched.sol/SablierV2LockupTranched.json | jq -r '.bytecode.object' | cut -c 3-)
nft_descriptor=$(cat out-optimized/SablierV2NFTDescriptor.sol/SablierV2NFTDescriptor.json | jq -r '.bytecode.object' | cut -c 3-)

precompiles_path="test/utils/Precompiles.sol"
Expand All @@ -27,6 +28,7 @@ fi
sd "(BYTECODE_COMPTROLLER =)[^;]+;" "\$1 hex\"$comptroller\";" $precompiles_path
sd "(BYTECODE_LOCKUP_DYNAMIC =)[^;]+;" "\$1 hex\"$lockup_dynamic\";" $precompiles_path
sd "(BYTECODE_LOCKUP_LINEAR =)[^;]+;" "\$1 hex\"$lockup_linear\";" $precompiles_path
sd "(BYTECODE_LOCKUP_TRANCHED =)[^;]+;" "\$1 hex\"$lockup_tranched\";" $precompiles_path
sd "(BYTECODE_NFT_DESCRIPTOR =)[^;]+;" "\$1 hex\"$nft_descriptor\";" $precompiles_path

# Reformat the code with Forge
Expand Down
1 change: 1 addition & 0 deletions src/SablierV2LockupDynamic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ contract SablierV2LockupDynamic is
notNull(streamId)
returns (LockupDynamic.StreamLD memory stream)
{
// Retrieve the lockup stream from storage.
Lockup.Stream memory lockupStream = _streams[streamId];

// Settled streams cannot be canceled.
Expand Down
1 change: 1 addition & 0 deletions src/SablierV2LockupLinear.sol
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ contract SablierV2LockupLinear is
notNull(streamId)
returns (LockupLinear.StreamLL memory stream)
{
// Retrieve the lockup stream from storage.
Lockup.Stream memory lockupStream = _streams[streamId];

// Settled streams cannot be canceled.
Expand Down
Loading

0 comments on commit 34fee6b

Please sign in to comment.