// Contract: HomeWorkDeployer
// Target function: function redeem(uint256 tokenId, address controller)
 order of the _allTokens array.
     * @param tokenId uint256 ID of the token to be removed from the tokens list
     */
    function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
        // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).

        uint256 lastTokenIndex = _allTokens.length.sub(1);
        uint256 tokenIndex = _allTokensIndex[tokenId];

        // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
        // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
        // an 'if' statement (like in _removeTokenFromOwnerEnumeration)
        uint256 lastTokenId = _allTokens[lastTokenIndex];

        _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
        _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index

        // This also deletes the contents at the last position of the array
        _allTokens.length--;
        _allTokensIndex[tokenId] = 0;
    }
}


/**
 * @title HomeWork (version 1)
 * @author 0age
 * @notice Homework is a utility to find, share, and reuse "home" addresses for
 * contracts. Anyone can work to find a new home address by searching for keys,
 * a 32-byte value with the first 20 bytes equal to the finder's calling address
 * (or derived by hashing an arbitrary 32-byte salt and the caller's address),
 * and can then deploy any contract they like (even one with a constructor) to
 * the address, or mint an ERC721 token that the owner can redeem that will then
 * allow them to do the same. Also, if the contract is `SELFDESTRUCT`ed, a new
 * contract can be redeployed by the current controller to the same address!
 * @dev This contract allows contract addresses to be located ahead of time, and
 * for arbitrary bytecode to be deployed (and redeployed if so desired, i.e.
 * metamorphic contracts) to the located address by a designated controller. To
 * enable this, the contract first deploys an "initialization-code-in-runtime"
 * contract, with the creation code of the contract you want to deploy stored in
 * RUNTIME code. Then, to deploy the actual contract, it retrieves the address
 * of the storage contract and `DELEGATECALL`s into it to execute the init code
 * and, if successful, retrieves and returns the contract runtime code. Rather
 * than using a located address directly, you can also lock it in the contract
 * and mint and ERC721 token for it, which can then be redeemed in order to gain
 * control over deployment to the address (note that tokens may not be minted if
 * the contract they control currently has a deployed contract at that address).
 * Once a contract undergoes metamorphosis, all existing storage will be deleted
 * and any existing contract code will be replaced with the deployed contract
 * code of the new implementation contract. The mechanisms behind this contract 
 * are highly experimental - proceed with caution and please share any exploits
 * or optimizations you discover.
 */
contract HomeWork is IHomeWork, ERC721Enumerable, IERC721Metadata, IERC1412 {
  // Allocate storage to track the current initialization-in-runtime contract.
  address private _initializationRuntimeStorageContract;

  // Finder of home address with lowest uint256 value can recover lost funds.
  bytes32 private _highScoreKey;

  // Track information on the Home address corresponding to each key.
  mapping (bytes32 => HomeAddress) private _home;

  // Provide optional reverse-lookup for key derivation of a given home address.
  mapping (address => KeyInformation) private _key;

  // Set 0xff + address(this) as a constant to use when deriving home addresses.
  bytes21 private constant _FF_AND_THIS_CONTRACT = bytes21(
    0xff0000000000001b84b1cb32787B0D64758d019317
  );

  // Set the address of the tokenURI runtime storage contract as a constant.
  address private constant _URI_END_SEGMENT_STORAGE = address(
    0x000000000071C1c84915c17BF21728BfE4Dac3f3
  );

  // Deploy arbitrary contracts to home addresses using metamorphic init code.
  bytes32 private constant _HOME_INIT_CODE = bytes32(
    0x5859385958601c335a585952fa1582838382515af43d3d93833e601e57fd5bf3
  );

  // Compute hash of above metamorphic init code in order to compute addresses.
  bytes32 private constant _HOME_INIT_CODE_HASH = bytes32(
    0x7816562e7f85866cae07183593075f3b5ec32aeff914a0693e20aaf39672babc
  );

  // Write arbitrary code to a contract's runtime using the following prelude.
  bytes11 private constant _ARBITRARY_RUNTIME_PRELUDE = bytes11(
    0x600b5981380380925939f3
  );

  // Set EIP165 interface IDs as constants (already set 165 and 721+enumerable).
  bytes4 private constant _INTERFACE_ID_HOMEWORK = 0xe5399799;
  /* this.deploy.selector ^ this.lock.selector ^ this.redeem.selector ^
     this.assignController.selector ^ this.relinquishControl.selector ^
     this.redeemAndDeploy.selector ^ this.deriveKey.selector ^
     this.deriveKeyAndLock.selector ^
     this.deriveKeyAndAssignController.selector ^
     this.deriveKeyAndRelinquishControl.selector ^
     this.setReverseLookup.selector ^ this.setDerivedReverseLookup.selector ^
     this.deployRuntimeStorageContract.selector ^
     this.deployViaExistingRuntimeStorageContract.selector ^
     this.redeemAndDeployViaExistingRuntimeStorageContract.selector ^
     this.deriveKeyAndDeploy.selector ^
     this.deriveKeyAndDeployViaExistingRuntimeStorageContract.selector ^
     this.batchLock.selector ^ this.deriveKeysAndBatchLock.selector ^
     this.batchLock_63efZf.selector ^ this.claimHighScore.selector ^
     this.recover.selector ^ this.isDeployable.selector ^
     this.getHighScore.selector ^ this.getHomeAddressInformation.selector ^
     this.hasNeverBeenDeployed.selector ^ this.reverseLookup.selector ^
     this.getDerivedKey.selector ^ this.getHomeAddress.selector ^
     this.getMetamorphicDelegatorInitializationCode.selector ^
     this.getMetamorphicDelegatorInitializationCodeHash.selector ^
     this.getArbitraryRuntimeCodePrelude.selector == 0xe5399799
  */

  bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;

  bytes4 private constant _INTERFACE_ID_ERC1412_BATCH_TRANSFERS = 0x2b89bcaa;

  // Set name of this contract as a constant (hex encoding is to support emoji).
  string private constant _NAME = (
    hex"486f6d65576f726b20f09f8fa0f09f9ba0efb88f"
  );

  // Set symbol of this contract as a constant.
  string private constant _SYMBOL = "HWK";

  // Set the start of each token URI for issued ERC721 tokens as a constant.
  bytes private constant _URI_START_SEGMENT = abi.encodePacked(
    hex"646174613a6170706c69636174696f6e2f6a736f6e2c7b226e616d65223a22486f6d65",
    hex"253230416464726573732532302d2532303078"
  ); /* data:application/json,{"name":"Home%20Address%20-%200x */

  // Store reused revert messages as constants.
  string private constant _ACCOUNT_EXISTS = string(
    "Only non-existent accounts can be deployed or used to mint tokens."
  );

  string private constant _ONLY_CONTROLLER = string(
    "Only the designated controller can call this function."
  );

  string private constant _NO_INIT_CODE_SUPPLIED = string(
    "Cannot deploy a contract with no initialization code supplied."
  );

  /**
   * @notice In the constructor, verify that deployment addresses are correct
   * and that supplied constant hash value of the contract creation code used to
   * deploy arbitrary contracts to home addresses is valid, and set an initial
   * high score key with the null address as the high score "holder". ERC165
   * supported interfaces are all registered during initizialization as well.
   */
  constructor() public {
    // Verify that the deployment address is set correctly as a constant.
    assert(address(this) == address(uint160(uint168(_FF_AND_THIS_CONTRACT))));

    // Verify the derivation of the deployment address.
    bytes32 initialDeployKey = bytes32(
      0x486f6d65576f726b20f09f8fa0f09f9ba0efb88faa3c548a76f9bd3c000c0000
    );    
    assert(address(this) == address(
      uint160(                      // Downcast to match the address type.
        uint256(                    // Convert to uint to truncate upper digits.
          keccak256(                // Compute the CREATE2 hash using 4 inputs.
            abi.encodePacked(       // Pack all inputs to the hash together.
              bytes1(0xff),         // Start with 0xff to distinguish from RLP.
              msg.sender,           // The deployer will be the caller.
              initialDeployKey,     // Pass in the supplied key as the salt.
              _HOME_INIT_CODE_HASH  // The metamorphic initialization code hash.
            )
          )
        )
      )
    ));

    // Verify the derivation of the tokenURI runtime storage address.
    bytes32 uriDeployKey = bytes32(
      0x486f6d65576f726b202d20746f6b656e55524920c21352fee5a62228db000000
    );
    bytes32 uriInitCodeHash = bytes32(
      0xdea98294867e3fdc48eb5975ecc53a79e2e1ea6e7e794137a9c34c4dd1565ba2
    );
    assert(_URI_END_SEGMENT_STORAGE == address(
      uint160(                      // Downcast to match the address type.
        uint256(                    // Convert to uint to truncate upper digits.
          keccak256(                // Compute the CREATE2 hash using 4 inputs.
            abi.encodePacked(       // Pack all inputs to the hash together.
              bytes1(0xff),         // Start with 0xff to distinguish from RLP.
              msg.sender,           // The deployer will be the caller.
              uriDeployKey,         // Pass in the supplied key as the salt.
              uriInitCodeHash       // The storage contract init code hash.
            )
          )
        )
      )
    ));

    // Verify that the correct runtime code is at the tokenURI storage contract.
    bytes32 expectedRuntimeStorageHash = bytes32(
      0x8834602968080bb1df9c44c9834c0a93533b72bbfa3865ee2c5be6a0c4125fc3
    );
    address runtimeStorage = _URI_END_SEGMENT_STORAGE;
    bytes32 runtimeStorageHash;
    assembly { runtimeStorageHash := extcodehash(runtimeStorage) }
    assert(runtimeStorageHash == expectedRuntimeStorageHash);

    // Verify that the supplied hash for the metamorphic init code is valid.
    assert(keccak256(abi.encode(_HOME_INIT_CODE)) == _HOME_INIT_CODE_HASH);

    // Set an initial high score key with the null address as the submitter.
    _highScoreKey = bytes32(
      0x0000000000000000000000000000000000000000ffffffffffffffffffffffff
    );

    // Register EIP165 interface for HomeWork.
    _registerInterface(_INTERFACE_ID_HOMEWORK);

    // Register EIP165 interface for ERC721 metadata.
    _registerInterface(_INTERFACE_ID_ERC721_METADATA);

    // Register EIP165 interface for ERC1412 (batch transfers).
    _registerInterface(_INTERFACE_ID_ERC1412_BATCH_TRANSFERS);
  }

  /**
   * @notice Deploy a new contract with the desired initialization code to the
   * home address corresponding to a given key. Two conditions must be met: the
   * submitter must be designated as the controller of the home address (with
   * the initial controller set to the address corresponding to the first twenty
   * bytes of the key), and there must not be a contract currently deployed at
   * the home address. These conditions can be checked by calling
   * `getHomeAddressInformation` and `isDeployable` with the same key.
   * @param key bytes32 The unique value used to derive the home address.
   * @param initializationCode bytes The contract creation code that will be
   * used to deploy the contract to the home address.
   * @return The home address of the deployed contract.
   * @dev In order to deploy the contract to the home address, a new contract
   * will be deployed with runtime code set to the initialization code of the
   * contract that will be deployed to the home address. Then, metamorphic
   * initialization code will retrieve that initialization code and use it to
   * set up and deploy the desired contract to the home address. Bear in mind
   * that the deployed contract will interpret msg.sender as the address of THIS
   * contract, and not the address of the submitter - if the constructor of the
   * deployed contract uses msg.sender to set up ownership or other variables,
   * you must modify it to accept a constructor argument with the appropriate
   * address, or alternately to hard-code the intended address. Also, if your
   * contract DOES have constructor arguments, remember to include them as
   * ABI-encoded arguments at the end of the initialization code, just as you
   * would when performing a standard deploy. You may also want to provide the
   * key to `setReverseLookup` in order to find it again using only the home
   * address to prevent accidentally losing the key.
   */
  function deploy(bytes32 key, bytes calldata initializationCode)
    external
    payable
    onlyEmpty(key)
    onlyControllerDeployer(key)
    returns (address homeAddress, bytes32 runtimeCodeHash)
  {
    // Ensure that initialization code was supplied.
    require(initializationCode.length > 0, _NO_INIT_CODE_SUPPLIED);

    // Deploy the initialization storage contract and set address in storage.
    _initializationRuntimeStorageContract = _deployRuntimeStorageContract(
      initializationCode
    );

    // Use metamorphic initialization code to deploy contract to home address.
    (homeAddress, runtimeCodeHash) = _deployToHomeAddress(key);
  }

  /**
   * @notice Mint an ERC721 token to the supplied owner that can be redeemed in
   * order to gain control of a home address corresponding to a given key. Two
   * conditions must be met: the submitter must be designated as the controller
   * of the home address (with the initial controller set to the address
   * corresponding to the first 20 bytes of the key), and there must not be a
   * contract currently deployed at the home address. These conditions can be
   * checked by calling `getHomeAddressInformation` and `isDeployable` with the
   * same key.
   * @param key bytes32 The unique value used to derive the home address.
   * @param owner address The account that will be granted ownership of the
   * ERC721 token.
   * @dev In order to mint an ERC721 token, the assocated home address cannot be
   * in use, or else the token will not be able to deploy to the home address.
   * The controller is set to this contract until the token is redeemed, at
   * which point the redeemer designates a new controller for the home address.
   * The key of the home address and the tokenID of the ERC721 token are the
   * same value, but different types (bytes32 vs. uint256).
   */
  function lock(bytes32 key, address owner)
    external
    onlyEmpty(key)
    onlyController(key)
  {
    // Ensure that the specified owner is a valid ERC721 receiver.
    _validateOwner(owner, key);

    // Get the HomeAddress storage struct from the mapping using supplied key.
    HomeAddress storage home = _home[key];

    // Set the exists flag to true and the controller to this contract.
    home.exists = true;
    home.controller = address(this);

    // Emit an event signifying that this contract is now the controller. 
    emit NewController(key, address(this));

    // Mint the ERC721 token to the designated owner.
    _mint(owner, uint256(key));
  }