diff --git a/src/ControllerToken.sol b/src/ControllerToken.sol index b9fd931..3aefd62 100644 --- a/src/ControllerToken.sol +++ b/src/ControllerToken.sol @@ -74,6 +74,10 @@ contract ControllerToken is Token { address to, uint256 amount ) external onlyFrontend returns (bool) { + require( + to != address(this) && to != getFrontend(), + "Transfer to the token contract is not allowed" + ); require( validator.validate(caller, to, amount), "Transfer not validated" @@ -88,6 +92,10 @@ contract ControllerToken is Token { address to, uint256 amount ) external onlyFrontend returns (bool) { + require( + to != address(this) && to != getFrontend(), + "Transfer to the token contract is not allowed" + ); require(validator.validate(from, to, amount), "Transfer not validated"); _spendAllowance(from, caller, amount); _transfer(from, to, amount); @@ -161,4 +169,3 @@ contract ControllerToken is Token { acceptOwnership(); } } - diff --git a/src/Token.sol b/src/Token.sol index 9edb38e..7012ec6 100644 --- a/src/Token.sol +++ b/src/Token.sol @@ -56,7 +56,10 @@ contract Token is __UUPSUpgradeable_init(); __SystemRole_init(); validator = IValidator(_validator); - require(validator.CONTRACT_ID() == keccak256("monerium.validator"), "Not Monerium Validator Contract"); + require( + validator.CONTRACT_ID() == keccak256("monerium.validator"), + "Not Monerium Validator Contract" + ); } // _authorizeUpgrade is a crucial part of the UUPS upgrade pattern in OpenZeppelin. @@ -74,11 +77,14 @@ contract Token is function burn( address from, uint256 amount, - bytes32 , + bytes32, bytes memory signature ) public onlySystemAccounts { require( - from.isValidSignatureNow(0xb77c35c892a1b24b10a2ce49b424e578472333ee8d2456234fff90626332c50f, signature), + from.isValidSignatureNow( + 0xb77c35c892a1b24b10a2ce49b424e578472333ee8d2456234fff90626332c50f, + signature + ), "signature/hash does not match" ); _burn(from, amount); @@ -87,7 +93,7 @@ contract Token is function recover( address from, address to, - bytes32 , + bytes32, uint8 v, bytes32 r, bytes32 s @@ -97,7 +103,10 @@ contract Token is signature = abi.encodePacked(r, s, v); } require( - from.isValidSignatureNow(0xb77c35c892a1b24b10a2ce49b424e578472333ee8d2456234fff90626332c50f, signature), + from.isValidSignatureNow( + 0xb77c35c892a1b24b10a2ce49b424e578472333ee8d2456234fff90626332c50f, + signature + ), "signature/hash does not match" ); uint256 amount = balanceOf(from); @@ -110,7 +119,10 @@ contract Token is // Function to set the validator, restricted to owner function setValidator(address _validator) public onlyOwner { validator = IValidator(_validator); - require(validator.CONTRACT_ID() == keccak256("monerium.validator"), "Not Monerium Validator Contract"); + require( + validator.CONTRACT_ID() == keccak256("monerium.validator"), + "Not Monerium Validator Contract" + ); } // Override transfer function to invoke validator @@ -118,6 +130,10 @@ contract Token is address to, uint256 amount ) public override returns (bool) { + require( + to != address(this), + "Transfer to the token contract is not allowed" + ); require( validator.validate(_msgSender(), to, amount), "Transfer not validated" @@ -131,6 +147,10 @@ contract Token is address to, uint256 amount ) public override returns (bool) { + require( + to != address(this), + "Transfer to the token contract is not allowed" + ); require(validator.validate(from, to, amount), "Transfer not validated"); return super.transferFrom(from, to, amount); } @@ -176,7 +196,4 @@ contract Token is ) ); } - - } - diff --git a/test/ControllerToken.t.sol b/test/ControllerToken.t.sol index 37679ec..7ebb6d4 100644 --- a/test/ControllerToken.t.sol +++ b/test/ControllerToken.t.sol @@ -190,6 +190,22 @@ contract ControllerTokenTest is Test { assertEq(frontend.balanceOf(user2), 2e18); } + function test_should_not_transfer_to_token_or_frontend() public { + vm.prank(user1); + vm.expectRevert("Transfer to the token contract is not allowed"); + frontend.transfer(address(token), 1e18); + vm.expectRevert("Transfer to the token contract is not allowed"); + frontend.transfer(address(frontend), 1e18); + } + + function test_should_not_transferFrom_to_token_or_frontend() public { + vm.prank(user1); + vm.expectRevert("Transfer to the token contract is not allowed"); + frontend.transferFrom(user1, address(token), 1e18); + vm.expectRevert("Transfer to the token contract is not allowed"); + frontend.transferFrom(user1, address(frontend), 1e18); + } + function test_shouldNotTransferIfBlacklisted() public { // Add user2 to blacklist vm.prank(admin); diff --git a/test/ERC20.t.sol b/test/ERC20.t.sol index 682208c..25f7620 100644 --- a/test/ERC20.t.sol +++ b/test/ERC20.t.sol @@ -79,6 +79,38 @@ contract ERC20TokenTest is Test { assertEq(token.balanceOf(user2), 1e18); } + function test_should_not_transfer_to_blackhole() public { + vm.prank(system); + token.mint(user1, 1e18); + + vm.prank(user1); + vm.expectRevert( + abi.encodeWithSignature("ERC20InvalidReceiver(address)", address(0)) + ); + token.transfer(address(0), 1e18); + } + + function test_should_not_transfer_to_token() public { + vm.prank(system); + token.mint(user1, 1e18); + + vm.prank(user1); + vm.expectRevert("Transfer to the token contract is not allowed"); + token.transfer(address(token), 1e18); + } + + function test_should_not_transferFrom_to_token() public { + vm.prank(system); + token.mint(user1, 1e18); + + vm.prank(user1); + token.approve(user2, 1e18); + + vm.prank(user2); + vm.expectRevert("Transfer to the token contract is not allowed"); + token.transferFrom(user1, address(token), 1e18); + } + function test_transferFrom() public { vm.prank(system); token.mint(user1, 1e18); @@ -302,7 +334,6 @@ contract ERC20TokenTest is Test { assertEq(token.balanceOf(user2), amount); // Emit event check is optional, depends on testing framework capabilities - } function test_recover_invalid_signature() public {