16.SWC-116_Block values as a proxy for time
2023-07-13 15:53:01 # 09.SWC

SWC-116_Block values as a proxy for time

Block values as a proxy for time

  • Description: Contracts often need access to time values to perform certain types of functionality. Values such as block.timestamp, and block.number can give you a sense of the current time or a time delta, however, they are not safe to use for most purposes.

    In the case of block.timestamp, developers often attempt to use it to trigger time-dependent events. As Ethereum is decentralized, nodes can synchronize time only to some degree. Moreover, malicious miners can alter the timestamp of their blocks, especially if they can gain advantages by doing so. However, miners can’t set a timestamp smaller than the previous one (otherwise the block will be rejected), nor can they set the timestamp too far ahead in the future. Taking all of the above into consideration, developers can’t rely on the preciseness of the provided timestamp.

    As for block.number, considering the block time on Ethereum is generally about 14 seconds, it’s possible to predict the time delta between blocks. However, block times are not constant and are subject to change for a variety of reasons, e.g. fork reorganisations and the difficulty bomb. Due to variable block times, block.number should also not be relied on for precise calculations of time.

  • Remediation: Developers should write smart contracts with the notion that block values are not precise, and the use of them can lead to unexpected effects. Alternatively, they may make use oracles.

vulnerability contract 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
pragma solidity ^0.5.0;

contract TimeLock {
struct User {
uint amount; // amount locked (in eth)
uint unlockBlock; // minimum block to unlock eth
}

mapping(address => User) private users;

// Tokens should be locked for exact time specified
function lockEth(uint _time, uint _amount) public payable {
require(msg.value == _amount, 'must send exact amount');
// Time lock contract using block number as proxy for time
users[msg.sender].unlockBlock = block.number + (_time / 14);
users[msg.sender].amount = _amount;
}

// Withdraw tokens if lock period is over
function withdraw() public {
require(users[msg.sender].amount > 0, 'no amount locked');
require(block.number >= users[msg.sender].unlockBlock, 'lock period not over');

uint amount = users[msg.sender].amount;
users[msg.sender].amount = 0;
(bool success, ) = msg.sender.call.value(amount)("");
require(success, 'transfer failed');
}
}

vulnerability contract 2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
pragma solidity ^0.5.0;

contract TimedCrowdsale {

event Finished();
event notFinished();

// Sale should finish exactly at January 1, 2019
function isSaleFinished() private returns (bool) {
// Timestamp Dependence
return block.timestamp >= 1546300800;
}

function run() public {
if (isSaleFinished()) {
emit Finished();
} else {
emit notFinished();
}
}

}
Prev
2023-07-13 15:53:01 # 09.SWC
Next