Skip to main content

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;
}
NameTypeDescription
accountAddressaddressUnique account address
subscriptionsArray of SubIndex structsAll subscriptions subscribed to by account
provSubsArray of SubIndex structsAll subscriptions created by account

Subscription

 struct Subscription {
bytes32 id;
uint amount;
address provider;
address token;
bool cancelled;
Frequency frequency;
uint16 dueDay;
}
NameTypeDescription
idbytes32Unique hash generated for each subscription
amountuintAmount of subscription in wei (18 decimals)
provideraddressAddress of the creator of the subscription
tokenaddressERC20 address of token used in subscription
cancelledboolTrue if subscription is cancelled
frequencyFrequencyFrequency
dueDayuint16Day in frequency range when subscription is paid

SubIndex

struct SubIndex {
bytes32 id;
uint16 dueDay;
Frequency frequency;
Status status;
}
NameTypeDescription
idbytes32Unique id of subscription
dueDayuint16Day in frequency range when subscription is paid
frequencyfrequencyFrequency
statusStatusStatus

PageStart

struct PageStart {
bytes32 id;
uint256 subscriberIndex;
uint256 subscriptionIndex;
uint256 frequency;
bool initialized;
}
NameTypeDescription
idbytes32Unique id of subscription where pagination starts
subscriberIndexuint256Index within remit call linked to subscriber
subscriptionIndexuint256Index within remit call link edto subscription
frequencyuint256Frequency index within remit call
initializedboolBoolean whether pagination is occuring or not

SubView

 struct SubView {
Subscription subscription;
Status status;
uint totalSubscribers;
}
NameTypeDescription
subscriptionSubscriptionSubscription
statusStatusStatus
totalsubscribersuintTotal number of subscribers

FeeEstimate

struct FeeEstimate {
uint fee;
address token;
}
NameTypeDescription
feeuintFee amount in wei (18 decimals)
tokenaddressERC20 address of token

ApprovedToken

struct ApprovedToken {
address tokenAddress;
uint8 decimals;
bool paused;
uint256 minimum;
}
NameTypeDescription
tokenAddressaddressContract address of approved ERC20 token
decimalsuint8Native decimal amount of token
pausedboolIs token paused
minimumuint256Minimum amount per subscription (in 10^18)

SubscriberView

struct SubscriberView {
address subscriber;
uint feeBalance;
}
NameTypeDescription
subscriberaddressSubscriber address
feeBalanceuintFee balance of subscriber in wei

Details

struct Details {
string url;
string description;
}
NameTypeDescription
urlstringURL of Subscription
descriptionstringDescription of Subscription

ProviderDetails

struct ProviderDetails {
string description;
string company;
string url;
string domain;
string email;
string misc;
}
NameTypeDescription
descriptionstringDescription of provider
companystringProvider company
urlstringProvider url
domainstringProvider domain
emailstringProvider email
miscstringProvider miscellaneous

Time

struct Time {
uint16 day;
uint16 weekDay;
uint16 quarterDay;
uint16 yearDay;
uint16 year;
uint16 month;
}
NameTypeDescription
dayuint16Day of month
weekDayuint16Day of week
quarterDayuint16Day of quarter
yearDayuint16Day of year
yearuint16Year
monthuint16Month

Enums

(Enum values are represented by numbers starting at zero)

Frequency

enum Frequency {
WEEKLY,
MONTHLY,
QUARTERLY,
YEARLY
}
ValueDescription
0WEEKLY
1MONTHLY
2QUARTERLY
3YEARLY

Status

enum Status {
ACTIVE,
CANCELLED,
UNSUBSCRIBED
}
ValueDescription
0ACTIVE
1CANCELLED
2UNSUBSCRIBED

SubscriptEvent

enum SubscriptEvent {
CREATE,
CANCEL,
PROVPAID,
FAILED,
PROVREFUND,
SUBPAID,
SUBSCRIBED,
UNSUBSCRIBED,
FEEFILL,
SUBREFUND
}
ValueDescription
0CREATE
1CANCEL
2PROVPAID
3FAILED
4PROVREFUND
5SUBPAID
6SUBSCRIBED
7UNSUBSCRIBED
8FEEFILL
9SUBREFUND

Global Variables

NameTypeDescriptionFormat
callerFeeuintPercentage of subscriptions paid to caller on remits10000 = No fee, 10100 = 1%, 10001 = 0.01%
systemFeeuintPercentage of caller fee paid to system when systemFee bool is true10000 = No fee, 10100 = 1%, 10001 = 0.01%
maxRemitsuintMaximum number of remits per remit function (usually based on block max)
adminaddressAddress for admin account
nextUncheckedDayuint40Day index of day that has not been remittedDay index

Events

UList

event UList(
uint40 indexed timestamp,
bytes32 indexed id,
address indexed subscriber
)

Log emitted when subscriber unsubscribes during pagination

NameTypeIndexedDescription
timestampuint40✔️Unix Epoch timestamp
idbytes32✔️Unique Susbcriber id
subscriberaddress✔️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

NameTypeIndexedDescription
idbytes32✔️Unique Subscription id
subscriberaddress✔️Address of subscriber
provideraddress✔️Address of provider
timestampuint40Unix Epoch timestamp
amountuintERC20 subscription amount in wei (18 decimals)
tokenaddressERC20 address of token used in subscription
subScriptEventSubScriptEventSubScriptEvent

CallerLog

event CallerLog(
uint40 timestamp,
uint40 checkedDay,
address indexed caller,
bool isFinished
)

Log emitted during Caller events

NameTypeIndexedDescription
timestampuint40✔️Unix epoch timestamp
checkedDayuint40✔️Day in frequency range checked by Caller
calleraddress✔️Address of caller
isFinishedboolShows 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

NameTypeIndexedDescription
idbytes32✔️Unique subscription id
provideraddress✔️Provider address
timestampuint40✔️Unix epoch timestamp
urlstringUrl of Subscription
descriptionstringDescription 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

NameTypeIndexedDescription
provideraddress✔️Provider address
timestampuint40✔️Unix epoch timestamp
descriptionstringDescription of Provider
companystringCompany of Provider
urlstringURL of Provider
domainstringDomain of Provider
emailstringEmail of Provider
miscstringMisc 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

NameTypeIndexedDescription
idbytes32✔️Unique subscription id
subscriberIndexuint256Index within remit call linked to subscriber
subscriptionIndexuint256Index within remit call linked to subscription
frequencyuint256Frequency index within remit call
nextUncheckedDayuint40✔️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:

NameTypeDescription
amountuintAmount of subscription in wei. (MUST BE IN 18 DECIMALS)
tokenaddressERC20 address of token used in subscription
detailsDetailsDetails
descriptionstringDescription of subscription
frequencyFrequencyFrequency
dueDayuint16Day in range based on frequency when subscription is paid

subscribe

function subscribe(
Subscription subscription
) external

Allows user to subscribe to subscription

Parameters:

NameTypeDescription
subscriptionSubscriptionSubscription

unsubscribe

function unsubscribe(
Subscription subscription
) external

Allows user to unsubscribe from subscription.

msg.sender must be subscribed to subscription.

Parameters:

NameTypeDescription
subscriptionSubscriptionSubscription

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:

NameTypeDescription
subscriptionSubscriptionSubscription
subscriberaddressSubscriber 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:

NameTypeDescription
subscriptionSubscriptionSubscription

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:

NameTypeDescription
accountaddressAccount 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:

NameTypeDescription
bySubscriberboolSee above description of bool
accountaddressAccount address for subscriptions

Return Value:

NameTypeDescription
SubView[]SubViewArray of Subview structs

getTotalSubscribers

function getTotalSubscribers(
) returns (uint)

Returns total number of subscribers.

Return Value:

NameTypeDescription
uintuintTotal amount of subscribers in contract

getSubscribersById

function getSubscribersById(
bytes32 id
) external view returns (SubscriberView[] memory)

Returns array of objects containing subscriber info.

Parameters:

NameTypeDescription
idbytes32Unique subscription id

Return Value:

NameTypeDescription
SubscriberView[]SubscriberViewArray of SubscriberView structs

getUnsubscribedLength

function getUnsubscribedLength(
bytes32 id
) external view returns (uint256)

Returns number of users in the unsubscribed during pagition mapping

Parameters:

NameTypeDescription
idbytes32Unique subscription id

Return Value:

NameTypeDescription
uint256uint256Number 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:

NameTypeDescription
unixuintUnix time value

Return Value:

NameTypeDescription
timeTimeTime 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:

NameTypeDescription
yearuintNumber of year in Gregorian Calendar

Return Value:

NameTypeDescription
leapYearboolTrue 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:

NameTypeDescription
yearuintNumber of year in Gregorian Calendar
monthuintNumber of month in Gregorian Calendar

Return Value:

NameTypeDescription
daysInMonthuintNumber 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:

NameTypeDescription
unixTimeuintUnix time value

Return Value:

NameTypeDescription
dayOfWeekuint16Day 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:

NameTypeDescription
yearDaysuintDay of the year (Between 1 - 365)
yearuintNumber of year in Gregorian Calendar

Return Value:

NameTypeDescription
quarterDayuint16Day 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:

NameTypeDescription
unixTimeuintUnix time value

Return Value:

NameTypeDescription
dayCountuint16Number 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:

NameTypeDescription
unixTimeuintUnix time value
dueDayuint40Day in frequency range when subscription is paid
feeuintFee amount in wei (18 decimals)
frequencyuint8Frequency

Return Value:

NameTypeDescription
uintuintProrated 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;