如何在构造函数中添加一个 uint T,它将成为我的智能合约中的一个时间常数?
How to add a uint T in constructor that will be a time constant inside my smart contract?
我需要一个时间常数来计算存款、取款和奖励子池的时间戳。这个称为 T 的时间常数将从合约部署开始,并且不会特定于一个 address/user。即奖励(R)被分为 3 个子池:R1 = 20% 在合约部署后 2T 后可用,R2 = 30% 在合约部署后 3T 后可用, R3= 50% 在合约部署后 4T 后可用。我需要这个变量以分钟为单位,比如发送方输入3 我希望每个时间戳之间的时间是3,比如存款在第一个T,取款在3T之后。如何分分钟设置?
这里是状态变量
uint256 public T;
这里是构造函数
constructor(address stakingToken, address rewardsToken, uint256 timeConstant) {
s_stakingToken = IERC20(stakingToken);
s_rewardsToken = IERC20(rewardsToken);
initialTime = block.timestamp;
T = timeConstant;
}
我的完整代码
error TransferFailed();
error NeedsMoreThanZero();
contract Staking is ReentrancyGuard {
IERC20 public s_rewardsToken;
IERC20 public s_stakingToken;
// This is the reward token per seco
nd
// Which will be multiplied by the tokens the user staked divided by the total
// This ensures a steady reward rate of the platform
// So the more users stake, the less for everyone who is staking.
uint256 public constant REWARD_RATE = 100;
uint256 public s_lastUpdateTime;
uint256 public s_rewardPerTokenStored;
//uint256 public constant T = 3;
uint256 public initialTime;
uint256 public T;
mapping(address => uint256) public s_userRewardPerTokenPaid;
mapping(address => uint256) public s_rewards;
uint256 private s_totalSupply;
mapping(address => uint256) public s_balances; // someones address => how much he staked
event Staked(address indexed user, uint256 indexed amount);
event WithdrewStake(address indexed user, uint256 indexed amount);
event RewardsClaimed(address indexed user, uint256 indexed amount);
constructor(address stakingToken, address rewardsToken, uint256 timeConstant) {
s_stakingToken = IERC20(stakingToken);
s_rewardsToken = IERC20(rewardsToken);
initialTime = block.timestamp;
T = timeConstant;
}
/**
* @notice How much reward a token gets based on how long it's been in and during which "snapshots"
*/
function rewardPerToken() public view returns (uint256) {
if (s_totalSupply == 0) {
return s_rewardPerTokenStored;
}
return
s_rewardPerTokenStored +
(((block.timestamp - s_lastUpdateTime) * REWARD_RATE * 1e18) / s_totalSupply);
}
/**
* @notice How much reward a user has earned
*/
function earned(address account) public view returns (uint256) {
uint256 nowTime = block.timestamp-initialTime;
require(nowTime > 2*T);
if (nowTime > 2*T && nowTime <= 3*T) {
return
((((s_balances[account] * (rewardPerToken() - s_userRewardPerTokenPaid[account])) /
1e18) + s_rewards[account]) / 5 );
} else if
(nowTime > 3*T && nowTime <= 4*T) {
return
((((s_balances[account] * (rewardPerToken() - s_userRewardPerTokenPaid[account])) /
1e18) + s_rewards[account]) / 2 );
} else {
return
(((s_balances[account] * (rewardPerToken() - s_userRewardPerTokenPaid[account])) /
1e18) + s_rewards[account]);
}
}
/**
* @notice Deposit tokens into this contract
* @param amount | How much to stake
*/
function stake(uint256 amount)
external
updateReward(msg.sender)
nonReentrant
moreThanZero(amount)
{
//from T0 to T deposit is available
uint256 nowTime = block.timestamp-initialTime; // time between deployment of contract and now.
require(nowTime < T);
s_totalSupply += amount;
// increasing how much they are staking for how much they staked each time.
s_balances[msg.sender] += amount;
emit Staked(msg.sender, amount);
// sending an amount of token from an address to this contract
bool success = s_stakingToken.transferFrom(msg.sender, address(this), amount);
// if not successfully sent, return an error.
// using the below code instead of "require(success, "Failed")" reduces gas fees, since it doesn't output a string.
if (!success) {
revert TransferFailed(); // revert resets everything done in a failed transaction.
}
}
/**
* @notice Withdraw tokens from this contract
* @param amount | How much to withdraw
*/
function withdraw(uint256 amount) external updateReward(msg.sender) nonReentrant {
// from 2T the user can reward his tokens
uint256 nowTime = block.timestamp-initialTime; // time between deployment of contract and now.
require(nowTime > 2* T);
s_totalSupply -= amount;
s_balances[msg.sender] -= amount;
emit WithdrewStake(msg.sender, amount);
// transfer: send tokens from contract back to msg.sender.
bool success = s_stakingToken.transfer(msg.sender, amount);
if (!success) {
revert TransferFailed(); // revert resets everything done in a failed transaction.
}
}
/**
* @notice User claims their tokens
*/
function claimReward() external updateReward(msg.sender) nonReentrant {
uint256 reward = s_rewards[msg.sender];
s_rewards[msg.sender] = 0;
emit RewardsClaimed(msg.sender, reward);
bool success = s_rewardsToken.transfer(msg.sender, reward);
if (!success) {
revert TransferFailed(); // revert resets everything done in a failed transaction.
}
}
/********************/
/* Modifiers Functions */
/********************/
modifier updateReward(address account) {
s_rewardPerTokenStored = rewardPerToken();
s_lastUpdateTime = block.timestamp;
s_rewards[account] = earned(account);
s_userRewardPerTokenPaid[account] = s_rewardPerTokenStored;
_;
}
modifier moreThanZero(uint256 amount) {
if (amount == 0) {
revert NeedsMoreThanZero();
}
_;
}
/********************/
/* Getter Functions */
/********************/
// Ideally, we'd have getter functions for all our s_ variables we want exposed, and set them all to private.
// But, for the purpose of this demo, we've left them public for simplicity.
function getStaked(address account) public view returns (uint256) {
return s_balances[account];
}
}
首先维护一个映射,用于存储每个用户的时间。然后制作诸如 depositTimeSet 、 withdrawalTimeSet 之类的函数,用于为不同的用户存储不同的时间。存入时更新变量,取款时检查时间是否超过。
struct Users {
uint dipositTime;
uint withDrawTime;
uint lastDepositTime;
}
mapping(address => Users ) users;
function depositeTimeSet(uint t) {
users[msg.sender].dipositTime = t minutes;
withdrawalTimeSet(t);
}
function withdrawalTimeSet(uint t) {
users[msg.sender].withDrawTime = 3 * t minutes
}
function deposite() {
transferFrom(msg.sender,address(this));
depositeTimeSet(3); // considering sender send 3
users[msg.sender].lastDepositTime = now;
}
function withdraw() {
if(
now > users[msg.sender].lastDepositTime +
users[msg.sender].withDrawTime,"too early for withdraw
request"
)
transferFrom(address(this),msg.sender);
}
您可以看到 THIS 一个可能会有帮助
您可以在 solidity 中看到 THIS 时间单位资源
我需要一个时间常数来计算存款、取款和奖励子池的时间戳。这个称为 T 的时间常数将从合约部署开始,并且不会特定于一个 address/user。即奖励(R)被分为 3 个子池:R1 = 20% 在合约部署后 2T 后可用,R2 = 30% 在合约部署后 3T 后可用, R3= 50% 在合约部署后 4T 后可用。我需要这个变量以分钟为单位,比如发送方输入3 我希望每个时间戳之间的时间是3,比如存款在第一个T,取款在3T之后。如何分分钟设置? 这里是状态变量
uint256 public T;
这里是构造函数
constructor(address stakingToken, address rewardsToken, uint256 timeConstant) {
s_stakingToken = IERC20(stakingToken);
s_rewardsToken = IERC20(rewardsToken);
initialTime = block.timestamp;
T = timeConstant;
}
我的完整代码
error TransferFailed();
error NeedsMoreThanZero();
contract Staking is ReentrancyGuard {
IERC20 public s_rewardsToken;
IERC20 public s_stakingToken;
// This is the reward token per seco
nd
// Which will be multiplied by the tokens the user staked divided by the total
// This ensures a steady reward rate of the platform
// So the more users stake, the less for everyone who is staking.
uint256 public constant REWARD_RATE = 100;
uint256 public s_lastUpdateTime;
uint256 public s_rewardPerTokenStored;
//uint256 public constant T = 3;
uint256 public initialTime;
uint256 public T;
mapping(address => uint256) public s_userRewardPerTokenPaid;
mapping(address => uint256) public s_rewards;
uint256 private s_totalSupply;
mapping(address => uint256) public s_balances; // someones address => how much he staked
event Staked(address indexed user, uint256 indexed amount);
event WithdrewStake(address indexed user, uint256 indexed amount);
event RewardsClaimed(address indexed user, uint256 indexed amount);
constructor(address stakingToken, address rewardsToken, uint256 timeConstant) {
s_stakingToken = IERC20(stakingToken);
s_rewardsToken = IERC20(rewardsToken);
initialTime = block.timestamp;
T = timeConstant;
}
/**
* @notice How much reward a token gets based on how long it's been in and during which "snapshots"
*/
function rewardPerToken() public view returns (uint256) {
if (s_totalSupply == 0) {
return s_rewardPerTokenStored;
}
return
s_rewardPerTokenStored +
(((block.timestamp - s_lastUpdateTime) * REWARD_RATE * 1e18) / s_totalSupply);
}
/**
* @notice How much reward a user has earned
*/
function earned(address account) public view returns (uint256) {
uint256 nowTime = block.timestamp-initialTime;
require(nowTime > 2*T);
if (nowTime > 2*T && nowTime <= 3*T) {
return
((((s_balances[account] * (rewardPerToken() - s_userRewardPerTokenPaid[account])) /
1e18) + s_rewards[account]) / 5 );
} else if
(nowTime > 3*T && nowTime <= 4*T) {
return
((((s_balances[account] * (rewardPerToken() - s_userRewardPerTokenPaid[account])) /
1e18) + s_rewards[account]) / 2 );
} else {
return
(((s_balances[account] * (rewardPerToken() - s_userRewardPerTokenPaid[account])) /
1e18) + s_rewards[account]);
}
}
/**
* @notice Deposit tokens into this contract
* @param amount | How much to stake
*/
function stake(uint256 amount)
external
updateReward(msg.sender)
nonReentrant
moreThanZero(amount)
{
//from T0 to T deposit is available
uint256 nowTime = block.timestamp-initialTime; // time between deployment of contract and now.
require(nowTime < T);
s_totalSupply += amount;
// increasing how much they are staking for how much they staked each time.
s_balances[msg.sender] += amount;
emit Staked(msg.sender, amount);
// sending an amount of token from an address to this contract
bool success = s_stakingToken.transferFrom(msg.sender, address(this), amount);
// if not successfully sent, return an error.
// using the below code instead of "require(success, "Failed")" reduces gas fees, since it doesn't output a string.
if (!success) {
revert TransferFailed(); // revert resets everything done in a failed transaction.
}
}
/**
* @notice Withdraw tokens from this contract
* @param amount | How much to withdraw
*/
function withdraw(uint256 amount) external updateReward(msg.sender) nonReentrant {
// from 2T the user can reward his tokens
uint256 nowTime = block.timestamp-initialTime; // time between deployment of contract and now.
require(nowTime > 2* T);
s_totalSupply -= amount;
s_balances[msg.sender] -= amount;
emit WithdrewStake(msg.sender, amount);
// transfer: send tokens from contract back to msg.sender.
bool success = s_stakingToken.transfer(msg.sender, amount);
if (!success) {
revert TransferFailed(); // revert resets everything done in a failed transaction.
}
}
/**
* @notice User claims their tokens
*/
function claimReward() external updateReward(msg.sender) nonReentrant {
uint256 reward = s_rewards[msg.sender];
s_rewards[msg.sender] = 0;
emit RewardsClaimed(msg.sender, reward);
bool success = s_rewardsToken.transfer(msg.sender, reward);
if (!success) {
revert TransferFailed(); // revert resets everything done in a failed transaction.
}
}
/********************/
/* Modifiers Functions */
/********************/
modifier updateReward(address account) {
s_rewardPerTokenStored = rewardPerToken();
s_lastUpdateTime = block.timestamp;
s_rewards[account] = earned(account);
s_userRewardPerTokenPaid[account] = s_rewardPerTokenStored;
_;
}
modifier moreThanZero(uint256 amount) {
if (amount == 0) {
revert NeedsMoreThanZero();
}
_;
}
/********************/
/* Getter Functions */
/********************/
// Ideally, we'd have getter functions for all our s_ variables we want exposed, and set them all to private.
// But, for the purpose of this demo, we've left them public for simplicity.
function getStaked(address account) public view returns (uint256) {
return s_balances[account];
}
}
首先维护一个映射,用于存储每个用户的时间。然后制作诸如 depositTimeSet 、 withdrawalTimeSet 之类的函数,用于为不同的用户存储不同的时间。存入时更新变量,取款时检查时间是否超过。
struct Users {
uint dipositTime;
uint withDrawTime;
uint lastDepositTime;
}
mapping(address => Users ) users;
function depositeTimeSet(uint t) {
users[msg.sender].dipositTime = t minutes;
withdrawalTimeSet(t);
}
function withdrawalTimeSet(uint t) {
users[msg.sender].withDrawTime = 3 * t minutes
}
function deposite() {
transferFrom(msg.sender,address(this));
depositeTimeSet(3); // considering sender send 3
users[msg.sender].lastDepositTime = now;
}
function withdraw() {
if(
now > users[msg.sender].lastDepositTime +
users[msg.sender].withDrawTime,"too early for withdraw
request"
)
transferFrom(address(this),msg.sender);
}
您可以看到 THIS 一个可能会有帮助
您可以在 solidity 中看到 THIS 时间单位资源