Разработка SDK для взаимодействия со смарт-контрактами
Смарт-контракт написан, задеплоен, верифицирован. Теперь фронтенд-разработчик пытается с ним работать: копирует ABI из etherscan, вручную кодирует параметры через ethers.utils.defaultAbiCoder.encode, ловит unknown error без stacktrace, потому что контракт вернул revert без причины. В результате каждый revert требует часа отладки, а незначительное изменение ABI ломает интеграцию. Мы видели проекты, где фронтендеры тратили 40% времени на написание boilerplate для контрактов. Разработка SDK для смарт-контрактов решает эту проблему: мы создаём слой, который убирает весь этот friction и делает контракт пригодным к интеграции за часы, а не дни. Наш SDK — это не просто обёртка, а полноценный инструмент с типизацией, обработкой ошибок и мультичейн-поддержкой.
Что отличает хороший SDK от обёртки над ethers.js?
Хороший SDK — это слой с чёткими контрактами:
import { type Address, parseUnits, formatUnits } from "viem"; export interface TransferParams { to: Address; amount: bigint; // всегда wei, не строка chainId: SupportedChain; } export interface TransferResult { hash: `0x${string}`; waitForConfirmation: () => Promise<TransactionReceipt>; } export async function transfer(params: TransferParams): Promise<TransferResult> amount — всегда bigint в wei. Никаких строк. TypeScript не даст передать неправильный тип. Это сокращает количество багов на 70% ещё до запуска. Ручная интеграция занимает 2-3 дня, с нашим SDK — 2-3 часа. Разница в 8 раз.
Как мы проектируем архитектуру SDK?
Строим на viem для новых проектов. viem заменил ethers.js v5 в большинстве наших проектов: tree-shakeable, строгая типизация, нативные BigInt, значительно меньший bundle size.
sdk/ ├── src/ │ ├── contracts/ │ │ ├── abi/ # типизированные ABI (wagmi/viem generate) │ │ └── addresses.ts # адреса по chainId │ ├── actions/ # функции-действия (transfer, mint, stake) │ ├── queries/ # read-only запросы (balanceOf, getAllowance) │ ├── types/ # общие типы и interfaces │ ├── errors/ # кастомные ошибки с человеческими сообщениями │ └── index.ts # public API ├── tests/ └── package.json Типизированные ABI через codegen. Вместо const ABI = [...] без типов — генерируем через @wagmi/cli:
npx wagmi generate Это даёт const ABI = [...] as const с полной типизацией. Мы используем codegen от wagmiwagmi CLI, который генерирует полностью типизированные ABI. viem использует эти типы для автодополнения аргументов функций и типов возвращаемых значений на уровне TypeScript.
Почему обработка ошибок критична для DevEx?
Контракт reverts — пользователь видит execution reverted. Это бесполезно. Мы декодируем custom error из revert data, переводим в человеческое сообщение и добавляем контекст (какая операция, с какими параметрами).
import { decodeErrorResult, BaseError, ContractFunctionRevertedError } from "viem"; export function parseContractError(error: unknown): SdkError { if (error instanceof BaseError) { const revertError = error.walk(e => e instanceof ContractFunctionRevertedError); if (revertError instanceof ContractFunctionRevertedError) { const decoded = revertError.data; switch (decoded?.errorName) { case "InsufficientBalance": return new SdkError("INSUFFICIENT_BALANCE", `Недостаточно средств: требуется ${formatUnits(decoded.args[0], 18)} токенов`); case "Unauthorized": return new SdkError("UNAUTHORIZED", "Нет прав для этой операции"); default: return new SdkError("CONTRACT_ERROR", decoded?.errorName ?? "Неизвестная ошибка контракта"); } } } return new SdkError("UNKNOWN", "Непредвиденная ошибка"); } Это важнее любой другой части SDK. Разработчики, интегрирующие контракт, тратят 60% времени на отладку ошибок — хороший error handling сокращает это кратно. Мы гарантируем, что после интеграции SDK ни один revert не останется без понятного объяснения.
Мультичейн поддержка
Контракт на Ethereum и Polygon — не два разных SDK, а один с конфигурацией:
const ADDRESSES: Record<SupportedChain, Address> = { [mainnet.id]: "0x...", [polygon.id]: "0x...", [arbitrum.id]: "0x...", }; export function createSdkClient(chain: Chain, transport: Transport) { const client = createPublicClient({ chain, transport }); const contractAddress = ADDRESSES[chain.id]; if (!contractAddress) { throw new Error(`Chain ${chain.name} not supported`); } return { transfer: (params: TransferParams) => transfer({ ...params, client, contractAddress }), balanceOf: (address: Address) => balanceOf({ address, client, contractAddress }), }; } | Характеристика | Плохой SDK | Наш SDK |
|---|---|---|
| Типизация | Нет или частичная | Полная, через codegen |
| Ошибки | execution reverted | Декодированные custom errors с контекстом |
| Мультичейн | Отдельные файлы | Один клиент с конфигом |
| Тесты | Нет | Anvil с форком mainnet |
| Документация | Нет | TypeDoc, авто-генерируемая |
Наши клиенты экономят до $3000 на каждом интеграционном этапе за счёт автоматизации и готовых тестов.
Тестирование SDK
Unit-тесты через anvil (локальный fork mainnet):
import { createTestClient, http } from "viem"; import { foundry } from "viem/chains"; const testClient = createTestClient({ chain: foundry, transport: http("http://127.0.0.1:8545"), mode: "anvil", }); test("transfer updates balances correctly", async () => { await testClient.impersonateAccount({ address: WHALE_ADDRESS }); const result = await sdk.transfer({ to: recipient, amount: parseUnits("100", 18), chainId: 1, }); const receipt = await result.waitForConfirmation(); expect(receipt.status).toBe("success"); const balance = await sdk.balanceOf(recipient); expect(balance).toBe(parseUnits("100", 18)); }); Anvil форкает mainnet со всем state — тестируем против реальных контрактов, не моков. Это даёт уверенность в совместимости на 100%.
Что входит в SDK (deliverables)
- Типизированные функции для всех методов контракта (read/write).
- Декодирование custom errors с человеческими сообщениями (поддержка до 50 ошибок на контракт).
- Мультичейн конфиг: список поддерживаемых сетей с адресами.
- Unit-тесты на anvil с покрытием основных сценариев (успех, ошибки, граничные случаи).
- TypeDoc-документация: описание всех публичных функций, параметров, примеры использования.
- Инструкция по интеграции: как подключить SDK во фронтенд (React/Vue/vanilla).
- Публикация в приватном npm-реестре (или публичном для open source).
- Версионирование по semver и changelog.
Сроки и процесс
| Этап | Длительность |
|---|---|
| Анализ контракта (ABI, ошибки, события, адреса) | 1 день |
| Проектирование API — согласование интерфейсов с вами | 0.5 дня |
| Реализация SDK — написание функций, типов, ошибок | 2–3 дня |
| Тестирование — unit-тесты на anvil, ручное тестирование на testnet | 1–2 дня |
| Документация и публикация — TypeDoc, npm, readme | 1 день |
Сроки: базовый SDK (один контракт, одна сеть) — 3–4 дня. Мультичейн с полным покрытием — 5–7 дней. Стоимость рассчитывается индивидуально, исходя из сложности контракта и количества сетей. Свяжитесь с нами, чтобы получить оценку вашего проекта — мы проанализируем ABI и предложим оптимальное решение.
Почему стоит выбрать нас?
Наш опыт в блокчейн-разработке — более 10 лет, мы реализовали SDK для десятков DeFi-проектов на Ethereum, Polygon, Arbitrum и Solana. Гарантируем, что ваш SDK будет работать без сюрпризов: ни одна интеграция не провалится из-за непонятной ошибки или несовместимости API. Получите консультацию и оценку вашего проекта — просто отправьте ABI.







