---
title: "Додайте зрозуміле підписання до вашого протоколу за допомогою ERC-7730"
description: "Дізнайтеся, як написати дескриптор ERC-7730, щоб взаємодії з вашим смарт-контрактом відображали зрозумілі для людини деталі в гаманцях перед тим, як користувачі їх підпишуть."
author: "Гестер Брюкман"
lang: uk
tags: ["ERC-7730", "безпека", "підписання", "смарт-контракти", "гаманці"]
skill: intermediate
breadcrumb: "Зрозуміле підписання"
published: 2026-05-11
---

Більшість великих експлойтів в Етеріумі мали однаковий останній крок: користувач схвалював транзакцію, яку не міг повноцінно зрозуміти. Апаратні гаманці показують необроблені шістнадцяткові дані виклику (calldata), і, що ще гірше, змушують вас вмикати сліпе підписання. Програмні гаманці показують розкодовані поля, але тільки тоді, коли вони розпізнають контракт. Коли ж вони цього не роблять — чи то через те, що протокол новий, застосунок скомпрометований, чи пристрій перебуває в автономному режимі — користувачі підписують наосліп.

[ERC-7730](https://eips.ethereum.org/EIPS/eip-7730) визначає стандартний формат JSON для опису того, що *означають* виклики функцій вашого контракту. 

Гаманець, який підтримує ERC-7730, зчитує ваш дескриптор і показує:

> **Обмін**  
> Надіслати: 1,000 USDC  
> Отримати мінімум: 0.42 WETH  
> Протокол: Юнісвоп V3

Або єдине побудоване речення, зрозуміле як людям, так і агентам:

> Обміняти 1,000 USDC на щонайменше 0.42 WETH

Замість селектора функції та списку необроблених цілих значень.

Це [зрозуміле підписання](https://clearsigning.org/) — «Що бачиш, те й підписуєш» (What You See Is What You Sign). Цей посібник допоможе вам написати дескриптор для власного контракту, перевірити його за допомогою офіційного інструменту CLI та надіслати до відкритого реєстру.

## Передумови {#prerequisites}

- Обізнаність із Solidity та ABI смарт-контрактів
- Розгорнутий смарт-контракт із верифікованим ABI (верифікація на [Sourcify](https://sourcify.dev) є обов'язковою вимогою перед прийняттям дескриптора до реєстру) 
- Python 3.12+ для CLI-інструменту перевірки 
- Базові знання JSON

## Що таке дескриптор ERC-7730? {#what-is-an-erc-7730-descriptor}

Дескриптор — це єдиний файл JSON із трьома розділами:

| Розділ | Призначення |
| :---- | :---- |
| `context` | Прив'язує дескриптор до конкретних розгортань контракту за ідентифікатором ланцюга (chain ID) та адресою |
| `metadata` | Називає проєкт і визначає константи для багаторазового використання |
| `display` | Зіставляє кожну сигнатуру функції зі зрозумілими для людини мітками та форматами полів |

Оскільки дескриптор відокремлений від самого контракту, ви можете додати підтримку зрозумілого підписання до будь-якого існуючого протоколу без повторного розгортання. Гаманці отримують дескриптори з реєстру та використовують їх під час підписання.

## Крок 1: Створіть каркас файлу {#step-1-create-the-file-skeleton}

Створіть файл із назвою `calldata-<contractname>-<descriptorversion>.json`. Префікс `calldata-` вказує реєстру, що цей дескриптор охоплює виклики функцій контракту, на відміну від `eip712-` для повідомлень із типізованими даними. `descriptorversion` вказує реєстру версію файлу дескриптора (за замовчуванням 0, якщо версія не вказана).


```json
{
  "$schema": "https://eips.ethereum.org/assets/eip-7730/erc7730-v2.schema.json",
  "context": {},
  "metadata": {},
  "display": {
    "formats": {}
  }
}
```

## Крок 2: Напишіть розділ контексту {#step-2-write-the-context-section}

Розділ `context` прив'язує дескриптор до одного або кількох розгортань контракту. Гаманці використовують це, щоб зіставити вхідну транзакцію з правильним дескриптором.

```json
"context": {
  "$id": "uniswap-v3-router-mainnet",
  "contract": {
    "deployments": [
      { "chainId": 1, "address": "0xYourContractAddressOnMainnet" },
      { "chainId": 137, "address": "0xYourContractAddressOnPolygon" }
    ]
  }
}
```

### Поля контексту {#context-fields}

- `context.$id` — Унікальний ідентифікатор для цього документа дескриптора або конфігурації розгортання.
- `contract.deployments` — Набір розгортань, до яких застосовується цей дескриптор.
- `deployments[].chainId` — Ідентифікатор ланцюга EVM (chain ID) для розгортання. Включіть кожен ланцюг, де розгорнуто ваш контракт.
- `deployments[].address` — Адреса контракту, яку гаманці повинні асоціювати з цим дескриптором. Використовуйте адресу реалізації, яка містить логіку виконання.

## Крок 3: Напишіть розділ метаданих {#step-3-write-the-metadata-section}

Розділ метаданих надає зрозумілу для людини інформацію про проєкт і контракт, описані в цьому файлі. Гаманці можуть використовувати цю інформацію для відображення назв протоколів, посилань та інших контекстних деталей під час підписання.

```json
"metadata": {
  "owner": "Example Swap Protocol",
  "info": { "url": "https://example.xyz" },
  "contractName": "SwapRouter"
}
```

### Поля метаданих {#metadata-fields}

- `owner` — Проєкт, протокол, організація або супроводжувач, відповідальний за цей дескриптор.
- `info.url` — Канонічна URL-адреса проєкту або документації, яку гаманці можуть показувати користувачам для додаткового контексту.
- `contractName` — Назва контракту або реалізації, описана в цьому файлі, яка зазвичай збігається з верифікованим вихідним кодом або ABI.

Якщо ваш файл ERC-7730 описує контракт ERC-20, вам також слід додати об'єкт токена. 

## Крок 4: Напишіть розділ форматів відображення {#step-4-write-the-displayformats-section}

Об'єкт `display.formats` зіставляє сигнатури функцій зі зрозумілими для людини інструкціями щодо підписання. Саме так гаманці показують вашу функцію користувачам перед тим, як вони схвалюють транзакцію!

Кожен ключ — це зрозумілий для людини фрагмент ABI: сигнатура функції, що включає як імена параметрів, так і їхні типи, точно так, як вони вказані у вашому ABI.


### Приклад: Опис обміну токенів {#eg-describing-token-swap}

```json
"display": {
  "formats": {
    "swapExactTokensForTokens(uint256 amountIn,uint256 amountOutMin,address[] path,address to,uint256 deadline)": {
      "intent": "Swap",
      "interpolatedIntent": "Swap {amountIn} for at least {amountOutMin}",
      "fields": [
        {
          "path": "#.amountIn",
          "label": "Send",
          "format": "tokenAmount",
          "params": {
            "tokenPath": "#.path[0]"
          }
        },
        {
          "path": "#.amountOutMin",
          "label": "Receive minimum",
          "format": "tokenAmount",
          "params": {
            "tokenPath": "#.path[1]"
          }
        },
        {
          "path": "#.to",
          "label": "Recipient",
          "format": "addressName",
          "params": {
            "types": ["eoa", "contract"],
            "sources": ["local", "ens"]
          }
        },
        {
          "path": "#.deadline",
          "label": "Expires",
          "format": "date",
          "params": {
            "encoding": "timestamp"
          }
        }
      ]
    }
  }
}

```

### Поля відображення {#display-fields}

- **`intent`** — **(Обов'язково)** Короткий, зручний для користувача опис дії, наприклад, «Обмін» (Swap).
- **`interpolatedIntent`** — **(Рекомендовано)** Більш розгорнутий шаблон речення, який містить відформатовані значення полів, наприклад `"Swap {amountIn} for at least {amountOutMin}"`. Додайте його разом із `intent`, щоб надати ще зручніший дескриптор, який гаманці зможуть відображати з урахуванням будь-яких обмежень екрана.
- **`fields`** — **(Обов'язково)** Впорядкований список полів транзакції, які гаманці повинні показувати користувачам.
  - **`path`** — **(Обов'язково)** Посилання на дані транзакції. `#.fieldName` вказує на розкодований параметр даних виклику за іменем в ABI. `@.value` стосується значення ETH, надісланого з транзакцією.
  - **`label`** — **(Обов'язково)** Зрозуміла для людини мітка, що відображається поруч зі значенням.
  - **`format`** — **(Рекомендовано)** Керує тим, як має відображатися значення. Поширені формати включають:
    - `tokenAmount`
    - `addressName`
    - `date`

    Використовуйте `raw`, коли додаткове форматування не потрібне. Деякі формати приймають додаткову конфігурацію **`params`**. Наприклад:

    - `tokenAmount` може використовувати `tokenPath` для визначення того, яка адреса токена надає метадані про десяткові знаки та тикер.
    - `date` може використовувати `encoding` для опису того, як закодована часова мітка.

    Якщо вибраний формат не потребує додаткової інформації, пропустіть `params`.

## Повний дескриптор {#the-complete-descriptor}

```json
{
  "$schema": "https://eips.ethereum.org/assets/eip-7730/erc7730-v2.schema.json",
  "context": {
    "$id": "uniswap-v3-router-mainnet",
    "contract": {
      "deployments": [
        {
          "chainId": 1,
          "address": "0xYourContractAddressOnMainnet"
        },
        {
          "chainId": 137,
          "address": "0xYourContractAddressOnPolygon"
        }
      ]
    }
  },
  "metadata": {
    "owner": "Example Swap Protocol",
    "info": {
      "url": "https://example.xyz"
    },
    "contractName": "SwapRouter"
  },
  "display": {
    "formats": {
      "swapExactTokensForTokens(uint256 amountIn,uint256 amountOutMin,address[] path,address to,uint256 deadline)": {
        "intent": "Swap",
        "interpolatedIntent": "Swap {amountIn} for at least {amountOutMin}",
        "fields": [
          {
            "path": "#.amountIn",
            "label": "Send",
            "format": "tokenAmount",
            "params": {
              "tokenPath": "#.path[0]"
            }
          },
          {
            "path": "#.amountOutMin",
            "label": "Receive minimum",
            "format": "tokenAmount",
            "params": {
              "tokenPath": "#.path[1]"
            }
          },
          {
            "path": "#.to",
            "label": "Recipient",
            "format": "addressName",
            "params": {
              "types": ["eoa", "contract"],
              "sources": ["local", "ens"]
            }
          },
          {
            "path": "#.deadline",
            "label": "Expires",
            "format": "date",
            "params": {
              "encoding": "timestamp"
            }
          }
        ]
      }
    }
  }
}
```

## Крок 5: Надішліть до реєстру {#step-5-submit-to-the-registry}

[Реєстр ERC-7730](https://github.com/ethereum/clear-signing-erc7730-registry) — це відкритий репозиторій, який підтримується [Фундацією Ethereum](/foundation/) як нейтральним розпорядником. Будь-хто може вільно клонувати та самостійно розміщувати його — гаманці незалежно вирішують, яким екземплярам реєстру вони довіряють.

1. Зробіть форк репозиторію на GitHub  
2. Створіть папку за шляхом `registry/<your-project-name>/`  
3. Помістіть свій файл у неї: `registry/myproject/calldata-mycontract-0_0.json`  
4. Оновіть поле `$schema` на відносний шлях, що використовується в репозиторії: `"../../specs/erc7730-v2.schema.json"`  
5. Відкрийте pull request (запит на злиття)

Коли ви відкриваєте PR, CI автоматично запускає перевірку схеми, перевіряє, чи сигнатури функцій створюють дійсні селектори, підтверджує, що адреса контракту верифікована на Sourcify, і позначає невідповідності ABI. Результати перевірки з'являються безпосередньо в PR. Супроводжувачі реєстру перевіряють подання на наявність неправильно сформованих або потенційно шкідливих дескрипторів. Включення до реєстру не означає проведення аудиту або схвалення.

<Alert variant="info">
<AlertContent>
<AlertDescription>
**Примітка:** Ваш контракт має бути верифікований на <a href="https://repo.sourcify.dev">Sourcify</a> перед тим, як ваш PR зможе бути прийнятий. Якщо він ще не верифікований, спочатку <a href="https://verify.sourcify.dev/">надішліть запит на верифікацію</a>.
</AlertDescription>
</AlertContent>
</Alert>

## Що відбувається після злиття? {#what-happens-after-merging}

Усі дескриптори в реєстрі відкриті для аудиторів. Після злиття вашого PR будь-який аудитор може перевірити ваш дескриптор і опублікувати криптографічну атестацію (відповідно до [ERC-8176](https://github.com/ethereum/ERCs/pull/1576)), що підтверджує його точність. 

Ці сигнали атестації дозволяють гаманцям застосовувати власні політики довіри — дескриптор із кількома незалежними атестаціями має більшу вагу, ніж той, що їх не має. Ви можете зв'язатися зі спільнотою аудиторів через [clearsigning.org](https://clearsigning.org).

Гаманці самі обирають, який реєстр вони підтримуватимуть. Щойно ваш дескриптор опиниться в реєстрі, гаманці, які підтримують ERC-7730, почнуть отримувати його (якщо він є в їхньому реєстрі) і відображатимуть зрозумілі для людини дані, коли користувачі взаємодіятимуть із вашим контрактом.

## Додаткові матеріали {#further-reading}

- [Специфікація ERC-7730](https://eips.ethereum.org/EIPS/eip-7730)  
- [Реєстр ERC-7730](https://github.com/ethereum/clear-signing-erc7730-registry)  
- [clearsigning.org](https://clearsigning.org) — інструменти, стан екосистеми та управління  
- [Верифікація контрактів на Sourcify](https://sourcify.dev)  
- [Ініціатива Trillion Dollar Security](https://trilliondollarsecurity.org)