OsiPad/evm/contracts/PADTokenStake.sol

124 lines
2.8 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "hardhat/console.sol";
import "./PADToken.sol";
contract PADTokenStake {
// pool id => pool info
mapping (uint => Pool) pools;
// staker => deposits
mapping(address => Deposit[]) deposits;
uint nextPoolId = 0;
uint nextDepositId = 0;
PADToken immutable padToken;
struct Pool {
uint id;
uint lockdownDays;
uint rewardPercentage;
uint lockedAmount;
}
struct Deposit {
uint id;
address staker;
uint poolId;
uint amount;
uint lockedAt;
uint releasedAt;
}
event Staked(address indexed staker, uint indexed poolId, uint amount, uint lockedAt);
constructor(PADToken _padToken) {
padToken = _padToken;
_initPools();
}
function _initPools() internal {
pools[0] = Pool({
id: nextPoolId,
lockdownDays: 30,
rewardPercentage: 25,
lockedAmount: 0
});
nextPoolId++;
pools[1] = Pool({
id: nextPoolId,
lockdownDays: 60,
rewardPercentage: 50,
lockedAmount: 0
});
nextPoolId++;
}
function getPools() public view returns (Pool[] memory _pools) {
_pools = new Pool[](nextPoolId);
for (uint i = 0; i < nextPoolId; i++) {
_pools[i] = pools[i];
}
}
function stake(uint _poolId, uint _amount) external {
address staker = msg.sender;
uint lockedAt = block.timestamp;
Pool storage pool = pools[_poolId];
padToken.transferFrom(staker, address(this), _amount);
Deposit memory newDeposit = Deposit({
id: nextDepositId,
staker: staker,
poolId: _poolId,
amount: _amount,
lockedAt: lockedAt,
releasedAt: lockedAt + (pool.lockdownDays * 1 days)
});
deposits[staker].push(newDeposit);
console.log("hey1");
pool.lockedAmount += _amount;
console.log("hey2");
emit Staked(staker, _poolId, _amount, lockedAt);
console.log(staker, _poolId, _amount, lockedAt);
}
function getDeposit(uint _depositId) public view returns (Deposit memory) {
Deposit memory deposit;
for (uint i = 0; i < deposits[msg.sender].length; i++) {
deposit = deposits[msg.sender][i];
if (deposit.id == _depositId) {
return deposit;
}
}
revert("Deposit with the given ID not found.");
}
function getWithdrawPenalty(uint _depositId) public view returns (uint) {
Deposit memory deposit = getDeposit(_depositId);
uint remainingMs = deposit.releasedAt - block.timestamp;
if (remainingMs <= 0) {
return 0;
}
// TODO Find a meaningful formula
return 100;
}
function withdraw(uint _depositId, bool _acceptPenaltyCut) external {
uint penalty = getWithdrawPenalty(_depositId);
if (penalty > 0) {
require(_acceptPenaltyCut, "You should accept the penalty cut.");
}
Deposit memory deposit = getDeposit(_depositId);
Pool memory pool = pools[deposit.poolId];
uint amountToTransfer = (deposit.amount * pool.rewardPercentage / 100) - penalty;
padToken.transfer(deposit.staker, amountToTransfer);
}
}