ETH Price: $3,128.00 (-4.48%)

Contract

0x1eb4490091bd0fFF6c3973623C014D082936EA03
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Deposit Souls Ba...205639532024-08-19 16:46:1187 days ago1724085971IN
0x1eb44900...82936EA03
0 ETH0.000364672.00707857
Deposit Souls Ba...200183142024-06-04 11:59:35163 days ago1717502375IN
0x1eb44900...82936EA03
0 ETH0.001219179.94087888
Merge Heroes200181892024-06-04 11:34:35163 days ago1717500875IN
0x1eb44900...82936EA03
0 ETH0.000878647.49464425
Deposit Souls Ba...198960982024-05-18 10:00:47180 days ago1716026447IN
0x1eb44900...82936EA03
0 ETH0.000722083.28947373
Deposit Souls Ba...195709532024-04-02 22:03:35225 days ago1712095415IN
0x1eb44900...82936EA03
0 ETH0.0049316434.08254712
Deposit Souls Ba...195705742024-04-02 20:46:47225 days ago1712090807IN
0x1eb44900...82936EA03
0 ETH0.0039005438.07565764
Deposit Souls Ba...191409952024-02-02 13:25:59286 days ago1706880359IN
0x1eb44900...82936EA03
0 ETH0.0056361622.92262445
Deposit Souls Ba...191409092024-02-02 13:08:35286 days ago1706879315IN
0x1eb44900...82936EA03
0 ETH0.0061245725.70854344
Deposit Souls Ba...191408712024-02-02 13:00:59286 days ago1706878859IN
0x1eb44900...82936EA03
0 ETH0.0063114726.49307148
Deposit Souls Ba...191407962024-02-02 12:45:35286 days ago1706877935IN
0x1eb44900...82936EA03
0 ETH0.0068107526.50740121
Deposit Souls Ba...191407622024-02-02 12:38:35286 days ago1706877515IN
0x1eb44900...82936EA03
0 ETH0.005309226.43803209
Deposit Souls Ba...191407302024-02-02 12:32:11286 days ago1706877131IN
0x1eb44900...82936EA03
0 ETH0.0050268122.89871487
Deposit Souls Ba...191407092024-02-02 12:27:59286 days ago1706876879IN
0x1eb44900...82936EA03
0 ETH0.0031536319.299592
Deposit Souls Ba...191406602024-02-02 12:18:11286 days ago1706876291IN
0x1eb44900...82936EA03
0 ETH0.003603319.78628856
Deposit Souls Ba...191406152024-02-02 12:09:11286 days ago1706875751IN
0x1eb44900...82936EA03
0 ETH0.0039190419.51551088
Deposit Souls Ba...191405872024-02-02 12:03:23286 days ago1706875403IN
0x1eb44900...82936EA03
0 ETH0.0035252419.35765204
Deposit Souls Ba...191405492024-02-02 11:55:47286 days ago1706874947IN
0x1eb44900...82936EA03
0 ETH0.0025756315.76235519
Deposit Souls Ba...191405202024-02-02 11:49:59286 days ago1706874599IN
0x1eb44900...82936EA03
0 ETH0.0035461419.47245108
Deposit Souls Ba...191404872024-02-02 11:43:23286 days ago1706874203IN
0x1eb44900...82936EA03
0 ETH0.0042223221.02572828
Deposit Souls Ba...191404502024-02-02 11:35:47286 days ago1706873747IN
0x1eb44900...82936EA03
0 ETH0.0029036817.7699463
Deposit Souls Ba...191404202024-02-02 11:29:35286 days ago1706873375IN
0x1eb44900...82936EA03
0 ETH0.0033620218.46137846
Merge Heroes190886182024-01-26 5:12:35293 days ago1706245955IN
0x1eb44900...82936EA03
0 ETH0.0042131417.05139872
Deposit Souls Ba...190886022024-01-26 5:09:23293 days ago1706245763IN
0x1eb44900...82936EA03
0 ETH0.0121406919.17819073
Deposit Souls Ba...189622602024-01-08 12:20:35311 days ago1704716435IN
0x1eb44900...82936EA03
0 ETH0.0034738224.00759849
Deposit Souls Ba...189622382024-01-08 12:16:11311 days ago1704716171IN
0x1eb44900...82936EA03
0 ETH0.0033395923.07993717
View all transactions

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To
147116842022-05-04 15:16:15925 days ago1651677375  Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
SoulsLocker

Compiler Version
v0.8.13+commit.abaa5c0e

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 8 : Anime2Merger.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

//        ___       ___                    ___           ___                       ___           ___     
//       /\__\     /\  \                  /\  \         /\__\          ___        /\__\         /\  \    
//      /:/  /    /::\  \                /::\  \       /::|  |        /\  \      /::|  |       /::\  \   
//     /:/  /    /:/\:\  \              /:/\:\  \     /:|:|  |        \:\  \    /:|:|  |      /:/\:\  \  
//    /:/  /    /::\~\:\  \            /::\~\:\  \   /:/|:|  |__      /::\__\  /:/|:|__|__   /::\~\:\  \ 
//   /:/__/    /:/\:\ \:\__\          /:/\:\ \:\__\ /:/ |:| /\__\  __/:/\/__/ /:/ |::::\__\ /:/\:\ \:\__\
//   \:\  \    \:\~\:\ \/__/          \/__\:\/:/  / \/__|:|/:/  / /\/:/  /    \/__/~~/:/  / \:\~\:\ \/__/
//    \:\  \    \:\ \:\__\                 \::/  /      |:/:/  /  \::/__/           /:/  /   \:\ \:\__\  
//     \:\  \    \:\ \/__/                 /:/  /       |::/  /    \:\__\          /:/  /     \:\ \/__/  
//      \:\__\    \:\__\                  /:/  /        /:/  /      \/__/         /:/  /       \:\__\    
//       \/__/     \/__/                  \/__/         \/__/                     \/__/         \/__/    


import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";

import "@openzeppelin/contracts/access/Ownable.sol";

import "@openzeppelin/contracts/utils/Strings.sol";

import "@rari-capital/solmate/src/utils/SSTORE2.sol";


// interface of Le Anime V2 wrapper contract + IERC721Metadata

interface IWrapper is IERC721Metadata {

    function transferFromBatch(address from, address to, uint256[] calldata tokenId) external;

}

// interface for merger callback contract - for future implementation

interface IMerger {
    function afterDeposit(uint256 heroId) external;
    function afterWithdrawAll(uint256 heroId) external;
    function afterWithdrawBatch(uint256 heroId) external;
    function afterMergeHeroes(uint256 mainHeroId, uint256 mergedHeroId) external;

    function afterLayerDeposit(uint256 heroId) external;
    function afterLayerWithdrawal(uint256 heroId) external;
}

// Merging Rules

struct MergeParameters {
    uint256[] rankThresholds; // Hero levels thresholds

    mapping(uint256 => uint256) additionalExtrasForRank; // number of additional extra slots for Hero Level
    mapping(uint256 => mapping(uint256 => uint256[])) traitsLevelsCut; // traits levels thresholds
}

// Hero Storage of Traits and Parameters

struct heroParams { 
    uint32 score; // max score of merged heroes is 255*10627*20 = 54'197'700 and uint32 is 4'294'967'295
    uint32 extraScore; // same as above for additional scoring

    uint16 imageIdx; // image displayed - max is 10627 variants - uint16 is 65536
    uint8 visibleBG; // max is 255 - this is the full colour BG overlay
    bool state; // anime&spirits vs hero state
    bool locked; // locker 
    
    bytes params; // hero traits
    bytes upper; // hero more traits
    bytes extraLayers; // additional layers
    bytes[] moreParams; // more additional layers
}

///////////////////////
// LOCKER CONTRACT
///////////////////////

contract SoulsLocker is Ownable {

    event DepositedSouls(uint256 indexed heroId, uint256[] tokenId);
    event ReleasedAllSouls(uint256 indexed heroId);
    event ReleasedSouls(uint256 indexed heroId, uint256[] index);
    event MergedHeroes(uint256 indexed mainHeroId, uint256 indexed mergedHeroId);

    uint256 private constant OFFSETAN2 = 100000;

    // WRAPPER CONTRACT
    IWrapper public wrapper;

    // MERGER CONTRACT - for callback implementation
    IMerger public merger;

    // Is merger contract closed? allows to render that immutable
    bool public closedMergerUpdate = false;

    // SOULS IN HERO
    mapping(uint256 => uint16[]) public soulsInHero;

    // Max units that can be merged
    uint256 public maxMergeUnits = 1000;

    // activate extra functionalities
    bool public isMergeHeroesActive = false;

    bool public isMergeHeroesBatchActive = false;

    bool public isWithdrawSoulsBatchActive = false;

    // EMERGENCY RECOVER FUNCTION TO BE REVOKED
    bool public emergencyRevoked = false;

    constructor(address wrapperAddress_) {
        wrapper = IWrapper(wrapperAddress_);
    }

    /*///////////////////////////////////////////////////////////////
                            ADMIN FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    function updateMerger(address mergerAddress_) external onlyOwner {
        require(!closedMergerUpdate, "Update Closed");
        merger = IMerger(mergerAddress_);
    }

    function closeUpdateMerger() external onlyOwner {
        closedMergerUpdate = true;
    }

    function changeMaxMergeUnits(uint256 maxMergeUnits_) external onlyOwner {
        require(!closedMergerUpdate, "Update Closed");
        maxMergeUnits = maxMergeUnits_;
    }

    function activateMergeHeroes() external onlyOwner {
        isMergeHeroesActive = true;
    }

    function activateMergeHeroesBatch() external onlyOwner {
        isMergeHeroesBatchActive = true;
    }

    function activateWithdrawSoulBatch() external onlyOwner {
        isWithdrawSoulsBatchActive = true;
    }

    /*///////////////////////////////////////////////////////////////
                            EMERGENCY FUNCTION
    //////////////////////////////////////////////////////////////*/

    
    // revokes the temporary emergency function - only owner can trigger it and will be disabled in the future
    function revokeEmergency() external onlyOwner  {
        emergencyRevoked = true;
    }

    // *** EMERGENCY FUNCTION *** emergency withdrawal to recover stuck ERC721 sent to the contract
    function emergencyRecoverBatch(address to, uint256[] calldata tokenId) external onlyOwner {
        require(emergencyRevoked == false, "Emergency power revoked");

        wrapper.transferFromBatch(address(this), to, tokenId);
    }

    /*///////////////////////////////////////////////////////////////
                            STORAGE GETTERS
    //////////////////////////////////////////////////////////////*/

    function getSoulsInHero(uint256 heroId) external view returns (uint16[] memory) {
        return soulsInHero[heroId];
    }

    /*///////////////////////////////////////////////////////////////
                            DEPOSIT/WITHDRAW
    //////////////////////////////////////////////////////////////*/

    // deposit only Souls And Spirits into Main token
    function depositSoulsBatch(uint256 heroId, uint256[] calldata tokenId) external {
        
        require(msg.sender == wrapper.ownerOf(heroId + OFFSETAN2), "Not the owner");

        uint256 totalHeroLength = soulsInHero[heroId].length + 1;

        require(totalHeroLength + tokenId.length <= maxMergeUnits, "Max units: 1000");

        // Max id mintable in anime contract is 110627 so (max - OFFSETAN2) is 10627
        wrapper.transferFromBatch(msg.sender, address(this), tokenId);

        uint16 currTokenId;

        for (uint256 i = 0; i < tokenId.length ; i++){

            currTokenId = uint16(tokenId[i] - OFFSETAN2);

            require(heroId != currTokenId, "Cannot add itself");
            require(soulsInHero[currTokenId].length == 0, "Cannot add a hero");

            soulsInHero[heroId].push(currTokenId);  
            
        }

        // call function after deposit - future implementation
        if (address(merger) != address(0)) {
            merger.afterDeposit(heroId);
        }

        emit DepositedSouls(heroId, tokenId);
        
    }

    // deposit Souls, Spirits and Heroes into Main token - activate later
    function depositSoulsBatchHeroes(uint256 heroId, uint256[] calldata tokenId) external {
        require(isMergeHeroesBatchActive, "Hero batch merge not active");
        
        // check if caller is the owner of the hero
        require(msg.sender == wrapper.ownerOf(heroId + OFFSETAN2), "Not the owner");

        // batch transfer tokens into this contract
        wrapper.transferFromBatch(msg.sender, address(this), tokenId);

        // store variable for the temporary current token id to add to the hero
        uint16 currTokenId;

        for (uint256 i = 0; i < tokenId.length ; i++){
            currTokenId = uint16(tokenId[i] - OFFSETAN2);

            // check hero is not adding itself
            require(heroId != currTokenId, "Cannot add itself");
            
            // check if the token to add contains already tokens or not
            // if not simply add token, else process internal tokens

            if (soulsInHero[currTokenId].length == 0) {

                soulsInHero[heroId].push(currTokenId); 
            }
            else {
                // process hero into hero
                // add main hero token - this one is outside the contract
                soulsInHero[heroId].push(currTokenId); 

                // adds the internal tokens already in the contract, into the new hero
                uint16[] memory currentSouls = soulsInHero[currTokenId];

                // add all internal tokens to new hero and counts length
                for (uint256 j = 0; j < currentSouls.length ; j++){
                    soulsInHero[heroId].push(currentSouls[j]);
                }
                
                // clears the added hero
                delete soulsInHero[currTokenId];
                
            }

        }

        // check the hero is not larger than max units
        require(soulsInHero[heroId].length + 1 <= maxMergeUnits, "Max units: 1000");
        
        // callback function after deposit
        if (address(merger) != address(0)) {
            merger.afterDeposit(heroId);
        }

        emit DepositedSouls(heroId, tokenId);  
    }

    // Withdraw all the tokens from main token
    function withdrawSoulsBatchAll(uint256 heroId) external {

        // check caller is the Hero owner
        require(msg.sender == wrapper.ownerOf(heroId + OFFSETAN2), "Not the owner");
        
        uint16[] memory soulsToWithdraw = soulsInHero[heroId];

        // transfer all the souls out
        for (uint256 i = 0; i < soulsToWithdraw.length; i++) {
            wrapper.transferFrom(address(this), msg.sender, soulsToWithdraw[i] + OFFSETAN2);
        }

        //removes the list of locked souls
        delete soulsInHero[heroId];

        // callback - for future implementation
        if (address(merger) != address(0)) {
            merger.afterWithdrawAll(heroId);
        }

        emit ReleasedAllSouls(heroId);
    }

    function withdrawSoulsBatch(uint256 heroId, uint256[] calldata index) external {
        require(isWithdrawSoulsBatchActive, "Batch withdrawal not active");
        // check the  caller is the hero owner
        require(msg.sender == wrapper.ownerOf(heroId + OFFSETAN2), "Not the owner");

        // pointer to storage for easy access
        uint16[] storage array = soulsInHero[heroId];

        wrapper.transferFrom(address(this), msg.sender, array[index[0]] + OFFSETAN2);
        
        array[index[0]] = array[array.length - 1];
        array.pop();

        for (uint256 i = 1; i < index.length; i++) {

            // makes sure the indexes are in descending order 
            require(index[i] < index[i - 1], "not in descending order");

            // first transfer
            wrapper.transferFrom(address(this), msg.sender, array[index[i]] + OFFSETAN2);

            array[index[i]] = array[array.length - 1];
            array.pop();
        }

        //cALLBACK
        if (address(merger) != address(0)) {
            merger.afterWithdrawBatch(heroId);
        }

        emit ReleasedSouls(heroId, index);
    }

    // merge hero 2 into hero 1 - activate later
    function mergeHeroes(uint256 mainHeroId, uint256 mergedHeroId) external {
        require(isMergeHeroesActive, "Hero merge not active");
        require(mainHeroId != mergedHeroId, "Cannot add itself");

        require(msg.sender == wrapper.ownerOf(mainHeroId + OFFSETAN2), "Not the owner");
        require(msg.sender == wrapper.ownerOf(mergedHeroId + OFFSETAN2), "Not the owner");

        uint16[] storage mainHeroSouls = soulsInHero[mainHeroId];

        uint16[] memory mergedHeroSouls = soulsInHero[mergedHeroId];

        require(mainHeroSouls.length + 1 + mergedHeroSouls.length + 1 <= maxMergeUnits, "Max units: 1000");

        // transfer the mergedHero token
        wrapper.transferFrom(msg.sender, address(this), mergedHeroId + OFFSETAN2);

        // adds the mergedHero token
        mainHeroSouls.push(uint16(mergedHeroId));

        // adds tokens inside mergedHero token - already locked
        for (uint256 i = 0; i < mergedHeroSouls.length ; i++){ 
            mainHeroSouls.push(mergedHeroSouls[i]);
        }

        // delete token list in mergedHero
        delete soulsInHero[mergedHeroId];

        // After Merge Callback - future implementation
        if (address(merger) != address(0)) {
            merger.afterMergeHeroes(mainHeroId, mergedHeroId);
        }

    }
}

///////////////////////
// HERO DATA CONTRACT
///////////////////////

contract HeroDataStorage is Ownable {

    event NewHeroData(uint256 indexed heroId, heroParams newParams);

    uint256 private constant OFFSETAN2 = 100000;

    // WRAPPER CONTRACT
    IWrapper public wrapper;

    // MERGER CONTRACT ADDRESS
    address public mergerAddress;

    // merger contract update closed?
    bool public closedMergerUpdate = false;

    // HERO STORAGE
    heroParams[10628] public dataHero;

    constructor(address wrapperAddress_) {
        
        wrapper = IWrapper(wrapperAddress_);

    }

    /*///////////////////////////////////////////////////////////////
                            ADMIN FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    function updateMerger(address mergerAddress_) external onlyOwner {
        require(!closedMergerUpdate, "Update Closed");
        mergerAddress = mergerAddress_;    
    }

    function closeUpdateMerger() external onlyOwner {
        closedMergerUpdate = true;
    }

    
    /*///////////////////////////////////////////////////////////////
                                GETTERS
    //////////////////////////////////////////////////////////////*/

    function getData(uint256 heroId) external view returns (heroParams memory) {
        return dataHero[heroId];
    }

    /*///////////////////////////////////////////////////////////////
                                SETTERS
    //////////////////////////////////////////////////////////////*/

    //this function will be used by the merge contracts to set data
    function setData(uint256 heroId, heroParams calldata newHeroData) external { 
        require(msg.sender == mergerAddress, "Not allowed - only merger");
        dataHero[heroId] = newHeroData;

        emit NewHeroData(heroId, dataHero[heroId]);
    }

    //this functions will be used by the hero owner to set data
    function setDataOwner(uint256 heroId, bytes calldata params_) external { 
        require(msg.sender == wrapper.ownerOf(heroId + OFFSETAN2), "Not the owner");

        dataHero[heroId].params = params_;

        emit NewHeroData(heroId, dataHero[heroId]);

    }

    function setDataOwner(uint256 heroId, bytes calldata params_, uint8 bg_) external { 
        require(msg.sender == wrapper.ownerOf(heroId + OFFSETAN2), "Not the owner");

        dataHero[heroId].params = params_;

        dataHero[heroId].visibleBG = bg_;

        emit NewHeroData(heroId, dataHero[heroId]);

    }

    function setDataOwner(uint256 heroId, bytes calldata params_, uint16 image_, uint8 bg_) external { 
        require(msg.sender == wrapper.ownerOf(heroId + OFFSETAN2), "Not the owner");

        dataHero[heroId].params = params_;

        dataHero[heroId].imageIdx = image_;

        dataHero[heroId].visibleBG = bg_;

        emit NewHeroData(heroId, dataHero[heroId]);

    }

    function setDataOwner(uint256 heroId, bytes[3] calldata heroP_, uint16 image_, uint8 bg_) external { 
        require(msg.sender == wrapper.ownerOf(heroId + OFFSETAN2), "Not the owner");

        dataHero[heroId].params = heroP_[0];
        dataHero[heroId].extraLayers = heroP_[1];
        dataHero[heroId].upper = heroP_[2];

        dataHero[heroId].imageIdx = image_;
        dataHero[heroId].visibleBG = bg_;

        emit NewHeroData(heroId, dataHero[heroId]);

    }

    function setDataOwner(uint256 heroId, heroParams calldata newHeroData) external { 
        require(msg.sender == wrapper.ownerOf(heroId + OFFSETAN2), "Not the owner");

        dataHero[heroId] = newHeroData;

        emit NewHeroData(heroId, dataHero[heroId]);
    }
  
}

///////////////////////
// MERGE DATA CONTRACTS
///////////////////////

contract StoreCharacters is Ownable {

    // ANIME / SPIRITS - METADATA STORAGE IN A CONTRACT
    address[] public pointers;

    // is the contract closed to modify souls and spirits data?
    bool public closedCharacters = false;

    /*///////////////////////////////////////////////////////////////
                        ADMIN FUNCTIONS MERGE
    //////////////////////////////////////////////////////////////*/
    
    function closeCharacters() external onlyOwner  {
        closedCharacters = true;
    }

    /*///////////////////////////////////////////////////////////////
                       STORE METADATA IN CONTRACTS
    //////////////////////////////////////////////////////////////*/

    function setTraitsBytes(bytes calldata params) external onlyOwner {
            require(!closedCharacters, "Closed");
            pointers.push(SSTORE2.write(params));   
    }

    function setPointers(address[] calldata pointersList) external onlyOwner {
        require(!closedCharacters, "Closed");
        pointers = pointersList;
    }

    /*///////////////////////////////////////////////////////////////
                       READ METADATA FROM CONTRACTS
    //////////////////////////////////////////////////////////////*/

    function getTraitsData(uint256 pointerId) external view returns (bytes memory) {
        return SSTORE2.read(pointers[pointerId]);
    }

    function getCharTraits(uint256 tokenId) external view returns (bytes memory) {
        //you can save 3000 tokens traits per contract
        uint256 pointer = (tokenId - 1) / 3000;
        uint256 idx = (tokenId - 1) % 3000 * 8;
        return SSTORE2.read(pointers[pointer], idx, idx + 8);
    }

    function getCharTraitsUInt8(uint256 tokenId) external view returns (uint8[8] memory) {
        uint256 pointer = (tokenId - 1) / 3000;
        uint256 idx = (tokenId - 1) % 3000 * 8;
        bytes memory temp =  SSTORE2.read(pointers[pointer], idx, idx + 8);
        
        return [
            uint8(temp[0]), uint8(temp[1]), uint8(temp[2]), uint8(temp[3]), 
            uint8(temp[4]), uint8(temp[5]), uint8(temp[6]), uint8(temp[7])
            ];
    }

}

contract LeAnimeV2MergerLAB is StoreCharacters {

    /*//////////////////////////////////////////////////////////////
                                STORAGE
    //////////////////////////////////////////////////////////////*/

    // SETTING MERGE CONSTANTS
    uint256 private constant OFFSETAN2 = 100000;

    // MERGE PARAMETERS
    MergeParameters private mergeP;

    bool public mergeActive;

    // WRAPPER CONTRACT
    IWrapper public wrapper;

    // SOULS LOCKER
    SoulsLocker public locker;

    // HERO STORAGE 
    HeroDataStorage public heroStorage;
    
    constructor(address wrapperAddr) {  
        wrapper = IWrapper(wrapperAddr);
       
        mergeP.rankThresholds = [1,30,70,170,390,800,1500,2000,2500,2900,6000,10000,15000,20000,25000];
        
        // Set additionalExtrasForRank slots -  mapping(uint256 => uint256)
        mergeP.additionalExtrasForRank[0] = 0;
        mergeP.additionalExtrasForRank[1] = 1;
        mergeP.additionalExtrasForRank[2] = 1;
        mergeP.additionalExtrasForRank[3] = 2;
        mergeP.additionalExtrasForRank[4] = 2;
        mergeP.additionalExtrasForRank[5] = 3;
        mergeP.additionalExtrasForRank[6] = 3;
        mergeP.additionalExtrasForRank[7] = 3;
        mergeP.additionalExtrasForRank[8] = 4;
        mergeP.additionalExtrasForRank[9] = 4;
        mergeP.additionalExtrasForRank[10] = 4;
        mergeP.additionalExtrasForRank[11] = 5;
        mergeP.additionalExtrasForRank[12] = 5;
        mergeP.additionalExtrasForRank[13] = 5;
        mergeP.additionalExtrasForRank[14] = 6;
        
        // extra levels thresholds
        mergeP.traitsLevelsCut[7][0] = [1]; // 0 invisible
        mergeP.traitsLevelsCut[7][1] = [1,4,7,14,27,53,103,201]; // 1 book
        mergeP.traitsLevelsCut[7][2] = [1,5,12,28,64]; // 2 sword
        mergeP.traitsLevelsCut[7][3] = [1,6,16,39,98]; // 3 laurel
        mergeP.traitsLevelsCut[7][4] = [1,4,9,18,36,74,152,312]; // 4 heart
        mergeP.traitsLevelsCut[7][5] = [1,4,7,13,25,47,89,170,323,613]; // 5 skull
        mergeP.traitsLevelsCut[7][6] = [1,4,8,17,35,72,147,300]; // 6 lyre
        mergeP.traitsLevelsCut[7][7] = [1,4,8,15,30,58,115,227,447]; // 7 crystal
        mergeP.traitsLevelsCut[7][8] = [1]; // 8 upOnly
        mergeP.traitsLevelsCut[7][9] = [1]; // 9 69
        mergeP.traitsLevelsCut[7][10] = [1]; // 10 777
        mergeP.traitsLevelsCut[7][11] = [1]; // Lightsaber
        mergeP.traitsLevelsCut[7][12] = [1]; // Gold Book
        mergeP.traitsLevelsCut[7][13] = [1]; // Gold Bow
        mergeP.traitsLevelsCut[7][14] = [1]; // Gold Lyre
        mergeP.traitsLevelsCut[7][15] = [1]; // Gold Scyte
        mergeP.traitsLevelsCut[7][16] = [1]; // Gold Staff
        mergeP.traitsLevelsCut[7][17] = [1]; // Gold Sword
        mergeP.traitsLevelsCut[7][18] = [1]; // Gold Wings
        mergeP.traitsLevelsCut[7][19] = [1]; // 420 special!
            
    
        // runes levels thresholds    
        mergeP.traitsLevelsCut[6][0] = [1]; // 0 invisible
        mergeP.traitsLevelsCut[6][1] = [1,3,6,11,21,39,71,131,242,445]; // 1 fish
        mergeP.traitsLevelsCut[6][2] = [1,3,5,10,17,30,52,92,162,285]; // 2 R
        mergeP.traitsLevelsCut[6][3] = [1,3,6,10,18,33,59,105,189,338]; // 3 I
        mergeP.traitsLevelsCut[6][4] = [1,3,6,12,22,41,77,143,266,496]; // 4 Mother
        mergeP.traitsLevelsCut[6][5] = [1,3,5,9,15,26,45,77,132,227]; // 5 Up Only
        mergeP.traitsLevelsCut[6][6] = [1,3,5,8,14,23,39,67,112,190]; // 6 Burning S
        mergeP.traitsLevelsCut[6][7] = [1]; // 7 Daemon Face
        mergeP.traitsLevelsCut[6][8] = [1]; // 8 Up Only fish
        mergeP.traitsLevelsCut[6][9] = [1,3,4,7,11,18,29,47,77,124]; // 9 roman
        mergeP.traitsLevelsCut[6][10] = [1,2,4,6,10,16,25,39,61,97]; // 10 hieroglyphs
        mergeP.traitsLevelsCut[6][11] = [1]; // Andrea  
        mergeP.traitsLevelsCut[6][12] = [1]; // gm
        mergeP.traitsLevelsCut[6][13] = [1]; // Loom
        mergeP.traitsLevelsCut[6][14] = [1]; // path
        mergeP.traitsLevelsCut[6][15] = [1]; // Abana
    }


    /*///////////////////////////////////////////////////////////////
                        ADMIN FUNCTIONS MERGE
    //////////////////////////////////////////////////////////////*/
    
    // set the SoulsLocker and HeroDataStorage modules
    function setupModules(address locker_, address heroStorage_) external onlyOwner {
        locker = SoulsLocker(locker_);
        
        heroStorage = HeroDataStorage(heroStorage_);
    }

    function activateMerge() external onlyOwner  {
        mergeActive = true;
    }

    function activateMergeLABMaster() external {
        require(callerIsLabMaster(), "Not the L.A.B Master");
        mergeActive = true;
    }

    function callerIsLabMaster() public view returns (bool) {
        // gets owner of The L.A.B. from SuperRare contract
        address labMaster = IERC721Metadata(0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0).ownerOf(28554);
        return (labMaster == msg.sender);
    }

    // Get and Set Merge parameters functions
    function getRankThresholds() external view returns (uint256[] memory) {
        return mergeP.rankThresholds;
    }

    function setRankThresholds(uint256[] calldata newRanks) external onlyOwner {
        mergeP.rankThresholds = newRanks;
    }

    function getTraitsLevelsCut(uint256 idx1, uint256 idx2) external view returns (uint256[] memory) {
        return mergeP.traitsLevelsCut[idx1][idx2];
    }

    function setTraitsLevelsCut(uint256 idx1, uint256 idx2, uint256[] calldata traitsCuts) external onlyOwner {
        mergeP.traitsLevelsCut[idx1][idx2] = traitsCuts;
    }

    function getAdditionalExtras(uint256 idx1) external view returns (uint256) {
        return mergeP.additionalExtrasForRank[idx1];
    }

    function setAdditionalExtras(uint256 idx1, uint256 additionalSlots) external onlyOwner {
        mergeP.additionalExtrasForRank[idx1] = additionalSlots;
    }
    
    /*///////////////////////////////////////////////////////////////
                        CHECK HERO FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    function checkParamsValidity(
        uint256 heroId,
        uint16[] memory tokenId,
        bytes memory params
    )   public view returns (uint256)
    {   
        // merge is not active yet
        if (mergeActive == false) {
            return 0;
        }
        
        //makes sure the params encoding is valid
        if (params.length < 10 || params.length % 2 != 0) { 
            return 0; // not a valid hero
        }

        // block to check for extra duplicates - doing it at the beginning to avoid computing more if this fails
        {
            bytes memory usedExtras = new bytes(7);
                
            usedExtras[0] = params[8]; //first extra

            
            //returns false if additional there is a duplicate extra
            for (uint256 i = 10; i < params.length; i+=2) {
                for (uint256 j = 0; j < (i-8)/2; j++) {
                    if (params[i] == usedExtras[j]) { 
                        return 0; //false
                    }
                }
                usedExtras[(i-8)/2] = params[i];   
            }
        }

        
        uint256 totScore;

        //number of additional extras:
        uint256 addExtraSlots = (params.length - 10)/2;

        uint256[] memory rarityCount = new uint256[](7 + addExtraSlots);

        
        //block to count traits
        {
            // load Allcharacters from on chain contracts in one go
            bytes[4] memory allData = [
                SSTORE2.read(pointers[0]), 
                SSTORE2.read(pointers[1]), 
                SSTORE2.read(pointers[2]), 
                SSTORE2.read(pointers[3])
            ];
            
            //count the heroId first
            uint256 idx = (heroId - 1) % 3000 * 8;
            uint256 ptr = (heroId - 1) / 3000;

            // checks anime vs spirit multiplier
            uint256 multiplier = heroId <= 1573 ? 20 : 1;

            //starts the count with the token associated with heroId
            totScore += uint8(allData[ptr][idx]) * multiplier;

            if (allData[ptr][idx+1] == params[1]) { // skin
                rarityCount[0] += multiplier;
            }
            if (allData[ptr][idx+2] == params[2]) { // clA
                rarityCount[1] += multiplier;
            }
            if (allData[ptr][idx+3] == params[3]) { // clB
                rarityCount[2] += multiplier;
            }
            if (allData[ptr][idx+4] == params[4]) { // bg
                rarityCount[3] += multiplier;
            }
            if (allData[ptr][idx+5] == params[5]) { // halo
                rarityCount[4] += multiplier;
            }
            if (allData[ptr][idx+6] == params[6]) { // runes
                rarityCount[5] += multiplier;
            }
            if (allData[ptr][idx+7] == params[8]) { // extra
                rarityCount[6] += multiplier;
            }
            
            // additional extras
            for (uint256 j = 0;  j < addExtraSlots; j++) {
                    if (allData[ptr][idx+7] == params[j*2 + 10]) {
                        rarityCount[j + 7] += multiplier;
                    }
                    
            }
            
            
            for (uint256 i = 0; i < tokenId.length ; i++){
        
                idx = (tokenId[i] - 1) % 3000 * 8;
                ptr = (tokenId[i] - 1) / 3000;

                multiplier = tokenId[i] <= 1573 ? 20 : 1;

                totScore += uint8(allData[ptr][idx]) * multiplier;

                if (allData[ptr][idx+1] == params[1]) { // skin
                    rarityCount[0] += multiplier;
                }
                if (allData[ptr][idx+2] == params[2]) { // clA
                    rarityCount[1] += multiplier;
                }
                if (allData[ptr][idx+3] == params[3]) { // clB
                    rarityCount[2] += multiplier;
                }
                if (allData[ptr][idx+4] == params[4]) { // bg
                    rarityCount[3] += multiplier;
                }
                if (allData[ptr][idx+5] == params[5]) { // halo
                    rarityCount[4] += multiplier;
                }
                if (allData[ptr][idx+6] == params[6]) { // runes
                    rarityCount[5] += multiplier;
                }
                if (allData[ptr][idx+7] == params[8]) { // extra
                    rarityCount[6] += multiplier;
                }
                
                // additional extras - if any
                for (uint256 j = 0;  j < addExtraSlots; j++) { 
                        if (allData[ptr][idx+7] == params[j*2 + 10]) {
                            rarityCount[j + 7] += multiplier;
                        }     
                }
                    

            }
        }

        //check that rank is valid - not above the MAX rank possible at the time
        if (uint8(params[0]) >= mergeP.rankThresholds.length) {
            return 0; //false
        }

        //check if rarity sum of souls is enough to match the rank of the requested hero
        if (totScore < mergeP.rankThresholds[uint8(params[0])]) {
            return 0; //false
        }

        // block that finds the max rank possible for the current total score
        // need to know to allocate the right nr of extras
        {
            uint8 maxRank = uint8(params[0]);

            for (uint8 i = uint8(params[0]); i < mergeP.rankThresholds.length; i++) {
                if (totScore >= mergeP.rankThresholds[i]) {
                    maxRank = i;
                }
            }
            
            //check that add extra slots are not more than the allowed ones for the rank
            if (addExtraSlots > mergeP.additionalExtrasForRank[maxRank]) {
                return 0;
            }
        }
        

        // block that checks that the level of the extras are allowed
        {
            uint256 levelCut;
            
            //cycle through traits with no leveling up (skin to halo)
            for (uint256 i = 1; i <= 5; i++) { 
                //check that there is at least one occurence of the trait or return 0
                if (rarityCount[i-1] == 0) {
                    return 0;
                }
            }

            //check that runes level is valid - not above the MAX level possible for the specific rune
            if (uint8(params[7]) >= mergeP.traitsLevelsCut[6][uint8(params[6])].length) {
                return 0; //false
            }

            // checks runes (leveling up and not)
            if (mergeP.traitsLevelsCut[6][uint8(params[6])].length > 1) {
                    levelCut = mergeP.traitsLevelsCut[6][uint8(params[6])][uint8(params[7])];
                    
                    //check if you have enough points on this trait
                    if (rarityCount[5] < levelCut) { 
                       return 0;
                    }                  
                    
            }
            else { //this is for unique traits that are not possible to level up 
                //check that the level is 0 and that there is one available
                if (rarityCount[5] == 0 || params[7] > 0) {
                    return 0;
                }
            }


            //cycle through extras with possible leveling up 
            for (uint256 i = 0; i < 1 + addExtraSlots; i++) {
                uint256 slotIdx = 8 + i * 2;

                //check that extra level is valid - not above the MAX level possible for the specific extra
                if (uint8(params[slotIdx + 1]) >= mergeP.traitsLevelsCut[7][uint8(params[slotIdx])].length) {
                    return 0; //false
                }
                
                if (mergeP.traitsLevelsCut[7][uint8(params[slotIdx])].length > 1) {
                    levelCut = mergeP.traitsLevelsCut[7][uint8(params[slotIdx])][uint8(params[slotIdx + 1])];
                    
                    // check if you have enough points on this trait
                    if (rarityCount[i + 6] < levelCut) { 
                       return 0;
                    }                  
                    
                }
                else { //this is for unique traits that are not possible to level up 
                    //check that the level is 0 and that there is one available
                    if (rarityCount[i + 6] == 0 || params[slotIdx + 1] > 0) {
                        return 0;
                    }
                }
                
                
            }
            
        }
        // if all the checks pass you get here and return the totScore
        return totScore;
    }

    function checkHeroValidity(uint256 heroId) external view returns (uint256){
        uint16[] memory soulsLocked = locker.getSoulsInHero(heroId);
       
        heroParams memory currentHero = heroStorage.getData(heroId);
        
        return checkParamsValidity(heroId, soulsLocked, currentHero.params);

    }

    function getHeroScore(uint256 heroId) external view returns (uint256){
        uint256 totScore;
        uint16[] memory tokenId = locker.getSoulsInHero(heroId);

        // block to count score
        {
            // loadAllcharacters in one go
            bytes[4] memory allData = [
                SSTORE2.read(pointers[0]), 
                SSTORE2.read(pointers[1]), 
                SSTORE2.read(pointers[2]), 
                SSTORE2.read(pointers[3])
            ];

            //count the heroId first
            uint256 idx = (heroId - 1) % 3000 * 8;
            uint256 ptr = (heroId - 1) / 3000;

            // checks anime vs spirit multiplier
            uint256 multiplier = heroId <= 1573 ? 20 : 1;

            //starts the count with the token associated with heroId
            totScore += uint8(allData[ptr][idx]) * multiplier;

            // add the score for each token contained
            for (uint256 i = 0; i < tokenId.length ; i++){

                idx = (tokenId[i] - 1) % 3000 * 8;
                ptr = (tokenId[i] - 1) / 3000;

                multiplier = tokenId[i] <= 1573 ? 20 : 1;

                totScore += uint8(allData[ptr][idx]) * multiplier;

            }
        }

        return totScore;
    }

}

///////////////////////
// CUSTOM URI CONTRACT
///////////////////////

interface IMergerURI {
    function checkHeroValidity(uint256 heroId) external view returns (uint256);
}

contract TokenURICustom {
    // Merger Interface
    IMergerURI public merger;

    // Hero Data Storage 
    HeroDataStorage public heroStorage;

    string public baseURI = "https://leanime.art/heroes/metadata/";

    string public heroURI = "https://api.leanime.art/heroes/metadata/";

    constructor(address mergerAddress_, address heroStorage_) {
        merger = IMergerURI(mergerAddress_);
        heroStorage = HeroDataStorage(heroStorage_);
    }

    function constructTokenURI(uint256 tokenId) external view returns (string memory) {
        string memory str = "H";

        uint256 heroId = tokenId - 100000;
        
        // minimal hero parameters
        uint256 score = merger.checkHeroValidity(heroId);
        
        if (score > 0) {
            str = string(abi.encodePacked(Strings.toString(heroId), "S" , Strings.toString(score), str));
            heroParams memory dataHero = heroStorage.getData(heroId);
            
            
            bytes memory params = dataHero.params;

            for (uint256 i = 0; i < params.length; i++){
                str = string(abi.encodePacked(str, itoh8(uint8(params[i]))));
            }
            
            //fixed BG
            str = string(abi.encodePacked(str, "G"));
            str = string(abi.encodePacked(str, itoh8(dataHero.visibleBG)));
            
            
            str = string(abi.encodePacked(heroURI, str));
        }
        else {
            str = string(abi.encodePacked(baseURI, Strings.toString(tokenId)));
        }
        return str;
    }
    
    // convert uint8 into hex string
    function itoh8(uint8 x) private pure returns (string memory) {
        if (x > 0) {
            string memory str;
            
            str = string(abi.encodePacked(uint8(x % 16 + (x % 16 < 10 ? 48 : 87)), str));
            x /= 16;
            str = string(abi.encodePacked(uint8(x % 16 + (x % 16 < 10 ? 48 : 87)), str));
            
            return str;
        }
        return "00";
    }

}

File 2 of 8 : IERC721Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC721.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Metadata is IERC721 {
    /**
     * @dev Returns the token collection name.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the token collection symbol.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

File 3 of 8 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 4 of 8 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }
}

File 5 of 8 : SSTORE2.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Read and write to persistent storage at a fraction of the cost.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/SSTORE2.sol)
/// @author Modified from 0xSequence (https://github.com/0xSequence/sstore2/blob/master/contracts/SSTORE2.sol)
library SSTORE2 {
    uint256 internal constant DATA_OFFSET = 1; // We skip the first byte as it's a STOP opcode to ensure the contract can't be called.

    /*//////////////////////////////////////////////////////////////
                               WRITE LOGIC
    //////////////////////////////////////////////////////////////*/

    function write(bytes memory data) internal returns (address pointer) {
        // Prefix the bytecode with a STOP opcode to ensure it cannot be called.
        bytes memory runtimeCode = abi.encodePacked(hex"00", data);

        bytes memory creationCode = abi.encodePacked(
            //---------------------------------------------------------------------------------------------------------------//
            // Opcode  | Opcode + Arguments  | Description  | Stack View                                                     //
            //---------------------------------------------------------------------------------------------------------------//
            // 0x60    |  0x600B             | PUSH1 11     | codeOffset                                                     //
            // 0x59    |  0x59               | MSIZE        | 0 codeOffset                                                   //
            // 0x81    |  0x81               | DUP2         | codeOffset 0 codeOffset                                        //
            // 0x38    |  0x38               | CODESIZE     | codeSize codeOffset 0 codeOffset                               //
            // 0x03    |  0x03               | SUB          | (codeSize - codeOffset) 0 codeOffset                           //
            // 0x80    |  0x80               | DUP          | (codeSize - codeOffset) (codeSize - codeOffset) 0 codeOffset   //
            // 0x92    |  0x92               | SWAP3        | codeOffset (codeSize - codeOffset) 0 (codeSize - codeOffset)   //
            // 0x59    |  0x59               | MSIZE        | 0 codeOffset (codeSize - codeOffset) 0 (codeSize - codeOffset) //
            // 0x39    |  0x39               | CODECOPY     | 0 (codeSize - codeOffset)                                      //
            // 0xf3    |  0xf3               | RETURN       |                                                                //
            //---------------------------------------------------------------------------------------------------------------//
            hex"60_0B_59_81_38_03_80_92_59_39_F3", // Returns all code in the contract except for the first 11 (0B in hex) bytes.
            runtimeCode // The bytecode we want the contract to have after deployment. Capped at 1 byte less than the code size limit.
        );

        assembly {
            // Deploy a new contract with the generated creation code.
            // We start 32 bytes into the code to avoid copying the byte length.
            pointer := create(0, add(creationCode, 32), mload(creationCode))
        }

        require(pointer != address(0), "DEPLOYMENT_FAILED");
    }

    /*//////////////////////////////////////////////////////////////
                               READ LOGIC
    //////////////////////////////////////////////////////////////*/

    function read(address pointer) internal view returns (bytes memory) {
        return readBytecode(pointer, DATA_OFFSET, pointer.code.length - DATA_OFFSET);
    }

    function read(address pointer, uint256 start) internal view returns (bytes memory) {
        start += DATA_OFFSET;

        return readBytecode(pointer, start, pointer.code.length - start);
    }

    function read(
        address pointer,
        uint256 start,
        uint256 end
    ) internal view returns (bytes memory) {
        start += DATA_OFFSET;
        end += DATA_OFFSET;

        require(pointer.code.length >= end, "OUT_OF_BOUNDS");

        return readBytecode(pointer, start, end - start);
    }

    /*//////////////////////////////////////////////////////////////
                          INTERNAL HELPER LOGIC
    //////////////////////////////////////////////////////////////*/

    function readBytecode(
        address pointer,
        uint256 start,
        uint256 size
    ) private view returns (bytes memory data) {
        assembly {
            // Get a pointer to some free memory.
            data := mload(0x40)

            // Update the free memory pointer to prevent overriding our data.
            // We use and(x, not(31)) as a cheaper equivalent to sub(x, mod(x, 32)).
            // Adding 31 to size and running the result through the logic above ensures
            // the memory pointer remains word-aligned, following the Solidity convention.
            mstore(0x40, add(data, and(add(add(size, 32), 31), not(31))))

            // Store the size of the data in the first 32 byte chunk of free memory.
            mstore(data, size)

            // Copy the code into memory right after the 32 bytes we used to store the size.
            extcodecopy(pointer, add(data, 32), start, size)
        }
    }
}

File 6 of 8 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

File 7 of 8 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

File 8 of 8 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

Settings
{
  "remappings": [
    "@openzeppelin/=lib/openzeppelin-contracts/",
    "@rari-capital/solmate/=lib/solmate/",
    "ds-test/=lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "solmate/=lib/solmate/src/",
    "src/=src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london"
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"wrapperAddress_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"heroId","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"tokenId","type":"uint256[]"}],"name":"DepositedSouls","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"mainHeroId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"mergedHeroId","type":"uint256"}],"name":"MergedHeroes","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"heroId","type":"uint256"}],"name":"ReleasedAllSouls","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"heroId","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"index","type":"uint256[]"}],"name":"ReleasedSouls","type":"event"},{"inputs":[],"name":"activateMergeHeroes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"activateMergeHeroesBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"activateWithdrawSoulBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxMergeUnits_","type":"uint256"}],"name":"changeMaxMergeUnits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"closeUpdateMerger","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"closedMergerUpdate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"heroId","type":"uint256"},{"internalType":"uint256[]","name":"tokenId","type":"uint256[]"}],"name":"depositSoulsBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"heroId","type":"uint256"},{"internalType":"uint256[]","name":"tokenId","type":"uint256[]"}],"name":"depositSoulsBatchHeroes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"tokenId","type":"uint256[]"}],"name":"emergencyRecoverBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyRevoked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"heroId","type":"uint256"}],"name":"getSoulsInHero","outputs":[{"internalType":"uint16[]","name":"","type":"uint16[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isMergeHeroesActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isMergeHeroesBatchActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isWithdrawSoulsBatchActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxMergeUnits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"mainHeroId","type":"uint256"},{"internalType":"uint256","name":"mergedHeroId","type":"uint256"}],"name":"mergeHeroes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"merger","outputs":[{"internalType":"contract IMerger","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"revokeEmergency","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"soulsInHero","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"mergerAddress_","type":"address"}],"name":"updateMerger","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"heroId","type":"uint256"},{"internalType":"uint256[]","name":"index","type":"uint256[]"}],"name":"withdrawSoulsBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"heroId","type":"uint256"}],"name":"withdrawSoulsBatchAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wrapper","outputs":[{"internalType":"contract IWrapper","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60806040526002805460ff60a01b191690556103e86004556005805463ffffffff191690553480156200003157600080fd5b50604051620021fd380380620021fd8339810160408190526200005491620000d5565b6200005f3362000085565b600180546001600160a01b0319166001600160a01b039290921691909117905562000107565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600060208284031215620000e857600080fd5b81516001600160a01b03811681146200010057600080fd5b9392505050565b6120e680620001176000396000f3fe608060405234801561001057600080fd5b506004361061018e5760003560e01c80639e33bbcb116100de578063dbf97b5e11610097578063f2fde38b11610071578063f2fde38b14610345578063f61917c214610358578063f6f6b23f1461036c578063f76946af1461037f57600080fd5b8063dbf97b5e14610312578063deb0d0311461031f578063f2f475d91461033257600080fd5b80639e33bbcb1461028e5780639fa9eb10146102a1578063ac210cc7146102b5578063af6d8942146102c8578063d75726f3146102db578063d7ab38c0146102f257600080fd5b80636caeb5e01161014b5780638afe0e67116101255780638afe0e671461023b5780638da5cb5b1461024e5780639804fa34146102735780639a2dec661461028657600080fd5b80636caeb5e014610218578063715018a61461022b5780638938a3151461023357600080fd5b80630a99fc591461019357806324aa95ec146101ba5780632be89cfd146101c45780632e8d7a24146101d757806347cc4dec146101fd5780636262f7de14610210575b600080fd5b6005546101a590610100900460ff1681565b60405190151581526020015b60405180910390f35b6101c2610387565b005b6101c26101d2366004611d68565b6103cf565b6101ea6101e5366004611db4565b61097b565b60405161ffff90911681526020016101b1565b6101c261020b366004611d68565b6109c2565b6101c2610cd6565b6101c2610226366004611d68565b610d13565b6101c2611190565b6101c26111c6565b6101c2610249366004611deb565b611201565b6000546001600160a01b03165b6040516001600160a01b0390911681526020016101b1565b6101c2610281366004611e0f565b611297565b6101c2611310565b60025461025b906001600160a01b031681565b6002546101a590600160a01b900460ff1681565b60015461025b906001600160a01b031681565b6101c26102d6366004611e0f565b61134f565b6102e460045481565b6040519081526020016101b1565b610305610300366004611e0f565b6115f9565b6040516101b19190611e28565b6005546101a59060ff1681565b6101c261032d366004611e70565b611683565b6101c2610340366004611db4565b611774565b6101c2610353366004611deb565b611bbf565b6005546101a5906301000000900460ff1681565b6005546101a59062010000900460ff1681565b6101c2611c5a565b6000546001600160a01b031633146103ba5760405162461bcd60e51b81526004016103b190611eac565b60405180910390fd5b6005805463ff00000019166301000000179055565b60055462010000900460ff166104275760405162461bcd60e51b815260206004820152601b60248201527f4261746368207769746864726177616c206e6f7420616374697665000000000060448201526064016103b1565b6001546001600160a01b0316636352211e610445620186a086611ef7565b6040518263ffffffff1660e01b815260040161046391815260200190565b602060405180830381865afa158015610480573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a49190611f0f565b6001600160a01b0316336001600160a01b0316146104d45760405162461bcd60e51b81526004016103b190611f2c565b600083815260036020526040812060015490916001600160a01b03909116906323b872dd9030903390620186a0908690899089908161051557610515611f53565b905060200201358154811061052c5761052c611f53565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff1661055e9190611ef7565b6040518463ffffffff1660e01b815260040161057c93929190611f69565b600060405180830381600087803b15801561059657600080fd5b505af11580156105aa573d6000803e3d6000fd5b505082548392506105be9150600190611f8d565b815481106105ce576105ce611f53565b90600052602060002090601091828204019190066002029054906101000a900461ffff16818484600081811061060657610606611f53565b905060200201358154811061061d5761061d611f53565b90600052602060002090601091828204019190066002026101000a81548161ffff021916908361ffff1602179055508080548061065c5761065c611fa4565b600082815260209020601060001990920191820401805461ffff6002600f8516026101000a0219169055905560015b828110156108ca5783836106a0600184611f8d565b8181106106af576106af611f53565b905060200201358484838181106106c8576106c8611f53565b905060200201351061071c5760405162461bcd60e51b815260206004820152601760248201527f6e6f7420696e2064657363656e64696e67206f7264657200000000000000000060448201526064016103b1565b6001546001600160a01b03166323b872dd3033620186a08689898881811061074657610746611f53565b905060200201358154811061075d5761075d611f53565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff1661078f9190611ef7565b6040518463ffffffff1660e01b81526004016107ad93929190611f69565b600060405180830381600087803b1580156107c757600080fd5b505af11580156107db573d6000803e3d6000fd5b505083548492506107ef9150600190611f8d565b815481106107ff576107ff611f53565b90600052602060002090601091828204019190066002029054906101000a900461ffff168285858481811061083657610836611f53565b905060200201358154811061084d5761084d611f53565b90600052602060002090601091828204019190066002026101000a81548161ffff021916908361ffff1602179055508180548061088c5761088c611fa4565b600082815260209020601060001990920191820401805461ffff6002600f8516026101000a02191690559055806108c281611fba565b91505061068b565b506002546001600160a01b03161561093b576002546040516301becc5d60e31b8152600481018690526001600160a01b0390911690630df662e890602401600060405180830381600087803b15801561092257600080fd5b505af1158015610936573d6000803e3d6000fd5b505050505b837fb38147929605e18bdb9a280f444623532fb781505521ae2683a236440093959b848460405161096d929190612009565b60405180910390a250505050565b6003602052816000526040600020818154811061099757600080fd5b9060005260206000209060109182820401919006600202915091509054906101000a900461ffff1681565b6001546001600160a01b0316636352211e6109e0620186a086611ef7565b6040518263ffffffff1660e01b81526004016109fe91815260200190565b602060405180830381865afa158015610a1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a3f9190611f0f565b6001600160a01b0316336001600160a01b031614610a6f5760405162461bcd60e51b81526004016103b190611f2c565b600083815260036020526040812054610a89906001611ef7565b600454909150610a998383611ef7565b1115610ab75760405162461bcd60e51b81526004016103b190612025565b600154604051632afa472360e11b81526001600160a01b03909116906355f48e4690610aed90339030908890889060040161204e565b600060405180830381600087803b158015610b0757600080fd5b505af1158015610b1b573d6000803e3d6000fd5b5060009250829150505b83811015610c2457620186a0858583818110610b4357610b43611f53565b90506020020135610b549190611f8d565b91508161ffff168603610b795760405162461bcd60e51b81526004016103b190612085565b61ffff821660009081526003602052604090205415610bce5760405162461bcd60e51b815260206004820152601160248201527043616e6e6f74206164642061206865726f60781b60448201526064016103b1565b600086815260036020908152604082208054600181018255908352912060108204018054600f9092166002026101000a61ffff818102199093169285160291909117905580610c1c81611fba565b915050610b25565b506002546001600160a01b031615610c95576002546040516301e0d93560e11b8152600481018790526001600160a01b03909116906303c1b26a90602401600060405180830381600087803b158015610c7c57600080fd5b505af1158015610c90573d6000803e3d6000fd5b505050505b847f8aad8a967a62aa86c2c3fb972b80bb1a235e22527aa4ea78a91b340e407e066e8585604051610cc7929190612009565b60405180910390a25050505050565b6000546001600160a01b03163314610d005760405162461bcd60e51b81526004016103b190611eac565b6005805462ff0000191662010000179055565b600554610100900460ff16610d6a5760405162461bcd60e51b815260206004820152601b60248201527f4865726f206261746368206d65726765206e6f7420616374697665000000000060448201526064016103b1565b6001546001600160a01b0316636352211e610d88620186a086611ef7565b6040518263ffffffff1660e01b8152600401610da691815260200190565b602060405180830381865afa158015610dc3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610de79190611f0f565b6001600160a01b0316336001600160a01b031614610e175760405162461bcd60e51b81526004016103b190611f2c565b600154604051632afa472360e11b81526001600160a01b03909116906355f48e4690610e4d90339030908790879060040161204e565b600060405180830381600087803b158015610e6757600080fd5b505af1158015610e7b573d6000803e3d6000fd5b5060009250829150505b828110156110b257620186a0848483818110610ea357610ea3611f53565b90506020020135610eb49190611f8d565b91508161ffff168503610ed95760405162461bcd60e51b81526004016103b190612085565b61ffff82166000908152600360205260408120549003610f3c57600085815260036020908152604082208054600181018255908352912060108204018054600f9092166002026101000a61ffff81810219909316928516029190911790556110a0565b600085815260036020908152604080832080546001810182559084528284206010820401805461ffff8089166002600f909516949094026101000a848102910219909116179055835280832080548251818502810185019093528083529192909190830182828015610ff557602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411610fbc5790505b5050505050905060005b8151811015611081576000878152600360205260409020825183908390811061102a5761102a611f53565b602090810291909101810151825460018101845560009384529190922060108204018054600f9092166002026101000a61ffff8181021990931692909316929092021790558061107981611fba565b915050610fff565b5061ffff8316600090815260036020526040812061109e91611ce3565b505b806110aa81611fba565b915050610e85565b506004546000858152600360205260409020546110d0906001611ef7565b11156110ee5760405162461bcd60e51b81526004016103b190612025565b6002546001600160a01b03161561115e576002546040516301e0d93560e11b8152600481018690526001600160a01b03909116906303c1b26a90602401600060405180830381600087803b15801561114557600080fd5b505af1158015611159573d6000803e3d6000fd5b505050505b837f8aad8a967a62aa86c2c3fb972b80bb1a235e22527aa4ea78a91b340e407e066e848460405161096d929190612009565b6000546001600160a01b031633146111ba5760405162461bcd60e51b81526004016103b190611eac565b6111c46000611c93565b565b6000546001600160a01b031633146111f05760405162461bcd60e51b81526004016103b190611eac565b6005805461ff001916610100179055565b6000546001600160a01b0316331461122b5760405162461bcd60e51b81526004016103b190611eac565b600254600160a01b900460ff16156112755760405162461bcd60e51b815260206004820152600d60248201526c155c19185d194810db1bdcd959609a1b60448201526064016103b1565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031633146112c15760405162461bcd60e51b81526004016103b190611eac565b600254600160a01b900460ff161561130b5760405162461bcd60e51b815260206004820152600d60248201526c155c19185d194810db1bdcd959609a1b60448201526064016103b1565b600455565b6000546001600160a01b0316331461133a5760405162461bcd60e51b81526004016103b190611eac565b6002805460ff60a01b1916600160a01b179055565b6001546001600160a01b0316636352211e61136d620186a084611ef7565b6040518263ffffffff1660e01b815260040161138b91815260200190565b602060405180830381865afa1580156113a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113cc9190611f0f565b6001600160a01b0316336001600160a01b0316146113fc5760405162461bcd60e51b81526004016103b190611f2c565b60008181526003602090815260408083208054825181850281018501909352808352919290919083018282801561147a57602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff16815260200190600201906020826001010492830192600103820291508084116114415790505b5050505050905060005b815181101561154257600160009054906101000a90046001600160a01b03166001600160a01b03166323b872dd3033620186a08686815181106114c9576114c9611f53565b602002602001015161ffff166114df9190611ef7565b6040518463ffffffff1660e01b81526004016114fd93929190611f69565b600060405180830381600087803b15801561151757600080fd5b505af115801561152b573d6000803e3d6000fd5b50505050808061153a90611fba565b915050611484565b50600082815260036020526040812061155a91611ce3565b6002546001600160a01b0316156115ca5760025460405163725e485d60e11b8152600481018490526001600160a01b039091169063e4bc90ba90602401600060405180830381600087803b1580156115b157600080fd5b505af11580156115c5573d6000803e3d6000fd5b505050505b60405182907f066eddc175e2bf3b3265d0d0b49dd427a3ea9a3cb1fa68d4e5740ff47e21f0ae90600090a25050565b60008181526003602090815260409182902080548351818402810184019094528084526060939283018282801561167757602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff168152602001906002019060208260010104928301926001038202915080841161163e5790505b50505050509050919050565b6000546001600160a01b031633146116ad5760405162461bcd60e51b81526004016103b190611eac565b6005546301000000900460ff16156117075760405162461bcd60e51b815260206004820152601760248201527f456d657267656e637920706f776572207265766f6b656400000000000000000060448201526064016103b1565b600154604051632afa472360e11b81526001600160a01b03909116906355f48e469061173d90309087908790879060040161204e565b600060405180830381600087803b15801561175757600080fd5b505af115801561176b573d6000803e3d6000fd5b50505050505050565b60055460ff166117be5760405162461bcd60e51b81526020600482015260156024820152744865726f206d65726765206e6f742061637469766560581b60448201526064016103b1565b8082036117dd5760405162461bcd60e51b81526004016103b190612085565b6001546001600160a01b0316636352211e6117fb620186a085611ef7565b6040518263ffffffff1660e01b815260040161181991815260200190565b602060405180830381865afa158015611836573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061185a9190611f0f565b6001600160a01b0316336001600160a01b03161461188a5760405162461bcd60e51b81526004016103b190611f2c565b6001546001600160a01b0316636352211e6118a8620186a084611ef7565b6040518263ffffffff1660e01b81526004016118c691815260200190565b602060405180830381865afa1580156118e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119079190611f0f565b6001600160a01b0316336001600160a01b0316146119375760405162461bcd60e51b81526004016103b190611f2c565b600082815260036020908152604080832084845281842080548351818602810186019094528084529194939091908301828280156119bc57602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff16815260200190600201906020826001010492830192600103820291508084116119835790505b505050505090506004548151838054905060016119d99190611ef7565b6119e39190611ef7565b6119ee906001611ef7565b1115611a0c5760405162461bcd60e51b81526004016103b190612025565b6001546001600160a01b03166323b872dd3330611a2c620186a088611ef7565b6040518463ffffffff1660e01b8152600401611a4a93929190611f69565b600060405180830381600087803b158015611a6457600080fd5b505af1158015611a78573d6000803e3d6000fd5b5050835460018101855560008581526020812060108304018054600f9093166002026101000a61ffff8181021990941693891602929092179091559150505b8151811015611b2a5782828281518110611ad357611ad3611f53565b602090810291909101810151825460018101845560009384529190922060108204018054600f9092166002026101000a61ffff81810219909316929093169290920217905580611b2281611fba565b915050611ab7565b506000838152600360205260408120611b4291611ce3565b6002546001600160a01b031615611bb9576002546040516328c7dc4f60e11b815260048101869052602481018590526001600160a01b039091169063518fb89e90604401600060405180830381600087803b158015611ba057600080fd5b505af1158015611bb4573d6000803e3d6000fd5b505050505b50505050565b6000546001600160a01b03163314611be95760405162461bcd60e51b81526004016103b190611eac565b6001600160a01b038116611c4e5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016103b1565b611c5781611c93565b50565b6000546001600160a01b03163314611c845760405162461bcd60e51b81526004016103b190611eac565b6005805460ff19166001179055565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b50805460008255600f016010900490600052602060002090810190611c5791905b80821115611d185760008155600101611d04565b5090565b60008083601f840112611d2e57600080fd5b50813567ffffffffffffffff811115611d4657600080fd5b6020830191508360208260051b8501011115611d6157600080fd5b9250929050565b600080600060408486031215611d7d57600080fd5b83359250602084013567ffffffffffffffff811115611d9b57600080fd5b611da786828701611d1c565b9497909650939450505050565b60008060408385031215611dc757600080fd5b50508035926020909101359150565b6001600160a01b0381168114611c5757600080fd5b600060208284031215611dfd57600080fd5b8135611e0881611dd6565b9392505050565b600060208284031215611e2157600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b81811015611e6457835161ffff1683529284019291840191600101611e44565b50909695505050505050565b600080600060408486031215611e8557600080fd5b8335611e9081611dd6565b9250602084013567ffffffffffffffff811115611d9b57600080fd5b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052601160045260246000fd5b60008219821115611f0a57611f0a611ee1565b500190565b600060208284031215611f2157600080fd5b8151611e0881611dd6565b6020808252600d908201526c2737ba103a34329037bbb732b960991b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b039384168152919092166020820152604081019190915260600190565b600082821015611f9f57611f9f611ee1565b500390565b634e487b7160e01b600052603160045260246000fd5b600060018201611fcc57611fcc611ee1565b5060010190565b81835260006001600160fb1b03831115611fec57600080fd5b8260051b8083602087013760009401602001938452509192915050565b60208152600061201d602083018486611fd3565b949350505050565b6020808252600f908201526e04d617820756e6974733a203130303608c1b604082015260600190565b6001600160a01b0385811682528416602082015260606040820181905260009061207b9083018486611fd3565b9695505050505050565b60208082526011908201527021b0b73737ba1030b2321034ba39b2b63360791b60408201526060019056fea2646970667358221220457164a5b44cc9754d503e2bc5ceabd7b5d7333bf950e423114c4d6e53a1713564736f6c634300080d003300000000000000000000000003bebcf3d62c1e7465f8a095bfa08a79ca2892a1

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061018e5760003560e01c80639e33bbcb116100de578063dbf97b5e11610097578063f2fde38b11610071578063f2fde38b14610345578063f61917c214610358578063f6f6b23f1461036c578063f76946af1461037f57600080fd5b8063dbf97b5e14610312578063deb0d0311461031f578063f2f475d91461033257600080fd5b80639e33bbcb1461028e5780639fa9eb10146102a1578063ac210cc7146102b5578063af6d8942146102c8578063d75726f3146102db578063d7ab38c0146102f257600080fd5b80636caeb5e01161014b5780638afe0e67116101255780638afe0e671461023b5780638da5cb5b1461024e5780639804fa34146102735780639a2dec661461028657600080fd5b80636caeb5e014610218578063715018a61461022b5780638938a3151461023357600080fd5b80630a99fc591461019357806324aa95ec146101ba5780632be89cfd146101c45780632e8d7a24146101d757806347cc4dec146101fd5780636262f7de14610210575b600080fd5b6005546101a590610100900460ff1681565b60405190151581526020015b60405180910390f35b6101c2610387565b005b6101c26101d2366004611d68565b6103cf565b6101ea6101e5366004611db4565b61097b565b60405161ffff90911681526020016101b1565b6101c261020b366004611d68565b6109c2565b6101c2610cd6565b6101c2610226366004611d68565b610d13565b6101c2611190565b6101c26111c6565b6101c2610249366004611deb565b611201565b6000546001600160a01b03165b6040516001600160a01b0390911681526020016101b1565b6101c2610281366004611e0f565b611297565b6101c2611310565b60025461025b906001600160a01b031681565b6002546101a590600160a01b900460ff1681565b60015461025b906001600160a01b031681565b6101c26102d6366004611e0f565b61134f565b6102e460045481565b6040519081526020016101b1565b610305610300366004611e0f565b6115f9565b6040516101b19190611e28565b6005546101a59060ff1681565b6101c261032d366004611e70565b611683565b6101c2610340366004611db4565b611774565b6101c2610353366004611deb565b611bbf565b6005546101a5906301000000900460ff1681565b6005546101a59062010000900460ff1681565b6101c2611c5a565b6000546001600160a01b031633146103ba5760405162461bcd60e51b81526004016103b190611eac565b60405180910390fd5b6005805463ff00000019166301000000179055565b60055462010000900460ff166104275760405162461bcd60e51b815260206004820152601b60248201527f4261746368207769746864726177616c206e6f7420616374697665000000000060448201526064016103b1565b6001546001600160a01b0316636352211e610445620186a086611ef7565b6040518263ffffffff1660e01b815260040161046391815260200190565b602060405180830381865afa158015610480573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a49190611f0f565b6001600160a01b0316336001600160a01b0316146104d45760405162461bcd60e51b81526004016103b190611f2c565b600083815260036020526040812060015490916001600160a01b03909116906323b872dd9030903390620186a0908690899089908161051557610515611f53565b905060200201358154811061052c5761052c611f53565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff1661055e9190611ef7565b6040518463ffffffff1660e01b815260040161057c93929190611f69565b600060405180830381600087803b15801561059657600080fd5b505af11580156105aa573d6000803e3d6000fd5b505082548392506105be9150600190611f8d565b815481106105ce576105ce611f53565b90600052602060002090601091828204019190066002029054906101000a900461ffff16818484600081811061060657610606611f53565b905060200201358154811061061d5761061d611f53565b90600052602060002090601091828204019190066002026101000a81548161ffff021916908361ffff1602179055508080548061065c5761065c611fa4565b600082815260209020601060001990920191820401805461ffff6002600f8516026101000a0219169055905560015b828110156108ca5783836106a0600184611f8d565b8181106106af576106af611f53565b905060200201358484838181106106c8576106c8611f53565b905060200201351061071c5760405162461bcd60e51b815260206004820152601760248201527f6e6f7420696e2064657363656e64696e67206f7264657200000000000000000060448201526064016103b1565b6001546001600160a01b03166323b872dd3033620186a08689898881811061074657610746611f53565b905060200201358154811061075d5761075d611f53565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff1661078f9190611ef7565b6040518463ffffffff1660e01b81526004016107ad93929190611f69565b600060405180830381600087803b1580156107c757600080fd5b505af11580156107db573d6000803e3d6000fd5b505083548492506107ef9150600190611f8d565b815481106107ff576107ff611f53565b90600052602060002090601091828204019190066002029054906101000a900461ffff168285858481811061083657610836611f53565b905060200201358154811061084d5761084d611f53565b90600052602060002090601091828204019190066002026101000a81548161ffff021916908361ffff1602179055508180548061088c5761088c611fa4565b600082815260209020601060001990920191820401805461ffff6002600f8516026101000a02191690559055806108c281611fba565b91505061068b565b506002546001600160a01b03161561093b576002546040516301becc5d60e31b8152600481018690526001600160a01b0390911690630df662e890602401600060405180830381600087803b15801561092257600080fd5b505af1158015610936573d6000803e3d6000fd5b505050505b837fb38147929605e18bdb9a280f444623532fb781505521ae2683a236440093959b848460405161096d929190612009565b60405180910390a250505050565b6003602052816000526040600020818154811061099757600080fd5b9060005260206000209060109182820401919006600202915091509054906101000a900461ffff1681565b6001546001600160a01b0316636352211e6109e0620186a086611ef7565b6040518263ffffffff1660e01b81526004016109fe91815260200190565b602060405180830381865afa158015610a1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a3f9190611f0f565b6001600160a01b0316336001600160a01b031614610a6f5760405162461bcd60e51b81526004016103b190611f2c565b600083815260036020526040812054610a89906001611ef7565b600454909150610a998383611ef7565b1115610ab75760405162461bcd60e51b81526004016103b190612025565b600154604051632afa472360e11b81526001600160a01b03909116906355f48e4690610aed90339030908890889060040161204e565b600060405180830381600087803b158015610b0757600080fd5b505af1158015610b1b573d6000803e3d6000fd5b5060009250829150505b83811015610c2457620186a0858583818110610b4357610b43611f53565b90506020020135610b549190611f8d565b91508161ffff168603610b795760405162461bcd60e51b81526004016103b190612085565b61ffff821660009081526003602052604090205415610bce5760405162461bcd60e51b815260206004820152601160248201527043616e6e6f74206164642061206865726f60781b60448201526064016103b1565b600086815260036020908152604082208054600181018255908352912060108204018054600f9092166002026101000a61ffff818102199093169285160291909117905580610c1c81611fba565b915050610b25565b506002546001600160a01b031615610c95576002546040516301e0d93560e11b8152600481018790526001600160a01b03909116906303c1b26a90602401600060405180830381600087803b158015610c7c57600080fd5b505af1158015610c90573d6000803e3d6000fd5b505050505b847f8aad8a967a62aa86c2c3fb972b80bb1a235e22527aa4ea78a91b340e407e066e8585604051610cc7929190612009565b60405180910390a25050505050565b6000546001600160a01b03163314610d005760405162461bcd60e51b81526004016103b190611eac565b6005805462ff0000191662010000179055565b600554610100900460ff16610d6a5760405162461bcd60e51b815260206004820152601b60248201527f4865726f206261746368206d65726765206e6f7420616374697665000000000060448201526064016103b1565b6001546001600160a01b0316636352211e610d88620186a086611ef7565b6040518263ffffffff1660e01b8152600401610da691815260200190565b602060405180830381865afa158015610dc3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610de79190611f0f565b6001600160a01b0316336001600160a01b031614610e175760405162461bcd60e51b81526004016103b190611f2c565b600154604051632afa472360e11b81526001600160a01b03909116906355f48e4690610e4d90339030908790879060040161204e565b600060405180830381600087803b158015610e6757600080fd5b505af1158015610e7b573d6000803e3d6000fd5b5060009250829150505b828110156110b257620186a0848483818110610ea357610ea3611f53565b90506020020135610eb49190611f8d565b91508161ffff168503610ed95760405162461bcd60e51b81526004016103b190612085565b61ffff82166000908152600360205260408120549003610f3c57600085815260036020908152604082208054600181018255908352912060108204018054600f9092166002026101000a61ffff81810219909316928516029190911790556110a0565b600085815260036020908152604080832080546001810182559084528284206010820401805461ffff8089166002600f909516949094026101000a848102910219909116179055835280832080548251818502810185019093528083529192909190830182828015610ff557602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411610fbc5790505b5050505050905060005b8151811015611081576000878152600360205260409020825183908390811061102a5761102a611f53565b602090810291909101810151825460018101845560009384529190922060108204018054600f9092166002026101000a61ffff8181021990931692909316929092021790558061107981611fba565b915050610fff565b5061ffff8316600090815260036020526040812061109e91611ce3565b505b806110aa81611fba565b915050610e85565b506004546000858152600360205260409020546110d0906001611ef7565b11156110ee5760405162461bcd60e51b81526004016103b190612025565b6002546001600160a01b03161561115e576002546040516301e0d93560e11b8152600481018690526001600160a01b03909116906303c1b26a90602401600060405180830381600087803b15801561114557600080fd5b505af1158015611159573d6000803e3d6000fd5b505050505b837f8aad8a967a62aa86c2c3fb972b80bb1a235e22527aa4ea78a91b340e407e066e848460405161096d929190612009565b6000546001600160a01b031633146111ba5760405162461bcd60e51b81526004016103b190611eac565b6111c46000611c93565b565b6000546001600160a01b031633146111f05760405162461bcd60e51b81526004016103b190611eac565b6005805461ff001916610100179055565b6000546001600160a01b0316331461122b5760405162461bcd60e51b81526004016103b190611eac565b600254600160a01b900460ff16156112755760405162461bcd60e51b815260206004820152600d60248201526c155c19185d194810db1bdcd959609a1b60448201526064016103b1565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031633146112c15760405162461bcd60e51b81526004016103b190611eac565b600254600160a01b900460ff161561130b5760405162461bcd60e51b815260206004820152600d60248201526c155c19185d194810db1bdcd959609a1b60448201526064016103b1565b600455565b6000546001600160a01b0316331461133a5760405162461bcd60e51b81526004016103b190611eac565b6002805460ff60a01b1916600160a01b179055565b6001546001600160a01b0316636352211e61136d620186a084611ef7565b6040518263ffffffff1660e01b815260040161138b91815260200190565b602060405180830381865afa1580156113a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113cc9190611f0f565b6001600160a01b0316336001600160a01b0316146113fc5760405162461bcd60e51b81526004016103b190611f2c565b60008181526003602090815260408083208054825181850281018501909352808352919290919083018282801561147a57602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff16815260200190600201906020826001010492830192600103820291508084116114415790505b5050505050905060005b815181101561154257600160009054906101000a90046001600160a01b03166001600160a01b03166323b872dd3033620186a08686815181106114c9576114c9611f53565b602002602001015161ffff166114df9190611ef7565b6040518463ffffffff1660e01b81526004016114fd93929190611f69565b600060405180830381600087803b15801561151757600080fd5b505af115801561152b573d6000803e3d6000fd5b50505050808061153a90611fba565b915050611484565b50600082815260036020526040812061155a91611ce3565b6002546001600160a01b0316156115ca5760025460405163725e485d60e11b8152600481018490526001600160a01b039091169063e4bc90ba90602401600060405180830381600087803b1580156115b157600080fd5b505af11580156115c5573d6000803e3d6000fd5b505050505b60405182907f066eddc175e2bf3b3265d0d0b49dd427a3ea9a3cb1fa68d4e5740ff47e21f0ae90600090a25050565b60008181526003602090815260409182902080548351818402810184019094528084526060939283018282801561167757602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff168152602001906002019060208260010104928301926001038202915080841161163e5790505b50505050509050919050565b6000546001600160a01b031633146116ad5760405162461bcd60e51b81526004016103b190611eac565b6005546301000000900460ff16156117075760405162461bcd60e51b815260206004820152601760248201527f456d657267656e637920706f776572207265766f6b656400000000000000000060448201526064016103b1565b600154604051632afa472360e11b81526001600160a01b03909116906355f48e469061173d90309087908790879060040161204e565b600060405180830381600087803b15801561175757600080fd5b505af115801561176b573d6000803e3d6000fd5b50505050505050565b60055460ff166117be5760405162461bcd60e51b81526020600482015260156024820152744865726f206d65726765206e6f742061637469766560581b60448201526064016103b1565b8082036117dd5760405162461bcd60e51b81526004016103b190612085565b6001546001600160a01b0316636352211e6117fb620186a085611ef7565b6040518263ffffffff1660e01b815260040161181991815260200190565b602060405180830381865afa158015611836573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061185a9190611f0f565b6001600160a01b0316336001600160a01b03161461188a5760405162461bcd60e51b81526004016103b190611f2c565b6001546001600160a01b0316636352211e6118a8620186a084611ef7565b6040518263ffffffff1660e01b81526004016118c691815260200190565b602060405180830381865afa1580156118e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119079190611f0f565b6001600160a01b0316336001600160a01b0316146119375760405162461bcd60e51b81526004016103b190611f2c565b600082815260036020908152604080832084845281842080548351818602810186019094528084529194939091908301828280156119bc57602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff16815260200190600201906020826001010492830192600103820291508084116119835790505b505050505090506004548151838054905060016119d99190611ef7565b6119e39190611ef7565b6119ee906001611ef7565b1115611a0c5760405162461bcd60e51b81526004016103b190612025565b6001546001600160a01b03166323b872dd3330611a2c620186a088611ef7565b6040518463ffffffff1660e01b8152600401611a4a93929190611f69565b600060405180830381600087803b158015611a6457600080fd5b505af1158015611a78573d6000803e3d6000fd5b5050835460018101855560008581526020812060108304018054600f9093166002026101000a61ffff8181021990941693891602929092179091559150505b8151811015611b2a5782828281518110611ad357611ad3611f53565b602090810291909101810151825460018101845560009384529190922060108204018054600f9092166002026101000a61ffff81810219909316929093169290920217905580611b2281611fba565b915050611ab7565b506000838152600360205260408120611b4291611ce3565b6002546001600160a01b031615611bb9576002546040516328c7dc4f60e11b815260048101869052602481018590526001600160a01b039091169063518fb89e90604401600060405180830381600087803b158015611ba057600080fd5b505af1158015611bb4573d6000803e3d6000fd5b505050505b50505050565b6000546001600160a01b03163314611be95760405162461bcd60e51b81526004016103b190611eac565b6001600160a01b038116611c4e5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016103b1565b611c5781611c93565b50565b6000546001600160a01b03163314611c845760405162461bcd60e51b81526004016103b190611eac565b6005805460ff19166001179055565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b50805460008255600f016010900490600052602060002090810190611c5791905b80821115611d185760008155600101611d04565b5090565b60008083601f840112611d2e57600080fd5b50813567ffffffffffffffff811115611d4657600080fd5b6020830191508360208260051b8501011115611d6157600080fd5b9250929050565b600080600060408486031215611d7d57600080fd5b83359250602084013567ffffffffffffffff811115611d9b57600080fd5b611da786828701611d1c565b9497909650939450505050565b60008060408385031215611dc757600080fd5b50508035926020909101359150565b6001600160a01b0381168114611c5757600080fd5b600060208284031215611dfd57600080fd5b8135611e0881611dd6565b9392505050565b600060208284031215611e2157600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b81811015611e6457835161ffff1683529284019291840191600101611e44565b50909695505050505050565b600080600060408486031215611e8557600080fd5b8335611e9081611dd6565b9250602084013567ffffffffffffffff811115611d9b57600080fd5b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052601160045260246000fd5b60008219821115611f0a57611f0a611ee1565b500190565b600060208284031215611f2157600080fd5b8151611e0881611dd6565b6020808252600d908201526c2737ba103a34329037bbb732b960991b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b039384168152919092166020820152604081019190915260600190565b600082821015611f9f57611f9f611ee1565b500390565b634e487b7160e01b600052603160045260246000fd5b600060018201611fcc57611fcc611ee1565b5060010190565b81835260006001600160fb1b03831115611fec57600080fd5b8260051b8083602087013760009401602001938452509192915050565b60208152600061201d602083018486611fd3565b949350505050565b6020808252600f908201526e04d617820756e6974733a203130303608c1b604082015260600190565b6001600160a01b0385811682528416602082015260606040820181905260009061207b9083018486611fd3565b9695505050505050565b60208082526011908201527021b0b73737ba1030b2321034ba39b2b63360791b60408201526060019056fea2646970667358221220457164a5b44cc9754d503e2bc5ceabd7b5d7333bf950e423114c4d6e53a1713564736f6c634300080d0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000003bebcf3d62c1e7465f8a095bfa08a79ca2892a1

-----Decoded View---------------
Arg [0] : wrapperAddress_ (address): 0x03BEbcf3D62C1e7465f8a095BFA08a79CA2892A1

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000003bebcf3d62c1e7465f8a095bfa08a79ca2892a1


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.