// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v5.0.0) (utils/Create2.sol)pragmasolidity ^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.
*/libraryCreate2{
/**
* @dev Not enough balance for performing a CREATE2 deploy.
*/errorCreate2InsufficientBalance(uint256 balance, uint256 needed);
/**
* @dev There's no code to deploy.
*/errorCreate2EmptyBytecode();
/**
* @dev The deployment failed.
*/errorCreate2FailedDeployment();
/**
* @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.
*/functiondeploy(uint256 amount, bytes32 salt, bytesmemory bytecode) internalreturns (address addr) {
if (address(this).balance< amount) {
revert Create2InsufficientBalance(address(this).balance, amount);
}
if (bytecode.length==0) {
revert Create2EmptyBytecode();
}
/// @solidity memory-safe-assemblyassembly {
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.
*/functioncomputeAddress(bytes32 salt, bytes32 bytecodeHash) internalviewreturns (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}.
*/functioncomputeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internalpurereturns (address addr) {
/// @solidity memory-safe-assemblyassembly {
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 byteslet start :=add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xffmstore8(start, 0xff)
addr :=keccak256(start, 85)
}
}
}
Contract Source Code
File 2 of 4: IUniswapV4DeployerCompetition.sol
// SPADIX-License-Identifier: UNLICENSEDpragmasolidity 0.8.26;/// @title UniswapV4DeployerCompetition/// @notice A competition to deploy the UniswapV4 contract with the best addressinterfaceIUniswapV4DeployerCompetition{
eventNewAddressFound(addressindexed bestAddress, addressindexed submitter, uint256 score);
errorInvalidBytecode();
errorCompetitionNotOver(uint256 currentTime, uint256 deadline);
errorCompetitionOver(uint256 currentTime, uint256 deadline);
errorNotAllowedToDeploy(address sender, address deployer);
errorWorseAddress(address newAddress, address bestAddress, uint256 newScore, uint256 bestScore);
errorInvalidSender(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.senderfunctionupdateBestAddress(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 initCodeHashfunctiondeploy(bytesmemory bytecode) external;
}
Contract Source Code
File 3 of 4: UniswapV4DeployerCompetition.sol
// SPADIX-License-Identifier: UNLICENSEDpragmasolidity 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 addresscontractUniswapV4DeployerCompetitionisIUniswapV4DeployerCompetition{
usingVanityAddressLibforaddress;
/// @dev The salt for the best address found so farbytes32public bestAddressSalt;
/// @dev The submitter of the best address found so faraddresspublic bestAddressSubmitter;
/// @dev The deadline for the competitionuint256publicimmutable competitionDeadline;
/// @dev The init code hash of the V4 contractbytes32publicimmutable 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.addresspublicimmutable deployer;
/// @dev The deadline for exclusive deployment by deployer after deadlineuint256publicimmutable exclusiveDeployDeadline;
constructor(bytes32 _initCodeHash,
uint256 _competitionDeadline,
address _exclusiveDeployer,
uint256 _exclusiveDeployLength
) {
initCodeHash = _initCodeHash;
competitionDeadline = _competitionDeadline;
exclusiveDeployDeadline = _competitionDeadline + _exclusiveDeployLength;
deployer = _exclusiveDeployer;
}
/// @inheritdoc IUniswapV4DeployerCompetitionfunctionupdateBestAddress(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 IUniswapV4DeployerCompetitionfunctiondeploy(bytesmemory 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 deadlinerevert 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 farfunctionbestAddress() publicviewreturns (address) {
return Create2.computeAddress(bestAddressSalt, initCodeHash);
}
}
Contract Source Code
File 4 of 4: VanityAddressLib.sol
// SPDX-License-Identifier: UNLICENSEDpragmasolidity ^0.8.0;/// @title VanityAddressLib/// @notice A library to score addresses based on their vanitylibraryVanityAddressLib{
/// @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 scorefunctionbetterThan(address first, address second) internalpurereturns (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 addressfunctionscore(address addr) internalpurereturns (uint256 calculatedScore) {
// convert the address to bytes for easier parsingbytes20 addrBytes =bytes20(addr);
unchecked {
// 10 points per leading zero nibbleuint256 leadingZeroCount = getLeadingNibbleCount(addrBytes, 0, 0);
calculatedScore += (leadingZeroCount *10);
// special handling for 4s immediately after leading 0suint256 leadingFourCount = getLeadingNibbleCount(addrBytes, leadingZeroCount, 4);
// If the first nonzero nibble is not 4, return 0if (leadingFourCount ==0) {
return0;
} elseif (leadingFourCount ==4) {
// 60 points if exactly 4 4s
calculatedScore +=60;
} elseif (leadingFourCount >4) {
// 40 points if more than 4 4s
calculatedScore +=40;
}
// handling for remaining nibblesfor (uint256 i =0; i < addrBytes.length*2; i++) {
uint8 currentNibble = getNibble(addrBytes, i);
// 1 extra point for any 4 nibblesif (currentNibble ==4) {
calculatedScore +=1;
}
}
// If the last 4 nibbles are 4s, add 20 pointsif (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 infunctiongetLeadingNibbleCount(bytes20 addrBytes, uint256 startIndex, uint8 comparison)
internalpurereturns (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 getfunctiongetNibble(bytes20 input, uint256 nibbleIndex) internalpurereturns (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;
}
}
}