You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Solidity如何处理block.timestamp实现8:00-18:00合约调用限制

Solidity 时间区间校验实现方案

核心计算原理

block.timestamp返回当前区块的Unix时间戳(单位:秒,基准为1970-01-01 00:00:00 UTC),不需要做复杂的字符串格式化,直接通过数学运算就能提取当日时间信息完成校验:

  • 一天总秒数固定为86400(246060)
  • 时间戳对86400取模,得到的结果就是当前时间距离当日UTC 0点的偏移秒数
  • 对应时段的秒数直接用小时数乘3600计算即可,比如UTC 8AM对应8*3600=28800,UTC 6PM对应18*3600=64800

修正后的完整代码

你原有代码存在一处逻辑疏漏:校验完2小时间隔后没有更新用户上次调用时间,会导致间隔校验规则完全不生效。加入时间区间校验的完整可运行代码如下:

mapping(address => uint256) public coffeKitchenLatestAqcuiredBalances;
// 常量统一定义,方便后续调整
uint256 public constant CALL_INTERVAL = 7200; // 2小时调用间隔
uint256 public constant DAY_SECONDS = 86400;
uint256 public constant ALLOW_START = 8 * 3600; // 允许调用起始时间:UTC 8AM
uint256 public constant ALLOW_END = 18 * 3600; // 允许调用结束时间:UTC 6PM

function requestStarCoinFromCoffeeKitchenFaucet() public {
    address callerAddress = msg.sender;
    uint256 userLastRetrieveTime = coffeKitchenLatestAqcuiredBalances[callerAddress];
    uint256 epochNow = block.timestamp;

    // 校验调用时间在允许区间内
    uint256 secondsOfDay = epochNow % DAY_SECONDS;
    require(secondsOfDay >= ALLOW_START && secondsOfDay < ALLOW_END, "Only callable between 8AM and 6PM");

    // 校验2小时调用间隔
    if (userLastRetrieveTime != 0){
        require(userLastRetrieveTime < epochNow - CALL_INTERVAL,"You need to wait for 2 hours from your last call");
    }

    // 更新用户上次调用时间,否则间隔校验永远不生效
    coffeKitchenLatestAqcuiredBalances[callerAddress] = epochNow;

    // 此处编写发放StarCoin的业务逻辑
}

注意事项

  • 时区适配:以上代码默认时间区间基于UTC时区,如果你需要对应特定时区的本地时间,只需要在取模前加/减对应时区偏移的秒数即可。比如要适配北京时间(UTC+8)的8AM-6PM,只需要把secondsOfDay的计算逻辑改为uint256 secondsOfDay = (epochNow + 8*3600) % DAY_SECONDS;,起止时间常量保持83600和183600不变即可。
  • 时间戳操纵风险:矿工可以对区块时间戳做最多几十秒的小幅调整,这类时间校验不适合高价值资产的严格时间判断,但水龙头这类低价值场景完全可以正常使用。
  • 不要在链上做复杂的日期字符串格式化,纯数学运算的gas成本最低,也完全能满足区间校验需求。

内容的提问来源于stack exchange,提问作者Akiner Alkan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 00:15:52