Predictable NFT

Idea

Go to the contract address and decompile the bytecode:

# Palkeoramix decompiler. 

def storage:
  id is uint256 at storage 0
  tokens is mapping of uint256 at storage 1

def tokens(uint256 _param1): # not payable
  require calldata.size - 4 >=′ 32
  return tokens[_param1]

def id(): # not payable
  return id

#
#  Regular functions
#

def _fallback() payable: # default function
  revert

def mint() payable: 
  if call.value != 10^18:
      revert with 0, 'show me the money'
  if id > id + 1:
      revert with 0, 17
  id++
  if sha3(id, caller, block.number) % 100 > 90:
      tokens[stor0] = 3
  else:
      if sha3(id, caller, block.number) % 100 <= 80:
          tokens[stor0] = 1
      else:
          tokens[stor0] = 2
  return id

Here tokens[stor0] is the rank of the NFT minted. tokens[stor0] = 3 means "Superior" and that is what we want. Therefore the key to this chall is handle sha3(id, caller, block.number) % 100 > 90.

Recall that block.number can't be used for the source of randomness because this information will stay the same if we recompute it within the same tx. There are two subtle details:

  1. id++ happens before sha3(), be aware of that.

  2. We can't see if encode() or encodePacked() is used by the original contract, so try both.

PoC

Last updated