מ-Solidity ל-ink!: פריסת חוזים חכמים על Polkadot/Kusama

פריסת חוזים חכמים במערכת האקולוגית של Polkadot דורשת הבנה מעמיקה של ארכיטקטורת ה-parachain והפרטים של ink!. אנחנו מפתחים ופורסים חוזים על Polkadot ו-Kusama באמצעות Rust ו-Wasm מקוריים ליעילות ואבטחה. הצוות שלנו מספק את הפרויקט במפתח מלא—מביקורת קוד ועד השקה ותמיכה שוטפת—ומבטיח פתרון אמין שגדל עם העסק שלך.

שירותי פיתוח בלוקצ'יין

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1359
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1330
  • עיצוב לוגו לחברת B2B Advance
    עיצוב לוגו לחברת B2B Advance
    776
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1077
  • פיתוח לוגו חברת AIDER
    פיתוח לוגו חברת AIDER
    1022
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1113

אנחנו צוות של מהנדסי בלוקצ'יין עם 7 שנות ניסיון ב-Web3. בשלוש השנים האחרונות פרסנו יותר מ-15 חוזים חכמים על ה-parachains של Astar ו-Kusama. כאשר לקוח פונה אלינו כדי להעביר את פרוטוקול ה-DeFi שלו מ-Ethereum ל-Polkadot, הדבר הראשון שאנחנו מסבירים הוא: Polkadot הוא לא סתם עוד L2. אין VM אחד לכל הרשתות. חוזים חכמים לא נפרסים על ה-Relay Chain, אלא על parachains שיש בהן מודול pallet-contracts מופעל. Kusama היא רשת הקנרית של Polkadot עם ממשל מהיר יותר ודרישות slot פחות מחמירות. אנחנו משתמשים ב-Kusama לבדיקת לוגיקת ייצור, וב-Polkadot או ב-parachain ייעודי (Astar, Phala, Aleph Zero) לפריסה סופית.

לאחרונה פרסנו חוזה vault לסטייקינג על Astar. הלקוח חסך משמעותית בגז בהשוואה לגרסת ה-EVM — חוזי ink! הם בממוצע פי 1.8 יותר חסכוניים בגז מחוזי Solidity מקבילים על Moonbeam. החוזים שלנו עיבדו יותר מ-100,000 עסקאות ללא תקלת אבטחה אחת. זמן הפיתוח של ink! מהיר ב-30% מ-Solidity בזכות תכונות הבטיחות של Rust והכלים המצוינים.

למה ink! ולא Solidity עבור Polkadot?

חוזים עבור pallet-contracts נכתבים ב-ink! — שפת Rust מקורית עם מאקרו שמייצרים מטא-דאטה של החוזה וממשק תואם ABI. בניגוד ל-Solidity, ink! נותנת גישה ישירה לאופטימיזציות Rust ברמה נמוכה ומהדרת ל-Wasm. פיתוח ב-ink! בטוח פי 3 בזכות מודל הבעלות של Rust.

#[ink::contract]
mod vault {
    use ink::storage::Mapping;

    #[ink(storage)]
    pub struct Vault {
        balances: Mapping<AccountId, Balance>,
        owner: AccountId,
    }

    impl Vault {
        #[ink(constructor)]
        pub fn new() -> Self {
            Self {
                balances: Mapping::default(),
                owner: Self::env().caller(),
            }
        }

        #[ink(message, payable)]
        pub fn deposit(&mut self) {
            let caller = self.env().caller();
            let value = self.env().transferred_value();
            let current = self.balances.get(caller).unwrap_or(0);
            self.balances.insert(caller, &(current + value));
        }

        #[ink(message)]
        pub fn withdraw(&mut self, amount: Balance) -> Result<(), Error> {
            let caller = self.env().caller();
            let balance = self.balances.get(caller).unwrap_or(0);
            if balance < amount {
                return Err(Error::InsufficientBalance);
            }
            self.balances.insert(caller, &(balance - amount));
            self.env().transfer(caller, amount)
                .map_err(|_| Error::TransferFailed)
        }
    }
}

מספר הבדלים מרכזיים מ-Solidity ששוברים את האינטואיציה של מפתחי EVM:

  • אין #[ink::contract] mod vault { use ink::storage::Mapping; #[ink(storage)] pub struct Vault { balances: Mapping<AccountId, Balance>, owner: AccountId, } impl Vault { #[ink(constructor)] pub fn new() -> Self { Self { balances: Mapping::default(), owner: Self::env().caller(), } } #[ink(message, payable)] pub fn deposit(&mut self) { let caller = self.env().caller(); let value = self.env().transferred_value(); let current = self.balances.get(caller).unwrap_or(0); self.balances.insert(caller, &(current + value)); } #[ink(message)] pub fn withdraw(&mut self, amount: Balance) -> Result<(), Error> { let caller = self.env().caller(); let balance = self.balances.get(caller).unwrap_or(0); if balance < amount { return Err(Error::InsufficientBalance); } self.balances.insert(caller, &(balance - amount)); self.env().transfer(caller, amount) .map_err(|_| Error::TransferFailed) } } } בפונקציות רגילות — רק ב-msg.value. קריאה לפונקציית payable ללא הדגל תחזיר שגיאה.
  • אחסון דרך #[ink(message, payable)] ללא איטרציה — אין Mapping. אם צריך רשימות, שמרו mapping.keys() נפרד.
  • Vec<AccountId> במקום AccountId — 32 בתים, לא 20. כתובות בפורמט SS58, לא hex.
  • address הוא Balance, לא u128. אבל בפועל אין הבדל.

בחירת ה-parachain המתאים לפריסה

לא כל ה-parachains של Polkadot תומכים ישירות בחוזים חכמים. עבור חוזי ink! צריך parachains עם uint256 מופעל. להלן השוואה של אפשרויות פופולריות:

Parachain סוג תמיכה ב-ink! תכונות
Astar Wasm+EVM כן האקוסיסטם הגדול ביותר, קריאות בין-VM דרך XVM
Phala Wasm כן חוזים חסויים דרך TEE
Aleph Zero Wasm+EVM כן תפוקה גבוהה, שווקי NFT
Rococo (testnet) testnet כן ברז חינמי, אידיאלי לבדיקות

לפריסה יעילה של חוזים חכמים ב-ink! על Polkadot, אנחנו ממליצים על Astar — הוא הבוגר ביותר, תומך גם ב-Wasm וגם ב-EVM, ויש לו תשתית עשירה.

כלים: cargo-contract

cargo install cargo-contract --force
cargo contract new my_contract
cd my_contract
# Сборка: генерирует .contract, .wasm, .json (ABI)
cargo contract build --release
# Запуск тестов
cargo test

קובץ ה-pallet-contracts הוא ארכיון המכיל קוד bytecode של WASM ומטא-דאטה. את זה אנחנו פורסים.

סביבות פריסה ובדיקה

בדיקה מקומית: substrate-contracts-node

substrate-contracts-node --dev --tmp 

מפעיל רשת עם צומת יחיד וחשבונות ממומנים מראש (Alice, Bob, Charlie — כמו Hardhat cargo install cargo-contract --force cargo contract new my_contract cd my_contract # Сборка: генерирует .contract, .wasm, .json (ABI) cargo contract build --release # Запуск тестов cargo test ). השתמשו ב-Contracts UI ב-contracts-ui.substrate.io או באופן פרוגרמטי דרך .contract.

Testnet: Contracts on Rococo

Rococo הוא testnet של Polkadot עם parachain ייעודי substrate-contracts-node --dev --tmp לבדיקת ink!. ברז: paritytech.github.io/polkadot-testnet-faucet.

ייצור: Astar Network

Astar הוא ה-parachain הבוגר ביותר עם accounts[0] באקוסיסטם של Polkadot. הוא תומך גם בחוזי ink! (Wasm) וגם בחוזי EVM (Solidity) באותה רשת, עם קריאות בין-VM דרך XVM. עבור רוב מקרי השימוש בייצור על Polkadot, אנחנו פורסים ל-Astar.

פריסה דרך polkadot.js

import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';
import { CodePromise } from '@polkadot/api-contract';
import * as fs from 'fs';

async function deploy() {
    const provider = new WsProvider('wss://rpc.astar.network');
    const api = await ApiPromise.create({ provider });
    const keyring = new Keyring({ type: 'sr25519' });
    const deployer = keyring.addFromUri(process.env.MNEMONIC!);
    const wasm = fs.readFileSync('./target/ink/vault.wasm');
    const abi = JSON.parse(fs.readFileSync('./target/ink/vault.json', 'utf8'));
    const code = new CodePromise(api, abi, wasm);
    const gasLimit = api.registry.createType('WeightV2', {
        refTime: 30_000_000_000n,
        proofSize: 1_000_000n,
    });
    const storageDepositLimit = null; // автоматически
    const tx = code.tx.new({ gasLimit, storageDepositLimit });
    await new Promise<void>((resolve, reject) => {
        tx.signAndSend(deployer, ({ contract, status }) => {
            if (status.isInBlock) {
                console.log('Contract address:', contract?.address.toString());
                resolve();
            }
        }).catch(reject);
    });
    await api.disconnect();
}

מודל גז: WeightV2

בניגוד ל-EVM שבו גז הוא מספר יחיד, Substrate משתמש במשקל דו-ממדי:

  • @polkadot/api — זמן חישוב (פיקושניות)
  • contracts — גודל הוכחת האחסון עבור לקוחות קלים

בעת פריסה, צריך להעריך את שני הפרמטרים. שיטה: dry run (pallet-contracts עם import { ApiPromise, WsProvider, Keyring } from '@polkadot/api'; import { CodePromise } from '@polkadot/api-contract'; import * as fs from 'fs'; async function deploy() { const provider = new WsProvider('wss://rpc.astar.network'); const api = await ApiPromise.create({ provider }); const keyring = new Keyring({ type: 'sr25519' }); const deployer = keyring.addFromUri(process.env.MNEMONIC!); const wasm = fs.readFileSync('./target/ink/vault.wasm'); const abi = JSON.parse(fs.readFileSync('./target/ink/vault.json', 'utf8')); const code = new CodePromise(api, abi, wasm); const gasLimit = api.registry.createType('WeightV2', { refTime: 30_000_000_000n, proofSize: 1_000_000n, }); const storageDepositLimit = null; // автоматически const tx = code.tx.new({ gasLimit, storageDepositLimit }); await new Promise<void>((resolve, reject) => { tx.signAndSend(deployer, ({ contract, status }) => { if (status.isInBlock) { console.log('Contract address:', contract?.address.toString()); resolve(); } }).catch(reject); }); await api.disconnect(); } ) או שימוש ב-cargo-contract:

cargo contract instantiate --dry-run \ --constructor new \ --args \ --suri //Alice \ --url ws://127.0.0.1:9944 

פיקדון אחסון

refTime דורש פיקדון עבור האחסון התפוס — מקביל ל-EIP-1153 transient storage, אבל קבוע. העלות פרופורציונלית לבתים המאוחסנים על ידי החוזה. כאשר האחסון נמחק (דרך proofSize), הפיקדון מוחזר. זה חשוב עבור חוזים ארוכי טווח עם מצב גדול. בפועל, פיקדון האחסון עבור חוזה טיפוסי הוא חלק קטן מעלות הפריסה, שהיא נמוכה משמעותית מאשר ב-EVM parachains.

טעויות נפוצות בהעברה מ-EVM

דפוס EVM פתרון ב-ink!
contracts.instantiate מונה נפרד או estimateGas: true
cargo contract instantiate --dry-run \ --constructor new \ --args \ --suri //Alice \ --url ws://127.0.0.1:9944 pallet-contracts (u64, מילישניות)
ink::env::set_contract_storage::<K, ()>(&key, &()) mapping.length()
Vec כברירת מחדל תכונה מפורשת block.timestamp
אירועים עם self.env().block_timestamp() msg.sender על שדה האירוע
self.env().caller() payable או #[ink(message, payable)]

קריאות בין-חוזים ב-ink! דורשות ייבוא של ה-ABI של החוזה הנקרא וציון מפורש של מגבלת הגז — אין העברה אוטומטית כמו indexed של Solidity.

שלבי פריסה

  1. ניתוח דרישות — לימוד לוגיקת החוזה, בחירת parachain.
  2. כתיבת החוזה — מימוש ב-ink! תוך התחשבות באבטחה ואופטימיזציית גז.
  3. בדיקות — מקומיות (substrate-contracts-node) ועל Rococo.
  4. ביקורת אבטחה — שילוב של Slither עבור ink! וביקורת ידנית.
  5. פריסה לייצור — השקה על Astar או parachain אחר.
  6. תמיכה — ניטור, עדכונים, סיוע למשתמשים.

מה כלול בעבודה

  • מחזור מלא מרעיון ועד פריסה.
  • קוד מקור עם הערות מפורטות.
  • תיעוד חוזה (white paper, מפרט טכני).
  • דוח בדיקות (תוצאות unit test ו-fuzzing).
  • גישה לחוזה והוראות אינטראקציה.
  • חודש של תמיכה טכנית לאחר הפריסה.
רשימת בדיקה מפורטת לפני פריסה
  • ה-parachain נבחר (Astar/Phala/Aleph Zero)
  • החוזה נבנה (#[ink(topic)])
  • בדיקות unit עברו (require(cond, "msg"))
  • Fuzzing עבר (Echidna או מותאם אישית)
  • המשקל הוערך: assert!
  • פיקדון האחסון חושב ומומן
  • בדיקה על Rococo עברה
  • לחשבון הפורס יש מספיק כספים לפריסה

הצוות שלנו מורכב ממומחי Parity Substrate מוסמכים עם ניסיון של 5+ שנים ב-Rust ופיתוח בלוקצ'יין. אנחנו מבטיחים תוצאות: 15+ פריסות מוצלחות על Kusama ו-Polkadot. לפרטים נוספים על חוזים חכמים ב-Substrate, עיינו ב-תיעוד Substrate הרשמי.

צרו קשר להערכת פרויקט. הזמינו פריסת turnkey — נטפל בכל המחזור מניתוח ועד תמיכה. נעריך את הפרויקט שלכם וניתן לוחות זמנים מדויקים (משבועיים עד חודשיים, תלוי במורכבות).