What:

When you think of Smart Contracts as public vending machines - without needing to know who put the machine there, you realise people will try and scam the money out of it. Here’s some common scams people have used to scam them.

Denial Of Service:

  • Unbounded Operations: Imagine there’s a contract that loops through an array that’s controlled by attackers. The attacker could add fake entries, causing the loop to consume excessive gas, thus freezing the contract.

  • Forced Failures (Griefing): An attacker could cause a single part of the transaction to fail, resulting in the entire transaction getting reverted.

    • E.g. if a contract sends dividends to 10 investors in a single transaction, an attacker (as the 10th) could force theirs to fail, causing the rest of the contract to fail.
  • Defending Against DOS:

    • Instead of a contract ā€œpushingā€ funds to users, a safer design allows users to ā€œpullā€ their funds out via separate withdrawal functions. (Pull vs push as that way they can only jeopardise their own pulled transactions).

Re-entrancy Attacks:

  1. An attacker’s contract calls a withdrawal function on a victim contract.
  2. The victim sends the Ether back.
  3. This transfer triggers a fallback function in the attacker’s contract
  4. This causes the withdrawal function again, before the victim’s even had a chance to update the attacker’s balance to zero. The loop allows the attacker to drain the contract’s funds.
Defences Against Re-entrancy Attacks:

Do things in the following order:

  1. Checks: Perform all validations first (e.g. require(user has sufficient balance))
  2. Effects: Update all state variables next (e.g. set(user's balance to 0).
  3. Interactions: Finally, interact with external contracts (e.g. send(ether to user))

Insecure Randomness:

  • Remember that randomness on computers isn’t truly random (it’s based off the timestamp and other parts of your computer) - it’s based off multiplying prime numbers by things that change frequently.
  • If you use the block.timestamp as a source of your randomness, the block proposer that creates that block has control over the resulting ā€œrandomā€ output.
    • E.g. if a gambling coin-flip contract pays out on an even timestamp, the validator/block proposer (who’s also separately engaged in the contract) can just wait to ensure the block they produce has an even timestamp.
Defences:
  • Multi-Party Commit Reveal: Get multiple people to commit secret seeds. The final number is generated by combining the random seeds. Assuming at least 1 person is honest, then it’s truly random.

Some General Defences:

  • Always use msg.sender over tx.origin. This is because phishing attacks phishing attacks are quite devastating.