Fixed new model for consent templates

Fixed new model for consent templates

pragma solidity ^0.4.11;

/*
 * This file contains a set of contracts used to handle consents between a company
 * and a person.
 *
 * Copyright (c) 2017, Tomas Stenlund, All rights reserved
 */

/*
 * This is the contract that handles consent templates for a specific purpouse. It is used
 * when a person or entity wants to get a consent from another user. The consent is then
 * generated from this template.
 *
 * It basically provides a textual description of the consent.
 *
 * Copyright (c) 2017, Tomas Stenlund, All rights reserved
 *
 */
contract ConsentTemplate {

  address private owner;        /* The owner of the template */
  string  private purpouse;     /* What purpouse the template is for */
  uint16  private version;      /* Version of the purpouse, i.e. if the text or title changes for the same purpouse */
  string  private title;        /* The title of the consent */
  string  private text;         /* The text that describes the purpouse of the consent */
  string  private languageCountry;       /* The language and country the consent template that it is valid for
					  *
					  * Standard country-language code according to ISO 639 and ISO 3166-1 alpha 2
					  * separated by a dash, so for swedish in Sweden it is "sv-SE" */

  /* Creates the contract and set the values of the contract. */
  function ConsentTemplate (string _purpouse, uint16 _version, string _title, string _text, string _languageCountry) public
  {
    owner = msg.sender;
    purpouse = _purpouse;
    version = _version;
    title = _title;
    text = _text;
    languageCountry = _languageCountry;
  }

  /* Getters for the contract */
  function getVersion () constant returns (uint16)
  {
    return version;
  }

  function getTitle () constant returns (string)
  {
    return title;
  }

  function getText () constant returns (string)
  {
    return text;
  }

}

/*
 * This is the contract that handles consents for a specific purpouse given by a
 * user (giver) to another user (owner).
 *
 * It basically provides a textual description  that is either accepted or denied by a user.
 *
 * Copyright (c) 2017, Tomas Stenlund, All rights reserved
 *
 */
contract Consent {

    /* Enumeration for the state of the consent */
  enum Status {denied,    /* The giver has denied the consent */
	       accepted,  /* The giver has accepted the consent */
	       requested, /* The company has requested a consent, user has not yet responded */
	       cancelled  /* The company has cancelled the consent because he no longer needs it */
  }

  /* State variables for the contract */
  address private owner;  /* Who issues to consent form */
  address private giver;  /* Who gives the consent, address to the account. */
  Status  private status; /* The status of the consent */
  address private consentTemplate; /* The template this consent is based on */

  /* Event to signal that the status has changed */
  event ConsentStatusChanged (address indexed owner, address indexed giver, address consent, Status status);

  /* This function is executed at initialization and sets the owner and the giver of the consent */
  /* as well as what it contains */
  function Consent(address _giver, address _consentTemplate) public
  {
    giver = _giver;
    owner = msg.sender;
    consentTemplate = _consentTemplate;
    status = Status.requested;
  }

  /* Sets the status of the consent, this can only be done by the giver. Should have a modifier for that. */
  function setStatus(Status _status)
  {
    status = _status;
    ConsentStatusChanged (owner, giver, this, _status);
  }

  /* Cancels a consent, this can only be done by the company who created the consent. Should have a modifier for that. */
  function cancelConsent ()
  {
    status = Status.cancelled;
    ConsentStatusChanged (owner, giver, this, Status.cancelled);
  }

  /* Returns the status of the consent */
  function getStatus() constant returns (Status)
  {
    return status;
  }

  /* Returns the consent template that this consent is based on */
  function getTemplate() constant returns (ConsentTemplate)
  {
    return ConsentTemplate(consentTemplate);
  }

  /* Function to recover the funds on the contract */
  function kill() { if (msg.sender == owner) selfdestruct(owner); }
}

/*
 * This a list of consents that are offered to a specific account.
 *
 * This contains a list of consents that a specific user has been
 * offered. Regardless if it is deined, approved or has no decision.
 *
 * Copyright (c) 2017, Tomas Stenlund, All rights reserved
 *
 */
contract ConsentFile {

  /* The owner of the file */
  address private owner;

  /* The list of all consents */
  address[] private listOfConsents;

  /* Events that are sent when things happen */
  event ConsentFileConsentAdded (address indexed user, address consent);

  /* The constructor of the file. Also attaches it to an owner */
  function ConsentFile (address _owner)
  {
    owner = _owner;
  }

  /* Adds a new consent to the file */
  function addConsent (address _consent)
  {
    listOfConsents.push (_consent);
    ConsentFileConsentAdded (owner,  _consent);
  }

  /* Retrieve a list of all consents in the file */
  function getListOfConsents () constant returns (address[])
  {
    return listOfConsents;
  }

  /* Retrieves the owner */
  function getOwner () constant returns (address)
  {
    return owner;
  }

}

/*
 * This is the consent factory contract that handles consents and version of
 * consents.
 *
 * It basically provides an interface to be able to create consents based on
 * a specific purpouse for a specific user. And always using the latest version
 * and always puts newly generated consents into a persons consent file.
 *
 * Copyright (c) 2017, Tomas Stenlund, All rights reserved
 *
 */
contract ConsentFactory {

  /* Enumeration for errors */
  enum Error {no_such_template /* If no such template exists for the purpouse, language and country */
  }

  /* The owner of this contract */
  address private owner;  /* Who owns this Consent Facotory, this is a company */

  /* List of all templates in this factory */
  address[] listOfAllConsentTemplates;
  address[] listOfActiveConsentTemplates;

  /* Contains a map from purpouse to language and country mapping to index into the list of active consent templates */
  mapping (string => mapping (string => uint)) private consentTemplates;

  /* Events generated when the consent has been created */
  event ConsentFactoryConsentCreatedEvent(address indexed owner, address indexed user, address indexed file, address consent);
  event ConsentFactoryFileCreatedEvent(address indexed owner, address indexed user, address file);
  event ConsentFactoryFailedEvent(address indexed owner, address indexed user, Error error);
  event ConsentFactoryTemplateAdded (address indexed owner, address indexed factory, address template);

  /* Constructor for the consent factory */
  function ConsentFactory() public
  {
    owner = msg.sender;
  }

  /* Adds a consent template to the factory to be used for consent generation. */

  function addConsentTemplate (string _purpouse, uint16 _version, string _title, string _text, string _languageCountry)
  {
    /* Add the template for the specific language, country and purpouse */
    uint ix = consentTemplates[_purpouse][_languageCountry];
    address ct = new ConsentTemplate (_purpouse, _version, _title, _text, _languageCountry);
    if (ix == 0) {
      ix = listOfActiveConsentTemplates.push (ct);
      consentTemplates[_purpouse][_languageCountry] = ix;
    } else {
      listOfActiveConsentTemplates[ix-1] = ct;
    }
    listOfAllConsentTemplates.push(ct);
    ConsentFactoryTemplateAdded (owner, this, ct);
  }

  /* Create a file that holds a users all consents
   *
   * This is the file that holds all consents regardless of their state.
   */
  function createConsentFile (address _user)
  {
    address file = new ConsentFile (_user);
    ConsentFactoryFileCreatedEvent(owner, _user, file);
  }

  /* Create a consent for a specific purpouse of the latest version, language and country.
   *
   * Country and Purpouse must exist otherwise it will fail, if language is not there it will
   * default to countrys default language if it exists otherwise it will fail. It adds
   * the consent to the users file as well.
   */
  function createConsent (address _file, string _purpouse, string _languageCountry)
  {
    ConsentFile cf = ConsentFile (_file);
    ConsentTemplate ct = getTemplate (_purpouse, _languageCountry);
    if (ct != address(0)) {

      /* We got a template so generate the consent and put it into the consent file */
      Consent consent = new Consent (cf.getOwner(), ct);
      ConsentFile(_file).addConsent (consent);
      ConsentFactoryConsentCreatedEvent(owner, cf.getOwner(), _file, consent);

    } else {

    ConsentFactoryFailedEvent(owner, cf.getOwner(), Error.no_such_template);

    }
  }

  /* This function checks to see that there is a consent to be generated */
  function hasConsent (string _purpouse, string _languageCountry) constant returns (bool)
  {
    ConsentTemplate ct = getTemplate (_purpouse, _languageCountry);
    return (ct != address(0));
  }

  /* This function tests wether a consent for a specific purpouse exists or not */
  function getTemplate (string _purpouse, string _languageCountry) constant internal returns (ConsentTemplate)
  {
    /* Get the consents for a specific purpouse and language, country*/
    uint ix = consentTemplates[_purpouse][_languageCountry];
    if (ix == 0) {

      /* Fallback here is to only go for the default language of the country */
      /* So we need to strip the language from the country */
      bytes memory b = bytes (_languageCountry);
      if (b.length==5) {
	if (b[2] == 45) {
    	  bytes memory c = new bytes(2);

	  /* Get the country */
    	  c[0] = b[3];
    	  c[1] = b[4];
    	  ix = consentTemplates[_purpouse][string(c)];
    	}
      }
    }

    /* Return the consent template if we found any */
    if (ix>0)
      return ConsentTemplate(listOfActiveConsentTemplates[ix-1]);
    else
      return ConsentTemplate(address(0));
  }

  /* Function to recover the funds on the contract */
  function kill() { if (msg.sender == owner) selfdestruct(owner); }
}

/*
 * END
 */

pragma solidity ^0.4.11;

/*
 * This file contains a set of contracts used to handle consents between a company
 * and a person.
 *
 * Copyright (c) 2017, Tomas Stenlund, All rights reserved
 */

/*
 * This is the contract that handles consent templates for a specific purpouse. It is used
 * when a person or entity wants to get a consent from another user. The consent is then
 * generated from this template.
 *
 * It basically provides a textual description of the consent.
 *
 * Copyright (c) 2017, Tomas Stenlund, All rights reserved
 *
 */
contract ConsentTemplate {

  address private owner;        /* The owner of the template */
  string  private purpouse;     /* What purpouse the template is for */
  uint16  private version;      /* Version of the purpouse, i.e. if the text or title changes for the same purpouse */
  string  private title;        /* The title of the consent */
  string  private text;         /* The text that describes the purpouse of the consent */
  string  private languageCountry;       /* The language and country the consent template that it is valid for
					  *
					  * Standard country-language code according to ISO 639 and ISO 3166-1 alpha 2
					  * separated by a dash, so for swedish in Sweden it is "sv-SE" */

  /* Creates the contract and set the values of the contract. */
  function ConsentTemplate (string _purpouse, uint16 _version, string _title, string _text, string _languageCountry) public
  {
    owner = msg.sender;
    purpouse = _purpouse;
    version = _version;
    title = _title;
    text = _text;
    languageCountry = _languageCountry;
  }

  /* Getters for the contract */
  function getVersion () constant returns (uint16)
  {
    return version;
  }

  function getTitle () constant returns (string)
  {
    return title;
  }

  function getText () constant returns (string)
  {
    return text;
  }

}

/*
 * This is the contract that handles consents for a specific purpouse given by a
 * user (giver) to another user (owner).
 *
 * It basically provides a textual description  that is either accepted or denied by a user.
 *
 * Copyright (c) 2017, Tomas Stenlund, All rights reserved
 *
 */
contract Consent {

    /* Enumeration for the state of the consent */
  enum Status {denied,    /* The giver has denied the consent */
	       accepted,  /* The giver has accepted the consent */
	       requested, /* The company has requested a consent, user has not yet responded */
	       cancelled  /* The company has cancelled the consent because he no longer needs it */
  }

  /* State variables for the contract */
  address private owner;  /* Who issues to consent form */
  address private giver;  /* Who gives the consent, address to the account. */
  Status  private status; /* The status of the consent */
  address private consentTemplate; /* The template this consent is based on */

  /* Event to signal that the status has changed */
  event ConsentStatusChanged (address indexed owner, address indexed giver, address consent, Status status);

  /* This function is executed at initialization and sets the owner and the giver of the consent */
  /* as well as what it contains */
  function Consent(address _giver, address _consentTemplate) public
  {
    giver = _giver;
    owner = msg.sender;
    consentTemplate = _consentTemplate;
    status = Status.requested;
  }

  /* Sets the status of the consent, this can only be done by the giver. Should have a modifier for that. */
  function setStatus(Status _status)
  {
    status = _status;
    ConsentStatusChanged (owner, giver, this, _status);
  }

  /* Cancels a consent, this can only be done by the company who created the consent. Should have a modifier for that. */
  function cancelConsent ()
  {
    status = Status.cancelled;
    ConsentStatusChanged (owner, giver, this, Status.cancelled);
  }

  /* Returns the status of the consent */
  function getStatus() constant returns (Status)
  {
    return status;
  }

  /* Returns the consent template that this consent is based on */
  function getTemplate() constant returns (ConsentTemplate)
  {
    return ConsentTemplate(consentTemplate);
  }

  /* Function to recover the funds on the contract */
  function kill() { if (msg.sender == owner) selfdestruct(owner); }
}

/*
 * This a list of consents that are offered to a specific account.
 *
 * This contains a list of consents that a specific user has been
 * offered. Regardless if it is deined, approved or has no decision.
 *
 * Copyright (c) 2017, Tomas Stenlund, All rights reserved
 *
 */
contract ConsentFile {

  /* The owner of the file */
  address private owner;

  /* The list of all consents */
  address[] private listOfConsents;

  /* Events that are sent when things happen */
  event ConsentFileConsentAdded (address indexed user, address consent);

  /* The constructor of the file. Also attaches it to an owner */
  function ConsentFile (address _owner)
  {
    owner = _owner;
  }

  /* Adds a new consent to the file */
  function addConsent (address _consent)
  {
    listOfConsents.push (_consent);
    ConsentFileConsentAdded (owner,  _consent);
  }

  /* Retrieve a list of all consents in the file */
  function getListOfConsents () constant returns (address[])
  {
    return listOfConsents;
  }

  /* Retrieves the owner */
  function getOwner () constant returns (address)
  {
    return owner;
  }

}

/*
 * This is the consent factory contract that handles consents and version of
 * consents.
 *
 * It basically provides an interface to be able to create consents based on
 * a specific purpouse for a specific user. And always using the latest version
 * and always puts newly generated consents into a persons consent file.
 *
 * Copyright (c) 2017, Tomas Stenlund, All rights reserved
 *
 */
contract ConsentFactory {

  /* Enumeration for errors */
  enum Error {no_such_template /* If no such template exists for the purpouse, language and country */
  }

  /* The owner of this contract */
  address private owner;  /* Who owns this Consent Facotory, this is a company */

  /* Contains a map from language and country according to ISO 639 and ISO 3166-1 alpha 2 separated by a dash to
   * consent template. For example swedish in Sweden is written sv-SE */
  struct ConsentLanguageCountry {
    bool exist;                                                 /* If there exists any consents, true if yes, false otherwsie */
    mapping (string => ConsentTemplate[]) consentTemplates;     /* An array of templates keyed to language and country */
    string[] languagesAndCountries;                               /* An array containing all languages and countries in the mapping */
  }

  /* A dynamic array that contains all purpouses that this factory handles */
  string[] private purpouses;

  /* Contains a map from purpouse to language and country mapping */
  mapping (string => ConsentLanguageCountry) private consentPurpouses;

  /* Events generated when the consent has been created */
  event ConsentFactoryConsentCreatedEvent(address indexed owner, address indexed user, address indexed file, address consent);
  event ConsentFactoryFileCreatedEvent(address indexed owner, address indexed user, address file);
  event ConsentFactoryFailedEvent(address indexed owner, address indexed user, Error error);
  event ConsentFactoryTemplateAdded (address indexed owner, address indexed factory, address template);

  /* Constructor for the consent factory */
  function ConsentFactory() public
  {
    owner = msg.sender;
  }

  /* Adds a consent template to the factory to be used for consent generation. */
  function addConsentTemplate (string _purpouse, uint16 _version, string _title, string _text, string _languageCountry)
  {
    /* Add the template last, i.e. the newest template, for the specific language, country and purpouse */
    if (!consentPurpouses[_purpouse].exist)
      purpouses.push (_purpouse);
    consentPurpouses[_purpouse].exist = true;
    ConsentTemplate consentTemplate = new ConsentTemplate (_purpouse, _version, _title, _text, _languageCountry);
    if (consentPurpouses[_purpouse].consentTemplates[_languageCountry].length==0)
      consentPurpouses[_purpouse].languagesAndCountries.push (_languageCountry);
    consentPurpouses[_purpouse].consentTemplates[_languageCountry].push (consentTemplate);
    ConsentFactoryTemplateAdded (owner, this, consentTemplate);
  }

  function getNumberOfPurpouses() constant returns (uint length)
  {
    return purpouses.length;
  }

  function getNumberOfLanguagesAndCountries(uint index) constant returns (uint length)
  {
    if (consentPurpouses[purpouses[index]].exist) {
      return  consentPurpouses[purpouses[index]].languagesAndCountries.length;
    } else {
      return 0;
    }
  }

  function getConsentTemplates(uint purpouseIndex, uint languageAndCountryIndex) constant returns (ConsentTemplate[])
  {
    ConsentTemplate[] memory ctl;
    if (consentPurpouses[purpouses[purpouseIndex]].exist)
      ctl =  consentPurpouses[purpouses[purpouseIndex]].consentTemplates[consentPurpouses[purpouses[purpouseIndex]].languagesAndCountries[languageAndCountryIndex]];
    return ctl;
  }

  /* Create a file that holds a users all consents
   *
   * This is the file that holds all consents regardless of their state.
   */
  function createConsentFile (address _user)
  {
    address file = new ConsentFile (_user);
    ConsentFactoryFileCreatedEvent(owner, _user, file);
  }

  /* Create a consent for a specific purpouse of the latest version, language and country.
   *
   * Country and Purpouse must exist otherwise it will fail, if language is not there it will
   * default to countrys default language if it exists otherwise it will fail. It adds
   * the consent to the users file as well.
   */
  function createConsent (address _file, string _purpouse, string _languageCountry)
  {
    ConsentFile cf = ConsentFile (_file);
    ConsentTemplate ct = getTemplate (_purpouse, _languageCountry);
    if (ct != address(0)) {

      /* We got a template so generate the consent and put it into the consent file */
      Consent consent = new Consent (cf.getOwner(), ct);
      ConsentFile(_file).addConsent (consent);
      ConsentFactoryConsentCreatedEvent(owner, cf.getOwner(), _file, consent);

    } else {

      ConsentFactoryFailedEvent(owner, cf.getOwner(), Error.no_such_template);

    }
  }

  /* This function checks to see that there is a consent to be generated */
  function hasConsent (string _purpouse, string _languageCountry) constant returns (bool)
  {
    ConsentTemplate ct = getTemplate (_purpouse, _languageCountry);
    return (ct != address(0));
  }

  /* This function tests wether a consent for a specific purpouse exists or not */
  function getTemplate (string _purpouse, string _languageCountry) constant internal returns (ConsentTemplate)
  {
    ConsentTemplate ct; /* Holds the found template */
    uint256 len; /* Holds the length of the template array so we can take the last one */

    /* Get the consents for a specific purpouse */
    ConsentLanguageCountry clc = consentPurpouses[_purpouse];
    if (clc.exist) {

      /* Get the specific consent for the language and country */
      len = clc.consentTemplates[_languageCountry].length;
      if (len == 0) {

	/* Fallback here is to only go for the default language of the country */
	/* So we need to strip the language from the country */
	bytes memory b = bytes (_languageCountry);
	if (b.length==5) {
	  if (b[2] == 45) {
	    bytes memory c = new bytes(2);

	    /* Get the country */
	    c[0] = b[3];
	    c[1] = b[4];
	    len = clc.consentTemplates[string(c)].length;

	    /* Get the last consent */
	    if (len > 0)
	      ct = clc.consentTemplates[string(c)][len-1];
	  }
	}
      } else {
	ct = clc.consentTemplates[_languageCountry][len-1];
      }
    }

    return ct;
  }

  /* Function to recover the funds on the contract */
  function kill() { if (msg.sender == owner) selfdestruct(owner); }
}

/*
 * END
 */


added description to data structure

added description to data structure

/*
    This is a very much work in progress draft of the data structure,
    mostly used for testing purposes so far.
*/

/// @dev Models a uint -> uint mapping where it is possible to iterate over all keys.
library IterableMapping
{
  struct itmap
  {
    mapping(address => IndexValue) data;
    KeyFlag[] keys;
    uint size;
  }
  struct IndexValue { uint keyIndex; string value; }
  struct KeyFlag { address key; bool deleted; }
  function insert(itmap storage self, address key, string value) returns (bool replaced)
  {
    uint keyIndex = self.data[key].keyIndex;
    self.data[key].value = value;
    if (keyIndex > 0)
      return true;
    else
    {
      keyIndex = self.keys.length++;
      self.data[key].keyIndex = keyIndex + 1;
      self.keys[keyIndex].key = key;
      self.size++;
      return false;
    }
  }
  function remove(itmap storage self, address key) returns (bool success)
  {
    uint keyIndex = self.data[key].keyIndex;
    if (keyIndex == 0)
      return false;
    delete self.data[key];
    self.keys[keyIndex - 1].deleted = true;
    self.size --;
  }
  function contains(itmap storage self, address key) returns (bool)
  {
    return self.data[key].keyIndex > 0;
  }
  function atIndex(itmap storage self, address key) returns (uint index)
  {
      return self.data[key].keyIndex;
  }
  function iterate_start(itmap storage self) returns (uint keyIndex)
  {
    return iterate_next(self, uint(-1));
  }
  function iterate_valid(itmap storage self, uint keyIndex) returns (bool)
  {
    return keyIndex < self.keys.length;
  }
  function iterate_next(itmap storage self, uint keyIndex) returns (uint r_keyIndex)
  {
    keyIndex++;
    while (keyIndex < self.keys.length && self.keys[keyIndex].deleted)
      keyIndex++;
    return keyIndex;
  }
  function iterate_get(itmap storage self, uint keyIndex) returns (address key, string value)
  {
    key = self.keys[keyIndex].key;
    value = self.data[key].value;
  }
}

// How to use it:
contract User
{
  // Just a struct holding our data.
  IterableMapping.itmap data;
  // Insert something
  function insert(address k, string v) returns (uint size)
  {
    // Actually calls itmap_impl.insert, auto-supplying the first parameter for us.
    IterableMapping.insert(data, k, v);
    // We can still access members of the struct - but we should take care not to mess with them.
    return data.size;
  }
  // Computes the sum of all stored data.
  /*
  function sum() returns (uint s)
  {
    for (var i = IterableMapping.iterate_start(data); IterableMapping.iterate_valid(data, i); i = IterableMapping.iterate_next(data, i))
    {
        var (key, value) = IterableMapping.iterate_get(data, i);
        s += value;
    }
  }*/

  function get(address k) returns (address key, string value) {
      uint index = IterableMapping.atIndex(data, k);
      IterableMapping.iterate_get(data, index);
  }
}


Added upper limit check

Added upper limit check

pragma solidity ^0.4.4;

// Vending machine to sell X number of tokens for approx Y number of ETH.
// As purchases are made, the owned ERC20 tokens will be sent out to purchaser.
// Purchases will be priced based on the purchase "Generation" the vending machine is in.
// As more purchases are made the Generation gets incremented.
// Each generation will sell the tokens for twice as much as the previous generation.
contract VendingMachine is Ownable {

    // The contract where the tokens are held by this contract until they are sold.
    ERC20 public token;

    // Total Amount of tokens to sell to purchasers
    uint public amountToSell = 21000000;

    // Total amount of tokens that have been sold so far.  Starts at 0.
    uint public amountSold = 0;

    // Initial price that each ETH sent in will get back in tokens.
    uint public initialPricePerEth = 10000;

    // Amount of tokens to sell per generation
    uint public tokensPerGeneration = 120000;

    // Constructor initalized with the token contract that it will be selling.
    function VendingMachine(ERC20 tokenContract){
        token = tokenContract;
    }

    // This function will calculate how many tokens they will get with the amount of ETH they are sending in
    function calculateSaleAmount(uint amountSoldStart, uint ethAmount) uint{
        // Keep track of the amount to sell
        uint amountToSell = 0;

        // First get the amount of tokens sold from the beginning of this generation and the amount left.
        uint currentGeneration = amountSoldStart / tokensPerGeneration;
        uint amountLeftInCurrentGeneration = tokensPerGeneration - (amountSoldStart % tokensPerGeneration);

        // Calculate the price per ETH of the current generation
        uint salePrice = initialPricePerEth;
        for(uint i = 0 ; i < currentGeneration; i ++){
            salePrice = salePrice / 2;
        }

        // Calculate how mant tokens they are trying to buy
        uint amountToSell = salePrice * ethAmount;

        // If they are buying past the current generation, then figure out how much they purchase in the next generation.
        if (amountToSell > amountLeftInCurrentGeneration){
            // Calculate how much ETH would be used from the current generation
            uint ethFromCurrentGen = salePrice * amountLeftInCurrentGeneration;

            // Recursively call this function with the starting amount being the next gen and remaining ETH
            return (ethFromCurrentGen * salePrice) + amountLeftInCurrentGeneration(currentGeneration * tokensPerGeneration, ethAmount - ethFromCurrentGen) ;
        }

        // Return the amount to sell
        return amountToSell;
    }

    // When this function is called, it will send the originator X tokens.
    // X is determined by the price calculated based on the current generation of sales.
    function PurchaseTokens payable(){

        // Figure out how many tokens they are buying
        uint amountPurchased = calculateSaleAmount(amountSold, msg.amount);

        // Verify the buyer isn't going over the limit of how many this contract is selling
        if( amountSold + amountPurchased > amountToSell ){
            throw;
        }

        // Updatete the total amount sold
        amountSold += amountPurchased;

        // Send the tokens to the buyers's account
        if(!token.transfer(msg.sender, amountPurchased)){
            throw;
        }
    }

    // This function allows the owner to withdraw any ETH that was sent in via purchases.
    function WithdrawEth(uint amount) onlyOwner {
        // Send out what they are requesting to withdraw and trigger the send
        msg.sender.send(amount);
    }
}

pragma solidity ^0.4.4;

// Vending machine to sell X number of tokens for approx Y number of ETH.
// As purchases are made, the owned ERC20 tokens will be sent out to purchaser.
// Purchases will be priced based on the purchase "Generation" the vending machine is in.
// As more purchases are made the Generation gets incremented.
// Each generation will sell the tokens for twice as much as the previous generation.
contract VendingMachine is Ownable {

    // The contract where the tokens are held by this contract until they are sold.
    ERC20 public token;

    // Total Amount of tokens to sell to purchasers
    uint public amountToSell = 21000000;

    // Total amount of tokens that have been sold so far.  Starts at 0.
    uint public amountSold = 0;

    // Initial price that each ETH sent in will get back in tokens.
    uint public initialPricePerEth = 10000;

    // Amount of tokens to sell per generation
    uint public tokensPerGeneration = 120000;

    // Constructor initalized with the token contract that it will be selling.
    function VendingMachine(ERC20 tokenContract){
        token = tokenContract;
    }

    // This function will calculate how many tokens they will get with the amount of ETH they are sending in
    function calculateSaleAmount(uint amountSoldStart, uint ethAmount) uint{
        // Keep track of the amount to sell
        uint amountToSell = 0;

        // First get the amount of tokens sold from the beginning of this generation and the amount left.
        uint currentGeneration = amountSoldStart / tokensPerGeneration;
        uint amountLeftInCurrentGeneration = tokensPerGeneration - (amountSoldStart % tokensPerGeneration);

        // Calculate the price per ETH of the current generation
        uint salePrice = initialPricePerEth;
        for(uint i = 0 ; i < currentGeneration; i ++){
            salePrice = salePrice / 2;
        }

        // Calculate how mant tokens they are trying to buy
        uint amountToSell = salePrice * ethAmount;

        // If they are buying past the current generation, then figure out how much they purchase in the next generation.
        if (amountToSell > amountLeftInCurrentGeneration){
            // Calculate how much ETH would be used from the current generation
            uint ethFromCurrentGen = salePrice * amountLeftInCurrentGeneration;

            // Recursively call this function with the starting amount being the next gen and remaining ETH
            return (ethFromCurrentGen * salePrice) + amountLeftInCurrentGeneration(currentGeneration * tokensPerGeneration, ethAmount - ethFromCurrentGen) ;
        }

        // Return the amount to sell
        return amountToSell;
    }

    // When this function is called, it will send the originator X tokens.
    // X is determined by the price calculated based on the current generation of sales.
    function PurchaseTokens payable(){

        // Figure out how many tokens they are buying
        uint amountPurchased = calculateSaleAmount(amountSold, msg.amount);

        // Updatete the total amount sold
        amountSold += amountPurchased;

        // Send the tokens to the buyers's account
        if(!token.transfer(msg.sender, amountPurchased)){
            throw;
        }
    }

    // This function allows the owner to withdraw any ETH that was sent in via purchases.
    function WithdrawEth(uint amount) onlyOwner {
        // Send out what they are requesting to withdraw and trigger the send
        msg.sender.send(amount);
    }
}


Test common case first (#2023)

Test common case first (#2023)

pragma solidity ^0.5.5;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        // solhint-disable-next-line no-inline-assembly
        assembly { codehash := extcodehash(account) }
        return (codehash != accountHash && codehash != 0x0);
    }

    /**
     * @dev Converts an `address` into `address payable`. Note that this is
     * simply a type cast: the actual underlying value is not changed.
     *
     * _Available since v2.4.0._
     */
    function toPayable(address account) internal pure returns (address payable) {
        return address(uint160(account));
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     *
     * _Available since v2.4.0._
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-call-value
        (bool success, ) = recipient.call.value(amount)("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }
}

pragma solidity ^0.5.5;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        // solhint-disable-next-line no-inline-assembly
        assembly { codehash := extcodehash(account) }
        return (codehash != 0x0 && codehash != accountHash);
    }

    /**
     * @dev Converts an `address` into `address payable`. Note that this is
     * simply a type cast: the actual underlying value is not changed.
     *
     * _Available since v2.4.0._
     */
    function toPayable(address account) internal pure returns (address payable) {
        return address(uint160(account));
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     *
     * _Available since v2.4.0._
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-call-value
        (bool success, ) = recipient.call.value(amount)("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }
}


Add basic contract.

Add basic contract.

pragma solidity ^0.4.2;

contract GreenChain {
	struct GreenBlock {
		uint uniqueID;
    	address owner;
    	string name;
    	uint quantity;
		mapping (string => double) lca;
	}

  	struct GreenBlockBlueprint {
		mapping (uint => GreenBlock) parts;
  	}

  	uint blkid;
  	mapping (uint => GreenBlock) inventory;

	function GreenChain() {
		blkid = 0;
	}

  	function addBlock(string name, uint quantity, GreenBlockBlueprint blk) {
  		blkid = blkid++;
  		inventory[blkid] = GreenBlock(blkid, msg.sender, name, quantity, blk[0].lca);
  	}

  	function fetchAllBlocks() constant returns (mapping (uint => GreenBlock)) {
    	return inventory;
  	}

  	function fetchBlocks(address owner) constant returns (mapping (uint => GreenBlock)) {
    	return inventory;
  	}
}

error: pathspec 'contracts/GreenChain.sol' did not match any file(s) known to git


Ethereum tutorial

Ethereum tutorial


Improve handling and docs for ERC4626.decimals (#3733)

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/extensions/ERC4626.sol)

pragma solidity ^0.8.0;

import "../ERC20.sol";
import "../utils/SafeERC20.sol";
import "../../../interfaces/IERC4626.sol";
import "../../../utils/math/Math.sol";

/**
 * @dev Implementation of the ERC4626 "Tokenized Vault Standard" as defined in
 * https://eips.ethereum.org/EIPS/eip-4626[EIP-4626].
 *
 * This extension allows the minting and burning of "shares" (represented using the ERC20 inheritance) in exchange for
 * underlying "assets" through standardized {deposit}, {mint}, {redeem} and {burn} workflows. This contract extends
 * the ERC20 standard. Any additional extensions included along it would affect the "shares" token represented by this
 * contract and not the "assets" token which is an independent contract.
 *
 * CAUTION: Deposits and withdrawals may incur unexpected slippage. Users should verify that the amount received of
 * shares or assets is as expected. EOAs should operate through a wrapper that performs these checks such as
 * https://github.com/fei-protocol/ERC4626#erc4626router-and-base[ERC4626Router].
 *
 * _Available since v4.7._
 */
abstract contract ERC4626 is ERC20, IERC4626 {
    using Math for uint256;

    IERC20 private immutable _asset;
    uint8 private immutable _decimals;

    /**
     * @dev Set the underlying asset contract. This must be an ERC20-compatible contract (ERC20 or ERC777).
     */
    constructor(IERC20 asset_) {
        (bool success, uint8 assetDecimals) = _tryGetAssetDecimals(asset_);
        _decimals = success ? assetDecimals : super.decimals();
        _asset = asset_;
    }

    /**
     * @dev Attempts to fetch the asset decimals. A return value of false indicates that the attempt failed in some way.
     */
    function _tryGetAssetDecimals(IERC20 asset_) private returns (bool, uint8) {
        (bool success, bytes memory encodedDecimals) = address(asset_).call(
            abi.encodeWithSelector(IERC20Metadata.decimals.selector)
        );
        if (success && encodedDecimals.length >= 32) {
            uint256 returnedDecimals = abi.decode(encodedDecimals, (uint256));
            if (returnedDecimals <= type(uint8).max) {
                return (true, uint8(returnedDecimals));
            }
        }
        return (false, 0);
    }

    /**
     * @dev Decimals are read from the underlying asset in the constructor and cached. If this fails (e.g., the asset
     * has not been created yet), the cached value is set to a default obtained by `super.decimals()` (which depends on
     * inheritance but is most likely 18). Override this function in order to set a guaranteed hardcoded value.
     * See {IERC20Metadata-decimals}.
     */
    function decimals() public view virtual override(IERC20Metadata, ERC20) returns (uint8) {
        return _decimals;
    }

    /** @dev See {IERC4626-asset}. */
    function asset() public view virtual override returns (address) {
        return address(_asset);
    }

    /** @dev See {IERC4626-totalAssets}. */
    function totalAssets() public view virtual override returns (uint256) {
        return _asset.balanceOf(address(this));
    }

    /** @dev See {IERC4626-convertToShares}. */
    function convertToShares(uint256 assets) public view virtual override returns (uint256 shares) {
        return _convertToShares(assets, Math.Rounding.Down);
    }

    /** @dev See {IERC4626-convertToAssets}. */
    function convertToAssets(uint256 shares) public view virtual override returns (uint256 assets) {
        return _convertToAssets(shares, Math.Rounding.Down);
    }

    /** @dev See {IERC4626-maxDeposit}. */
    function maxDeposit(address) public view virtual override returns (uint256) {
        return _isVaultCollateralized() ? type(uint256).max : 0;
    }

    /** @dev See {IERC4626-maxMint}. */
    function maxMint(address) public view virtual override returns (uint256) {
        return type(uint256).max;
    }

    /** @dev See {IERC4626-maxWithdraw}. */
    function maxWithdraw(address owner) public view virtual override returns (uint256) {
        return _convertToAssets(balanceOf(owner), Math.Rounding.Down);
    }

    /** @dev See {IERC4626-maxRedeem}. */
    function maxRedeem(address owner) public view virtual override returns (uint256) {
        return balanceOf(owner);
    }

    /** @dev See {IERC4626-previewDeposit}. */
    function previewDeposit(uint256 assets) public view virtual override returns (uint256) {
        return _convertToShares(assets, Math.Rounding.Down);
    }

    /** @dev See {IERC4626-previewMint}. */
    function previewMint(uint256 shares) public view virtual override returns (uint256) {
        return _convertToAssets(shares, Math.Rounding.Up);
    }

    /** @dev See {IERC4626-previewWithdraw}. */
    function previewWithdraw(uint256 assets) public view virtual override returns (uint256) {
        return _convertToShares(assets, Math.Rounding.Up);
    }

    /** @dev See {IERC4626-previewRedeem}. */
    function previewRedeem(uint256 shares) public view virtual override returns (uint256) {
        return _convertToAssets(shares, Math.Rounding.Down);
    }

    /** @dev See {IERC4626-deposit}. */
    function deposit(uint256 assets, address receiver) public virtual override returns (uint256) {
        require(assets <= maxDeposit(receiver), "ERC4626: deposit more than max");

        uint256 shares = previewDeposit(assets);
        _deposit(_msgSender(), receiver, assets, shares);

        return shares;
    }

    /** @dev See {IERC4626-mint}. */
    function mint(uint256 shares, address receiver) public virtual override returns (uint256) {
        require(shares <= maxMint(receiver), "ERC4626: mint more than max");

        uint256 assets = previewMint(shares);
        _deposit(_msgSender(), receiver, assets, shares);

        return assets;
    }

    /** @dev See {IERC4626-withdraw}. */
    function withdraw(
        uint256 assets,
        address receiver,
        address owner
    ) public virtual override returns (uint256) {
        require(assets <= maxWithdraw(owner), "ERC4626: withdraw more than max");

        uint256 shares = previewWithdraw(assets);
        _withdraw(_msgSender(), receiver, owner, assets, shares);

        return shares;
    }

    /** @dev See {IERC4626-redeem}. */
    function redeem(
        uint256 shares,
        address receiver,
        address owner
    ) public virtual override returns (uint256) {
        require(shares <= maxRedeem(owner), "ERC4626: redeem more than max");

        uint256 assets = previewRedeem(shares);
        _withdraw(_msgSender(), receiver, owner, assets, shares);

        return assets;
    }

    /**
     * @dev Internal conversion function (from assets to shares) with support for rounding direction.
     *
     * Will revert if assets > 0, totalSupply > 0 and totalAssets = 0. That corresponds to a case where any asset
     * would represent an infinite amount of shares.
     */
    function _convertToShares(uint256 assets, Math.Rounding rounding) internal view virtual returns (uint256 shares) {
        uint256 supply = totalSupply();
        return
            (assets == 0 || supply == 0)
                ? _initialConvertToShares(assets, rounding)
                : assets.mulDiv(supply, totalAssets(), rounding);
    }

    /**
     * @dev Internal conversion function (from assets to shares) to apply when the vault is empty.
     *
     * NOTE: Make sure to keep this function consistent with {_initialConvertToAssets} when overriding it.
     */
    function _initialConvertToShares(
        uint256 assets,
        Math.Rounding /*rounding*/
    ) internal view virtual returns (uint256 shares) {
        return assets;
    }

    /**
     * @dev Internal conversion function (from shares to assets) with support for rounding direction.
     */
    function _convertToAssets(uint256 shares, Math.Rounding rounding) internal view virtual returns (uint256 assets) {
        uint256 supply = totalSupply();
        return
            (supply == 0) ? _initialConvertToAssets(shares, rounding) : shares.mulDiv(totalAssets(), supply, rounding);
    }

    /**
     * @dev Internal conversion function (from shares to assets) to apply when the vault is empty.
     *
     * NOTE: Make sure to keep this function consistent with {_initialConvertToShares} when overriding it.
     */
    function _initialConvertToAssets(
        uint256 shares,
        Math.Rounding /*rounding*/
    ) internal view virtual returns (uint256 assets) {
        return shares;
    }

    /**
     * @dev Deposit/mint common workflow.
     */
    function _deposit(
        address caller,
        address receiver,
        uint256 assets,
        uint256 shares
    ) internal virtual {
        // If _asset is ERC777, `transferFrom` can trigger a reenterancy BEFORE the transfer happens through the
        // `tokensToSend` hook. On the other hand, the `tokenReceived` hook, that is triggered after the transfer,
        // calls the vault, which is assumed not malicious.
        //
        // Conclusion: we need to do the transfer before we mint so that any reentrancy would happen before the
        // assets are transferred and before the shares are minted, which is a valid state.
        // slither-disable-next-line reentrancy-no-eth
        SafeERC20.safeTransferFrom(_asset, caller, address(this), assets);
        _mint(receiver, shares);

        emit Deposit(caller, receiver, assets, shares);
    }

    /**
     * @dev Withdraw/redeem common workflow.
     */
    function _withdraw(
        address caller,
        address receiver,
        address owner,
        uint256 assets,
        uint256 shares
    ) internal virtual {
        if (caller != owner) {
            _spendAllowance(owner, caller, shares);
        }

        // If _asset is ERC777, `transfer` can trigger a reentrancy AFTER the transfer happens through the
        // `tokensReceived` hook. On the other hand, the `tokensToSend` hook, that is triggered before the transfer,
        // calls the vault, which is assumed not malicious.
        //
        // Conclusion: we need to do the transfer after the burn so that any reentrancy would happen after the
        // shares are burned and after the assets are transferred, which is a valid state.
        _burn(owner, shares);
        SafeERC20.safeTransfer(_asset, receiver, assets);

        emit Withdraw(caller, receiver, owner, assets, shares);
    }

    function _isVaultCollateralized() private view returns (bool) {
        return totalAssets() > 0 || totalSupply() == 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/extensions/ERC4626.sol)

pragma solidity ^0.8.0;

import "../ERC20.sol";
import "../utils/SafeERC20.sol";
import "../../../interfaces/IERC4626.sol";
import "../../../utils/math/Math.sol";

/**
 * @dev Implementation of the ERC4626 "Tokenized Vault Standard" as defined in
 * https://eips.ethereum.org/EIPS/eip-4626[EIP-4626].
 *
 * This extension allows the minting and burning of "shares" (represented using the ERC20 inheritance) in exchange for
 * underlying "assets" through standardized {deposit}, {mint}, {redeem} and {burn} workflows. This contract extends
 * the ERC20 standard. Any additional extensions included along it would affect the "shares" token represented by this
 * contract and not the "assets" token which is an independent contract.
 *
 * CAUTION: Deposits and withdrawals may incur unexpected slippage. Users should verify that the amount received of
 * shares or assets is as expected. EOAs should operate through a wrapper that performs these checks such as
 * https://github.com/fei-protocol/ERC4626#erc4626router-and-base[ERC4626Router].
 *
 * _Available since v4.7._
 */
abstract contract ERC4626 is ERC20, IERC4626 {
    using Math for uint256;

    IERC20 private immutable _asset;
    uint8 private immutable _decimals;

    /**
     * @dev Set the underlying asset contract. This must be an ERC20-compatible contract (ERC20 or ERC777).
     */
    constructor(IERC20 asset_) {
        uint8 decimals_;
        try IERC20Metadata(address(asset_)).decimals() returns (uint8 value) {
            decimals_ = value;
        } catch {
            decimals_ = super.decimals();
        }

        _asset = asset_;
        _decimals = decimals_;
    }

    /** @dev See {IERC20Metadata-decimals}. */
    function decimals() public view virtual override(IERC20Metadata, ERC20) returns (uint8) {
        return _decimals;
    }

    /** @dev See {IERC4626-asset}. */
    function asset() public view virtual override returns (address) {
        return address(_asset);
    }

    /** @dev See {IERC4626-totalAssets}. */
    function totalAssets() public view virtual override returns (uint256) {
        return _asset.balanceOf(address(this));
    }

    /** @dev See {IERC4626-convertToShares}. */
    function convertToShares(uint256 assets) public view virtual override returns (uint256 shares) {
        return _convertToShares(assets, Math.Rounding.Down);
    }

    /** @dev See {IERC4626-convertToAssets}. */
    function convertToAssets(uint256 shares) public view virtual override returns (uint256 assets) {
        return _convertToAssets(shares, Math.Rounding.Down);
    }

    /** @dev See {IERC4626-maxDeposit}. */
    function maxDeposit(address) public view virtual override returns (uint256) {
        return _isVaultCollateralized() ? type(uint256).max : 0;
    }

    /** @dev See {IERC4626-maxMint}. */
    function maxMint(address) public view virtual override returns (uint256) {
        return type(uint256).max;
    }

    /** @dev See {IERC4626-maxWithdraw}. */
    function maxWithdraw(address owner) public view virtual override returns (uint256) {
        return _convertToAssets(balanceOf(owner), Math.Rounding.Down);
    }

    /** @dev See {IERC4626-maxRedeem}. */
    function maxRedeem(address owner) public view virtual override returns (uint256) {
        return balanceOf(owner);
    }

    /** @dev See {IERC4626-previewDeposit}. */
    function previewDeposit(uint256 assets) public view virtual override returns (uint256) {
        return _convertToShares(assets, Math.Rounding.Down);
    }

    /** @dev See {IERC4626-previewMint}. */
    function previewMint(uint256 shares) public view virtual override returns (uint256) {
        return _convertToAssets(shares, Math.Rounding.Up);
    }

    /** @dev See {IERC4626-previewWithdraw}. */
    function previewWithdraw(uint256 assets) public view virtual override returns (uint256) {
        return _convertToShares(assets, Math.Rounding.Up);
    }

    /** @dev See {IERC4626-previewRedeem}. */
    function previewRedeem(uint256 shares) public view virtual override returns (uint256) {
        return _convertToAssets(shares, Math.Rounding.Down);
    }

    /** @dev See {IERC4626-deposit}. */
    function deposit(uint256 assets, address receiver) public virtual override returns (uint256) {
        require(assets <= maxDeposit(receiver), "ERC4626: deposit more than max");

        uint256 shares = previewDeposit(assets);
        _deposit(_msgSender(), receiver, assets, shares);

        return shares;
    }

    /** @dev See {IERC4626-mint}. */
    function mint(uint256 shares, address receiver) public virtual override returns (uint256) {
        require(shares <= maxMint(receiver), "ERC4626: mint more than max");

        uint256 assets = previewMint(shares);
        _deposit(_msgSender(), receiver, assets, shares);

        return assets;
    }

    /** @dev See {IERC4626-withdraw}. */
    function withdraw(
        uint256 assets,
        address receiver,
        address owner
    ) public virtual override returns (uint256) {
        require(assets <= maxWithdraw(owner), "ERC4626: withdraw more than max");

        uint256 shares = previewWithdraw(assets);
        _withdraw(_msgSender(), receiver, owner, assets, shares);

        return shares;
    }

    /** @dev See {IERC4626-redeem}. */
    function redeem(
        uint256 shares,
        address receiver,
        address owner
    ) public virtual override returns (uint256) {
        require(shares <= maxRedeem(owner), "ERC4626: redeem more than max");

        uint256 assets = previewRedeem(shares);
        _withdraw(_msgSender(), receiver, owner, assets, shares);

        return assets;
    }

    /**
     * @dev Internal conversion function (from assets to shares) with support for rounding direction.
     *
     * Will revert if assets > 0, totalSupply > 0 and totalAssets = 0. That corresponds to a case where any asset
     * would represent an infinite amount of shares.
     */
    function _convertToShares(uint256 assets, Math.Rounding rounding) internal view virtual returns (uint256 shares) {
        uint256 supply = totalSupply();
        return
            (assets == 0 || supply == 0)
                ? _initialConvertToShares(assets, rounding)
                : assets.mulDiv(supply, totalAssets(), rounding);
    }

    /**
     * @dev Internal conversion function (from assets to shares) to apply when the vault is empty.
     *
     * NOTE: Make sure to keep this function consistent with {_initialConvertToAssets} when overriding it.
     */
    function _initialConvertToShares(
        uint256 assets,
        Math.Rounding /*rounding*/
    ) internal view virtual returns (uint256 shares) {
        return assets;
    }

    /**
     * @dev Internal conversion function (from shares to assets) with support for rounding direction.
     */
    function _convertToAssets(uint256 shares, Math.Rounding rounding) internal view virtual returns (uint256 assets) {
        uint256 supply = totalSupply();
        return
            (supply == 0) ? _initialConvertToAssets(shares, rounding) : shares.mulDiv(totalAssets(), supply, rounding);
    }

    /**
     * @dev Internal conversion function (from shares to assets) to apply when the vault is empty.
     *
     * NOTE: Make sure to keep this function consistent with {_initialConvertToShares} when overriding it.
     */
    function _initialConvertToAssets(
        uint256 shares,
        Math.Rounding /*rounding*/
    ) internal view virtual returns (uint256 assets) {
        return shares;
    }

    /**
     * @dev Deposit/mint common workflow.
     */
    function _deposit(
        address caller,
        address receiver,
        uint256 assets,
        uint256 shares
    ) internal virtual {
        // If _asset is ERC777, `transferFrom` can trigger a reenterancy BEFORE the transfer happens through the
        // `tokensToSend` hook. On the other hand, the `tokenReceived` hook, that is triggered after the transfer,
        // calls the vault, which is assumed not malicious.
        //
        // Conclusion: we need to do the transfer before we mint so that any reentrancy would happen before the
        // assets are transferred and before the shares are minted, which is a valid state.
        // slither-disable-next-line reentrancy-no-eth
        SafeERC20.safeTransferFrom(_asset, caller, address(this), assets);
        _mint(receiver, shares);

        emit Deposit(caller, receiver, assets, shares);
    }

    /**
     * @dev Withdraw/redeem common workflow.
     */
    function _withdraw(
        address caller,
        address receiver,
        address owner,
        uint256 assets,
        uint256 shares
    ) internal virtual {
        if (caller != owner) {
            _spendAllowance(owner, caller, shares);
        }

        // If _asset is ERC777, `transfer` can trigger a reentrancy AFTER the transfer happens through the
        // `tokensReceived` hook. On the other hand, the `tokensToSend` hook, that is triggered before the transfer,
        // calls the vault, which is assumed not malicious.
        //
        // Conclusion: we need to do the transfer after the burn so that any reentrancy would happen after the
        // shares are burned and after the assets are transferred, which is a valid state.
        _burn(owner, shares);
        SafeERC20.safeTransfer(_asset, receiver, assets);

        emit Withdraw(caller, receiver, owner, assets, shares);
    }

    function _isVaultCollateralized() private view returns (bool) {
        return totalAssets() > 0 || totalSupply() == 0;
    }
}


Fixes Issue #11: One admin can replay last executed operation without approval

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.
            _;

            // Reset hashes after successful execution
            multiSigHashes[admin1] = 0x0;
            multiSigHashes[admin2] = 0x0;
        } 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 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);
    }
}


Change to support hash of state

Change to support hash of state

contract Adjudicator {

	bool public frozen = false;
	uint nonce = 0;
	uint lastTimestamp = 0;
	address owner;
	uint timeout;
	bytes32 public stateHash;

	modifier onlyOwner {
		if (msg.sender == owner) {
			_
		} else {
			throw;
		}
	}

	modifier notFrozen {
		if (frozen) {
			throw;
		} else {
			_
		}
	}

	function Adjudicator(address _owner, uint _timeout) {
		owner = _owner;
		timeout = _timeout;
	}

	function submit(uint _newNonce, bytes32 _stateHash)
		external
		onlyOwner
		notFrozen
		returns (bool)
	{
		if (_newNonce > nonce) {
			nonce = _newNonce;
			stateHash = _stateHash;
			return true;
		} else {
			return false;
		}
	}

	function giveConsent() external onlyOwner notFrozen {
		frozen = true;
	}

	function finalize() external notFrozen returns (bool) {
		if (lastTimestamp > 0 && now > lastTimestamp + timeout) {
			frozen = true;
			return true;
		} else {
			return false;
		}
	}

	function kill(address _recipient) external onlyOwner {
		selfdestruct(_recipient);
	}
}

contract Adjudicator {

	bool public frozen = false;
	uint nonce = 0;
	uint lastTimestamp = 0;
	address owner;
	uint timeout;
	bytes32[] state;

	modifier onlyOwner {
		if (msg.sender == owner) {
			_
		} else {
			throw;
		}
	}

	modifier notFrozen {
		if (frozen) {
			throw;
		} else {
			_
		}
	}

	function Adjudicator(address _owner, uint _timeout) {
		owner = _owner;
		timeout = _timeout;
	}

	function getStateLength() constant returns (uint) {
		return state.length;
	}

	function getStateAt(uint _index) constant returns (bytes32) {
		return state[_index];
	}

	function submit(uint _newNonce, bytes32[] _state)
		external
		onlyOwner
		notFrozen
		returns (bool)
	{
		if (_newNonce > nonce) {
			nonce = _newNonce;
			state = _state;
			return true;
		} else {
			return false;
		}
	}

	function giveConsent() external onlyOwner notFrozen {
		frozen = true;
	}

	function finalize() external notFrozen returns (bool) {
		if (lastTimestamp > 0 && now > lastTimestamp + timeout) {
			frozen = true;
			return true;
		} else {
			return false;
		}
	}

	function kill(address _recipient) external onlyOwner {
		selfdestruct(_recipient);
	}
}


node => parentNode

node => parentNode

//SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

interface INameWrapperUpgrade {
    function setSubnodeRecord(
        bytes32 parentNode,
        string calldata label,
        address owner,
        address resolver,
        uint64 ttl,
        uint32 fuses,
        uint64 expiry
    ) external;

    function wrapETH2LD(
        string calldata label,
        address wrappedOwner,
        uint32 fuses,
        uint64 expiry,
        address resolver
    ) external;
}

//SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

interface INameWrapperUpgrade {
    function setSubnodeRecord(
        bytes32 node,
        string calldata label,
        address owner,
        address resolver,
        uint64 ttl,
        uint32 fuses,
        uint64 expiry
    ) external;

    function wrapETH2LD(
        string calldata label,
        address wrappedOwner,
        uint32 fuses,
        uint64 expiry,
        address resolver
    ) external;
}


Add events to Adjudicator

Add events to Adjudicator

import "./CompareOp.sol";

/**
 * This contract ensures that the latest signed state between some parties is
 * revealed. This solves the data availability contest problem.
 */
contract Adjudicator {

	event StateSubmitted(bytes32[] _state);
	event AdjudicatorUnfrozen();
	event AdjudicatorFinalized(bytes32[] _state);

	// Whether the state has been frozen or not
	bool public frozen = false;

	// The timestamp of the last state sent
	uint lastTimestamp = 0;

	// The CompareOp which will be used to validate states
	CompareOp compareOp;

	// The address of the owner of this contract
	address owner;

	// The timeout period before this contract can be frozen
	uint timeout;

	// The newest state sent
	bytes32[] state;

	modifier onlyOwner {
		if (msg.sender == owner) {
			_
		} else {
			throw;
		}
	}

	modifier notFrozen {
		if (frozen) {
			throw;
		} else {
			_
		}
	}

	/**
	 * Creates a new Adjudicator contract.
	 *
	 * _compareOp: The CompareOp which will be used to validate states
	 * _owner: The owner of this contract
	 * _timeout: The timeout period before this contract can be frozen
	 */
	function Adjudicator(CompareOp _compareOp, address _owner, uint _timeout) {
		compareOp = _compareOp;
		owner = _owner;
		timeout = _timeout;
	}

	/**
	 * Submits a state into this contract.
	 *
	 * _state: The state to be submitted
	 *
	 * returns: `true` if sucessful, otherwise `false`
	 */
	function submit(bytes32[] _state)
		external
		onlyOwner
		notFrozen
		returns (bool)
	{
		if (compareOp.isSuperior(_state, state)) {
			state = _state;
			StateSubmitted(_state);
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Unfreezes the contract and prevents last sent state from being frozen.
	 *
	 * returns: `true` if successful, otherwise `false`
	 */
	function unfreeze() external onlyOwner returns (bool) {
		if (!compareOp.isFinal(state)) {
			lastTimestamp = 0;
			frozen = false;
			AdjudicatorUnfrozen();
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Freezes the contract if the nonce is final or if the timeout period has
	 * been reached.
	 *
	 * returns: `true` if successful, otherwise `false`
	 */
	function finalize() external notFrozen returns (bool) {
		if (compareOp.isFinal(state) || (lastTimestamp != 0 && now > lastTimestamp + timeout)) {
			frozen = true;
			AdjudicatorFinalized(state);
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Kills the current contract.
	 *
	 * _recipient: The recipient of funds from the `selfdestruct` call
	 */
	function kill(address _recipient) external onlyOwner {
		selfdestruct(_recipient);
	}
}

import "./CompareOp.sol";

/**
 * This contract ensures that the latest signed state between some parties is
 * revealed. This solves the data availability contest problem.
 */
contract Adjudicator {

	// Whether the state has been frozen or not
	bool public frozen = false;

	// The timestamp of the last state sent
	uint lastTimestamp = 0;

	// The CompareOp which will be used to validate states
	CompareOp compareOp;

	// The address of the owner of this contract
	address owner;

	// The timeout period before this contract can be frozen
	uint timeout;

	// The newest state sent
	bytes32[] state;

	modifier onlyOwner {
		if (msg.sender == owner) {
			_
		} else {
			throw;
		}
	}

	modifier notFrozen {
		if (frozen) {
			throw;
		} else {
			_
		}
	}

	/**
	 * Creates a new Adjudicator contract.
	 *
	 * _compareOp: The CompareOp which will be used to validate states
	 * _owner: The owner of this contract
	 * _timeout: The timeout period before this contract can be frozen
	 */
	function Adjudicator(CompareOp _compareOp, address _owner, uint _timeout) {
		compareOp = _compareOp;
		owner = _owner;
		timeout = _timeout;
	}

	/**
	 * Submits a state into this contract.
	 *
	 * _state: The state to be submitted
	 *
	 * returns: `true` if sucessful, otherwise `false`
	 */
	function submit(bytes32[] _state)
		external
		onlyOwner
		notFrozen
		returns (bool)
	{
		if (compareOp.isSuperior(_state, state)) {
			state = _state;
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Unfreezes the contract and prevents last sent state from being frozen.
	 *
	 * returns: `true` if successful, otherwise `false`
	 */
	function unfreeze() external onlyOwner returns (bool) {
		if (!compareOp.isFinal(state)) {
			lastTimestamp = 0;
			frozen = false;
			AdjudicatorUnfrozen();
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Freezes the contract if the nonce is final or if the timeout period has
	 * been reached.
	 *
	 * returns: `true` if successful, otherwise `false`
	 */
	function finalize() external notFrozen returns (bool) {
		if (compareOp.isFinal(state) || (lastTimestamp != 0 && now > lastTimestamp + timeout)) {
			frozen = true;
			AdjudicatorFinalized(state);
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Kills the current contract.
	 *
	 * _recipient: The recipient of funds from the `selfdestruct` call
	 */
	function kill(address _recipient) external onlyOwner {
		selfdestruct(_recipient);
	}
}


Make Adjudicator state public

Make Adjudicator state public

contract Adjudicator {

	bool public frozen = false;
	uint nonce = 0;
	uint lastTimestamp = 0;
	address owner;
	uint timeout;
	bytes32[] state;

	modifier onlyOwner {
		if (msg.sender == owner) {
			_
		} else {
			throw;
		}
	}

	modifier notFrozen {
		if (frozen) {
			throw;
		} else {
			_
		}
	}

	function Adjudicator(address _owner, uint _timeout) {
		owner = _owner;
		timeout = _timeout;
	}

	function getStateLength() constant returns (uint) {
		return state.length;
	}

	function getStateIndex(uint _index) constant returns (bytes32) {
		return state[_index];
	}

	function submit(bytes32[] _state) external onlyOwner notFrozen {
		state = _state;
	}

	function appeal() external onlyOwner notFrozen;// this will have something to do with the rules

	function giveConsent() external onlyOwner notFrozen {
		frozen = true;
	}

	function finalize() external notFrozen returns (bool) {
		if (lastTimestamp > 0 && now > lastTimestamp + timeout) {
			frozen = true;
			return true;
		} else {
			return false;
		}
	}

	function kill(address _recipient) external onlyOwner {
		selfdestruct(_recipient);
	}
}

contract Adjudicator {

	bool frozen = false;
	uint nonce = 0;
	uint lastTimestamp = 0;
	address owner;
	uint timeout;
	bytes32[] state;

	modifier onlyOwner {
		if (msg.sender == owner) {
			_
		} else {
			throw;
		}
	}

	modifier notFrozen {
		if (frozen) {
			throw;
		} else {
			_
		}
	}

	function Adjudicator(address _owner, uint _timeout) {
		owner = _owner;
		timeout = _timeout;
	}

	function getStateLength() constant returns (uint) {
		return state.length;
	}

	function getStateIndex(uint _index) constant returns (bytes32) {
		return state[_index];
	}

	function submit(bytes32[] _state) external onlyOwner notFrozen {
		state = _state;
	}

	function appeal() external onlyOwner notFrozen;// this will have something to do with the rules

	function giveConsent() external onlyOwner notFrozen {
		frozen = true;
	}

	function finalize() external notFrozen returns (bool) {
		if (lastTimestamp > 0 && now > lastTimestamp + timeout) {
			frozen = true;
			return true;
		} else {
			return false;
		}
	}

	function kill(address _recipient) external onlyOwner {
		selfdestruct(_recipient);
	}
}