账户
0x48...98cb
0x48...98Cb

0x48...98Cb

$500
此合同的源代码已经过验证!
合同元数据
编译器
0.8.26+commit.8a97fa7a
语言
Solidity
合同源代码
文件 1 的 4:Create2.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Create2.sol)

pragma solidity ^0.8.20;

/**
 * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
 * `CREATE2` can be used to compute in advance the address where a smart
 * contract will be deployed, which allows for interesting new mechanisms known
 * as 'counterfactual interactions'.
 *
 * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
 * information.
 */
library Create2 {
    /**
     * @dev Not enough balance for performing a CREATE2 deploy.
     */
    error Create2InsufficientBalance(uint256 balance, uint256 needed);

    /**
     * @dev There's no code to deploy.
     */
    error Create2EmptyBytecode();

    /**
     * @dev The deployment failed.
     */
    error Create2FailedDeployment();

    /**
     * @dev Deploys a contract using `CREATE2`. The address where the contract
     * will be deployed can be known in advance via {computeAddress}.
     *
     * The bytecode for a contract can be obtained from Solidity with
     * `type(contractName).creationCode`.
     *
     * Requirements:
     *
     * - `bytecode` must not be empty.
     * - `salt` must have not been used for `bytecode` already.
     * - the factory must have a balance of at least `amount`.
     * - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
     */
    function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) {
        if (address(this).balance < amount) {
            revert Create2InsufficientBalance(address(this).balance, amount);
        }
        if (bytecode.length == 0) {
            revert Create2EmptyBytecode();
        }
        /// @solidity memory-safe-assembly
        assembly {
            addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
        }
        if (addr == address(0)) {
            revert Create2FailedDeployment();
        }
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
     * `bytecodeHash` or `salt` will result in a new destination address.
     */
    function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
        return computeAddress(salt, bytecodeHash, address(this));
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
     * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
     */
    function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40) // Get free memory pointer

            // |                   | ↓ ptr ...  ↓ ptr + 0x0B (start) ...  ↓ ptr + 0x20 ...  ↓ ptr + 0x40 ...   |
            // |-------------------|---------------------------------------------------------------------------|
            // | bytecodeHash      |                                                        CCCCCCCCCCCCC...CC |
            // | salt              |                                      BBBBBBBBBBBBB...BB                   |
            // | deployer          | 000000...0000AAAAAAAAAAAAAAAAAAA...AA                                     |
            // | 0xFF              |            FF                                                             |
            // |-------------------|---------------------------------------------------------------------------|
            // | memory            | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |
            // | keccak(start, 85) |            ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |

            mstore(add(ptr, 0x40), bytecodeHash)
            mstore(add(ptr, 0x20), salt)
            mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes
            let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff
            mstore8(start, 0xff)
            addr := keccak256(start, 85)
        }
    }
}
合同源代码
文件 2 的 4:IUniswapV4DeployerCompetition.sol
// SPADIX-License-Identifier: UNLICENSED
pragma solidity 0.8.26;

/// @title UniswapV4DeployerCompetition
/// @notice A competition to deploy the UniswapV4 contract with the best address
interface IUniswapV4DeployerCompetition {
    event NewAddressFound(address indexed bestAddress, address indexed submitter, uint256 score);

    error InvalidBytecode();
    error CompetitionNotOver(uint256 currentTime, uint256 deadline);
    error CompetitionOver(uint256 currentTime, uint256 deadline);
    error NotAllowedToDeploy(address sender, address deployer);
    error WorseAddress(address newAddress, address bestAddress, uint256 newScore, uint256 bestScore);
    error InvalidSender(bytes32 salt, address sender);

    /// @notice Updates the best address if the new address has a better vanity score
    /// @param salt The salt to use to compute the new address with CREATE2
    /// @dev The first 20 bytes of the salt must be either address(0) or msg.sender
    function updateBestAddress(bytes32 salt) external;

    /// @notice deploys the Uniswap v4 PoolManager contract
    /// @param bytecode The bytecode of the Uniswap v4 PoolManager contract
    /// @dev The bytecode must match the initCodeHash
    function deploy(bytes memory bytecode) external;
}
合同源代码
文件 3 的 4:UniswapV4DeployerCompetition.sol
// SPADIX-License-Identifier: UNLICENSED
pragma solidity 0.8.26;

import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";
import {VanityAddressLib} from "./libraries/VanityAddressLib.sol";
import {IUniswapV4DeployerCompetition} from "./interfaces/IUniswapV4DeployerCompetition.sol";

/// @title UniswapV4DeployerCompetition
/// @notice A contract to crowdsource a salt for the best Uniswap V4 address
contract UniswapV4DeployerCompetition is IUniswapV4DeployerCompetition {
    using VanityAddressLib for address;

    /// @dev The salt for the best address found so far
    bytes32 public bestAddressSalt;
    /// @dev The submitter of the best address found so far
    address public bestAddressSubmitter;

    /// @dev The deadline for the competition
    uint256 public immutable competitionDeadline;
    /// @dev The init code hash of the V4 contract
    bytes32 public immutable initCodeHash;

    /// @dev The deployer who can initiate the deployment of the v4 PoolManager, until the exclusive deploy deadline.
    /// @dev After this deadline anyone can deploy.
    address public immutable deployer;
    /// @dev The deadline for exclusive deployment by deployer after deadline
    uint256 public immutable exclusiveDeployDeadline;

    constructor(
        bytes32 _initCodeHash,
        uint256 _competitionDeadline,
        address _exclusiveDeployer,
        uint256 _exclusiveDeployLength
    ) {
        initCodeHash = _initCodeHash;
        competitionDeadline = _competitionDeadline;
        exclusiveDeployDeadline = _competitionDeadline + _exclusiveDeployLength;
        deployer = _exclusiveDeployer;
    }

    /// @inheritdoc IUniswapV4DeployerCompetition
    function updateBestAddress(bytes32 salt) external {
        if (block.timestamp > competitionDeadline) {
            revert CompetitionOver(block.timestamp, competitionDeadline);
        }

        address saltSubAddress = address(bytes20(salt));
        if (saltSubAddress != msg.sender && saltSubAddress != address(0)) revert InvalidSender(salt, msg.sender);

        address newAddress = Create2.computeAddress(salt, initCodeHash);
        address _bestAddress = bestAddress();
        if (!newAddress.betterThan(_bestAddress)) {
            revert WorseAddress(newAddress, _bestAddress, newAddress.score(), _bestAddress.score());
        }

        bestAddressSalt = salt;
        bestAddressSubmitter = msg.sender;

        emit NewAddressFound(newAddress, msg.sender, newAddress.score());
    }

    /// @inheritdoc IUniswapV4DeployerCompetition
    function deploy(bytes memory bytecode) external {
        if (keccak256(bytecode) != initCodeHash) {
            revert InvalidBytecode();
        }

        if (block.timestamp <= competitionDeadline) {
            revert CompetitionNotOver(block.timestamp, competitionDeadline);
        }

        if (msg.sender != deployer && block.timestamp <= exclusiveDeployDeadline) {
            // anyone can deploy after the deadline
            revert NotAllowedToDeploy(msg.sender, deployer);
        }

        // the owner of the contract must be encoded in the bytecode
        Create2.deploy(0, bestAddressSalt, bytecode);
    }

    /// @dev returns the best address found so far
    function bestAddress() public view returns (address) {
        return Create2.computeAddress(bestAddressSalt, initCodeHash);
    }
}
合同源代码
文件 4 的 4:VanityAddressLib.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

/// @title VanityAddressLib
/// @notice A library to score addresses based on their vanity
library VanityAddressLib {
    /// @notice Compares two addresses and returns true if the first address has a better vanity score
    /// @param first The first address to compare
    /// @param second The second address to compare
    /// @return better True if the first address has a better vanity score
    function betterThan(address first, address second) internal pure returns (bool better) {
        return score(first) > score(second);
    }

    /// @notice Scores an address based on its vanity
    /// @dev Scoring rules:
    ///    Requirement: The first nonzero nibble must be 4
    ///    10 points for every leading 0 nibble
    ///    40 points if the first 4 is followed by 3 more 4s
    ///    20 points if the first nibble after the 4 4s is NOT a 4
    ///    20 points if the last 4 nibbles are 4s
    ///    1 point for every 4
    /// @param addr The address to score
    /// @return calculatedScore The vanity score of the address
    function score(address addr) internal pure returns (uint256 calculatedScore) {
        // convert the address to bytes for easier parsing
        bytes20 addrBytes = bytes20(addr);

        unchecked {
            // 10 points per leading zero nibble
            uint256 leadingZeroCount = getLeadingNibbleCount(addrBytes, 0, 0);
            calculatedScore += (leadingZeroCount * 10);

            // special handling for 4s immediately after leading 0s
            uint256 leadingFourCount = getLeadingNibbleCount(addrBytes, leadingZeroCount, 4);
            // If the first nonzero nibble is not 4, return 0
            if (leadingFourCount == 0) {
                return 0;
            } else if (leadingFourCount == 4) {
                // 60 points if exactly 4 4s
                calculatedScore += 60;
            } else if (leadingFourCount > 4) {
                // 40 points if more than 4 4s
                calculatedScore += 40;
            }

            // handling for remaining nibbles
            for (uint256 i = 0; i < addrBytes.length * 2; i++) {
                uint8 currentNibble = getNibble(addrBytes, i);

                // 1 extra point for any 4 nibbles
                if (currentNibble == 4) {
                    calculatedScore += 1;
                }
            }

            // If the last 4 nibbles are 4s, add 20 points
            if (addrBytes[18] == 0x44 && addrBytes[19] == 0x44) {
                calculatedScore += 20;
            }
        }
    }

    /// @notice Returns the number of leading nibbles in an address that match a given value
    /// @param addrBytes The address to count the leading zero nibbles in
    function getLeadingNibbleCount(bytes20 addrBytes, uint256 startIndex, uint8 comparison)
        internal
        pure
        returns (uint256 count)
    {
        if (startIndex >= addrBytes.length * 2) {
            return count;
        }

        for (uint256 i = startIndex; i < addrBytes.length * 2; i++) {
            uint8 currentNibble = getNibble(addrBytes, i);
            if (currentNibble != comparison) {
                return count;
            }
            count += 1;
        }
    }

    /// @notice Returns the nibble at a given index in an address
    /// @param input The address to get the nibble from
    /// @param nibbleIndex The index of the nibble to get
    function getNibble(bytes20 input, uint256 nibbleIndex) internal pure returns (uint8 currentNibble) {
        uint8 currByte = uint8(input[nibbleIndex / 2]);
        if (nibbleIndex % 2 == 0) {
            // Get the higher nibble of the byte
            currentNibble = currByte >> 4;
        } else {
            // Get the lower nibble of the byte
            currentNibble = currByte & 0x0F;
        }
    }
}
设置
{
  "compilationTarget": {
    "src/UniswapV4DeployerCompetition.sol": "UniswapV4DeployerCompetition"
  },
  "evmVersion": "cancun",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "none"
  },
  "optimizer": {
    "enabled": true,
    "runs": 44444444
  },
  "remappings": [
    ":@ensdomains/=lib/v4-core/node_modules/@ensdomains/",
    ":@openzeppelin/=lib/v4-core/lib/openzeppelin-contracts/",
    ":@openzeppelin/contracts/=lib/v4-core/lib/openzeppelin-contracts/contracts/",
    ":@uniswap/v4-core/=lib/v4-core/",
    ":ds-test/=lib/v4-core/lib/forge-std/lib/ds-test/src/",
    ":erc4626-tests/=lib/v4-core/lib/openzeppelin-contracts/lib/erc4626-tests/",
    ":forge-gas-snapshot/=lib/forge-gas-snapshot/src/",
    ":forge-std/=lib/v4-core/lib/forge-std/src/",
    ":hardhat/=lib/v4-core/node_modules/hardhat/",
    ":openzeppelin-contracts/=lib/v4-core/lib/openzeppelin-contracts/",
    ":permit2/=lib/permit2/",
    ":solmate/=lib/v4-core/lib/solmate/",
    ":v4-core/=lib/v4-core/src/"
  ],
  "viaIR": true
}
ABI
[{"inputs":[{"internalType":"bytes32","name":"_initCodeHash","type":"bytes32"},{"internalType":"uint256","name":"_competitionDeadline","type":"uint256"},{"internalType":"address","name":"_exclusiveDeployer","type":"address"},{"internalType":"uint256","name":"_exclusiveDeployLength","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"currentTime","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"CompetitionNotOver","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentTime","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"CompetitionOver","type":"error"},{"inputs":[],"name":"Create2EmptyBytecode","type":"error"},{"inputs":[],"name":"Create2FailedDeployment","type":"error"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"Create2InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidBytecode","type":"error"},{"inputs":[{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"}],"name":"InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"deployer","type":"address"}],"name":"NotAllowedToDeploy","type":"error"},{"inputs":[{"internalType":"address","name":"newAddress","type":"address"},{"internalType":"address","name":"bestAddress","type":"address"},{"internalType":"uint256","name":"newScore","type":"uint256"},{"internalType":"uint256","name":"bestScore","type":"uint256"}],"name":"WorseAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"bestAddress","type":"address"},{"indexed":true,"internalType":"address","name":"submitter","type":"address"},{"indexed":false,"internalType":"uint256","name":"score","type":"uint256"}],"name":"NewAddressFound","type":"event"},{"inputs":[],"name":"bestAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bestAddressSalt","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bestAddressSubmitter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"competitionDeadline","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"bytecode","type":"bytes"}],"name":"deploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deployer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exclusiveDeployDeadline","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initCodeHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"updateBestAddress","outputs":[],"stateMutability":"nonpayable","type":"function"}]