Fix IPFS capitalization.

Fix IPFS capitalization.

/**
 * @title Glofile
 * @author Jonathan Brown <jbrown@bluedroplet.com>
 */
contract Glofile {

  enum GlofileType { Anon, Person, Project, Organization, Proxy, Parody, Bot }
  enum SafetyLevel { Safe, NSFW, NSFL }

  struct Glofile {
    bool dontIndex;
    GlofileType glofileType;
    SafetyLevel safetyLevel;
    string fullName;
    string location;
    bytes topics;
    bytes uris;
    bytes parents;
    bytes children;
    bytes3[] foregroundColors;
    bytes3[] backgroundColors;
    bytes3[] bioLangs;
    bytes[] avatars;
    bytes[] coverImages;
    bytes[] backgroundImages;
    bytes[] publicKeys;
    mapping (bytes3 => bytes) bioTranslations;
  }

  mapping (address => Glofile) glofiles;

  event Updated(address indexed account);
  event Deleted(address indexed account);
  event PublicKeyAdded(address indexed account, uint indexed i);
  event PublicKeyDeleted(address indexed account, uint indexed i);

  /**
   * @notice Set your Glofile don't index flag to `dontIndex`
   * @dev Sets the "don't index" flag. Glofiles with this flag set should only be accessible directly and not be discoverable via search.
   * @param dontIndex flag to indicate that this Glofile should not be indexed
   */
  function setDontIndex(bool dontIndex) {
    glofiles[msg.sender].dontIndex = dontIndex;
    Updated(msg.sender);
  }

  /**
   * @notice Set your Glofile type to `glofileType`
   * @dev Sets the Glofile type.
   * @param glofileType Glofile type
   */
  function setGlofileType(GlofileType glofileType) {
    glofiles[msg.sender].glofileType = glofileType;
    Updated(msg.sender);
  }

  /**
   * @notice Set your Glofile safety level to `safetyLevel`
   * @dev Sets the safety level. This applies to the Glofile itself. The account may publish other content that needs to be rated separately.
   * @param safetyLevel safety level
   */
  function setSafetyLevel(SafetyLevel safetyLevel) {
    glofiles[msg.sender].safetyLevel = safetyLevel;
    Updated(msg.sender);
  }

  /**
   * @notice Set your Glofile full name to `fullName`
   * @dev Sets the full name.
   * @param fullName UTF-8 string of full name - max length 128 chars
   */
  function setFullName(string fullName) {
    glofiles[msg.sender].fullName = fullName;
    Updated(msg.sender);
  }

  /**
   * @notice Set your Glofile location
   * @dev Sets the location. A dedicated contract could be used for more sophisticated location functionality.
   * @param location UTF-8 string of location - max string length 128 chars
   */
  function setLocation(string location) {
    glofiles[msg.sender].location = location;
    Updated(msg.sender);
  }

  /**
   * @notice Set your Glofile topics
   * @dev Sets the topics. This is a hint that this account will be publishing content in other contracts under these topics.
   * @param topics raw Deflated UTF-8 string of space-separated topics
   */
  function setTopics(bytes topics) {
    glofiles[msg.sender].topics = topics;
    Updated(msg.sender);
  }

  /**
   * @notice Set your Glofile URIs
   * @dev Sets the URIs. These URIs can reference anthing associated with the account, e.g. social network accounts.
   * @param uris raw Deflated UTF-8 string of space-separated percent-encoded URIs
   */
  function setUris(bytes uris) {
    glofiles[msg.sender].uris = uris;
    Updated(msg.sender);
  }

  /**
   * @notice Set your Glofile parents
   * @dev Sets the parents.
   * @param parents raw Deflated UTF-8 string of space-separated usernames
   */
  function setParents(bytes parents) {
    glofiles[msg.sender].parents = parents;
    Updated(msg.sender);
  }

  /**
   * @notice Set your Glofile children
   * @dev Sets the children.
   * @param children Raw Deflated UTF-8 string of space-separated usernames
   */
  function setChildren(bytes children) {
    glofiles[msg.sender].children = children;
    Updated(msg.sender);
  }

  /**
   * @notice Set your Glofile foreground colors
   * @dev Sets all the foreground colors.
   * @param colors array of RGB triplets
   */
  function setForegroundColors(bytes3[] colors) {
    glofiles[msg.sender].foregroundColors = colors;
    Updated(msg.sender);
  }

  /**
   * @notice Set your Glofile background colors
   * @dev Sets all the background colors.
   * @param colors array of RGB triplets
   */
  function setBackgroundColors(bytes3[] colors) {
    glofiles[msg.sender].backgroundColors = colors;
    Updated(msg.sender);
  }

  /**
   * @notice Get Glofile basic info
   * @dev Gets all the info that can be retreived in a single call.
   * @param address account to access - defaults to sender
   * @return dontIndex flag to indicate that this Glofile should not be indexed
   * @return glofileType Glofile type
   * @return safetyLevel safety level
   * @return fullName UTF-8 string of full name
   * @return location UTF-8 string of location
   * @return topics raw Deflated UTF-8 of space-separated topics
   * @return uris raw Deflated UTF-8 string of space-separated percent-encoded URIs.
   * @return parents raw Deflated UTF-8 string of space-separated usernames
   * @return children raw Deflated UTF-8 string of space-separated usernames
   * @return foregroundColors array of RGB triplets of foreground colors
   * @return backgroundColors array of RGB triplets of background colors
   */
  function getBasicInfo(address account) constant returns (bool dontIndex, GlofileType glofileType, SafetyLevel safetyLevel, bytes fullName, bytes location, bytes topics, bytes uris, bytes parents, bytes children, bytes3[] foregroundColors, bytes3[] backgroundColors) {
    if (account == 0) account = msg.sender;
    Glofile glofile = glofiles[account];
    dontIndex = glofile.dontIndex;
    glofileType = glofile.glofileType;
    safetyLevel = glofile.safetyLevel;
    fullName = glofile.fullName;
    location = glofile.location;
    topics = glofile.topics;
    uris = glofile.uris;
    parents = glofile.parents;
    children = glofile.children;
    foregroundColors = glofile.foregroundColors;
    backgroundColors = glofile.backgroundColors;
  }

  /**
   * @notice Set your Glofile bio with langauge code `lang`
   * @dev Sets the bio in a specific language.
   * @param lang 3 letter ISO 639-3 language code
   * @param translation raw Deflated UTF-8 Markdown of bio - max Markdown length 256 chars
   */
  function setBio(bytes3 lang, bytes translation) {
    Glofile glofile = glofiles[msg.sender];
    // Check if we already have the language code.
    for (uint i = 0; i < glofile.bioLangs.length; i++) {
      if (glofile.bioLangs[i] == lang) {
        break;
      }
    }
    if (i == glofile.bioLangs.length) {
      // We didn't find it. Try to find a free slot.
      for (i = 0; i < glofile.bioLangs.length; i++) {
        if (glofile.bioLangs[i] == 0) {
          break;
        }
      }
      if (i == glofile.bioLangs.length) {
        // We didn't find a free slot. Make the array bigger.
        glofile.bioLangs.length++;
      }
      glofile.bioLangs[i] = lang;
    }
    // Set translation.
    glofile.bioTranslations[lang] = translation;
    Updated(msg.sender);
  }

  /**
   * @notice Delete your Glofile bio with language code `lang`
   * @dev Deletes a bio translation.
   * @param lang 3 letter ISO 639-3 language code
   */
  function deleteBio(bytes3 lang) {
    Glofile glofile = glofiles[msg.sender];
    for (uint i = 0; i < glofile.bioLangs.length; i++) {
      if (glofile.bioLangs[i] == lang) {
        delete glofile.bioLangs[i];
        break;
      }
    }
    // Delete the actual mapping in case a client accesses without checking
    // language key.
    delete glofile.bioTranslations[lang];
    Updated(msg.sender);
  }

  /**
   * @notice Delete all of your Glofile bio translations
   * @dev Deletes all of the bio translations.
   */
  function deleteAllBioTranslations() {
    Glofile glofile = glofiles[msg.sender];
    // Delete the actual mappings in case a client accesses without checking
    // language key.
    for (uint i = 0; i < glofile.bioLangs.length; i++) {
      delete glofile.bioTranslations[glofile.bioLangs[i]];
    }
    delete glofile.bioLangs;
    Updated(msg.sender);
  }

  /**
   * @notice Get the list of language code a Glofile bio is available in
   * @dev Gets the list of language codes the bio is available in.
   * @param address account to access - defaults to sender
   * @return array of 3 letter ISO 639-3 language codes
   */
  function getBioLangCodes(address account) constant returns (bytes3[]) {
    if (account == 0) account = msg.sender;
    return glofiles[account].bioLangs;
  }

  /**
   * @notice Get the Glofile bio with language code `lang`
   * @dev Gets the bio in a specific language.
   * @param lang 3 letter ISO 639-3 language code
   * @param address account to access - defaults to sender
   * @return raw Deflated UTF-8 Markdown of bio
   */
  function getBioTranslation(bytes3 lang, address account) constant returns (bytes) {
    if (account == 0) account = msg.sender;
    return glofiles[account].bioTranslations[lang];
  }

  /**
   * @notice Set your Glofile avatar with index `i` to `ipfsHash`
   * @dev Sets the avatar with a specific index to an IPFS hash.
   * @param i index of avatar to set
   * @param ipfsHash binary IPFS hash of image
   */
  function setAvatar(uint i, bytes ipfsHash) {
    bytes[] avatars = glofiles[msg.sender].avatars;
    // Make sure the array is long enough.
    if (avatars.length <= i) {
      avatars.length = i;
    }
    avatars[i] = ipfsHash;
    Updated(msg.sender);
  }

  /**
   * @notice Delete your Glofile avatar with index `i`
   * @dev Deletes an avatar with a specific index.
   * @param i index of avatar to delete
   */
  function deleteAvatar(uint i) {
    delete glofiles[msg.sender].avatars[i];
    Updated(msg.sender);
  }

  /**
   * @notice Delete all your Glofile avatars
   * @dev Deletes all avatars from the Glofile.
   */
  function deleteAllAvatars() {
    delete glofiles[msg.sender].avatars;
    Updated(msg.sender);
  }

  /**
   * @notice Get the number of Glofile avatars
   * @dev Gets the number of avatars.
   * @param address account to access - defaults to sender
   * @return number of avatars
   */
  function getAvatarCount(address account) constant returns (uint) {
    if (account == 0) account = msg.sender;
    return glofiles[account].avatars.length;
  }

  /**
   * @notice Get the Glofile avatar with index `i`
   * @dev Gets the avatar with a specific index.
   * @param i index of avatar to get
   * @param address account to access - defaults to sender
   * @return binary IPFS hash of image
   */
  function getAvatar(uint i, address account) constant returns (bytes) {
    if (account == 0) account = msg.sender;
    return glofiles[account].avatars[i];
  }

  /**
   * @notice Set your Glofile cover image with index `i` to `ipfsHash`
   * @dev Sets the cover image with a specific index to an IPFS hash.
   * @param i index of cover image to set
   * @param ipfsHash binary IPFS hash of image
   */
  function setCoverImage(uint i, bytes ipfsHash) {
    bytes[] coverImages = glofiles[msg.sender].coverImages;
    // Make sure the array is long enough.
    if (coverImages.length <= i) {
      coverImages.length = i;
    }
    coverImages[i] = ipfsHash;
    Updated(msg.sender);
  }

  /**
   * @notice Delete your Glofile cover image with index `i`
   * @dev Deletes the cover image with a specific index.
   * @param i index of cover image to delete
   */
  function deleteCoverImage(uint i) {
    delete glofiles[msg.sender].coverImages[i];
    Updated(msg.sender);
  }

  /**
   * @notice Delete all your Glofile cover images
   * @dev Deletes all cover images from the Glofile.
   */
  function deleteAllCoverImages() {
    delete glofiles[msg.sender].coverImages;
    Updated(msg.sender);
  }

  /**
   * @notice Get the number of Glofile cover images
   * @dev Gets the number of cover images.
   * @param address account to access - defaults to sender
   * @return number of cover images
   */
  function getCoverImageCount(address account) constant returns (uint) {
    if (account == 0) account = msg.sender;
    return glofiles[account].coverImages.length;
  }

  /**
   * @notice Get the Glofile cover image with index `i`
   * @dev Gets the cover image with a specific index.
   * @param i index of cover image to get
   * @param ipfsHash binary ipfs hash of image
   * @return binary IPFS hash of image
   */
  function getCoverImage(uint i, address account) constant returns (bytes) {
    if (account == 0) account = msg.sender;
    return glofiles[account].coverImages[i];
  }

  /**
   * @notice Set your Glofile background image with index `i` to `ipfsHash`
   * @dev Sets the background image with a specific index to an IPFS hash.
   * @param i index of background image to set
   * @param ipfsHash binary IPFS hash of image
   */
  function setBackgroundImage(uint i, bytes ipfsHash) {
    bytes[] backgroundImages = glofiles[msg.sender].backgroundImages;
    // Make sure the array is long enough.
    if (backgroundImages.length <= i) {
      backgroundImages.length = i;
    }
    backgroundImages[i] = ipfsHash;
    Updated(msg.sender);
  }

  /**
   * @notice Delete your Glofile background image with index `i`
   * @dev Deletes the background image with a specific index.
   * @param i index of background image to get
   */
  function deleteBackgroundImage(uint i) {
    delete glofiles[msg.sender].backgroundImages[i];
    Updated(msg.sender);
  }

  /**
   * @notice Delete all your Glofile background images
   * @dev Deletes all the background images.
   */
  function deleteAllBackgroundImages() {
    delete glofiles[msg.sender].backgroundImages;
    Updated(msg.sender);
  }

  /**
   * @notice Get the number of Glofile background images
   * @dev Gets the number of background images.
   * @param address account to access - defaults to sender
   * @return number of background images
   */
  function getBackgroundImageCount(address account) constant returns (uint) {
    if (account == 0) account = msg.sender;
    return glofiles[account].backgroundImages.length;
  }

  /**
   * @notice Get the Glofile background image with index `i`
   * @dev Gets the background image with a specific index.
   * @param i index of cover image to get
   * @param address account to access - defaults to sender
   * @return binary IPFS hash of image
   */
  function getBackgroundImage(uint i, address account) constant returns (bytes) {
    if (account == 0) account = msg.sender;
    return glofiles[account].backgroundImages[i];
  }

  /**
   * @notice Add a public key to your Glofile
   * @dev Adds a public key.
   * @param publicKey Raw Deflated UTF-8 public key
   */
  function addPublicKey(bytes publicKey) {
    Glofile glofile = glofiles[msg.sender];
    uint i = glofile.publicKeys.length++;
    glofile.publicKeys[i] = publicKey;
    PublicKeyAdded(msg.sender, i);
  }

  /**
   * @notice Delete the public key with index `i` from your Glofile
   * @dev Deletes the public key with a specific index.
   * @param i index of public key to delete
   */
  function deletePublicKey(uint i) {
    delete glofiles[msg.sender].publicKeys[i];
    PublicKeyDeleted(msg.sender, i);
  }

  /**
   * @notice Get the number of public keys in the Glofile
   * @dev Gets the number of public keys.
   * @param address account to access - defaults to sender
   * @return the number of public keys
   */
  function getPublicKeyCount(address account) constant returns (uint) {
    if (account == 0) account = msg.sender;
    return glofiles[account].publicKeys.length;
  }

  /**
   * @notice Get the public key with index `i` from the Glofile
   * @dev Gets the public key with a specific index.
   * @param i index of public key to get
   * @param address account to access - defaults to sender
   * @return raw Deflated UTF-8 public key
   */
  function getPublicKey(uint i, address account) constant returns (bytes) {
    if (account == 0) account = msg.sender;
    return glofiles[account].publicKeys[i];
  }

  /**
   * @notice Copy entire Glofile from `source`
   * @dev Copies the Glofile from another account to this one.
   * @param source account of Glofile to copy from
   * TODO: check this works
   */
  function copyEntireGlofile(address source) {
    glofiles[msg.sender] = glofiles[source];
    Updated(msg.sender);
  }

  /**
   * @notice Delete your entire Glofile
   * @dev Deletes the Glofile completely.
   */
  function deleteEntireGlofile() {
    delete glofiles[msg.sender];
    Deleted(msg.sender);
  }

}

/**
 * @title Glofile
 * @author Jonathan Brown <jbrown@bluedroplet.com>
 */
contract Glofile {

  enum GlofileType { Anon, Person, Project, Organization, Proxy, Parody, Bot }
  enum SafetyLevel { Safe, NSFW, NSFL }

  struct Glofile {
    bool dontIndex;
    GlofileType glofileType;
    SafetyLevel safetyLevel;
    string fullName;
    string location;
    bytes topics;
    bytes uris;
    bytes parents;
    bytes children;
    bytes3[] foregroundColors;
    bytes3[] backgroundColors;
    bytes3[] bioLangs;
    bytes[] avatars;
    bytes[] coverImages;
    bytes[] backgroundImages;
    bytes[] publicKeys;
    mapping (bytes3 => bytes) bioTranslations;
  }

  mapping (address => Glofile) glofiles;

  event Updated(address indexed account);
  event Deleted(address indexed account);
  event PublicKeyAdded(address indexed account, uint indexed i);
  event PublicKeyDeleted(address indexed account, uint indexed i);

  /**
   * @notice Set your Glofile don't index flag to `dontIndex`
   * @dev Sets the "don't index" flag. Glofiles with this flag set should only be accessible directly and not be discoverable via search.
   * @param dontIndex flag to indicate that this Glofile should not be indexed
   */
  function setDontIndex(bool dontIndex) {
    glofiles[msg.sender].dontIndex = dontIndex;
    Updated(msg.sender);
  }

  /**
   * @notice Set your Glofile type to `glofileType`
   * @dev Sets the Glofile type.
   * @param glofileType Glofile type
   */
  function setGlofileType(GlofileType glofileType) {
    glofiles[msg.sender].glofileType = glofileType;
    Updated(msg.sender);
  }

  /**
   * @notice Set your Glofile safety level to `safetyLevel`
   * @dev Sets the safety level. This applies to the Glofile itself. The account may publish other content that needs to be rated separately.
   * @param safetyLevel safety level
   */
  function setSafetyLevel(SafetyLevel safetyLevel) {
    glofiles[msg.sender].safetyLevel = safetyLevel;
    Updated(msg.sender);
  }

  /**
   * @notice Set your Glofile full name to `fullName`
   * @dev Sets the full name.
   * @param fullName UTF-8 string of full name - max length 128 chars
   */
  function setFullName(string fullName) {
    glofiles[msg.sender].fullName = fullName;
    Updated(msg.sender);
  }

  /**
   * @notice Set your Glofile location
   * @dev Sets the location. A dedicated contract could be used for more sophisticated location functionality.
   * @param location UTF-8 string of location - max string length 128 chars
   */
  function setLocation(string location) {
    glofiles[msg.sender].location = location;
    Updated(msg.sender);
  }

  /**
   * @notice Set your Glofile topics
   * @dev Sets the topics. This is a hint that this account will be publishing content in other contracts under these topics.
   * @param topics raw Deflated UTF-8 string of space-separated topics
   */
  function setTopics(bytes topics) {
    glofiles[msg.sender].topics = topics;
    Updated(msg.sender);
  }

  /**
   * @notice Set your Glofile URIs
   * @dev Sets the URIs. These URIs can reference anthing associated with the account, e.g. social network accounts.
   * @param uris raw Deflated UTF-8 string of space-separated percent-encoded URIs
   */
  function setUris(bytes uris) {
    glofiles[msg.sender].uris = uris;
    Updated(msg.sender);
  }

  /**
   * @notice Set your Glofile parents
   * @dev Sets the parents.
   * @param parents raw Deflated UTF-8 string of space-separated usernames
   */
  function setParents(bytes parents) {
    glofiles[msg.sender].parents = parents;
    Updated(msg.sender);
  }

  /**
   * @notice Set your Glofile children
   * @dev Sets the children.
   * @param children Raw Deflated UTF-8 string of space-separated usernames
   */
  function setChildren(bytes children) {
    glofiles[msg.sender].children = children;
    Updated(msg.sender);
  }

  /**
   * @notice Set your Glofile foreground colors
   * @dev Sets all the foreground colors.
   * @param colors array of RGB triplets
   */
  function setForegroundColors(bytes3[] colors) {
    glofiles[msg.sender].foregroundColors = colors;
    Updated(msg.sender);
  }

  /**
   * @notice Set your Glofile background colors
   * @dev Sets all the background colors.
   * @param colors array of RGB triplets
   */
  function setBackgroundColors(bytes3[] colors) {
    glofiles[msg.sender].backgroundColors = colors;
    Updated(msg.sender);
  }

  /**
   * @notice Get Glofile basic info
   * @dev Gets all the info that can be retreived in a single call.
   * @param address account to access - defaults to sender
   * @return dontIndex flag to indicate that this Glofile should not be indexed
   * @return glofileType Glofile type
   * @return safetyLevel safety level
   * @return fullName UTF-8 string of full name
   * @return location UTF-8 string of location
   * @return topics raw Deflated UTF-8 of space-separated topics
   * @return uris raw Deflated UTF-8 string of space-separated percent-encoded URIs.
   * @return parents raw Deflated UTF-8 string of space-separated usernames
   * @return children raw Deflated UTF-8 string of space-separated usernames
   * @return foregroundColors array of RGB triplets of foreground colors
   * @return backgroundColors array of RGB triplets of background colors
   */
  function getBasicInfo(address account) constant returns (bool dontIndex, GlofileType glofileType, SafetyLevel safetyLevel, bytes fullName, bytes location, bytes topics, bytes uris, bytes parents, bytes children, bytes3[] foregroundColors, bytes3[] backgroundColors) {
    if (account == 0) account = msg.sender;
    Glofile glofile = glofiles[account];
    dontIndex = glofile.dontIndex;
    glofileType = glofile.glofileType;
    safetyLevel = glofile.safetyLevel;
    fullName = glofile.fullName;
    location = glofile.location;
    topics = glofile.topics;
    uris = glofile.uris;
    parents = glofile.parents;
    children = glofile.children;
    foregroundColors = glofile.foregroundColors;
    backgroundColors = glofile.backgroundColors;
  }

  /**
   * @notice Set your Glofile bio with langauge code `lang`
   * @dev Sets the bio in a specific language.
   * @param lang 3 letter ISO 639-3 language code
   * @param translation raw Deflated UTF-8 Markdown of bio - max Markdown length 256 chars
   */
  function setBio(bytes3 lang, bytes translation) {
    Glofile glofile = glofiles[msg.sender];
    // Check if we already have the language code.
    for (uint i = 0; i < glofile.bioLangs.length; i++) {
      if (glofile.bioLangs[i] == lang) {
        break;
      }
    }
    if (i == glofile.bioLangs.length) {
      // We didn't find it. Try to find a free slot.
      for (i = 0; i < glofile.bioLangs.length; i++) {
        if (glofile.bioLangs[i] == 0) {
          break;
        }
      }
      if (i == glofile.bioLangs.length) {
        // We didn't find a free slot. Make the array bigger.
        glofile.bioLangs.length++;
      }
      glofile.bioLangs[i] = lang;
    }
    // Set translation.
    glofile.bioTranslations[lang] = translation;
    Updated(msg.sender);
  }

  /**
   * @notice Delete your Glofile bio with language code `lang`
   * @dev Deletes a bio translation.
   * @param lang 3 letter ISO 639-3 language code
   */
  function deleteBio(bytes3 lang) {
    Glofile glofile = glofiles[msg.sender];
    for (uint i = 0; i < glofile.bioLangs.length; i++) {
      if (glofile.bioLangs[i] == lang) {
        delete glofile.bioLangs[i];
        break;
      }
    }
    // Delete the actual mapping in case a client accesses without checking
    // language key.
    delete glofile.bioTranslations[lang];
    Updated(msg.sender);
  }

  /**
   * @notice Delete all of your Glofile bio translations
   * @dev Deletes all of the bio translations.
   */
  function deleteAllBioTranslations() {
    Glofile glofile = glofiles[msg.sender];
    // Delete the actual mappings in case a client accesses without checking
    // language key.
    for (uint i = 0; i < glofile.bioLangs.length; i++) {
      delete glofile.bioTranslations[glofile.bioLangs[i]];
    }
    delete glofile.bioLangs;
    Updated(msg.sender);
  }

  /**
   * @notice Get the list of language code a Glofile bio is available in
   * @dev Gets the list of language codes the bio is available in.
   * @param address account to access - defaults to sender
   * @return array of 3 letter ISO 639-3 language codes
   */
  function getBioLangCodes(address account) constant returns (bytes3[]) {
    if (account == 0) account = msg.sender;
    return glofiles[account].bioLangs;
  }

  /**
   * @notice Get the Glofile bio with language code `lang`
   * @dev Gets the bio in a specific language.
   * @param lang 3 letter ISO 639-3 language code
   * @param address account to access - defaults to sender
   * @return raw Deflated UTF-8 Markdown of bio
   */
  function getBioTranslation(bytes3 lang, address account) constant returns (bytes) {
    if (account == 0) account = msg.sender;
    return glofiles[account].bioTranslations[lang];
  }

  /**
   * @notice Set your Glofile avatar with index `i` to `ipfsHash`
   * @dev Sets the avatar with a specific index to an IPFS hash.
   * @param i index of avatar to set
   * @param ipfsHash binary ipfs hash of image
   */
  function setAvatar(uint i, bytes ipfsHash) {
    bytes[] avatars = glofiles[msg.sender].avatars;
    // Make sure the array is long enough.
    if (avatars.length <= i) {
      avatars.length = i;
    }
    avatars[i] = ipfsHash;
    Updated(msg.sender);
  }

  /**
   * @notice Delete your Glofile avatar with index `i`
   * @dev Deletes an avatar with a specific index.
   * @param i index of avatar to delete
   */
  function deleteAvatar(uint i) {
    delete glofiles[msg.sender].avatars[i];
    Updated(msg.sender);
  }

  /**
   * @notice Delete all your Glofile avatars
   * @dev Deletes all avatars from the Glofile.
   */
  function deleteAllAvatars() {
    delete glofiles[msg.sender].avatars;
    Updated(msg.sender);
  }

  /**
   * @notice Get the number of Glofile avatars
   * @dev Gets the number of avatars.
   * @param address account to access - defaults to sender
   * @return number of avatars
   */
  function getAvatarCount(address account) constant returns (uint) {
    if (account == 0) account = msg.sender;
    return glofiles[account].avatars.length;
  }

  /**
   * @notice Get the Glofile avatar with index `i`
   * @dev Gets the avatar with a specific index.
   * @param i index of avatar to get
   * @param address account to access - defaults to sender
   * @return binary ipfs hash of image
   */
  function getAvatar(uint i, address account) constant returns (bytes) {
    if (account == 0) account = msg.sender;
    return glofiles[account].avatars[i];
  }

  /**
   * @notice Set your Glofile cover image with index `i` to `ipfsHash`
   * @dev Sets the cover image with a specific index to an IPFS hash.
   * @param i index of cover image to set
   * @param ipfsHash binary ipfs hash of image
   */
  function setCoverImage(uint i, bytes ipfsHash) {
    bytes[] coverImages = glofiles[msg.sender].coverImages;
    // Make sure the array is long enough.
    if (coverImages.length <= i) {
      coverImages.length = i;
    }
    coverImages[i] = ipfsHash;
    Updated(msg.sender);
  }

  /**
   * @notice Delete your Glofile cover image with index `i`
   * @dev Deletes the cover image with a specific index.
   * @param i index of cover image to delete
   */
  function deleteCoverImage(uint i) {
    delete glofiles[msg.sender].coverImages[i];
    Updated(msg.sender);
  }

  /**
   * @notice Delete all your Glofile cover images
   * @dev Deletes all cover images from the Glofile.
   */
  function deleteAllCoverImages() {
    delete glofiles[msg.sender].coverImages;
    Updated(msg.sender);
  }

  /**
   * @notice Get the number of Glofile cover images
   * @dev Gets the number of cover images.
   * @param address account to access - defaults to sender
   * @return number of cover images
   */
  function getCoverImageCount(address account) constant returns (uint) {
    if (account == 0) account = msg.sender;
    return glofiles[account].coverImages.length;
  }

  /**
   * @notice Get the Glofile cover image with index `i`
   * @dev Gets the cover image with a specific index.
   * @param i index of cover image to get
   * @param ipfsHash binary ipfs hash of image
   * @return binary ipfs hash of image
   */
  function getCoverImage(uint i, address account) constant returns (bytes) {
    if (account == 0) account = msg.sender;
    return glofiles[account].coverImages[i];
  }

  /**
   * @notice Set your Glofile background image with index `i` to `ipfsHash`
   * @dev Sets the background image with a specific index to an IPFS hash.
   * @param i index of background image to set
   * @param ipfsHash binary ipfs hash of image
   */
  function setBackgroundImage(uint i, bytes ipfsHash) {
    bytes[] backgroundImages = glofiles[msg.sender].backgroundImages;
    // Make sure the array is long enough.
    if (backgroundImages.length <= i) {
      backgroundImages.length = i;
    }
    backgroundImages[i] = ipfsHash;
    Updated(msg.sender);
  }

  /**
   * @notice Delete your Glofile background image with index `i`
   * @dev Deletes the background image with a specific index.
   * @param i index of background image to get
   */
  function deleteBackgroundImage(uint i) {
    delete glofiles[msg.sender].backgroundImages[i];
    Updated(msg.sender);
  }

  /**
   * @notice Delete all your Glofile background images
   * @dev Deletes all the background images.
   */
  function deleteAllBackgroundImages() {
    delete glofiles[msg.sender].backgroundImages;
    Updated(msg.sender);
  }

  /**
   * @notice Get the number of Glofile background images
   * @dev Gets the number of background images.
   * @param address account to access - defaults to sender
   * @return number of background images
   */
  function getBackgroundImageCount(address account) constant returns (uint) {
    if (account == 0) account = msg.sender;
    return glofiles[account].backgroundImages.length;
  }

  /**
   * @notice Get the Glofile background image with index `i`
   * @dev Gets the background image with a specific index.
   * @param i index of cover image to get
   * @param address account to access - defaults to sender
   * @return binary ipfs hash of image
   */
  function getBackgroundImage(uint i, address account) constant returns (bytes) {
    if (account == 0) account = msg.sender;
    return glofiles[account].backgroundImages[i];
  }

  /**
   * @notice Add a public key to your Glofile
   * @dev Adds a public key.
   * @param publicKey Raw Deflated UTF-8 public key
   */
  function addPublicKey(bytes publicKey) {
    Glofile glofile = glofiles[msg.sender];
    uint i = glofile.publicKeys.length++;
    glofile.publicKeys[i] = publicKey;
    PublicKeyAdded(msg.sender, i);
  }

  /**
   * @notice Delete the public key with index `i` from your Glofile
   * @dev Deletes the public key with a specific index.
   * @param i index of public key to delete
   */
  function deletePublicKey(uint i) {
    delete glofiles[msg.sender].publicKeys[i];
    PublicKeyDeleted(msg.sender, i);
  }

  /**
   * @notice Get the number of public keys in the Glofile
   * @dev Gets the number of public keys.
   * @param address account to access - defaults to sender
   * @return the number of public keys
   */
  function getPublicKeyCount(address account) constant returns (uint) {
    if (account == 0) account = msg.sender;
    return glofiles[account].publicKeys.length;
  }

  /**
   * @notice Get the public key with index `i` from the Glofile
   * @dev Gets the public key with a specific index.
   * @param i index of public key to get
   * @param address account to access - defaults to sender
   * @return raw Deflated UTF-8 public key
   */
  function getPublicKey(uint i, address account) constant returns (bytes) {
    if (account == 0) account = msg.sender;
    return glofiles[account].publicKeys[i];
  }

  /**
   * @notice Copy entire Glofile from `source`
   * @dev Copies the Glofile from another account to this one.
   * @param source account of Glofile to copy from
   * TODO: check this works
   */
  function copyEntireGlofile(address source) {
    glofiles[msg.sender] = glofiles[source];
    Updated(msg.sender);
  }

  /**
   * @notice Delete your entire Glofile
   * @dev Deletes the Glofile completely.
   */
  function deleteEntireGlofile() {
    delete glofiles[msg.sender];
    Deleted(msg.sender);
  }

}


test: fixed bug where old contract was being used for test

pragma solidity ^0.8.9;

import "ds-test/test.sol";
import "contracts/governance/Governor.sol";
import "contracts/Controller.sol";
import "contracts/bonding/BondingManager.sol";
import "contracts/snapshots/MerkleSnapshot.sol";

interface CheatCodes {
    function roll(uint256) external;

    function prank(address) external;

    function expectRevert(bytes calldata) external;

    function expectEmit(
        bool checkTopic1,
        bool checkTopic2,
        bool checkTopic3,
        bool checkData
    ) external;

    function mockCall(
        address,
        bytes calldata,
        bytes calldata
    ) external;
}

interface L2Migrator {
    function claimStake(
        address,
        uint256,
        uint256,
        bytes32[] calldata,
        address
    ) external;
}

// forge test --match-contract BondingManagerForceChangeDelegateFix --fork-url https://arbitrum-mainnet.infura.io/v3/<INFURA_KEY> -vvv --fork-block-number 8006620
contract BondingManagerForceChangeDelegateFix is DSTest {
    CheatCodes public constant CHEATS = CheatCodes(HEVM_ADDRESS);

    Governor public constant GOVERNOR = Governor(0xD9dEd6f9959176F0A04dcf88a0d2306178A736a6);
    Controller public constant CONTROLLER = Controller(0xD8E8328501E9645d16Cf49539efC04f734606ee4);
    BondingManager public constant BONDING_MANAGER = BondingManager(0x35Bcf3c30594191d53231E4FF333E8A770453e40);
    MerkleSnapshot public constant MERKLE_SNAPSHOT = MerkleSnapshot(0x10736ffaCe687658F88a46D042631d182C7757f7);
    L2Migrator public constant L2_MIGRATOR = L2Migrator(0x148D5b6B4df9530c7C76A810bd1Cdf69EC4c2085);

    address public constant GOVERNOR_OWNER = 0x04F53A0bb244f015cC97731570BeD26F0229da05;

    bytes32 public constant BONDING_MANAGER_TARGET_ID = keccak256("BondingManagerTarget");

    // Governor update
    address[] public targets;
    uint256[] public values;
    bytes[] public datas;

    BondingManager public newBondingManagerTarget;

    event Bond(
        address indexed newDelegate,
        address indexed oldDelegate,
        address indexed delegator,
        uint256 additionalAmount,
        uint256 bondedAmount
    );

    function setUp() public {
        newBondingManagerTarget = new BondingManager(address(CONTROLLER));

        targets = [address(CONTROLLER)];
        values = [0];

        (, bytes20 gitCommitHash) = CONTROLLER.getContractInfo(BONDING_MANAGER_TARGET_ID);
        datas = [
            abi.encodeWithSelector(
                CONTROLLER.setContractInfo.selector,
                BONDING_MANAGER_TARGET_ID,
                address(newBondingManagerTarget),
                gitCommitHash
            )
        ];
    }

    function upgradeBondingManager() public {
        Governor.Update memory update = Governor.Update({ target: targets, value: values, data: datas, nonce: 0 });

        // Impersonate Governor owner
        CHEATS.prank(GOVERNOR_OWNER);
        GOVERNOR.stage(update, 0);
        GOVERNOR.execute(update);
    }

    function testUpgrade() public {
        (, bytes20 gitCommitHash) = CONTROLLER.getContractInfo(BONDING_MANAGER_TARGET_ID);

        upgradeBondingManager();

        // Check that new BondingManagerTarget is registered
        (address infoAddr, bytes20 infoGitCommitHash) = CONTROLLER.getContractInfo(BONDING_MANAGER_TARGET_ID);
        assertEq(infoAddr, address(newBondingManagerTarget));
        assertEq(infoGitCommitHash, gitCommitHash);
    }

    function testBond() public {
        upgradeBondingManager();

        uint256 round = 2499;
        uint256 blockNum = round * 5760;
        CHEATS.roll(blockNum);

        address delegator = 0x5Ec2be1aDC70Bc338471277c2dCc183b0b2C91be;
        (, , address delegateAddress, , , , ) = BONDING_MANAGER.getDelegator(delegator);

        uint256 initialStake = BONDING_MANAGER.transcoderTotalStake(delegateAddress);

        CHEATS.prank(delegator);
        BONDING_MANAGER.bond(10, delegateAddress);

        uint256 finalStake = BONDING_MANAGER.transcoderTotalStake(delegateAddress);

        assertEq(finalStake, initialStake + 10);
    }

    function testChangeDelegate() public {
        upgradeBondingManager();

        uint256 round = 2499;
        uint256 blockNum = round * 5760;
        CHEATS.roll(blockNum);

        address delegator = 0xAcA4bD77e459b9898A0de9Ad7C1caC34fF540D0B;
        address delegate = 0x525419FF5707190389bfb5C87c375D710F5fCb0E;

        // checks if owner can change delegate
        CHEATS.prank(delegator);
        BONDING_MANAGER.bond(0, delegate);

        (, , address delegateAddress, , , , ) = BONDING_MANAGER.getDelegator(delegator);

        assertEq(delegateAddress, delegate);
    }

    function testClaimStake() public {
        upgradeBondingManager();

        CHEATS.mockCall(
            address(MERKLE_SNAPSHOT),
            abi.encodeWithSelector(MERKLE_SNAPSHOT.verify.selector),
            abi.encode(true)
        );

        uint256 round = 2499;
        uint256 blockNum = round * 5760;
        CHEATS.roll(blockNum);

        address delegator = 0xE22d48950C88C4e8F2C5dA6c7d32D4bc9fE43Bff;
        address delegate = 0x91f19C0335BC776f4693EeB1D88765243f63e9D6;

        bytes32[] memory proof;
        CHEATS.prank(delegator);

        CHEATS.expectEmit(true, true, false, true);
        emit Bond(delegate, address(0), delegator, 500000000000000000000, 500000000000000000000);
        L2_MIGRATOR.claimStake(delegate, 500000000000000000000, 0, proof, address(0));

        (, , address delegateAddress, , , , ) = BONDING_MANAGER.getDelegator(delegator);

        assertEq(delegateAddress, delegate);
    }

    function testChangeDelegateByThirdParty() public {
        upgradeBondingManager();

        uint256 round = 2499;
        uint256 blockNum = round * 5760;
        CHEATS.roll(blockNum);

        address delegator = 0xAcA4bD77e459b9898A0de9Ad7C1caC34fF540D0B;
        address delegate = 0x525419FF5707190389bfb5C87c375D710F5fCb0E;
        address thirdParty = 0x12336b564A71Cc4C1319bf35E87Ea45681E4D94a;

        // trying to change delegate of a delegator should revert
        CHEATS.prank(thirdParty);
        CHEATS.expectRevert(bytes("INVALID_CALLER"));
        BONDING_MANAGER.bondForWithHint(0, delegator, delegate, address(0), address(0), address(0), address(0));
    }
}

pragma solidity ^0.8.9;

import "ds-test/test.sol";
import "contracts/governance/Governor.sol";
import "contracts/Controller.sol";
import "contracts/bonding/BondingManager.sol";
import "contracts/snapshots/MerkleSnapshot.sol";

interface CheatCodes {
    function roll(uint256) external;

    function prank(address) external;

    function mockCall(
        address,
        bytes calldata,
        bytes calldata
    ) external;
}

interface L2Migrator {
    function claimStake(
        address,
        uint256,
        uint256,
        bytes32[] calldata,
        address
    ) external;
}

contract BondingManagerForceChangeDelegateFix is DSTest {
    CheatCodes public constant CHEATS = CheatCodes(HEVM_ADDRESS);

    Governor public constant GOVERNOR = Governor(0xD9dEd6f9959176F0A04dcf88a0d2306178A736a6);
    Controller public constant CONTROLLER = Controller(0xD8E8328501E9645d16Cf49539efC04f734606ee4);
    BondingManager public constant BONDING_MANAGER = BondingManager(0x35Bcf3c30594191d53231E4FF333E8A770453e40);
    MerkleSnapshot public constant MERKLE_SNAPSHOT = MerkleSnapshot(0x10736ffaCe687658F88a46D042631d182C7757f7);
    L2Migrator public constant L2_MIGRATOR = L2Migrator(0x148D5b6B4df9530c7C76A810bd1Cdf69EC4c2085);

    address public constant GOVERNOR_OWNER = 0x04F53A0bb244f015cC97731570BeD26F0229da05;

    bytes32 public constant BONDING_MANAGER_TARGET_ID = keccak256("BondingManagerTarget");

    // Governor update
    address[] public targets;
    uint256[] public values;
    bytes[] public datas;

    BondingManager public newBondingManagerTarget;

    function setUp() public {
        newBondingManagerTarget = new BondingManager(address(CONTROLLER));

        targets = [address(CONTROLLER)];
        values = [0];

        (, bytes20 gitCommitHash) = CONTROLLER.getContractInfo(BONDING_MANAGER_TARGET_ID);
        datas = [
            abi.encodeWithSelector(
                CONTROLLER.setContractInfo.selector,
                BONDING_MANAGER_TARGET_ID,
                address(newBondingManagerTarget),
                gitCommitHash
            )
        ];
    }

    function testUpgrade() public {
        (, bytes20 gitCommitHash) = CONTROLLER.getContractInfo(BONDING_MANAGER_TARGET_ID);

        Governor.Update memory update = Governor.Update({ target: targets, value: values, data: datas, nonce: 0 });

        // Impersonate Governor owner
        CHEATS.prank(GOVERNOR_OWNER);
        GOVERNOR.stage(update, 0);
        GOVERNOR.execute(update);

        // Check that new BondingManagerTarget is registered
        (address infoAddr, bytes20 infoGitCommitHash) = CONTROLLER.getContractInfo(BONDING_MANAGER_TARGET_ID);
        assertEq(infoAddr, address(newBondingManagerTarget));
        assertEq(infoGitCommitHash, gitCommitHash);
    }

    function testBond() public {
        uint256 round = 2499;
        uint256 blockNum = round * 5760;
        CHEATS.roll(blockNum);

        address delegator = 0x5Ec2be1aDC70Bc338471277c2dCc183b0b2C91be;
        (, , address delegateAddress, , , , ) = BONDING_MANAGER.getDelegator(delegator);

        uint256 initialStake = BONDING_MANAGER.transcoderTotalStake(delegateAddress);

        // checks if owner can change delegate
        CHEATS.prank(delegator);
        BONDING_MANAGER.bond(10, delegateAddress);

        uint256 finalStake = BONDING_MANAGER.transcoderTotalStake(delegateAddress);

        assertEq(finalStake, initialStake + 10);
    }

    function testChangeDelegate() public {
        uint256 round = 2499;
        uint256 blockNum = round * 5760;
        CHEATS.roll(blockNum);

        address delegator = 0xAcA4bD77e459b9898A0de9Ad7C1caC34fF540D0B;
        address delegate = 0x525419FF5707190389bfb5C87c375D710F5fCb0E;

        // checks if owner can change delegate
        CHEATS.prank(delegator);
        BONDING_MANAGER.bond(0, delegate);

        (, , address delegateAddress, , , , ) = BONDING_MANAGER.getDelegator(delegator);

        assertEq(delegateAddress, delegate);
    }

    function testClaimStake() public {
        CHEATS.mockCall(
            address(MERKLE_SNAPSHOT),
            abi.encodeWithSelector(MERKLE_SNAPSHOT.verify.selector),
            abi.encode(true)
        );

        uint256 round = 2499;
        uint256 blockNum = round * 5760;
        CHEATS.roll(blockNum);

        address delegator = 0xE22d48950C88C4e8F2C5dA6c7d32D4bc9fE43Bff;
        address delegate = 0x21d1130DC36958dB75fbB0e5a9E3e5F5680238FF;

        bytes32[] memory proof;
        CHEATS.prank(delegator);
        L2_MIGRATOR.claimStake(delegate, 500000000000000000000, 0, proof, address(0));

        (, , address delegateAddress, , , , ) = BONDING_MANAGER.getDelegator(delegator);

        assertEq(delegateAddress, delegate);
    }

    function testFailChangeDelegateByThirdParty() public {
        uint256 round = 2499;
        uint256 blockNum = round * 5760;
        CHEATS.roll(blockNum);

        address delegator = 0xAcA4bD77e459b9898A0de9Ad7C1caC34fF540D0B;
        address delegate = 0x525419FF5707190389bfb5C87c375D710F5fCb0E;
        address thirdParty = 0x12336b564A71Cc4C1319bf35E87Ea45681E4D94a;

        // trying to change delegate of a delegator should revert
        CHEATS.prank(thirdParty);
        BONDING_MANAGER.bondForWithHint(0, delegator, delegate, address(0), address(0), address(0), address(0));
    }
}


Made version constant.

Made version constant.

Signed-off-by: Nikita <5c9993fe5c1b9bfc216420fea06629aef1fdc9c2@gmail.com>

pragma solidity ^0.4.17;

import "./StandardToken.sol";

/**
 * @title The Pre-Leo Token contract.
 *
 * Credit: Taking ideas from BAT token and NET token
 */
contract PLToken is StandardToken {

    // Token metadata
    string public constant name = "Pre-Leo Token";
    string public constant symbol = "PLT";
    uint256 public constant decimals = 18;
    string public constant version = "0.9";

    // Fundraising parameters
    enum ContractState { Fundraising, Finalized, Redeeming, Paused }
    ContractState public state;           // Current state of the contract
    ContractState private savedState;     // State of the contract before pause

    uint256 public fundingStartBlock;        // These two blocks need to be chosen to comply with the
    uint256 public fundingEndBlock;          // start date and 28 day duration requirements
    uint256 public exchangeRateChangesBlock; // block number that triggers the exchange rate change

    address public admin1; // First administrator for multi-sig mechanism
    address public admin2; // Second administrator for multi-sig mechanism

    uint256 public constant TOKEN_FIRST_EXCHANGE_RATE = 200; // 200 PLTs per 1 ETH
    uint256 public constant TOKEN_SECOND_EXCHANGE_RATE = 175; // 175 PLTs per 1 ETH
    uint256 public constant TOKEN_CREATION_CAP = 10 * (10**6) * 10**decimals; // 10 million PLTs
    uint256 public constant ETH_RECEIVED_CAP = 50 * (10**3) * 10**decimals; // 50 000 ETH
    uint256 public constant ETH_RECEIVED_MIN = 10 * (10**3) * 10**decimals; // 10 000 ETH
    uint256 public constant TOKEN_MIN = 1 * 10**decimals; // 1 PLT

    // We need to keep track of how much ether have been contributed, since we have a cap for ETH too
    uint256 public totalReceivedEth = 0;

    // Since we have different exchange rates at different stages, we need to keep track
    // of how much ether each contributed in case that we need to issue a refund
    mapping (address => uint256) private ethBalances;
    mapping (address => bytes32) private multiSigHashes; // store the hashes of admins' msg.data

    // Events used for logging
    event LogRefund(address indexed _to, uint256 _value);
    event LogCreatePLT(address indexed _to, uint256 _value);
    event LogRedeemPLT(address indexed _from, uint256 _value, string _leoAddress);

    modifier isFinalized() {
        require(state == ContractState.Finalized);
        _;
    }

    modifier isFundraising() {
        require(state == ContractState.Fundraising);
        _;
    }

    modifier isRedeeming() {
        require(state == ContractState.Redeeming);
        _;
    }

    modifier isPaused() {
        require(state == ContractState.Paused);
        _;
    }

    modifier notPaused() {
        require(state != ContractState.Paused);
        _;
    }

    modifier isFundraisingIgnorePaused() {
        require(state == ContractState.Fundraising || (state == ContractState.Paused && savedState == ContractState.Fundraising));
        _;
    }

    modifier onlyOwner() {
        // check if transaction sender is admin.
        require (msg.sender == admin1 || msg.sender == admin2);
        // if yes, store his msg.data.
        multiSigHashes[msg.sender] = keccak256(msg.data);
        // check if his stored msg.data hash equals to the one of the other admin
        if ((multiSigHashes[admin1]) == (multiSigHashes[admin2])) {
            // if yes, both admins agreed - continue.
            _;
        } else {
            // if not (yet), return.
            return;
        }
    }

    modifier minimumReached() {
        require(totalReceivedEth >= ETH_RECEIVED_MIN);
        _;
    }

    /**
     * @dev Create a new PLToken contract.
     *
     * @param _fundingStartBlock The starting block of the fundraiser (has to be in the future).
     * @param _fundingEndBlock The end block of the fundraiser (has to be after _fundingStartBlock).
     * @param _exchangeRateChangesBlock The block that changes the exchange rate (has to be between _fundingStartBlock and _fundingEndBlock).
     * @param _admin1 The first admin account that owns this contract.
     * @param _admin2 The second admin account that owns this contract.
     */
    function PLToken(
        uint256 _fundingStartBlock,
        uint256 _fundingEndBlock,
        uint256 _exchangeRateChangesBlock,
        address _admin1,
        address _admin2)
    public
    {
        // Check that the parameters make sense
        require(block.number <= _fundingStartBlock); // The start of the fundraising should happen in the future
        require(_fundingStartBlock <= _exchangeRateChangesBlock); // The exchange rate change should happen after the start of the fundraising
        require(_exchangeRateChangesBlock <= _fundingEndBlock); // And the end of the fundraising should happen after the exchange rate change
        require (_admin1 != 0x0); // admin1 address must be set
        require (_admin2 != 0x0); // admin2 address must be set
        require (_admin1 != _admin2); // Ensure that admin accounts are different

        // Contract state
        state = ContractState.Fundraising;
        savedState = ContractState.Fundraising;
        fundingStartBlock = _fundingStartBlock;
        fundingEndBlock = _fundingEndBlock;
        exchangeRateChangesBlock = _exchangeRateChangesBlock;
        totalSupply = 0;

        admin1 = _admin1;
        admin2 = _admin2;
    }

    // Overridden method to check for end of fundraising before allowing transfer of tokens
    function transfer(address _to, uint256 _value)
    public
    isFinalized // Only allow token transfer after the fundraising has ended
    onlyPayloadSize(2)
    returns (bool success)
    {
        return super.transfer(_to, _value);
    }

    // Overridden method to check for end of fundraising before allowing transfer of tokens
    function transferFrom(address _from, address _to, uint256 _value)
    public
    isFinalized // Only allow token transfer after the fundraising has ended
    onlyPayloadSize(3)
    returns (bool success)
    {
        return super.transferFrom(_from, _to, _value);
    }

    /// @dev Accepts ether and creates new PLT tokens
    function createTokens()
    payable
    external
    isFundraising
    {
        require(block.number >= fundingStartBlock);
        require(block.number <= fundingEndBlock);
        require(msg.value > 0);

        // First we check the ETH cap, as it's easier to calculate, return
        // the contribution if the cap has been reached already
        uint256 checkedReceivedEth = SafeMath.add(totalReceivedEth, msg.value);
        require(checkedReceivedEth <= ETH_RECEIVED_CAP);

        // If all is fine with the ETH cap, we continue to check the
        // minimum amount of tokens and the cap for how many tokens
        // have been generated so far
        uint256 tokens = SafeMath.mul(msg.value, getCurrentTokenPrice());
        require(tokens >= TOKEN_MIN);
        uint256 checkedSupply = SafeMath.add(totalSupply, tokens);
        require(checkedSupply <= TOKEN_CREATION_CAP);

        // Only when all the checks have passed, then we update the state (ethBalances,
        // totalReceivedEth, totalSupply, and balances) of the contract
        ethBalances[msg.sender] = SafeMath.add(ethBalances[msg.sender], msg.value);
        totalReceivedEth = checkedReceivedEth;
        totalSupply = checkedSupply;
        balances[msg.sender] += tokens;  // safeAdd not needed; bad semantics to use here

        // Log the creation of this tokens
        LogCreatePLT(msg.sender, tokens);
    }

    /// @dev Returns the current token price
    function getCurrentTokenPrice()
    private
    constant
    returns (uint256 currentPrice)
    {
        if (block.number < exchangeRateChangesBlock) {
            return TOKEN_FIRST_EXCHANGE_RATE;
        } else {
            return TOKEN_SECOND_EXCHANGE_RATE;
        }
    }

    /// @dev Redeems PLTs and records the LEO address of the sender
    function redeemTokens(string leoAddress)
    external
    isRedeeming
    {
        uint256 pltVal = balances[msg.sender];
        require(pltVal >= TOKEN_MIN); // At least TOKEN_MIN tokens have to be redeemed

        // Burn Tokens on redemption
        require(super.transfer(0x0, pltVal));
        // Log the redeeming of this tokens
        LogRedeemPLT(msg.sender, pltVal, leoAddress);
    }

    /// @dev Allows to transfer ether from the contract as soon as the minimum is reached
    function retrieveEth(uint256 _value, address _safe)
    external
    minimumReached
    onlyOwner
    {
        require(_value <= this.balance);
        // make sure a recipient was defined !
        require (_safe != 0x0);

        // send the eth to where admins agree upon
        _safe.transfer(_value);
    }

    /// @dev Ends the fundraising period and sends the ETH to wherever the admins agree upon
    function finalize(address _safe)
    external
    isFundraising
    minimumReached
    onlyOwner  // Only the admins calling this method exactly the same way can finalize the sale.
    {
        // Only allow to finalize the contract before the ending block if we already reached any of the two caps
        require(block.number > fundingEndBlock || totalSupply >= TOKEN_CREATION_CAP || totalReceivedEth >= ETH_RECEIVED_CAP);
        // make sure a recipient was defined !
        require (_safe != 0x0);

        // Move the contract to Finalized state
        state = ContractState.Finalized;
        savedState = ContractState.Finalized;

        // Send the ETH to where admins agree upon.
        _safe.transfer(this.balance);
    }

    /// @dev Starts the redeeming period
    function startRedeeming()
    external
    isFinalized // The redeeming period can only be started after the contract is finalized
    onlyOwner   // Only both admins calling this method can initiate the redeeming period
    {
        // Move the contract to Redeeming state
        state = ContractState.Redeeming;
        savedState = ContractState.Redeeming;
    }

    /// @dev Pauses the contract
    function pause()
    external
    notPaused   // Prevent the contract getting stuck in the Paused state
    onlyOwner   // Only both admins calling this method can pause the contract
    {
        // Move the contract to Paused state
        savedState = state;
        state = ContractState.Paused;
    }

    /// @dev Proceeds with the contract
    function proceed()
    external
    isPaused
    onlyOwner   // Only both admins calling this method can proceed with the contract
    {
        // Move the contract to the previous state
        state = savedState;
    }

    /// @dev Allows contributors to recover their ether in case the minimum funding goal is not reached
    function refund()
    external
    isFundraisingIgnorePaused // Refunding is only possible in the fundraising phase (no matter if paused) by definition
    {
        require(block.number > fundingEndBlock); // Prevents refund until fundraising period is over
        require(totalReceivedEth < ETH_RECEIVED_MIN);  // No refunds if the minimum has been reached

        uint256 pltVal = balances[msg.sender];
        require(pltVal > 0);
        uint256 ethVal = ethBalances[msg.sender];
        require(ethVal > 0);

        // Update the state only after all the checks have passed
        balances[msg.sender] = 0;
        ethBalances[msg.sender] = 0;
        totalSupply = SafeMath.sub(totalSupply, pltVal); // Extra safe

        // Log this refund
        LogRefund(msg.sender, ethVal);

        // Send the contributions only after we have updated all the balances
        // If you're using a contract, make sure it works with .transfer() gas limits
        msg.sender.transfer(ethVal);
    }
}

pragma solidity ^0.4.17;

import "./StandardToken.sol";

/**
 * @title The Pre-Leo Token contract.
 *
 * Credit: Taking ideas from BAT token and NET token
 */
contract PLToken is StandardToken {

    // Token metadata
    string public constant name = "Pre-Leo Token";
    string public constant symbol = "PLT";
    uint256 public constant decimals = 18;
    string public version = "0.9";

    // Fundraising parameters
    enum ContractState { Fundraising, Finalized, Redeeming, Paused }
    ContractState public state;           // Current state of the contract
    ContractState private savedState;     // State of the contract before pause

    uint256 public fundingStartBlock;        // These two blocks need to be chosen to comply with the
    uint256 public fundingEndBlock;          // start date and 28 day duration requirements
    uint256 public exchangeRateChangesBlock; // block number that triggers the exchange rate change

    address public admin1; // First administrator for multi-sig mechanism
    address public admin2; // Second administrator for multi-sig mechanism

    uint256 public constant TOKEN_FIRST_EXCHANGE_RATE = 200; // 200 PLTs per 1 ETH
    uint256 public constant TOKEN_SECOND_EXCHANGE_RATE = 175; // 175 PLTs per 1 ETH
    uint256 public constant TOKEN_CREATION_CAP = 10 * (10**6) * 10**decimals; // 10 million PLTs
    uint256 public constant ETH_RECEIVED_CAP = 50 * (10**3) * 10**decimals; // 50 000 ETH
    uint256 public constant ETH_RECEIVED_MIN = 10 * (10**3) * 10**decimals; // 10 000 ETH
    uint256 public constant TOKEN_MIN = 1 * 10**decimals; // 1 PLT

    // We need to keep track of how much ether have been contributed, since we have a cap for ETH too
    uint256 public totalReceivedEth = 0;

    // Since we have different exchange rates at different stages, we need to keep track
    // of how much ether each contributed in case that we need to issue a refund
    mapping (address => uint256) private ethBalances;
    mapping (address => bytes32) private multiSigHashes; // store the hashes of admins' msg.data

    // Events used for logging
    event LogRefund(address indexed _to, uint256 _value);
    event LogCreatePLT(address indexed _to, uint256 _value);
    event LogRedeemPLT(address indexed _from, uint256 _value, string _leoAddress);

    modifier isFinalized() {
        require(state == ContractState.Finalized);
        _;
    }

    modifier isFundraising() {
        require(state == ContractState.Fundraising);
        _;
    }

    modifier isRedeeming() {
        require(state == ContractState.Redeeming);
        _;
    }

    modifier isPaused() {
        require(state == ContractState.Paused);
        _;
    }

    modifier notPaused() {
        require(state != ContractState.Paused);
        _;
    }

    modifier isFundraisingIgnorePaused() {
        require(state == ContractState.Fundraising || (state == ContractState.Paused && savedState == ContractState.Fundraising));
        _;
    }

    modifier onlyOwner() {
        // check if transaction sender is admin.
        require (msg.sender == admin1 || msg.sender == admin2);
        // if yes, store his msg.data.
        multiSigHashes[msg.sender] = keccak256(msg.data);
        // check if his stored msg.data hash equals to the one of the other admin
        if ((multiSigHashes[admin1]) == (multiSigHashes[admin2])) {
            // if yes, both admins agreed - continue.
            _;
        } else {
            // if not (yet), return.
            return;
        }
    }

    modifier minimumReached() {
        require(totalReceivedEth >= ETH_RECEIVED_MIN);
        _;
    }

    /**
     * @dev Create a new PLToken contract.
     *
     * @param _fundingStartBlock The starting block of the fundraiser (has to be in the future).
     * @param _fundingEndBlock The end block of the fundraiser (has to be after _fundingStartBlock).
     * @param _exchangeRateChangesBlock The block that changes the exchange rate (has to be between _fundingStartBlock and _fundingEndBlock).
     * @param _admin1 The first admin account that owns this contract.
     * @param _admin2 The second admin account that owns this contract.
     */
    function PLToken(
        uint256 _fundingStartBlock,
        uint256 _fundingEndBlock,
        uint256 _exchangeRateChangesBlock,
        address _admin1,
        address _admin2)
    public
    {
        // Check that the parameters make sense
        require(block.number <= _fundingStartBlock); // The start of the fundraising should happen in the future
        require(_fundingStartBlock <= _exchangeRateChangesBlock); // The exchange rate change should happen after the start of the fundraising
        require(_exchangeRateChangesBlock <= _fundingEndBlock); // And the end of the fundraising should happen after the exchange rate change
        require (_admin1 != 0x0); // admin1 address must be set
        require (_admin2 != 0x0); // admin2 address must be set
        require (_admin1 != _admin2); // Ensure that admin accounts are different

        // Contract state
        state = ContractState.Fundraising;
        savedState = ContractState.Fundraising;
        fundingStartBlock = _fundingStartBlock;
        fundingEndBlock = _fundingEndBlock;
        exchangeRateChangesBlock = _exchangeRateChangesBlock;
        totalSupply = 0;

        admin1 = _admin1;
        admin2 = _admin2;
    }

    // Overridden method to check for end of fundraising before allowing transfer of tokens
    function transfer(address _to, uint256 _value)
    public
    isFinalized // Only allow token transfer after the fundraising has ended
    onlyPayloadSize(2)
    returns (bool success)
    {
        return super.transfer(_to, _value);
    }

    // Overridden method to check for end of fundraising before allowing transfer of tokens
    function transferFrom(address _from, address _to, uint256 _value)
    public
    isFinalized // Only allow token transfer after the fundraising has ended
    onlyPayloadSize(3)
    returns (bool success)
    {
        return super.transferFrom(_from, _to, _value);
    }

    /// @dev Accepts ether and creates new PLT tokens
    function createTokens()
    payable
    external
    isFundraising
    {
        require(block.number >= fundingStartBlock);
        require(block.number <= fundingEndBlock);
        require(msg.value > 0);

        // First we check the ETH cap, as it's easier to calculate, return
        // the contribution if the cap has been reached already
        uint256 checkedReceivedEth = SafeMath.add(totalReceivedEth, msg.value);
        require(checkedReceivedEth <= ETH_RECEIVED_CAP);

        // If all is fine with the ETH cap, we continue to check the
        // minimum amount of tokens and the cap for how many tokens
        // have been generated so far
        uint256 tokens = SafeMath.mul(msg.value, getCurrentTokenPrice());
        require(tokens >= TOKEN_MIN);
        uint256 checkedSupply = SafeMath.add(totalSupply, tokens);
        require(checkedSupply <= TOKEN_CREATION_CAP);

        // Only when all the checks have passed, then we update the state (ethBalances,
        // totalReceivedEth, totalSupply, and balances) of the contract
        ethBalances[msg.sender] = SafeMath.add(ethBalances[msg.sender], msg.value);
        totalReceivedEth = checkedReceivedEth;
        totalSupply = checkedSupply;
        balances[msg.sender] += tokens;  // safeAdd not needed; bad semantics to use here

        // Log the creation of this tokens
        LogCreatePLT(msg.sender, tokens);
    }

    /// @dev Returns the current token price
    function getCurrentTokenPrice()
    private
    constant
    returns (uint256 currentPrice)
    {
        if (block.number < exchangeRateChangesBlock) {
            return TOKEN_FIRST_EXCHANGE_RATE;
        } else {
            return TOKEN_SECOND_EXCHANGE_RATE;
        }
    }

    /// @dev Redeems PLTs and records the LEO address of the sender
    function redeemTokens(string leoAddress)
    external
    isRedeeming
    {
        uint256 pltVal = balances[msg.sender];
        require(pltVal >= TOKEN_MIN); // At least TOKEN_MIN tokens have to be redeemed

        // Burn Tokens on redemption
        require(super.transfer(0x0, pltVal));
        // Log the redeeming of this tokens
        LogRedeemPLT(msg.sender, pltVal, leoAddress);
    }

    /// @dev Allows to transfer ether from the contract as soon as the minimum is reached
    function retrieveEth(uint256 _value, address _safe)
    external
    minimumReached
    onlyOwner
    {
        require(_value <= this.balance);
        // make sure a recipient was defined !
        require (_safe != 0x0);

        // send the eth to where admins agree upon
        _safe.transfer(_value);
    }

    /// @dev Ends the fundraising period and sends the ETH to wherever the admins agree upon
    function finalize(address _safe)
    external
    isFundraising
    minimumReached
    onlyOwner  // Only the admins calling this method exactly the same way can finalize the sale.
    {
        // Only allow to finalize the contract before the ending block if we already reached any of the two caps
        require(block.number > fundingEndBlock || totalSupply >= TOKEN_CREATION_CAP || totalReceivedEth >= ETH_RECEIVED_CAP);
        // make sure a recipient was defined !
        require (_safe != 0x0);

        // Move the contract to Finalized state
        state = ContractState.Finalized;
        savedState = ContractState.Finalized;

        // Send the ETH to where admins agree upon.
        _safe.transfer(this.balance);
    }

    /// @dev Starts the redeeming period
    function startRedeeming()
    external
    isFinalized // The redeeming period can only be started after the contract is finalized
    onlyOwner   // Only both admins calling this method can initiate the redeeming period
    {
        // Move the contract to Redeeming state
        state = ContractState.Redeeming;
        savedState = ContractState.Redeeming;
    }

    /// @dev Pauses the contract
    function pause()
    external
    notPaused   // Prevent the contract getting stuck in the Paused state
    onlyOwner   // Only both admins calling this method can pause the contract
    {
        // Move the contract to Paused state
        savedState = state;
        state = ContractState.Paused;
    }

    /// @dev Proceeds with the contract
    function proceed()
    external
    isPaused
    onlyOwner   // Only both admins calling this method can proceed with the contract
    {
        // Move the contract to the previous state
        state = savedState;
    }

    /// @dev Allows contributors to recover their ether in case the minimum funding goal is not reached
    function refund()
    external
    isFundraisingIgnorePaused // Refunding is only possible in the fundraising phase (no matter if paused) by definition
    {
        require(block.number > fundingEndBlock); // Prevents refund until fundraising period is over
        require(totalReceivedEth < ETH_RECEIVED_MIN);  // No refunds if the minimum has been reached

        uint256 pltVal = balances[msg.sender];
        require(pltVal > 0);
        uint256 ethVal = ethBalances[msg.sender];
        require(ethVal > 0);

        // Update the state only after all the checks have passed
        balances[msg.sender] = 0;
        ethBalances[msg.sender] = 0;
        totalSupply = SafeMath.sub(totalSupply, pltVal); // Extra safe

        // Log this refund
        LogRefund(msg.sender, ethVal);

        // Send the contributions only after we have updated all the balances
        // If you're using a contract, make sure it works with .transfer() gas limits
        msg.sender.transfer(ethVal);
    }
}


refactored interpreter

refactored interpreter

pragma solidity ^0.4.15;

import "alu.sol";

contract Instruction is ALU {

    address winner;

    struct Roots {
        bytes32 code;
        bytes32 stack;
        bytes32 mem;
        bytes32 globals;
        bytes32 calltable;
        bytes32 calltypes;
        bytes32 call_stack;
        bytes32 input;
    }

    struct VM {
        uint pc;
        uint stack_ptr;
        uint call_ptr;
        uint memsize;
    }

    VM vm;
    Roots vm_r;

    struct Machine {
        bytes32 vm;
        bytes32 op;
        uint reg1;
        uint reg2;
        uint reg3;
        uint ireg;
    }

    function setVM2(bytes32[8] roots, uint[4] pointers) internal {
        vm_r.code = roots[0];
        vm_r.stack = roots[1];
        vm_r.mem = roots[2];
        vm_r.call_stack = roots[3];
        vm_r.globals = roots[4];
        vm_r.calltable = roots[5];
        vm_r.calltypes = roots[6];
        vm_r.input = roots[7];

        vm.pc = pointers[0];
        vm.stack_ptr = pointers[1];
        vm.call_ptr = pointers[2];
        vm.memsize = pointers[3];
    }

    function hashVM() internal view returns (bytes32) {
        bytes32[] memory arr = new bytes32[](12);
        arr[0] = vm_r.code;
        arr[1] = vm_r.mem;
        arr[2] = vm_r.stack;
        arr[3] = vm_r.globals;
        arr[4] = vm_r.call_stack;
        arr[5] = vm_r.calltable;
        arr[6] = vm_r.calltypes;
        arr[7] = vm_r.input;
        arr[8] = bytes32(vm.pc);
        arr[9] = bytes32(vm.stack_ptr);
        arr[10] = bytes32(vm.call_ptr);
        arr[11] = bytes32(vm.memsize);
        return keccak256(arr);
    }

    Machine m;

    function setMachine(
        bytes32 vm_,
        bytes32 op,
        uint reg1,
        uint reg2,
        uint reg3,
        uint ireg) internal {
        m.vm = vm_;
        m.op = op;
        m.reg1 = reg1;
        m.reg2 = reg2;
        m.reg3 = reg3;
        m.ireg = ireg;
    }

    function hashMachine() internal view returns (bytes32) {
        return keccak256(m.vm, m.op, m.reg1, m.reg2, m.reg3, m.ireg);
    }

    function getLeaf(bytes32[] proof, uint loc) internal pure returns (bytes32) {
        require(proof.length >= 2);
        if (loc%2 == 0) return proof[0];
        else return proof[1];
    }

    function getRoot(bytes32[] proof, uint loc) internal pure returns (bytes32) {
        require(proof.length >= 2);
        bytes32 res = keccak256(proof[0], proof[1]);
        for (uint i = 2; i < proof.length; i++) {
            loc = loc/2;
            if (loc%2 == 0) res = keccak256(res, proof[i]);
            else res = keccak256(proof[i], res);
        }
        require(loc < 2);
        return res;
    }

    function getImmed(bytes32 op) internal pure returns (uint256) {
        // it is the first 8 bytes
        return uint(op)/(2**(13*8));
    }

    function readPosition(uint hint) internal view returns (uint) {
        assert(hint > 4);
        if (hint == 5) return m.reg1;
        else if (hint == 6) return vm.stack_ptr-1;
        else if (hint == 7) return vm.stack_ptr-2;
        else if (hint == 8) return vm.stack_ptr-m.reg1; // Stack in reg
        else if (hint == 9) return vm.stack_ptr-m.reg2;
        else if (hint == 14) return vm.call_ptr-1;
        else if (hint == 15) return (m.reg1+m.ireg)/8;
        else if (hint == 16) return m.reg1;
        else if (hint == 17) return (m.reg1+m.ireg)/8 + 1;
        else if (hint == 18) return m.reg1;
        else if (hint == 19) return m.reg1;
    }

    function writePosition(uint hint) internal view returns (uint) {
        assert(hint > 0);
        if (hint == 2) return vm.stack_ptr-m.reg1;
        else if (hint == 3) return vm.stack_ptr;
        else if (hint == 4) return vm.stack_ptr-1;
        else if (hint == 5) return m.reg1+m.reg2;
        else if (hint == 6) return vm.call_ptr;
        else if (hint == 8) return m.reg1;
        else if (hint == 9) return vm.stack_ptr-2;
        else if (hint & 0xc0 == 0x80) return (m.reg1+m.ireg)/8;
        else if (hint & 0xc0 == 0xc0) return (m.reg1+m.ireg)/8 + 1;
    }

    function readRoot(uint hint) internal view returns (bytes32) {
        assert(hint > 4);
        if (hint == 5) return vm_r.globals;
        else if (hint == 6) return vm_r.stack;
        else if (hint == 7) return vm_r.stack;
        else if (hint == 8) return vm_r.stack;
        else if (hint == 9) return vm_r.stack;
        else if (hint == 14) return vm_r.call_stack;
        else if (hint == 15) return vm_r.mem;
        else if (hint == 16) return vm_r.calltable;
        else if (hint == 17) return vm_r.mem;
        else if (hint == 18) return vm_r.calltypes;
        else if (hint == 19) return vm_r.input;
    }

    function writeRoot(uint hint) internal view returns (bytes32) {
        assert(hint > 0);
        if (hint == 2) return vm_r.stack;
        else if (hint == 3) return vm_r.stack;
        else if (hint == 4) return vm_r.stack;
        else if (hint == 5) return vm_r.mem;
        else if (hint == 6) return vm_r.call_stack;
        else if (hint == 8) return vm_r.globals;
        else if (hint == 9) return vm_r.stack;
        else return vm_r.mem;
    }

    function checkReadProof(bytes32[] proof, uint loc, uint hint) internal view returns (bool) {
        if (hint <= 4) return true;
        return readPosition(hint) == loc && readRoot(hint) == getRoot(proof, loc);
    }

    function checkWriteProof(bytes32[] proof, uint loc, uint hint) internal view returns (bool) {
        if (hint == 0) return true;
        return writePosition(hint) == loc && writeRoot(hint) == getRoot(proof, loc);
    }

    function readFromProof(bytes32[] proof, uint loc, uint hint) internal view returns (uint) {
        if (hint == 0) return 0;
        if (hint == 1) return m.ireg;
        if (hint == 2) return vm.pc+1;
        if (hint == 3) return vm.stack_ptr;
        if (hint == 4) return vm.memsize;
        return uint(getLeaf(proof, loc));
    }

    function makeChange(bytes32[] proof, uint loc, uint v) internal pure returns (bytes32) {
        assert(proof.length >= 2);
        if (loc%2 == 0) proof[0] = bytes32(v);
        else proof[1] = bytes32(v);
        return getRoot(proof, loc);
    }

    uint debug;

    function makeMemChange1(bytes32[] proof, uint loc, uint v, uint hint) internal view returns (bytes32) {
        assert(proof.length >= 2);

        uint old = uint(getLeaf(proof, loc));
        uint8[] memory mem = toMemory(old, 0);
        storeX(mem, (m.reg1+m.ireg)%8, v, hint);
        uint res; uint extra;
        (res, extra) = fromMemory(mem);

        if (loc%2 == 0) proof[0] = bytes32(res);
        else proof[1] = bytes32(res);
        return getRoot(proof, loc);
    }

    function makeMemChange2(bytes32[] proof, uint loc, uint v, uint hint) internal view returns (bytes32) {
        assert(proof.length >= 2);

        uint old = uint(getLeaf(proof, loc));
        uint8[] memory mem = toMemory(0, old);
        storeX(mem, (m.reg1+m.ireg)%8, v, hint);
        uint res; uint extra;
        (extra, res) = fromMemory(mem);

        if (loc%2 == 0) proof[0] = bytes32(res);
        else proof[1] = bytes32(res);
        return getRoot(proof, loc);
    }

    function writeStuff(uint hint, bytes32[] proof, uint loc, uint v) internal {
        if (hint == 0) return;
        bytes32 root;
        if (hint & 0xc0 == 0x80) root = makeMemChange1(proof, loc, v, hint);
        else if (hint & 0xc0 == 0xc0) root = makeMemChange2(proof, loc, v, hint);
        else root = makeChange(proof, loc, v);

        if (hint == 2) vm_r.stack = root;
        else if (hint == 3) vm_r.stack = root;
        else if (hint == 4) vm_r.stack = root;
        else if (hint == 5) vm_r.mem = root;
        else if (hint == 6) vm_r.call_stack = root;
        else if (hint == 8) vm_r.globals = root;
        else if (hint == 9) vm_r.stack = root;
        else vm_r.mem = root;
    }

    function handlePointer(uint hint, uint ptr) internal view returns (uint) {
        if (hint == 0) return ptr - m.reg1;
        else if (hint == 1) return m.reg1;
        else if (hint == 2) return m.reg2;
        else if (hint == 3) return m.reg3;
        else if (hint == 4) return ptr+1;
        else if (hint == 5) return ptr-1;
        else if (hint == 6) return ptr;
        else if (hint == 7) return ptr-2;
        else if (hint == 8) return ptr-1-m.ireg;
    }

    function performFetch(bytes32 state1, bytes32[] proof) internal view returns (bytes32) {
        require(state1 == hashVM());
        bytes32 op = getLeaf(proof, vm.pc);
        require(vm_r.code == getRoot(proof, vm.pc));
        return keccak256(state1, op);
    }

    function performInit(bytes32 state1, bytes32 op) internal returns (bytes32) {
        m.vm = hashVM();
        m.op = op;
        m.reg1 = 0;
        m.reg2 = 0;
        m.reg3 = 0;
        m.ireg = getImmed(op);
        require(state1 == keccak256(m.vm, op));
        return hashMachine();
    }
    function performRead1(bytes32 state1, bytes32[] proof, uint loc) internal returns (bytes32) {
        require(m.vm == hashVM());
        require(state1 == hashMachine());
        uint hint = (uint(m.op)/2**(8*0))&0xff;
        require(checkReadProof(proof, loc, hint));
        m.reg1 = readFromProof(proof, loc, hint);
        return hashMachine();
    }
    function performRead2(bytes32 state1, bytes32[] proof, uint loc) internal returns (bytes32) {
        require(m.vm == hashVM());
        require(state1 == hashMachine());
        uint hint = (uint(m.op)/2**(8*1))&0xff;
        require(checkReadProof(proof, loc, hint));
        m.reg2 = readFromProof(proof, loc, hint);
        // debug = hint;
        return hashMachine();
    }
    function performRead3(bytes32 state1, bytes32[] proof, uint loc) internal returns (bytes32) {
        require(m.vm == hashVM());
        require(state1 == hashMachine());
        uint hint = (uint(m.op)/2**(8*2))&0xff;
        require(checkReadProof(proof, loc, hint));
        m.reg3 = readFromProof(proof, loc, hint);
        return hashMachine();
    }

    function performALU(bytes32 state1) internal returns (bytes32) {
        require(state1 == hashMachine());
        uint hint = (uint(m.op)/2**(8*3))&0xff;
        m.reg1 = handleALU(hint, m.reg1, m.reg2, m.reg3, m.ireg);
        return hashMachine();
    }

    function performWrite1(bytes32 state1, bytes32[] proof, uint loc) internal returns (bytes32) {
        require(m.vm == hashVM());
        require(state1 == hashMachine());
        uint target = (uint(m.op)/2**(8*4))&0xff;
        uint hint = (uint(m.op)/2**(8*5))&0xff;
        debug = hint;
        require(checkWriteProof(proof, loc, hint));
        uint v;
        if (target == 1) v = m.reg1;
        if (target == 2) v = m.reg2;
        if (target == 3) v = m.reg3;
        writeStuff(hint, proof, loc, v);

        m.vm = hashVM();
        return hashMachine();
    }
    function performWrite2(bytes32 state1, bytes32[] proof, uint loc) internal returns (bytes32) {
        require(m.vm == hashVM());
        require(state1 == hashMachine());
        uint target = (uint(m.op)/2**(8*6))&0xff;
        uint hint = (uint(m.op)/2**(8*7))&0xff;
        debug = hint;
        require(checkWriteProof(proof, loc, hint));

        uint v;
        if (target == 1) v = m.reg1;
        if (target == 2) v = m.reg2;
        if (target == 3) v = m.reg3;
        writeStuff(hint, proof, loc, v);

        m.vm = hashVM();
        return hashMachine();
    }

    function performUpdatePC(bytes32 state1) internal returns (bytes32) {
        require(m.vm == hashVM());
        require(state1 == hashMachine());
        uint hint = (uint(m.op)/2**(8*11))&0xff;
        vm.pc = handlePointer(hint, vm.pc);
        m.vm = hashVM();
        return hashMachine();
    }
    function performUpdateStackPtr(bytes32 state1) internal returns (bytes32) {
        require(m.vm == hashVM());
        require(state1 == hashMachine());
        uint hint = (uint(m.op)/2**(8*9))&0xff;
        vm.stack_ptr = handlePointer(hint, vm.stack_ptr);
        m.vm = hashVM();
        return hashMachine();
    }
    function performUpdateCallPtr(bytes32 state1) internal returns (bytes32) {
        require(m.vm == hashVM());
        require(state1 == hashMachine());
        uint hint = (uint(m.op)/2**(8*8))&0xff;
        vm.call_ptr = handlePointer(hint, vm.call_ptr);
        m.vm = hashVM();
        return hashMachine();
    }
    function performUpdateMemsize(bytes32 state1) internal returns (bytes32) {
        require(m.vm == hashVM());
        require(state1 == hashMachine());
        uint hint = (uint(m.op)/2**(8*12))&0xff;
        if (hint == 1) vm.memsize = vm.memsize+m.reg1;
        return hashVM();
    }

    function performPhase(bytes32 state, uint init, bytes32[] proof, uint loc, bytes32 op) internal returns (bytes32) {
        if (init == 0) return performFetch(state, proof);
        if (init == 1) return performInit(state, op);
        if (init == 2) return performRead1(state, proof, loc);
        if (init == 3) return performRead2(state, proof, loc);
        if (init == 4) return performRead3(state, proof, loc);
        if (init == 5) return performALU(state);
        if (init == 6) return performWrite1(state, proof, loc);
        if (init == 7) return performWrite2(state, proof, loc);
        if (init == 8) return performUpdatePC(state);
        if (init == 9) return performUpdateStackPtr(state);
        if (init == 10) return performUpdateCallPtr(state);
        if (init == 11) return performUpdateMemsize(state);
    }

    function judge(bytes32[13] res, uint q,
                        bytes32[] proof, uint loc, bytes32 fetched_op,
                        bytes32 vm_, bytes32 op, uint[4] regs,
                        bytes32[8] roots, uint[4] pointers) public returns (uint) {
        // setup(res,msg.sender,msg.sender,q);
        setMachine(vm_, op, regs[0], regs[1], regs[2], regs[3]);
        setVM2(roots, pointers);
        require(performPhase(res[q], q, proof, loc, fetched_op) == res[q+1]);
        // debug = performPhase(res[q], q, proof, loc, fetched_op);
        winner = msg.sender;
        return debug;
    }

}

pragma solidity ^0.4.15;

import "alu.sol";

contract Instruction is ALU {

    bytes32[13] phases;
    address challenger;
    address prover;
    uint init;
    address winner;

    function setup(bytes32[13] arr, address c, address p, uint i) internal {
        phases = arr;
        challenger = c;
        prover = p;
        init = i;
        winner = challenger;
    }

    struct Roots {
        bytes32 code;
        bytes32 stack;
        bytes32 mem;
        bytes32 globals;
        bytes32 calltable;
        bytes32 calltypes;
        bytes32 call_stack;
        bytes32 input;
    }

    struct VM {
        uint pc;
        uint stack_ptr;
        uint call_ptr;
        uint memsize;
    }

    VM vm;
    Roots vm_r;

    struct Machine {
        bytes32 vm;
        bytes32 op;
        uint reg1;
        uint reg2;
        uint reg3;
        uint ireg;
    }

    function setVM2(bytes32[8] roots, uint[4] pointers) internal {
        require(msg.sender == prover);
        vm_r.code = roots[0];
        vm_r.stack = roots[1];
        vm_r.mem = roots[2];
        vm_r.call_stack = roots[3];
        vm_r.globals = roots[4];
        vm_r.calltable = roots[5];
        vm_r.calltypes = roots[6];
        vm_r.input = roots[7];

        vm.pc = pointers[0];
        vm.stack_ptr = pointers[1];
        vm.call_ptr = pointers[2];
        vm.memsize = pointers[3];
    }

    function hashVM() internal view returns (bytes32) {
        bytes32[] memory arr = new bytes32[](12);
        arr[0] = vm_r.code;
        arr[1] = vm_r.mem;
        arr[2] = vm_r.stack;
        arr[3] = vm_r.globals;
        arr[4] = vm_r.call_stack;
        arr[5] = vm_r.calltable;
        arr[6] = vm_r.calltypes;
        arr[7] = vm_r.input;
        arr[8] = bytes32(vm.pc);
        arr[9] = bytes32(vm.stack_ptr);
        arr[10] = bytes32(vm.call_ptr);
        arr[11] = bytes32(vm.memsize);
        return keccak256(arr);
    }

    Machine m;

    function setMachine(
        bytes32 vm_,
        bytes32 op,
        uint reg1,
        uint reg2,
        uint reg3,
        uint ireg) internal {
        m.vm = vm_;
        m.op = op;
        m.reg1 = reg1;
        m.reg2 = reg2;
        m.reg3 = reg3;
        m.ireg = ireg;
    }

    function hashMachine() internal view returns (bytes32) {
        return keccak256(m.vm, m.op, m.reg1, m.reg2, m.reg3, m.ireg);
    }

    function getLeaf(bytes32[] proof, uint loc) internal pure returns (bytes32) {
        require(proof.length >= 2);
        if (loc%2 == 0) return proof[0];
        else return proof[1];
    }

    function getRoot(bytes32[] proof, uint loc) internal pure returns (bytes32) {
        require(proof.length >= 2);
        bytes32 res = keccak256(proof[0], proof[1]);
        for (uint i = 2; i < proof.length; i++) {
            loc = loc/2;
            if (loc%2 == 0) res = keccak256(res, proof[i]);
            else res = keccak256(proof[i], res);
        }
        require(loc < 2);
        return res;
    }

    function proveFetch(bytes32[] proof) internal returns (bool) {
        require(init == 0 && msg.sender == prover);
        bytes32 state1 = phases[0];
        bytes32 state2 = phases[1];
        bytes32 op = getLeaf(proof, vm.pc);
        require(state1 == hashVM());
        require(state2 == keccak256(state1, op));
        require(vm_r.code == getRoot(proof, vm.pc));
        winner = prover;
        return true;
    }

    function getImmed(bytes32 op) internal pure returns (uint256) {
        // it is the first 8 bytes
        return uint(op)/(2**(13*8));
    }

    function proveInit(bytes32 op) internal returns (bool) {
        require(init == 1 && msg.sender == prover);
        bytes32 state1 = phases[1];
        bytes32 state2 = phases[2];
        m.vm = hashVM();
        m.op = op;
        m.reg1 = 0;
        m.reg2 = 0;
        m.reg3 = 0;
        m.ireg = getImmed(op);
        require(state1 == keccak256(m.vm, op));
        require(state2 == hashMachine());
        winner = prover;
        return true;
    }

    function readPosition(uint hint) internal view returns (uint) {
        assert(hint > 4);
        if (hint == 5) return m.reg1;
        else if (hint == 6) return vm.stack_ptr-1;
        else if (hint == 7) return vm.stack_ptr-2;
        else if (hint == 8) return vm.stack_ptr-m.reg1; // Stack in reg
        else if (hint == 9) return vm.stack_ptr-m.reg2;
        else if (hint == 14) return vm.call_ptr-1;
        else if (hint == 15) return (m.reg1+m.ireg)/8;
        else if (hint == 16) return m.reg1;
        else if (hint == 17) return (m.reg1+m.ireg)/8 + 1;
        else if (hint == 18) return m.reg1;
        else if (hint == 19) return m.reg1;
    }

    function writePosition(uint hint) internal view returns (uint) {
        assert(hint > 0);
        if (hint == 2) return vm.stack_ptr-m.reg1;
        else if (hint == 3) return vm.stack_ptr;
        else if (hint == 4) return vm.stack_ptr-1;
        else if (hint == 5) return m.reg1+m.reg2;
        else if (hint == 6) return vm.call_ptr;
        else if (hint == 8) return m.reg1;
        else if (hint == 9) return vm.stack_ptr-2;
        else if (hint & 0xc0 == 0x80) return (m.reg1+m.ireg)/8;
        else if (hint & 0xc0 == 0xc0) return (m.reg1+m.ireg)/8 + 1;
    }

    function readRoot(uint hint) internal view returns (bytes32) {
        assert(hint > 4);
        if (hint == 5) return vm_r.globals;
        else if (hint == 6) return vm_r.stack;
        else if (hint == 7) return vm_r.stack;
        else if (hint == 8) return vm_r.stack;
        else if (hint == 9) return vm_r.stack;
        else if (hint == 14) return vm_r.call_stack;
        else if (hint == 15) return vm_r.mem;
        else if (hint == 16) return vm_r.calltable;
        else if (hint == 17) return vm_r.mem;
        else if (hint == 18) return vm_r.calltypes;
        else if (hint == 19) return vm_r.input;
    }

    function writeRoot(uint hint) internal view returns (bytes32) {
        assert(hint > 0);
        if (hint == 2) return vm_r.stack;
        else if (hint == 3) return vm_r.stack;
        else if (hint == 4) return vm_r.stack;
        else if (hint == 5) return vm_r.mem;
        else if (hint == 6) return vm_r.call_stack;
        else if (hint == 8) return vm_r.globals;
        else if (hint == 9) return vm_r.stack;
        else return vm_r.mem;
    }

    function checkReadProof(bytes32[] proof, uint loc, uint hint) internal view returns (bool) {
        if (hint <= 4) return true;
        return readPosition(hint) == loc && readRoot(hint) == getRoot(proof, loc);
    }

    function checkWriteProof(bytes32[] proof, uint loc, uint hint) internal view returns (bool) {
        if (hint == 0) return true;
        return writePosition(hint) == loc && writeRoot(hint) == getRoot(proof, loc);
    }

    function readFromProof(bytes32[] proof, uint loc, uint hint) internal view returns (uint) {
        if (hint == 0) return 0;
        if (hint == 1) return m.ireg;
        if (hint == 2) return vm.pc+1;
        if (hint == 3) return vm.stack_ptr;
        if (hint == 4) return vm.memsize;
        return uint(getLeaf(proof, loc));
    }

    function proveRead1(bytes32[] proof, uint loc) internal returns (bool) {
        require(init == 2 && msg.sender == prover);
        bytes32 state1 = phases[2];
        bytes32 state2 = phases[3];
        require(m.vm == hashVM());
        require(state1 == hashMachine());
        uint hint = (uint(m.op)/2**(8*0))&0xff;
        require(checkReadProof(proof, loc, hint));
        m.reg1 = readFromProof(proof, loc, hint);
        require(state2 == hashMachine());
        winner = prover;
        return true;
    }
    function proveRead2(bytes32[] proof, uint loc) internal returns (bool) {
        require(init == 3 && msg.sender == prover);
        bytes32 state1 = phases[3];
        bytes32 state2 = phases[4];
        require(m.vm == hashVM());
        require(state1 == hashMachine());
        uint hint = (uint(m.op)/2**(8*1))&0xff;
        require(checkReadProof(proof, loc, hint));
        m.reg2 = readFromProof(proof, loc, hint);
        // debug = hint;
        require(state2 == hashMachine());
        winner = prover;
        return true;
    }
    function proveRead3(bytes32[] proof, uint loc) internal returns (bool) {
        require(init == 4 && msg.sender == prover);
        bytes32 state1 = phases[4];
        bytes32 state2 = phases[5];
        require(m.vm == hashVM());
        require(state1 == hashMachine());
        uint hint = (uint(m.op)/2**(8*2))&0xff;
        require(checkReadProof(proof, loc, hint));
        m.reg3 = readFromProof(proof, loc, hint);
        require(state2 == hashMachine());
        winner = prover;
        return true;
    }

    function proveALU() internal returns (uint) {
        require(init == 5 && msg.sender == prover);
        bytes32 state1 = phases[5];
        bytes32 state2 = phases[6];
        require(state1 == hashMachine());
        uint hint = (uint(m.op)/2**(8*3))&0xff;
        // m.reg1 = ALU.handleALU(hint, m.reg1, m.reg2, m.reg3, m.ireg);
        m.reg1 = handleALU(hint, m.reg1, m.reg2, m.reg3, m.ireg);
        require(state2 == hashMachine());
        winner = prover;
        return debug;
    }

    function makeChange(bytes32[] proof, uint loc, uint v) internal pure returns (bytes32) {
        assert(proof.length >= 2);
        if (loc%2 == 0) proof[0] = bytes32(v);
        else proof[1] = bytes32(v);
        return getRoot(proof, loc);
    }

    uint debug;

    function makeMemChange1(bytes32[] proof, uint loc, uint v, uint hint) internal view returns (bytes32) {
        assert(proof.length >= 2);

        uint old = uint(getLeaf(proof, loc));
        uint8[] memory mem = toMemory(old, 0);
        storeX(mem, (m.reg1+m.ireg)%8, v, hint);
        uint res; uint extra;
        (res, extra) = fromMemory(mem);

        if (loc%2 == 0) proof[0] = bytes32(res);
        else proof[1] = bytes32(res);
        return getRoot(proof, loc);
    }

    function makeMemChange2(bytes32[] proof, uint loc, uint v, uint hint) internal view returns (bytes32) {
        assert(proof.length >= 2);

        uint old = uint(getLeaf(proof, loc));
        uint8[] memory mem = toMemory(0, old);
        storeX(mem, (m.reg1+m.ireg)%8, v, hint);
        uint res; uint extra;
        (extra, res) = fromMemory(mem);

        if (loc%2 == 0) proof[0] = bytes32(res);
        else proof[1] = bytes32(res);
        return getRoot(proof, loc);
    }

    function writeStuff(uint hint, bytes32[] proof, uint loc, uint v) internal {
        if (hint == 0) return;
        bytes32 root;
        if (hint & 0xc0 == 0x80) root = makeMemChange1(proof, loc, v, hint);
        else if (hint & 0xc0 == 0xc0) root = makeMemChange2(proof, loc, v, hint);
        else root = makeChange(proof, loc, v);

        if (hint == 2) vm_r.stack = root;
        else if (hint == 3) vm_r.stack = root;
        else if (hint == 4) vm_r.stack = root;
        else if (hint == 5) vm_r.mem = root;
        else if (hint == 6) vm_r.call_stack = root;
        else if (hint == 8) vm_r.globals = root;
        else if (hint == 9) vm_r.stack = root;
        else vm_r.mem = root;
    }

    function proveWrite1(bytes32[] proof, uint loc) internal returns (uint) {
        require(init == 6 && msg.sender == prover);
        bytes32 state1 = phases[6];
        bytes32 state2 = phases[7];
        require(m.vm == hashVM());
        require(state1 == hashMachine());
        uint target = (uint(m.op)/2**(8*4))&0xff;
        uint hint = (uint(m.op)/2**(8*5))&0xff;
        debug = hint;
        require(checkWriteProof(proof, loc, hint));
        uint v;
        if (target == 1) v = m.reg1;
        if (target == 2) v = m.reg2;
        if (target == 3) v = m.reg3;
        writeStuff(hint, proof, loc, v);

        m.vm = hashVM();
        require(state2 == hashMachine());
        winner = prover;
        return debug;
    }
    function proveWrite2(bytes32[] proof, uint loc) internal returns (bool) {
        require(init == 7 && msg.sender == prover);
        bytes32 state1 = phases[7];
        bytes32 state2 = phases[8];
        require(m.vm == hashVM());
        require(state1 == hashMachine());
        uint target = (uint(m.op)/2**(8*6))&0xff;
        uint hint = (uint(m.op)/2**(8*7))&0xff;
        debug = hint;
        require(checkWriteProof(proof, loc, hint));

        uint v;
        if (target == 1) v = m.reg1;
        if (target == 2) v = m.reg2;
        if (target == 3) v = m.reg3;
        writeStuff(hint, proof, loc, v);

        m.vm = hashVM();
        require(state2 == hashMachine());
        winner = prover;
        return true;
    }

    function handlePointer(uint hint, uint ptr) internal view returns (uint) {
        if (hint == 0) return ptr - m.reg1;
        else if (hint == 1) return m.reg1;
        else if (hint == 2) return m.reg2;
        else if (hint == 3) return m.reg3;
        else if (hint == 4) return ptr+1;
        else if (hint == 5) return ptr-1;
        else if (hint == 6) return ptr;
        else if (hint == 7) return ptr-2;
        else if (hint == 8) return ptr-1-m.ireg;
    }

    function proveUpdatePC() internal returns (bool) {
        require(init == 8 && msg.sender == prover);
        bytes32 state1 = phases[8];
        bytes32 state2 = phases[9];
        require(m.vm == hashVM());
        require(state1 == hashMachine());
        uint hint = (uint(m.op)/2**(8*11))&0xff;
        vm.pc = handlePointer(hint, vm.pc);
        m.vm = hashVM();
        require(state2 == hashMachine());
        winner = prover;
        return true;
    }
    function proveUpdateStackPtr() internal returns (bool) {
        require(init == 9 && msg.sender == prover);
        bytes32 state1 = phases[9];
        bytes32 state2 = phases[10];
        require(m.vm == hashVM());
        require(state1 == hashMachine());
        uint hint = (uint(m.op)/2**(8*9))&0xff;
        vm.stack_ptr = handlePointer(hint, vm.stack_ptr);
        m.vm = hashVM();
        require(state2 == hashMachine());
        winner = prover;
        return true;
    }
    function proveUpdateCallPtr() internal returns (bool) {
        require(init == 10 && msg.sender == prover);
        bytes32 state1 = phases[10];
        bytes32 state2 = phases[11];
        require(m.vm == hashVM());
        require(state1 == hashMachine());
        uint hint = (uint(m.op)/2**(8*8))&0xff;
        vm.call_ptr = handlePointer(hint, vm.call_ptr);
        m.vm = hashVM();
        require(state2 == hashMachine());
        winner = prover;
        return true;
    }
    function proveUpdateMemsize() internal returns (bool) {
        require(init == 11 && msg.sender == prover);
        bytes32 state1 = phases[11];
        bytes32 state2 = phases[12];
        require(m.vm == hashVM());
        require(state1 == hashMachine());
        uint hint = (uint(m.op)/2**(8*12))&0xff;
        if (hint == 1) vm.memsize = vm.memsize+m.reg1;
        m.vm = hashVM();
        require(state2 == hashVM());
        winner = prover;
        return true;
    }

    function provePhase(bytes32[] proof, uint loc, bytes32 op) internal {
        if (init == 0) proveFetch(proof);
        if (init == 1) proveInit(op);
        if (init == 2) proveRead1(proof, loc);
        if (init == 3) proveRead2(proof, loc);
        if (init == 4) proveRead3(proof, loc);
        if (init == 5) proveALU();
        if (init == 6) proveWrite1(proof, loc);
        if (init == 7) proveWrite2(proof, loc);
        if (init == 8) proveUpdatePC();
        if (init == 9) proveUpdateStackPtr();
        if (init == 10) proveUpdateCallPtr();
        if (init == 11) proveUpdateMemsize();
    }

    function judge(bytes32[13] res, uint q,
                        bytes32[] proof, uint loc, bytes32 fetched_op,
                        bytes32 vm_, bytes32 op, uint[4] regs,
                        bytes32[8] roots, uint[4] pointers) public returns (uint) {
        setup(res,msg.sender,msg.sender,q);
        setMachine(vm_, op, regs[0], regs[1], regs[2], regs[3]);
        setVM2(roots, pointers);
        provePhase(proof, loc, fetched_op);
        return debug;
    }

}