4

I have a trouble with comparing timestamp parameter(in test) and now in smart contract.

Here is my smart contract:

function create(uint created_at) public {
    require(now > created_at, "The created_at should be less than now .");
}

And test function:

it("...should store the created_at", async () => {
    const storageInstance = await Storage.deployed();
    let created_at = new Date().getTime();//create utc now timestamp 
    await storageInstance.create(created_at);
 }

The test doesn't pass. Error:

The created_at should be less than now .

2
  • 1
    It's not supposed to pass. Even if you take a pair of "regular" machines and compare the JS time on each one of them, they will almost certainly not be the same every time you run the test. Let alone, comparing the JS time on your machine with the current block's timestamp of whatever network you are working with. Also, note that the current block timestamp is updated on average every 15-17 seconds, so even the best you could possibly hope for would give you about 5% success. Mar 11, 2019 at 14:06
  • Actually even if i try require((now + 1 days) > created_at, "The created_at should be less than now ."); in smart contracts, the error is same. Mar 11, 2019 at 14:11

2 Answers 2

9

now in Solidity is the amount of seconds since the Epoch, (see Is the block.timestamp value in Solidity seconds or milliseconds?). Javascript's new Date().getTime() / Date.now() returns the amount of milliseconds since the Epoch (see Date.prototype.getTime & Date.now).

This means that Javascript's timestamp is always a factor 1000 larger than the one used by Solidity. You could change your JS code to divide the timestamp by 1000.

let created_at = Math.floor(Date.now() / 1000)

Also be mindful of goodvibration's comment in your design.

UPDATE: new Date().getTime() --> Date.now() (goodvibration's comment)

0
0

I would avoid using javascript dates when working with Solidity. It's better to work with unix time directly. I've also been struggling with this and came up with this solution:

  • use hardhat's network-helpers library to get the timestamp of the latest block
  • use unix seconds to assert results
  • use assert.closeTo() instead of assert.equalTo(), this way you can factor in you code execution time

Here I've made a simple example where you have a contract which sets a variable to next week when setNextWeek() is called. In the test we assert if the setNextWeek() function indeed set the time to next week.

Solidity

uint256 nextWeek;

function setNextWeek() public {
    nextWeek = block.timestamp + 1 weeks;
}

Hardhat Test

const helpers = require("@nomicfoundation/hardhat-network-helpers")


const ONE_WEEK_UNIX = 604800 // 1 week in UNIX time (seconds)

it.only("setNextWeek should set UNIX time to 1 week from now", async function () {
    await contract.setNextWeek()
    const nextWeekResult = await contract.nextWeek()

    const timestamp = parseInt(await helpers.time.latest());
    const nextWeek = timestamp + ONE_WEEK_UNIX
    
    // checks if the result is close to the expected result with a maximum difference of 5 (seconds)
    assert.closeTo(nextWeekResult.toNumber(), nextWeek, 5);
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.