-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(invoice-module): add Sablier V2 Lockup Linear stream management
- Loading branch information
1 parent
5c422a1
commit 95c6f55
Showing
2 changed files
with
144 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
pragma solidity >=0.8.22; | ||
|
||
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | ||
import { ud60x18, UD60x18 } from "@prb/math/src/UD60x18.sol"; | ||
import { ISablierV2LockupLinear } from "@sablier/v2-core/src/interfaces/ISablierV2LockupLinear.sol"; | ||
import { ILockupStreamCreator } from "./interfaces/ILockupStreamCreator.sol"; | ||
import { Broker, LockupLinear } from "@sablier/v2-core/src/types/DataTypes.sol"; | ||
import { LockupLinear } from "@sablier/v2-core/src/types/DataTypes.sol"; | ||
import { Errors } from "./libraries/Errors.sol"; | ||
|
||
/// @title LockupStreamCreator | ||
/// @dev See the documentation in {ILockupStreamCreator} | ||
contract LockupStreamCreator is ILockupStreamCreator { | ||
/*////////////////////////////////////////////////////////////////////////// | ||
PUBLIC STORAGE | ||
//////////////////////////////////////////////////////////////////////////*/ | ||
|
||
/// @inheritdoc ILockupStreamCreator | ||
ISablierV2LockupLinear public immutable override LOCKUP_LINEAR; | ||
|
||
/// @inheritdoc ILockupStreamCreator | ||
address public override brokerAdmin; | ||
|
||
/// @inheritdoc ILockupStreamCreator | ||
UD60x18 public brokerFee; | ||
|
||
/*////////////////////////////////////////////////////////////////////////// | ||
CONSTRUCTOR | ||
//////////////////////////////////////////////////////////////////////////*/ | ||
|
||
/// @dev Initializes the address of the {SablierV2LockupLinear} contract and the address of the broker admin account or contract | ||
constructor(address _sablierLockupDeployment, address _brokerAdmin) { | ||
LOCKUP_LINEAR = ISablierV2LockupLinear(_sablierLockupDeployment); | ||
brokerAdmin = _brokerAdmin; | ||
} | ||
|
||
/*////////////////////////////////////////////////////////////////////////// | ||
MODIFIERS | ||
//////////////////////////////////////////////////////////////////////////*/ | ||
|
||
/// @notice Reverts if the `msg.sender` is not the broker admin account or contract | ||
modifier onlyBrokerAdmin() { | ||
if (msg.sender != brokerAdmin) revert Errors.OnlyBrokerAdmin(); | ||
_; | ||
} | ||
|
||
/*////////////////////////////////////////////////////////////////////////// | ||
NON-CONSTANT FUNCTIONS | ||
//////////////////////////////////////////////////////////////////////////*/ | ||
|
||
/// @dev Creates either a Lockup Linear or Dynamic stream | ||
function createStream( | ||
IERC20 asset, | ||
uint128 totalAmount, | ||
LockupLinear.Durations memory durations, | ||
address recipient | ||
) public returns (uint256 streamId) { | ||
// Transfer the provided amount of ERC-20 tokens to this contract | ||
asset.transferFrom(msg.sender, address(this), totalAmount); | ||
|
||
// Approve the Sablier contract to spend the ERC-20 tokens | ||
asset.approve(address(LOCKUP_LINEAR), totalAmount); | ||
|
||
// Create the Lockup Linear stream | ||
streamId = _createLinearStream(asset, totalAmount, durations, recipient); | ||
} | ||
|
||
/// @dev Updates the fee charged by the broker | ||
function updateBrokerFee(UD60x18 newBrokerFee) public onlyBrokerAdmin { | ||
// Log the broker fee update | ||
emit BrokerFeeUpdated({ oldFee: brokerFee, newFee: newBrokerFee }); | ||
|
||
// Update the fee charged by the broker | ||
brokerFee = newBrokerFee; | ||
} | ||
|
||
/*////////////////////////////////////////////////////////////////////////// | ||
INTERNAL-METHODS | ||
//////////////////////////////////////////////////////////////////////////*/ | ||
|
||
/// @dev Creates a Lockup Linear stream | ||
/// See https://docs.sablier.com/contracts/v2/guides/create-stream/lockup-linear | ||
function _createLinearStream( | ||
IERC20 asset, | ||
uint128 totalAmount, | ||
LockupLinear.Durations memory durations, | ||
address recipient | ||
) internal returns (uint256 streamId) { | ||
// Declare the params struct | ||
LockupLinear.CreateWithDurations memory params; | ||
|
||
// Declare the function parameters | ||
params.sender = msg.sender; // The sender will be able to cancel the stream | ||
params.recipient = recipient; // The recipient of the streamed assets | ||
params.totalAmount = totalAmount; // Total amount is the amount inclusive of all fees | ||
params.asset = asset; // The streaming asset | ||
params.cancelable = true; // Whether the stream will be cancelable or not | ||
params.transferable = true; // Whether the stream will be transferable or not | ||
params.durations = LockupLinear.Durations({ | ||
cliff: durations.cliff, // Assets will be unlocked only after x period of time | ||
total: durations.total // Setting a total duration of x period of time | ||
}); | ||
params.broker = Broker({ account: brokerAdmin, fee: brokerFee }); // Optional parameter for charging a fee | ||
|
||
// Create the LockupLinear stream using a function that sets the start time to `block.timestamp` | ||
streamId = LOCKUP_LINEAR.createWithDurations(params); | ||
} | ||
} |
35 changes: 35 additions & 0 deletions
35
src/modules/invoice-module/interfaces/ILockupStreamCreator.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
pragma solidity >=0.8.22; | ||
|
||
import { ISablierV2LockupLinear } from "@sablier/v2-core/src/interfaces/ISablierV2LockupLinear.sol"; | ||
import { UD60x18 } from "@prb/math/src/UD60x18.sol"; | ||
|
||
/// @title ILockupStreamCreator | ||
/// @notice Contract used to create Sablier V2 compatible streams | ||
/// @dev This code is referenced in the docs: https://docs.sablier.com/contracts/v2/guides/create-stream/lockup-linear | ||
interface ILockupStreamCreator { | ||
/*////////////////////////////////////////////////////////////////////////// | ||
EVENTS | ||
//////////////////////////////////////////////////////////////////////////*/ | ||
|
||
/// @notice Emitted when the broker fee is updated | ||
/// @param oldFee The old broker fee | ||
/// @param newFee The new broker fee | ||
event BrokerFeeUpdated(UD60x18 oldFee, UD60x18 newFee); | ||
|
||
/*////////////////////////////////////////////////////////////////////////// | ||
CONSTANT FUNCTIONS | ||
//////////////////////////////////////////////////////////////////////////*/ | ||
|
||
/// @notice The address of the {SablierV2LockupLinear} contract used to create linear streams | ||
/// @dev This is initialized at construction time and it might be different depending on the deployment chain | ||
/// See https://docs.sablier.com/contracts/v2/deployments | ||
function LOCKUP_LINEAR() external view returns (ISablierV2LockupLinear); | ||
|
||
/// @notice The address of the broker admin account or contract managing the broker fee | ||
function brokerAdmin() external view returns (address); | ||
|
||
/// @notice The broker fee charged to create Sablier V2 stream | ||
/// @dev See the `UD60x18` type definition in the `@prb/math/src/ud60x18/ValueType.sol file` | ||
function brokerFee() external view returns (UD60x18); | ||
} |