> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getpara.com/llms.txt
> Use this file to discover all available pages before exploring further.

# EIP-712 Typed Data Signing with Para

> Learn how to sign structured, typed data using EIP-712 standard with Para's Ethers integration

EIP-712 enables signing complex, structured data in a standardized way, providing better security and user experience compared to simple message signing. This walkthrough shows how to implement EIP-712 typed data signing using Para's Ethers integration.

## What is EIP-712?

EIP-712 is a standard for signing typed structured data, offering several advantages:

* **Structured data signing** - Sign complex objects with multiple fields and nested structures
* **Domain separation** - Prevents signature replay attacks across different applications or chains
* **Human-readable format** - Users can see exactly what they're signing in wallet interfaces
* **Type safety** - Ensures data conforms to expected structure before signing

## Common Use Cases

EIP-712 is commonly used for:

* **Meta-transactions** - Gasless transactions with relayer support
* **Permit signatures** - Token approvals without on-chain transactions
* **Attestations** - Cryptographically signed claims or certificates
* **Voting systems** - Off-chain voting with on-chain verification
* **Order signing** - DEX orders and marketplace listings

## Setup Requirements

You need an authenticated Para client and Ethers provider to implement EIP-712 signing.

### Install Dependencies

```bash theme={null}
npm install @getpara/react-sdk @getpara/ethers-v6-integration ethers
```

### Create Ethers Provider Hook

```typescript hooks/useEthersProvider.ts theme={null}
import { useMemo } from "react";
import { ethers } from "ethers";

const RPC_URL = process.env.NEXT_PUBLIC_RPC_URL || 
  "https://ethereum-holesky-rpc.publicnode.com";

export function useEthersProvider() {
  const provider = useMemo(() => {
    return new ethers.JsonRpcProvider(RPC_URL);
  }, []);

  return { provider };
}
```

### Create Para Signer Hook

```typescript hooks/useParaSigner.ts theme={null}
import { useState, useEffect } from "react";
import { createParaEthersSigner } from "@getpara/ethers-v6-integration";
import { useAccount, useClient } from "@getpara/react-sdk";
import { useEthersProvider } from "./useEthersProvider";

export function useParaSigner() {
  const { data: account } = useAccount();
  const client = useClient();
  const { provider } = useEthersProvider();
  const [signer, setSigner] = useState<ParaEthersSigner | null>(null);

  useEffect(() => {
    if (account?.isConnected && provider && client) {
      try {
        const newSigner = createParaEthersSigner({ para: client, provider: provider });
        setSigner(newSigner);
      } catch (error) {
        console.error("Failed to initialize Para signer:", error);
        setSigner(null);
      }
    } else {
      setSigner(null);
    }
  }, [account?.isConnected, provider, client]);

  return { signer, provider };
}
```

## EIP-712 Implementation

### Define Domain and Types

The domain separator provides context and prevents replay attacks:

```typescript theme={null}
// Domain definition - provides context for the signature
const domain = {
  name: "MyDApp",                    // Application name
  version: "1",                      // Version of signing domain
  chainId: 17000,                    // Network chain ID (Holesky testnet)
  verifyingContract: "0x..." as Address  // Contract that will verify signatures
};

// Types definition - structure of the data being signed
const types = {
  TokenAttestation: [
    { name: "holder", type: "address" },
    { name: "balance", type: "string" },
    { name: "purpose", type: "string" },
    { name: "timestamp", type: "uint256" },
    { name: "nonce", type: "uint256" }
  ]
};
```

### Create Typed Data Structure

```typescript theme={null}
interface TokenAttestation {
  holder: string;
  balance: string;
  purpose: string;
  timestamp: number;
  nonce: number;
}

// Create the data object to sign
const attestation: TokenAttestation = {
  holder: "0x742d35Cc6634C0532925a3b8D756e3C98d8a3a1B",
  balance: "1000.5",
  purpose: "Identity verification",
  timestamp: Math.floor(Date.now() / 1000),
  nonce: 1
};
```

### Sign Typed Data

```typescript theme={null}
import { useParaSigner } from "./hooks/useParaSigner";

export function TypedDataSigning() {
  const { signer } = useParaSigner();
  const [signature, setSignature] = useState<string>("");
  const [isLoading, setIsLoading] = useState(false);

  const signAttestation = async () => {
    if (!signer) {
      throw new Error("Signer not available");
    }

    setIsLoading(true);
    
    try {
      // Sign the typed data
      const signature = await signer.signTypedData(domain, types, attestation);
      
      setSignature(signature);
      console.log("Signed attestation:", signature);
    } catch (error) {
      console.error("Signing failed:", error);
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <div>
      <button 
        onClick={signAttestation}
        disabled={!signer || isLoading}
      >
        {isLoading ? "Signing..." : "Sign Attestation"}
      </button>
      
      {signature && (
        <div>
          <h3>Signature:</h3>
          <code>{signature}</code>
        </div>
      )}
    </div>
  );
}
```

## Advanced Examples

### Permit Signature for Token Approvals

```typescript theme={null}
// EIP-2612 Permit signature
const permitTypes = {
  Permit: [
    { name: "owner", type: "address" },
    { name: "spender", type: "address" },
    { name: "value", type: "uint256" },
    { name: "nonce", type: "uint256" },
    { name: "deadline", type: "uint256" }
  ]
};

const permitData = {
  owner: userAddress,
  spender: spenderAddress,
  value: ethers.parseUnits("100", 18),
  nonce: await token.nonces(userAddress),
  deadline: Math.floor(Date.now() / 1000) + 3600 // 1 hour
};

const permitSignature = await signer.signTypedData(
  {
    name: "MyToken",
    version: "1",
    chainId: 1,
    verifyingContract: tokenAddress
  },
  permitTypes,
  permitData
);
```

### Voting Signature

```typescript theme={null}
const voteTypes = {
  Vote: [
    { name: "proposalId", type: "uint256" },
    { name: "support", type: "bool" },
    { name: "voter", type: "address" },
    { name: "reason", type: "string" },
    { name: "timestamp", type: "uint256" }
  ]
};

const voteData = {
  proposalId: 42,
  support: true,
  voter: userAddress,
  reason: "I support this proposal",
  timestamp: Math.floor(Date.now() / 1000)
};

const voteSignature = await signer.signTypedData(domain, voteTypes, voteData);
```

### Marketplace Order Signature

```typescript theme={null}
const orderTypes = {
  Order: [
    { name: "seller", type: "address" },
    { name: "buyer", type: "address" },
    { name: "tokenContract", type: "address" },
    { name: "tokenId", type: "uint256" },
    { name: "price", type: "uint256" },
    { name: "deadline", type: "uint256" },
    { name: "nonce", type: "uint256" }
  ]
};

const orderData = {
  seller: userAddress,
  buyer: "0x0000000000000000000000000000000000000000", // Any buyer
  tokenContract: nftContractAddress,
  tokenId: 123,
  price: ethers.parseEther("1.5"),
  deadline: Math.floor(Date.now() / 1000) + 86400, // 24 hours
  nonce: 1
};

const orderSignature = await signer.signTypedData(domain, orderTypes, orderData);
```

## Signature Verification

### Client-Side Verification

```typescript theme={null}
import { ethers } from "ethers";

async function verifySignature(
  domain: any,
  types: any,
  data: any,
  signature: string,
  expectedSigner: string
) {
  try {
    const recoveredSigner = ethers.verifyTypedData(domain, types, data, signature);
    
    return recoveredSigner.toLowerCase() === expectedSigner.toLowerCase();
  } catch (error) {
    console.error("Verification failed:", error);
    return false;
  }
}

// Usage
const isValid = await verifySignature(
  domain,
  types,
  attestation,
  signature,
  userAddress
);

console.log("Signature valid:", isValid);
```

### Smart Contract Verification

```solidity theme={null}
// Solidity contract for verifying EIP-712 signatures
contract AttestationVerifier {
    bytes32 private constant ATTESTATION_TYPEHASH = keccak256(
        "TokenAttestation(address holder,string balance,string purpose,uint256 timestamp,uint256 nonce)"
    );
    
    bytes32 private immutable DOMAIN_SEPARATOR;
    
    constructor() {
        DOMAIN_SEPARATOR = keccak256(
            abi.encode(
                keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                keccak256(bytes("MyDApp")),
                keccak256(bytes("1")),
                block.chainid,
                address(this)
            )
        );
    }
    
    function verifyAttestation(
        TokenAttestation memory attestation,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public view returns (address) {
        bytes32 structHash = keccak256(
            abi.encode(
                ATTESTATION_TYPEHASH,
                attestation.holder,
                keccak256(bytes(attestation.balance)),
                keccak256(bytes(attestation.purpose)),
                attestation.timestamp,
                attestation.nonce
            )
        );
        
        bytes32 digest = keccak256(
            abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, structHash)
        );
        
        return ecrecover(digest, v, r, s);
    }
}
```

## Error Handling

### Common Issues and Solutions

```typescript theme={null}
const signWithErrorHandling = async () => {
  try {
    const signature = await signer.signTypedData(domain, types, data);
    return signature;
  } catch (error) {
    if (error.code === 'ACTION_REJECTED') {
      console.log("User rejected the signing request");
    } else if (error.message.includes('invalid domain')) {
      console.error("Domain configuration error:", error);
    } else if (error.message.includes('invalid types')) {
      console.error("Types definition error:", error);
    } else {
      console.error("Unexpected signing error:", error);
    }
    throw error;
  }
};
```

### Validation Before Signing

```typescript theme={null}
function validateTypedData(domain: any, types: any, data: any) {
  // Validate domain
  if (!domain.name || !domain.version || !domain.chainId) {
    throw new Error("Invalid domain: missing required fields");
  }
  
  // Validate types
  if (!types || Object.keys(types).length === 0) {
    throw new Error("Invalid types: empty or undefined");
  }
  
  // Validate data matches types
  const primaryType = Object.keys(types)[0];
  const typeFields = types[primaryType];
  
  for (const field of typeFields) {
    if (!(field.name in data)) {
      throw new Error(`Missing required field: ${field.name}`);
    }
  }
  
  return true;
}
```

## Best Practices

### Security Considerations

* **Validate all inputs** before signing
* **Use proper domain separation** to prevent replay attacks
* **Include nonces** to prevent signature reuse
* **Set reasonable deadlines** for time-sensitive signatures
* **Verify contract addresses** in domain separator

### Type Definition Guidelines

* **Use specific types** (uint256 instead of uint)
* **Order fields consistently** across your application
* **Document field purposes** for maintainability
* **Version your types** when making changes

### User Experience

* **Provide clear descriptions** of what users are signing
* **Show human-readable summaries** before signing
* **Handle rejection gracefully** with meaningful error messages
* **Cache signatures** when appropriate to avoid re-signing

## Next Steps

<CardGroup cols={2}>
  <Card title="Ethers Integration" href="/v2/react/guides/web3-operations/evm/setup-libraries">
    Learn more about Para's Ethers integration
  </Card>

  <Card title="Session Management" href="/v2/react/guides/sessions">
    Understand Para's authentication system
  </Card>
</CardGroup>

## Related Walkthroughs

<CardGroup cols={3}>
  <Card title="Ethereum Transfers" icon="ethereum" href="/v2/walkthroughs/ethereum-transfers">
    Intermediate · 20 min · Send ETH with Ethers and Viem
  </Card>

  <Card title="Porto Integration" icon="key" href="/v2/walkthroughs/porto">
    Intermediate · 30 min · EIP-7702 smart accounts with session keys
  </Card>

  <Card title="Aave v3 Integration" icon="landmark" href="/v2/walkthroughs/aave">
    Advanced · 45 min · Lending, borrowing, and yield strategies
  </Card>
</CardGroup>
