generated from defi-wonderland/solidity-foundry-boilerplate
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
274 additions
and
66 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,60 @@ | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
pragma solidity >=0.8.19; | ||
|
||
import {ISablierV2LockupDynamic} from '@sablier/v2-core/src/interfaces/ISablierV2LockupDynamic.sol'; | ||
import {Broker, LockupDynamic} from '@sablier/v2-core/src/types/DataTypes.sol'; | ||
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; | ||
import {ud2x18} from '@prb/math/src/UD2x18.sol'; | ||
import {ud60x18} from '@prb/math/src/UD60x18.sol'; | ||
|
||
/// @notice Example of how to create a Lockup Dynamic stream. | ||
/// @dev This code is referenced in the docs: https://docs.sablier.com/contracts/v2/guides/create-stream/lockup-dynamic | ||
contract LockupDynamicStreamCreator { | ||
IERC20 public constant DAI = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); | ||
ISablierV2LockupDynamic public immutable lockupDynamic; | ||
|
||
constructor(ISablierV2LockupDynamic lockupDynamic_) { | ||
lockupDynamic = lockupDynamic_; | ||
} | ||
|
||
function createLockupDynamicStream(uint256 amount0, uint256 amount1) public returns (uint256 streamId) { | ||
// Sum the segment amounts | ||
uint256 totalAmount = amount0 + amount1; | ||
|
||
// Transfer the provided amount of DAI tokens to this contract | ||
DAI.transferFrom(msg.sender, address(this), totalAmount); | ||
|
||
// Approve the Sablier contract to spend DAI | ||
DAI.approve(address(lockupDynamic), totalAmount); | ||
|
||
// Declare the params struct | ||
LockupDynamic.CreateWithMilestones memory params; | ||
|
||
// Declare the function parameters | ||
params.sender = msg.sender; // The sender will be able to cancel the stream | ||
params.recipient = address(0xcafe); // The recipient of the streamed assets | ||
params.totalAmount = uint128(totalAmount); // Total amount is the amount inclusive of all fees | ||
params.asset = DAI; // The streaming asset | ||
params.cancelable = true; // Whether the stream will be cancelable or not | ||
params.startTime = uint40(block.timestamp + 100 seconds); | ||
params.broker = Broker(address(0), ud60x18(0)); // Optional parameter left undefined | ||
|
||
// Declare some dummy segments | ||
params.segments = new LockupDynamic.Segment[](2); | ||
params.segments[0] = LockupDynamic.Segment({ | ||
amount: uint128(amount0), | ||
exponent: ud2x18(1e18), | ||
milestone: uint40(block.timestamp + 4 weeks) | ||
}); | ||
params.segments[1] = ( | ||
LockupDynamic.Segment({ | ||
amount: uint128(amount1), | ||
exponent: ud2x18(3.14e18), | ||
milestone: uint40(block.timestamp + 52 weeks) | ||
}) | ||
); | ||
|
||
// Create the LockupDynamic stream | ||
streamId = lockupDynamic.createWithMilestones(params); | ||
} | ||
} |
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,48 @@ | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
pragma solidity >=0.8.19; | ||
|
||
import {ISablierV2LockupDynamic} from '@sablier/v2-core/src/interfaces/ISablierV2LockupDynamic.sol'; | ||
import {Broker, LockupDynamic} from '@sablier/v2-core/src/types/DataTypes.sol'; | ||
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; | ||
import {ud2x18} from '@prb/math/src/UD2x18.sol'; | ||
import {ud60x18} from '@prb/math/src/UD60x18.sol'; | ||
|
||
/// @notice Example of how to create a Lockup Dynamic stream. | ||
/// @dev This code is referenced in the docs: https://docs.sablier.com/contracts/v2/guides/create-stream/lockup-dynamic | ||
contract MockLockupDynamicStreamCreator { | ||
IERC20 public constant ASSET = IERC20(0x17422D756cE9024CC3fe7569f64941010eF277Db); | ||
uint128 public TOTAL_AMOUNT = 2_000_000_000_000_000_000_000; | ||
ISablierV2LockupDynamic public immutable lockupDynamic; | ||
|
||
constructor(ISablierV2LockupDynamic lockupDynamic_) { | ||
lockupDynamic = lockupDynamic_; | ||
} | ||
|
||
function createLockupDynamicStream() public returns (uint256 streamId) { | ||
// Approve the Sablier contract to spend DAI | ||
ASSET.approve(address(lockupDynamic), TOTAL_AMOUNT); | ||
|
||
// Declare the params struct | ||
LockupDynamic.CreateWithMilestones memory params; | ||
|
||
// Declare the function parameters | ||
params.sender = 0x54E0119cf6B50bD96a18c99f5227cce602097623; // The sender will be able to cancel the stream | ||
params.recipient = 0x4dC83b54500236a1BDd5d3c503e753609d71e371; // The recipient of the streamed assets | ||
params.totalAmount = TOTAL_AMOUNT; // 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.startTime = 1_699_027_200; | ||
params.broker = Broker(address(0), ud60x18(0)); // Optional parameter left undefined | ||
|
||
// Declare some dummy segments | ||
params.segments = new LockupDynamic.Segment[](1); | ||
params.segments[0] = LockupDynamic.Segment({ | ||
amount: TOTAL_AMOUNT, | ||
exponent: ud2x18(3_000_000_000_000_000_000), | ||
milestone: 1_702_483_200 | ||
}); | ||
|
||
// Create the LockupDynamic stream | ||
streamId = lockupDynamic.createWithMilestones(params); | ||
} | ||
} |
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,80 @@ | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
pragma solidity 0.8.19; | ||
|
||
import {ISablierV2LockupDynamic} from '@sablier/v2-core/src/interfaces/ISablierV2LockupDynamic.sol'; | ||
import {Broker, LockupDynamic} from '@sablier/v2-core/src/types/DataTypes.sol'; | ||
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; | ||
import {ud2x18} from '@prb/math/src/UD2x18.sol'; | ||
import {ud60x18} from '@prb/math/src/UD60x18.sol'; | ||
import {Test} from 'forge-std/Test.sol'; | ||
import {console} from 'forge-std/Console.sol'; | ||
|
||
/// @notice Example of how to create a Lockup Dynamic stream. | ||
/// @dev This code is referenced in the docs: https://docs.sablier.com/contracts/v2/guides/create-stream/lockup-dynamic | ||
contract WonderLockupDynamicStreamCreator { | ||
address public constant NEXT_MAINNET = 0xFE67A4450907459c3e1FFf623aA927dD4e28c67a; | ||
|
||
ISablierV2LockupDynamic internal lockupDynamic; | ||
|
||
constructor(ISablierV2LockupDynamic lockupDynamic_) { | ||
lockupDynamic = lockupDynamic_; | ||
} | ||
|
||
function createLockupDynamicStream( | ||
uint256 amount0, | ||
uint256 amount1, | ||
uint256 amount2 | ||
) public returns (uint256 streamId) { | ||
// Sum the segment amounts | ||
uint256 totalAmount = amount0 + amount1 + amount2; | ||
|
||
// Transfer the provided amount of DAI tokens to this contract | ||
IERC20(NEXT_MAINNET).transferFrom(msg.sender, address(this), totalAmount); | ||
|
||
// Approve the Sablier contract to spend DAI | ||
IERC20(NEXT_MAINNET).approve(address(lockupDynamic), totalAmount); | ||
|
||
console.log('HERE'); | ||
|
||
// Declare the params struct | ||
LockupDynamic.CreateWithMilestones memory params; | ||
|
||
// Declare the function parameters | ||
params.sender = msg.sender; // The sender will be able to cancel the stream | ||
params.recipient = address(0xcafe); // The recipient of the streamed assets | ||
params.totalAmount = uint128(totalAmount); // Total amount is the amount inclusive of all fees | ||
params.asset = IERC20(NEXT_MAINNET); // The streaming asset | ||
params.cancelable = true; // Whether the stream will be cancelable or not | ||
params.startTime = uint40(block.timestamp); | ||
params.broker = Broker(address(0), ud60x18(0)); // Optional parameter left undefined | ||
|
||
// Declare some dummy segments | ||
params.segments = new LockupDynamic.Segment[](3); | ||
params.segments[0] = LockupDynamic.Segment({ | ||
amount: uint128(amount0), | ||
exponent: ud2x18(0), // unlock at milestone | ||
milestone: uint40(block.timestamp + 365 days) // 12 months | ||
}); | ||
params.segments[1] = ( | ||
LockupDynamic.Segment({ | ||
amount: uint128(amount1), | ||
exponent: ud2x18(1e18), // linear unlock | ||
milestone: uint40(block.timestamp + 365 days + 90 days) // ~15 months | ||
}) | ||
); | ||
params.segments[2] = ( | ||
LockupDynamic.Segment({ | ||
amount: uint128(amount2), | ||
exponent: ud2x18(1e18), // linear unlock | ||
milestone: uint40(block.timestamp + (365 days * 4)) // 48 months | ||
}) | ||
); | ||
|
||
console.log('HERE'); | ||
|
||
// Create the LockupDynamic stream | ||
streamId = lockupDynamic.createWithMilestones(params); | ||
|
||
console.log('HERE'); | ||
} | ||
} |
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
37 changes: 37 additions & 0 deletions
37
solidity/test/integration/MockLockupDynamicStreamCreator.t.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,37 @@ | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
pragma solidity 0.8.19; | ||
|
||
import {ISablierV2LockupDynamic} from '@sablier/v2-core/src/interfaces/ISablierV2LockupDynamic.sol'; | ||
import {MockLockupDynamicStreamCreator} from 'contracts/MockLockupDynamicStreamCreator.sol'; | ||
import {Broker, LockupDynamic} from '@sablier/v2-core/src/types/DataTypes.sol'; | ||
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; | ||
import {ud2x18} from '@prb/math/src/UD2x18.sol'; | ||
import {ud60x18} from '@prb/math/src/UD60x18.sol'; | ||
import {Test} from 'forge-std/Test.sol'; | ||
import {console} from 'forge-std/Console.sol'; | ||
|
||
/// @notice Example of how to create a Lockup Dynamic stream. | ||
/// @dev This code is referenced in the docs: https://docs.sablier.com/contracts/v2/guides/create-stream/lockup-dynamic | ||
contract MockLockupDynamicStreamCreatorTest is Test { | ||
address internal _owner = makeAddr('owner'); | ||
|
||
address constant SABLIER_DYNAMIC_MAINNET = 0x39EFdC3dbB57B2388CcC4bb40aC4CB1226Bc9E44; | ||
|
||
ISablierV2LockupDynamic internal lockupDynamic; | ||
MockLockupDynamicStreamCreator internal creator; | ||
|
||
function setUp() public { | ||
// mint some NEXT tokens | ||
vm.createSelectFork(vm.rpcUrl('mainnet'), 18_820_679); | ||
creator = new MockLockupDynamicStreamCreator(ISablierV2LockupDynamic(SABLIER_DYNAMIC_MAINNET)); | ||
deal(address(creator.ASSET()), address(creator), creator.TOTAL_AMOUNT()); | ||
|
||
lockupDynamic = ISablierV2LockupDynamic(SABLIER_DYNAMIC_MAINNET); | ||
} | ||
|
||
function test_Creation() external { | ||
vm.prank(_owner); | ||
uint256 streamId = creator.createLockupDynamicStream(); | ||
console.log('streamId: %s', streamId); | ||
} | ||
} |
40 changes: 40 additions & 0 deletions
40
solidity/test/integration/WonderLockupDynamicStreamCreator.t.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,40 @@ | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
pragma solidity 0.8.19; | ||
|
||
import {ISablierV2LockupDynamic} from '@sablier/v2-core/src/interfaces/ISablierV2LockupDynamic.sol'; | ||
import {Broker, LockupDynamic} from '@sablier/v2-core/src/types/DataTypes.sol'; | ||
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; | ||
import {ud2x18} from '@prb/math/src/UD2x18.sol'; | ||
import {ud60x18} from '@prb/math/src/UD60x18.sol'; | ||
import {Test} from 'forge-std/Test.sol'; | ||
import {console} from 'forge-std/Console.sol'; | ||
import {WonderLockupDynamicStreamCreator} from 'contracts/WonderLockupDynamicStreamCreator.sol'; | ||
|
||
/// @notice Example of how to create a Lockup Dynamic stream. | ||
/// @dev This code is referenced in the docs: https://docs.sablier.com/contracts/v2/guides/create-stream/lockup-dynamic | ||
contract WonderLockupDynamicStreamCreatorTest is Test { | ||
address internal _owner = makeAddr('owner'); | ||
WonderLockupDynamicStreamCreator internal creator; | ||
|
||
address public constant SABLIER_DYNAMIC_MAINNET = 0x39EFdC3dbB57B2388CcC4bb40aC4CB1226Bc9E44; | ||
uint256 public constant TOTAL_AMOUNT = 24_960_000 ether; | ||
|
||
function setUp() public { | ||
// mint some NEXT tokens | ||
vm.createSelectFork(vm.rpcUrl('mainnet'), 18_820_679); | ||
creator = new WonderLockupDynamicStreamCreator(ISablierV2LockupDynamic(SABLIER_DYNAMIC_MAINNET)); | ||
deal(creator.NEXT_MAINNET(), _owner, TOTAL_AMOUNT); | ||
vm.prank(_owner); | ||
IERC20(creator.NEXT_MAINNET()).approve(address(creator), TOTAL_AMOUNT); | ||
} | ||
|
||
function test_Creation() external { | ||
assertEq(TOTAL_AMOUNT, 1_920_000 ether + 5_917_440 ether + 17_122_560 ether); | ||
assertEq(IERC20(creator.NEXT_MAINNET()).balanceOf(_owner), TOTAL_AMOUNT); | ||
assertEq(IERC20(creator.NEXT_MAINNET()).allowance(_owner, address(creator)), TOTAL_AMOUNT); | ||
console.log('here'); | ||
vm.prank(_owner); | ||
uint256 streamId = creator.createLockupDynamicStream(1_920_000 ether, 5_917_440 ether, 17_122_560 ether); | ||
console.log('streamId: %s', streamId); | ||
} | ||
} |