Skip to content

Commit 9fedb7a

Browse files
committed
chore: polish flow examples
1 parent 8bb3f4c commit 9fedb7a

10 files changed

+109
-102
lines changed

.solhint.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,13 @@
66
"contract-name-camelcase": "off",
77
"func-name-mixedcase": "off",
88
"func-visibility": ["error", { "ignoreConstructors": true }],
9+
"gas-custom-errors": "off",
10+
"immutable-vars-naming": "off",
911
"max-line-length": ["error", 124],
1012
"named-parameters-mapping": "warn",
1113
"no-console": "off",
12-
"not-rely-on-time": "off"
14+
"no-empty-blocks": "off",
15+
"not-rely-on-time": "off",
16+
"one-contract-per-file": "off"
1317
}
1418
}

bun.lockb

-5 Bytes
Binary file not shown.

flow/FlowBatchable.sol

Lines changed: 68 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -3,60 +3,41 @@ pragma solidity >=0.8.22;
33

44
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
55
import { ud21x18, UD21x18 } from "@prb/math/src/UD21x18.sol";
6-
import { ud60x18, UD60x18 } from "@prb/math/src/UD60x18.sol";
6+
import { ud60x18 } from "@prb/math/src/UD60x18.sol";
77

88
import { Broker, SablierFlow } from "@sablier/flow/src/SablierFlow.sol";
99

10-
/// @dev The `Batch` contract, inherited in SablierFlow, allows multiple function calls to be batched together.
11-
/// This enables any possible combination of functions to be executed within a single transaction.
10+
/// @notice The `Batch` contract, inherited in SablierFlow, allows multiple function calls to be batched together. This
11+
/// enables any possible combination of functions to be executed within a single transaction.
12+
/// @dev For some functions to work, `msg.sender` must have approved this contract to spend USDC.
1213
contract FlowBatchable {
1314
IERC20 public constant USDC = IERC20(0xf08A50178dfcDe18524640EA6618a1f965821715);
14-
SablierFlow public immutable SABLIER_FLOW;
15+
SablierFlow public immutable sablierFlow;
1516

1617
constructor(SablierFlow sablierFlow_) {
17-
SABLIER_FLOW = sablierFlow_;
18+
sablierFlow = sablierFlow_;
1819
}
1920

20-
/// @dev A function to adjust the rate per second and deposits into a stream.
21+
/// @dev A function to adjust the rate per second and deposit into a stream in a single transaction.
2122
function adjustRatePerSecondAndDeposit(uint256 streamId) external {
2223
UD21x18 newRatePerSecond = ud21x18(0.0001e18);
2324
uint128 depositAmount = 1000e6;
2425

25-
// Transfer to this contract the amount to deposit in both streams.
26+
// Transfer to this contract the amount to deposit in the stream.
2627
USDC.transferFrom(msg.sender, address(this), depositAmount);
2728

28-
// Approve the Sablier contract to spend USDC
29-
USDC.approve(address(SABLIER_FLOW), depositAmount);
29+
// Approve the Sablier contract to spend USDC.
30+
USDC.approve(address(sablierFlow), depositAmount);
3031

31-
// The call data declared as bytes
32-
bytes[] memory calls = new bytes[](2);
33-
calls[0] = abi.encodeCall(SABLIER_FLOW.adjustRatePerSecond, (streamId, newRatePerSecond));
34-
calls[1] = abi.encodeCall(SABLIER_FLOW.deposit, (streamId, depositAmount, msg.sender, address(0xCAFE)));
35-
36-
SABLIER_FLOW.batch(calls);
37-
}
38-
39-
/// @dev A function to create multiple streams in a single transaction.
40-
function createMultiple() external returns (uint256[] memory streamIds) {
41-
address sender = msg.sender;
42-
address firstRecipient = address(0xCAFE);
43-
address secondRecipient = address(0xBEEF);
44-
UD21x18 firstRatePerSecond = ud21x18(0.0001e18);
45-
UD21x18 secondRatePerSecond = ud21x18(0.0002e18);
32+
// Fetch the stream recipient.
33+
address recipient = sablierFlow.getRecipient(streamId);
4634

47-
// The call data declared as bytes
35+
// The call data declared as bytes.
4836
bytes[] memory calls = new bytes[](2);
49-
calls[0] = abi.encodeCall(SABLIER_FLOW.create, (sender, firstRecipient, firstRatePerSecond, USDC, true));
50-
calls[1] = abi.encodeCall(SABLIER_FLOW.create, (sender, secondRecipient, secondRatePerSecond, USDC, true));
51-
52-
// Prepare the `streamIds` array to return them
53-
uint256 nextStreamId = SABLIER_FLOW.nextStreamId();
54-
streamIds = new uint256[](2);
55-
streamIds[0] = nextStreamId;
56-
streamIds[1] = nextStreamId + 1;
37+
calls[0] = abi.encodeCall(sablierFlow.adjustRatePerSecond, (streamId, newRatePerSecond));
38+
calls[1] = abi.encodeCall(sablierFlow.deposit, (streamId, depositAmount, msg.sender, recipient));
5739

58-
// Execute multiple calls in a single transaction using the prepared call data.
59-
SABLIER_FLOW.batch(calls);
40+
sablierFlow.batch(calls);
6041
}
6142

6243
/// @dev A function to create a stream and deposit via a broker in a single transaction.
@@ -66,30 +47,53 @@ contract FlowBatchable {
6647
UD21x18 ratePerSecond = ud21x18(0.0001e18);
6748
uint128 depositAmount = 1000e6;
6849

69-
// The broker struct
50+
// The broker struct.
7051
Broker memory broker = Broker({
7152
account: address(0xDEAD),
7253
fee: ud60x18(0.0001e18) // the fee percentage
7354
});
7455

75-
// Transfer to this contract the amount to deposit in both streams.
56+
// Transfer to this contract the amount to deposit in the stream.
7657
USDC.transferFrom(msg.sender, address(this), depositAmount);
7758

78-
// Approve the Sablier contract to spend USDC
79-
USDC.approve(address(SABLIER_FLOW), depositAmount);
59+
// Approve the Sablier contract to spend USDC.
60+
USDC.approve(address(sablierFlow), depositAmount);
8061

81-
streamId = SABLIER_FLOW.nextStreamId();
62+
streamId = sablierFlow.nextStreamId();
8263

8364
// The call data declared as bytes
8465
bytes[] memory calls = new bytes[](2);
85-
calls[0] = abi.encodeCall(SABLIER_FLOW.create, (sender, recipient, ratePerSecond, USDC, true));
86-
calls[1] = abi.encodeCall(SABLIER_FLOW.depositViaBroker, (streamId, depositAmount, sender, recipient, broker));
66+
calls[0] = abi.encodeCall(sablierFlow.create, (sender, recipient, ratePerSecond, USDC, true));
67+
calls[1] = abi.encodeCall(sablierFlow.depositViaBroker, (streamId, depositAmount, sender, recipient, broker));
8768

8869
// Execute multiple calls in a single transaction using the prepared call data.
89-
SABLIER_FLOW.batch(calls);
70+
sablierFlow.batch(calls);
9071
}
9172

92-
/// @dev A function to create multiple streams and deposit via a broker in a single transaction.
73+
/// @dev A function to create multiple streams in a single transaction.
74+
function createMultiple() external returns (uint256[] memory streamIds) {
75+
address sender = msg.sender;
76+
address firstRecipient = address(0xCAFE);
77+
address secondRecipient = address(0xBEEF);
78+
UD21x18 firstRatePerSecond = ud21x18(0.0001e18);
79+
UD21x18 secondRatePerSecond = ud21x18(0.0002e18);
80+
81+
// The call data declared as bytes
82+
bytes[] memory calls = new bytes[](2);
83+
calls[0] = abi.encodeCall(sablierFlow.create, (sender, firstRecipient, firstRatePerSecond, USDC, true));
84+
calls[1] = abi.encodeCall(sablierFlow.create, (sender, secondRecipient, secondRatePerSecond, USDC, true));
85+
86+
// Prepare the `streamIds` array to return them
87+
uint256 nextStreamId = sablierFlow.nextStreamId();
88+
streamIds = new uint256[](2);
89+
streamIds[0] = nextStreamId;
90+
streamIds[1] = nextStreamId + 1;
91+
92+
// Execute multiple calls in a single transaction using the prepared call data.
93+
sablierFlow.batch(calls);
94+
}
95+
96+
/// @dev A function to create multiple streams and deposit via a broker into all the stream in a single transaction.
9397
function createMultipleAndDepositViaBroker() external returns (uint256[] memory streamIds) {
9498
address sender = msg.sender;
9599
address firstRecipient = address(0xCAFE);
@@ -100,68 +104,67 @@ contract FlowBatchable {
100104
// Transfer the deposit amount of USDC tokens to this contract for both streams
101105
USDC.transferFrom(msg.sender, address(this), 2 * depositAmount);
102106

103-
// Approve the Sablier contract to spend USDC
104-
USDC.approve(address(SABLIER_FLOW), 2 * depositAmount);
107+
// Approve the Sablier contract to spend USDC.
108+
USDC.approve(address(sablierFlow), 2 * depositAmount);
105109

106110
// The broker struct
107111
Broker memory broker = Broker({
108112
account: address(0xDEAD),
109113
fee: ud60x18(0.0001e18) // the fee percentage
110114
});
111115

112-
uint256 nextStreamId = SABLIER_FLOW.nextStreamId();
116+
uint256 nextStreamId = sablierFlow.nextStreamId();
113117
streamIds = new uint256[](2);
114118
streamIds[0] = nextStreamId;
115119
streamIds[1] = nextStreamId + 1;
116120

117121
// We need to have 4 different function calls, 2 for creating streams and 2 for depositing via broker
118122
bytes[] memory calls = new bytes[](4);
119-
calls[0] = abi.encodeCall(SABLIER_FLOW.create, (sender, firstRecipient, ratePerSecond, USDC, true));
120-
calls[1] = abi.encodeCall(SABLIER_FLOW.create, (sender, secondRecipient, ratePerSecond, USDC, true));
123+
calls[0] = abi.encodeCall(sablierFlow.create, (sender, firstRecipient, ratePerSecond, USDC, true));
124+
calls[1] = abi.encodeCall(sablierFlow.create, (sender, secondRecipient, ratePerSecond, USDC, true));
121125
calls[2] =
122-
abi.encodeCall(SABLIER_FLOW.depositViaBroker, (streamIds[0], depositAmount, sender, firstRecipient, broker));
123-
calls[3] = abi.encodeCall(
124-
SABLIER_FLOW.depositViaBroker, (streamIds[1], depositAmount, sender, secondRecipient, broker)
125-
);
126+
abi.encodeCall(sablierFlow.depositViaBroker, (streamIds[0], depositAmount, sender, firstRecipient, broker));
127+
calls[3] =
128+
abi.encodeCall(sablierFlow.depositViaBroker, (streamIds[1], depositAmount, sender, secondRecipient, broker));
126129

127130
// Execute multiple calls in a single transaction using the prepared call data.
128-
SABLIER_FLOW.batch(calls);
131+
sablierFlow.batch(calls);
129132
}
130133

131134
/// @dev A function to pause a stream and withdraw the maximum available funds.
132135
function pauseAndWithdrawMax(uint256 streamId) external {
133-
// The call data declared as bytes
136+
// The call data declared as bytes.
134137
bytes[] memory calls = new bytes[](2);
135-
calls[0] = abi.encodeCall(SABLIER_FLOW.pause, (streamId));
136-
calls[1] = abi.encodeCall(SABLIER_FLOW.withdrawMax, (streamId, address(0xCAFE)));
138+
calls[0] = abi.encodeCall(sablierFlow.pause, (streamId));
139+
calls[1] = abi.encodeCall(sablierFlow.withdrawMax, (streamId, address(0xCAFE)));
137140

138141
// Execute multiple calls in a single transaction using the prepared call data.
139-
SABLIER_FLOW.batch(calls);
142+
sablierFlow.batch(calls);
140143
}
141144

142145
/// @dev A function to void a stream and withdraw what is left.
143146
function voidAndWithdrawMax(uint256 streamId) external {
144147
// The call data declared as bytes
145148
bytes[] memory calls = new bytes[](2);
146-
calls[0] = abi.encodeCall(SABLIER_FLOW.void, (streamId));
147-
calls[1] = abi.encodeCall(SABLIER_FLOW.withdrawMax, (streamId, address(0xCAFE)));
149+
calls[0] = abi.encodeCall(sablierFlow.void, (streamId));
150+
calls[1] = abi.encodeCall(sablierFlow.withdrawMax, (streamId, address(0xCAFE)));
148151

149152
// Execute multiple calls in a single transaction using the prepared call data.
150-
SABLIER_FLOW.batch(calls);
153+
sablierFlow.batch(calls);
151154
}
152155

153156
/// @dev A function to withdraw maximum available funds from multiple streams in a single transaction.
154157
function withdrawMaxMultiple(uint256[] calldata streamIds) external {
155158
uint256 count = streamIds.length;
156159

157-
// Iterate over the streamIds and prepare the call data for each stream
160+
// Iterate over the streamIds and prepare the call data for each stream.
158161
bytes[] memory calls = new bytes[](count);
159162
for (uint256 i = 0; i < count; ++i) {
160-
address recipient = SABLIER_FLOW.getRecipient(streamIds[i]);
161-
calls[i] = abi.encodeCall(SABLIER_FLOW.withdrawMax, (streamIds[i], recipient));
163+
address recipient = sablierFlow.getRecipient(streamIds[i]);
164+
calls[i] = abi.encodeCall(sablierFlow.withdrawMax, (streamIds[i], recipient));
162165
}
163166

164167
// Execute multiple calls in a single transaction using the prepared call data.
165-
SABLIER_FLOW.batch(calls);
168+
sablierFlow.batch(calls);
166169
}
167170
}

flow/FlowManager.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// SPDX-License-Identifier: GPL-3.0-or-later
22
pragma solidity >=0.8.22;
33

4-
import { ud21x18, UD21x18 } from "@prb/math/src/UD21x18.sol";
4+
import { ud21x18 } from "@prb/math/src/UD21x18.sol";
55

66
import { ISablierFlow } from "@sablier/flow/src/interfaces/ISablierFlow.sol";
77

flow/FlowStreamCreator.sol

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ contract FlowStreamCreator {
1717
sablierFlow = sablierFlow_;
1818
}
1919

20-
// Create a stream that sends 1000 USDC per month
21-
function createStream_1T_PerMonth() external returns (uint256 streamId) {
20+
// Create a stream that sends 1000 USDC per month.
21+
function createStream_1K_PerMonth() external returns (uint256 streamId) {
2222
UD21x18 ratePerSecond =
2323
FlowUtilities.ratePerSecondWithDuration({ token: address(USDC), amount: 1000e6, duration: 30 days });
2424

@@ -31,7 +31,7 @@ contract FlowStreamCreator {
3131
});
3232
}
3333

34-
// Create a stream that sends 1,000,000 USDC per year
34+
// Create a stream that sends 1,000,000 USDC per year.
3535
function createStream_1M_PerYear() external returns (uint256 streamId) {
3636
UD21x18 ratePerSecond =
3737
FlowUtilities.ratePerSecondWithDuration({ token: address(USDC), amount: 1_000_000e6, duration: 365 days });

flow/FlowStreamCreator.t.sol

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,13 @@ contract FlowStreamCreator_Test is Test {
3434
streamCreator.USDC().approve({ spender: address(streamCreator), value: 1_000_000e6 });
3535
}
3636

37-
function test_CreateStream_1T_PerMonth() external {
37+
function test_CreateStream_1K_PerMonth() external {
3838
uint256 expectedStreamId = flow.nextStreamId();
3939

40-
uint256 actualStreamId = streamCreator.createStream_1T_PerMonth();
40+
uint256 actualStreamId = streamCreator.createStream_1K_PerMonth();
4141
assertEq(actualStreamId, expectedStreamId);
4242

43-
// Warp more than 30 days into the future to see if the debt accumulated is more than 1 thousand
43+
// Warp slightly over 30 days so that the debt accumulated is slightly over 1000 USDC.
4444
vm.warp({ newTimestamp: block.timestamp + 30 days + 1 seconds });
4545

4646
assertGe(flow.totalDebtOf(actualStreamId), 1000e6);
@@ -52,7 +52,7 @@ contract FlowStreamCreator_Test is Test {
5252
uint256 actualStreamId = streamCreator.createStream_1M_PerYear();
5353
assertEq(actualStreamId, expectedStreamId);
5454

55-
// Warp more than 30 days into the future to see if the debt accumulated is more than 1 thousand
55+
// Warp slightly over 365 days so that the debt accumulated is slightly over 1M USDC.
5656
vm.warp({ newTimestamp: block.timestamp + 365 days + 1 seconds });
5757

5858
assertGe(flow.totalDebtOf(actualStreamId), 1_000_000e6);

flow/FlowUtilities.sol

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@ pragma solidity >=0.8.22;
44
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
55
import { ud21x18, UD21x18 } from "@prb/math/src/UD21x18.sol";
66

7-
/// @dev A utility library to calculate the rate per second for a given amount of tokens over a specific duration, and
8-
/// the amounts streamed over various periods of time.
7+
/// @dev A utility library to calculate rate per second and streamed amount based on a given time frame.
98
library FlowUtilities {
10-
/// @notice This function calculates the rate per second for a given amount of tokens for a specific duration.
11-
/// @dev The rate per second is a 18 decimal fixed-point number and it is calculated as `amount / duration`.
9+
/// @notice This function calculates the rate per second based on a given amount of tokens and a specified duration.
10+
/// @dev The rate per second is a 18-decimal fixed-point number and it is calculated as `amount / duration`.
1211
/// @param token The address of the token.
1312
/// @param amount The amount of tokens, denoted in token's decimals.
14-
/// @param duration The duration in seconds wished to stream.
15-
/// @return ratePerSecond The rate per second as a fixed-point number.
13+
/// @param duration The duration in seconds user wishes to stream.
14+
/// @return ratePerSecond The rate per second as a 18-decimal fixed-point number.
1615
function ratePerSecondWithDuration(
1716
address token,
1817
uint128 amount,
@@ -35,16 +34,16 @@ library FlowUtilities {
3534
uint128 scaleFactor = uint128(10 ** (18 - decimals));
3635

3736
// Multiply the amount by the scale factor and divide by the duration.
38-
ratePerSecond = ud21x18(scaleFactor * amount / duration);
37+
ratePerSecond = ud21x18((scaleFactor * amount) / duration);
3938
}
4039

41-
/// @notice This function calculates the rate per second for a given amount of tokens for a specific range of time.
42-
/// @dev The rate per second is a 18 decimal fixed-point number and it is calculated as `amount / (end - start)`.
40+
/// @notice This function calculates the rate per second based on a given amount of tokens and a specified range.
41+
/// @dev The rate per second is a 18-decimal fixed-point number and it is calculated as `amount / (end - start)`.
4342
/// @param token The address of the token.
4443
/// @param amount The amount of tokens, denoted in token's decimals.
4544
/// @param start The start timestamp.
4645
/// @param end The end timestamp.
47-
/// @return ratePerSecond The rate per second as a fixed-point number.
46+
/// @return ratePerSecond The rate per second as a 18-decimal fixed-point number.
4847
function ratePerSecondForTimestamps(
4948
address token,
5049
uint128 amount,
@@ -61,34 +60,34 @@ library FlowUtilities {
6160
// Calculate the duration.
6261
uint40 duration = end - start;
6362

64-
if (decimals < 18) {
63+
if (decimals == 18) {
6564
return ud21x18(amount / duration);
6665
}
6766

6867
// Calculate the scale factor from the token's decimals.
6968
uint128 scaleFactor = uint128(10 ** (18 - decimals));
7069

7170
// Multiply the amount by the scale factor and divide by the duration.
72-
ratePerSecond = ud21x18(scaleFactor * amount / duration);
71+
ratePerSecond = ud21x18((scaleFactor * amount) / duration);
7372
}
7473

7574
/// @notice This function calculates the amount streamed over a week for a given rate per second.
76-
/// @param ratePerSecond The rate per second as a fixed-point number.
75+
/// @param ratePerSecond The rate per second as a 18-decimal fixed-point number.
7776
/// @return amountPerWeek The amount streamed over a week.
7877
function calculateAmountStreamedPerWeek(UD21x18 ratePerSecond) internal pure returns (uint128 amountPerWeek) {
7978
amountPerWeek = ratePerSecond.unwrap() * 1 weeks;
8079
}
8180

8281
/// @notice This function calculates the amount streamed over a month for a given rate per second.
83-
/// @dev We use 30 days as the number of days in a month.
84-
/// @param ratePerSecond The rate per second as a fixed-point number.
82+
/// @dev For simplicity, we have assumed that there are 30 days in a month.
83+
/// @param ratePerSecond The rate per second as a 18-decimal fixed-point number.
8584
/// @return amountPerMonth The amount streamed over a month.
8685
function calculateAmountStreamedPerMonth(UD21x18 ratePerSecond) internal pure returns (uint128 amountPerMonth) {
8786
amountPerMonth = ratePerSecond.unwrap() * 30 days;
8887
}
8988

9089
/// @notice This function calculates the amount streamed over a year for a given rate per second.
91-
/// @dev We use 365 days as the number of days in a year.
90+
/// @dev For simplicity, we have assumed that there are 365 days in a year.
9291
/// @param ratePerSecond The rate per second as a fixed-point number.
9392
/// @return amountPerYear The amount streamed over a year.
9493
function calculateAmountStreamedPerYear(UD21x18 ratePerSecond) internal pure returns (uint128 amountPerYear) {

lockup/core/RecipientHooks.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ contract RecipientHooks is ISablierLockupRecipient {
1111
/// depending on which type of streams are supported in this hook.
1212
address public immutable SABLIER_LOCKUP;
1313

14-
mapping(address => uint256) internal _balances;
14+
mapping(address account => uint256 amount) internal _balances;
1515

1616
/// @dev Constructor will set the address of the lockup contract.
1717
constructor(address sablierLockup_) {

0 commit comments

Comments
 (0)