// 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); } }