UNPKG

@graphprotocol/toolshed

Version:

A collection of tools and utilities for the Graph Protocol Typescript components

124 lines (110 loc) 4.01 kB
import { ethers, id, Wallet } from 'ethers' export const EIP712_DISPUTE_MANAGER_DOMAIN_SALT = ethers.getBytes( '0xa070ffb1cd7409649bf77822cce74495468e06dbfaef09556838bf188679b9c2', ) export const EIP712_ATTESTATION_PROOF_TYPEHASH = id( 'Receipt(bytes32 requestCID,bytes32 responseCID,bytes32 subgraphDeploymentID)', ) export const EIP712_ATTESTATION_PROOF_TYPES = { Receipt: [ { name: 'requestCID', type: 'bytes32' }, { name: 'responseCID', type: 'bytes32' }, { name: 'subgraphDeploymentID', type: 'bytes32' }, ], } /** * Creates an attestation data for a given request and response CIDs. * @param requestCID The request CID. * @param responseCID The response CID. * @param signerPrivateKey The private key of the signer. * @param subgraphDeploymentId The subgraph deployment ID. * @param disputeManagerAddress The address of the dispute manager contract. * @param chainId The chain ID. * @returns The attestation data. */ export async function generateAttestationData( requestCID: string, responseCID: string, subgraphDeploymentId: string, signerPrivateKey: string, disputeManagerAddress: string, chainId: number, ): Promise<string> { // Create the domain for the EIP712 signature const domain = { name: 'Graph Protocol', version: '0', chainId: chainId, verifyingContract: disputeManagerAddress, salt: EIP712_DISPUTE_MANAGER_DOMAIN_SALT, } // Create receipt struct const receipt = { requestCID: ethers.hexlify(ethers.getBytes(requestCID)), responseCID: ethers.hexlify(ethers.getBytes(responseCID)), subgraphDeploymentID: ethers.hexlify(ethers.getBytes(subgraphDeploymentId)), } // Sign the receipt hash with the allocation private key const signer = new Wallet(signerPrivateKey) const signature = await signer.signTypedData(domain, EIP712_ATTESTATION_PROOF_TYPES, receipt) const sig = ethers.Signature.from(signature) // Concatenate the bytes directly return ethers.concat([ ethers.getBytes(requestCID), ethers.getBytes(responseCID), ethers.getBytes(subgraphDeploymentId), ethers.getBytes(sig.r), ethers.getBytes(sig.s), new Uint8Array([sig.v]), ]) } /** * Verifies the signer of an attestation data. * @param attestationData The attestation data to verify. * @param expectedSigner The expected signer address. * @param disputeManagerAddress The address of the dispute manager contract. * @param chainId The chain ID. * @returns True if the signer matches the expected signer, false otherwise. */ export function verifyAttestationSigner( attestationData: string, expectedSigner: string, disputeManagerAddress: string, chainId: number, ): boolean { try { // Extract components from attestation data const data = ethers.getBytes(attestationData) // Each CID and deployment ID is 32 bytes const requestCID = ethers.hexlify(data.slice(0, 32)) const responseCID = ethers.hexlify(data.slice(32, 64)) const subgraphDeploymentID = ethers.hexlify(data.slice(64, 96)) // Extract signature components const r = ethers.hexlify(data.slice(96, 128)) const s = ethers.hexlify(data.slice(128, 160)) const v = data[160] // Create the domain for the EIP712 signature const domain = { name: 'Graph Protocol', version: '0', chainId: chainId, verifyingContract: disputeManagerAddress, salt: EIP712_DISPUTE_MANAGER_DOMAIN_SALT, } // Create receipt struct const receipt = { requestCID, responseCID, subgraphDeploymentID, } // Recover the signer address const signature = ethers.Signature.from({ r, s, v }) const recoveredAddress = ethers.verifyTypedData(domain, EIP712_ATTESTATION_PROOF_TYPES, receipt, signature) console.log(`recoveredAddress: ${recoveredAddress}`) // Compare addresses (case-insensitive) return recoveredAddress.toLowerCase() === expectedSigner.toLowerCase() } catch (error) { console.log(error) return false } }