Skip to content

feat: function to calculate min fee in wei for a given stream ID #1270

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions bun.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"dependencies": {
"@openzeppelin/contracts": "5.3.0",
"@prb/math": "4.1.0",
"@sablier/evm-utils": "github:sablier-labs/evm-utils",
"@sablier/evm-utils": "github:sablier-labs/evm-utils#31f94ff",
},
"devDependencies": {
"@sablier/devkit": "github:sablier-labs/devkit",
Expand Down Expand Up @@ -172,7 +172,7 @@

"@sablier/devkit": ["@sablier/devkit@github:sablier-labs/devkit#16816ca", {}, "sablier-labs-devkit-16816ca"],

"@sablier/evm-utils": ["@sablier/evm-utils@github:sablier-labs/evm-utils#cc3a85c", { "dependencies": { "@chainlink/contracts": "1.3.0" } }, "sablier-labs-evm-utils-cc3a85c"],
"@sablier/evm-utils": ["@sablier/evm-utils@github:sablier-labs/evm-utils#31f94ff", { "dependencies": { "@chainlink/contracts": "1.3.0" } }, "sablier-labs-evm-utils-31f94ff"],

"@scroll-tech/contracts": ["@scroll-tech/[email protected]", "", {}, "sha512-aBbDOc3WB/WveZdpJYcrfvMYMz7ZTEiW8M9XMJLba8p9FAR5KGYB/cV+8+EUsq3MKt7C1BfR+WnXoTVdvwIY6w=="],

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"dependencies": {
"@openzeppelin/contracts": "5.3.0",
"@prb/math": "4.1.0",
"@sablier/evm-utils": "github:sablier-labs/evm-utils"
"@sablier/evm-utils": "github:sablier-labs/evm-utils#31f94ff"
},
"devDependencies": {
"@sablier/devkit": "github:sablier-labs/devkit",
Expand Down
23 changes: 22 additions & 1 deletion src/SablierLockup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions
import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import { Batch } from "@sablier/evm-utils/src/Batch.sol";
import { Comptrollerable } from "@sablier/evm-utils/src/Comptrollerable.sol";
import { ISablierComptroller } from "@sablier/evm-utils/src/interfaces/ISablierComptroller.sol";

import { SablierLockupDynamic } from "./abstracts/SablierLockupDynamic.sol";
import { SablierLockupLinear } from "./abstracts/SablierLockupLinear.sol";
Expand Down Expand Up @@ -64,6 +65,21 @@ contract SablierLockup is
USER-FACING READ-ONLY FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/

/// @inheritdoc ISablierLockup
function calculateMinFeeWei(uint256 streamId)
external
view
override
notNull(streamId)
returns (uint256 minFeeWei)
{
// Calculate the minimum fee in wei for the stream sender.
minFeeWei = comptroller.calculateMinFeeWeiFor({
protocol: ISablierComptroller.Protocol.Lockup,
user: _streams[streamId].sender
});
}

/// @inheritdoc ISablierLockup
function getRecipient(uint256 streamId) external view override returns (address recipient) {
// Check the stream NFT exists and return the owner, which is the stream's recipient.
Expand Down Expand Up @@ -645,7 +661,12 @@ contract SablierLockup is

/// @dev See the documentation for the user-facing functions that call this private function.
function _withdraw(uint256 streamId, address to, uint128 amount) private {
uint256 minFeeWei = comptroller.calculateLockupMinFeeWeiFor(_streams[streamId].sender);
// Calculate the minimum fee in wei for the stream sender.
uint256 minFeeWei = comptroller.calculateMinFeeWeiFor({
protocol: ISablierComptroller.Protocol.Lockup,
user: _streams[streamId].sender
});

uint256 feePaid = msg.value;

// Check: fee paid is at least the minimum fee.
Expand Down
5 changes: 5 additions & 0 deletions src/interfaces/ISablierLockup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ interface ISablierLockup is
USER-FACING READ-ONLY FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/

/// @notice Calculates the minimum fee in wei required to withdraw from the given stream ID.
/// @dev Reverts if `streamId` references a null stream.
/// @param streamId The stream ID for the query.
function calculateMinFeeWei(uint256 streamId) external view returns (uint256 minFeeWei);

/// @notice Retrieves the stream's recipient.
/// @dev Reverts if the NFT has been burned.
/// @param streamId The stream ID for the query.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.22 <0.9.0;

import { ISablierComptroller } from "@sablier/evm-utils/src/interfaces/ISablierComptroller.sol";

import { Integration_Test } from "../../../Integration.t.sol";

contract CalculateMinFeeWeiFor_Integration_Concrete_Test is Integration_Test {
function test_RevertGiven_Null() external {
expectRevert_Null({ callData: abi.encodeCall(lockup.calculateMinFeeWei, ids.nullStream) });
}

function test_GivenCustomFeeSet() external givenNotNull {
setMsgSender(admin);

uint256 customFeeUSD = 100e8; // 100 USD.

// Set the custom fee.
comptroller.setCustomFeeUSDFor({
protocol: ISablierComptroller.Protocol.Lockup,
user: users.sender,
customFeeUSD: customFeeUSD
});

uint256 expectedFeeWei = (1e18 * customFeeUSD) / ETH_PRICE_USD;

// It should return the custom fee in wei.
assertEq(lockup.calculateMinFeeWei(ids.defaultStream), expectedFeeWei, "customFeeWei");
}

function test_GivenCustomFeeNotSet() external view givenNotNull {
// It should return the minimum fee in wei.
assertEq(lockup.calculateMinFeeWei(ids.defaultStream), LOCKUP_MIN_FEE_WEI, "minFeeWei");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CalculateMinFeeWeiFor_Integration_Concrete_Test
├── given null
│ └── it should revert
└── given not null
├── given custom fee set
│ └── it should return the custom fee in wei
└── given custom fee not set
└── it should return the minimum fee in wei
Loading