Skip to content

Commit

Permalink
test: separate contracts and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
dristpunk committed Dec 19, 2023
1 parent 0777562 commit b7b030e
Show file tree
Hide file tree
Showing 6 changed files with 274 additions and 66 deletions.
60 changes: 60 additions & 0 deletions solidity/contracts/LockupDynamicStreamCreator.sol
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);
}
}
48 changes: 48 additions & 0 deletions solidity/contracts/MockLockupDynamicStreamCreator.sol
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);
}
}
80 changes: 80 additions & 0 deletions solidity/contracts/WonderLockupDynamicStreamCreator.sol
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');
}
}
75 changes: 9 additions & 66 deletions solidity/test/integration/LockupDynamicStreamCreator.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity 0.8.19;

import {ISablierV2LockupDynamic} from '@sablier/v2-core/src/interfaces/ISablierV2LockupDynamic.sol';
import {LockupDynamicStreamCreator} from 'contracts/LockupDynamicStreamCreator.sol';
import {Broker, LockupDynamic} from '@sablier/v2-core/src/types/DataTypes.sol';

Check warning on line 6 in solidity/test/integration/LockupDynamicStreamCreator.t.sol

View workflow job for this annotation

GitHub Actions / Lint Commit Messages

imported name Broker is not used

Check warning on line 6 in solidity/test/integration/LockupDynamicStreamCreator.t.sol

View workflow job for this annotation

GitHub Actions / Lint Commit Messages

imported name LockupDynamic is not used
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import {ud2x18} from '@prb/math/src/UD2x18.sol';

Check warning on line 8 in solidity/test/integration/LockupDynamicStreamCreator.t.sol

View workflow job for this annotation

GitHub Actions / Lint Commit Messages

imported name ud2x18 is not used
Expand All @@ -15,85 +16,27 @@ contract LockupDynamicStreamCreatorTest is Test {
address internal _owner = makeAddr('owner');

address constant SABLIER_DYNAMIC_MAINNET = 0x39EFdC3dbB57B2388CcC4bb40aC4CB1226Bc9E44;

Check warning on line 18 in solidity/test/integration/LockupDynamicStreamCreator.t.sol

View workflow job for this annotation

GitHub Actions / Lint Commit Messages

Explicitly mark visibility of state

Check warning on line 18 in solidity/test/integration/LockupDynamicStreamCreator.t.sol

View workflow job for this annotation

GitHub Actions / Lint Commit Messages

'SABLIER_DYNAMIC_MAINNET' should start with _
address constant NEXT_MAINNET = 0xFE67A4450907459c3e1FFf623aA927dD4e28c67a;

address constant SABLIER_DYNAMIC_GOERLI = 0x4BE70EDe968e9dBA12DB42b9869Bec66bEDC17d7;
address constant NEXT_GOERLI = 0x7ea6eA49B0b0Ae9c5db7907d139D9Cd3439862a1;
address constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;

Check warning on line 19 in solidity/test/integration/LockupDynamicStreamCreator.t.sol

View workflow job for this annotation

GitHub Actions / Lint Commit Messages

Explicitly mark visibility of state

Check warning on line 19 in solidity/test/integration/LockupDynamicStreamCreator.t.sol

View workflow job for this annotation

GitHub Actions / Lint Commit Messages

'DAI' should start with _

uint256 constant TOTAL_AMOUNT = 24_960_000 ether;

Check warning on line 21 in solidity/test/integration/LockupDynamicStreamCreator.t.sol

View workflow job for this annotation

GitHub Actions / Lint Commit Messages

Explicitly mark visibility of state

ISablierV2LockupDynamic internal lockupDynamic;
LockupDynamicStreamCreator internal creator;

function setUp() public {
// mint some NEXT tokens
vm.createSelectFork(vm.rpcUrl('mainnet'), 18_820_753);
deal(NEXT_MAINNET, _owner, TOTAL_AMOUNT);
vm.createSelectFork(vm.rpcUrl('mainnet'), 18_820_679);
creator = new LockupDynamicStreamCreator(ISablierV2LockupDynamic(SABLIER_DYNAMIC_MAINNET));
deal(DAI, _owner, TOTAL_AMOUNT);
vm.prank(_owner);
IERC20(NEXT_MAINNET).approve(address(this), TOTAL_AMOUNT);
IERC20(DAI).approve(address(creator), TOTAL_AMOUNT);

lockupDynamic = ISablierV2LockupDynamic(SABLIER_DYNAMIC_MAINNET);
}

function test_Creation() external {
uint256 streamId = createLockupDynamicStream(1_920_000, 5_917_440, 17_122_560);
vm.prank(_owner);
uint256 streamId = creator.createLockupDynamicStream(1000, 2000); // 1_920_000, 5_917_440, 17_122_560
console.log('streamId: %s', streamId);
}

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(_owner, 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 = _owner; // 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');
}
}
37 changes: 37 additions & 0 deletions solidity/test/integration/MockLockupDynamicStreamCreator.t.sol
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 solidity/test/integration/WonderLockupDynamicStreamCreator.t.sol
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);
}
}

0 comments on commit b7b030e

Please sign in to comment.