Hey All,
I'm working through a smart contract and have been reading up on security best practices, I wanted to post a particular function I'm working on here to get some feedback.
I am aware that the way I am generating the random function is 'pseudo' random, however due to the fact that I am going to be launching this contract on layer 2 protocols, I do not believe I have VRF as an option. The function is also onlyOwner, so I believe there is no risk here as no one can really guess the exact block.timestamp as to when I am going to manually call the function.
What I am most concerned about is that this code is sustainable and secure (i.e. not open to re-entry attacks, running out of gas mid function etc.)
Thanks in advance!
function transferERC20(address _token, address to, uint256 amount) public onlyOwner { require(amount <= IERC20(_token).balanceOf(address(this)), "Insufficient balance"); IERC20(_token).safeTransfer(to, amount); } event Winner(address indexed _winner, uint256 _amount); function giveaway() public onlyOwner nonReentrant { require(countSpecialIDs > 0, "Special IDs have not been uploaded"); require(devWallets.length > 0, "No dev wallets specified"); require(treasuryWallets.length > 0, "No treasury wallets specified"); uint256 erc20balance = nodeTokenBalance(); require((erc20balance / 10000) * 10000 == erc20balance, "Node token balance too small"); uint256 winTokenId = uint256(keccak256(abi.encodePacked(block.timestamp, msg.sender, block.difficulty))) % supply.current(); address winnerAddress = ownerOf(winTokenId); // Prevent burnaddress winner while (burnAddresses[winnerAddress]) { winTokenId = uint256(keccak256(abi.encodePacked(block.timestamp, msg.sender, block.difficulty))) % supply.current(); winnerAddress = ownerOf(winTokenId); } uint256 devAmount = erc20balance * devFee / 10000; uint256 treasuryAmount = (erc20balance * compoundFee / 10000); uint256 winnerAmount = (erc20balance * winnerFee / 10000); if (specialIDs[winTokenId]) { winnerAmount = erc20balance * (winnerFee + specialFee) / 10000; treasuryAmount = erc20balance * (compoundFee - specialFee) / 10000; } require(devAmount > 0, "Dev fee could not be calculated"); require(treasuryAmount > 0, "Treasury fee could not be calculated"); require(winnerAmount > 0, "Winner fee could not be calculated"); for (uint256 i = 0; i < treasuryWallets.length; i++) { transferERC20(nodeToken, address(treasuryWallets[i]), treasuryAmount / treasuryWallets.length); } for (uint256 i = 0; i < devWallets.length; i++) { transferERC20(address(nodeToken), address(devWallets[i]), devAmount / devWallets.length); } transferERC20(nodeToken, winnerAddress, winnerAmount); emit Winner(winnerAddress, winnerAmount); }