Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
PRIVATE_KEY=
ETHERSCAN_API_KEY=
SEPOLIA_URL=
SEPOLIA_RPC_URL=
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ lcov.info

Prover.toml
raw_inputs.json
target/
# ignore target dir contents but keep generated .sol verifiers (e.g. HonkVerifier.sol)
**/target/*
!**/target/*.sol
Comment thread
benceharomi marked this conversation as resolved.
5 changes: 2 additions & 3 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ coverage/
node_modules/
out/

# circuit generated files
test/fixtures/handleCommand/circuit/target
test/fixtures/redditHandleCommand/circuit/target
# ignore circuit generated files (target directories under fixtures)
test/fixtures/**/target

# files
.env
Expand Down
8 changes: 5 additions & 3 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ evm_version = "prague"
ignored_warnings_from = ["node_modules"]
fs_permissions = [{ access = "read", path = "./test/fixtures" }]

[rpc_endpoints]
sepolia = "${SEPOLIA_RPC_URL}"

[profile.ci]
verbosity = 4

Expand All @@ -26,7 +29,6 @@ quote_style = "double"
tab_width = 4
wrap_comments = true
ignore = [
# ignore circuit generated files
"test/fixtures/handleCommand/circuit/target/*.sol",
"test/fixtures/redditHandleCommand/circuit/target/*.sol",
# ignore circuit generated files (target directories under fixtures)
"test/fixtures/**/target/*.sol",
]
2 changes: 1 addition & 1 deletion script/DeployAllDiscord.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Script, console } from "forge-std/Script.sol";
import { HandleRegistrar } from "../src/entrypoints/HandleRegistrar.sol";
import { HandleResolver } from "../src/resolvers/HandleResolver.sol";
import { ClaimHandleCommandVerifier } from "../src/verifiers/ClaimHandleCommandVerifier.sol";
import { HonkVerifier } from "../test/fixtures/handleCommand/HonkVerifier.sol";
import { HonkVerifier } from "../test/fixtures/linkHandleCommand/twitter/target/HonkVerifier.sol";
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
import { EnsUtils } from "../src/utils/EnsUtils.sol";

contract DeployAllDiscordScript is Script {
Expand Down
2 changes: 1 addition & 1 deletion script/DeployAllX.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Script, console } from "forge-std/Script.sol";
import { HandleRegistrar } from "../src/entrypoints/HandleRegistrar.sol";
import { HandleResolver } from "../src/resolvers/HandleResolver.sol";
import { ClaimHandleCommandVerifier } from "../src/verifiers/ClaimHandleCommandVerifier.sol";
import { HonkVerifier } from "../test/fixtures/handleCommand/HonkVerifier.sol";
import { HonkVerifier } from "../test/fixtures/linkHandleCommand/twitter/target/HonkVerifier.sol";
import { EnsUtils } from "../src/utils/EnsUtils.sol";

contract DeployAllXScript is Script {
Expand Down
2 changes: 1 addition & 1 deletion script/DeployHandleRegistrar.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity ^0.8.30;
import { Script, console } from "forge-std/Script.sol";
import { HandleRegistrar } from "../src/entrypoints/HandleRegistrar.sol";
import { ClaimHandleCommandVerifier } from "../src/verifiers/ClaimHandleCommandVerifier.sol";
import { HonkVerifier } from "../test/fixtures/handleCommand/HonkVerifier.sol";
import { HonkVerifier } from "../test/fixtures/linkHandleCommand/twitter/target/HonkVerifier.sol";
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
import { EnsUtils } from "../src/utils/EnsUtils.sol";

contract DeployHandleRegistrarScript is Script {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

import { DeployLinkHandleEntrypointScript } from "./_DeployLinkHandleEntrypoint.s.sol";
import { HonkVerifier } from "../../test/fixtures/linkHandleCommand/twitter/target/HonkVerifier.sol";

contract DeployLinkHandleEntrypointTwitterScript is DeployLinkHandleEntrypointScript {
function _deployHonkVerifier() internal override returns (address) {
return address(new HonkVerifier());
}

function _getDkimRegistryAddress() internal pure override returns (address) {
// sepolia always valid dkim registry
return 0xc4f628496b8c474096650C8f9023954643cC614F;
}

function _getPlatformName() internal pure override returns (string memory) {
return "x";
}

function _getRecordName() internal pure override returns (string memory) {
return "com.twitter";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

import { Script, console } from "forge-std/Script.sol";
import { LinkHandleEntrypoint } from "../../src/entrypoints/LinkHandleEntrypoint.sol";
import { LinkHandleCommandVerifier } from "../../src/verifiers/LinkHandleCommandVerifier.sol";

abstract contract DeployLinkHandleEntrypointScript is Script {
function run() external {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");

vm.startBroadcast(deployerPrivateKey);

console.log("\n=== Step 0: Deploy HonkVerifier ===");
address honkVerifierAddress = _deployHonkVerifier();
console.log("HonkVerifier deployed at:", honkVerifierAddress);

console.log("\n=== Step 1: Deploy LinkHandleCommandVerifier ===");
LinkHandleCommandVerifier commandVerifier =
new LinkHandleCommandVerifier(honkVerifierAddress, _getDkimRegistryAddress());
console.log("LinkHandleCommandVerifier deployed at:", address(commandVerifier));

console.log("\n=== Step 2: Deploy LinkHandleEntrypoint ===");
LinkHandleEntrypoint entrypoint =
new LinkHandleEntrypoint(address(commandVerifier), _getRecordName(), _getPlatformName());
console.log("LinkHandleEntrypoint deployed at:", address(entrypoint));

vm.stopBroadcast();

console.log("\n=== Deployment Complete ===");
console.log("HONK_VERIFIER=", honkVerifierAddress);
console.log("DKIM_REGISTRY=", _getDkimRegistryAddress());
console.log("LINK_HANDLE_COMMAND_VERIFIER=", address(commandVerifier));
console.log("RECORD_NAME=", _getRecordName());
console.log("PLATFORM_NAME=", _getPlatformName());
console.log("LINK_HANDLE_ENTRYPOINT=", address(entrypoint));
}

/**
* @notice Deploys the HonkVerifier and returns the address.
* @dev TODO: ideally ths would be a pure address getter and would only return the address of the HonkVerifier
* deployed by the
* registry. Currently this is deployed inside this function. Remove it once the registry deploys the
* HonkVerifier.
* @return The address of the HonkVerifier
Comment thread
coderabbitai[bot] marked this conversation as resolved.
*/
function _deployHonkVerifier() internal virtual returns (address);

/**
* @notice The DKIM registry address.
* @dev Example (sepolia): return 0xe24c24Ab94c93D5754De1cbE61b777e47cc57723;
* Example (sepolia always valid): return 0xc4f628496b8c474096650C8f9023954643cC614F;
* @return The address of the DKIM registry
*/
function _getDkimRegistryAddress() internal pure virtual returns (address);

/**
* @notice The platform name in the command (e.g. "x").
* @return The platform name used in the command
*/
function _getPlatformName() internal pure virtual returns (string memory);

/**
* @notice ENS text record name (e.g. "com.twitter") — the key in setText(node, key, value).
* @return The record name for the text record
*/
function _getRecordName() internal pure virtual returns (string memory);
}
27 changes: 0 additions & 27 deletions script/DeployLinkHandleVerifier.s.sol

This file was deleted.

4 changes: 2 additions & 2 deletions script/LinkHandleWithFixture.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity ^0.8.30;
import { Script } from "forge-std/Script.sol";
import { LinkHandleEntrypoint } from "../src/entrypoints/LinkHandleEntrypoint.sol";
import { LinkHandleCommand } from "../src/verifiers/HandleVerifier.sol";
import { HandleCommandTestFixture } from "../test/fixtures/handleCommand/HandleCommandTestFixture.sol";
import { LinkHandleCommandTestFixture } from "../test/fixtures/linkHandleCommand/LinkHandleCommandTestFixture.sol";

contract LinkHandleWithFixtureScript is Script {
// sepolia mock
Expand All @@ -16,7 +16,7 @@ contract LinkHandleWithFixtureScript is Script {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");

LinkHandleEntrypoint verifier = LinkHandleEntrypoint(LINK_X_HANDLE_VERIFIER);
(LinkHandleCommand memory command,) = HandleCommandTestFixture.getLinkXFixture();
(LinkHandleCommand memory command,) = LinkHandleCommandTestFixture.getTwitterFixture();

vm.startBroadcast(deployerPrivateKey);

Expand Down
2 changes: 1 addition & 1 deletion src/entrypoints/LinkEmailEntrypoint.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { LinkEmailCommand } from "../verifiers/LinkEmailCommandVerifier.sol";
* @dev The verifier can be updated via the entrypoint function.
*/
contract LinkEmailEntrypoint is LinkTextRecordEntrypoint {
constructor(address verifier) LinkTextRecordEntrypoint(verifier, "email") { }
constructor(address verifier) LinkTextRecordEntrypoint(verifier, "email", "email") { }

/**
* @inheritdoc LinkTextRecordEntrypoint
Expand Down
14 changes: 13 additions & 1 deletion src/entrypoints/LinkHandleEntrypoint.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,19 @@ import { LinkHandleCommand } from "../verifiers/HandleVerifier.sol";
* @dev The verifier can be updated via the entrypoint function.
*/
contract LinkHandleEntrypoint is LinkTextRecordEntrypoint {
constructor(address verifier) LinkTextRecordEntrypoint(verifier, "com.twitter") { }
/**
* @notice Constructor
* @param verifier The LinkHandleCommandVerifier contract address
* @param recordName ENS text record name (e.g. "com.twitter") — the key in setText(node, key, value)
* @param platformName The platform name in the command (e.g. "Twitter")
*/
constructor(
address verifier,
string memory recordName,
string memory platformName
)
LinkTextRecordEntrypoint(verifier, recordName, platformName)
{ }

/**
* @inheritdoc LinkTextRecordEntrypoint
Expand Down
19 changes: 14 additions & 5 deletions src/entrypoints/LinkTextRecordEntrypoint.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { IVerifier } from "../interfaces/IVerifier.sol";
import { EnsUtils } from "../utils/EnsUtils.sol";

struct TextRecord {
string platformName;
string ensName;
string value;
bytes32 nullifier;
Expand All @@ -20,7 +21,8 @@ struct TextRecord {
abstract contract LinkTextRecordEntrypoint is IEntryPoint, ITextRecordVerifier {
using EnsUtils for bytes;

bytes32 private immutable _KEY;
bytes32 private immutable _recordNameHash;
bytes32 private immutable _platformNameHash;

// link text record command verifier
address public immutable VERIFIER;
Expand All @@ -34,9 +36,12 @@ abstract contract LinkTextRecordEntrypoint is IEntryPoint, ITextRecordVerifier {
error InvalidCommand();
error NullifierUsed();

constructor(address verifier, string memory keyName) {
/// @param recordName ENS text record name (e.g. "com.twitter") — the key in setText(node, key, value)
/// @param platformName Platform name in the command (e.g. "x")
constructor(address verifier, string memory recordName, string memory platformName) {
VERIFIER = verifier;
_KEY = keccak256(bytes(keyName));
_recordNameHash = keccak256(bytes(recordName));
_platformNameHash = bytes(platformName).length == 0 ? bytes32(0) : keccak256(bytes(platformName));
}

/**
Expand All @@ -47,6 +52,10 @@ abstract contract LinkTextRecordEntrypoint is IEntryPoint, ITextRecordVerifier {
function entrypoint(bytes memory data) external {
TextRecord memory record = _extractTextRecord(data);

if (_platformNameHash != bytes32(0) && keccak256(bytes(record.platformName)) != _platformNameHash) {
revert InvalidCommand();
}

if (_isUsed[record.nullifier]) {
revert NullifierUsed();
}
Expand Down Expand Up @@ -81,8 +90,8 @@ abstract contract LinkTextRecordEntrypoint is IEntryPoint, ITextRecordVerifier {
* @inheritdoc ITextRecordVerifier
*/
function verifyTextRecord(bytes32 node, string memory key, string memory value) external view returns (bool) {
// this verifier only supports this specific text record
if (keccak256(bytes(key)) != _KEY) {
// this verifier only supports this specific text record (key must match constructor recordName)
if (keccak256(bytes(key)) != _recordNameHash) {
revert UnsupportedKey();
}
string memory storedTextRecord = textRecord[node];
Expand Down
17 changes: 13 additions & 4 deletions src/verifiers/LinkEmailCommandVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ import { TextRecord } from "../entrypoints/LinkTextRecordEntrypoint.sol";
/**
* @notice Enum representing the indices of command parameters in the command template
* @dev Used to specify which parameter to extract from the command string
* @param ENS_NAME = 0
* @param PLATFORM_NAME = 0
* @param ENS_NAME = 1
*/
enum CommandParamIndex {
PLATFORM_NAME,
ENS_NAME
}

Expand Down Expand Up @@ -79,6 +81,11 @@ contract LinkEmailCommandVerifier is EmailAuthVerifier {
PublicInputs memory publicInputs = _unpackPublicInputs(publicInputsFields);
return LinkEmailCommand({
textRecord: TextRecord({
platformName: string(
CommandUtils.extractCommandParamByIndex(
_getTemplate(), publicInputs.maskedCommand, uint256(CommandParamIndex.PLATFORM_NAME)
)
),
// ensName is extracted from the command
ensName: string(
CommandUtils.extractCommandParamByIndex(
Expand All @@ -95,8 +102,10 @@ contract LinkEmailCommandVerifier is EmailAuthVerifier {
}

function _getMaskedCommand(LinkEmailCommand memory command) private pure returns (string memory) {
bytes[] memory commandParams = new bytes[](1);
commandParams[0] = abi.encode(command.textRecord.ensName);
bytes[] memory commandParams = new bytes[](2);
commandParams[0] = abi.encode(command.textRecord.platformName);
commandParams[1] = abi.encode(command.textRecord.ensName);

return CommandUtils.computeExpectedCommand(commandParams, _getTemplate(), 0);
}

Expand All @@ -105,7 +114,7 @@ contract LinkEmailCommandVerifier is EmailAuthVerifier {

template[0] = "Link";
template[1] = "my";
template[2] = "email";
template[2] = CommandUtils.STRING_MATCHER;
template[3] = "to";
template[4] = CommandUtils.STRING_MATCHER;

Expand Down
16 changes: 12 additions & 4 deletions src/verifiers/LinkHandleCommandVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import { HandleVerifier, LinkHandleCommand, PublicInputs, TextRecord } from "./H
/**
* @notice Enum representing the indices of command parameters in the command template
* @dev Used to specify which parameter to extract from the command string
* @param ENS_NAME = 0
* @param PLATFORM_NAME = 0
* @param ENS_NAME = 1
*/
enum CommandParamIndex {
PLATFORM_NAME,
ENS_NAME
}

Expand Down Expand Up @@ -65,6 +67,11 @@ contract LinkHandleCommandVerifier is HandleVerifier {
PublicInputs memory publicInputs = _unpackPublicInputs(publicInputsFields);
return LinkHandleCommand({
textRecord: TextRecord({
platformName: string(
CommandUtils.extractCommandParamByIndex(
_getTemplate(), publicInputs.command, uint256(CommandParamIndex.PLATFORM_NAME)
)
),
// ensName is extracted from the command
ensName: string(
CommandUtils.extractCommandParamByIndex(
Expand All @@ -81,8 +88,9 @@ contract LinkHandleCommandVerifier is HandleVerifier {
}

function _getCommand(LinkHandleCommand memory command) private pure returns (string memory) {
bytes[] memory commandParams = new bytes[](1);
commandParams[0] = abi.encode(command.textRecord.ensName);
bytes[] memory commandParams = new bytes[](2);
commandParams[0] = abi.encode(command.textRecord.platformName);
commandParams[1] = abi.encode(command.textRecord.ensName);

return CommandUtils.computeExpectedCommand(commandParams, _getTemplate(), 0);
}
Expand All @@ -92,7 +100,7 @@ contract LinkHandleCommandVerifier is HandleVerifier {

template[0] = "Link";
template[1] = "my";
template[2] = "x";
template[2] = CommandUtils.STRING_MATCHER;
template[3] = "handle";
template[4] = "to";
template[5] = CommandUtils.STRING_MATCHER;
Expand Down
Loading