-
Notifications
You must be signed in to change notification settings - Fork 396
Expand file tree
/
Copy pathAggregationModePaymentService.sol
More file actions
214 lines (175 loc) · 8.57 KB
/
AggregationModePaymentService.sol
File metadata and controls
214 lines (175 loc) · 8.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.12;
import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol";
import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol";
import {UUPSUpgradeable} from "@openzeppelin-upgrades/contracts/proxy/utils/UUPSUpgradeable.sol";
/**
* @title AggregationModePaymentService
* @author Aligned Layer
* @notice Handles deposits that grant time-limited access to aggregation services.
*/
contract AggregationModePaymentService is Initializable, OwnableUpgradeable, UUPSUpgradeable {
/// @notice for how much time the payment is valid in seconds
uint256 public paymentExpirationTimeSeconds;
/// @notice The amount to pay for a subscription in wei.
uint256 public amountToPayInWei;
/// @notice The address where the payment funds will be sent.
address public paymentFundsRecipient;
/// @notice The limit of subscriptions for different addresses per month
uint256 public subscriptionLimit;
/// @notice The amount of subscriptions for the current month
uint256 public monthlySubscriptionsAmount;
/// @notice The amount of addresses currently subscribed. expirationTime is UTC seconds, to be
/// compared against block timestamps
mapping(address subscriber => uint256 expirationTime) public subscribedAddresses;
/**
* @notice Emitted when a user deposits funds to purchase service time.
* @param user Address that sent the payment.
* @param amount Native token amount paid.
* @param from Timestamp when the payment was recorded.
* @param until Timestamp until when the payment is valid.
*/
event UserPayment(address user, uint256 indexed amount, uint256 indexed from, uint256 indexed until);
/// @notice Event emitted when the payment expiration time is updated
/// @param newExpirationTime the new expiration time in seconds
event PaymentExpirationTimeUpdated(uint256 indexed newExpirationTime);
/// @notice Event emitted when the amount to pay for subscription is updated
/// @param newAmountToPay the new amount to pay for a subscription in wei.
event AmountToPayUpdated(uint256 indexed newAmountToPay);
/// @notice Event emitted when the subscription limit is updated
/// @param newSubscriptionLimit the new monthly subscription limit.
event SubscriptionLimitUpdated(uint256 indexed newSubscriptionLimit);
/// @notice Event emitted when the funds recipient is updated
/// @param newFundsRecipient the new address for receiving the funds on withdrawal.
event FundsRecipientUpdated(address indexed newFundsRecipient);
/// @notice Event emitted when the balance is withdrawn to the recipient address
/// @param recipient the address where the funds will be sent
/// @param amount the amont send to the recipient address
event FundsWithdrawn(address indexed recipient, uint256 amount);
error InvalidDepositAmount(uint256 amountReceived, uint256 amountRequired);
error SubscriptionLimitReached(uint256 subscriptionLimit);
error SubscriptionNotExpired(uint256 expiration, uint256 currentTime);
/**
* @notice Disables initializers for the implementation contract.
*/
constructor() {
_disableInitializers();
}
/**
* @notice Initializes the contract and transfers ownership to the provided address.
* @param _owner Address that becomes the contract owner.
* @param _paymentFundsRecipient Address that will receive the withdrawal funds.
* @param _amountToPayInWei Amount to pay in wei for the subscription.
* @param _paymentExpirationTimeSeconds The time in seconds that the subscription takes to expire.
* @param _subscriptionLimit The maximum subscribers that can be subscribed at the same time.
*
*/
function initialize(
address _owner,
address _paymentFundsRecipient,
uint256 _amountToPayInWei,
uint256 _paymentExpirationTimeSeconds,
uint256 _subscriptionLimit
) public initializer {
__Ownable_init();
__UUPSUpgradeable_init();
_transferOwnership(_owner);
paymentExpirationTimeSeconds = _paymentExpirationTimeSeconds;
amountToPayInWei = _amountToPayInWei;
paymentFundsRecipient = _paymentFundsRecipient;
subscriptionLimit = _subscriptionLimit;
}
/**
* @notice Ensures only the owner can authorize upgrades.
* @param newImplementation Address of the new implementation contract.
*/
function _authorizeUpgrade(address newImplementation)
internal
override
onlyOwner // solhint-disable-next-line no-empty-blocks
{}
/**
* @notice Sets the new expiration time. Only callable by the owner
* @param newExpirationTimeInSeconds The new expiration time for the users payments in seconds.
*/
function setPaymentExpirationTimeSeconds(uint256 newExpirationTimeInSeconds) public onlyOwner() {
paymentExpirationTimeSeconds = newExpirationTimeInSeconds;
emit PaymentExpirationTimeUpdated(newExpirationTimeInSeconds);
}
/**
* @notice Sets the new amount to pay. Only callable by the owner
* @param newRecipient The new address for receiving the funds on withdrawal.
*/
function setFundsRecipientAddress(address newRecipient) public onlyOwner() {
paymentFundsRecipient = newRecipient;
emit FundsRecipientUpdated(newRecipient);
}
/**
* @notice Sets the new amount to pay. Only callable by the owner
* @param newAmountToPay The new amount to pay for subscription in wei.
*/
function setAmountToPay(uint256 newAmountToPay) public onlyOwner() {
amountToPayInWei = newAmountToPay;
emit AmountToPayUpdated(newAmountToPay);
}
/**
* @notice Sets the new subscription limit. Only callable by the owner
* @param newSubscriptionLimit The new monthly subscription limit.
*/
function setSubscriptionLimit(uint256 newSubscriptionLimit) public onlyOwner() {
subscriptionLimit = newSubscriptionLimit;
emit SubscriptionLimitUpdated(newSubscriptionLimit);
}
/**
* @notice Resets the monthly subscriptions mapping counter to zero.
*/
function resetSubscriptions() public onlyOwner() {
monthlySubscriptionsAmount = 0;
}
/**
* @notice Adds an array of addresses to the payment map and emits the Payment event.
* @param addressesToAdd the addresses to be subscribed
* @param expirationTimestamp the expiration timestamp (UTC seconds) for that subscriptions
*/
function addArbitraryExpirationSubscriptions(address[] memory addressesToAdd, uint256 expirationTimestamp) public onlyOwner() {
for (uint256 i=0; i < addressesToAdd.length; ++i) {
address addressToAdd = addressesToAdd[i];
subscribedAddresses[addressToAdd] = expirationTimestamp;
emit UserPayment(addressToAdd, amountToPayInWei, block.timestamp, expirationTimestamp);
}
}
/**
* @notice Accepts payments and validates they meet the minimum requirement.
*/
receive() external payable {
uint256 amount = msg.value;
if (amount < amountToPayInWei) {
revert InvalidDepositAmount(amount, amountToPayInWei);
}
if (monthlySubscriptionsAmount == subscriptionLimit) {
revert SubscriptionLimitReached(subscriptionLimit);
}
// Check if the user has already payed a subscription for this month
uint256 insertedExpiration = subscribedAddresses[msg.sender];
if (insertedExpiration == 0) {
// this means the sender has not payed for a subscription before
subscribedAddresses[msg.sender] = block.timestamp + paymentExpirationTimeSeconds;
} else if (insertedExpiration > block.timestamp) {
// this means the sender has an expired subscription
subscribedAddresses[msg.sender] = block.timestamp + paymentExpirationTimeSeconds;
} else {
// this means the sender has a subscription that has not expired yet
revert SubscriptionNotExpired(insertedExpiration, block.timestamp);
}
++monthlySubscriptionsAmount;
emit UserPayment(msg.sender, amount, block.timestamp, block.timestamp + paymentExpirationTimeSeconds);
}
/**
* @notice Withdraws the contract balance to the recipient address.
*/
function withdraw() external onlyOwner {
uint256 balance = address(this).balance;
payable(paymentFundsRecipient).transfer(balance);
emit FundsWithdrawn(paymentFundsRecipient, balance);
}
}