Деплой смарт-контрактів у NEAR Protocol

Проєктуємо та розробляємо блокчейн-рішення повного циклу: від архітектури смарт-контрактів до запуску DeFi-протоколів, NFT-маркетплейсів та криптобірж. Аудит безпеки, токеноміка, інтеграція з наявною інфраструктурою.
Показано 1 з 1Усі 1306 послуг
Деплой смарт-контрактів у NEAR Protocol
Середній
від 4 годин до 2 днів
Часті запитання

Напрямки блокчейн-розробки

Етапи блокчейн-розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1306
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1217
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    919
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1146
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    609
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    884

Розгортування смарт-контрактів у Near Protocol

Розробники, які приходять з екосистеми EVM, зазвичай очікують щось подібне до Solidity + Hardhat. Near працює інакше: контракти — це модулі WebAssembly, модель облікових записів принципово відрізняється від Ethereum, а розробник оплачує зберігання даних, а не користувач. Ці відмінності необхідно зрозуміти до написання першого рядка коду, інакше розгортування перетворюється на серію неприємних сюрпризів.

Середовище виконання та мови

Near VM виконує байт-код WASM. Офіційно підтримуються дві мови:

Rust + near-sdk-rs — основний вибір для production. SDK надає макроси #[near_bindgen], #[init], BorshSerialize/BorshDeserialize для серіалізації стану. Borsh (Binary Object Representation Serializer for Hashing) — детермінований бінарний формат, обов'язковий для зберігання стану контрактів Near.

JavaScript/TypeScript + near-sdk-js — для прототипів та простої логіки. Компілюється в WASM через QuickJS, продуктивність значно нижча, ліміти газу суворіші.

Приклад мінімального Rust контракту:

use near_sdk::{near_bindgen, env, AccountId};
use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize};

#[near_bindgen]
#[derive(BorshDeserialize, BorshSerialize)]
pub struct Counter {
    value: i64,
}

#[near_bindgen]
impl Counter {
    #[init]
    pub fn new() -> Self {
        Self { value: 0 }
    }

    pub fn increment(&mut self) {
        self.value += 1;
    }

    pub fn get(&self) -> i64 {
        self.value
    }
}

Модель облікових записів та зберігання

Ключова відмінність від EVM: у Near кожен смарт-контракт живе на іменованому обліковому записі (myapp.near, myapp.testnet). Обліковий запис зберігає код контракту та його стан. Вартість зберігання — 1 NEAR на 100 КБ стану, і ці засоби блокуються на балансі облікового запису. Це називається storage staking.

Практичне наслідок: якщо контракт зберігає дані користувачів, потрібна логіка storage_deposit — користувач вносить депозит NEAR перед реєстрацією, ці засоби покривають його зберігання. Стандарт NEP-145 визначає цей паттерн для fungible tokens.

#[payable]
pub fn storage_deposit(&mut self, account_id: Option<AccountId>) -> StorageBalance {
    let amount = env::attached_deposit();
    let account_id = account_id.unwrap_or_else(env::predecessor_account_id);
    // мінімум 0.00125 NEAR за запис облікового запису
    assert!(amount >= STORAGE_PER_ACCOUNT, "Insufficient deposit");
    // ...
}

Підоблікові записи — стандартний паттерн для factory контрактів: token.myapp.near, pool.myapp.near. Кожен підоблік — повністю незалежний обліковий запис.

Кросконтрактні виклики та асинхронна модель

Near — асинхронний розділений блокчейн. Кросконтрактний виклик не виконується синхронно в одній транзакції — він створює окремий receipt, який обробляється в наступному блоці. Результат приходить через callback.

#[near_bindgen]
impl MyContract {
    pub fn call_external(&mut self, contract_id: AccountId) -> Promise {
        ext_other_contract::ext(contract_id)
            .with_static_gas(Gas(5 * TGAS))
            .get_value()
            .then(
                Self::ext(env::current_account_id())
                    .with_static_gas(Gas(5 * TGAS))
                    .on_value_received()
            )
    }

    #[private]
    pub fn on_value_received(&mut self, #[callback_result] result: Result<u64, PromiseError>) {
        match result {
            Ok(value) => { /* обробка */ }
            Err(_) => { env::panic_str("External call failed") }
        }
    }
}

#[private] — макрос, що додає перевірку assert_eq!(env::current_account_id(), env::predecessor_account_id()). Без нього будь-хто може викликати callback безпосередньо.

Збирання та розгортування

Інструменти: cargo-near — офіційний CLI для збирання, near-cli-rs (переписана версія на Rust) для розгортування.

# Установка
cargo install cargo-near
cargo install near-cli-rs

# Зберіть оптимізований WASM
cargo near build

# Розгортування на testnet
near contract deploy myapp.testnet \
  use-file ./target/near/myapp.wasm \
  without-init-call \
  network-config testnet \
  sign-with-keychain \
  send

WASM файл після збирання з cargo-near автоматично проходить через wasm-opt (Binaryen) — це зменшує розмір та економить на зберіганні.

Для розгортування mainnet через multisig обліковий запис або через near-cli з апаратним гаманцем (--useLedgerKey). Розгортування без ініціалізації — контракт у ненієнціалізованому стані, перший виклик new() встановлює початковий стан.

Тестування

Unit тести — стандартні Rust unit тести з VMContextBuilder для моку середовища (predecessor, attached_deposit, block_timestamp).

Workspaces-rs — інтеграційні тести, які запускають локальну Near sandbox та розгортують реальний WASM. Це де-факто стандарт для тестування кросконтрактної взаємодії:

#[tokio::test]
async fn test_full_flow() -> anyhow::Result<()> {
    let worker = near_workspaces::sandbox().await?;
    let wasm = std::fs::read("./target/near/myapp.wasm")?;
    let contract = worker.dev_deploy(&wasm).await?;
    
    let result = contract.call("increment")
        .transact().await?;
    assert!(result.is_success());
    Ok(())
}

Типові помилки при міграції з EVM

  • Немає msg.sender як адреси. У Near env::predecessor_account_id() — рядок, не 20 байт. Порівняння через == для AccountId.
  • Паніка замість revert. env::panic_str("message") або assert!() — аналог require() у Solidity. Витрати газу на паніку не повертаються.
  • Ітерація по LookupMap. LookupMap не итерируемий. Для ітерованих колекцій — UnorderedMap, Vector. Вибір структури даних впливає на газ.
  • Одиниці газу. 1 TGas = 10^12 газу. Простий виклик ~2-3 TGas, кросконтрактний +5 TGas мінімум. Ліміт транзакції — 300 TGas.

Процес роботи

Аудит вимог → вибір мови (Rust/JS) → проектування моделі зберігання (критично для вартості) → розробка з unit тестами → інтеграційне тестування через workspaces → розгортування на testnet → верифікація через Near Explorer → розгортування на mainnet.

Терміни 4 години — це розгортування готового коду. Розробка контракту з нуля з тестуванням: 1-5 днів залежно від складності логіки.