Skip to main content

Documentation Index

Fetch the complete documentation index at: https://daehan-base.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

Privy를 사용하여 EVM 지갑의 메시지 서명, 타입 데이터 서명, 트랜잭션을 수행하는 방법을 알아보세요.

개요

Privy는 EVM(이더리움 호환) 지갑과 원활하게 작동하는 포괄적인 지갑 액션 훅을 제공합니다. 메시지, 타입 데이터, 원시 해시에 서명하고 트랜잭션을 직접 전송할 수 있습니다.

달성할 내용

이 가이드를 마치면 다음을 할 수 있습니다:
  • EVM 지갑으로 메시지 서명
  • 구조화된 데이터에 타입 데이터(EIP-712) 서명
  • EVM 네트워크에서 트랜잭션 전송
이 가이드의 코드 스니펫은 다음 예제 프로젝트를 기반으로 합니다:

구현

컴포넌트 설정

"use client";

import { useState, useMemo, useEffect } from "react";
import {
  useWallets,
  useSendTransaction,
  useSignMessage,
  useSignTypedData,
} from "@privy-io/react-auth";

const WalletActions = () => {
  const { signMessage } = useSignMessage();
  const { sendTransaction } = useSendTransaction();
  const { signTypedData } = useSignTypedData();
  const { wallets } = useWallets();

const [selectedWallet, setSelectedWallet] = useState<{
    address: string;
    type: string;
    name: string;
  } | null>(null);

  // 선택을 위한 지갑 매핑
  const allWallets = useMemo(() => {
    return wallets.map((wallet) => ({
      address: wallet.address,
      type: "ethereum",
      name: wallet.address,
    }));
  }, [wallets]);

  useEffect(() => {
    if (allWallets.length > 0 && !selectedWallet) {
      setSelectedWallet(allWallets[0]);
    }
  }, [allWallets, selectedWallet]);

  const handleSignMessage = async () => {
    if (!selectedWallet) return;
    
    try {
      const message = "Hello, world!";
      const { signature } = await signMessage(
        { message },
        { address: selectedWallet.address }
      );
      console.log("Message signed:", signature);
    } catch (error) {
      console.error("Failed to sign message:", error);
    }
  };


  const handleSendTransaction = async () => {
    if (!selectedWallet) return;
    
    try {
      const transaction = await sendTransaction(
        { 
          to: "0xE3070d3e4309afA3bC9a6b057685743CF42da77C", 
          value: 10000 
        },
        { address: selectedWallet.address }
      );
      console.log("Transaction sent:", transaction);
    } catch (error) {
      console.error("Failed to send transaction:", error);
    }
  };

  const handleSignTypedData = async () => {
    if (!selectedWallet) return;
    
    try {
      const typedData = {
        domain: {
          name: "Example App",
          version: "1",
          chainId: 1,
          verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
        },
        types: {
          Person: [
            { name: "name", type: "string" },
            { name: "wallet", type: "address" },
          ],
          Mail: [
            { name: "from", type: "Person" },
            { name: "to", type: "Person" },
            { name: "contents", type: "string" },
          ],
        },
        primaryType: "Mail",
        message: {
          from: {
            name: "Alice",
            wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
          },
          to: {
            name: "Bob",
            wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB",
          },
          contents: "Hello, Bob!",
        },
      };

      const { signature } = await signTypedData(typedData, {
        address: selectedWallet.address,
      });
      console.log("Typed data signature:", signature);
    } catch (error) {
      console.error("Failed to sign typed data:", error);
    }
  };

  return (
    <div className="space-y-4">
      {/* 지갑 선택 */}
      <div>
        <label className="block text-sm font-medium mb-2">지갑 선택:</label>
        <select
          value={selectedWallet?.address || ""}
          onChange={(e) => {
            const wallet = allWallets.find((w) => w.address === e.target.value);
            setSelectedWallet(wallet || null);
          }}
          className="w-full p-2 border rounded-md"
        >
          <option value="">지갑 선택</option>
          {allWallets.map((wallet, index) => (
            <option key={index} value={wallet.address}>
              {wallet.address}
            </option>
          ))}
        </select>
      </div>

      {/* 액션 버튼 */}
      <div className="grid grid-cols-3 gap-4">
        <button 
          onClick={handleSignMessage}
          disabled={!selectedWallet}
          className="px-4 py-2 bg-blue-600 text-white rounded disabled:opacity-50"
        >
          메시지 서명
        </button>
        <button 
          onClick={handleSignTypedData}
          disabled={!selectedWallet}
          className="px-4 py-2 bg-green-600 text-white rounded disabled:opacity-50"
        >
          타입 데이터 서명
        </button>
        <button 
          onClick={handleSendTransaction}
          disabled={!selectedWallet}
          className="px-4 py-2 bg-red-600 text-white rounded disabled:opacity-50"
        >
          트랜잭션 전송
        </button>
      </div>
    </div>
  );
};

지갑 액션

메시지 서명

const handleSignMessage = async () => {
  if (!selectedWallet) return;
  
  try {
    const message = "Hello, world!";
    const { signature } = await signMessage(
      { message },
      { address: selectedWallet.address }
    );
    console.log("Signature:", signature);
  } catch (error) {
    console.error("Failed to sign message:", error);
  }
};

타입 데이터 서명 (EIP-712)

const handleSignTypedData = async () => {
  if (!selectedWallet) return;
  
  try {
    const typedData = {
      domain: {
        name: "Example App",
        version: "1",
        chainId: 1,
        verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
      },
      types: {
        Person: [
          { name: "name", type: "string" },
          { name: "wallet", type: "address" },
        ],
        Mail: [
          { name: "from", type: "Person" },
          { name: "to", type: "Person" },
          { name: "contents", type: "string" },
        ],
      },
      primaryType: "Mail",
      message: {
        from: {
          name: "Alice",
          wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
        },
        to: {
          name: "Bob",
          wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB",
        },
        contents: "Hello, Bob!",
      },
    };

    const { signature } = await signTypedData(typedData, {
      address: selectedWallet.address,
    });
    console.log("Typed data signature:", signature);
  } catch (error) {
    console.error("Failed to sign typed data:", error);
  }
};

트랜잭션 전송

const handleSendTransaction = async () => {
  if (!selectedWallet) return;
  
  try {
    const transaction = await sendTransaction(
      { 
        to: "0xE3070d3e4309afA3bC9a6b057685743CF42da77C", 
        value: 10000 // Wei
      },
      { address: selectedWallet.address }
    );
    console.log("Transaction hash:", transaction);
  } catch (error) {
    console.error("Failed to send transaction:", error);
  }
};

더 알아보기