保存块。固体结构中的timestamp,但功能正在返回当前时间的时间戳
这是我第一次在stackoverflow上问一个问题,所以我希望我在这里提供了所有所需的信息 ,
所以我写了一份坚固的智能合约来维持nfts好吧,但是脱落的部分不是,我试图编写拆卸功能,以便所有者只有一定时间过去了,只能释放其NFT,这次是存储在固定结构中的UINT48值
struct Stake {
uint24 tokenId;
uint48 timestamp; <------
address owner;
}
:是放入功能:
function stake(uint256[] calldata tokenIds) external {
IERC721N nft = IERC721N(NftAddress);
uint256 tokenId;
totalStaked += tokenIds.length;
for (uint256 i = 0; i < tokenIds.length; i++) {
tokenId = tokenIds[i];
require(nft.ownerOf(tokenId) == msg.sender, "not your token");
require(vault[tokenId].tokenId == 0, "already staked");
nft.transferFrom(msg.sender, address(this), tokenId);
emit BlockStaked(msg.sender, tokenId, block.timestamp);
vault[tokenId] = Stake({
owner: msg.sender,
tokenId: uint24(tokenId),
timestamp: uint48(block.timestamp)
});
}
}
这是放下的功能:
function _unstakeMany(address account, uint256[] calldata tokenIds)
internal
{
IERC721N nft = IERC721N(NftAddress);
// uint256 tokenId;
Stake memory staked;
totalStaked -= tokenIds.length;
for (uint256 i = 0; i < tokenIds.length; i++) {
// tokenId = tokenIds[i];
staked = vault[tokenIds[i]];
uint256 timeStamp = stakeStamp(tokenIds[i]);
require(staked.owner == msg.sender, "not an owner");
if(block.timestamp < timeStamp + 60){
revert timeError(timeStamp, tokenIds[i]);
}
delete vault[tokenIds[i]];
emit BlockUnstaked(account, tokenIds[i], block.timestamp);
nft.transferFrom(address(this), account, tokenIds[i]);
}
}
这是完整的代码:
// SPDX-License-Identifier: MIT LICENSE
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
interface IERC20N is IERC20 {
function mint(address to, uint256 amount) external;
}
interface IERC721N is IERC721 {
function totalSupply() external view returns (uint256);
}
contract Vault is Ownable, IERC721Receiver {
using SafeMath for uint256;
uint256 public totalStaked;
// struct to store a stake's token, owner, and earning values
struct Stake {
uint24 tokenId;
uint48 timestamp;
address owner;
}
event BlockStaked(address owner, uint256 tokenId, uint256 value);
event BlockUnstaked(address owner, uint256 tokenId, uint256 value);
event Claimed(address owner, uint256 amount);
// maps tokenId to stake
mapping(uint256 => Stake) public vault;
// initialising Nft cotract and coin contract
address public NftAddress;
address public TokenAddress;
// IERC721N nft1 = IERC721N(NftAddress);
// IERC20N token = IERC20N(TokenAddress);
error timeError(uint256 timeleft, uint256 tokenId);
// error timeError(uint256 timeleft, uint256 blockStamp, uint256 tokenId);
constructor() {}
function setNftAddress(address _address) public onlyOwner {
NftAddress = _address;
}
function setTokenAddress(address _address) public onlyOwner {
TokenAddress = _address;
}
function stake(uint256[] calldata tokenIds) external {
IERC721N nft = IERC721N(NftAddress);
uint256 tokenId;
totalStaked += tokenIds.length;
for (uint256 i = 0; i < tokenIds.length; i++) {
tokenId = tokenIds[i];
require(nft.ownerOf(tokenId) == msg.sender, "not your token");
require(vault[tokenId].tokenId == 0, "already staked");
nft.transferFrom(msg.sender, address(this), tokenId);
emit BlockStaked(msg.sender, tokenId, block.timestamp);
vault[tokenId] = Stake({
owner: msg.sender,
tokenId: uint24(tokenId),
timestamp: uint48(block.timestamp)
});
}
}
uint256 public TIMe;
function _unstakeMany(address account, uint256[] calldata tokenIds)
internal
{
// IERC721N nft = IERC721N(NftAddress);
// uint256 tokenId;
Stake memory staked;
totalStaked -= tokenIds.length;
for (uint256 i = 0; i < tokenIds.length; i++) {
// tokenId = tokenIds[i];
staked = vault[tokenIds[i]];
uint256 timeStamp = stakeStamp(tokenIds[i]);
require(staked.owner == msg.sender, "not an owner");
if(block.timestamp < timeStamp + 60){
revert timeError(timeStamp, tokenIds[i]);
}
delete vault[tokenIds[i]];
emit BlockUnstaked(account, tokenIds[i], block.timestamp);
// nft.transferFrom(address(this), account, tokenIds[i]);
}
}
function blockStamp() public view returns(uint256){
return block.timestamp;
}
function stakeStamp(uint256 id) public view returns(uint256){
return vault[id].timestamp;
}
function unstake(uint256[] calldata tokenIds) external {
_claim(msg.sender, tokenIds, true);
}
function _claim(
address account,
uint256[] calldata tokenIds,
bool _unstake
) internal {
uint256 tokenId;
uint256 earned = 0;
IERC20N token = IERC20N(TokenAddress);
for (uint256 i = 0; i < tokenIds.length; i++) {
tokenId = tokenIds[i];
Stake memory staked = vault[tokenId];
require(staked.owner == account, "not an owner");
uint256 stakedAt = staked.timestamp;
vault[tokenId] = Stake({
owner: account,
tokenId: uint24(tokenId),
timestamp: uint48(block.timestamp)
});
if (block.timestamp - stakedAt > 300) {
earned += 1000 ether;
}
}
if (earned > 0) {
token.mint(msg.sender, earned);
}
if (_unstake) {
_unstakeMany(account, tokenIds);
}
emit Claimed(account, earned);
}
function timeFromStaked(uint256[] calldata tokenIds)
public
view
returns (uint256[] memory)
{
uint256[] memory list = new uint256[](tokenIds.length);
for (uint256 i = 0; i < tokenIds.length; i++) {
uint256 tokenId = tokenIds[i];
Stake memory staked = vault[tokenId];
uint256 stakedAt = staked.timestamp;
list[i] = uint48(block.timestamp) - stakedAt;
}
return list;
}
// should never be used inside of transaction because of gas fee
function balanceOf(address account) public view returns (uint256) {
IERC721N nft = IERC721N(NftAddress);
uint256 balance = 0;
uint256 supply = nft.totalSupply();
for (uint256 i = 1; i <= supply; i++) {
if (vault[i].owner == account) {
balance += 1;
}
}
return balance;
}
// should never be used inside of transaction because of gas fee
function tokensOfOwner(address account)
public
view
returns (uint256[] memory ownerTokens)
{
IERC721N nft = IERC721N(NftAddress);
uint256 supply = nft.totalSupply();
uint256[] memory tmp = new uint256[](supply);
uint256 index = 0;
for (uint256 tokenId = 1; tokenId <= supply; tokenId++) {
if (vault[tokenId].owner == account) {
tmp[index] = vault[tokenId].tokenId;
index += 1;
}
}
uint256[] memory tokens = new uint256[](index);
for (uint256 i = 0; i < index; i++) {
tokens[i] = tmp[i];
}
return tokens;
}
function onERC721Received(
address,
address from,
uint256,
bytes calldata
) external pure override returns (bytes4) {
require(from == address(0x0), "Cannot send nfts to Vault directly");
return IERC721Receiver.onERC721Received.selector;
}
}
在我在Ganache-Cli上运行它并执行初始化合同所需的步骤,我将一个NFT放在一个NFT
之后,然后一段时间后,我在本地区块链上进行另一次交易要更新块。Timestamp值并尝试
在我尝试在时间通过之前取消销售时尝试删除,返回的TimeError会返回相应股份的时间戳记的值,而不是正确的值,因为它总是每次运行Unbestake函数时它总是更改,并且它始终等于block.timestamp value
此时间邮票值使用称为stakestamp的函数获取,stakestamp函数始终从结构中返回正确的值block.timestamp值,而不是struct 中保存的timeStamp
这是stakestamp函数:
function stakeStamp(uint256 id) public view returns(uint256){
return vault[id].timestamp;
}
您可以在第三代码块中检查我如何在上面的unainsest函数中使用它,
我希望我提供有关问题的良好信息。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
首先,我认为您应该进行一些自动测试,以确定导致此时间戳错误的原因。我已经为您做了一些,我会附加这个答案。
您的合同中有些事情可能会更好。
例如,在第99行中(至少在我的编辑中,在我的编辑中)
block.timestamp
是一个不断增长的值。这是EVM的时间戳,因此它增加了几秒钟。检查block.timestamp&lt; Timestamp + 60
将在60秒钟调用stake()
后会丢弃错误。也许您应该将其重写为,因为阻止计时器似乎很小,我认为您没有使用测试环境并在混音或其他内容上测试合同。
我使用Hardhat对您的合同进行了一些测试,并提出了可以访问的要点。看看:
https://remix.ethereum.org/#version = soljson-v0.8.7+commit.e28d00a7.js&amptimize = false=false&amp = false&amp =
200股份和抢劫。
关于您的问题,这一点:
在调用函数的那一刻,您 赌注降低到特定的
block.timestamp
。它是静态的,不会改变。我完全不明白你在那里的意思。另外,timestamp
从stakestamp()
返回的始终不同于block.timestmap
。 ,它始终低于block.timestmap
,因为目的是设置stake()
并在unstake()
上检查它更具体地说 是否有使用
uint48
作为时间戳的特定原因?鉴于在坚固的文档中指出的是uint256
我不知道这种铸件是否有任何不必要的行为。鉴于时间戳已在几秒钟内,并且它将完全适合uint48
。First of all, I think you should make some automated tests in order to identify what is causing this timestamp bug. I've made some for you already that I will be appending to this answer.
There are some things that could be better in your contract.
For example, in line 99 (at least in my editor after some linting)
block.timestamp
is a value that keeps growing. It's the timestamp of the EVM, so it's increasing by the seconds. checkingblock.timestamp < timeStamp + 60
will throw error after 60 seconds of callingstake()
. Maybe you should rewrite it toAs the blocking timers seem to be small, I assume you are not using a testing environment and testing the contract on Remix or something else.
I've made some testing on your contract using Hardhat and made a gist that you can access. Take a look:
https://remix.ethereum.org/#version=soljson-v0.8.7+commit.e28d00a7.js&optimize=false&runs=200&gist=3ad1a14ab5ad4ec5aca16ae6414ffb67
It basically tests if the Vault can stake and unstake.
Regarding to your question in this point:
You stake to a specific
block.timestamp
in the moment the function was called. It is static, doesn't change. I quite doesn't understand what you mean there. Also,timeStamp
returned from thestakeStamp()
is always different fromblock.timestmap
. More specifically, it's always lower thanblock.timestmap
since the intention is to set itstake()
and check it onunstake()
Also, is there any specific reason to use
uint48
as the timestamp? Given that it is stated in the Solidity documentation that it is anuint256
I don't know if this cast has any unwanted behavior. Probably not, given that the timestamp is in seconds and it would perfectly fit in auint48
.导入
safetransferfrom
功能从IERC721发出。使用safetransfrom
stake中的功能,_UNSTAKEMANY
函数。如果您没有得到解决方案,只需在Twitter(@bhargav_dasappa)中ping我即可。Import
safeTransferFrom
function from IERC721. usesafeTransferFrom
function in stake and_unstakeMany
functions. if you dont get solution , just ping me in twitter(@bhargav_dasappa).