Skip to content

Commit

Permalink
test: Test subscription creation
Browse files Browse the repository at this point in the history
  • Loading branch information
mgnfy-view committed Dec 16, 2024
1 parent 367a909 commit b2f54d7
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 6 deletions.
5 changes: 2 additions & 3 deletions src/SafeSubscriptions.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,8 @@ contract SafeSubscriptions is EIP712, ISafeSubscriptions {
{
if (
_subscription.serviceProvider == address(0) || _subscription.token == address(0)
|| _subscription.amount == 0 || _subscription.startingTimestamp == 0
|| _subscription.startingTimestamp < block.timestamp || _subscription.duration == 0
|| _subscription.rounds == 0 || _subscription.roundsClaimedSoFar > 0
|| _subscription.amount == 0 || _subscription.startingTimestamp < block.timestamp
|| _subscription.duration == 0 || _subscription.rounds == 0 || _subscription.roundsClaimedSoFar > 0
) revert InvalidSubscription();

(bytes memory encodedSubscriptionDataWithDeadlineAndNonce, bytes32 subscriptionDataWithDeadlineAndNonceHash) =
Expand Down
1 change: 0 additions & 1 deletion src/interfaces/ISafeSubscriptions.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ interface ISafeSubscriptions {
error SubscriptionDoesNotExist(bytes32 subscriptionDataHash);
error SubscriptionHasNotStartedYet(bytes32 subscriptionDataHash);
error TransactionFailed();
error UnauthorizedUpgrade(address caller, address upgradeAuthority);
error DeadlinePassed(uint256 deadline, uint256 currentTimestamp);
error InvalidNonce(uint256 givenNonce, uint256 _expectedNonce);
}
136 changes: 136 additions & 0 deletions test/unit/CreateSubscription.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import { ISafeSubscriptions } from "../../src/interfaces/ISafeSubscriptions.sol";

import { GlobalHelper } from "../utils/GlobalHelper.sol";

contract CreateSubscriptionTest is GlobalHelper {
function test_creatingANewSubscriptionFailsIfServiceProviderIsAddressZero() public {
(ISafeSubscriptions.Subscription memory subscription, uint256 deadline, uint256 nonce) =
_getTestCreateSubscriptionData();
subscription.serviceProvider = address(0);

vm.expectRevert(ISafeSubscriptions.InvalidSubscription.selector);
safeSubscriptions.createSubscription(subscription, deadline, nonce, "");
}

function test_creatingANewSubscriptionFailsIfTokenIsAddressZero() public {
(ISafeSubscriptions.Subscription memory subscription, uint256 deadline, uint256 nonce) =
_getTestCreateSubscriptionData();
subscription.token = address(0);

vm.expectRevert(ISafeSubscriptions.InvalidSubscription.selector);
safeSubscriptions.createSubscription(subscription, deadline, nonce, "");
}

function test_creatingANewSubscriptionFailsIfAmountIsZero() public {
(ISafeSubscriptions.Subscription memory subscription, uint256 deadline, uint256 nonce) =
_getTestCreateSubscriptionData();
subscription.amount = 0;

vm.expectRevert(ISafeSubscriptions.InvalidSubscription.selector);
safeSubscriptions.createSubscription(subscription, deadline, nonce, "");
}

function test_creatingANewSubscriptionFailsIfStartingTimestampIsLessThanCurrentTimestamp() public {
(ISafeSubscriptions.Subscription memory subscription, uint256 deadline, uint256 nonce) =
_getTestCreateSubscriptionData();

_warpBy(1);

vm.expectRevert(ISafeSubscriptions.InvalidSubscription.selector);
safeSubscriptions.createSubscription(subscription, deadline, nonce, "");
}

function test_creatingANewSubscriptionFailsIfDurationIsZero() public {
(ISafeSubscriptions.Subscription memory subscription, uint256 deadline, uint256 nonce) =
_getTestCreateSubscriptionData();
subscription.duration = 0;

vm.expectRevert(ISafeSubscriptions.InvalidSubscription.selector);
safeSubscriptions.createSubscription(subscription, deadline, nonce, "");
}

function test_creatingANewSubscriptionFailsIfRoundsIsZero() public {
(ISafeSubscriptions.Subscription memory subscription, uint256 deadline, uint256 nonce) =
_getTestCreateSubscriptionData();
subscription.rounds = 0;

vm.expectRevert(ISafeSubscriptions.InvalidSubscription.selector);
safeSubscriptions.createSubscription(subscription, deadline, nonce, "");
}

function test_creatingANewSubscriptionFailsIfRoundsClaimedSoFarIsGreaterThanZero() public {
(ISafeSubscriptions.Subscription memory subscription, uint256 deadline, uint256 nonce) =
_getTestCreateSubscriptionData();
subscription.roundsClaimedSoFar = 1;

vm.expectRevert(ISafeSubscriptions.InvalidSubscription.selector);
safeSubscriptions.createSubscription(subscription, deadline, nonce, "");
}

function test_creatingANewSubscriptionFailsIfInvalidSignatureIsPassed() public {
(ISafeSubscriptions.Subscription memory subscription, uint256 deadline, uint256 nonce) =
_getTestCreateSubscriptionData();

vm.expectRevert();
safeSubscriptions.createSubscription(subscription, deadline, nonce, "");
}

function test_creatingANewSubscriptionFailsIfDeadlineHasPassed() public {
(ISafeSubscriptions.Subscription memory subscription, uint256 deadline, uint256 nonce) =
_getTestCreateSubscriptionData();
subscription.startingTimestamp = block.timestamp + 2 * delay;
bytes memory signatures = _getSignaturesForSubscriptionCreation(subscription, deadline, nonce);

_warpBy(delay + 1);

vm.expectRevert(abi.encodeWithSelector(ISafeSubscriptions.DeadlinePassed.selector, deadline, block.timestamp));
safeSubscriptions.createSubscription(subscription, deadline, nonce, signatures);
}

function test_creatingANewSubscriptionFailsIfInvalidNonceIsUsed() public {
(ISafeSubscriptions.Subscription memory subscription, uint256 deadline, uint256 nonce) =
_getTestCreateSubscriptionData();
nonce = 10;
bytes memory signatures = _getSignaturesForSubscriptionCreation(subscription, deadline, nonce);

vm.expectRevert(
abi.encodeWithSelector(ISafeSubscriptions.InvalidNonce.selector, nonce, safeSubscriptions.getNextNonce())
);
safeSubscriptions.createSubscription(subscription, deadline, nonce, signatures);
}

function test_creatingANewSubscriptionSucceeds() public {
(ISafeSubscriptions.Subscription memory subscription, uint256 deadline, uint256 nonce) =
_getTestCreateSubscriptionData();
bytes memory signatures = _getSignaturesForSubscriptionCreation(subscription, deadline, nonce);

safeSubscriptions.createSubscription(subscription, deadline, nonce, signatures);

ISafeSubscriptions.Subscription memory subscriptionData =
safeSubscriptions.getSbscriptionData(safeSubscriptions.getSubscriptionDataHash(subscription));
assertEq(subscriptionData.serviceProvider, subscription.serviceProvider);
assertEq(subscriptionData.token, subscription.token);
assertEq(subscriptionData.amount, subscription.amount);
assertEq(subscriptionData.startingTimestamp, subscription.startingTimestamp);
assertEq(subscriptionData.duration, subscription.duration);
assertEq(subscriptionData.rounds, subscription.rounds);
assertEq(subscriptionData.isRecurring, subscription.isRecurring);
assertEq(subscriptionData.roundsClaimedSoFar, subscription.roundsClaimedSoFar);
assertEq(subscriptionData.salt, subscription.salt);

assertEq(safeSubscriptions.getNextNonce(), nonce + 1);
}

function test_creatingANewSubscriptionEmitsEvent() public {
(ISafeSubscriptions.Subscription memory subscription, uint256 deadline, uint256 nonce) =
_getTestCreateSubscriptionData();
bytes memory signatures = _getSignaturesForSubscriptionCreation(subscription, deadline, nonce);

vm.expectEmit(true, true, true, true);
emit ISafeSubscriptions.SubscriptionCreated(subscription);
safeSubscriptions.createSubscription(subscription, deadline, nonce, signatures);
}
}
2 changes: 0 additions & 2 deletions test/unit/Initialization.t.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import { Safe } from "@safe/Safe.sol";

import { GlobalHelper } from "../utils/GlobalHelper.sol";

contract InitializationTest is GlobalHelper {
Expand Down
63 changes: 63 additions & 0 deletions test/utils/GlobalHelper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ import { Enum } from "@safe/common/Enum.sol";
import { SafeProxy } from "@safe/proxies/SafeProxy.sol";
import { SafeProxyFactory } from "@safe/proxies/SafeProxyFactory.sol";

import { ISafeSubscriptions } from "../../src/interfaces/ISafeSubscriptions.sol";

import { SafeSubscriptions } from "../../src/SafeSubscriptions.sol";

contract GlobalHelper is Test {
address public constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

address[] public owners;
uint256[] public privateKeys;
uint256 public threshold;
Expand All @@ -21,6 +25,15 @@ contract GlobalHelper is Test {
SafeProxyFactory public safeProxyFactory;
Safe public safe;

address public serviceProvider;
uint256 public amount;
uint256 public startingTimestamp;
uint256 public duration;
uint256 public rounds;
bool public isRecurring;
uint256 public salt;
uint256 public delay;

function setUp() public {
(address owner, uint256 ownerPrivateKey) = makeAddrAndKey("Bob");
owners.push(owner);
Expand Down Expand Up @@ -65,5 +78,55 @@ contract GlobalHelper is Test {
payable(0),
signatures
);

serviceProvider = makeAddr("Service provider");
amount = 0.1 ether;
duration = 30 days;
rounds = 2;
delay = 2 minutes;
}

function _getTestCreateSubscriptionData()
internal
view
returns (ISafeSubscriptions.Subscription memory, uint256, uint256)
{
ISafeSubscriptions.Subscription memory subscription = ISafeSubscriptions.Subscription({
serviceProvider: serviceProvider,
token: NATIVE_TOKEN,
amount: amount,
startingTimestamp: block.timestamp,
duration: duration,
rounds: rounds,
isRecurring: isRecurring,
roundsClaimedSoFar: 0,
salt: salt
});
uint256 deadline = block.timestamp + delay;
uint256 nonce = safeSubscriptions.getNextNonce();

return (subscription, deadline, nonce);
}

function _getSignaturesForSubscriptionCreation(
ISafeSubscriptions.Subscription memory _subscription,
uint256 _deadline,
uint256 _nonce
)
internal
returns (bytes memory)
{
(, bytes32 subscriptionDataHash) =
safeSubscriptions.getEncodedSubscriptionDataAndHash(_subscription, _deadline, _nonce);

(uint8 v1, bytes32 r1, bytes32 s1) = vm.sign(privateKeys[0], subscriptionDataHash);
(uint8 v2, bytes32 r2, bytes32 s2) = vm.sign(privateKeys[1], subscriptionDataHash);
bytes memory signatures = abi.encodePacked(abi.encodePacked(r1, s1, v1), abi.encodePacked(r2, s2, v2));

return signatures;
}

function _warpBy(uint256 _duration) internal {
vm.warp(block.timestamp + _duration);
}
}

0 comments on commit b2f54d7

Please sign in to comment.