Skip to content

Commit

Permalink
feat: add payments amount logic in subscriptions
Browse files Browse the repository at this point in the history
  • Loading branch information
0xblu committed Aug 27, 2024
1 parent 4585d95 commit e479dc3
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 31 deletions.
2 changes: 1 addition & 1 deletion script/Deploy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ contract Deploy is Script {
Grateful _grateful = new Grateful(_params.tokens, _params.aavePool);
AaveV3Vault _vault = new AaveV3Vault(
ERC20(_params.tokens[0]),
ERC20(0x6d80113e533a2C0fe82EaBD35f1875DcEA89Ea97),
ERC20(0x98C23E9d8f34FEFb1B7BD6a91B7FF122F4e16F5c),
_params.aavePool,
address(0),
IRewardsController(0x8164Cc65827dcFe994AB23944CBC90e0aa80bFcb),
Expand Down
16 changes: 12 additions & 4 deletions src/contracts/Grateful.sol
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,18 @@ contract Grateful is IGrateful, Ownable2Step {
address _token,
address _receiver,
uint256 _amount,
uint256 _interval
uint40 _interval,
uint16 _paymentsAmount
) external onlyWhenTokenWhitelisted(_token) returns (uint256 subscriptionId) {
subscriptionId = subscriptionCount++;
subscriptions[subscriptionId] = Subscription({
token: _token,
sender: msg.sender,
receiver: _receiver,
amount: _amount,
receiver: _receiver,
interval: _interval,
lastPaymentTime: block.timestamp
paymentsAmount: _paymentsAmount - 1, // Subtract 1 because the first payment is already processed
lastPaymentTime: uint40(block.timestamp)
});

_processPayment(msg.sender, _receiver, _token, _amount);
Expand All @@ -94,9 +96,13 @@ contract Grateful is IGrateful, Ownable2Step {
) {
revert Grateful_TooEarlyForNextPayment();
}
if (subscription.paymentsAmount == 0) {
revert Grateful_PaymentsAmountReached();
}

_processPayment(subscription.sender, subscription.receiver, subscription.token, subscription.amount);
subscription.lastPaymentTime = block.timestamp;
subscription.lastPaymentTime = uint40(block.timestamp);
subscription.paymentsAmount--;
}

// @inheritdoc IGrateful
Expand Down Expand Up @@ -143,5 +149,7 @@ contract Grateful is IGrateful, Ownable2Step {
revert Grateful_TransferFailed();
}
}

emit PaymentProcessed(_sender, _merchant, _token, _amount, yieldingFunds[_merchant]);
}
}
25 changes: 21 additions & 4 deletions src/interfaces/IGrateful.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,27 @@ interface IGrateful {
struct Subscription {
address token;
address sender;
address receiver;
uint256 amount;
uint256 interval;
uint256 lastPaymentTime;
address receiver;
uint40 interval;
uint40 lastPaymentTime;
uint16 paymentsAmount;
}

/*///////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/

/**
* @notice Emitted when a payment is processed
* @param sender Address of the sender
* @param merchant Address of the merchant
* @param token Address of the token
* @param amount Amount of the token
* @param yielded Indicates if the payment was yielded
*/
event PaymentProcessed(address sender, address merchant, address token, uint256 amount, bool yielded);

/*///////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
Expand Down Expand Up @@ -65,6 +76,11 @@ interface IGrateful {
*/
error Grateful_OnlySenderCanCancelSubscription();

/**
* @notice Throws if the payments amount has been reached
*/
error Grateful_PaymentsAmountReached();

/*///////////////////////////////////////////////////////////////
VARIABLES
//////////////////////////////////////////////////////////////*/
Expand Down Expand Up @@ -135,7 +151,8 @@ interface IGrateful {
address _token,
address _receiver,
uint256 _amount,
uint256 _interval
uint40 _interval,
uint16 _paymentsAmount
) external returns (uint256 subscriptionId);

/**
Expand Down
36 changes: 22 additions & 14 deletions test/integration/Grateful.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import {IGrateful, IntegrationBase} from "test/integration/IntegrationBase.sol";

contract IntegrationGreeter is IntegrationBase {
function test_Payment() public {
vm.startPrank(_daiWhale);
_dai.approve(address(_grateful), _amount);
_grateful.pay(_merchant, address(_dai), _amount);
vm.startPrank(_usdcWhale);
_usdc.approve(address(_grateful), _amount);
_grateful.pay(_merchant, address(_usdc), _amount);
vm.stopPrank();

assertEq(_dai.balanceOf(_merchant), _amount);
assertEq(_usdc.balanceOf(_merchant), _amount);
}

function test_PaymentYieldingFunds() public {
Expand All @@ -21,27 +21,27 @@ contract IntegrationGreeter is IntegrationBase {

assertEq(_grateful.yieldingFunds(_merchant), true);

vm.startPrank(_daiWhale);
_dai.approve(address(_grateful), _amount);
_grateful.pay(_merchant, address(_dai), _amount);
vm.startPrank(_usdcWhale);
_usdc.approve(address(_grateful), _amount);
_grateful.pay(_merchant, address(_usdc), _amount);
vm.stopPrank();

vm.warp(block.timestamp + 60 days);

vm.prank(_merchant);
_grateful.withdraw(address(_dai));
_grateful.withdraw(address(_usdc));

assertGt(_dai.balanceOf(_merchant), _amount);
assertGt(_usdc.balanceOf(_merchant), _amount);
}

function test_Subscription() public {
vm.startPrank(_daiWhale);
_dai.approve(address(_grateful), _amount * 2);
uint256 subscriptionId = _grateful.subscribe(address(_dai), _merchant, _amount, 30 days);
vm.startPrank(_usdcWhale);
_usdc.approve(address(_grateful), _amount * 2);
uint256 subscriptionId = _grateful.subscribe(address(_usdc), _merchant, _amount, 30 days, 2);
vm.stopPrank();

// When subscription is created, a initial payment is made
assertEq(_dai.balanceOf(_merchant), _amount);
assertEq(_usdc.balanceOf(_merchant), _amount);

// Shouldn't be able to process the subscription before 30 days have passed
vm.expectRevert(IGrateful.Grateful_TooEarlyForNextPayment.selector);
Expand All @@ -52,6 +52,14 @@ contract IntegrationGreeter is IntegrationBase {

_grateful.processSubscription(subscriptionId);

assertEq(_dai.balanceOf(_merchant), _amount * 2);
assertEq(_usdc.balanceOf(_merchant), _amount * 2);

// Should revert if the payments amount has been reached

// Fast forward 30 days
vm.warp(block.timestamp + 30 days);

vm.expectRevert(IGrateful.Grateful_PaymentsAmountReached.selector);
_grateful.processSubscription(subscriptionId);
}
}
16 changes: 8 additions & 8 deletions test/integration/IntegrationBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,33 +18,33 @@ contract IntegrationBase is Test {
address internal _user = makeAddr("user");
address internal _merchant = makeAddr("merchant");
address internal _owner = makeAddr("owner");
address internal _daiWhale = 0xbf702ea18BB1AB2A710394993a576eC61476cCf3;
address internal _usdcWhale = 0x555d73f2002A457211d690313f942B065eAD1FFF;
address[] internal _tokens;
IERC20 internal _dai = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F);
address _aDai = 0x018008bfb33d285247A21d44E50697654f754e63;
IERC20 internal _usdc = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);
address _aUsdc = 0x98C23E9d8f34FEFb1B7BD6a91B7FF122F4e16F5c;

Check warning on line 24 in test/integration/IntegrationBase.sol

View workflow job for this annotation

GitHub Actions / Lint Commit Messages

Explicitly mark visibility of state
address _rewardsController = 0x8164Cc65827dcFe994AB23944CBC90e0aa80bFcb;

Check warning on line 25 in test/integration/IntegrationBase.sol

View workflow job for this annotation

GitHub Actions / Lint Commit Messages

Explicitly mark visibility of state
IPool internal _aavePool = IPool(0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2);
IGrateful internal _grateful;
AaveV3Vault internal _vault;
uint256 internal _amount = 10 * 10 ** 18; // 10 DAI
uint256 internal _amount = 10 * 10 ** 6; // 10 DAI

function setUp() public {
vm.startPrank(_owner);
vm.createSelectFork(vm.rpcUrl("mainnet"), _FORK_BLOCK);
vm.label(address(_vault), "Vault");
_tokens = new address[](1);
_tokens[0] = address(_dai);
_tokens[0] = address(_usdc);
_grateful = new Grateful(_tokens, _aavePool);
_vault = new AaveV3Vault(
ERC20(address(_dai)),
ERC20(_aDai),
ERC20(address(_usdc)),
ERC20(_aUsdc),
_aavePool,
address(0),
IRewardsController(_rewardsController),
address(_grateful)
);
vm.label(address(_grateful), "Grateful");
_grateful.addVault(address(_dai), address(_vault));
_grateful.addVault(address(_usdc), address(_vault));
vm.stopPrank();
}
}

0 comments on commit e479dc3

Please sign in to comment.