Skip to main content
Integrating with Clocktower?

For HTTP/MCP access and the TypeScript SDK, see the Developers section. This page documents the on-chain contract API (structs, functions, and error codes).

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;