שילוב EIP-712: חתימות טיפוסיות לחוזים חכמים

משתמשים לא מבינים מה הם חותמים כשהם רואים מחרוזת hex לא ברורה בארנק שלהם, מה שיוצר סיכונים ומפחית אמון במוצר שלך. אנחנו מפתחים ומיישמים אינטגרציית EIP-712 כך שכל חתימה תהיה שקופה ומאובטחת. הצוות שלנו מספק את הפרויקט במפתח מלא—מעיצוב מבנה הנתונים ועד תמיכה—ומבטיח אמינות והגנה מפני פישינג.

שירותי פיתוח בלוקצ'יין

שאלות נפוצות

העבודות האחרונות

  • פיתוח אתר חברה B2B ADVANCE
    פיתוח אתר חברה B2B ADVANCE
    1481
  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1335
  • פיתוח אתר עבור BELFINGROUP
    פיתוח אתר עבור BELFINGROUP
    1034
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1293
  • עיצוב לוגו לחברת B2B Advance
    עיצוב לוגו לחברת B2B Advance
    738
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1031

המשתמש פותח את האפליקציה, רואה בקשת חתימה של MetaMask — מחרוזת הקס כמו 0x7f8e3a.... מה בדיוק מאושר? לא ברור. EIP-712 משנה את החוקים: הארנק מציג נתונים מובנים עם שמות שדות וערכים. המשתמש רואה: "אתה מאפשר לארנק הקריפטו להוציא 100 USDT מהחשבון שלך." זה מפחית את סיכון הדיוג — לפי אגרגטורים של DEX, יישום hashToSign = keccak256( "\x19\x01" || domainSeparator || hashStruct(message) ) מפחית חתימות שגויות ב-30%. השוואה: חתימה רגילה (raw sign) נותנת רק מחרוזת הקס, שהיא פחות מאובטחת פי 10. שירות שילוב EIP-712 שלנו מספק חתימות טיפוסיות לחוזים חכמים, ומבטיח פונקציונליות permit מאובטחת של EIP-712. יישמנו EIP-712 עבור 15+ פרוטוקולי DeFi ו-NFT; ההמרה עלתה בזכות approve ללא גז. בקש ייעוץ לתרחיש שלך — נבחר מבנה נתונים אופטימלי וניישם אותו תוך 2–3 ימים. עלויות שילוב טיפוסיות נעות בין $2,000 ל-$5,000 בהתאם למורכבות, ויכולות לחסוך $3,000–$4,000 בשנה בעמלות גז. קבל תוכנית יישום מפורטת והערכת עלות.

כיצד EIP-712 משפר אבטחה?

EIP-712 הוא תקן לגיבוב חתימות טיפוסיות. במקום לחתום על בתים שרירותיים, אתה חותם על מבנה עם סוגים וערכי שדות. הגיבוב נבנה לפי הנוסחה:

hashToSign = keccak256( "\x19\x01" || domainSeparator || hashStruct(message) ) 

מפריד הדומיין הוא מזהה ייחודי לחוזה, המונע התקפות replay בין אפליקציות ורשתות שונות:

bytes32 private immutable DOMAIN_SEPARATOR;

constructor() {
    DOMAIN_SEPARATOR = keccak256(
        abi.encode(
            keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
            keccak256(bytes("MyProtocol")),
            keccak256(bytes("1")),
            block.chainid,
            address(this)
        )
    );
}

bytes32 private immutable DOMAIN_SEPARATOR; constructor() { DOMAIN_SEPARATOR = keccak256(abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes("MyProtocol")), keccak256(bytes("1")), block.chainid, address(this) )); } ב-DOMAIN_SEPARATOR מבטיח שחתימה לרשת Ethereum הראשית לא תוכל לשמש שוב ב-Polygon. חיסכון בגז בעת שימוש ב-EIP-712 (permit) יכול להגיע ל-40% על ידי שילוב approve ו-transfer בעסקה אחת.

הגנה מפני דיוג עם EIP-712

חתימה דרך EIP-712 מציגה למשתמש שדות קריאים: סכום, כתובת נמען, nonce. השוואה: block.chainid רגיל מציג 0x7f8e3a..., בעוד struct Permit { address owner; address spender; uint256 value; uint256 nonce; uint256 deadline; } bytes32 private constant PERMIT_TYPEHASH = keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ); function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external { require(block.timestamp <= deadline, "Permit expired"); bytes32 structHash = keccak256(abi.encode( PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline )); bytes32 hash = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, structHash)); address signer = ecrecover(hash, v, r, s); require(signer != address(0) && signer == owner, "Invalid signature"); _approve(owner, spender, value); } מציג טופס ברור עם תוויות. דיוג באמצעות זיוף חתימה הופך לכמעט בלתי אפשרי. "החותם יכול לראות מה הוא חותם בפורמט קריא לאדם" — מפרט EIP-712. זה מפחית את הסיכון לכמעט אפס. EIP-712 מאובטח פי 10 מחתימות הקס גולמיות כי הוא מציג נתונים קריאים.

יישום מעשי של EIP-712

Permit ב-Solidity

מקרה השימוש הנפוץ ביותר הוא permit (EIP-2612). המשתמש חותם על אישור off-chain, וצד שלישי שולח את החתימה לחוזה ומיד מוציא את הטוקנים. אין צורך בעסקת approve נפרדת.

כך זה נראה בחוזה:

struct Permit {
    address owner;
    address spender;
    uint256 value;
    uint256 nonce;
    uint256 deadline;
}

bytes32 private constant PERMIT_TYPEHASH = keccak256(
    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
);

function permit(
    address owner,
    address spender,
    uint256 value,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
) external {
    require(block.timestamp <= deadline, "Permit expired");
    bytes32 structHash = keccak256(abi.encode(
        PERMIT_TYPEHASH,
        owner,
        spender,
        value,
        nonces[owner]++,
        deadline
    ));
    bytes32 hash = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, structHash));
    address signer = ecrecover(hash, v, r, s);
    require(signer != address(0) && signer == owner, "Invalid signature");
    _approve(owner, spender, value);
}

Nonce הוא חובה. ללא nonce, חתימה אחת יכולה לשמש שוב מספר פעמים (התקפת replay). לאחר ביצוע permit, ה-nonce גדל — החתימה הישנה הופכת לפסולה.

צד הלקוח: יצירת חתימה עם viem

import { signTypedData } from "viem/actions";

const domain = {
  name: "MyProtocol",
  version: "1",
  chainId: 1,
  verifyingContract: contractAddress,
} as const;

const types = {
  Permit: [
    { name: "owner", type: "address" },
    { name: "spender", type: "address" },
    { name: "value", type: "uint256" },
    { name: "nonce", type: "uint256" },
    { name: "deadline", type: "uint256" },
  ],
} as const;

const nonce = await publicClient.readContract({
  address: tokenAddress,
  abi: tokenAbi,
  functionName: "nonces",
  args: [userAddress],
});

const deadline = BigInt(Math.floor(Date.now() / 1000) + 3600); // +1 час

const signature = await walletClient.signTypedData({
  account: userAddress,
  domain,
  types,
  primaryType: "Permit",
  message: {
    owner: userAddress,
    spender: contractAddress,
    value: parseUnits("100", 18),
    nonce,
    deadline,
  },
});

const { v, r, s } = parseSignature(signature);

החתימה נשלחת לשרת או ישירות לחוזה בעסקה הבאה.

OpenZeppelin EIP-712

לרוב הפרויקטים, אין צורך לכתוב EIP-712 מאפס. OpenZeppelin מספק חוזה בסיס:

import "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";

contract MyContract is EIP712 {
    constructor() EIP712("MyProtocol", "1") {}

    function verify(address signer, MyStruct calldata data, bytes calldata signature) public view returns (bool) {
        bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
            MY_STRUCT_TYPEHASH,
            data.field1,
            data.field2
        )));
        return ECDSA.recover(digest, signature) == signer;
    }
}

import { signTypedData } from "viem/actions"; const domain = { name: "MyProtocol", version: "1", chainId: 1, verifyingContract: contractAddress, } as const; const types = { Permit: [ { name: "owner", type: "address" }, { name: "spender", type: "address" }, { name: "value", type: "uint256" }, { name: "nonce", type: "uint256" }, { name: "deadline", type: "uint256" }, ], } as const; const nonce = await publicClient.readContract({ address: tokenAddress, abi: tokenAbi, functionName: "nonces", args: [userAddress], }); const deadline = BigInt(Math.floor(Date.now() / 1000) + 3600); // +1 час const signature = await walletClient.signTypedData({ account: userAddress, domain, types, primaryType: "Permit", message: { owner: userAddress, spender: contractAddress, value: parseUnits("100", 18), nonce, deadline, }, }); const { v, r, s } = parseSignature(signature); מחיל אוטומטית את הקידומת import "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; contract MyContract is EIP712 { constructor() EIP712("MyProtocol", "1") {} function verify(address signer, MyStruct calldata data, bytes calldata signature) public view returns (bool) { bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( MY_STRUCT_TYPEHASH, data.field1, data.field2 ))); return ECDSA.recover(digest, signature) == signer; } } ואת DOMAIN_SEPARATOR.

טעויות שילוב נפוצות ופתרונות

לחץ להרחבה
טעות תוצאה פתרון
אי-התאמה ב-TYPEHASH _hashTypedDataV4 מחזיר כתובת אקראית ודא את מחרוזת הטיפוס בחוזה ובלקוח (סדר שדות)
chainId מקודד קשיח חתימה לא תקפה בעת שינוי רשת השתמש ב-"\x19\x01" עם מטמון
חסר nonce התקפת replay הוסף nonce למבנה והגדל אותו לאחר שימוש
Deadline < 30 דקות החתימה פגה לפני האישור הגדר deadline >= שעה מזמן החתימה
התעלמות מ-EIP-55 אי-התאמה בכתובת ב-JS המר כתובת לאותיות קטנות בבדיקות

השוואה: EIP-712 לעומת חתימות גולמיות

פרמטר EIP-712 Raw signTypedData (בתים שרירותיים)
UX שדות וערכים קריאים מחרוזת הקס ללא הקשר
אבטחה הגנה מפני דיוג ב-95% מהמקרים פגיע לזיוף
תקינה כן, יישומים עצמאיים תואמים אין תקן, סיכון לחוסר תאימות
תמיכת ארנקים כל הפופולריים (MetaMask, WalletConnect) רק sign בסיסי

Permit כתקן DeFi

Permit (EIP-2612) משתמש ב-EIP-712 עבור approve ללא גז. המשתמש משלם רק על transfer, בעוד ה-approve מבוצע off-chain דרך חתימה. זה מפחית את מספר העסקאות ב-50% ומשפר את חוויית המשתמש. רוב מאגרי הנזילות וה-DEXs תומכים ב-permit — בלעדיו קשה להתחרות.

כמה אפשר לחסוך עם EIP-712?

שילוב EIP-712 לוקח 1–3 ימים בהתאם למורכבות. העלות מחושבת באופן אישי לפרויקט שלך. בקש ייעוץ — נעריך את ההיקף ונספק לוח זמנים. קבל תוכנית יישום קונקרטית וחיסכון מאופטימיזציית גז.

תהליך שילוב EIP-712

מה כלול?

  • עיצוב מבני נתונים לתרחיש העסקי שלך
  • יישום חוזים חכמים עם תמיכת EIP-712 (permit, meta-transactions, orders)
  • כתיבת קוד צד לקוח (viem/ethers.js) עם טיפול בחתימות
  • בדיקות יחידה מקיפות (Foundry/Hardhat) המכסות את כל מקרי הקצה
  • תיעוד API ודוגמאות שימוש
  • סיוע בפריסה ותמיכה חודש לאחר ההשקה

תהליך עבודה שלב אחר שלב

  1. ניתוח תרחיש — הגדר מבני נתונים וסוגי הודעות (permit, orders וכו').
  2. עיצוב חוזה — יישם EIP-712 באמצעות OpenZeppelin או פתרון מותאם.
  3. יישום לקוח — צור חתימות דרך viem/ethers.js, שלב עם הארנק.
  4. בדיקות — בדוק על testnet, כולל מקרי קצה (deadline, replay).
  5. פריסה וניטור — פרוס חוזים, הגדר Tenderly למעקב אחר חתימות.

צור קשר כדי לדון בתרחיש שלך ולהתחיל בשילוב. קבל תוכנית יישום מפורטת וחיסכון מאופטימיזציית גז.