如何在前端JavaScript中无签名获取Solana链上unix_timestamp
前端无签名获取Solana链上unix_timestamp实现方案
Solana Rust智能合约通过如下代码获取链上时间戳:
solana_program::clock::Clock::get()?.unix_timestamp
该值为自纪元时间(1970年1月1日GMT零点)起算的秒数,受Solana网络出块性能影响,和本地现实时间可能存在几秒到几十秒的偏差,不少依赖时间因子计算奖励的合约(比如Step Finance、复用其逻辑的Gem Farm)都需要前端拿到和链上完全一致的时间戳才能复现计算逻辑。
不需要发起交易、不需要钱包签名,仅通过Solana节点只读RPC接口就能拿到和合约执行时完全一致的unix_timestamp,具体实现如下:
实现原理
链上unix_timestamp属于Solana Clock系统变量(Sysvar)的公开字段,节点会在对应确认级别的区块上维护该值,所有RPC节点都开放无权限查询接口,查询过程不涉及链上状态修改,不会产生任何Gas费用,也不需要用户签名授权。
具体实现方法
首先安装依赖@solana/web3.js,不需要引入任何钱包相关SDK。
两种实现方式效果完全一致,可以按需选择:
方法1:直接解析Clock Sysvar账号(单次RPC,性能更高)
Clock系统变量有固定的公开地址,直接拉取该账号的二进制数据,按结构解析出unix_timestamp即可,只需要一次RPC请求:
const { Connection, PublicKey, clusterApiUrl } = require('@solana/web3.js'); // 初始化RPC连接,可替换为自己的节点地址,commitment级别和合约执行环境保持一致即可 const connection = new Connection(clusterApiUrl('mainnet-beta'), 'confirmed'); const CLOCK_SYSVAR_ADDRESS = new PublicKey('SysvarC1ock11111111111111111111111111111111'); async function getChainUnixTimestamp() { const clockAccount = await connection.getAccountInfo(CLOCK_SYSVAR_ADDRESS); if (!clockAccount) throw new Error('获取Clock系统变量失败'); // Clock数据结构按顺序排列,每个字段占8字节:slot、epoch_start_timestamp、epoch、leader_schedule_epoch、unix_timestamp // unix_timestamp从第32字节偏移位置开始,为小端编码的64位有符号整数 return Number(clockAccount.data.readBigInt64LE(32)); }
方法2:通过最新区块时间查询(代码直观,不易出错)
先获取当前确认级别的最新slot,再查询该slot对应的出块时间,不需要记忆系统变量地址和数据偏移:
const { Connection, clusterApiUrl } = require('@solana/web3.js'); const connection = new Connection(clusterApiUrl('mainnet-beta'), 'confirmed'); async function getChainUnixTimestamp() { let latestSlot = await connection.getSlot('confirmed'); // 最新slot如果还没完成时间标注,往前退1-2个slot重试即可 while (latestSlot > 0) { const timestamp = await connection.getBlockTime(latestSlot); if (timestamp !== null) return timestamp; latestSlot--; } throw new Error('获取链上时间戳失败'); }
注意事项
- 必须设置和合约逻辑一致的commitment级别:大部分DApp默认用
confirmed级别,如果需要拿最终不可回滚的时间戳就换成finalized,commitment不匹配会导致拿到的时间和合约实际执行值有偏差。 - 不要直接用本地
Math.floor(Date.now() / 1000)的结果,Solana出块偶尔会出现延迟,本地时间和链上时间的偏差会导致奖励计算结果和链上实际执行结果不一致。 - 两种方法返回值都是秒级unix时间戳,和Rust合约中拿到的值完全一致,可以直接用于复现合约的时间相关计算逻辑。
内容的提问来源于stack exchange,提问作者Ozymandias
相关产品推荐
相关产品推荐

