ETH Price: $3,771.45 (+2.00%)

Contract

0x1B16b25dbdC8AE5775290101332A5e7379EecF9f
 

Overview

ETH Balance

0.821300582706383962 ETH

ETH Value

$3,097.49 (@ $3,771.45/ETH)

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Claim Payout816860622023-03-17 15:28:58434 days ago1679066938IN
0x1B16b25d...379EecF9f
0 ETH0.000000080.001
Claim Payout491169652022-12-13 22:31:35528 days ago1670970695IN
0x1B16b25d...379EecF9f
0 ETH0.000000080.001
Claim Payout464608262022-12-07 17:13:54534 days ago1670433234IN
0x1B16b25d...379EecF9f
0 ETH0.000000080.001
Claim Payout461756072022-12-07 0:37:21535 days ago1670373441IN
0x1B16b25d...379EecF9f
0 ETH0.000000080.001
Claim Payout457866522022-12-05 19:48:03536 days ago1670269683IN
0x1B16b25d...379EecF9f
0 ETH0.000000080.001
Claim Payout456878942022-12-05 13:56:55536 days ago1670248615IN
0x1B16b25d...379EecF9f
0 ETH0.000000080.001
Claim Payout453924002022-12-04 18:28:16537 days ago1670178496IN
0x1B16b25d...379EecF9f
0 ETH0.000000080.001
Claim Payout442219642022-12-01 10:10:54541 days ago1669889454IN
0x1B16b25d...379EecF9f
0 ETH0.000000080.001
Claim Payout440775972022-12-01 2:13:51541 days ago1669860831IN
0x1B16b25d...379EecF9f
0 ETH0.000000080.001
Claim Payout440436342022-11-30 23:37:32541 days ago1669851452IN
0x1B16b25d...379EecF9f
0 ETH0.000000080.001
Claim Payout439552762022-11-30 16:21:55541 days ago1669825315IN
0x1B16b25d...379EecF9f
0 ETH0.000000080.001
Claim Payout438772122022-11-30 12:13:03541 days ago1669810383IN
0x1B16b25d...379EecF9f
0 ETH0.000000020.001
Claim Payout438771882022-11-30 12:13:03541 days ago1669810383IN
0x1B16b25d...379EecF9f
0 ETH0.000000080.001
Claim Payout438172932022-11-30 8:57:23542 days ago1669798643IN
0x1B16b25d...379EecF9f
0 ETH0.000000080.001
Claim Payout436806972022-11-30 0:16:50542 days ago1669767410IN
0x1B16b25d...379EecF9f
0 ETH0.000000080.001
Claim Payout436642112022-11-29 21:54:23542 days ago1669758863IN
0x1B16b25d...379EecF9f
0 ETH0.000000080.001
Claim Payout436522632022-11-29 20:22:27542 days ago1669753347IN
0x1B16b25d...379EecF9f
0 ETH0.000000080.001
Claim Payout436489802022-11-29 19:57:10542 days ago1669751830IN
0x1B16b25d...379EecF9f
0 ETH0.000000080.001
Claim Payout436418632022-11-29 19:03:23542 days ago1669748603IN
0x1B16b25d...379EecF9f
0 ETH0.000000080.001
Claim Payout436323572022-11-29 18:02:44542 days ago1669744964IN
0x1B16b25d...379EecF9f
0 ETH0.000000080.001
Claim Payout436296052022-11-29 17:47:40542 days ago1669744060IN
0x1B16b25d...379EecF9f
0 ETH0.000000080.001
Claim Payout435937012022-11-29 14:58:45542 days ago1669733925IN
0x1B16b25d...379EecF9f
0 ETH0.000000080.001
Claim Payout435676532022-11-29 13:32:38542 days ago1669728758IN
0x1B16b25d...379EecF9f
0 ETH0.000000080.001
Claim Payout435659952022-11-29 13:26:38542 days ago1669728398IN
0x1B16b25d...379EecF9f
0 ETH0.000000080.001
Claim Payout435618132022-11-29 13:11:07542 days ago1669727467IN
0x1B16b25d...379EecF9f
0 ETH0.000000080.001
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To Value
816860622023-03-17 15:28:58434 days ago1679066938
0x1B16b25d...379EecF9f
0.00701534 ETH
491169652022-12-13 22:31:35528 days ago1670970695
0x1B16b25d...379EecF9f
0.01557714 ETH
464608262022-12-07 17:13:54534 days ago1670433234
0x1B16b25d...379EecF9f
0.00554033 ETH
461756072022-12-07 0:37:21535 days ago1670373441
0x1B16b25d...379EecF9f
0.02920927 ETH
457866522022-12-05 19:48:03536 days ago1670269683
0x1B16b25d...379EecF9f
0.40514685 ETH
456878942022-12-05 13:56:55536 days ago1670248615
0x1B16b25d...379EecF9f
0.01587387 ETH
453924002022-12-04 18:28:16537 days ago1670178496
0x1B16b25d...379EecF9f
0.00413451 ETH
442219642022-12-01 10:10:54541 days ago1669889454
0x1B16b25d...379EecF9f
0.16728695 ETH
440775972022-12-01 2:13:51541 days ago1669860831
0x1B16b25d...379EecF9f
0.00174957 ETH
440436342022-11-30 23:37:32541 days ago1669851452
0x1B16b25d...379EecF9f
0.02214702 ETH
439552762022-11-30 16:21:55541 days ago1669825315
0x1B16b25d...379EecF9f
0.04839698 ETH
438771882022-11-30 12:13:03541 days ago1669810383
0x1B16b25d...379EecF9f
0.03349184 ETH
438172932022-11-30 8:57:23542 days ago1669798643
0x1B16b25d...379EecF9f
0.07562807 ETH
436806972022-11-30 0:16:50542 days ago1669767410
0x1B16b25d...379EecF9f
0.0042371 ETH
436642112022-11-29 21:54:23542 days ago1669758863
0x1B16b25d...379EecF9f
0.13124058 ETH
436522632022-11-29 20:22:27542 days ago1669753347
0x1B16b25d...379EecF9f
0.00116638 ETH
436489802022-11-29 19:57:10542 days ago1669751830
0x1B16b25d...379EecF9f
0.020385 ETH
436418632022-11-29 19:03:23542 days ago1669748603
0x1B16b25d...379EecF9f
0.11822164 ETH
436323572022-11-29 18:02:44542 days ago1669744964
0x1B16b25d...379EecF9f
0.08485901 ETH
436296052022-11-29 17:47:40542 days ago1669744060
0x1B16b25d...379EecF9f
0.00462454 ETH
435937012022-11-29 14:58:45542 days ago1669733925
0x1B16b25d...379EecF9f
0.01769184 ETH
435676532022-11-29 13:32:38542 days ago1669728758
0x1B16b25d...379EecF9f
0.06022719 ETH
435659952022-11-29 13:26:38542 days ago1669728398
0x1B16b25d...379EecF9f
0.02342607 ETH
435618132022-11-29 13:11:07542 days ago1669727467
0x1B16b25d...379EecF9f
0.13782614 ETH
435534582022-11-29 12:40:21542 days ago1669725621
0x1B16b25d...379EecF9f
0.01649172 ETH
View All Internal Transactions

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
BoardSystem

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
default evmVersion
File 1 of 31 : BoardSystem.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.0;
import "solecs/System.sol";
import {IWorld} from "solecs/interfaces/IWorld.sol";
import {getAddressById} from "solecs/utils.sol";
import {TileComponent, ID as TileComponentID} from "../components/TileComponent.sol";
import {ScoreComponent, ID as ScoreComponentID} from "../components/ScoreComponent.sol";
import {LetterCountComponent, ID as LetterCountComponentID} from "../components/LetterCountComponent.sol";
import {Letter} from "../common/Letter.sol";
import {Tile} from "../common/Tile.sol";
import {Score} from "../common/Score.sol";
import {Direction, Bounds, Position} from "../common/Play.sol";
import {LinearVRGDA} from "../vrgda/LinearVRGDA.sol";
import {toDaysWadUnsafe} from "solmate/utils/SignedWadMath.sol";
import {LibBoard} from "../libraries/LibBoard.sol";
import "../common/Errors.sol";

uint256 constant ID = uint256(keccak256("system.Board"));

/// @title Game Board System for Words3
/// @author Small Brain Games
/// @notice Logic for placing words, scoring points, and claiming winnings
contract BoardSystem is System, LinearVRGDA {
    /// ============ Immutable Storage ============

    /// @notice Target price for a token, to be scaled according to sales pace.
    int256 public immutable vrgdaTargetPrice = 5e14;
    /// @notice The percent price decays per unit of time with no sales, scaled by 1e18.
    int256 public immutable vrgdaPriceDecayPercent = 0.77e18;
    /// @notice The number of tokens to target selling in 1 full unit of time, scaled by 1e18.
    int256 public immutable vrgdaPerTimeUnit = 20e18;
    /// @notice Start time for vrgda calculations
    uint256 public immutable startTime = block.timestamp;

    /// @notice End time for game end
    uint256 public immutable endTime = block.timestamp + 86400 * 6;
    /// @notice Amount of sales that go to rewards (1/4)
    uint256 public immutable rewardFraction = 4;

    /// @notice Merkle root for dictionary of words
    bytes32 private merkleRoot =
        0xd848d23e6ac07f7c22c9cb0e121f568619a636d37fab669e76595adfda216273;

    /// @notice Mapping for point values of letters, set up in setupLetterPoints()
    mapping(Letter => uint8) private letterValue;

    /// ============ Mutable Storage (ECS Sin, but gas savings) ============

    /// @notice Mapping to store if a player has claimed their end of game payout
    mapping(address => bool) private claimedPayout;
    /// @notice Store of treasury to be paid out to game winners
    uint256 private treasury;

    constructor(IWorld _world, address _components)
        LinearVRGDA(vrgdaTargetPrice, vrgdaPriceDecayPercent, vrgdaPerTimeUnit)
        System(_world, _components)
    {
        setupLetterPoints();
    }

    /// ============ Public functions ============

    function execute(bytes memory arguments) public returns (bytes memory) {
        (
            Letter[] memory word,
            bytes32[] memory proof,
            Position memory position,
            Direction direction,
            Bounds memory bounds
        ) = abi.decode(
                arguments,
                (Letter[], bytes32[], Position, Direction, Bounds)
            );
        executeInternal(word, proof, position, direction, bounds);
    }

    /// @notice Checks if a move is valid and if so, plays a word on the board.
    /// @param word The letters of the word being played, empty letters mean using existing letters on board.
    /// @param proof The Merkle proof that the word is in the dictionary.
    /// @param position The starting position that the word is being played from.
    /// @param direction The direction the word is being played (top-down, or left-to-right).
    /// @param bounds The bounds of all other words on the cross axis this word makes.
    function executeTyped(
        Letter[] memory word,
        bytes32[] memory proof,
        Position memory position,
        Direction direction,
        Bounds memory bounds
    ) public payable returns (bytes memory) {
        return execute(abi.encode(word, proof, position, direction, bounds));
    }

    /// @notice Claims winnings for a player at game end, can only be called once.
    function claimPayout() public {
        if (!isGameOver()) revert GameNotOver();
        if (claimedPayout[msg.sender]) revert AlreadyClaimedPayout();
        claimedPayout[msg.sender] = true;
        ScoreComponent scores = ScoreComponent(
            getAddressById(components, ScoreComponentID)
        );
        Score memory playerScore = scores.getValueAtAddress(msg.sender);
        uint256 winnings = (treasury * playerScore.score) /
            uint256(scores.getTotalScore());
        uint256 rewards = playerScore.rewards;
        payable(msg.sender).transfer(winnings + rewards);
    }

    /// @notice Allows anyone to seed the treasury for this game with extra funds.
    function fundTreasury() public payable {
        if (msg.value > 0) {
            treasury += msg.value;
        }
    }

    /// @notice Gets funds in treasury (only treasury, not player rewards).
    function getTreasury() public view returns (uint256) {
        return treasury;
    }

    /// @notice Plays the first word "infinite" on the board.
    function setupInitialGrid() public {
        TileComponent tiles = TileComponent(
            getAddressById(components, TileComponentID)
        );
        if (tiles.hasTileAtPosition(Position({x: 0, y: 0})))
            revert AlreadySetupGrid();
        tiles.set(Tile(address(0), Position({x: 0, y: 0}), Letter.I));
        tiles.set(Tile(address(0), Position({x: 1, y: 0}), Letter.N));
        tiles.set(Tile(address(0), Position({x: 2, y: 0}), Letter.F));
        tiles.set(Tile(address(0), Position({x: 3, y: 0}), Letter.I));
        tiles.set(Tile(address(0), Position({x: 4, y: 0}), Letter.N));
        tiles.set(Tile(address(0), Position({x: 5, y: 0}), Letter.I));
        tiles.set(Tile(address(0), Position({x: 6, y: 0}), Letter.T));
        tiles.set(Tile(address(0), Position({x: 7, y: 0}), Letter.E));
    }

    /// ============ Private functions ============

    /// @notice Internal function to check if a move is valid and if so, play it on the board.
    /// @dev Making execute payable breaks the System interface, so executeInternal is needed.
    function executeInternal(
        Letter[] memory word,
        bytes32[] memory proof,
        Position memory position,
        Direction direction,
        Bounds memory bounds
    ) private {
        // Ensure game is not ever
        if (isGameOver()) revert GameOver();

        // Ensure payment is sufficient
        uint256 price = getPriceForWord(word);
        if (msg.value < price) revert PaymentTooLow();

        // Increment letter counts
        LetterCountComponent letterCount = LetterCountComponent(
            getAddressById(components, LetterCountComponentID)
        );
        for (uint32 i = 0; i < word.length; i++) {
            if (word[i] != Letter.EMPTY) {
                letterCount.incrementValueAtLetter(word[i]);
            }
        }

        // Increment treasury
        treasury += (msg.value * (rewardFraction - 1)) / rewardFraction;

        // Check if move is valid, and if so, make it
        makeMoveChecked(word, proof, position, direction, bounds);
    }

    /// @notice Checks if a move is valid, and if so, update TileComponent and ScoreComponent.
    function makeMoveChecked(
        Letter[] memory word,
        bytes32[] memory proof,
        Position memory position,
        Direction direction,
        Bounds memory bounds
    ) private {
        TileComponent tiles = TileComponent(
            getAddressById(components, TileComponentID)
        );
        checkWord(word, proof, position, direction, tiles);
        checkBounds(word, position, direction, bounds, tiles);
        Letter[] memory filledWord = processWord(
            word,
            position,
            direction,
            tiles
        );
        countPointsChecked(filledWord, position, direction, bounds, tiles);
    }

    /// @notice Checks if a word is 1) played on another word, 2) has at least one letter, 3) is a valid word, 4) has valid bounds, and 5) has not been played yet
    function checkWord(
        Letter[] memory word,
        bytes32[] memory proof,
        Position memory position,
        Direction direction,
        TileComponent tiles
    ) public view {
        // Ensure word is less than 200 letters
        if (word.length > 200) revert WordTooLong();
        // Ensure word isn't missing letters at edges
        if (
            tiles.hasTileAtPosition(
                LibBoard.getLetterPosition(-1, position, direction)
            )
        ) revert InvalidWordStart();
        if (
            tiles.hasTileAtPosition(
                LibBoard.getLetterPosition(
                    int32(uint32(word.length)),
                    position,
                    direction
                )
            )
        ) revert InvalidWordEnd();

        bool emptyTile = false;
        bool nonEmptyTile = false;

        Letter[] memory filledWord = new Letter[](word.length);

        for (uint32 i = 0; i < word.length; i++) {
            Position memory letterPosition = LibBoard.getLetterPosition(
                int32(i),
                position,
                direction
            );
            if (word[i] == Letter.EMPTY) {
                emptyTile = true;

                // Ensure empty letter is played on existing letter
                if (!tiles.hasTileAtPosition(letterPosition))
                    revert EmptyLetterNotOnExisting();

                filledWord[i] = tiles.getValueAtPosition(letterPosition).letter;
            } else {
                nonEmptyTile = true;

                // Ensure non-empty letter is played on empty tile
                if (tiles.hasTileAtPosition(letterPosition))
                    revert LetterOnExistingTile();

                filledWord[i] = word[i];
            }
        }

        // Ensure word is played on another word
        if (!emptyTile) revert LonelyWord();
        // Ensure word has at least one letter
        if (!nonEmptyTile) revert NoLettersPlayed();
        // Ensure word is a valid word
        LibBoard.verifyWordProof(filledWord, proof, merkleRoot);
    }

    /// @notice Checks if the given bounds for other words on the cross axis are well formed.
    function checkBounds(
        Letter[] memory word,
        Position memory position,
        Direction direction,
        Bounds memory bounds,
        TileComponent tiles
    ) private view {
        // Ensure bounds of equal length
        if (bounds.positive.length != bounds.negative.length)
            revert BoundsDoNotMatch();
        // Ensure bounds of correct length
        if (bounds.positive.length != word.length) revert InvalidBoundLength();
        // Ensure proof of correct length
        if (bounds.positive.length != bounds.proofs.length)
            revert InvalidCrossProofs();

        // Ensure positive and negative bounds are valid
        for (uint32 i; i < word.length; i++) {
            if (word[i] == Letter.EMPTY) {
                // Ensure bounds are 0 if letter is empty
                // since you cannot get points for words formed by letters you did not play
                if (bounds.positive[i] != 0 || bounds.negative[i] != 0)
                    revert InvalidEmptyLetterBound();
            } else {
                // Ensure bounds are valid (empty at edges) for nonempty letters
                // Bounds that are too large will be caught while verifying formed words
                (Position memory start, Position memory end) = LibBoard
                    .getOutsideBoundPositions(
                        LibBoard.getLetterPosition(
                            int32(i),
                            position,
                            direction
                        ),
                        direction,
                        bounds.positive[i],
                        bounds.negative[i]
                    );
                if (
                    tiles.hasTileAtPosition(start) ||
                    tiles.hasTileAtPosition(end)
                ) revert InvalidBoundEdges();
            }
        }
    }

    /// @notice 1) Places the word on the board, 2) adds word rewards to other players, and 3) returns a filled in word.
    /// @return filledWord A word that has empty letters replaced with the underlying letters from the board.
    function processWord(
        Letter[] memory word,
        Position memory position,
        Direction direction,
        TileComponent tiles
    ) private returns (Letter[] memory) {
        Letter[] memory filledWord = new Letter[](word.length);

        // Rewards are tracked in the score component
        ScoreComponent scores = ScoreComponent(
            getAddressById(components, ScoreComponentID)
        );

        // Evenly split the reward fraction of among tiles the player used to create their word
        // Rewards are only awarded to players who are used in the "primary" word
        uint256 rewardPerEmptyTile = LibBoard.getRewardPerEmptyTile(
            word,
            rewardFraction,
            msg.value
        );

        // Place tiles and fill filledWord
        for (uint32 i = 0; i < word.length; i++) {
            Position memory letterPosition = LibBoard.getLetterPosition(
                int32(i),
                position,
                direction
            );
            if (word[i] == Letter.EMPTY) {
                Tile memory tile = tiles.getValueAtPosition(letterPosition);
                scores.incrementValueAtAddress(
                    tile.player,
                    0,
                    rewardPerEmptyTile,
                    0
                );
                filledWord[i] = tile.letter;
            } else {
                tiles.set(
                    Tile(
                        msg.sender,
                        Position({x: letterPosition.x, y: letterPosition.y}),
                        word[i]
                    )
                );
                filledWord[i] = word[i];
            }
        }
        return filledWord;
    }

    /// @notice Updates the score for a player for the main word and cross words and checks every cross word.
    /// @dev Expects a word input with empty letters filled in
    function countPointsChecked(
        Letter[] memory filledWord,
        Position memory position,
        Direction direction,
        Bounds memory bounds,
        TileComponent tiles
    ) private {
        uint32 points = countPointsForWord(filledWord);
        // Count points for perpendicular word
        // This double counts points on purpose (points are recounted for every valid word)
        for (uint32 i; i < filledWord.length; i++) {
            if (bounds.positive[i] != 0 || bounds.negative[i] != 0) {
                Letter[] memory perpendicularWord = LibBoard
                    .getWordInBoundsChecked(
                        LibBoard.getLetterPosition(
                            int32(i),
                            position,
                            direction
                        ),
                        direction,
                        bounds.positive[i],
                        bounds.negative[i],
                        tiles
                    );
                LibBoard.verifyWordProof(
                    perpendicularWord,
                    bounds.proofs[i],
                    merkleRoot
                );
                points += countPointsForWord(perpendicularWord);
            }
        }
        ScoreComponent scores = ScoreComponent(
            getAddressById(components, ScoreComponentID)
        );
        scores.incrementValueAtAddress(msg.sender, msg.value, 0, points);
    }

    /// @notice Ge the points for a given word. The points are simply a sum of the letter point values.
    function countPointsForWord(Letter[] memory word)
        private
        view
        returns (uint32)
    {
        uint32 points;
        for (uint32 i; i < word.length; i++) {
            points += letterValue[word[i]];
        }
        return points;
    }

    /// @notice Get price for a letter using a linear VRGDA.
    function getPriceForLetter(Letter letter) public view returns (uint256) {
        LetterCountComponent letterCount = LetterCountComponent(
            getAddressById(components, LetterCountComponentID)
        );
        return
            getVRGDAPrice(
                toDaysWadUnsafe(block.timestamp - startTime),
                ((letterValue[letter] + 1) / 2) *
                    letterCount.getValueAtLetter(letter)
            );
    }

    /// @notice Get price for a word using a linear VRGDA.
    function getPriceForWord(Letter[] memory word)
        public
        view
        returns (uint256)
    {
        uint256 price;
        for (uint32 i = 0; i < word.length; i++) {
            if (word[i] != Letter.EMPTY) {
                price += getPriceForLetter(word[i]);
            }
        }
        return price;
    }

    /// @notice Get if game is over.
    function isGameOver() private view returns (bool) {
        return block.timestamp >= endTime;
    }

    /// ============ Setup functions ============

    function setupLetterPoints() private {
        letterValue[Letter.A] = 1;
        letterValue[Letter.B] = 3;
        letterValue[Letter.C] = 3;
        letterValue[Letter.D] = 2;
        letterValue[Letter.E] = 1;
        letterValue[Letter.F] = 4;
        letterValue[Letter.G] = 2;
        letterValue[Letter.H] = 4;
        letterValue[Letter.I] = 1;
        letterValue[Letter.J] = 8;
        letterValue[Letter.K] = 5;
        letterValue[Letter.L] = 1;
        letterValue[Letter.M] = 3;
        letterValue[Letter.N] = 1;
        letterValue[Letter.O] = 1;
        letterValue[Letter.P] = 3;
        letterValue[Letter.Q] = 10;
        letterValue[Letter.R] = 1;
        letterValue[Letter.S] = 1;
        letterValue[Letter.T] = 1;
        letterValue[Letter.U] = 1;
        letterValue[Letter.V] = 4;
        letterValue[Letter.W] = 4;
        letterValue[Letter.X] = 8;
        letterValue[Letter.Y] = 4;
        letterValue[Letter.Z] = 10;
    }
}

File 2 of 31 : System.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.0;

import { ISystem } from "./interfaces/ISystem.sol";
import { IUint256Component } from "./interfaces/IUint256Component.sol";
import { IWorld } from "./interfaces/IWorld.sol";

/**
 * System base contract
 */
abstract contract System is ISystem {
  IUint256Component components;
  IWorld world;
  address _owner;

  modifier onlyOwner() {
    require(msg.sender == _owner, "ONLY_OWNER");
    _;
  }

  constructor(IWorld _world, address _components) {
    _owner = msg.sender;
    components = _components == address(0) ? _world.components() : IUint256Component(_components);
    world = _world;
  }

  function owner() public view returns (address) {
    return _owner;
  }
}

File 3 of 31 : IWorld.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.0;
import { QueryType } from "./Query.sol";
import { IUint256Component } from "./IUint256Component.sol";

// For ProxyRead and ProxyExpand QueryFragments:
// - component must be a component whose raw value decodes to a single uint256
// - value must decode to a single uint256 represents the proxy depth
struct WorldQueryFragment {
  QueryType queryType;
  uint256 componentId;
  bytes value;
}

interface IWorld {
  function components() external view returns (IUint256Component);

  function systems() external view returns (IUint256Component);

  function registerComponent(address componentAddr, uint256 id) external;

  function getComponent(uint256 id) external view returns (address);

  function getComponentIdFromAddress(address componentAddr) external view returns (uint256);

  function registerSystem(address systemAddr, uint256 id) external;

  function registerComponentValueSet(
    address component,
    uint256 entity,
    bytes calldata data
  ) external;

  function registerComponentValueSet(uint256 entity, bytes calldata data) external;

  function registerComponentValueRemoved(address component, uint256 entity) external;

  function registerComponentValueRemoved(uint256 entity) external;

  function getNumEntities() external view returns (uint256);

  function hasEntity(uint256 entity) external view returns (bool);

  function getUniqueEntityId() external view returns (uint256);

  function query(WorldQueryFragment[] calldata worldQueryFragments) external view returns (uint256[] memory);
}

File 4 of 31 : utils.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.0;

import { IUint256Component } from "./interfaces/IUint256Component.sol";
import { IComponent } from "./interfaces/IComponent.sol";
import { ISystem } from "./interfaces/ISystem.sol";
import { systemsComponentId } from "./constants.sol";

/** Turn an entity ID into its corresponding Ethereum address. */
function entityToAddress(uint256 entity) pure returns (address) {
  return address(uint160(entity));
}

/** Turn an Ethereum address into its corresponding entity ID. */
function addressToEntity(address addr) pure returns (uint256) {
  return uint256(uint160(addr));
}

/** Get an Ethereum address from an address/id registry component (like _components/_systems in World.sol) */
function getAddressById(IUint256Component registry, uint256 id) view returns (address) {
  uint256[] memory entities = registry.getEntitiesWithValue(id);
  require(entities.length != 0, "id not registered");
  return entityToAddress(entities[0]);
}

/** Get an entity id from an address/id registry component (like _components/_systems in World.sol) */
function getIdByAddress(IUint256Component registry, address addr) view returns (uint256) {
  require(registry.has(addressToEntity(addr)), "address not registered");
  return registry.getValue(addressToEntity(addr));
}

/** Get a Component from an address/id registry component (like _components in World.sol) */
function getComponentById(IUint256Component components, uint256 id) view returns (IComponent) {
  return IComponent(getAddressById(components, id));
}

/**
 * Get the Ethereum address of a System from an address/id component registry component in which the
 * System registry component is registered (like _components in World.sol)
 */
function getSystemAddressById(IUint256Component components, uint256 id) view returns (address) {
  IUint256Component systems = IUint256Component(getAddressById(components, systemsComponentId));
  return getAddressById(systems, id);
}

/**
 * Get a System from an address/id component registry component in which the
 * System registry component is registered (like _components in World.sol)
 */
function getSystemById(IUint256Component components, uint256 id) view returns (ISystem) {
  return ISystem(getSystemAddressById(components, id));
}

File 5 of 31 : TileComponent.sol
// SPDX-License-Identifier: Unlicensed
// Adapted from Mud's CoordComponent (https://github.com/latticexyz/mud/blob/main/packages/std-contracts/src/components/CoordComponent.sol)
pragma solidity >=0.8.0;
import "solecs/BareComponent.sol";
import { Letter } from "../common/Letter.sol";
import { Tile } from "../common/Tile.sol";
import { Position } from "../common/Play.sol";

uint256 constant ID = uint256(keccak256("component.Tile"));

contract TileComponent is BareComponent {
  constructor(address world) BareComponent(world, ID) {}

  function getSchema() public pure override returns (string[] memory keys, LibTypes.SchemaValue[] memory values) {
    keys = new string[](1);
    values = new LibTypes.SchemaValue[](1);

    keys[0] = "value";
    values[0] = LibTypes.SchemaValue.UINT256;
  }

  function set(Tile calldata tile) public {
    set(
      getEntityAtPosition(tile.position),
      abi.encode(
        bytes32(
          bytes.concat(
            bytes20(tile.player),
            bytes4(uint32(tile.position.x)),
            bytes4(uint32(tile.position.y)),
            bytes1(uint8(tile.letter))
          )
        )
      )
    );
  }

  function getValue(uint256 entity) public view returns (Tile memory) {
    uint256 rawData = abi.decode(getRawValue(entity), (uint256));
    address player = address(uint160(rawData >> ((32 - 20) * 8)));
    int32 x = int32(uint32(((rawData << (20 * 8)) >> ((32 - 4) * 8))));
    int32 y = int32(uint32((rawData << (24 * 8)) >> ((32 - 4) * 8)));
    Letter letter = Letter(uint8((uint256(rawData) << (28 * 8)) >> ((32 - 1) * 8)));

    return Tile(player, Position({ x: x, y: y }), letter);
  }

  function hasTileAtPosition(Position memory position) public view returns (bool) {
    return has(getEntityAtPosition(position));
  }

  function getEntityAtPosition(Position memory position) public pure returns (uint256) {
    return uint256(keccak256(abi.encode(ID, position.x, position.y)));
  }

  function getValueAtPosition(Position memory position) public view returns (Tile memory) {
    return getValue(getEntityAtPosition(position));
  }
}

File 6 of 31 : ScoreComponent.sol
// SPDX-License-Identifier: Unlicensed
pragma solidity >=0.8.0;
import "solecs/BareComponent.sol";
import { addressToEntity } from "solecs/utils.sol";
import { Score } from "../common/Score.sol";

uint256 constant ID = uint256(keccak256("component.Score"));

contract ScoreComponent is BareComponent {
  uint32 private totalScore;

  constructor(address world) BareComponent(world, ID) {}

  function getSchema() public pure override returns (string[] memory keys, LibTypes.SchemaValue[] memory values) {
    keys = new string[](3);
    values = new LibTypes.SchemaValue[](3);

    keys[0] = "spent";
    values[0] = LibTypes.SchemaValue.UINT256;

    keys[1] = "rewards";
    values[1] = LibTypes.SchemaValue.UINT256;

    keys[2] = "score";
    values[2] = LibTypes.SchemaValue.UINT32;
  }

  function set(
    address player,
    uint256 spent,
    uint256 rewards,
    uint32 score
  ) public {
    set(getEntityAtAddress(player), abi.encode(Score({ spent: spent, rewards: rewards, score: score })));
  }

  function getValue(uint256 entity) public view returns (Score memory) {
    Score memory score = abi.decode(getRawValue(entity), (Score));
    return score;
  }

  function getEntityAtAddress(address player) public pure returns (uint256) {
    return addressToEntity(player);
  }

  function getValueAtAddress(address player) public view returns (Score memory) {
    uint256 entity = getEntityAtAddress(player);
    return getValue(entity);
  }

  function hasValueAtAddress(address player) public view returns (bool) {
    return has(getEntityAtAddress(player));
  }

  function incrementValueAtAddress(
    address player,
    uint256 spent,
    uint256 rewards,
    uint32 score
  ) public {
    if (hasValueAtAddress(player)) {
      Score memory previous = getValueAtAddress(player);
      set(player, previous.spent + spent, previous.rewards + rewards, previous.score + score);
    } else {
      set(player, spent, rewards, score);
    }
    totalScore += score;
  }

  function getTotalScore() public view returns (uint32) {
    return totalScore;
  }
}

File 7 of 31 : LetterCountComponent.sol
// SPDX-License-Identifier: Unlicense
// Adapted from UInt256 Component (cannot use default UInt256 Component since this must be bare)
pragma solidity >=0.8.0;
import { Letter } from "../common/Letter.sol";
import "std-contracts/components/UInt32BareComponent.sol";
import { console } from "forge-std/console.sol";


uint256 constant ID = uint256(keccak256("component.LetterCount"));

contract LetterCountComponent is Uint32BareComponent {
  constructor(address world) Uint32BareComponent(world, ID) {}

  function getEntityAtLetter(Letter letter) private pure returns (uint256) {
    return uint256(keccak256(abi.encode(ID, uint8(letter))));
  }

  function getValueAtLetter(Letter letter) public view returns (uint32) {
    uint256 entity = getEntityAtLetter(letter);
    if (!has(entity)) return 0;
    return getValue(entity);
  }

  function incrementValueAtLetter(Letter letter) public {
    uint256 entity = getEntityAtLetter(letter);
    uint256 letterCount = getValueAtLetter(letter);
    set(entity, abi.encode(letterCount + 1));
  }
}

File 8 of 31 : Letter.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.0;

// Letters
enum Letter {
  EMPTY,
  A,
  B,
  C,
  D,
  E,
  F,
  G,
  H,
  I,
  J,
  K,
  L,
  M,
  N,
  O,
  P,
  Q,
  R,
  S,
  T,
  U,
  V,
  W,
  X,
  Y,
  Z
}

File 9 of 31 : Tile.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.0;

import { Letter } from "./Letter.sol";
import { Position } from "./Play.sol";

struct Tile {
  address player;
  Position position;
  Letter letter;
}

File 10 of 31 : Score.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.0;

struct Score {
  uint256 spent;
  uint256 rewards;
  uint32 score;
}

File 11 of 31 : Play.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.0;

import { Letter } from "./Letter.sol";

struct Position {
  int32 x;
  int32 y;
}

// Boundaries for a played word
struct Bounds {
  uint32[] positive; // Distance in the positive direction
  uint32[] negative; // Distance in the negative direction
  bytes32[][] proofs;
}

enum Direction {
  LEFT_TO_RIGHT,
  TOP_TO_BOTTOM
}

File 12 of 31 : LinearVRGDA.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

import { unsafeWadDiv } from "solmate/utils/SignedWadMath.sol";
import { VRGDA } from "./VRGDA.sol";

/// @title Linear Variable Rate Gradual Dutch Auction
/// @author transmissions11 <[email protected]>
/// @author FrankieIsLost <[email protected]>
/// @notice VRGDA with a linear issuance curve.
abstract contract LinearVRGDA is VRGDA {
  /*//////////////////////////////////////////////////////////////
                           PRICING PARAMETERS
    //////////////////////////////////////////////////////////////*/

  /// @dev The total number of tokens to target selling every full unit of time.
  /// @dev Represented as an 18 decimal fixed point number.
  int256 internal immutable perTimeUnit;

  /// @notice Sets pricing parameters for the VRGDA.
  /// @param _targetPrice The target price for a token if sold on pace, scaled by 1e18.
  /// @param _priceDecayPercent The percent price decays per unit of time with no sales, scaled by 1e18.
  /// @param _perTimeUnit The number of tokens to target selling in 1 full unit of time, scaled by 1e18.
  constructor(
    int256 _targetPrice,
    int256 _priceDecayPercent,
    int256 _perTimeUnit
  ) VRGDA(_targetPrice, _priceDecayPercent) {
    perTimeUnit = _perTimeUnit;
  }

  /*//////////////////////////////////////////////////////////////
                              PRICING LOGIC
    //////////////////////////////////////////////////////////////*/

  /// @dev Given a number of tokens sold, return the target time that number of tokens should be sold by.
  /// @param sold A number of tokens sold, scaled by 1e18, to get the corresponding target sale time for.
  /// @return The target time the tokens should be sold by, scaled by 1e18, where the time is
  /// relative, such that 0 means the tokens should be sold immediately when the VRGDA begins.
  function getTargetSaleTime(int256 sold) public view virtual override returns (int256) {
    return unsafeWadDiv(sold, perTimeUnit);
  }
}

File 13 of 31 : SignedWadMath.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

/// @notice Signed 18 decimal fixed point (wad) arithmetic library.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/SignedWadMath.sol)

/// @dev Will not revert on overflow, only use where overflow is not possible.
function toWadUnsafe(uint256 x) pure returns (int256 r) {
    assembly {
        // Multiply x by 1e18.
        r := mul(x, 1000000000000000000)
    }
}

/// @dev Takes an integer amount of seconds and converts it to a wad amount of days.
/// @dev Will not revert on overflow, only use where overflow is not possible.
/// @dev Not meant for negative second amounts, it assumes x is positive.
function toDaysWadUnsafe(uint256 x) pure returns (int256 r) {
    assembly {
        // Multiply x by 1e18 and then divide it by 86400.
        r := div(mul(x, 1000000000000000000), 86400)
    }
}

/// @dev Takes a wad amount of days and converts it to an integer amount of seconds.
/// @dev Will not revert on overflow, only use where overflow is not possible.
/// @dev Not meant for negative day amounts, it assumes x is positive.
function fromDaysWadUnsafe(int256 x) pure returns (uint256 r) {
    assembly {
        // Multiply x by 86400 and then divide it by 1e18.
        r := div(mul(x, 86400), 1000000000000000000)
    }
}

/// @dev Will not revert on overflow, only use where overflow is not possible.
function unsafeWadMul(int256 x, int256 y) pure returns (int256 r) {
    assembly {
        // Multiply x by y and divide by 1e18.
        r := sdiv(mul(x, y), 1000000000000000000)
    }
}

/// @dev Will return 0 instead of reverting if y is zero and will
/// not revert on overflow, only use where overflow is not possible.
function unsafeWadDiv(int256 x, int256 y) pure returns (int256 r) {
    assembly {
        // Multiply x by 1e18 and divide it by y.
        r := sdiv(mul(x, 1000000000000000000), y)
    }
}

function wadMul(int256 x, int256 y) pure returns (int256 r) {
    assembly {
        // Store x * y in r for now.
        r := mul(x, y)

        // Equivalent to require(x == 0 || (x * y) / x == y)
        if iszero(or(iszero(x), eq(sdiv(r, x), y))) {
            revert(0, 0)
        }

        // Scale the result down by 1e18.
        r := sdiv(r, 1000000000000000000)
    }
}

function wadDiv(int256 x, int256 y) pure returns (int256 r) {
    assembly {
        // Store x * 1e18 in r for now.
        r := mul(x, 1000000000000000000)

        // Equivalent to require(y != 0 && ((x * 1e18) / 1e18 == x))
        if iszero(and(iszero(iszero(y)), eq(sdiv(r, 1000000000000000000), x))) {
            revert(0, 0)
        }

        // Divide r by y.
        r := sdiv(r, y)
    }
}

function wadExp(int256 x) pure returns (int256 r) {
    unchecked {
        // When the result is < 0.5 we return zero. This happens when
        // x <= floor(log(0.5e18) * 1e18) ~ -42e18
        if (x <= -42139678854452767551) return 0;

        // When the result is > (2**255 - 1) / 1e18 we can not represent it as an
        // int. This happens when x >= floor(log((2**255 - 1) / 1e18) * 1e18) ~ 135.
        if (x >= 135305999368893231589) revert("EXP_OVERFLOW");

        // x is now in the range (-42, 136) * 1e18. Convert to (-42, 136) * 2**96
        // for more intermediate precision and a binary basis. This base conversion
        // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.
        x = (x << 78) / 5**18;

        // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers
        // of two such that exp(x) = exp(x') * 2**k, where k is an integer.
        // Solving this gives k = round(x / log(2)) and x' = x - k * log(2).
        int256 k = ((x << 96) / 54916777467707473351141471128 + 2**95) >> 96;
        x = x - k * 54916777467707473351141471128;

        // k is in the range [-61, 195].

        // Evaluate using a (6, 7)-term rational approximation.
        // p is made monic, we'll multiply by a scale factor later.
        int256 y = x + 1346386616545796478920950773328;
        y = ((y * x) >> 96) + 57155421227552351082224309758442;
        int256 p = y + x - 94201549194550492254356042504812;
        p = ((p * y) >> 96) + 28719021644029726153956944680412240;
        p = p * x + (4385272521454847904659076985693276 << 96);

        // We leave p in 2**192 basis so we don't need to scale it back up for the division.
        int256 q = x - 2855989394907223263936484059900;
        q = ((q * x) >> 96) + 50020603652535783019961831881945;
        q = ((q * x) >> 96) - 533845033583426703283633433725380;
        q = ((q * x) >> 96) + 3604857256930695427073651918091429;
        q = ((q * x) >> 96) - 14423608567350463180887372962807573;
        q = ((q * x) >> 96) + 26449188498355588339934803723976023;

        assembly {
            // Div in assembly because solidity adds a zero check despite the unchecked.
            // The q polynomial won't have zeros in the domain as all its roots are complex.
            // No scaling is necessary because p is already 2**96 too large.
            r := sdiv(p, q)
        }

        // r should be in the range (0.09, 0.25) * 2**96.

        // We now need to multiply r by:
        // * the scale factor s = ~6.031367120.
        // * the 2**k factor from the range reduction.
        // * the 1e18 / 2**96 factor for base conversion.
        // We do this all at once, with an intermediate result in 2**213
        // basis, so the final right shift is always by a positive amount.
        r = int256((uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k));
    }
}

function wadLn(int256 x) pure returns (int256 r) {
    unchecked {
        require(x > 0, "UNDEFINED");

        // We want to convert x from 10**18 fixed point to 2**96 fixed point.
        // We do this by multiplying by 2**96 / 10**18. But since
        // ln(x * C) = ln(x) + ln(C), we can simply do nothing here
        // and add ln(2**96 / 10**18) at the end.

        assembly {
            r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffff, shr(r, x))))
            r := or(r, shl(3, lt(0xff, shr(r, x))))
            r := or(r, shl(2, lt(0xf, shr(r, x))))
            r := or(r, shl(1, lt(0x3, shr(r, x))))
            r := or(r, lt(0x1, shr(r, x)))
        }

        // Reduce range of x to (1, 2) * 2**96
        // ln(2^k * x) = k * ln(2) + ln(x)
        int256 k = r - 96;
        x <<= uint256(159 - k);
        x = int256(uint256(x) >> 159);

        // Evaluate using a (8, 8)-term rational approximation.
        // p is made monic, we will multiply by a scale factor later.
        int256 p = x + 3273285459638523848632254066296;
        p = ((p * x) >> 96) + 24828157081833163892658089445524;
        p = ((p * x) >> 96) + 43456485725739037958740375743393;
        p = ((p * x) >> 96) - 11111509109440967052023855526967;
        p = ((p * x) >> 96) - 45023709667254063763336534515857;
        p = ((p * x) >> 96) - 14706773417378608786704636184526;
        p = p * x - (795164235651350426258249787498 << 96);

        // We leave p in 2**192 basis so we don't need to scale it back up for the division.
        // q is monic by convention.
        int256 q = x + 5573035233440673466300451813936;
        q = ((q * x) >> 96) + 71694874799317883764090561454958;
        q = ((q * x) >> 96) + 283447036172924575727196451306956;
        q = ((q * x) >> 96) + 401686690394027663651624208769553;
        q = ((q * x) >> 96) + 204048457590392012362485061816622;
        q = ((q * x) >> 96) + 31853899698501571402653359427138;
        q = ((q * x) >> 96) + 909429971244387300277376558375;
        assembly {
            // Div in assembly because solidity adds a zero check despite the unchecked.
            // The q polynomial is known not to have zeros in the domain.
            // No scaling required because p is already 2**96 too large.
            r := sdiv(p, q)
        }

        // r is in the range (0, 0.125) * 2**96

        // Finalization, we need to:
        // * multiply by the scale factor s = 5.549…
        // * add ln(2**96 / 10**18)
        // * add k * ln(2)
        // * multiply by 10**18 / 2**96 = 5**18 >> 78

        // mul s * 5e18 * 2**96, base is now 5**18 * 2**192
        r *= 1677202110996718588342820967067443963516166;
        // add ln(2) * k * 5e18 * 2**192
        r += 16597577552685614221487285958193947469193820559219878177908093499208371 * k;
        // add ln(2**96 / 10**18) * 5e18 * 2**192
        r += 600920179829731861736702779321621459595472258049074101567377883020018308;
        // base conversion: mul 2**18 / 2**192
        r >>= 174;
    }
}

/// @dev Will return 0 instead of reverting if y is zero.
function unsafeDiv(int256 x, int256 y) pure returns (int256 r) {
    assembly {
        // Divide x by y.
        r := sdiv(x, y)
    }
}

File 14 of 31 : LibBoard.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.0;

import {Letter} from "../common/Letter.sol";
import {Position, Direction} from "../common/Play.sol";
import {MerkleProof} from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import {TileComponent, ID as TileComponentID} from "../components/TileComponent.sol";
import "../common/Errors.sol";

library LibBoard {
    /// @notice Verifies a Merkle proof to check if a given word is in the dictionary.
    function verifyWordProof(
        Letter[] memory word,
        bytes32[] memory proof,
        bytes32 merkleRoot
    ) internal pure {
        bytes32 leaf = keccak256(abi.encodePacked(word));
        bool isValidLeaf = MerkleProof.verify(proof, merkleRoot, leaf);
        if (!isValidLeaf) revert InvalidWord();
    }

    /// @notice Get the amount of rewards paid to every empty tile in the word.
    function getRewardPerEmptyTile(
        Letter[] memory word,
        uint256 rewardFraction,
        uint256 value
    ) internal pure returns (uint256) {
        uint256 numEmptyTiles;
        for (uint32 i = 0; i < word.length; i++) {
            if (word[i] == Letter.EMPTY) numEmptyTiles++;
        }
        // msg.value / rewardFraction is total to be paid out in rewards, split across numEmptyTiles
        return (value / rewardFraction) / numEmptyTiles;
    }

    /// @notice Gets the position of a letter in a word given an offset and a direction.
    /// @dev Useful for looping through words.
    /// @param letterOffset The offset of the position from the start position.
    /// @param position The start position of the word.
    /// @param direction The direction the word is being played in.
    function getLetterPosition(
        int32 letterOffset,
        Position memory position,
        Direction direction
    ) internal pure returns (Position memory) {
        if (direction == Direction.LEFT_TO_RIGHT) {
            return Position(position.x + letterOffset, position.y);
        } else {
            return Position(position.x, position.y + letterOffset);
        }
    }

    /// @notice Gets the positions OUTSIDE a boundary on the boundary axis.
    /// @dev Useful for checking if a boundary is valid.
    /// @param letterPosition The start position of the letter for which the boundary is for.
    /// @param direction The direction the original word (not the boundary) is being played in.
    /// @param positive The distance the bound spans in the positive direction.
    /// @param negative The distance the bound spans in the negative direction.
    function getOutsideBoundPositions(
        Position memory letterPosition,
        Direction direction,
        uint32 positive,
        uint32 negative
    ) internal pure returns (Position memory, Position memory) {
        if (positive > 200 || negative > 200) revert BoundTooLong();
        Position memory start = Position(letterPosition.x, letterPosition.y);
        Position memory end = Position(letterPosition.x, letterPosition.y);
        if (direction == Direction.LEFT_TO_RIGHT) {
            start.y -= (int32(negative) + 1);
            end.y += (int32(positive) + 1);
        } else {
            start.x -= (int32(negative) + 1);
            end.x += (int32(positive) + 1);
        }
        return (start, end);
    }

    /// @notice Gets the word inside a given boundary and checks to make sure there are no empty letters in the bound.
    /// @dev Assumes that the word being made this round has already been played on board
    function getWordInBoundsChecked(
        Position memory letterPosition,
        Direction direction,
        uint32 positive,
        uint32 negative,
        TileComponent tiles
    ) internal view returns (Letter[] memory) {
        uint32 wordLength = positive + negative + 1;
        Letter[] memory word = new Letter[](wordLength);
        Position memory position;
        // Start at edge of negative bound
        if (direction == Direction.LEFT_TO_RIGHT) {
            position = LibBoard.getLetterPosition(
                -1 * int32(negative),
                letterPosition,
                Direction.TOP_TO_BOTTOM
            );
        } else {
            position = LibBoard.getLetterPosition(
                -1 * int32(negative),
                letterPosition,
                Direction.LEFT_TO_RIGHT
            );
        }
        for (uint32 i = 0; i < wordLength; i++) {
            word[i] = tiles.getValueAtPosition(position).letter;
            if (word[i] == Letter.EMPTY) revert EmptyLetterInBounds();
            if (direction == Direction.LEFT_TO_RIGHT) {
                position.y += 1;
            } else {
                position.x += 1;
            }
        }
        return word;
    }
}

File 15 of 31 : Errors.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.0;

error BoundsDoNotMatch();
error InvalidBoundLength();
error InvalidWordStart();
error InvalidWordEnd();
error GameOver();
error GameNotOver();
error AlreadyClaimedPayout();
error PaymentTooLow();
error InvalidEmptyLetterBound();
error InvalidBoundEdges();
error InvalidWord();
error EmptyLetterInBounds();
error EmptyLetterNotOnExisting();
error LetterOnExistingTile();
error LonelyWord();
error NoLettersPlayed();
error AlreadySetupGrid();
error InvalidCrossProofs();
error BoundTooLong();
error WordTooLong();

File 16 of 31 : ISystem.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.0;

import "./IOwned.sol";

// The minimum requirement for a system is to have an `execute` function.
// For convenience having an `executeTyped` function with typed arguments is recommended.
interface ISystem is IOwned {
  function execute(bytes memory arguments) external returns (bytes memory);
}

File 17 of 31 : IUint256Component.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.0;

import { IComponent } from "./IComponent.sol";

interface IUint256Component is IComponent {
  function set(uint256 entity, uint256 value) external;

  function getValue(uint256 entity) external view returns (uint256);

  function getEntitiesWithValue(uint256 value) external view returns (uint256[] memory);
}

File 18 of 31 : Query.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.13;
import { IComponent } from "./IComponent.sol";
import { LinkedList } from "memmove/LinkedList.sol";

enum QueryType {
  Has,
  Not,
  HasValue,
  NotValue,
  ProxyRead,
  ProxyExpand
}

// For ProxyRead and ProxyExpand QueryFragments:
// - component must be a component whose raw value decodes to a single uint256
// - value must decode to a single uint256 represents the proxy depth
struct QueryFragment {
  QueryType queryType;
  IComponent component;
  bytes value;
}

File 19 of 31 : IComponent.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.0;

import "./IOwned.sol";

interface IComponent is IOwned {
  function transferOwnership(address newOwner) external;

  function set(uint256 entity, bytes memory value) external;

  function remove(uint256 entity) external;

  function has(uint256 entity) external view returns (bool);

  function getRawValue(uint256 entity) external view returns (bytes memory);

  function getEntities() external view returns (uint256[] memory);

  function getEntitiesWithValue(bytes memory value) external view returns (uint256[] memory);

  function authorizeWriter(address writer) external;

  function unauthorizeWriter(address writer) external;
}

File 20 of 31 : constants.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.0;

uint256 constant componentsComponentId = uint256(keccak256("world.component.components"));
uint256 constant systemsComponentId = uint256(keccak256("world.component.systems"));

File 21 of 31 : BareComponent.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.0;

import { IWorld } from "./interfaces/IWorld.sol";
import { IComponent } from "./interfaces/IComponent.sol";

import { Set } from "./Set.sol";
import { MapSet } from "./MapSet.sol";
import { LibTypes } from "./LibTypes.sol";

/**
 * Components are a key-value store from entity id to component value.
 * They are registered in the World and register updates to their state in the World.
 * They have an owner, who can grant write access to more addresses.
 * (Systems that want to write to a component need to be given write access first.)
 * Everyone has read access.
 */
abstract contract BareComponent is IComponent {
  error BareComponent__NotImplemented();

  /** Reference to the World contract this component is registered in */
  address public world;

  /** Owner of the component has write access and can given write access to other addresses */
  address internal _owner;

  /** Addresses with write access to this component */
  mapping(address => bool) public writeAccess;

  /** Mapping from entity id to value in this component */
  mapping(uint256 => bytes) internal entityToValue;

  /** Public identifier of this component */
  uint256 public id;

  constructor(address _world, uint256 _id) {
    _owner = msg.sender;
    writeAccess[msg.sender] = true;
    id = _id;
    if (_world != address(0)) registerWorld(_world);
  }

  /** Revert if caller is not the owner of this component */
  modifier onlyOwner() {
    require(msg.sender == _owner, "ONLY_OWNER");
    _;
  }

  /** Revert if caller does not have write access to this component */
  modifier onlyWriter() {
    require(writeAccess[msg.sender], "ONLY_WRITER");
    _;
  }

  /** Get the owner of this component */
  function owner() public view override returns (address) {
    return _owner;
  }

  /**
   * Transfer ownership of this component to a new owner.
   * Can only be called by the current owner.
   * @param newOwner Address of the new owner.
   */
  function transferOwnership(address newOwner) public override onlyOwner {
    writeAccess[msg.sender] = false;
    _owner = newOwner;
    writeAccess[newOwner] = true;
  }

  /**
   * Register this component in the given world.
   * @param _world Address of the World contract.
   */
  function registerWorld(address _world) public onlyOwner {
    world = _world;
    IWorld(world).registerComponent(address(this), id);
  }

  /**
   * Grant write access to this component to the given address.
   * Can only be called by the owner of this component.
   * @param writer Address to grant write access to.
   */
  function authorizeWriter(address writer) public override onlyOwner {
    writeAccess[writer] = true;
  }

  /**
   * Revoke write access to this component to the given address.
   * Can only be called by the owner of this component.
   * @param writer Address to revoke write access .
   */
  function unauthorizeWriter(address writer) public override onlyOwner {
    delete writeAccess[writer];
  }

  /**
   * Return the keys and value types of the schema of this component.
   */
  function getSchema() public pure virtual returns (string[] memory keys, LibTypes.SchemaValue[] memory values);

  /**
   * Set the given component value for the given entity.
   * Registers the update in the World contract.
   * Can only be called by addresses with write access to this component.
   * @param entity Entity to set the value for.
   * @param value Value to set for the given entity.
   */
  function set(uint256 entity, bytes memory value) public override onlyWriter {
    _set(entity, value);
  }

  /**
   * Remove the given entity from this component.
   * Registers the update in the World contract.
   * Can only be called by addresses with write access to this component.
   * @param entity Entity to remove from this component.
   */
  function remove(uint256 entity) public override onlyWriter {
    _remove(entity);
  }

  /**
   * Check whether the given entity has a value in this component.
   * @param entity Entity to check whether it has a value in this component for.
   */
  function has(uint256 entity) public view virtual override returns (bool) {
    return entityToValue[entity].length != 0;
  }

  /**
   * Get the raw (abi-encoded) value of the given entity in this component.
   * @param entity Entity to get the raw value in this component for.
   */
  function getRawValue(uint256 entity) public view virtual override returns (bytes memory) {
    // Return the entity's component value
    return entityToValue[entity];
  }

  function getEntities() public view virtual override returns (uint256[] memory) {
    revert BareComponent__NotImplemented();
  }

  function getEntitiesWithValue(bytes memory) public view virtual override returns (uint256[] memory) {
    revert BareComponent__NotImplemented();
  }

  function registerIndexer(address) external virtual {
    revert BareComponent__NotImplemented();
  }

  /**
   * Set the given component value for the given entity.
   * Registers the update in the World contract.
   * Can only be called internally (by the component or contracts deriving from it),
   * without requiring explicit write access.
   * @param entity Entity to set the value for.
   * @param value Value to set for the given entity.
   */
  function _set(uint256 entity, bytes memory value) internal virtual {
    // Store the entity's value;
    entityToValue[entity] = value;

    // Emit global event
    IWorld(world).registerComponentValueSet(entity, value);
  }

  /**
   * Remove the given entity from this component.
   * Registers the update in the World contract.
   * Can only be called internally (by the component or contracts deriving from it),
   * without requiring explicit write access.
   * @param entity Entity to remove from this component.
   */
  function _remove(uint256 entity) internal virtual {
    // Remove the entity from the mapping
    delete entityToValue[entity];

    // Emit global event
    IWorld(world).registerComponentValueRemoved(entity);
  }
}

File 22 of 31 : UInt32BareComponent.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.0;
import "solecs/BareComponent.sol";

contract Uint32BareComponent is BareComponent {
  constructor(address world, uint256 id) BareComponent(world, id) {}

  function getSchema() public pure override returns (string[] memory keys, LibTypes.SchemaValue[] memory values) {
    keys = new string[](1);
    values = new LibTypes.SchemaValue[](1);

    keys[0] = "value";
    values[0] = LibTypes.SchemaValue.UINT32;
  }

  function set(uint256 entity, uint32 value) public {
    set(entity, abi.encode(value));
  }

  function getValue(uint256 entity) public view returns (uint32) {
    uint32 value = abi.decode(getRawValue(entity), (uint32));
    return value;
  }
}

File 23 of 31 : console.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

library console {
    address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);

    function _sendLogPayload(bytes memory payload) private view {
        uint256 payloadLength = payload.length;
        address consoleAddress = CONSOLE_ADDRESS;
        /// @solidity memory-safe-assembly
        assembly {
            let payloadStart := add(payload, 32)
            let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0)
        }
    }

    function log() internal view {
        _sendLogPayload(abi.encodeWithSignature("log()"));
    }

    function logInt(int p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(int)", p0));
    }

    function logUint(uint p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint)", p0));
    }

    function logString(string memory p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
    }

    function logBool(bool p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
    }

    function logAddress(address p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
    }

    function logBytes(bytes memory p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0));
    }

    function logBytes1(bytes1 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0));
    }

    function logBytes2(bytes2 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0));
    }

    function logBytes3(bytes3 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0));
    }

    function logBytes4(bytes4 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0));
    }

    function logBytes5(bytes5 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0));
    }

    function logBytes6(bytes6 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0));
    }

    function logBytes7(bytes7 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0));
    }

    function logBytes8(bytes8 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0));
    }

    function logBytes9(bytes9 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0));
    }

    function logBytes10(bytes10 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0));
    }

    function logBytes11(bytes11 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0));
    }

    function logBytes12(bytes12 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0));
    }

    function logBytes13(bytes13 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0));
    }

    function logBytes14(bytes14 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0));
    }

    function logBytes15(bytes15 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0));
    }

    function logBytes16(bytes16 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0));
    }

    function logBytes17(bytes17 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0));
    }

    function logBytes18(bytes18 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0));
    }

    function logBytes19(bytes19 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0));
    }

    function logBytes20(bytes20 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0));
    }

    function logBytes21(bytes21 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0));
    }

    function logBytes22(bytes22 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0));
    }

    function logBytes23(bytes23 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0));
    }

    function logBytes24(bytes24 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0));
    }

    function logBytes25(bytes25 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0));
    }

    function logBytes26(bytes26 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0));
    }

    function logBytes27(bytes27 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0));
    }

    function logBytes28(bytes28 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0));
    }

    function logBytes29(bytes29 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0));
    }

    function logBytes30(bytes30 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0));
    }

    function logBytes31(bytes31 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0));
    }

    function logBytes32(bytes32 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0));
    }

    function log(uint p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint)", p0));
    }

    function log(string memory p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
    }

    function log(bool p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
    }

    function log(address p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
    }

    function log(uint p0, uint p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint)", p0, p1));
    }

    function log(uint p0, string memory p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string)", p0, p1));
    }

    function log(uint p0, bool p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool)", p0, p1));
    }

    function log(uint p0, address p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address)", p0, p1));
    }

    function log(string memory p0, uint p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint)", p0, p1));
    }

    function log(string memory p0, string memory p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1));
    }

    function log(string memory p0, bool p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1));
    }

    function log(string memory p0, address p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1));
    }

    function log(bool p0, uint p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint)", p0, p1));
    }

    function log(bool p0, string memory p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1));
    }

    function log(bool p0, bool p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1));
    }

    function log(bool p0, address p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1));
    }

    function log(address p0, uint p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint)", p0, p1));
    }

    function log(address p0, string memory p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1));
    }

    function log(address p0, bool p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1));
    }

    function log(address p0, address p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1));
    }

    function log(uint p0, uint p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2));
    }

    function log(uint p0, uint p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2));
    }

    function log(uint p0, uint p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2));
    }

    function log(uint p0, uint p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2));
    }

    function log(uint p0, string memory p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2));
    }

    function log(uint p0, string memory p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2));
    }

    function log(uint p0, string memory p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2));
    }

    function log(uint p0, string memory p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2));
    }

    function log(uint p0, bool p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2));
    }

    function log(uint p0, bool p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2));
    }

    function log(uint p0, bool p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2));
    }

    function log(uint p0, bool p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2));
    }

    function log(uint p0, address p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2));
    }

    function log(uint p0, address p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2));
    }

    function log(uint p0, address p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2));
    }

    function log(uint p0, address p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2));
    }

    function log(string memory p0, uint p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2));
    }

    function log(string memory p0, uint p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2));
    }

    function log(string memory p0, uint p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2));
    }

    function log(string memory p0, uint p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2));
    }

    function log(string memory p0, address p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2));
    }

    function log(string memory p0, address p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2));
    }

    function log(string memory p0, address p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2));
    }

    function log(string memory p0, address p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2));
    }

    function log(bool p0, uint p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2));
    }

    function log(bool p0, uint p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2));
    }

    function log(bool p0, uint p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2));
    }

    function log(bool p0, uint p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2));
    }

    function log(bool p0, bool p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2));
    }

    function log(bool p0, bool p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2));
    }

    function log(bool p0, bool p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2));
    }

    function log(bool p0, bool p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2));
    }

    function log(bool p0, address p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2));
    }

    function log(bool p0, address p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2));
    }

    function log(bool p0, address p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2));
    }

    function log(bool p0, address p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2));
    }

    function log(address p0, uint p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2));
    }

    function log(address p0, uint p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2));
    }

    function log(address p0, uint p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2));
    }

    function log(address p0, uint p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2));
    }

    function log(address p0, string memory p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2));
    }

    function log(address p0, string memory p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2));
    }

    function log(address p0, string memory p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2));
    }

    function log(address p0, string memory p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2));
    }

    function log(address p0, bool p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2));
    }

    function log(address p0, bool p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2));
    }

    function log(address p0, bool p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2));
    }

    function log(address p0, bool p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2));
    }

    function log(address p0, address p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2));
    }

    function log(address p0, address p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2));
    }

    function log(address p0, address p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2));
    }

    function log(address p0, address p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2));
    }

    function log(uint p0, uint p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3));
    }

}

File 24 of 31 : VRGDA.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

import { wadExp, wadLn, wadMul, unsafeWadMul, toWadUnsafe } from "solmate/utils/SignedWadMath.sol";

/// @title Variable Rate Gradual Dutch Auction
/// @author transmissions11 <[email protected]>
/// @author FrankieIsLost <[email protected]>
/// @notice Sell tokens roughly according to an issuance schedule.
abstract contract VRGDA {
  /*//////////////////////////////////////////////////////////////
                            VRGDA PARAMETERS
    //////////////////////////////////////////////////////////////*/

  /// @notice Target price for a token, to be scaled according to sales pace.
  /// @dev Represented as an 18 decimal fixed point number.
  int256 public immutable targetPrice;

  /// @dev Precomputed constant that allows us to rewrite a pow() as an exp().
  /// @dev Represented as an 18 decimal fixed point number.
  int256 internal immutable decayConstant;

  /// @notice Sets target price and per time unit price decay for the VRGDA.
  /// @param _targetPrice The target price for a token if sold on pace, scaled by 1e18.
  /// @param _priceDecayPercent The percent price decays per unit of time with no sales, scaled by 1e18.
  constructor(int256 _targetPrice, int256 _priceDecayPercent) {
    targetPrice = _targetPrice;

    decayConstant = wadLn(1e18 - _priceDecayPercent);

    // The decay constant must be negative for VRGDAs to work.
    require(decayConstant < 0, "NON_NEGATIVE_DECAY_CONSTANT");
  }

  /*//////////////////////////////////////////////////////////////
                              PRICING LOGIC
    //////////////////////////////////////////////////////////////*/

  /// @notice Calculate the price of a token according to the VRGDA formula.
  /// @param timeSinceStart Time passed since the VRGDA began, scaled by 1e18.
  /// @param sold The total number of tokens that have been sold so far.
  /// @return The price of a token according to VRGDA, scaled by 1e18.
  function getVRGDAPrice(int256 timeSinceStart, uint256 sold) public view virtual returns (uint256) {
    unchecked {
      // prettier-ignore
      return uint256(wadMul(targetPrice, wadExp(unsafeWadMul(decayConstant,
                // Theoretically calling toWadUnsafe with sold can silently overflow but under
                // any reasonable circumstance it will never be large enough. We use sold + 1 as
                // the VRGDA formula's n param represents the nth token and sold is the n-1th token.
                timeSinceStart - getTargetSaleTime(toWadUnsafe(sold + 1))
            ))));
    }
  }

  /// @dev Given a number of tokens sold, return the target time that number of tokens should be sold by.
  /// @param sold A number of tokens sold, scaled by 1e18, to get the corresponding target sale time for.
  /// @return The target time the tokens should be sold by, scaled by 1e18, where the time is
  /// relative, such that 0 means the tokens should be sold immediately when the VRGDA begins.
  function getTargetSaleTime(int256 sold) public view virtual returns (int256);
}

File 25 of 31 : MerkleProof.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/MerkleProof.sol)

pragma solidity ^0.8.0;

/**
 * @dev These functions deal with verification of Merkle Tree proofs.
 *
 * The tree and the proofs can be generated using our
 * https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
 * You will find a quickstart guide in the readme.
 *
 * WARNING: You should avoid using leaf values that are 64 bytes long prior to
 * hashing, or use a hash function other than keccak256 for hashing leaves.
 * This is because the concatenation of a sorted pair of internal nodes in
 * the merkle tree could be reinterpreted as a leaf value.
 * OpenZeppelin's JavaScript library generates merkle trees that are safe
 * against this attack out of the box.
 */
library MerkleProof {
    /**
     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
     * defined by `root`. For this, a `proof` must be provided, containing
     * sibling hashes on the branch from the leaf to the root of the tree. Each
     * pair of leaves and each pair of pre-images are assumed to be sorted.
     */
    function verify(
        bytes32[] memory proof,
        bytes32 root,
        bytes32 leaf
    ) internal pure returns (bool) {
        return processProof(proof, leaf) == root;
    }

    /**
     * @dev Calldata version of {verify}
     *
     * _Available since v4.7._
     */
    function verifyCalldata(
        bytes32[] calldata proof,
        bytes32 root,
        bytes32 leaf
    ) internal pure returns (bool) {
        return processProofCalldata(proof, leaf) == root;
    }

    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. When processing the proof, the pairs
     * of leafs & pre-images are assumed to be sorted.
     *
     * _Available since v4.4._
     */
    function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = _hashPair(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Calldata version of {processProof}
     *
     * _Available since v4.7._
     */
    function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = _hashPair(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a merkle tree defined by
     * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
     *
     * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
     *
     * _Available since v4.7._
     */
    function multiProofVerify(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProof(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Calldata version of {multiProofVerify}
     *
     * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
     *
     * _Available since v4.7._
     */
    function multiProofVerifyCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProofCalldata(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
     * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
     * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
     * respectively.
     *
     * CAUTION: Not all merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
     * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
     * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
     *
     * _Available since v4.7._
     */
    function processMultiProof(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32[] memory leaves
    ) internal pure returns (bytes32 merkleRoot) {
        // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 totalHashes = proofFlags.length;

        // Check proof validity.
        require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](totalHashes);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < totalHashes; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
            hashes[i] = _hashPair(a, b);
        }

        if (totalHashes > 0) {
            return hashes[totalHashes - 1];
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    /**
     * @dev Calldata version of {processMultiProof}.
     *
     * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
     *
     * _Available since v4.7._
     */
    function processMultiProofCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32[] memory leaves
    ) internal pure returns (bytes32 merkleRoot) {
        // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 totalHashes = proofFlags.length;

        // Check proof validity.
        require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](totalHashes);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < totalHashes; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
            hashes[i] = _hashPair(a, b);
        }

        if (totalHashes > 0) {
            return hashes[totalHashes - 1];
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
        return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
    }

    function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, a)
            mstore(0x20, b)
            value := keccak256(0x00, 0x40)
        }
    }
}

File 26 of 31 : IOwned.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.0;

interface IOwned {
  function owner() external view returns (address);
}

File 27 of 31 : LinkedList.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13 <0.9.0;

import "./Array.sol";

type LinkedList is bytes32;

// A basic wrapper around an array that returns a pointer to an element in
// the array. Unfortunately without generics, the user has to cast from a pointer to a type
// held in memory manually
//
// is indexable
//
// data structure:
//   |-----------------------------|                      |-------|
//   |                             v                      |       v  
// [ptr, ptr2, ptr3, ptr4]         {value, other value, next}     {value, other value, next}
//        |                                                       ^
//        |-------------------------------------------------------|
//
// where `mload(add(ptr, linkingOffset))` (aka `next`) == ptr2

library IndexableLinkedListLib {
    using ArrayLib for Array;

    function newIndexableLinkedList(uint16 capacityHint) internal pure returns (LinkedList s) {
        s = LinkedList.wrap(Array.unwrap(ArrayLib.newArray(capacityHint)));
    }

    function capacity(LinkedList self) internal pure returns (uint256 cap) {
        cap = Array.wrap(LinkedList.unwrap(self)).capacity();
    }

    function length(LinkedList self) internal pure returns (uint256 len) {
        len = Array.wrap(LinkedList.unwrap(self)).length();
    }

    function push_no_link(LinkedList self, bytes32 element) internal view returns (LinkedList s) {
        s = LinkedList.wrap(
            Array.unwrap(
                Array.wrap(LinkedList.unwrap(self)).push(uint256(element))
            )
        );
    }

    // linkingOffset is the offset from the element ptr that is written to 
    function push_and_link(LinkedList self, bytes32 element, uint256 linkingOffset) internal view returns (LinkedList s) {
        Array asArray = Array.wrap(LinkedList.unwrap(self));

        uint256 len = asArray.length();
        if (len == 0) {
            // nothing to link to
            Array arrayS = asArray.push(uint256(element), 3);
            s = LinkedList.wrap(Array.unwrap(arrayS));
        } else {
            // over alloc by 3
            Array arrayS = asArray.push(uint256(element), 3);
            uint256 newPtr = arrayS.unsafe_get(len);
            uint256 lastPtr = arrayS.unsafe_get(len - 1);
            
            // link the previous element with the new element
            assembly ("memory-safe") {
                mstore(add(lastPtr, linkingOffset), newPtr)
            }

            s = LinkedList.wrap(Array.unwrap(arrayS));
        }
    }

    function next(LinkedList /*self*/, bytes32 element, uint256 linkingOffset) internal pure returns (bool exists, bytes32 elem) {
        assembly ("memory-safe") {
            elem := mload(add(element, linkingOffset))
            exists := gt(elem, 0x00)
        }
    }

    function get(LinkedList self, uint256 index) internal pure returns (bytes32 elementPointer) {
        elementPointer = bytes32(Array.wrap(LinkedList.unwrap(self)).get(index));
    }

    function unsafe_get(LinkedList self, uint256 index) internal pure returns (bytes32 elementPointer) {
        elementPointer = bytes32(Array.wrap(LinkedList.unwrap(self)).unsafe_get(index));
    }
}

// the only way to traverse is to start at head and iterate via `next`. More memory efficient, better for maps
//
// data structure:
//   |-------------------------tail----------------------------|
//   |head|                                           |--------|
//   |    v                                           |        v
//  head, dataStruct{.., next} }     dataStruct{.., next}     dataStruct{.., next}
//                          |          ^
//                          |----------|
//
// `head` is a packed word split as 80, 80, 80 of linking offset, ptr to first element, ptr to last element
// `head` *isn't* stored in memory because it fits in a word 

library LinkedListLib {
    uint256 constant HEAD_MASK = 0xFFFFFFFFFFFFFFFFFFFF00000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF;
    uint256 constant TAIL_MASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000;

    function newLinkedList(uint80 _linkingOffset) internal pure returns (LinkedList s) {
        assembly ("memory-safe") {
            s := shl(176, _linkingOffset)
        }
    }

    function tail(LinkedList s) internal pure returns (bytes32 elemPtr) {
        assembly ("memory-safe") {
            elemPtr := shr(176, shl(160, s))
        }
    }

    function head(LinkedList s) internal pure returns (bytes32 elemPtr) {
        assembly ("memory-safe") {
            elemPtr := shr(176, shl(80, s))
        }
    }

    function linkingOffset(LinkedList s) internal pure returns (uint80 offset) {
        assembly ("memory-safe") {
            offset := shr(176, s)
        }
    }

    function set_head(LinkedList self, bytes32 element) internal pure returns (LinkedList s) {
        assembly ("memory-safe") {
            s := or(and(self, HEAD_MASK), shl(96, element))
        }
    }

    // manually links one element to another
    function set_link(LinkedList self, bytes32 prevElem, bytes32 nextElem) internal pure {
        assembly ("memory-safe") {
            // store the new element as the `next` ptr for the tail
            mstore(
                add(
                    prevElem, // get the tail ptr
                    shr(176, self) // add the offset size to get `next`
                ),
                nextElem
            )
        }
    }

    function push_and_link(LinkedList self, bytes32 element) internal pure returns (LinkedList s) {
        assembly ("memory-safe") {
            switch gt(shr(176, shl(80, self)), 0) 
            case 1 {
                // store the new element as the `next` ptr for the tail
                mstore(
                    add(
                        shr(176, shl(160, self)), // get the tail ptr
                        shr(176, self) // add the offset size to get `next`
                    ),
                    element
                )

                // update the tail ptr
                s := or(and(self, TAIL_MASK), shl(16, element))
            }
            default {
                // no head, set element as head and tail
                s := or(or(self, shl(96, element)), shl(16, element))
            }
        }
    }

    function next(LinkedList self, bytes32 element) internal pure returns (bool exists, bytes32 elem) {
        assembly ("memory-safe") {
            elem := mload(add(element, shr(176, self)))
            exists := gt(elem, 0x00)
        }
    }
}

File 28 of 31 : Set.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.0;

/**
 * Set of unique uint256
 */
contract Set {
  address private owner;
  uint256[] private items;
  mapping(uint256 => uint256) private itemToIndex;

  constructor() {
    owner = msg.sender;
  }

  modifier onlyOwner() {
    require(msg.sender == owner, "ONLY_OWNER");
    _;
  }

  function add(uint256 item) public onlyOwner {
    if (has(item)) return;

    itemToIndex[item] = items.length;
    items.push(item);
  }

  function remove(uint256 item) public onlyOwner {
    if (!has(item)) return;

    // Copy the last item to the given item's index
    items[itemToIndex[item]] = items[items.length - 1];

    // Update the moved item's stored index to the new index
    itemToIndex[items[itemToIndex[item]]] = itemToIndex[item];

    // Remove the given item's stored index
    delete itemToIndex[item];

    // Remove the last item
    items.pop();
  }

  function getIndex(uint256 item) public view returns (bool, uint256) {
    if (!has(item)) return (false, 0);

    return (true, itemToIndex[item]);
  }

  function has(uint256 item) public view returns (bool) {
    if (items.length == 0) return false;
    if (itemToIndex[item] == 0) return items[0] == item;
    return itemToIndex[item] != 0;
  }

  function getItems() public view returns (uint256[] memory) {
    return items;
  }

  function size() public view returns (uint256) {
    return items.length;
  }
}

File 29 of 31 : MapSet.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.0;

/**
 * Key value store with uint256 key and uint256 Set value
 */
contract MapSet {
  address private owner;
  mapping(uint256 => uint256[]) private items;
  mapping(uint256 => mapping(uint256 => uint256)) private itemToIndex;

  constructor() {
    owner = msg.sender;
  }

  modifier onlyOwner() {
    require(msg.sender == owner, "ONLY_OWNER");
    _;
  }

  function add(uint256 setKey, uint256 item) public onlyOwner {
    if (has(setKey, item)) return;

    itemToIndex[setKey][item] = items[setKey].length;
    items[setKey].push(item);
  }

  function remove(uint256 setKey, uint256 item) public onlyOwner {
    if (!has(setKey, item)) return;

    // Copy the last item to the given item's index
    items[setKey][itemToIndex[setKey][item]] = items[setKey][items[setKey].length - 1];

    // Update the moved item's stored index to the new index
    itemToIndex[setKey][items[setKey][itemToIndex[setKey][item]]] = itemToIndex[setKey][item];

    // Remove the given item's stored index
    delete itemToIndex[setKey][item];

    // Remove the last item
    items[setKey].pop();
  }

  function has(uint256 setKey, uint256 item) public view returns (bool) {
    if (items[setKey].length == 0) return false;
    if (itemToIndex[setKey][item] == 0) return items[setKey][0] == item;
    return itemToIndex[setKey][item] != 0;
  }

  function getItems(uint256 setKey) public view returns (uint256[] memory) {
    return items[setKey];
  }

  function size(uint256 setKey) public view returns (uint256) {
    return items[setKey].length;
  }
}

File 30 of 31 : LibTypes.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.8.13;

/**
 * Enum of supported schema types
 */
library LibTypes {
  enum SchemaValue {
    BOOL,
    INT8,
    INT16,
    INT32,
    INT64,
    INT128,
    INT256,
    INT,
    UINT8,
    UINT16,
    UINT32,
    UINT64,
    UINT128,
    UINT256,
    BYTES,
    STRING,
    ADDRESS,
    BYTES4,
    BOOL_ARRAY,
    INT8_ARRAY,
    INT16_ARRAY,
    INT32_ARRAY,
    INT64_ARRAY,
    INT128_ARRAY,
    INT256_ARRAY,
    INT_ARRAY,
    UINT8_ARRAY,
    UINT16_ARRAY,
    UINT32_ARRAY,
    UINT64_ARRAY,
    UINT128_ARRAY,
    UINT256_ARRAY,
    BYTES_ARRAY,
    STRING_ARRAY
  }
}

File 31 of 31 : Array.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13 <0.9.0;

// create a user defined type that is a pointer to memory
type Array is bytes32;

/* 
Memory layout:
offset..offset+32: current first unset element (cheaper to have it first most of the time), aka "length"
offset+32..offset+64: capacity of elements in array
offset+64..offset+64+(capacity*32): elements

nominclature:
 - capacity: total number of elements able to be stored prior to having to perform a move
 - length/current unset index: the number of defined items in the array

a dynamic array is such a primitive data structure that it should be extremely optimized. so everything is in assembly
*/
library ArrayLib {
    function newArray(uint16 capacityHint) internal pure returns (Array s) {
        assembly ("memory-safe") {
            // grab free mem ptr
            s := mload(0x40)
            
            // update free memory pointer based on array's layout:
            //  + 32 bytes for capacity
            //  + 32 bytes for current unset pointer/length
            //  + 32*capacity
            //  + current free memory pointer (s is equal to mload(0x40)) 
            mstore(0x40, add(s, mul(add(0x02, capacityHint), 0x20)))

            // store the capacity in the second word (see memory layout above)
            mstore(add(0x20, s), capacityHint)

            // store length as 0 because otherwise the compiler may have rugged us
            mstore(s, 0x00)
        }
    }

    // capacity of elements before a move would occur
    function capacity(Array self) internal pure returns (uint256 cap) {
        assembly ("memory-safe") {
            cap := mload(add(0x20, self))
        }
    }

    // number of set elements in the array
    function length(Array self) internal pure returns (uint256 len) {
        assembly ("memory-safe") {
            len := mload(self)
        }
    }

    // gets a ptr to an element
    function unsafe_ptrToElement(Array self, uint256 index) internal pure returns (bytes32 ptr) {
        assembly ("memory-safe") {
            ptr := add(self, mul(0x20, add(0x02, index)))
        }
    }

    // overloaded to default push function with 0 overallocation
    function push(Array self, uint256 elem) internal view returns (Array ret) {
        ret = push(self, elem, 0);
    }

    // push an element safely into the array - will perform a move if needed as well as updating the free memory pointer
    // returns the new pointer.
    //
    // WARNING: if a move occurs, the user *must* update their pointer, thus the returned updated pointer. safest
    // method is *always* updating the pointer
    function push(Array self, uint256 elem, uint256 overalloc) internal view returns (Array) {
        Array ret;
        assembly ("memory-safe") {
            // set the return ptr
            ret := self
            // check if length == capacity (meaning no more preallocated space)
            switch eq(mload(self), mload(add(0x20, self))) 
            case 1 {
                // optimization: check if the free memory pointer is equal to the end of the preallocated space
                // if it is, we can just natively extend the array because nothing has been allocated *after*
                // us. i.e.:
                // evm_memory = [00...free_mem_ptr...Array.length...Array.lastElement]
                // this check compares free_mem_ptr to Array.lastElement, if they are equal, we know there is nothing after
                //
                // optimization 2: length == capacity in this case (per above) so we can avoid an add to look at capacity
                // to calculate where the last element it
                switch eq(mload(0x40), add(self, mul(add(0x02, mload(self)), 0x20))) 
                case 1 {
                    // the free memory pointer hasn't moved, i.e. free_mem_ptr == Array.lastElement, just extend

                    // Add 1 to the Array.capacity
                    mstore(add(0x20, self), add(0x01, mload(add(0x20, self))))

                    // the free mem ptr is where we want to place the next element
                    mstore(mload(0x40), elem)

                    // move the free_mem_ptr by a word (32 bytes. 0x20 in hex)
                    mstore(0x40, add(0x20, mload(0x40)))

                    // update the length
                    mstore(self, add(0x01, mload(self)))
                }
                default {
                    // we couldn't do the above optimization, use the `identity` precompile to perform a memory move
                    
                    // move the array to the free mem ptr by using the identity precompile which just returns the values
                    let array_size := mul(add(0x02, mload(self)), 0x20)
                    pop(
                        staticcall(
                            gas(), // pass gas
                            0x04,  // call identity precompile address 
                            self,  // arg offset == pointer to self
                            array_size,  // arg size: capacity + 2 * word_size (we add 2 to capacity to account for capacity and length words)
                            mload(0x40), // set return buffer to free mem ptr
                            array_size   // identity just returns the bytes of the input so equal to argsize 
                        )
                    )
                    
                    // add the element to the end of the array
                    mstore(add(mload(0x40), array_size), elem)

                    // add to the capacity
                    mstore(
                        add(0x20, mload(0x40)), // free_mem_ptr + word == new capacity word
                        add(add(0x01, overalloc), mload(add(0x20, mload(0x40)))) // add one + overalloc to capacity
                    )

                    // add to length
                    mstore(mload(0x40), add(0x01, mload(mload(0x40))))

                    // set the return ptr to the new array
                    ret := mload(0x40)

                    // update free memory pointer
                    // we also over allocate if requested
                    mstore(0x40, add(add(array_size, add(0x20, mul(overalloc, 0x20))), mload(0x40)))
                }
            }
            default {
                // we have capacity for the new element, store it
                mstore(
                    // mem_loc := capacity_ptr + (capacity + 2) * 32
                    // we add 2 to capacity to acct for capacity and length words, then multiply by element size
                    add(self, mul(add(0x02, mload(self)), 0x20)), 
                    elem
                )

                // update length
                mstore(self, add(0x01, mload(self)))
            }
        }
        return ret;
    }

    // used when you *guarantee* that the array has the capacity available to be pushed to.
    // no need to update return pointer in this case
    //
    // NOTE: marked as memory safe, but potentially not memory safe if the safety contract is broken by the caller
    function unsafe_push(Array self, uint256 elem) internal pure {
        assembly ("memory-safe") {
            mstore(
                // mem_loc := capacity_ptr + (capacity + 2) * 32
                // we add 2 to capacity to acct for capacity and length words, then multiply by element size
                add(self, mul(add(0x02, mload(self)), 0x20)),
                elem
            )

            // update length
            mstore(self, add(0x01, mload(self)))
        }
    }

    // used when you *guarantee* that the index, i, is within the bounds of length
    // NOTE: marked as memory safe, but potentially not memory safe if the safety contract is broken by the caller
    function unsafe_set(Array self, uint256 i, uint256 value) internal pure {
        assembly ("memory-safe") {
            mstore(add(self, mul(0x20, add(0x02, i))), value)
        }
    }

    function set(Array self, uint256 i, uint256 value) internal pure {
        // if the index is greater than or equal to the capacity, revert
        assembly ("memory-safe") {
            if lt(mload(add(0x20, self)), i) {
                // emit compiler native Panic(uint256) style error
                mstore(0x00, 0x4e487b7100000000000000000000000000000000000000000000000000000000)
                mstore(0x04, 0x32)
                revert(0, 0x24)
            }
            mstore(add(self, mul(0x20, add(0x02, i))), value)
        }
    }

    // used when you *guarantee* that the index, i, is within the bounds of length
    // NOTE: marked as memory safe, but potentially not memory safe if the safety contract is broken by the caller
    function unsafe_get(Array self, uint256 i) internal pure returns (uint256 s) {
        assembly ("memory-safe") {
            s := mload(add(self, mul(0x20, add(0x02, i))))
        }
    }

    // a safe `get` that checks capacity
    function get(Array self, uint256 i) internal pure returns (uint256 s) {
        // if the index is greater than or equal to the capacity, revert
        assembly ("memory-safe") {
            if lt(mload(add(0x20, self)), i) {
                // emit compiler native Panic(uint256) style error
                mstore(0x00, 0x4e487b7100000000000000000000000000000000000000000000000000000000)
                mstore(0x04, 0x32)
                revert(0, 0x24)
            }
            s := mload(add(self, mul(0x20, add(0x02, i))))
        }
    } 
}

// A wrapper around the lower level array that does one layer of indirection so that the pointer
// the user has to hold never moves. Effectively a reference to the array. i.e. push doesn't return anything
// because it doesnt need to. Slightly less efficient, generally adds 1-3 memops per func
library RefArrayLib {
    using ArrayLib for Array;

    function newArray(uint16 capacityHint) internal pure returns (Array s) {
        Array referenced = ArrayLib.newArray(capacityHint);
        assembly ("memory-safe") {
            // grab free memory pointer for return value
            s := mload(0x40)
            // store referenced array in s
            mstore(mload(0x40), referenced)
            // update free mem ptr
            mstore(0x40, add(mload(0x40), 0x20))
        }
    }

    // capacity of elements before a move would occur
    function capacity(Array self) internal pure returns (uint256 cap) {
        assembly ("memory-safe") {
            cap := mload(add(0x20, mload(self)))
        }
    }

    // number of set elements in the array
    function length(Array self) internal pure returns (uint256 len) {
        assembly ("memory-safe") {
            len := mload(mload(self))
        }
    }

    // gets a ptr to an element
    function unsafe_ptrToElement(Array self, uint256 index) internal pure returns (bytes32 ptr) {
        assembly ("memory-safe") {
            ptr := add(mload(self), mul(0x20, add(0x02, index)))
        }
    }

    // overloaded to default push function with 0 overallocation
    function push(Array self, uint256 elem) internal view {
        push(self, elem, 0);
    }

    // dereferences the array
    function deref(Array self) internal pure returns (Array s) {
        assembly ("memory-safe") {
            s := mload(self)
        }
    }

    // push an element safely into the array - will perform a move if needed as well as updating the free memory pointer
    function push(Array self, uint256 elem, uint256 overalloc) internal view {
        Array newArr = deref(self).push(elem, overalloc);
        assembly ("memory-safe") {
            // we always just update the pointer because it is cheaper to do so than check whether
            // the array moved
            mstore(self, newArr)
        }
    }

    // used when you *guarantee* that the array has the capacity available to be pushed to.
    // no need to update return pointer in this case
    function unsafe_push(Array self, uint256 elem) internal pure {
        // no need to update pointer
        deref(self).unsafe_push(elem);
    }

    // used when you *guarantee* that the index, i, is within the bounds of length
    // NOTE: marked as memory safe, but potentially not memory safe if the safety contract is broken by the caller
    function unsafe_set(Array self, uint256 i, uint256 value) internal pure {
        deref(self).unsafe_set(i, value);
    }

    function set(Array self, uint256 i, uint256 value) internal pure {
        deref(self).set(i, value);
    }

    // used when you *guarantee* that the index, i, is within the bounds of length
    // NOTE: marked as memory safe, but potentially not memory safe if the safety contract is broken by the caller
    function unsafe_get(Array self, uint256 i) internal pure returns (uint256 s) {
        s = deref(self).unsafe_get(i);
    }

    // a safe `get` that checks capacity
    function get(Array self, uint256 i) internal pure returns (uint256 s) {
        s = deref(self).get(i);
    }
}

Settings
{
  "remappings": [
    "@openzeppelin/=node_modules/@openzeppelin/",
    "base64/=node_modules/base64-sol/",
    "ds-test/=node_modules/ds-test/src/",
    "forge-std/=node_modules/forge-std/src/",
    "gsn/=node_modules/@opengsn/contracts/src/",
    "memmove/=node_modules/memmove/src/",
    "royalty-registry/=node_modules/@manifoldxyz/royalty-registry-solidity/contracts/",
    "solecs/=node_modules/@latticexyz/solecs/src/",
    "solmate/=node_modules/solmate/src/",
    "std-contracts/=node_modules/@latticexyz/std-contracts/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 1000000
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract IWorld","name":"_world","type":"address"},{"internalType":"address","name":"_components","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyClaimedPayout","type":"error"},{"inputs":[],"name":"AlreadySetupGrid","type":"error"},{"inputs":[],"name":"BoundTooLong","type":"error"},{"inputs":[],"name":"BoundsDoNotMatch","type":"error"},{"inputs":[],"name":"EmptyLetterInBounds","type":"error"},{"inputs":[],"name":"EmptyLetterNotOnExisting","type":"error"},{"inputs":[],"name":"GameNotOver","type":"error"},{"inputs":[],"name":"GameOver","type":"error"},{"inputs":[],"name":"InvalidBoundEdges","type":"error"},{"inputs":[],"name":"InvalidBoundLength","type":"error"},{"inputs":[],"name":"InvalidCrossProofs","type":"error"},{"inputs":[],"name":"InvalidEmptyLetterBound","type":"error"},{"inputs":[],"name":"InvalidWord","type":"error"},{"inputs":[],"name":"InvalidWordEnd","type":"error"},{"inputs":[],"name":"InvalidWordStart","type":"error"},{"inputs":[],"name":"LetterOnExistingTile","type":"error"},{"inputs":[],"name":"LonelyWord","type":"error"},{"inputs":[],"name":"NoLettersPlayed","type":"error"},{"inputs":[],"name":"PaymentTooLow","type":"error"},{"inputs":[],"name":"WordTooLong","type":"error"},{"inputs":[{"internalType":"enum Letter[]","name":"word","type":"uint8[]"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"components":[{"internalType":"int32","name":"x","type":"int32"},{"internalType":"int32","name":"y","type":"int32"}],"internalType":"struct Position","name":"position","type":"tuple"},{"internalType":"enum Direction","name":"direction","type":"uint8"},{"internalType":"contract TileComponent","name":"tiles","type":"address"}],"name":"checkWord","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimPayout","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"endTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"arguments","type":"bytes"}],"name":"execute","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum Letter[]","name":"word","type":"uint8[]"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"components":[{"internalType":"int32","name":"x","type":"int32"},{"internalType":"int32","name":"y","type":"int32"}],"internalType":"struct Position","name":"position","type":"tuple"},{"internalType":"enum Direction","name":"direction","type":"uint8"},{"components":[{"internalType":"uint32[]","name":"positive","type":"uint32[]"},{"internalType":"uint32[]","name":"negative","type":"uint32[]"},{"internalType":"bytes32[][]","name":"proofs","type":"bytes32[][]"}],"internalType":"struct Bounds","name":"bounds","type":"tuple"}],"name":"executeTyped","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"fundTreasury","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"enum Letter","name":"letter","type":"uint8"}],"name":"getPriceForLetter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum Letter[]","name":"word","type":"uint8[]"}],"name":"getPriceForWord","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int256","name":"sold","type":"int256"}],"name":"getTargetSaleTime","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTreasury","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int256","name":"timeSinceStart","type":"int256"},{"internalType":"uint256","name":"sold","type":"uint256"}],"name":"getVRGDAPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardFraction","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"setupInitialGrid","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"targetPrice","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vrgdaPerTimeUnit","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vrgdaPriceDecayPercent","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vrgdaTargetPrice","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"}]

6101a06040526601c6bf5263400060e052670aaf96eb9d0d0000610100526801158e460913d00000610120524261014081905262000041906207e9006200088e565b610160526004610180527fd848d23e6ac07f7c22c9cb0e121f568619a636d37fab669e76595adfda2162736003553480156200007c57600080fd5b506040516200484e3803806200484e8339810160408190526200009f91620008c3565b60e0516101005161012051600280546001600160a01b03191633179055828286866001600160a01b03811615620000d757806200013c565b816001600160a01b031663ba62fbe46040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000116573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200013c919062000902565b600080546001600160a01b039283166001600160a01b0319918216179091556001805494909216931692909217909155506080829052620001906200018a82670de0b6b3a764000062000929565b6200064f565b60a0819052600013620001ea5760405162461bcd60e51b815260206004820152601b60248201527f4e4f4e5f4e454741544956455f44454341595f434f4e5354414e54000000000060448201526064015b60405180910390fd5b505060c0525050600460208190527fabd6e7cb50984ff9c2f3e18a2660c3353dadf4e3291deeb275dae2cd1e44fe058054600160ff1991821681179092557f91da3fd0782e51c6b3986e9e672fd566868e71f3dbc2d6c2cd6fbb3e361af2a78054600390831681179091557f2e174c10e159ea99b867ce3205125c24a42d128804e4070ed6fcc8cc98166aa080548316821790557f1a1e6821cde7d0159c0d293177871e09677b4e42307c7db3ba94f8648a5a050f8054600290841681179091557f04cde762ef08b6b6c5ded8e8c4c0b3f4e5c9ad7342c88fcc93681b4588b73f0580548416851790557fc59312466997bb42aaaf719ece141047820e6b34531e1670dc1852a453648f0f80548416861790557fbeb3bad75134cb432e5707980e3245c52c5998a1125ee30f2f0dbf3925b1e5518054841690911790557f2645749a946633740611cfc8178319f0958659d6922e4bf7e3a08b44789f53a480548316851790557f4ad5a04d53b5856f318545bb721f67d3f6d0a5a999f25eec7e20eaeb4c47b93380548316841790557f5c6b02db8b672415ffad906d7ccee10bd53dbad7d0b29e2bc0e50c93d5f310938054600890841681179091557f0c1469ad586d86b6976c45826d7ae56d76ee516e37a2bccffbe904b74dbae7ea8054841660051790557f140aabff1a85df08546c9a350c79ae18341bde4a2cef5d2fd460885c0128ce2680548416851790557fa5022b2bfd144bf9103d80168549b5df7c72ab60bd51bf71a02a08d844853b4a80548416831790557feb3e677499e881fe1bdbc344a49c412138038a9f40883b6dc68f713aab48352380548416851790557f66b61daf77b854ca6ba000a8d4b340eafcdb71b6583753b4af89fceb54988fff80548416851790557f4a597304b2df0a7a7b428b3c24c35ba6373aabebf9972387f5610f74a01b21bd805484169092179091557fac375bcb880242328180c23d4a918023a12a7caf7cf12b8c4074e4a3f39900a08054600a90841681179091557f7f6fa3f34639ea1891363ca773619dbd5f652d7ab50411111dde2f57e3ae13ad80548416851790557f9bbf2ad10217b6212df1939350a047a69b6887b770020d3fa8c328c0653ee98780548416851790557ff7deed9399d719bf61dcb1322c056a03a885c275ab093673b0cc182b84bea06180548416851790557f1bb30a1647f6f6723cb3a88838ce0319afabe51263fc466f2f669a7a24ad88c6805484169094179093557f87e655ef16e4075af30c6a90c2b439f7dcd2d83a606dafadaee10cffaf91813280548316851790557fff624574ceefb6578b3887a7448cf2ca4d120002f646987b0a9b9ad3f6dc2c1080548316851790557f1ac66383b86984a837d32661c9fdda480194de6e2dbd3891e29fadcb763a62da8054831690911790557feb5726be0cc40daa58a5f8f81528465ddb0c35e1e56e157eca916d69d6c3432480548216909317909255601a6000527ff6eb4279aa452568dd287204244d7e29d7ca1bc7a01440f08342bf2599f4b9b68054909216179055505062000953565b60008082136200068e5760405162461bcd60e51b815260206004820152600960248201526815539111519253915160ba1b6044820152606401620001e1565b5060606001600160801b03821160071b82811c6001600160401b031060061b1782811c63ffffffff1060051b1782811c61ffff1060041b1782811c60ff10600390811b90911783811c600f1060021b1783811c909110600190811b90911783811c90911017609f81810383019390931b90921c6c465772b2bbbb5f824b15207a3081018102821d6d0388eaa27412d5aca026815d636e018102821d6d0df99ac502031bf953eff472fdcc018102821d6d13cdffb29d51d99322bdff5f2211018102821d6d0a0f742023def783a307a986912e018102821d6d01920d8043ca89b5239253284e42018102821d6c0b7a86d7375468fac667a0a527016c29508e458543d8aa4df2abee7882018202831d6d0139601a2efabe717e604cbb4894018202831d6d02247f7a7b6594320649aa03aba1018202831d6c8c3f38e95a6b1ff2ab1c3b343619018202831d6d02384773bdf1ac5676facced60901901820290921d6cb9a025d814b29c212b8b1a07cd19010260016c0504a838426634cdd8738f543560611b03190105711340daa0d5f769dba1915cef59f0815a550602605f19919091017d0267a36c0c95b3975ab3ee5b203a7614a3f75373f047d803ae7b6687f2b302017d57115e47018c7177eebf7cd370a3356a1b7863008a5ae8028c72b88642840160ae1d90565b634e487b7160e01b600052601160045260246000fd5b80820180821115620008a457620008a462000878565b92915050565b6001600160a01b0381168114620008c057600080fd5b50565b60008060408385031215620008d757600080fd5b8251620008e481620008aa565b6020840151909250620008f781620008aa565b809150509250929050565b6000602082840312156200091557600080fd5b81516200092281620008aa565b9392505050565b81810360008312801583831316838312821617156200094c576200094c62000878565b5092915050565b60805160a05160c05160e0516101005161012051610140516101605161018051613e60620009ee6000396000818161034b0152818161188f015261226b0152600081816101e10152818161131d01526116c10152600081816102930152610ab2015260006102fc015260006103b30152600061023f0152600061128d0152600061166f01526000818161037f01526116480152613e606000f3fe6080604052600436106101445760003560e01c80638da5cb5b116100c0578063dc38679c11610074578063e88499a911610059578063e88499a9146103d5578063ee1c59e9146103ea578063f466d4ab1461040a57600080fd5b8063dc38679c1461036d578063dd9208ae146103a157600080fd5b8063b9c18685116100a5578063b9c186851461031e578063c3f6fc9214610326578063c7c1ea4b1461033957600080fd5b80638da5cb5b146102b55780639cd64232146102ea57600080fd5b80633b19e84a116101175780634163e2de116100fc5780634163e2de1461022d5780636d9d33b71461026157806378e979251461028157600080fd5b80633b19e84a146102035780634011512f1461021857600080fd5b806309c5eabe146101495780630be523201461017f5780630f3e64a2146101a15780633197cbb6146101cf575b600080fd5b34801561015557600080fd5b50610169610164366004612ea5565b61042a565b6040516101769190612f58565b60405180910390f35b34801561018b57600080fd5b5061019f61019a366004613147565b610469565b005b3480156101ad57600080fd5b506101c16101bc3660046131e4565b610a5f565b604051908152602001610176565b3480156101db57600080fd5b506101c17f000000000000000000000000000000000000000000000000000000000000000081565b34801561020f57600080fd5b506006546101c1565b34801561022457600080fd5b5061019f610bf0565b34801561023957600080fd5b506101c17f000000000000000000000000000000000000000000000000000000000000000081565b34801561026d57600080fd5b506101c161027c366004613201565b611289565b34801561028d57600080fd5b506101c17f000000000000000000000000000000000000000000000000000000000000000081565b3480156102c157600080fd5b5060025460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610176565b3480156102f657600080fd5b506101c17f000000000000000000000000000000000000000000000000000000000000000081565b61019f6112bf565b610169610334366004613290565b6112df565b34801561034557600080fd5b506101c17f000000000000000000000000000000000000000000000000000000000000000081565b34801561037957600080fd5b506101c17f000000000000000000000000000000000000000000000000000000000000000081565b3480156103ad57600080fd5b506101c17f000000000000000000000000000000000000000000000000000000000000000081565b3480156103e157600080fd5b5061019f61131b565b3480156103f657600080fd5b506101c161040536600461341f565b6115a6565b34801561041657600080fd5b506101c1610425366004613454565b611641565b6060600080600080600086806020019051810190610448919061367e565b9450945094509450945061045f85858585856116bf565b5050505050919050565b60c8855111156104a5576040517f24426e2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1663408d96216104ec7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86866118fa565b6040518263ffffffff1660e01b8152600401610508919061378a565b602060405180830381865afa158015610525573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061054991906137ab565b15610580576040517f8016119c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1663408d96216105a8875186866118fa565b6040518263ffffffff1660e01b81526004016105c4919061378a565b602060405180830381865afa1580156105e1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060591906137ab565b1561063c576040517f6ec1bda600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806000875167ffffffffffffffff81111561065b5761065b612ddb565b604051908082528060200260200182016040528015610684578160200160208202803683370190505b50905060005b88518163ffffffff1610156109d95760006106a68289896118fa565b905060008a8363ffffffff16815181106106c2576106c26137fc565b6020026020010151601a8111156106db576106db6137cd565b03610890576040517f408d96210000000000000000000000000000000000000000000000000000000081526001955073ffffffffffffffffffffffffffffffffffffffff87169063408d96219061073690849060040161378a565b602060405180830381865afa158015610753573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077791906137ab565b6107ad576040517fe5893dde00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fedd0abb900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87169063edd0abb9906107ff90849060040161378a565b608060405180830381865afa15801561081c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610840919061382b565b60400151838363ffffffff168151811061085c5761085c6137fc565b6020026020010190601a811115610875576108756137cd565b9081601a811115610888576108886137cd565b9052506109c6565b6040517f408d96210000000000000000000000000000000000000000000000000000000081526001945073ffffffffffffffffffffffffffffffffffffffff87169063408d9621906108e690849060040161378a565b602060405180830381865afa158015610903573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061092791906137ab565b1561095e576040517f03f4877500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b898263ffffffff1681518110610976576109766137fc565b6020026020010151838363ffffffff1681518110610996576109966137fc565b6020026020010190601a8111156109af576109af6137cd565b9081601a8111156109c2576109c26137cd565b9052505b50806109d1816138ad565b91505061068a565b5082610a11576040517f08b0f2c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81610a48576040517f95217a0200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a558188600354611991565b5050505050505050565b600080548190610aa59073ffffffffffffffffffffffffffffffffffffffff167f29648ae8e2331b77ae3afd0a1c04805c6c5aa5a17726a131d73f7f6333aa287b611a02565b9050610be9610aec610ad77f0000000000000000000000000000000000000000000000000000000000000000426138d0565b62015180670de0b6b3a7640000919091020490565b6040517fb5243f0600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84169063b5243f0690610b3e9088906004016138f7565b602060405180830381865afa158015610b5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7f9190613905565b60026004600088601a811115610b9757610b976137cd565b601a811115610ba857610ba86137cd565b8152602081019190915260400160002054610bc79060ff166001613922565b610bd1919061396a565b60ff16610bde919061398c565b63ffffffff16611641565b9392505050565b60008054610c349073ffffffffffffffffffffffffffffffffffffffff167f30f1c358b0a577824afcc8e464bcbd763eba254820a547b425765e75cc511f1e611a02565b6040805180820182526000808252602082015290517f408d962100000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff83169163408d962191610c999160040161378a565b602060405180830381865afa158015610cb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cda91906137ab565b15610d11576040517fbdb5af4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516060810182526000808252825180840184528181526020808201929092529082015260098183015290517ffb8fde7300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83169163fb8fde7391610d8d91906004016139b4565b600060405180830381600087803b158015610da757600080fd5b505af1158015610dbb573d6000803e3d6000fd5b5050604080516060810182526000808252825180840184526001815260208082019290925290820152600e8183015290517ffb8fde7300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516935063fb8fde739250610e3c91906004016139b4565b600060405180830381600087803b158015610e5657600080fd5b505af1158015610e6a573d6000803e3d6000fd5b505060408051606081018252600080825282518084018452600281526020808201929092529082015260068183015290517ffb8fde7300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516935063fb8fde739250610eeb91906004016139b4565b600060405180830381600087803b158015610f0557600080fd5b505af1158015610f19573d6000803e3d6000fd5b505060408051606081018252600080825282518084018452600381526020808201929092529082015260098183015290517ffb8fde7300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516935063fb8fde739250610f9a91906004016139b4565b600060405180830381600087803b158015610fb457600080fd5b505af1158015610fc8573d6000803e3d6000fd5b505060408051606081018252600080825282518084018452600480825260208083019390935291830152600e8284015291517ffb8fde7300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8616945063fb8fde73935061104792016139b4565b600060405180830381600087803b15801561106157600080fd5b505af1158015611075573d6000803e3d6000fd5b505060408051606081018252600080825282518084018452600581526020808201929092529082015260098183015290517ffb8fde7300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516935063fb8fde7392506110f691906004016139b4565b600060405180830381600087803b15801561111057600080fd5b505af1158015611124573d6000803e3d6000fd5b505060408051606081018252600080825282518084018452600681526020808201929092529082015260148183015290517ffb8fde7300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516935063fb8fde7392506111a591906004016139b4565b600060405180830381600087803b1580156111bf57600080fd5b505af11580156111d3573d6000803e3d6000fd5b505060408051606081018252600080825282518084018452600781526020808201929092529082015260058183015290517ffb8fde7300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516935063fb8fde73925061125491906004016139b4565b600060405180830381600087803b15801561126e57600080fd5b505af1158015611282573d6000803e3d6000fd5b5050505050565b60007f0000000000000000000000000000000000000000000000000000000000000000670de0b6b3a76400008302055b92915050565b34156112dd5734600660008282546112d79190613a03565b90915550505b565b606061131186868686866040516020016112fd959493929190613b39565b60405160208183030381529060405261042a565b9695505050505050565b7f0000000000000000000000000000000000000000000000000000000000000000421015611375576040517f04643c3900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526005602052604090205460ff16156113bf576040517f8c14de1a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260056020526040812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580546114399073ffffffffffffffffffffffffffffffffffffffff167f8d5746953402e95fa35ce71ddaa7efe7922c48a307985b7d64ea3f27abcb14f9611a02565b6040517fe3352c2b00000000000000000000000000000000000000000000000000000000815233600482015290915060009073ffffffffffffffffffffffffffffffffffffffff83169063e3352c2b90602401606060405180830381865afa1580156114a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114cd9190613be2565b905060008273ffffffffffffffffffffffffffffffffffffffff16632011cdae6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561151c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115409190613905565b63ffffffff16826040015163ffffffff1660065461155e9190613c38565b6115689190613c4f565b6020830151909150336108fc61157e8385613a03565b6040518115909202916000818181858888f19350505050158015611282573d6000803e3d6000fd5b60008060005b83518163ffffffff16101561163a576000848263ffffffff16815181106115d5576115d56137fc565b6020026020010151601a8111156115ee576115ee6137cd565b146116285761161b848263ffffffff168151811061160e5761160e6137fc565b6020026020010151610a5f565b6116259083613a03565b91505b80611632816138ad565b9150506115ac565b5092915050565b6000610be97f00000000000000000000000000000000000000000000000000000000000000006116ba6116b57f00000000000000000000000000000000000000000000000000000000000000006116a4670de0b6b3a76400006001890102611289565b8803670de0b6b3a764000091020590565b611b53565b611d92565b7f00000000000000000000000000000000000000000000000000000000000000004210611718576040517fdf469ccb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611723866115a6565b90508034101561175f576040517f0494526a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080546117a39073ffffffffffffffffffffffffffffffffffffffff167f29648ae8e2331b77ae3afd0a1c04805c6c5aa5a17726a131d73f7f6333aa287b611a02565b905060005b87518163ffffffff16101561188c576000888263ffffffff16815181106117d1576117d16137fc565b6020026020010151601a8111156117ea576117ea6137cd565b1461187a578173ffffffffffffffffffffffffffffffffffffffff1663cc586ed3898363ffffffff1681518110611823576118236137fc565b60200260200101516040518263ffffffff1660e01b815260040161184791906138f7565b600060405180830381600087803b15801561186157600080fd5b505af1158015611875573d6000803e3d6000fd5b505050505b80611884816138ad565b9150506117a8565b507f00000000000000000000000000000000000000000000000000000000000000006118b96001826138d0565b6118c39034613c38565b6118cd9190613c4f565b600660008282546118de9190613a03565b909155506118f190508787878787611db7565b50505050505050565b60408051808201909152600080825260208201526000826001811115611922576119226137cd565b0361195c5760405180604001604052808585600001516119429190613c63565b60030b8152602001846020015160030b8152509050610be9565b6040518060400160405280846000015160030b81526020018585602001516119849190613c63565b60030b9052949350505050565b6000836040516020016119a49190613ca5565b60405160208183030381529060405280519060200120905060006119c9848484611e34565b905080611282576040517fd1bf1a9200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517ffbdfa1ea00000000000000000000000000000000000000000000000000000000815260048101829052600090819073ffffffffffffffffffffffffffffffffffffffff85169063fbdfa1ea90602401600060405180830381865afa158015611a72573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611ab89190810190613ce2565b90508051600003611b2a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f6964206e6f74207265676973746572656400000000000000000000000000000060448201526064015b60405180910390fd5b611b4b81600081518110611b4057611b406137fc565b602002602001015190565b949350505050565b60007ffffffffffffffffffffffffffffffffffffffffffffffffdb731c958f34d94c18213611b8457506000919050565b680755bf798b4a1bf1e58212611bf6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4558505f4f564552464c4f5700000000000000000000000000000000000000006044820152606401611b21565b6503782dace9d9604e83901b059150600060606bb17217f7d1cf79abc9e3b39884821b056b80000000000000000000000001901d6bb17217f7d1cf79abc9e3b39881029093037fffffffffffffffffffffffffffffffffffffffdbf3ccf1604d263450f02a550481018102606090811d6d0277594991cfc85f6e2461837cd9018202811d7fffffffffffffffffffffffffffffffffffffe5adedaa1cb095af9e4da10e363c018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d7ffffffffffffffffffffffffffffffffffffd38dc772608b0ae56cce01296c0eb018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084017ffffffffffffffffffffffffffffffffffffffe2c69812cf03b0763fd454a8f7e010290911d6e0587f503bb6ea29d25fcb7401964500190910279d835ebba824c98fb31b83b2ca45c000000000000000000000000010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b8181028215838205831417611da657600080fd5b670de0b6b3a7640000900592915050565b60008054611dfb9073ffffffffffffffffffffffffffffffffffffffff167f30f1c358b0a577824afcc8e464bcbd763eba254820a547b425765e75cc511f1e611a02565b9050611e0a8686868685610469565b611e178685858585611e4a565b6000611e25878686856121d1565b90506118f181868686866125e4565b600082611e41858461280c565b14949350505050565b60208201515182515114611e8a576040517f7f23a46400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b845182515114611ec6576040517f8c3db81700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408201515182515114611f06576040517feaae398900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b85518163ffffffff1610156121c9576000868263ffffffff1681518110611f3257611f326137fc565b6020026020010151601a811115611f4b57611f4b6137cd565b03611fed578251805163ffffffff8316908110611f6a57611f6a6137fc565b602002602001015163ffffffff166000141580611fb1575082602001518163ffffffff1681518110611f9e57611f9e6137fc565b602002602001015163ffffffff16600014155b15611fe8576040517fedfe90b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6121b7565b60008061204c611ffe8489896118fa565b8787600001518663ffffffff168151811061201b5761201b6137fc565b602002602001015188602001518763ffffffff168151811061203f5761203f6137fc565b6020026020010151612859565b6040517f408d9621000000000000000000000000000000000000000000000000000000008152919350915073ffffffffffffffffffffffffffffffffffffffff85169063408d9621906120a390859060040161378a565b602060405180830381865afa1580156120c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120e491906137ab565b8061217d57506040517f408d962100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85169063408d96219061213c90849060040161378a565b602060405180830381865afa158015612159573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061217d91906137ab565b156121b4576040517fc582491700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505b806121c1816138ad565b915050611f09565b505050505050565b60606000855167ffffffffffffffff8111156121ef576121ef612ddb565b604051908082528060200260200182016040528015612218578160200160208202803683370190505b5060008054919250906122619073ffffffffffffffffffffffffffffffffffffffff167f8d5746953402e95fa35ce71ddaa7efe7922c48a307985b7d64ea3f27abcb14f9611a02565b90506000612290887f0000000000000000000000000000000000000000000000000000000000000000346129b9565b905060005b88518163ffffffff1610156125d75760006122b1828a8a6118fa565b905060008a8363ffffffff16815181106122cd576122cd6137fc565b6020026020010151601a8111156122e6576122e66137cd565b0361246f576040517fedd0abb900000000000000000000000000000000000000000000000000000000815260009073ffffffffffffffffffffffffffffffffffffffff89169063edd0abb99061234090859060040161378a565b608060405180830381865afa15801561235d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612381919061382b565b80516040517f6551ee6b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9182166004820152600060248201819052604482018890526064820152919250861690636551ee6b90608401600060405180830381600087803b15801561240457600080fd5b505af1158015612418573d6000803e3d6000fd5b505050508060400151868463ffffffff1681518110612439576124396137fc565b6020026020010190601a811115612452576124526137cd565b9081601a811115612465576124656137cd565b81525050506125c4565b8673ffffffffffffffffffffffffffffffffffffffff1663fb8fde7360405180606001604052803373ffffffffffffffffffffffffffffffffffffffff1681526020016040518060400160405280866000015160030b8152602001866020015160030b81525081526020018d8663ffffffff16815181106124f2576124f26137fc565b6020026020010151601a81111561250b5761250b6137cd565b8152506040518263ffffffff1660e01b815260040161252a91906139b4565b600060405180830381600087803b15801561254457600080fd5b505af1158015612558573d6000803e3d6000fd5b50505050898263ffffffff1681518110612574576125746137fc565b6020026020010151858363ffffffff1681518110612594576125946137fc565b6020026020010190601a8111156125ad576125ad6137cd565b9081601a8111156125c0576125c06137cd565b9052505b50806125cf816138ad565b915050612295565b5091979650505050505050565b60006125ef86612a45565b905060005b86518163ffffffff161015612723578351805163ffffffff831690811061261d5761261d6137fc565b602002602001015163ffffffff166000141580612664575083602001518163ffffffff1681518110612651576126516137fc565b602002602001015163ffffffff16600014155b156127115760006126c86126798389896118fa565b8787600001518563ffffffff1681518110612696576126966137fc565b602002602001015188602001518663ffffffff16815181106126ba576126ba6137fc565b602002602001015188612ad2565b90506126fa8186604001518463ffffffff16815181106126ea576126ea6137fc565b6020026020010151600354611991565b61270381612a45565b61270d9084613d73565b9250505b8061271b816138ad565b9150506125f4565b50600080546127689073ffffffffffffffffffffffffffffffffffffffff167f8d5746953402e95fa35ce71ddaa7efe7922c48a307985b7d64ea3f27abcb14f9611a02565b6040517f6551ee6b0000000000000000000000000000000000000000000000000000000081523360048201523460248201526000604482015263ffffffff8416606482015290915073ffffffffffffffffffffffffffffffffffffffff821690636551ee6b90608401600060405180830381600087803b1580156127eb57600080fd5b505af11580156127ff573d6000803e3d6000fd5b5050505050505050505050565b600081815b84518110156128515761283d82868381518110612830576128306137fc565b6020026020010151612dac565b91508061284981613d90565b915050612811565b509392505050565b6040805180820190915260008082526020820152604080518082019091526000808252602082015260c88463ffffffff16118061289c575060c88363ffffffff16115b156128d3576040517f7c832cd600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820182528751600390810b82526020808a018051830b8285015284518086019095528a51830b85525190910b9083015290600087600181111561291d5761291d6137cd565b0361296b5761292d856001613c63565b8260200181815161293e9190613dc8565b60030b90525061294f866001613c63565b816020018181516129609190613c63565b60030b9052506129ac565b612976856001613c63565b82518390612985908390613dc8565b60030b905250612996866001613c63565b815182906129a5908390613c63565b60030b9052505b9097909650945050505050565b60008060005b85518163ffffffff161015612a26576000868263ffffffff16815181106129e8576129e86137fc565b6020026020010151601a811115612a0157612a016137cd565b03612a145781612a1081613d90565b9250505b80612a1e816138ad565b9150506129bf565b5080612a328585613c4f565b612a3c9190613c4f565b95945050505050565b60008060005b83518163ffffffff16101561163a5760046000858363ffffffff1681518110612a7657612a766137fc565b6020026020010151601a811115612a8f57612a8f6137cd565b601a811115612aa057612aa06137cd565b8152602081019190915260400160002054612abe9060ff1683613d73565b915080612aca816138ad565b915050612a4b565b60606000612ae08486613d73565b612aeb906001613d73565b905060008163ffffffff1667ffffffffffffffff811115612b0e57612b0e612ddb565b604051908082528060200260200182016040528015612b37578160200160208202803683370190505b5060408051808201909152600080825260208201529091506000886001811115612b6357612b636137cd565b03612ba457612b9d612b95877fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff613e0a565b8a60016118fa565b9050612bdc565b612bd9612bd1877fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff613e0a565b8a60006118fa565b90505b60005b8363ffffffff168163ffffffff161015612d9e576040517fedd0abb900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87169063edd0abb990612c4590859060040161378a565b608060405180830381865afa158015612c62573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c86919061382b565b60400151838263ffffffff1681518110612ca257612ca26137fc565b6020026020010190601a811115612cbb57612cbb6137cd565b9081601a811115612cce57612cce6137cd565b9052506000838263ffffffff1681518110612ceb57612ceb6137fc565b6020026020010151601a811115612d0457612d046137cd565b03612d3b576040517f5cff06e600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000896001811115612d4f57612d4f6137cd565b03612d7257600182602001818151612d679190613c63565b60030b905250612d8c565b600182600001818151612d859190613c63565b60030b9052505b80612d96816138ad565b915050612bdf565b509098975050505050505050565b6000818310612dc8576000828152602084905260409020610be9565b6000838152602083905260409020610be9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715612e2d57612e2d612ddb565b60405290565b6040516060810167ffffffffffffffff81118282101715612e2d57612e2d612ddb565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715612e9d57612e9d612ddb565b604052919050565b60006020808385031215612eb857600080fd5b823567ffffffffffffffff80821115612ed057600080fd5b818501915085601f830112612ee457600080fd5b813581811115612ef657612ef6612ddb565b612f26847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601612e56565b91508082528684828501011115612f3c57600080fd5b8084840185840137600090820190930192909252509392505050565b600060208083528351808285015260005b81811015612f8557858101830151858201604001528201612f69565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b600067ffffffffffffffff821115612fde57612fde612ddb565b5060051b60200190565b601b8110612ff557600080fd5b50565b600082601f83011261300957600080fd5b8135602061301e61301983612fc4565b612e56565b82815260059290921b8401810191818101908684111561303d57600080fd5b8286015b8481101561306157803561305481612fe8565b8352918301918301613041565b509695505050505050565b600082601f83011261307d57600080fd5b8135602061308d61301983612fc4565b82815260059290921b840181019181810190868411156130ac57600080fd5b8286015b8481101561306157803583529183019183016130b0565b8060030b8114612ff557600080fd5b6000604082840312156130e857600080fd5b6130f0612e0a565b905081356130fd816130c7565b8152602082013561310d816130c7565b602082015292915050565b60028110612ff557600080fd5b73ffffffffffffffffffffffffffffffffffffffff81168114612ff557600080fd5b600080600080600060c0868803121561315f57600080fd5b853567ffffffffffffffff8082111561317757600080fd5b61318389838a01612ff8565b9650602088013591508082111561319957600080fd5b506131a68882890161306c565b9450506131b687604088016130d6565b925060808601356131c681613118565b915060a08601356131d681613125565b809150509295509295909350565b6000602082840312156131f657600080fd5b8135610be981612fe8565b60006020828403121561321357600080fd5b5035919050565b63ffffffff81168114612ff557600080fd5b600082601f83011261323d57600080fd5b8135602061324d61301983612fc4565b82815260059290921b8401810191818101908684111561326c57600080fd5b8286015b848110156130615780356132838161321a565b8352918301918301613270565b600080600080600060c086880312156132a857600080fd5b67ffffffffffffffff80873511156132bf57600080fd5b6132cc8888358901612ff8565b9550602080880135828111156132e157600080fd5b6132ed8a828b0161306c565b9650506132fd8960408a016130d6565b9450608088013561330d81613118565b935060a08801358281111561332157600080fd5b88016060818b03121561333357600080fd5b61333b612e33565b838235111561334957600080fd5b6133568b8335840161322c565b8152828201358481111561336957600080fd5b6133758c82850161322c565b848301525060408201358481111561338c57600080fd5b8083019250508a601f8301126133a157600080fd5b81356133af61301982612fc4565b81815260059190911b8301840190848101908d8311156133ce57600080fd5b8585015b838110156134045787813511156133e857600080fd5b6133f78f88833589010161306c565b83529186019186016133d2565b50806040850152505050809450505050509295509295909350565b60006020828403121561343157600080fd5b813567ffffffffffffffff81111561344857600080fd5b611b4b84828501612ff8565b6000806040838503121561346757600080fd5b50508035926020909101359150565b600082601f83011261348757600080fd5b8151602061349761301983612fc4565b82815260059290921b840181019181810190868411156134b657600080fd5b8286015b8481101561306157805183529183019183016134ba565b6000604082840312156134e357600080fd5b6134eb612e0a565b905081516134f8816130c7565b8152602082015161310d816130c7565b805161351381613118565b919050565b600082601f83011261352957600080fd5b8151602061353961301983612fc4565b82815260059290921b8401810191818101908684111561355857600080fd5b8286015b8481101561306157805161356f8161321a565b835291830191830161355c565b60006060828403121561358e57600080fd5b613596612e33565b9050815167ffffffffffffffff808211156135b057600080fd5b6135bc85838601613518565b83526020915081840151818111156135d357600080fd5b6135df86828701613518565b83850152506040840151818111156135f657600080fd5b8401601f8101861361360757600080fd5b805161361561301982612fc4565b81815260059190911b8201840190848101908883111561363457600080fd5b8584015b8381101561366c578051868111156136505760008081fd5b61365e8b8983890101613476565b845250918601918601613638565b50604087015250939695505050505050565b600080600080600060c0868803121561369657600080fd5b855167ffffffffffffffff808211156136ae57600080fd5b818801915088601f8301126136c257600080fd5b815160206136d261301983612fc4565b82815260059290921b8401810191818101908c8411156136f157600080fd5b948201945b8386101561371857855161370981612fe8565b825294820194908201906136f6565b918b015191995090935050508082111561373157600080fd5b61373d89838a01613476565b955061374c8960408a016134d1565b945061375a60808901613508565b935060a088015191508082111561377057600080fd5b5061377d8882890161357c565b9150509295509295909350565b604081016112b98284805160030b8252602081015160030b60208301525050565b6000602082840312156137bd57600080fd5b81518015158114610be957600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006080828403121561383d57600080fd5b613845612e33565b825161385081613125565b815261385f84602085016134d1565b6020820152606083015161387281612fe8565b60408201529392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff8083168181036138c6576138c661387e565b6001019392505050565b818103818111156112b9576112b961387e565b601b81106138f3576138f36137cd565b9052565b602081016112b982846138e3565b60006020828403121561391757600080fd5b8151610be98161321a565b60ff81811683821601908111156112b9576112b961387e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff83168061397d5761397d61393b565b8060ff84160491505092915050565b63ffffffff8181168382160280821691908281146139ac576139ac61387e565b505092915050565b815173ffffffffffffffffffffffffffffffffffffffff1681526020808301518051600390810b838501529181015190910b6040830152608082019050604083015161163a60608401826138e3565b808201808211156112b9576112b961387e565b600081518084526020808501945080840160005b83811015613a4657815187529582019590820190600101613a2a565b509495945050505050565b600081518084526020808501945080840160005b83811015613a4657815163ffffffff1687529582019590820190600101613a65565b6000815160608452613a9c6060850182613a51565b905060208084015185830382870152613ab58382613a51565b925050604084015185830360408701528281518085528385019150838160051b860101848401935060005b82811015613b2c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0878303018452613b1a828651613a16565b94860194938601939150600101613ae0565b5098975050505050505050565b60c0808252865190820181905260009060209060e0840190828a01845b82811015613b7957613b698483516138e3565b9284019290840190600101613b56565b50505083810382850152613b8d8189613a16565b8751600390810b60408701526020890151900b60608601529150613bae9050565b60028510613bbe57613bbe6137cd565b84608084015282810360a0840152613bd68185613a87565b98975050505050505050565b600060608284031215613bf457600080fd5b6040516060810181811067ffffffffffffffff82111715613c1757613c17612ddb565b8060405250825181526020830151602082015260408301516138728161321a565b80820281158282048414176112b9576112b961387e565b600082613c5e57613c5e61393b565b500490565b600381810b9083900b01637fffffff81137fffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000821217156112b9576112b961387e565b815160009082906020808601845b83811015613cd657613cc68583516138e3565b9382019390820190600101613cb3565b50929695505050505050565b60006020808385031215613cf557600080fd5b825167ffffffffffffffff811115613d0c57600080fd5b8301601f81018513613d1d57600080fd5b8051613d2b61301982612fc4565b81815260059190911b82018301908381019087831115613d4a57600080fd5b928401925b82841015613d6857835182529284019290840190613d4f565b979650505050505050565b63ffffffff81811683821601908082111561163a5761163a61387e565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613dc157613dc161387e565b5060010190565b600382810b9082900b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffff800000008112637fffffff821317156112b9576112b961387e565b60008260030b8260030b028060030b915080821461163a5761163a61387e56fea2646970667358221220063a3c8bf7ef552f43e66a134a9eade6ef03ef0ddeb69c0c5068baa72d259ae064736f6c6343000811003300000000000000000000000061f0f349b8c7539854b34f2b81f08a30368851ac000000000000000000000000e26d5e20d796676e54e075e84d6fac6e9c46da26

Deployed Bytecode

0x6080604052600436106101445760003560e01c80638da5cb5b116100c0578063dc38679c11610074578063e88499a911610059578063e88499a9146103d5578063ee1c59e9146103ea578063f466d4ab1461040a57600080fd5b8063dc38679c1461036d578063dd9208ae146103a157600080fd5b8063b9c18685116100a5578063b9c186851461031e578063c3f6fc9214610326578063c7c1ea4b1461033957600080fd5b80638da5cb5b146102b55780639cd64232146102ea57600080fd5b80633b19e84a116101175780634163e2de116100fc5780634163e2de1461022d5780636d9d33b71461026157806378e979251461028157600080fd5b80633b19e84a146102035780634011512f1461021857600080fd5b806309c5eabe146101495780630be523201461017f5780630f3e64a2146101a15780633197cbb6146101cf575b600080fd5b34801561015557600080fd5b50610169610164366004612ea5565b61042a565b6040516101769190612f58565b60405180910390f35b34801561018b57600080fd5b5061019f61019a366004613147565b610469565b005b3480156101ad57600080fd5b506101c16101bc3660046131e4565b610a5f565b604051908152602001610176565b3480156101db57600080fd5b506101c17f000000000000000000000000000000000000000000000000000000006385511481565b34801561020f57600080fd5b506006546101c1565b34801561022457600080fd5b5061019f610bf0565b34801561023957600080fd5b506101c17f0000000000000000000000000000000000000000000000000001c6bf5263400081565b34801561026d57600080fd5b506101c161027c366004613201565b611289565b34801561028d57600080fd5b506101c17f00000000000000000000000000000000000000000000000000000000637d681481565b3480156102c157600080fd5b5060025460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610176565b3480156102f657600080fd5b506101c17f000000000000000000000000000000000000000000000001158e460913d0000081565b61019f6112bf565b610169610334366004613290565b6112df565b34801561034557600080fd5b506101c17f000000000000000000000000000000000000000000000000000000000000000481565b34801561037957600080fd5b506101c17f0000000000000000000000000000000000000000000000000001c6bf5263400081565b3480156103ad57600080fd5b506101c17f0000000000000000000000000000000000000000000000000aaf96eb9d0d000081565b3480156103e157600080fd5b5061019f61131b565b3480156103f657600080fd5b506101c161040536600461341f565b6115a6565b34801561041657600080fd5b506101c1610425366004613454565b611641565b6060600080600080600086806020019051810190610448919061367e565b9450945094509450945061045f85858585856116bf565b5050505050919050565b60c8855111156104a5576040517f24426e2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1663408d96216104ec7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86866118fa565b6040518263ffffffff1660e01b8152600401610508919061378a565b602060405180830381865afa158015610525573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061054991906137ab565b15610580576040517f8016119c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1663408d96216105a8875186866118fa565b6040518263ffffffff1660e01b81526004016105c4919061378a565b602060405180830381865afa1580156105e1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061060591906137ab565b1561063c576040517f6ec1bda600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806000875167ffffffffffffffff81111561065b5761065b612ddb565b604051908082528060200260200182016040528015610684578160200160208202803683370190505b50905060005b88518163ffffffff1610156109d95760006106a68289896118fa565b905060008a8363ffffffff16815181106106c2576106c26137fc565b6020026020010151601a8111156106db576106db6137cd565b03610890576040517f408d96210000000000000000000000000000000000000000000000000000000081526001955073ffffffffffffffffffffffffffffffffffffffff87169063408d96219061073690849060040161378a565b602060405180830381865afa158015610753573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077791906137ab565b6107ad576040517fe5893dde00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fedd0abb900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87169063edd0abb9906107ff90849060040161378a565b608060405180830381865afa15801561081c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610840919061382b565b60400151838363ffffffff168151811061085c5761085c6137fc565b6020026020010190601a811115610875576108756137cd565b9081601a811115610888576108886137cd565b9052506109c6565b6040517f408d96210000000000000000000000000000000000000000000000000000000081526001945073ffffffffffffffffffffffffffffffffffffffff87169063408d9621906108e690849060040161378a565b602060405180830381865afa158015610903573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061092791906137ab565b1561095e576040517f03f4877500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b898263ffffffff1681518110610976576109766137fc565b6020026020010151838363ffffffff1681518110610996576109966137fc565b6020026020010190601a8111156109af576109af6137cd565b9081601a8111156109c2576109c26137cd565b9052505b50806109d1816138ad565b91505061068a565b5082610a11576040517f08b0f2c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81610a48576040517f95217a0200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a558188600354611991565b5050505050505050565b600080548190610aa59073ffffffffffffffffffffffffffffffffffffffff167f29648ae8e2331b77ae3afd0a1c04805c6c5aa5a17726a131d73f7f6333aa287b611a02565b9050610be9610aec610ad77f00000000000000000000000000000000000000000000000000000000637d6814426138d0565b62015180670de0b6b3a7640000919091020490565b6040517fb5243f0600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84169063b5243f0690610b3e9088906004016138f7565b602060405180830381865afa158015610b5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7f9190613905565b60026004600088601a811115610b9757610b976137cd565b601a811115610ba857610ba86137cd565b8152602081019190915260400160002054610bc79060ff166001613922565b610bd1919061396a565b60ff16610bde919061398c565b63ffffffff16611641565b9392505050565b60008054610c349073ffffffffffffffffffffffffffffffffffffffff167f30f1c358b0a577824afcc8e464bcbd763eba254820a547b425765e75cc511f1e611a02565b6040805180820182526000808252602082015290517f408d962100000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff83169163408d962191610c999160040161378a565b602060405180830381865afa158015610cb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cda91906137ab565b15610d11576040517fbdb5af4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516060810182526000808252825180840184528181526020808201929092529082015260098183015290517ffb8fde7300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83169163fb8fde7391610d8d91906004016139b4565b600060405180830381600087803b158015610da757600080fd5b505af1158015610dbb573d6000803e3d6000fd5b5050604080516060810182526000808252825180840184526001815260208082019290925290820152600e8183015290517ffb8fde7300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516935063fb8fde739250610e3c91906004016139b4565b600060405180830381600087803b158015610e5657600080fd5b505af1158015610e6a573d6000803e3d6000fd5b505060408051606081018252600080825282518084018452600281526020808201929092529082015260068183015290517ffb8fde7300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516935063fb8fde739250610eeb91906004016139b4565b600060405180830381600087803b158015610f0557600080fd5b505af1158015610f19573d6000803e3d6000fd5b505060408051606081018252600080825282518084018452600381526020808201929092529082015260098183015290517ffb8fde7300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516935063fb8fde739250610f9a91906004016139b4565b600060405180830381600087803b158015610fb457600080fd5b505af1158015610fc8573d6000803e3d6000fd5b505060408051606081018252600080825282518084018452600480825260208083019390935291830152600e8284015291517ffb8fde7300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8616945063fb8fde73935061104792016139b4565b600060405180830381600087803b15801561106157600080fd5b505af1158015611075573d6000803e3d6000fd5b505060408051606081018252600080825282518084018452600581526020808201929092529082015260098183015290517ffb8fde7300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516935063fb8fde7392506110f691906004016139b4565b600060405180830381600087803b15801561111057600080fd5b505af1158015611124573d6000803e3d6000fd5b505060408051606081018252600080825282518084018452600681526020808201929092529082015260148183015290517ffb8fde7300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516935063fb8fde7392506111a591906004016139b4565b600060405180830381600087803b1580156111bf57600080fd5b505af11580156111d3573d6000803e3d6000fd5b505060408051606081018252600080825282518084018452600781526020808201929092529082015260058183015290517ffb8fde7300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516935063fb8fde73925061125491906004016139b4565b600060405180830381600087803b15801561126e57600080fd5b505af1158015611282573d6000803e3d6000fd5b5050505050565b60007f000000000000000000000000000000000000000000000001158e460913d00000670de0b6b3a76400008302055b92915050565b34156112dd5734600660008282546112d79190613a03565b90915550505b565b606061131186868686866040516020016112fd959493929190613b39565b60405160208183030381529060405261042a565b9695505050505050565b7f0000000000000000000000000000000000000000000000000000000063855114421015611375576040517f04643c3900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526005602052604090205460ff16156113bf576040517f8c14de1a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260056020526040812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580546114399073ffffffffffffffffffffffffffffffffffffffff167f8d5746953402e95fa35ce71ddaa7efe7922c48a307985b7d64ea3f27abcb14f9611a02565b6040517fe3352c2b00000000000000000000000000000000000000000000000000000000815233600482015290915060009073ffffffffffffffffffffffffffffffffffffffff83169063e3352c2b90602401606060405180830381865afa1580156114a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114cd9190613be2565b905060008273ffffffffffffffffffffffffffffffffffffffff16632011cdae6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561151c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115409190613905565b63ffffffff16826040015163ffffffff1660065461155e9190613c38565b6115689190613c4f565b6020830151909150336108fc61157e8385613a03565b6040518115909202916000818181858888f19350505050158015611282573d6000803e3d6000fd5b60008060005b83518163ffffffff16101561163a576000848263ffffffff16815181106115d5576115d56137fc565b6020026020010151601a8111156115ee576115ee6137cd565b146116285761161b848263ffffffff168151811061160e5761160e6137fc565b6020026020010151610a5f565b6116259083613a03565b91505b80611632816138ad565b9150506115ac565b5092915050565b6000610be97f0000000000000000000000000000000000000000000000000001c6bf526340006116ba6116b57fffffffffffffffffffffffffffffffffffffffffffffffffeb9aa97dedb58b126116a4670de0b6b3a76400006001890102611289565b8803670de0b6b3a764000091020590565b611b53565b611d92565b7f00000000000000000000000000000000000000000000000000000000638551144210611718576040517fdf469ccb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611723866115a6565b90508034101561175f576040517f0494526a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080546117a39073ffffffffffffffffffffffffffffffffffffffff167f29648ae8e2331b77ae3afd0a1c04805c6c5aa5a17726a131d73f7f6333aa287b611a02565b905060005b87518163ffffffff16101561188c576000888263ffffffff16815181106117d1576117d16137fc565b6020026020010151601a8111156117ea576117ea6137cd565b1461187a578173ffffffffffffffffffffffffffffffffffffffff1663cc586ed3898363ffffffff1681518110611823576118236137fc565b60200260200101516040518263ffffffff1660e01b815260040161184791906138f7565b600060405180830381600087803b15801561186157600080fd5b505af1158015611875573d6000803e3d6000fd5b505050505b80611884816138ad565b9150506117a8565b507f00000000000000000000000000000000000000000000000000000000000000046118b96001826138d0565b6118c39034613c38565b6118cd9190613c4f565b600660008282546118de9190613a03565b909155506118f190508787878787611db7565b50505050505050565b60408051808201909152600080825260208201526000826001811115611922576119226137cd565b0361195c5760405180604001604052808585600001516119429190613c63565b60030b8152602001846020015160030b8152509050610be9565b6040518060400160405280846000015160030b81526020018585602001516119849190613c63565b60030b9052949350505050565b6000836040516020016119a49190613ca5565b60405160208183030381529060405280519060200120905060006119c9848484611e34565b905080611282576040517fd1bf1a9200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517ffbdfa1ea00000000000000000000000000000000000000000000000000000000815260048101829052600090819073ffffffffffffffffffffffffffffffffffffffff85169063fbdfa1ea90602401600060405180830381865afa158015611a72573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611ab89190810190613ce2565b90508051600003611b2a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f6964206e6f74207265676973746572656400000000000000000000000000000060448201526064015b60405180910390fd5b611b4b81600081518110611b4057611b406137fc565b602002602001015190565b949350505050565b60007ffffffffffffffffffffffffffffffffffffffffffffffffdb731c958f34d94c18213611b8457506000919050565b680755bf798b4a1bf1e58212611bf6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4558505f4f564552464c4f5700000000000000000000000000000000000000006044820152606401611b21565b6503782dace9d9604e83901b059150600060606bb17217f7d1cf79abc9e3b39884821b056b80000000000000000000000001901d6bb17217f7d1cf79abc9e3b39881029093037fffffffffffffffffffffffffffffffffffffffdbf3ccf1604d263450f02a550481018102606090811d6d0277594991cfc85f6e2461837cd9018202811d7fffffffffffffffffffffffffffffffffffffe5adedaa1cb095af9e4da10e363c018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d7ffffffffffffffffffffffffffffffffffffd38dc772608b0ae56cce01296c0eb018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084017ffffffffffffffffffffffffffffffffffffffe2c69812cf03b0763fd454a8f7e010290911d6e0587f503bb6ea29d25fcb7401964500190910279d835ebba824c98fb31b83b2ca45c000000000000000000000000010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b8181028215838205831417611da657600080fd5b670de0b6b3a7640000900592915050565b60008054611dfb9073ffffffffffffffffffffffffffffffffffffffff167f30f1c358b0a577824afcc8e464bcbd763eba254820a547b425765e75cc511f1e611a02565b9050611e0a8686868685610469565b611e178685858585611e4a565b6000611e25878686856121d1565b90506118f181868686866125e4565b600082611e41858461280c565b14949350505050565b60208201515182515114611e8a576040517f7f23a46400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b845182515114611ec6576040517f8c3db81700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408201515182515114611f06576040517feaae398900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b85518163ffffffff1610156121c9576000868263ffffffff1681518110611f3257611f326137fc565b6020026020010151601a811115611f4b57611f4b6137cd565b03611fed578251805163ffffffff8316908110611f6a57611f6a6137fc565b602002602001015163ffffffff166000141580611fb1575082602001518163ffffffff1681518110611f9e57611f9e6137fc565b602002602001015163ffffffff16600014155b15611fe8576040517fedfe90b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6121b7565b60008061204c611ffe8489896118fa565b8787600001518663ffffffff168151811061201b5761201b6137fc565b602002602001015188602001518763ffffffff168151811061203f5761203f6137fc565b6020026020010151612859565b6040517f408d9621000000000000000000000000000000000000000000000000000000008152919350915073ffffffffffffffffffffffffffffffffffffffff85169063408d9621906120a390859060040161378a565b602060405180830381865afa1580156120c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120e491906137ab565b8061217d57506040517f408d962100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85169063408d96219061213c90849060040161378a565b602060405180830381865afa158015612159573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061217d91906137ab565b156121b4576040517fc582491700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505b806121c1816138ad565b915050611f09565b505050505050565b60606000855167ffffffffffffffff8111156121ef576121ef612ddb565b604051908082528060200260200182016040528015612218578160200160208202803683370190505b5060008054919250906122619073ffffffffffffffffffffffffffffffffffffffff167f8d5746953402e95fa35ce71ddaa7efe7922c48a307985b7d64ea3f27abcb14f9611a02565b90506000612290887f0000000000000000000000000000000000000000000000000000000000000004346129b9565b905060005b88518163ffffffff1610156125d75760006122b1828a8a6118fa565b905060008a8363ffffffff16815181106122cd576122cd6137fc565b6020026020010151601a8111156122e6576122e66137cd565b0361246f576040517fedd0abb900000000000000000000000000000000000000000000000000000000815260009073ffffffffffffffffffffffffffffffffffffffff89169063edd0abb99061234090859060040161378a565b608060405180830381865afa15801561235d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612381919061382b565b80516040517f6551ee6b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9182166004820152600060248201819052604482018890526064820152919250861690636551ee6b90608401600060405180830381600087803b15801561240457600080fd5b505af1158015612418573d6000803e3d6000fd5b505050508060400151868463ffffffff1681518110612439576124396137fc565b6020026020010190601a811115612452576124526137cd565b9081601a811115612465576124656137cd565b81525050506125c4565b8673ffffffffffffffffffffffffffffffffffffffff1663fb8fde7360405180606001604052803373ffffffffffffffffffffffffffffffffffffffff1681526020016040518060400160405280866000015160030b8152602001866020015160030b81525081526020018d8663ffffffff16815181106124f2576124f26137fc565b6020026020010151601a81111561250b5761250b6137cd565b8152506040518263ffffffff1660e01b815260040161252a91906139b4565b600060405180830381600087803b15801561254457600080fd5b505af1158015612558573d6000803e3d6000fd5b50505050898263ffffffff1681518110612574576125746137fc565b6020026020010151858363ffffffff1681518110612594576125946137fc565b6020026020010190601a8111156125ad576125ad6137cd565b9081601a8111156125c0576125c06137cd565b9052505b50806125cf816138ad565b915050612295565b5091979650505050505050565b60006125ef86612a45565b905060005b86518163ffffffff161015612723578351805163ffffffff831690811061261d5761261d6137fc565b602002602001015163ffffffff166000141580612664575083602001518163ffffffff1681518110612651576126516137fc565b602002602001015163ffffffff16600014155b156127115760006126c86126798389896118fa565b8787600001518563ffffffff1681518110612696576126966137fc565b602002602001015188602001518663ffffffff16815181106126ba576126ba6137fc565b602002602001015188612ad2565b90506126fa8186604001518463ffffffff16815181106126ea576126ea6137fc565b6020026020010151600354611991565b61270381612a45565b61270d9084613d73565b9250505b8061271b816138ad565b9150506125f4565b50600080546127689073ffffffffffffffffffffffffffffffffffffffff167f8d5746953402e95fa35ce71ddaa7efe7922c48a307985b7d64ea3f27abcb14f9611a02565b6040517f6551ee6b0000000000000000000000000000000000000000000000000000000081523360048201523460248201526000604482015263ffffffff8416606482015290915073ffffffffffffffffffffffffffffffffffffffff821690636551ee6b90608401600060405180830381600087803b1580156127eb57600080fd5b505af11580156127ff573d6000803e3d6000fd5b5050505050505050505050565b600081815b84518110156128515761283d82868381518110612830576128306137fc565b6020026020010151612dac565b91508061284981613d90565b915050612811565b509392505050565b6040805180820190915260008082526020820152604080518082019091526000808252602082015260c88463ffffffff16118061289c575060c88363ffffffff16115b156128d3576040517f7c832cd600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820182528751600390810b82526020808a018051830b8285015284518086019095528a51830b85525190910b9083015290600087600181111561291d5761291d6137cd565b0361296b5761292d856001613c63565b8260200181815161293e9190613dc8565b60030b90525061294f866001613c63565b816020018181516129609190613c63565b60030b9052506129ac565b612976856001613c63565b82518390612985908390613dc8565b60030b905250612996866001613c63565b815182906129a5908390613c63565b60030b9052505b9097909650945050505050565b60008060005b85518163ffffffff161015612a26576000868263ffffffff16815181106129e8576129e86137fc565b6020026020010151601a811115612a0157612a016137cd565b03612a145781612a1081613d90565b9250505b80612a1e816138ad565b9150506129bf565b5080612a328585613c4f565b612a3c9190613c4f565b95945050505050565b60008060005b83518163ffffffff16101561163a5760046000858363ffffffff1681518110612a7657612a766137fc565b6020026020010151601a811115612a8f57612a8f6137cd565b601a811115612aa057612aa06137cd565b8152602081019190915260400160002054612abe9060ff1683613d73565b915080612aca816138ad565b915050612a4b565b60606000612ae08486613d73565b612aeb906001613d73565b905060008163ffffffff1667ffffffffffffffff811115612b0e57612b0e612ddb565b604051908082528060200260200182016040528015612b37578160200160208202803683370190505b5060408051808201909152600080825260208201529091506000886001811115612b6357612b636137cd565b03612ba457612b9d612b95877fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff613e0a565b8a60016118fa565b9050612bdc565b612bd9612bd1877fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff613e0a565b8a60006118fa565b90505b60005b8363ffffffff168163ffffffff161015612d9e576040517fedd0abb900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87169063edd0abb990612c4590859060040161378a565b608060405180830381865afa158015612c62573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c86919061382b565b60400151838263ffffffff1681518110612ca257612ca26137fc565b6020026020010190601a811115612cbb57612cbb6137cd565b9081601a811115612cce57612cce6137cd565b9052506000838263ffffffff1681518110612ceb57612ceb6137fc565b6020026020010151601a811115612d0457612d046137cd565b03612d3b576040517f5cff06e600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000896001811115612d4f57612d4f6137cd565b03612d7257600182602001818151612d679190613c63565b60030b905250612d8c565b600182600001818151612d859190613c63565b60030b9052505b80612d96816138ad565b915050612bdf565b509098975050505050505050565b6000818310612dc8576000828152602084905260409020610be9565b6000838152602083905260409020610be9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715612e2d57612e2d612ddb565b60405290565b6040516060810167ffffffffffffffff81118282101715612e2d57612e2d612ddb565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715612e9d57612e9d612ddb565b604052919050565b60006020808385031215612eb857600080fd5b823567ffffffffffffffff80821115612ed057600080fd5b818501915085601f830112612ee457600080fd5b813581811115612ef657612ef6612ddb565b612f26847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601612e56565b91508082528684828501011115612f3c57600080fd5b8084840185840137600090820190930192909252509392505050565b600060208083528351808285015260005b81811015612f8557858101830151858201604001528201612f69565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b600067ffffffffffffffff821115612fde57612fde612ddb565b5060051b60200190565b601b8110612ff557600080fd5b50565b600082601f83011261300957600080fd5b8135602061301e61301983612fc4565b612e56565b82815260059290921b8401810191818101908684111561303d57600080fd5b8286015b8481101561306157803561305481612fe8565b8352918301918301613041565b509695505050505050565b600082601f83011261307d57600080fd5b8135602061308d61301983612fc4565b82815260059290921b840181019181810190868411156130ac57600080fd5b8286015b8481101561306157803583529183019183016130b0565b8060030b8114612ff557600080fd5b6000604082840312156130e857600080fd5b6130f0612e0a565b905081356130fd816130c7565b8152602082013561310d816130c7565b602082015292915050565b60028110612ff557600080fd5b73ffffffffffffffffffffffffffffffffffffffff81168114612ff557600080fd5b600080600080600060c0868803121561315f57600080fd5b853567ffffffffffffffff8082111561317757600080fd5b61318389838a01612ff8565b9650602088013591508082111561319957600080fd5b506131a68882890161306c565b9450506131b687604088016130d6565b925060808601356131c681613118565b915060a08601356131d681613125565b809150509295509295909350565b6000602082840312156131f657600080fd5b8135610be981612fe8565b60006020828403121561321357600080fd5b5035919050565b63ffffffff81168114612ff557600080fd5b600082601f83011261323d57600080fd5b8135602061324d61301983612fc4565b82815260059290921b8401810191818101908684111561326c57600080fd5b8286015b848110156130615780356132838161321a565b8352918301918301613270565b600080600080600060c086880312156132a857600080fd5b67ffffffffffffffff80873511156132bf57600080fd5b6132cc8888358901612ff8565b9550602080880135828111156132e157600080fd5b6132ed8a828b0161306c565b9650506132fd8960408a016130d6565b9450608088013561330d81613118565b935060a08801358281111561332157600080fd5b88016060818b03121561333357600080fd5b61333b612e33565b838235111561334957600080fd5b6133568b8335840161322c565b8152828201358481111561336957600080fd5b6133758c82850161322c565b848301525060408201358481111561338c57600080fd5b8083019250508a601f8301126133a157600080fd5b81356133af61301982612fc4565b81815260059190911b8301840190848101908d8311156133ce57600080fd5b8585015b838110156134045787813511156133e857600080fd5b6133f78f88833589010161306c565b83529186019186016133d2565b50806040850152505050809450505050509295509295909350565b60006020828403121561343157600080fd5b813567ffffffffffffffff81111561344857600080fd5b611b4b84828501612ff8565b6000806040838503121561346757600080fd5b50508035926020909101359150565b600082601f83011261348757600080fd5b8151602061349761301983612fc4565b82815260059290921b840181019181810190868411156134b657600080fd5b8286015b8481101561306157805183529183019183016134ba565b6000604082840312156134e357600080fd5b6134eb612e0a565b905081516134f8816130c7565b8152602082015161310d816130c7565b805161351381613118565b919050565b600082601f83011261352957600080fd5b8151602061353961301983612fc4565b82815260059290921b8401810191818101908684111561355857600080fd5b8286015b8481101561306157805161356f8161321a565b835291830191830161355c565b60006060828403121561358e57600080fd5b613596612e33565b9050815167ffffffffffffffff808211156135b057600080fd5b6135bc85838601613518565b83526020915081840151818111156135d357600080fd5b6135df86828701613518565b83850152506040840151818111156135f657600080fd5b8401601f8101861361360757600080fd5b805161361561301982612fc4565b81815260059190911b8201840190848101908883111561363457600080fd5b8584015b8381101561366c578051868111156136505760008081fd5b61365e8b8983890101613476565b845250918601918601613638565b50604087015250939695505050505050565b600080600080600060c0868803121561369657600080fd5b855167ffffffffffffffff808211156136ae57600080fd5b818801915088601f8301126136c257600080fd5b815160206136d261301983612fc4565b82815260059290921b8401810191818101908c8411156136f157600080fd5b948201945b8386101561371857855161370981612fe8565b825294820194908201906136f6565b918b015191995090935050508082111561373157600080fd5b61373d89838a01613476565b955061374c8960408a016134d1565b945061375a60808901613508565b935060a088015191508082111561377057600080fd5b5061377d8882890161357c565b9150509295509295909350565b604081016112b98284805160030b8252602081015160030b60208301525050565b6000602082840312156137bd57600080fd5b81518015158114610be957600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006080828403121561383d57600080fd5b613845612e33565b825161385081613125565b815261385f84602085016134d1565b6020820152606083015161387281612fe8565b60408201529392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff8083168181036138c6576138c661387e565b6001019392505050565b818103818111156112b9576112b961387e565b601b81106138f3576138f36137cd565b9052565b602081016112b982846138e3565b60006020828403121561391757600080fd5b8151610be98161321a565b60ff81811683821601908111156112b9576112b961387e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff83168061397d5761397d61393b565b8060ff84160491505092915050565b63ffffffff8181168382160280821691908281146139ac576139ac61387e565b505092915050565b815173ffffffffffffffffffffffffffffffffffffffff1681526020808301518051600390810b838501529181015190910b6040830152608082019050604083015161163a60608401826138e3565b808201808211156112b9576112b961387e565b600081518084526020808501945080840160005b83811015613a4657815187529582019590820190600101613a2a565b509495945050505050565b600081518084526020808501945080840160005b83811015613a4657815163ffffffff1687529582019590820190600101613a65565b6000815160608452613a9c6060850182613a51565b905060208084015185830382870152613ab58382613a51565b925050604084015185830360408701528281518085528385019150838160051b860101848401935060005b82811015613b2c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0878303018452613b1a828651613a16565b94860194938601939150600101613ae0565b5098975050505050505050565b60c0808252865190820181905260009060209060e0840190828a01845b82811015613b7957613b698483516138e3565b9284019290840190600101613b56565b50505083810382850152613b8d8189613a16565b8751600390810b60408701526020890151900b60608601529150613bae9050565b60028510613bbe57613bbe6137cd565b84608084015282810360a0840152613bd68185613a87565b98975050505050505050565b600060608284031215613bf457600080fd5b6040516060810181811067ffffffffffffffff82111715613c1757613c17612ddb565b8060405250825181526020830151602082015260408301516138728161321a565b80820281158282048414176112b9576112b961387e565b600082613c5e57613c5e61393b565b500490565b600381810b9083900b01637fffffff81137fffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000821217156112b9576112b961387e565b815160009082906020808601845b83811015613cd657613cc68583516138e3565b9382019390820190600101613cb3565b50929695505050505050565b60006020808385031215613cf557600080fd5b825167ffffffffffffffff811115613d0c57600080fd5b8301601f81018513613d1d57600080fd5b8051613d2b61301982612fc4565b81815260059190911b82018301908381019087831115613d4a57600080fd5b928401925b82841015613d6857835182529284019290840190613d4f565b979650505050505050565b63ffffffff81811683821601908082111561163a5761163a61387e565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613dc157613dc161387e565b5060010190565b600382810b9082900b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffff800000008112637fffffff821317156112b9576112b961387e565b60008260030b8260030b028060030b915080821461163a5761163a61387e56fea2646970667358221220063a3c8bf7ef552f43e66a134a9eade6ef03ef0ddeb69c0c5068baa72d259ae064736f6c63430008110033

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

00000000000000000000000061f0f349b8c7539854b34f2b81f08a30368851ac000000000000000000000000e26d5e20d796676e54e075e84d6fac6e9c46da26

-----Decoded View---------------
Arg [0] : _world (address): 0x61f0f349B8C7539854b34f2b81F08A30368851ac
Arg [1] : _components (address): 0xe26d5E20D796676E54E075E84d6faC6e9c46da26

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000061f0f349b8c7539854b34f2b81f08a30368851ac
Arg [1] : 000000000000000000000000e26d5e20d796676e54e075e84d6fac6e9c46da26


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
[ 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.