Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add remote sign for attestation #59

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 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
8 changes: 7 additions & 1 deletion .env.local
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind moving these changes to: https://github.com/Layr-Labs/hello-world-avs/blob/master/.env.example ?

We're trying to make the deployments more streamlined for local and holesky, so we removed .env.local

Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# local or remote
SIGNER_TYPE=local

PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
RPC_URL=http://127.0.0.1:8545
CONTRACT_ADDRESS=0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB
Expand All @@ -13,4 +16,7 @@ HOLESKY_CONTRACT_ADDRESS=0x3361953F4a9628672dCBcDb29e91735fb1985390
HOLESKY_DELEGATION_MANAGER_ADDRESS=0xA44151489861Fe9e3055d95adC98FbD462B948e7
HOLESKY_STAKE_REGISTRY_ADDRESS=0xBDACD5998989Eec814ac7A0f0f6596088AA2a270
HOLESKY_AVS_DIRECTORY_ADDRESS=0x055733000064333CaDDbC92763c58BF0192fFeBf
HOLESKY_WS_RPC_URL=wss://holesky.drpc.org
HOLESKY_WS_RPC_URL=wss://holesky.drpc.org

REMOTE_SIGNER_URL="fill me in if you want to use remote signer"
OPERATOR_ADDRESS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
81 changes: 74 additions & 7 deletions operator/index.ts
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI: there were a LOT of changes to index.ts. It might be easier to start with a fresh PR?

Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ const contractAddress = process.env.CONTRACT_ADDRESS!;
const stakeRegistryAddress = process.env.STAKE_REGISTRY_ADDRESS!;
const avsDirectoryAddress = process.env.AVS_DIRECTORY_ADDRESS!;

const remoteSignerUrl = process.env.REMOTE_SIGNER_URL!;
const operatorAddress = process.env.OPERATOR_ADDRESS!;

const signerType = process.env.SIGNER_TYPE!;

const delegationManager = new ethers.Contract(delegationManagerAddress, delegationABI, wallet);
const contract = new ethers.Contract(contractAddress, contractABI, wallet);
const registryContract = new ethers.Contract(stakeRegistryAddress, registryABI, wallet);
Expand All @@ -22,8 +27,20 @@ const avsDirectory = new ethers.Contract(avsDirectoryAddress, avsDirectoryABI, w
const signAndRespondToTask = async (taskIndex: number, taskCreatedBlock: number, taskName: string) => {
const message = `Hello, ${taskName}`;
const messageHash = ethers.utils.solidityKeccak256(["string"], [message]);
const messageBytes = ethers.utils.arrayify(messageHash);
const signature = await wallet.signMessage(messageBytes);

let signature = "";
if (signerType === "local") {
console.log("Using local private key to sign message")
const messageBytes = ethers.utils.arrayify(messageHash);
signature = await wallet.signMessage(messageBytes);
} else if (signerType === "remote") {
console.log("Using remote signer to sign message")
signature = await callJsonRpcEndpoint(
remoteSignerUrl,
"eth_sign",
[operatorAddress, messageHash]
);
}

console.log(
`Signing and responding to task ${taskIndex}`
Expand Down Expand Up @@ -60,16 +77,16 @@ const registerOperator = async () => {

// Calculate the digest hash using the avsDirectory's method
const digestHash = await avsDirectory.calculateOperatorAVSRegistrationDigestHash(
wallet.address,
contract.address,
salt,
wallet.address,
contract.address,
salt,
expiry
);

// // Sign the digest hash with the operator's private key
const signingKey = new ethers.utils.SigningKey(process.env.PRIVATE_KEY!);
const signature = signingKey.signDigest(digestHash);

// // Encode the signature in the required format
operatorSignature.signature = ethers.utils.joinSignature(signature);

Expand Down Expand Up @@ -101,4 +118,54 @@ const main = async () => {

main().catch((error) => {
console.error("Error in main function:", error);
});
});

interface JsonRpcRequest {
jsonrpc: string;
method: string;
params: any[];
id: number;
}

interface JsonRpcResponse {
jsonrpc: string;
result?: any;
error?: {
code: number;
message: string;
};
id: number;
}

async function callJsonRpcEndpoint(
url: string,
method: string,
params: any[] = []
): Promise<any> {
const request: JsonRpcRequest = {
jsonrpc: "2.0",
method,
params,
id: 1, // You might want to generate a unique id for each request
};

const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(request),
});

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

const jsonResponse: JsonRpcResponse = await response.json();

if (jsonResponse.error) {
throw new Error(`JSON-RPC error: ${jsonResponse.error.message}`);
}

return jsonResponse.result;
}