diff --git a/src/libraries/VanityAddressLib.sol b/src/libraries/VanityAddressLib.sol index ecf73b1c..9c2d70f0 100644 --- a/src/libraries/VanityAddressLib.sol +++ b/src/libraries/VanityAddressLib.sol @@ -16,45 +16,72 @@ library VanityAddressLib { /// @param addr The address to score /// @return calculatedScore The vanity score of the address function score(address addr) internal pure returns (uint256 calculatedScore) { - // 10 points for every leading 0 - // 3 points for every leading 4 - // 1 point for every 4 after that + // 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 bytes20 addrBytes = bytes20(addr); bool startingZeros = true; bool startingFours = true; - // iterate over the bytes of the address - for (uint256 i = 0; i < 20; i++) { - if (startingZeros && addrBytes[i] == 0x00) { - calculatedScore += 20; - continue; - } else if (startingZeros && (addrBytes[i] & 0xF0) == 0x00) { - calculatedScore += 10; - startingZeros = false; + bool firstFour = true; + uint8 fourCounts; // counter for the number of 4s + // iterate over the nibbles of the address + for (uint256 i = 0; i < addrBytes.length * 2; i++) { + uint8 currentNibble; + if (i % 2 == 0) { + // Get the higher nibble of the byte + currentNibble = uint8(addrBytes[i / 2] >> 4); } else { - startingZeros = false; + // Get the lower nibble of the byte + currentNibble = uint8(addrBytes[i / 2] & 0x0F); } - if (startingFours && addrBytes[i] == 0x44) { - calculatedScore += 6; - continue; - } else if (startingFours && (addrBytes[i] & 0xF0 == 0x40) || (addrBytes[i] & 0xFF == 0x04)) { - calculatedScore += 3; - startingFours = false; + + // leading 0s + if (startingZeros && currentNibble == 0) { + calculatedScore += 10; continue; } else { - startingFours = false; + startingZeros = false; } - if (!startingZeros && !startingFours) { - // count each nibble separately - if (addrBytes[i] & 0xFF == 0x44) { - calculatedScore += 2; - } else if (addrBytes[i] & 0x0F == 0x04) { - calculatedScore += 1; - } else if (addrBytes[i] & 0xF0 == 0x40) { - calculatedScore += 1; + // leading 4s + if (startingFours) { + // If the first nonzero nibble is not 4, the score is an automatic 0 + if (firstFour && currentNibble != 4) { + return 0; + } + + if (currentNibble == 4) { + fourCounts += 1; + if (fourCounts == 4) { + calculatedScore += 40; + // If the leading 4 4s are also the last 4 nibbles, add 20 points + if (i == addrBytes.length * 2 - 1) { + calculatedScore += 20; + } + } + } else { + // If the first nibble after the 4 4s is not a 4, add 20 points + if (fourCounts == 4) { + calculatedScore += 20; + } + startingFours = false; } + firstFour = false; } + + // count each 4 nibble separately + if (currentNibble == 4) { + calculatedScore += 1; + } + } + + // If the last 4 nibbles are 4s, add 20 points + if (addrBytes[18] & 0xFF == 0x44 && addrBytes[19] & 0xFF == 0x44) { + calculatedScore += 20; } } } diff --git a/test/UniswapV4DeployerCompetition.t.sol b/test/UniswapV4DeployerCompetition.t.sol index f008fc45..a38ea84c 100644 --- a/test/UniswapV4DeployerCompetition.t.sol +++ b/test/UniswapV4DeployerCompetition.t.sol @@ -120,6 +120,7 @@ contract UniswapV4DeployerCompetitionTest is Test { function testEqualSaltNotChanged(bytes32 salt) public { vm.prank(winner); deployer.updateBestAddress(salt); + assertFalse(deployer.bestAddress() == address(0)); assertEq(deployer.bestAddressSender(), winner); assertEq(deployer.bestAddressSalt(), salt); @@ -139,18 +140,6 @@ contract UniswapV4DeployerCompetitionTest is Test { deployer.updateBestAddress(salt >> 1); } - function testUpdateNotEqual() public { - bytes32 salt1 = keccak256(abi.encodePacked(uint256(1))); - bytes32 salt2 = keccak256(abi.encodePacked(uint256(2))); - vm.prank(winner); - deployer.updateBestAddress(salt1); - vm.prank(winner); - deployer.updateBestAddress(salt2); - assertFalse(deployer.bestAddress() == address(0)); - assertEq(deployer.bestAddressSender(), winner); - assertEq(deployer.bestAddressSalt(), salt2); - } - function testTokenURI(bytes32 salt) public { vm.prank(winner); deployer.updateBestAddress(salt); diff --git a/test/libraries/VanityAddressLib.t.sol b/test/libraries/VanityAddressLib.t.sol index 90035a7c..b284a91b 100644 --- a/test/libraries/VanityAddressLib.t.sol +++ b/test/libraries/VanityAddressLib.t.sol @@ -8,21 +8,21 @@ contract VanityAddressLibTest is Test { function test_scoreAllZeros() public pure { address addr = address(0); uint256 score = VanityAddressLib.score(addr); - uint256 expected = 400; // 20 * 10 + uint256 expected = 400; // not a 4 after the zeros assertEq(score, expected); } function test_scoreAllFours() public pure { address addr = address(0x4444444444444444444444444444444444444444); uint256 score = VanityAddressLib.score(addr); - uint256 expected = 120; // 6 * 20 + uint256 expected = 100; // 40 + 40 + 20 = 100 assertEq(score, expected); } function test_scoreLaterFours() public pure { address addr = address(0x1444444444444444444444444444444444444444); uint256 score = VanityAddressLib.score(addr); - uint256 expected = 39; // 1 + (5 * 19) = 39 + uint256 expected = 0; // no leading 4 assertEq(score, expected); } @@ -33,7 +33,7 @@ contract VanityAddressLibTest is Test { // does not count future null bytes // counts 4 nibbles after that uint256 score = VanityAddressLib.score(addr); - uint256 expected = 28; // 20+6+1+1 + uint256 expected = 24; // 10 * 2 + 2 + 2 = 24 assertEq(score, expected); } @@ -44,7 +44,7 @@ contract VanityAddressLibTest is Test { // does not count future null bytes // counts 4 nibbles after that uint256 score = VanityAddressLib.score(addr); - uint256 expected = 30; // 20+6+2+2 + uint256 expected = 46; // 10 * 2 + 6 + 20 = 46 assertEq(score, expected); } @@ -53,31 +53,50 @@ contract VanityAddressLibTest is Test { // counts first null byte // counts first leading 4s after that uint256 score = VanityAddressLib.score(addr); - uint256 expected = 33; // 20+10+3 + uint256 expected = 31; // 10 * 3 + 1 = 31 assertEq(score, expected); } + function test_scores_succeed() public pure { + assertEq(VanityAddressLib.score(address(0x0000000000000000000000000000000000000082)), 0); // 0 + assertEq(VanityAddressLib.score(address(0x0400000000000000000000000000000000000000)), 11); // 10 * 1 + 1 = 11 + assertEq(VanityAddressLib.score(address(0x0044000000000000000000000000000000004444)), 46); // 10 * 2 + 6 + 20 = 46 + assertEq(VanityAddressLib.score(address(0x4444000000000000000000000000000000004444)), 88); // 40 + 20 + 20 + 8 = 88 + assertEq(VanityAddressLib.score(address(0x0044440000000000000000000000000000000044)), 86); // 10 * 2 + 40 + 20 + 6 = 86 + assertEq(VanityAddressLib.score(address(0x0000444400000000000000000000000000004444)), 128); // 10 * 4 + 40 + 20 + 20 + 8 = 128 + assertEq(VanityAddressLib.score(address(0x0040444444444444444444444444444444444444)), 77); // 10 * 2 + 37 + 20 = 77 + assertEq(VanityAddressLib.score(address(0x0000000000000000000000000000000000000444)), 373); // 10 * 37 + 3 = 373 + assertEq(VanityAddressLib.score(address(0x0000000000000000000000000000000044444444)), 388); // 10 * 32 + 40 + 20 + 8 = 388 + assertEq(VanityAddressLib.score(address(0x0000000000000000000000000000000000454444)), 365); // 10 * 34 + 20 + 5 = 365 + assertEq(VanityAddressLib.score(address(0x0000000000000000000000000000000000000044)), 382); // 10 * 38 + 2 = 382 + assertEq(VanityAddressLib.score(address(0x0000000000000000000000000000000000000004)), 391); // 10 * 39 + 1 = 391 + assertEq(VanityAddressLib.score(address(0x0000000000000000000000000000000000444444)), 406); // 10 * 34 + 40 + 20 + 6 = 406 + assertEq(VanityAddressLib.score(address(0x0000000000000000000000000000000000044444)), 415); // 10 * 35 + 40 + 20 + 5 = 415 + assertEq(VanityAddressLib.score(address(0x0000000000000000000000000000000000444455)), 404); // 10 * 34 + 40 + 20 + 4 = 404 + assertEq(VanityAddressLib.score(address(0x0000000000000000000000000000000000044445)), 414); // 10 * 35 + 40 + 20 + 4 = 414 + assertEq(VanityAddressLib.score(address(0x0000000000000000000000000000000000004444)), 444); // 10 * 36 + 40 + 20 + 20 + 4 = 444 + } + function test_betterThan() public pure { - address addr1 = address(0x0011111111111111111111111111111111111111); // 20 points - address addr2 = address(0x0000111111111111111111111111111111111111); // 40 points - address addr3 = address(0x0000411111111111111111111111111111111111); // 43 points - address addr4 = address(0x0000441111111111111111111111111111111111); // 46 points - address addr5 = address(0x0000440011111111111111111111111111111111); // 46 points - assertTrue(VanityAddressLib.betterThan(addr2, addr1)); // 40 > 20 - assertTrue(VanityAddressLib.betterThan(addr3, addr2)); // 43 > 40 - assertTrue(VanityAddressLib.betterThan(addr3, addr1)); // 43 > 20 - assertTrue(VanityAddressLib.betterThan(addr4, addr3)); // 46 > 43 - assertTrue(VanityAddressLib.betterThan(addr4, addr2)); // 46 > 40 - assertTrue(VanityAddressLib.betterThan(addr4, addr1)); // 46 > 20 - assertFalse(VanityAddressLib.betterThan(addr5, addr4)); // 46 == 46 - assertEq(VanityAddressLib.score(addr5), VanityAddressLib.score(addr4)); // 46 == 46 - assertTrue(VanityAddressLib.betterThan(addr5, addr3)); // 46 > 43 - assertTrue(VanityAddressLib.betterThan(addr5, addr2)); // 46 > 40 - assertTrue(VanityAddressLib.betterThan(addr5, addr1)); // 46 > 20 + address addr1 = address(0x0011111111111111111111111111111111111111); // 0 points + address addr2 = address(0x4000111111111111111111111111111111111111); // 1 points + address addr3 = address(0x0000411111111111111111111111111111111111); // 10 * 4 + 1 = 41 points + address addr4 = address(0x0000441111111111111111111111111111111111); // 10 * 4 + 2 = 42 points + address addr5 = address(0x0000440011111111111111111111111111111111); // 10 * 4 + 2 = 42 points + assertTrue(VanityAddressLib.betterThan(addr2, addr1)); // 1 > 0 + assertTrue(VanityAddressLib.betterThan(addr3, addr2)); // 41 > 1 + assertTrue(VanityAddressLib.betterThan(addr3, addr1)); // 41 > 0 + assertTrue(VanityAddressLib.betterThan(addr4, addr3)); // 42 > 41 + assertTrue(VanityAddressLib.betterThan(addr4, addr2)); // 42 > 1 + assertTrue(VanityAddressLib.betterThan(addr4, addr1)); // 42 > 0 + assertFalse(VanityAddressLib.betterThan(addr5, addr4)); // 42 == 42 + assertEq(VanityAddressLib.score(addr5), VanityAddressLib.score(addr4)); // 42 == 42 + assertTrue(VanityAddressLib.betterThan(addr5, addr3)); // 42 > 41 + assertTrue(VanityAddressLib.betterThan(addr5, addr2)); // 42 > 1 + assertTrue(VanityAddressLib.betterThan(addr5, addr1)); // 42 > 0 - // is this intentional? address addr6 = address(0x0000000000000000000000000000000000004444); address addr7 = address(0x0000000000000000000000000000000000000082); - assertFalse(VanityAddressLib.betterThan(addr6, addr7)); // 20 * 18 + 6 + 6 = 372 < 20 * 19 = 380 + assertTrue(VanityAddressLib.betterThan(addr6, addr7)); // 10 * 36 + 40 + 20 + 20 + 4 = 444 > 0 } }