Розробка 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 (локальний форк 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.







