diff --git a/bun.lockb b/bun.lockb index d3bf753..f145dcd 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/flow/FlowBatchable.sol b/flow/FlowBatchable.sol new file mode 100644 index 0000000..913b395 --- /dev/null +++ b/flow/FlowBatchable.sol @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { ud21x18, UD21x18 } from "@prb/math/src/UD21x18.sol"; +import { ud60x18, UD60x18 } from "@prb/math/src/UD60x18.sol"; + +import { Broker, SablierFlow } from "@sablier/flow/src/SablierFlow.sol"; + +/// @dev The `Batch` contract, inherited in SablierFlow, allows multiple function calls to be batched together. +/// This enables any possible combination of functions to be executed within a single transaction. +contract FlowBatchable { + IERC20 public constant USDC = IERC20(0xf08A50178dfcDe18524640EA6618a1f965821715); + SablierFlow public immutable SABLIER_FLOW; + + constructor(SablierFlow sablierFlow_) { + SABLIER_FLOW = sablierFlow_; + } + + /// @dev A function to adjust the rate per second and deposits into a stream. + function adjustRatePerSecondAndDeposit(uint256 streamId) external { + UD21x18 newRatePerSecond = ud21x18(0.0001e18); + uint128 depositAmount = 1000e6; + + // Transfer to this contract the amount to deposit in both streams. + USDC.transferFrom(msg.sender, address(this), depositAmount); + + // Approve the Sablier contract to spend USDC + USDC.approve(address(SABLIER_FLOW), depositAmount); + + // The call data declared as bytes + bytes[] memory calls = new bytes[](2); + calls[0] = abi.encodeCall(SABLIER_FLOW.adjustRatePerSecond, (streamId, newRatePerSecond)); + calls[1] = abi.encodeCall(SABLIER_FLOW.deposit, (streamId, depositAmount, msg.sender, address(0xCAFE))); + + SABLIER_FLOW.batch(calls); + } + + /// @dev A function to create multiple streams in a single transaction. + function createMultiple() external returns (uint256[] memory streamIds) { + address sender = msg.sender; + address firstRecipient = address(0xCAFE); + address secondRecipient = address(0xBEEF); + UD21x18 firstRatePerSecond = ud21x18(0.0001e18); + UD21x18 secondRatePerSecond = ud21x18(0.0002e18); + + // The call data declared as bytes + bytes[] memory calls = new bytes[](2); + calls[0] = abi.encodeCall(SABLIER_FLOW.create, (sender, firstRecipient, firstRatePerSecond, USDC, true)); + calls[1] = abi.encodeCall(SABLIER_FLOW.create, (sender, secondRecipient, secondRatePerSecond, USDC, true)); + + // Prepare the `streamIds` array to return them + uint256 nextStreamId = SABLIER_FLOW.nextStreamId(); + streamIds = new uint256[](2); + streamIds[0] = nextStreamId; + streamIds[1] = nextStreamId + 1; + + // Execute multiple calls in a single transaction using the prepared call data. + SABLIER_FLOW.batch(calls); + } + + /// @dev A function to create a stream and deposit via a broker in a single transaction. + function createAndDepositViaBroker() external returns (uint256 streamId) { + address sender = msg.sender; + address recipient = address(0xCAFE); + UD21x18 ratePerSecond = ud21x18(0.0001e18); + uint128 depositAmount = 1000e6; + + // The broker struct + Broker memory broker = Broker({ + account: address(0xDEAD), + fee: ud60x18(0.0001e18) // the fee percentage + }); + + // Transfer to this contract the amount to deposit in both streams. + USDC.transferFrom(msg.sender, address(this), depositAmount); + + // Approve the Sablier contract to spend USDC + USDC.approve(address(SABLIER_FLOW), depositAmount); + + streamId = SABLIER_FLOW.nextStreamId(); + + // The call data declared as bytes + bytes[] memory calls = new bytes[](2); + calls[0] = abi.encodeCall(SABLIER_FLOW.create, (sender, recipient, ratePerSecond, USDC, true)); + calls[1] = abi.encodeCall(SABLIER_FLOW.depositViaBroker, (streamId, depositAmount, sender, recipient, broker)); + + // Execute multiple calls in a single transaction using the prepared call data. + SABLIER_FLOW.batch(calls); + } + + /// @dev A function to create multiple streams and deposit via a broker in a single transaction. + function createMultipleAndDepositViaBroker() external returns (uint256[] memory streamIds) { + address sender = msg.sender; + address firstRecipient = address(0xCAFE); + address secondRecipient = address(0xBEEF); + UD21x18 ratePerSecond = ud21x18(0.0001e18); + uint128 depositAmount = 1000e6; + + // Transfer the deposit amount of USDC tokens to this contract for both streams + USDC.transferFrom(msg.sender, address(this), 2 * depositAmount); + + // Approve the Sablier contract to spend USDC + USDC.approve(address(SABLIER_FLOW), 2 * depositAmount); + + // The broker struct + Broker memory broker = Broker({ + account: address(0xDEAD), + fee: ud60x18(0.0001e18) // the fee percentage + }); + + uint256 nextStreamId = SABLIER_FLOW.nextStreamId(); + streamIds = new uint256[](2); + streamIds[0] = nextStreamId; + streamIds[1] = nextStreamId + 1; + + // We need to have 4 different function calls, 2 for creating streams and 2 for depositing via broker + bytes[] memory calls = new bytes[](4); + calls[0] = abi.encodeCall(SABLIER_FLOW.create, (sender, firstRecipient, ratePerSecond, USDC, true)); + calls[1] = abi.encodeCall(SABLIER_FLOW.create, (sender, secondRecipient, ratePerSecond, USDC, true)); + calls[2] = + abi.encodeCall(SABLIER_FLOW.depositViaBroker, (streamIds[0], depositAmount, sender, firstRecipient, broker)); + calls[3] = abi.encodeCall( + SABLIER_FLOW.depositViaBroker, (streamIds[1], depositAmount, sender, secondRecipient, broker) + ); + + // Execute multiple calls in a single transaction using the prepared call data. + SABLIER_FLOW.batch(calls); + } + + /// @dev A function to pause a stream and withdraw the maximum available funds. + function pauseAndWithdrawMax(uint256 streamId) external { + // The call data declared as bytes + bytes[] memory calls = new bytes[](2); + calls[0] = abi.encodeCall(SABLIER_FLOW.pause, (streamId)); + calls[1] = abi.encodeCall(SABLIER_FLOW.withdrawMax, (streamId, address(0xCAFE))); + + // Execute multiple calls in a single transaction using the prepared call data. + SABLIER_FLOW.batch(calls); + } + + /// @dev A function to void a stream and withdraw what is left. + function voidAndWithdrawMax(uint256 streamId) external { + // The call data declared as bytes + bytes[] memory calls = new bytes[](2); + calls[0] = abi.encodeCall(SABLIER_FLOW.void, (streamId)); + calls[1] = abi.encodeCall(SABLIER_FLOW.withdrawMax, (streamId, address(0xCAFE))); + + // Execute multiple calls in a single transaction using the prepared call data. + SABLIER_FLOW.batch(calls); + } + + /// @dev A function to withdraw maximum available funds from multiple streams in a single transaction. + function withdrawMaxMultiple(uint256[] calldata streamIds) external { + uint256 count = streamIds.length; + + // Iterate over the streamIds and prepare the call data for each stream + bytes[] memory calls = new bytes[](count); + for (uint256 i = 0; i < count; ++i) { + address recipient = SABLIER_FLOW.getRecipient(streamIds[i]); + calls[i] = abi.encodeCall(SABLIER_FLOW.withdrawMax, (streamIds[i], recipient)); + } + + // Execute multiple calls in a single transaction using the prepared call data. + SABLIER_FLOW.batch(calls); + } +} diff --git a/flow/FlowBatchable.t.sol b/flow/FlowBatchable.t.sol new file mode 100644 index 0000000..0d38352 --- /dev/null +++ b/flow/FlowBatchable.t.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { Test } from "forge-std/src/Test.sol"; + +import { FlowBatchable } from "./FlowBatchable.sol"; + +import { IFlowNFTDescriptor, SablierFlow } from "@sablier/flow/src/SablierFlow.sol"; + +contract FlowBatchable_Test is Test { + FlowBatchable internal batchable; + SablierFlow internal flow; + address internal user; + + function setUp() external { + // Fork Ethereum Sepolia + vm.createSelectFork({ urlOrAlias: "sepolia", blockNumber: 6_240_816 }); + + // Deploy a SablierFlow contract + flow = new SablierFlow({ initialAdmin: address(this), initialNFTDescriptor: IFlowNFTDescriptor(address(this)) }); + + // Deploy the batchable contract + batchable = new FlowBatchable(flow); + + user = makeAddr("User"); + + // Mint some DAI tokens to the test user, which will be pulled by the creator contract + deal({ token: address(batchable.USDC()), to: user, give: 1_000_000e6 }); + + // Make the test user the `msg.sender` in all following calls + vm.startPrank({ msgSender: user }); + + // Approve the batchable contract to pull USDC tokens from the test user + batchable.USDC().approve({ spender: address(batchable), value: 1_000_000e6 }); + } + + function test_CreateMultiple() external { + uint256 nextStreamIdBefore = flow.nextStreamId(); + + uint256[] memory actualStreamIds = batchable.createMultiple(); + uint256[] memory expectedStreamIds = new uint256[](2); + expectedStreamIds[0] = nextStreamIdBefore; + expectedStreamIds[1] = nextStreamIdBefore + 1; + + assertEq(actualStreamIds, expectedStreamIds); + } + + function test_CreateAndDepositViaBroker() external { + uint256 nextStreamIdBefore = flow.nextStreamId(); + + uint256[] memory actualStreamIds = batchable.createMultipleAndDepositViaBroker(); + uint256[] memory expectedStreamIds = new uint256[](2); + expectedStreamIds[0] = nextStreamIdBefore; + expectedStreamIds[1] = nextStreamIdBefore + 1; + + assertEq(actualStreamIds, expectedStreamIds); + } +} diff --git a/flow/FlowManager.sol b/flow/FlowManager.sol new file mode 100644 index 0000000..9aa2418 --- /dev/null +++ b/flow/FlowManager.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { ud21x18, UD21x18 } from "@prb/math/src/UD21x18.sol"; + +import { ISablierFlow } from "@sablier/flow/src/interfaces/ISablierFlow.sol"; + +contract FlowManager { + ISablierFlow public immutable sablierFlow; + + constructor(ISablierFlow sablierFlow_) { + sablierFlow = sablierFlow_; + } + + function adjustRatePerSecond(uint256 streamId) external { + sablierFlow.adjustRatePerSecond({ streamId: streamId, newRatePerSecond: ud21x18(0.0001e18) }); + } + + function deposit(uint256 streamId) external { + sablierFlow.deposit(streamId, 3.14159e18, msg.sender, address(0xCAFE)); + } + + function depositAndPause(uint256 streamId) external { + sablierFlow.depositAndPause(streamId, 3.14159e18); + } + + function pause(uint256 streamId) external { + sablierFlow.pause(streamId); + } + + function refund(uint256 streamId) external { + sablierFlow.refund({ streamId: streamId, amount: 1.61803e18 }); + } + + function refundAndPause(uint256 streamId) external { + sablierFlow.refundAndPause({ streamId: streamId, amount: 1.61803e18 }); + } + + function restart(uint256 streamId) external { + sablierFlow.restart({ streamId: streamId, ratePerSecond: ud21x18(0.0001e18) }); + } + + function restartAndDeposit(uint256 streamId) external { + sablierFlow.restartAndDeposit({ streamId: streamId, ratePerSecond: ud21x18(0.0001e18), amount: 2.71828e18 }); + } + + function void(uint256 streamId) external { + sablierFlow.void(streamId); + } + + function withdraw(uint256 streamId) external { + sablierFlow.withdraw({ streamId: streamId, to: address(0xCAFE), amount: 2.71828e18 }); + } + + function withdrawMax(uint256 streamId) external { + sablierFlow.withdrawMax({ streamId: streamId, to: address(0xCAFE) }); + } +} diff --git a/flow/FlowStreamCreator.sol b/flow/FlowStreamCreator.sol new file mode 100644 index 0000000..e62ca8e --- /dev/null +++ b/flow/FlowStreamCreator.sol @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { UD21x18 } from "@prb/math/src/UD21x18.sol"; + +import { ISablierFlow } from "@sablier/flow/src/interfaces/ISablierFlow.sol"; + +import { FlowUtilities } from "./FlowUtilities.sol"; + +contract FlowStreamCreator { + // Mainnet USDC + IERC20 public constant USDC = IERC20(0xf08A50178dfcDe18524640EA6618a1f965821715); + ISablierFlow public immutable sablierFlow; + + constructor(ISablierFlow sablierFlow_) { + sablierFlow = sablierFlow_; + } + + // Create a stream that sends 1000 USDC per month + function createStream_1T_PerMonth() external returns (uint256 streamId) { + UD21x18 ratePerSecond = + FlowUtilities.ratePerSecondWithDuration({ token: address(USDC), amount: 1000e6, duration: 30 days }); + + streamId = sablierFlow.create({ + sender: msg.sender, // The sender will be able to manage the stream + recipient: address(0xCAFE), // The recipient of the streamed assets + ratePerSecond: ratePerSecond, // The rate per second equivalent to 1000 USDC per month + token: USDC, // The token to be streamed + transferable: true // Whether the stream will be transferable or not + }); + } + + // Create a stream that sends 1,000,000 USDC per year + function createStream_1M_PerYear() external returns (uint256 streamId) { + UD21x18 ratePerSecond = + FlowUtilities.ratePerSecondWithDuration({ token: address(USDC), amount: 1_000_000e6, duration: 365 days }); + + streamId = sablierFlow.create({ + sender: msg.sender, // The sender will be able to manage the stream + recipient: address(0xCAFE), // The recipient of the streamed assets + ratePerSecond: ratePerSecond, // The rate per second equivalent to 1,000,00 USDC per year + token: USDC, // The token to be streamed + transferable: true // Whether the stream will be transferable or not + }); + } +} diff --git a/flow/FlowStreamCreator.t.sol b/flow/FlowStreamCreator.t.sol new file mode 100644 index 0000000..bdc3e62 --- /dev/null +++ b/flow/FlowStreamCreator.t.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { Test } from "forge-std/src/Test.sol"; + +import { FlowStreamCreator } from "./FlowStreamCreator.sol"; + +import { IFlowNFTDescriptor, SablierFlow } from "@sablier/flow/src/SablierFlow.sol"; + +contract FlowStreamCreator_Test is Test { + FlowStreamCreator internal streamCreator; + SablierFlow internal flow; + address internal user; + + function setUp() external { + // Fork Ethereum Sepolia + vm.createSelectFork({ urlOrAlias: "sepolia", blockNumber: 6_240_816 }); + + // Deploy a SablierFlow contract + flow = new SablierFlow({ initialAdmin: address(this), initialNFTDescriptor: IFlowNFTDescriptor(address(this)) }); + + // Deploy the FlowStreamCreator contract + streamCreator = new FlowStreamCreator(flow); + + user = makeAddr("User"); + + // Mint some DAI tokens to the test user, which will be pulled by the creator contract + deal({ token: address(streamCreator.USDC()), to: user, give: 1_000_000e6 }); + + // Make the test user the `msg.sender` in all following calls + vm.startPrank({ msgSender: user }); + + // Approve the streamCreator contract to pull USDC tokens from the test user + streamCreator.USDC().approve({ spender: address(streamCreator), value: 1_000_000e6 }); + } + + function test_CreateStream_1T_PerMonth() external { + uint256 expectedStreamId = flow.nextStreamId(); + + uint256 actualStreamId = streamCreator.createStream_1T_PerMonth(); + assertEq(actualStreamId, expectedStreamId); + + // Warp more than 30 days into the future to see if the debt accumulated is more than 1 thousand + vm.warp({ newTimestamp: block.timestamp + 30 days + 1 seconds }); + + assertGe(flow.totalDebtOf(actualStreamId), 1000e6); + } + + function test_CreateStream_1M_PerYear() external { + uint256 expectedStreamId = flow.nextStreamId(); + + uint256 actualStreamId = streamCreator.createStream_1M_PerYear(); + assertEq(actualStreamId, expectedStreamId); + + // Warp more than 30 days into the future to see if the debt accumulated is more than 1 thousand + vm.warp({ newTimestamp: block.timestamp + 365 days + 1 seconds }); + + assertGe(flow.totalDebtOf(actualStreamId), 1_000_000e6); + } +} diff --git a/flow/FlowUtilities.sol b/flow/FlowUtilities.sol new file mode 100644 index 0000000..f9bcccf --- /dev/null +++ b/flow/FlowUtilities.sol @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import { ud21x18, UD21x18 } from "@prb/math/src/UD21x18.sol"; + +/// @dev A utility library to calculate the rate per second for a given amount of tokens over a specific duration, and +/// the amounts streamed over various periods of time. +library FlowUtilities { + /// @notice This function calculates the rate per second for a given amount of tokens for a specific duration. + /// @dev The rate per second is a 18 decimal fixed-point number and it is calculated as `amount / duration`. + /// @param token The address of the token. + /// @param amount The amount of tokens, denoted in token's decimals. + /// @param duration The duration in seconds wished to stream. + /// @return ratePerSecond The rate per second as a fixed-point number. + function ratePerSecondWithDuration( + address token, + uint128 amount, + uint40 duration + ) + internal + view + returns (UD21x18 ratePerSecond) + { + // Get the decimals of the token. + uint8 decimals = IERC20Metadata(token).decimals(); + + // If the token has 18 decimals, we can simply divide the amount by the duration as it returns a 18 decimal + // fixed-point number. + if (decimals == 18) { + return ud21x18(amount / duration); + } + + // Calculate the scale factor from the token's decimals. + uint128 scaleFactor = uint128(10 ** (18 - decimals)); + + // Multiply the amount by the scale factor and divide by the duration. + ratePerSecond = ud21x18(scaleFactor * amount / duration); + } + + /// @notice This function calculates the rate per second for a given amount of tokens for a specific range of time. + /// @dev The rate per second is a 18 decimal fixed-point number and it is calculated as `amount / (end - start)`. + /// @param token The address of the token. + /// @param amount The amount of tokens, denoted in token's decimals. + /// @param start The start timestamp. + /// @param end The end timestamp. + /// @return ratePerSecond The rate per second as a fixed-point number. + function ratePerSecondForTimestamps( + address token, + uint128 amount, + uint40 start, + uint40 end + ) + internal + view + returns (UD21x18 ratePerSecond) + { + // Get the decimals of the token. + uint8 decimals = IERC20Metadata(token).decimals(); + + // Calculate the duration. + uint40 duration = end - start; + + if (decimals < 18) { + return ud21x18(amount / duration); + } + + // Calculate the scale factor from the token's decimals. + uint128 scaleFactor = uint128(10 ** (18 - decimals)); + + // Multiply the amount by the scale factor and divide by the duration. + ratePerSecond = ud21x18(scaleFactor * amount / duration); + } + + /// @notice This function calculates the amount streamed over a week for a given rate per second. + /// @param ratePerSecond The rate per second as a fixed-point number. + /// @return amountPerWeek The amount streamed over a week. + function calculateAmountStreamedPerWeek(UD21x18 ratePerSecond) internal pure returns (uint128 amountPerWeek) { + amountPerWeek = ratePerSecond.unwrap() * 1 weeks; + } + + /// @notice This function calculates the amount streamed over a month for a given rate per second. + /// @dev We use 30 days as the number of days in a month. + /// @param ratePerSecond The rate per second as a fixed-point number. + /// @return amountPerMonth The amount streamed over a month. + function calculateAmountStreamedPerMonth(UD21x18 ratePerSecond) internal pure returns (uint128 amountPerMonth) { + amountPerMonth = ratePerSecond.unwrap() * 30 days; + } + + /// @notice This function calculates the amount streamed over a year for a given rate per second. + /// @dev We use 365 days as the number of days in a year. + /// @param ratePerSecond The rate per second as a fixed-point number. + /// @return amountPerYear The amount streamed over a year. + function calculateAmountStreamedPerYear(UD21x18 ratePerSecond) internal pure returns (uint128 amountPerYear) { + amountPerYear = ratePerSecond.unwrap() * 365 days; + } +} diff --git a/foundry.toml b/foundry.toml index 26fd21e..a71c655 100644 --- a/foundry.toml +++ b/foundry.toml @@ -8,8 +8,14 @@ optimizer = true optimizer_runs = 5000 out = "out" solc = "0.8.26" -src = "v2" -test = "v2" + +[profile.lockup] +src = "lockup" +test = "lockup" + +[profile.flow] +src = "flow" +test = "flow" [fmt] bracket_spacing = true diff --git a/v2/core/LockupDynamicCurvesCreator.sol b/lockup/core/LockupDynamicCurvesCreator.sol similarity index 100% rename from v2/core/LockupDynamicCurvesCreator.sol rename to lockup/core/LockupDynamicCurvesCreator.sol diff --git a/v2/core/LockupDynamicCurvesCreator.t.sol b/lockup/core/LockupDynamicCurvesCreator.t.sol similarity index 100% rename from v2/core/LockupDynamicCurvesCreator.t.sol rename to lockup/core/LockupDynamicCurvesCreator.t.sol diff --git a/v2/core/LockupDynamicStreamCreator.sol b/lockup/core/LockupDynamicStreamCreator.sol similarity index 100% rename from v2/core/LockupDynamicStreamCreator.sol rename to lockup/core/LockupDynamicStreamCreator.sol diff --git a/v2/core/LockupLinearStreamCreator.sol b/lockup/core/LockupLinearStreamCreator.sol similarity index 100% rename from v2/core/LockupLinearStreamCreator.sol rename to lockup/core/LockupLinearStreamCreator.sol diff --git a/v2/core/LockupStreamCreator.t.sol b/lockup/core/LockupStreamCreator.t.sol similarity index 100% rename from v2/core/LockupStreamCreator.t.sol rename to lockup/core/LockupStreamCreator.t.sol diff --git a/v2/core/LockupTranchedStreamCreator.sol b/lockup/core/LockupTranchedStreamCreator.sol similarity index 100% rename from v2/core/LockupTranchedStreamCreator.sol rename to lockup/core/LockupTranchedStreamCreator.sol diff --git a/v2/core/RecipientHooks.sol b/lockup/core/RecipientHooks.sol similarity index 100% rename from v2/core/RecipientHooks.sol rename to lockup/core/RecipientHooks.sol diff --git a/v2/core/StreamManagement.sol b/lockup/core/StreamManagement.sol similarity index 100% rename from v2/core/StreamManagement.sol rename to lockup/core/StreamManagement.sol diff --git a/v2/periphery/AirstreamCreator.sol b/lockup/periphery/AirstreamCreator.sol similarity index 100% rename from v2/periphery/AirstreamCreator.sol rename to lockup/periphery/AirstreamCreator.sol diff --git a/v2/periphery/AirstreamCreator.t.sol b/lockup/periphery/AirstreamCreator.t.sol similarity index 100% rename from v2/periphery/AirstreamCreator.t.sol rename to lockup/periphery/AirstreamCreator.t.sol diff --git a/v2/periphery/BatchLDStreamCreator.sol b/lockup/periphery/BatchLDStreamCreator.sol similarity index 100% rename from v2/periphery/BatchLDStreamCreator.sol rename to lockup/periphery/BatchLDStreamCreator.sol diff --git a/v2/periphery/BatchLLStreamCreator.sol b/lockup/periphery/BatchLLStreamCreator.sol similarity index 100% rename from v2/periphery/BatchLLStreamCreator.sol rename to lockup/periphery/BatchLLStreamCreator.sol diff --git a/v2/periphery/BatchLTStreamCreator.sol b/lockup/periphery/BatchLTStreamCreator.sol similarity index 100% rename from v2/periphery/BatchLTStreamCreator.sol rename to lockup/periphery/BatchLTStreamCreator.sol diff --git a/v2/periphery/BatchStreamCreator.t.sol b/lockup/periphery/BatchStreamCreator.t.sol similarity index 100% rename from v2/periphery/BatchStreamCreator.t.sol rename to lockup/periphery/BatchStreamCreator.t.sol diff --git a/package.json b/package.json index 12fac0c..657b66e 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,8 @@ }, "dependencies": { "@openzeppelin/contracts": "5.0.2", - "@prb/math": "4.0.3", + "@prb/math": "4.1.0", + "@sablier/flow": "github:sablier-labs/flow#main", "@sablier/v2-core": "1.2.0", "@sablier/v2-periphery": "1.2.0" }, @@ -40,10 +41,14 @@ "private": true, "repository": "github.com:sablier-labs/examples", "scripts": { + "build:flow": "FOUNDRY_PROFILE=flow forge build", + "build:lockup": "FOUNDRY_PROFILE=lockup forge build", "clean": "rm -rf cache out", "lint": "bun run lint:sol && bun run prettier:check", "lint:sol": "forge fmt --check && bun solhint \"{script,src,test}/**/*.sol\"", "prettier:check": "prettier --check \"**/*.{json,md,yml}\"", - "prettier:write": "prettier --write \"**/*.{json,md,yml}\"" + "prettier:write": "prettier --write \"**/*.{json,md,yml}\"", + "test:flow": "FOUNDRY_PROFILE=flow forge test", + "test:lockup": "FOUNDRY_PROFILE=lockup forge test" } } diff --git a/remappings.txt b/remappings.txt index 86e658e..8331950 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,5 +1,6 @@ @openzeppelin/contracts/=node_modules/@openzeppelin/contracts/ @prb/math/=node_modules/@prb/math/ +@sablier/flow/=node_modules/@sablier/flow/ @sablier/v2-core/=node_modules/@sablier/v2-core/ @sablier/v2-periphery/=node_modules/@sablier/v2-periphery/ forge-std/=node_modules/forge-std/