Conversion from CRC to Time Circles and back


Time Circles (TC) are a time-dependent display unit for Circles.

The unit is rooted in the daily UBI payout every user receives in CRC and the fixed inflation rate. It normalizes the daily UBI payout to 24 TC regardless of the inflation.



  • Circles Year: A year in circles is 365.25 days long (in seconds: 31557600).
  • Inflation: 7% per Circles Year.
  • Initial daily payout: In the first year everyone got 8 CRC per day.
  • Circles inception: 2020-10-15 The date when the official Circles contract was deployed.


  1. How many circles-years and days have passed between the circles inception and the transaction?
    // Your transaction timestamp and amount in CRC  
    const transactionTimestamp = new Date("2022-05-03T04:21:25.000Z").getTime();  
    const transactionCrcAmount = 8.566935185185093;  
    // Constants  
    const circlesInceptionTimestamp = new Date("2020-10-15T00:00:00.000Z").getTime();  
    const oneDayInMilliSeconds = 86400 * 1000;  
    const oneCirclesYearInMilliSeconds = 31557600 * 1000;  
    // How many days passed between the circles inception and the transaction?  
    const daysSinceCirclesInception = (transactionTimestamp - circlesInceptionTimestamp) / oneDayInMilliSeconds;  
    // How many circles years passed between the circles inception and the transaction?  
    const circlesYearsSince = (transactionTimestamp - circlesInceptionTimestamp) / oneCirclesYearInMilliSeconds;  
    // How many days passed since the last circles new-year?  
    const daysInCurrentCirclesYear = daysSinceCirclesInception % 365.25;
    // NOTE: still uses the code-line below
    // const daysInCurrentCirclesYear = Math.ceil(daysSinceCirclesInception % 365.25);
  2. How large is the daily payout for the previous and current circles year?
    // Everyone got 8 CRC per day in the first year  
    const initialDailyCrcPayout = 8;  
    let circlesPayoutInCurrentYear = initialDailyCrcPayout;  
    let previousCirclesPerDayValue = initialDailyCrcPayout;  
    // Add the yearly inflation to the initial payout and keep track  
    // of the previous and current year's value  
    for (let index = 0; index < circlesYearsSince; index++) {  
        previousCirclesPerDayValue = circlesPayoutInCurrentYear;  
        circlesPayoutInCurrentYear = circlesPayoutInCurrentYear * 1.07;  
    // The daily payout for the previous and current year  
    const payoutPerDayInYear = {  
        current: circlesPayoutInCurrentYear,  
        previous: previousCirclesPerDayValue  
  3. Interpolate the exact “Payout per day” value for the transaction timestamp
    const x = payoutPerDayInYear.previous;  
    const y = payoutPerDayInYear.current;  
    const a = daysInCurrentCirclesYear / 365.25;  
    const payoutAtTimestamp = x * (1 - a) + y * a;
  4. a) Calculate the Time Circles value
    const timeCircles = transactionCrcAmount / payoutAtTimestamp * 24;
    b) Calculate the CRC value
    const crc = timeCircles / 24 * payoutAtTimestamp;

To make sure all interfaces consume show the same numbers it might sense to write a “Circles token view” in solidity.

The function could get an array of trusted accounts as input (either Safe or token address) and return the sum of the CRC balances of a user of those while applying the conversion.

I’ve published the code to @jaensen/timecircles - npm

import {CrcToTc, TcToCrc} from "@jaensen/timecircles";

// Since TC are time-dependent we'll always need a timestamp
const transactionTimestamp = new Date("2022-05-03T04:21:25.000Z");
// The amount in CRC
const transactionCrcAmount = 8.566935185185093;  

// Convert to TC
const tcAmount = CrcToTc(transactionTimestamp, transactionCrcAmount);
console.log(`${transactionCrcAmount} CRC are ${tcAmount} TC at ${transactionTimestamp}`);

// Convert back to CRC
const crcAmount = TcToCrc(transactionTimestamp, tcAmount);
console.log(`${crcAmount} TC are ${crcAmount} CRC at ${transactionTimestamp}`);

Hi all, in order to seek more collaboration between teams we propose to create a joint github repository where all the Circles dev teams are members, so for example the code with the conversion between CRC and TC that @jaensen has written ( can live there and we can all contribute. Then, there is also a @circles scope in npm registry that we (bitspossessed) manage but we invite other teams to use and publish on it from that shared repository. So for now, we are going publish the package from circlesland repository also under the @circles scope.


I tried to convert this to Solidity, the result is deployed here

It is split into a Solidity library at 0xE7e8FCb389Bf950b0347b955155083d9B93EE7fa and a contract with the external functions crcToTc and tcToCrc as in the Typescript code.

Note: the result has to be divided by 10^9 as Solidity has no floating point, only integers

I added two small changes:

  1. timestamp in seconds, not milliseconds.
  2. scale is expanded to 10^18

It is split into a Solidity library at 0x089589883CcAc00E8E8eDe98aE84A2c4C40B5558 and the contract with the external functions crcToTc and tcToCrc as in the Typescript code.

1 Like

Here you can find the timecircles package under @circles scope: