ClockTower Subscribe
Time Ranges
- Weekly Subscriptions -- 1 - 7 (Weekdays)
- Monthly Subscriptions -- 1 - 28 (Day of Month)
- Quarterly Subscriptions -- 1 - 90 (Day of Quarter)
- Yearly Subscription -- 1 - 365 (Day of Year (not including leap days))
Decimals
All ERC20 values are stored in the contract as 18 decimals and are converted before interacting with the token contracts.
Data Structures
The following are the data structs required or returned by external functions:
Structs
Account
struct Account {
address accountAddress;
SubIndex[] subscriptions;
SubIndex[] provSubs;
}
Name | Type | Description |
---|---|---|
accountAddress | address | Unique account address |
subscriptions | Array of SubIndex structs | All subscriptions subscribed to by account |
provSubs | Array of SubIndex structs | All subscriptions created by account |
Subscription
struct Subscription {
bytes32 id;
uint amount;
address provider;
address token;
bool cancelled;
Frequency frequency;
uint16 dueDay;
}
Name | Type | Description |
---|---|---|
id | bytes32 | Unique hash generated for each subscription |
amount | uint | Amount of subscription in wei (18 decimals) |
provider | address | Address of the creator of the subscription |
token | address | ERC20 address of token used in subscription |
cancelled | bool | True if subscription is cancelled |
frequency | Frequency | Frequency |
dueDay | uint16 | Day in frequency range when subscription is paid |
SubIndex
struct SubIndex {
bytes32 id;
uint16 dueDay;
Frequency frequency;
Status status;
}
Name | Type | Description |
---|---|---|
id | bytes32 | Unique id of subscription |
dueDay | uint16 | Day in frequency range when subscription is paid |
frequency | frequency | Frequency |
status | Status | Status |
PageStart
struct PageStart {
bytes32 id;
uint256 subscriberIndex;
uint256 subscriptionIndex;
uint256 frequency;
bool initialized;
}
Name | Type | Description |
---|---|---|
id | bytes32 | Unique id of subscription where pagination starts |
subscriberIndex | uint256 | Index within remit call linked to subscriber |
subscriptionIndex | uint256 | Index within remit call link edto subscription |
frequency | uint256 | Frequency index within remit call |
initialized | bool | Boolean whether pagination is occuring or not |
SubView
struct SubView {
Subscription subscription;
Status status;
uint totalSubscribers;
}
Name | Type | Description |
---|---|---|
subscription | Subscription | Subscription |
status | Status | Status |
totalsubscribers | uint | Total number of subscribers |
FeeEstimate
struct FeeEstimate {
uint fee;
address token;
}
Name | Type | Description |
---|---|---|
fee | uint | Fee amount in wei (18 decimals) |
token | address | ERC20 address of token |
ApprovedToken
struct ApprovedToken {
address tokenAddress;
uint8 decimals;
bool paused;
uint256 minimum;
}
Name | Type | Description |
---|---|---|
tokenAddress | address | Contract address of approved ERC20 token |
decimals | uint8 | Native decimal amount of token |
paused | bool | Is token paused |
minimum | uint256 | Minimum amount per subscription (in 10^18) |
SubscriberView
struct SubscriberView {
address subscriber;
uint feeBalance;
}
Name | Type | Description |
---|---|---|
subscriber | address | Subscriber address |
feeBalance | uint | Fee balance of subscriber in wei |
Details
struct Details {
string url;
string description;
}
Name | Type | Description |
---|---|---|
url | string | URL of Subscription |
description | string | Description of Subscription |
ProviderDetails
struct ProviderDetails {
string description;
string company;
string url;
string domain;
string email;
string misc;
}
Name | Type | Description |
---|---|---|
description | string | Description of provider |
company | string | Provider company |
url | string | Provider url |
domain | string | Provider domain |
string | Provider email | |
misc | string | Provider miscellaneous |
Time
struct Time {
uint16 day;
uint16 weekDay;
uint16 quarterDay;
uint16 yearDay;
uint16 year;
uint16 month;
}
Name | Type | Description |
---|---|---|
day | uint16 | Day of month |
weekDay | uint16 | Day of week |
quarterDay | uint16 | Day of quarter |
yearDay | uint16 | Day of year |
year | uint16 | Year |
month | uint16 | Month |
Enums
(Enum values are represented by numbers starting at zero)
Frequency
enum Frequency {
WEEKLY,
MONTHLY,
QUARTERLY,
YEARLY
}
Value | Description |
---|---|
0 | WEEKLY |
1 | MONTHLY |
2 | QUARTERLY |
3 | YEARLY |
Status
enum Status {
ACTIVE,
CANCELLED,
UNSUBSCRIBED
}
Value | Description |
---|---|
0 | ACTIVE |
1 | CANCELLED |
2 | UNSUBSCRIBED |
SubscriptEvent
enum SubscriptEvent {
CREATE,
CANCEL,
PROVPAID,
FAILED,
PROVREFUND,
SUBPAID,
SUBSCRIBED,
UNSUBSCRIBED,
FEEFILL,
SUBREFUND
}
Value | Description |
---|---|
0 | CREATE |
1 | CANCEL |
2 | PROVPAID |
3 | FAILED |
4 | PROVREFUND |
5 | SUBPAID |
6 | SUBSCRIBED |
7 | UNSUBSCRIBED |
8 | FEEFILL |
9 | SUBREFUND |
Global Variables
Name | Type | Description | Format |
---|---|---|---|
callerFee | uint | Percentage of subscriptions paid to caller on remits | 10000 = No fee, 10100 = 1%, 10001 = 0.01% |
systemFee | uint | Percentage of caller fee paid to system when systemFee bool is true | 10000 = No fee, 10100 = 1%, 10001 = 0.01% |
maxRemits | uint | Maximum number of remits per remit function (usually based on block max) | |
admin | address | Address for admin account | |
nextUncheckedDay | uint40 | Day index of day that has not been remitted | Day index |
Events
UList
event UList(
uint40 indexed timestamp,
bytes32 indexed id,
address indexed subscriber
)
Log emitted when subscriber unsubscribes during pagination
Name | Type | Indexed | Description |
---|---|---|---|
timestamp | uint40 | ✔️ | Unix Epoch timestamp |
id | bytes32 | ✔️ | Unique Susbcriber id |
subscriber | address | ✔️ | Address of subscriber |
SubLog
event SubLog(
bytes32 indexed id,
address indexed provider,
address indexed subscriber,
uint40 timestamp,
uint amount,
address token,
SubScriptEvent subScriptEvent
)
Log emitted during subscription events
Name | Type | Indexed | Description |
---|---|---|---|
id | bytes32 | ✔️ | Unique Subscription id |
subscriber | address | ✔️ | Address of subscriber |
provider | address | ✔️ | Address of provider |
timestamp | uint40 | Unix Epoch timestamp | |
amount | uint | ERC20 subscription amount in wei (18 decimals) | |
token | address | ERC20 address of token used in subscription | |
subScriptEvent | SubScriptEvent | SubScriptEvent |
CallerLog
event CallerLog(
uint40 timestamp,
uint40 checkedDay,
address indexed caller,
bool isFinished
)
Log emitted during Caller events
Name | Type | Indexed | Description |
---|---|---|---|
timestamp | uint40 | ✔️ | Unix epoch timestamp |
checkedDay | uint40 | ✔️ | Day in frequency range checked by Caller |
caller | address | ✔️ | Address of caller |
isFinished | bool | Shows if Caller is done |
DetailsLog
event DetailsLog(
bytes32 indexed id,
address indexed provider,
uint40 indexed timestamp,
string url,
string description
)
Log emitted when subscription details are changed
Name | Type | Indexed | Description |
---|---|---|---|
id | bytes32 | ✔️ | Unique subscription id |
provider | address | ✔️ | Provider address |
timestamp | uint40 | ✔️ | Unix epoch timestamp |
url | string | Url of Subscription | |
description | string | Description of subscription |
ProvDetailsLog
event ProvDetailsLog(
address indexed provider,
uint40 indexed timestamp,
string description,
string company,
string url,
string domain,
string email,
string misc
)
Log emitted when Provider details are changed
Name | Type | Indexed | Description |
---|---|---|---|
provider | address | ✔️ | Provider address |
timestamp | uint40 | ✔️ | Unix epoch timestamp |
description | string | Description of Provider | |
company | string | Company of Provider | |
url | string | URL of Provider | |
domain | string | Domain of Provider | |
email | string | Email of Provider | |
misc | string | Misc field for Provider |
Coordinates
event Coordinates(
bytes32 indexed id,
uint256 subscriberIndex,
uint256 subscriptionIndex,
uint256 frequency,
uint40 indexed nextUncheckedDay
)
Log emitted when remitting showing the pagination coordinates
Name | Type | Indexed | Description |
---|---|---|---|
id | bytes32 | ✔️ | Unique subscription id |
subscriberIndex | uint256 | Index within remit call linked to subscriber | |
subscriptionIndex | uint256 | Index within remit call linked to subscription | |
frequency | uint256 | Frequency index within remit call | |
nextUncheckedDay | uint40 | ✔️ | Day index of day that has not been remitted |
Functions
Subscription Functions
createSubscription
function createSubscription(
uint amount,
address token,
Details details,
string description,
Frequency frequency,
uint16 dueDay
) external
Allows provider to create a new subscription.
Parameters:
Name | Type | Description |
---|---|---|
amount | uint | Amount of subscription in wei. (MUST BE IN 18 DECIMALS) |
token | address | ERC20 address of token used in subscription |
details | Details | Details |
description | string | Description of subscription |
frequency | Frequency | Frequency |
dueDay | uint16 | Day in range based on frequency when subscription is paid |
subscribe
function subscribe(
Subscription subscription
) external
Allows user to subscribe to subscription
Parameters:
Name | Type | Description |
---|---|---|
subscription | Subscription | Subscription |
unsubscribe
function unsubscribe(
Subscription subscription
) external
Allows user to unsubscribe from subscription.
msg.sender must be subscribed to subscription.
Parameters:
Name | Type | Description |
---|---|---|
subscription | Subscription | Subscription |
unsubscribeByProvider
function unsubscribeByProvider(
Subscription subscription,
address subscriber
) external
Allows provider to cancel subscriber from their created subscriptions.
msg.sender must be creator of subscription and subscriber must be subscribed.
Parameters:
Name | Type | Description |
---|---|---|
subscription | Subscription | Subscription |
subscriber | address | Subscriber address |
cancelSubscription
function cancelSubscription(
Subscription subscription
) external
Allows provider to cancel subscription. All existing subscribers will no longer be charged
msg.sender must be creator of subscription
Parameters:
Name | Type | Description |
---|---|---|
subscription | Subscription | Subscription |
remit
function remit()
Function that remits payments between the subscriber and provider and increments time
View Functions
getAccount
function getAccount(
address account
) returns (Account)
Returns Account struct based on address
Parameters:
Name | Type | Description |
---|---|---|
account | address | Account address |
getAccountSubscriptions
function getAccountSubscriptions(
bool bySubscriber,
address account
) returns (SubView[])
Returns an array of objects containing subscription and status by account.
If bySubscriber is true it gets a list of subscriptions account is subscribed to. If false it gets a list of subscriptions account created as the provider.
Parameters:
Name | Type | Description |
---|---|---|
bySubscriber | bool | See above description of bool |
account | address | Account address for subscriptions |
Return Value:
Name | Type | Description |
---|---|---|
SubView[] | SubView | Array of Subview structs |
getTotalSubscribers
function getTotalSubscribers(
) returns (uint)
Returns total number of subscribers.
Return Value:
Name | Type | Description |
---|---|---|
uint | uint | Total amount of subscribers in contract |
getSubscribersById
function getSubscribersById(
bytes32 id
) external view returns (SubscriberView[] memory)
Returns array of objects containing subscriber info.
Parameters:
Name | Type | Description |
---|---|---|
id | bytes32 | Unique subscription id |
Return Value:
Name | Type | Description |
---|---|---|
SubscriberView[] | SubscriberView | Array of SubscriberView structs |
getUnsubscribedLength
function getUnsubscribedLength(
bytes32 id
) external view returns (uint256)
Returns number of users in the unsubscribed during pagition mapping
Parameters:
Name | Type | Description |
---|---|---|
id | bytes32 | Unique subscription id |
Return Value:
Name | Type | Description |
---|---|---|
uint256 | uint256 | Number of users in the unsubscribed during pagition mapping |
Time Functions
unixToTime
function unixToTime(
uint unix
) returns(Time time)
Converts a unix time value to Time struct
Parameter:
Name | Type | Description |
---|---|---|
unix | uint | Unix time value |
Return Value:
Name | Type | Description |
---|---|---|
time | Time | Time struct |
Code:
uint _days = unix/86400;
uint16 day;
uint16 yearDay;
int __days = int(_days);
int L = __days + 68569 + 2440588;
int N = 4 * L / 146097;
L = L - (146097 * N + 3) / 4;
int _year = 4000 * (L + 1) / 1461001;
L = L - 1461 * _year / 4 + 31;
int _month = 80 * L / 2447;
int _day = L - 2447 * _month / 80;
L = _month / 11;
_month = _month + 2 - 12 * L;
_year = 100 * (N - 49) + _year + L;
uint uintyear = uint(_year);
uint month = uint(_month);
uint uintday = uint(_day);
day = uint16(uintday);
uint dayCounter;
//loops through months to get current day of year
for(uint monthCounter = 1; monthCounter <= month; monthCounter++) {
if(monthCounter == month) {
dayCounter += day;
} else {
dayCounter += getDaysInMonth(uintyear, monthCounter);
}
}
yearDay = uint16(dayCounter);
//gets day of quarter
time.quarterDay = getdayOfQuarter(yearDay, uintyear);
time.weekDay = getDayOfWeek(unix);
time.day = day;
time.yearDay = yearDay;
isLeapYear
function isLeapYear(
uint year
) returns (bool leapYear)
Checks if year is a leap year
Parameter:
Name | Type | Description |
---|---|---|
year | uint | Number of year in Gregorian Calendar |
Return Value:
Name | Type | Description |
---|---|---|
leapYear | bool | True if leap year |
Code:
leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
getDaysInMonth
function getDaysInMonth(
uint year,
uint month
) returns (uint daysInMonth)
Returns the number of days in the month based on Gregorian year and month calendar values
Parameters:
Name | Type | Description |
---|---|---|
year | uint | Number of year in Gregorian Calendar |
month | uint | Number of month in Gregorian Calendar |
Return Value:
Name | Type | Description |
---|---|---|
daysInMonth | uint | Number of days in the month |
Code:
if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
daysInMonth = 31;
} else if (month != 2) {
daysInMonth = 30;
} else {
daysInMonth = isLeapYear(year) ? 29 : 28;
}
getDaysOfWeek
function getDaysofWeek(
uint unixTime
) returns (uint16 dayOfWeek)
Returns the number of the day of the week
Parameter:
Name | Type | Description |
---|---|---|
unixTime | uint | Unix time value |
Return Value:
Name | Type | Description |
---|---|---|
dayOfWeek | uint16 | Day of the week (1 = Monday, 7 = Sunday) |
Code:
uint _days = unixTime / 86400;
uint dayOfWeekuint = (_days + 3) % 7 + 1;
dayOfWeek = uint16(dayOfWeekuint);
getdayOfQuarter
function getdayOfQuarter(
uint yearDays,
uint year
) returns (uint16 quarterDay)
Returns the day of the quarter range day based the year and the day of the year
Parameters:
Name | Type | Description |
---|---|---|
yearDays | uint | Day of the year (Between 1 - 365) |
year | uint | Number of year in Gregorian Calendar |
Return Value:
Name | Type | Description |
---|---|---|
quarterDay | uint16 | Day of the quarter (1 - 90) |
Code:
uint leapDay;
if(isLeapYear(year)) {
leapDay = 1;
} else {
leapDay = 0;
}
if(yearDays <= (90 + leapDay)) {
quarterDay = uint16(yearDays);
} else if((90 + leapDay) < yearDays && yearDays <= (181 + leapDay)) {
quarterDay = uint16(yearDays - (90 + leapDay));
} else if((181 + leapDay) < yearDays && yearDays <= (273 + leapDay)) {
quarterDay = uint16(yearDays - (181 + leapDay));
} else {
quarterDay = uint16(yearDays - (273 + leapDay));
}
unixToDays
function unixToDays (
uint40 unixTime
) returns (uint40 dayCount)
Returns the amount of days (rounded down) since unix epoch based on a provided unix time
Parameter:
Name | Type | Description |
---|---|---|
unixTime | uint | Unix time value |
Return Value:
Name | Type | Description |
---|---|---|
dayCount | uint16 | Number of days (rounded down) since unix epoch |
Code:
dayCount = unixTime/86400;
prorate
function prorate (
uint unixTime,
uint40 dueDay,
uint fee,
uint8 frequency) returns (uint)
Returns prorated amount of subscription based upons subscription parameters
Parameters:
Name | Type | Description |
---|---|---|
unixTime | uint | Unix time value |
dueDay | uint40 | Day in frequency range when subscription is paid |
fee | uint | Fee amount in wei (18 decimals) |
frequency | uint8 | Frequency |
Return Value:
Name | Type | Description |
---|---|---|
uint | uint | Prorated amount of susbcription in wei (18 decimals) |
Code:
Time memory time = unixToTime(unixTime);
uint currentDay;
uint max;
uint lastDayOfMonth;
//sets maximum range day amount
if(frequency == 0) {
currentDay = time.weekDay;
max = 7;
//monthly
} else if (frequency == 1){
//calculates maximum days in current month
lastDayOfMonth = getDaysInMonth(time.year, time.month);
currentDay = time.dayOfMonth;
max = lastDayOfMonth;
//quarterly and yearly
} else if (frequency == 2) {
currentDay = getdayOfQuarter(time.yearDay, time.year);
max = 90;
//adjusts for different sized quarters
if(currentDay == 92) {
max = 92;
}
if(currentDay == 91) {
max = 91;
}
//yearly
} else if (frequency == 3) {
currentDay = time.yearDay;
max = 365;
}
//monthly
if(frequency == 1) {
uint dailyFee = (fee * 12 / 365);
if(dueDay != currentDay && currentDay > dueDay){
//dates split months
fee = (dailyFee * (max - (currentDay - dueDay)));
} else if (dueDay != currentDay && currentDay < dueDay) {
//both dates are in the same month
fee = (dailyFee * (dueDay - currentDay));
}
}
//weekly quarterly and yearly
else if(frequency == 0 || frequency == 2 || frequency == 3) {
if(dueDay != currentDay && currentDay > dueDay){
fee = (fee / max) * (max - (currentDay - dueDay));
} else if (dueDay != currentDay && currentDay < dueDay) {
fee = (fee / max) * (dueDay - currentDay);
}
}
return fee;