Разработка 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.







