見出し画像

【翻訳】Cross-Virtual Machine: Creating a Portal to the Future of Smart Contracts

前置き

この記事は、Astar Networkの公式Mediumに投稿された記事を翻訳したものです。XVMは、EVMとWASMの複数の実行環境を横断してアプリケーションを作ることを可能とする新しいシステムです。現在主流のEVMと、これから来るといわれているWASM、両方のスマートコントラクトを橋渡しできるため、Astarのエコシステムとってはかなり重要な要素だと考えられます。

その機能が、ついにTestnetで使用可能になりました。また、Portal内でも使用できるように開発中であり、PolkadotのウォレットからEVMのトークンを動かすことが出来るようになります。アプリケーションが拡張されていくと、1つのウォレットからEVMやWASMのアプリケーションを動かせるようになるため、かなり便利になります。

また、XVMにより将来的にAstarのWASM/EVM関係なくXCMPやCeler IMなどを利用してCross-chainのトランザクションが可能になります。

非常に楽しみですね!

原文



翻訳本文

Introduction

2022年はいろいろなことがありました。Web3業界全体が技術的な成果を上げ、現実の課題を解決し、今までにない産業を生み出す土壌となりました。もちろん、業界が学び、改善すべき事件や出来事も多くありました。2022年のWeb3業界は、まさに「激動」のうちに幕を閉じたと言えるでしょう。

しかし、技術は成長するものであり、こうした出来事を経験することで、何が有効で何が有効でないかをビルダーは知ることができるのです。

Astar Foundationでは、今起きている外部からの影響に左右されることなく、未来の基盤を作るために努力を続けてきました。そして今日、Astar Visionを実現するための最も重要な機能の1つであるXVM(Cross-Virtual Machine)を紹介できることを誇りに思います。本記事では、Web3におけるスマートコントラクトの役割、dApp開発を進める上での課題、XVMを作った理由、XVMの仕組み、そして最後に、未来に向けた展望を紹介します。

WASM Smart Contract VMs

WebAssembly(WASM)とは、WASMのバイトコードを解釈するためにWebAssembly仮想マシンが読むことができるメッセージ形式のことです。厳密には、WASMは仮想環境でシステムと通信するために高級言語からコンパイルされるメッセージ形式を指します。しかし、わかりやすくするために、この記事でWASMと言った場合、バイナリとしてのWASMとブロックチェーンにおける仮想マシンの両方を指すことにします。

WASMはもともと、システムレベル言語からコンパイルされたバイナリをブラウザで利用し、Webアプリケーションのネイティブに近いパフォーマンスを実現するためのものでした。しかし、WASMのポータビリティのおかげで、これはブラウザ以外でも実行できるようになりました。

WASMのVMはEthereum Virtual Machine(EVM)のようなスタックベースのVMであるため、WASMのバイナリにコンパイルされていれば、スマートコントラクトの実行環境を構築することが可能です。EVMとは異なり、WASMを通じて、Rust、Go、C++など、WASMをターゲットにできる言語で書かれたスマートコントラクトを実行するブロックチェーンを作ることが可能で、これらはすべて型安全性と適切なエラー処理をサポートしています。

さらに、WASMをネイティブにコンパイルできる主要な言語は、その構文で非同期関数をサポートしているので、WASMスマートコントラクトに非同期性を導入することが可能です。相互運用性については、レスポンスがわからないままやみくもにメッセージを送信するのではなく、スマートコントラクト内でクロスチェーン関数を扱えるようになったということです。EVMとSolidityがこの部門で欠けていることを考えると、これはDeFi以外の業界レベルの、クロスチェーンのネイティブアプリケーションを作る上で大きな意味を持ちます。多くの要因から、WASMはスマートコントラクトの未来と言えます。しかし、EVMとの互換性の問題から、ブロックチェーン技術の大量導入は困難になっています。

The Motivation Behind XVM

技術的に言えば、WASMベースのスマートコントラクトが良いということは、誰もが知っていることです。しかし、EVMが支配的な世界でWASMスマートコントラクトを採用する場合、大きな課題があります。ほとんどのチームは、リッチなEVMエコシステムに慣れすぎています。ほとんどのWASM VMエコシステムは小さく、あまりにも異質なため、多くの既存プロジェクトはWASMスマートコントラクトをゼロから学習するメリットを見出せず、EVMエコシステムへのアクセスを犠牲にしています。

私たちは、この典型的な問題を解決するためにXVMを作りました。

Plasmから私たちを知っている人は、私たちが常にWASMのスマートコントラクトにフォーカスしたネットワークであったことを思い出すかもしれません。しかし、Astarを立ち上げたとき、コントラクトパレットではなくEVMで立ち上げました。これは、エコシステムを起動させ、より広いオーディエンスにプラットフォームを提供するためでした。しかし、私たちは常にWASMスマートコントラクトをより広いエコシステムに取り込むことを計画していました。そこで、XVMのアイデアが始まりました。

XVMは、ある仮想マシン内のスマートコントラクトが、あたかも同じ環境にあるかのように別の仮想マシンと通信することを可能にするカスタムパレットとインターフェースのセットです。つまり、XVMを使えば、ink!のスマートコントラクトを作成し、EVM側で利用できるあらゆるアセットやコントラクトにアクセスすることができるのです。さらに、AstarのEVMがAxelarやCelerといった別のレイヤー0に接続されている場合、AxelarやCelerに接続されているすべてのEVMチェーンにアクセスできるinkスマートコントラクトを作成することができるのです!

これによって可能性は無限に広がり、XVMがビルダーに対して、大規模なEVMエコシステムと相互作用しないという犠牲を払うことなく、革新的なdApps開発の促進を期待しています。

The Mechanisms of XVM

では、XVMはどのように動作するのでしょうか?実際の仕組みはとてもシンプルで、エンコードされた呼び出しを配列として受け取り(SCALEコーデックにヒントを得た)、それをXVMパレットへの引数として渡します。

The Architecture

以下は、XVMの背後にあるアーキテクチャと、他のVMとの接続方法です。

XVM Architecture

私たちのスマートコントラクトの各VMは、他の環境のスマートコントラクトがそれらを使用できるように、XVMモジュールを公開する方法を持つことになります。XVMパレット関数を公開する各VMの関数を作成します。例えば、コントラクトパレットにはチェーンエクステンションがあり、EVM側にはプリコンパイルされたコントラクトがあります。一方のVM側に展開されたスマートコントラクトは、チェーンエクステンションまたはプリコンパイルされたコントラクトへのエンコードされたcallを送信することで、他方のVMと相互作用することができます。XVM関数が呼び出されると、パレットはターゲットVMのアダプタを呼び出し、function callをターゲットのスマートコントラクトに渡します。ブロックチェーンの観点からは、このトランザクションの行は単一のブロックの一部となり、完全な取引になります。これがXVM callの方法です。

Using XVM

XVM callの基本的な動作が分かったところで、スマートコントラクト開発者の観点からそれがどのように動作するかを説明します。最初のユースケースは、ink!開発者がEVM空間のアセットにアクセスすることなので、このセクションでは、ink!コントラクトからXVMを使用することに主に焦点を当てます。しかし、EVM上のSolidityコントラクトにも同じ原則が適用されることに注意してください。

SolidityコントラクトにXVM callを行うために必要なのは、スマートコントラクトのH160 EVMアドレス、関数セレクタ、関数に渡すエンコードされた引数だけです。

話はここまでにして、実際のコードを見てみましょう。

※ここから何回かコードが出現しますが、noteのコードブロックは読みづらいため、Mediumの方で読むことを推奨します。
コードよくわからない人は、しばらく飛ばしても良いと思います。

//! ERC721 EVM contract interoperability using XVM interface.
#![cfg_attr(not(feature = "std"), no_std)]

pub use self::erc721::{
    Erc721,
    Erc721Ref,
};
use ink_lang as ink;

/// EVM ID (from astar runtime)
const EVM_ID: u8 = 0x0F;

/// The EVM ERC721 delegation contract.
#[ink::contract(env = xvm_environment::XvmDefaultEnvironment)]
mod erc721 {
    const APPROVE_SELECTOR: [u8; 4] = hex!["095ea7b3"];
    const TRANSFER_FROM_SELECTOR: [u8; 4] = hex!["23b872dd"];
    const MINT_SELECTOR: [u8; 4] = hex!["40c10f19"];

    use ethabi::{
        ethereum_types::{
            H160,
            U256,
        },
        Token,
    };
    use hex_literal::hex;
    use ink_prelude::vec::Vec;

    #[ink(storage)]
    pub struct Erc721 {
        evm_address: [u8; 20],
    }

    impl Erc721 {
        /// Create new ERC721 abstraction from given contract address.
        #[ink(constructor)]
        pub fn new(evm_address: [u8; 20]) -> Self {
            Self { evm_address }
        }

        #[ink(message)]
        pub fn transfer_from(&mut self, from: [u8; 20], to: [u8; 20], token_id: u128) -> bool {
            let encoded_input = Self::transfer_from_encode(from.into(), to.into(), token_id.into());
            self.env()
                .extension()
                .xvm_call(
                    super::EVM_ID,
                    Vec::from(self.evm_address.as_ref()),
                    encoded_input,
                )
                .is_ok()
        }

        #[ink(message)]
        pub fn approve(&mut self, to: [u8; 20], token_id: u128) -> bool {
            let encoded_input = Self::approve_encode(to.into(), token_id.into());
            self.env()
                .extension()
                .xvm_call(
                    super::EVM_ID,
                    Vec::from(self.evm_address.as_ref()),
                    encoded_input,
                )
                .is_ok()
        }

        #[ink(message)]
        pub fn mint(&mut self, to: [u8; 20], token_id: u128) -> bool {
            let encoded_input = Self::mint_encode(to.into(), token_id.into());
            self.env()
                .extension()
                .xvm_call(
                    super::EVM_ID,
                    Vec::from(self.evm_address.as_ref()),
                    encoded_input,
                )
                .is_ok()
        }

        fn transfer_from_encode(from: H160, to: H160, token_id: U256) -> Vec<u8> {
            let mut encoded = TRANSFER_FROM_SELECTOR.to_vec();
            let input = [
                Token::Address(from),
                Token::Address(to),
                Token::Uint(token_id),
            ];
            encoded.extend(&ethabi::encode(&input));
            encoded
        }

        fn approve_encode(to: H160, token_id: U256) -> Vec<u8> {
            let mut encoded = APPROVE_SELECTOR.to_vec();
            let input = [Token::Address(to), Token::Uint(token_id)];
            encoded.extend(&ethabi::encode(&input));
            encoded
        }

        fn mint_encode(to: H160, token_id: U256) -> Vec<u8> {
            let mut encoded = MINT_SELECTOR.to_vec();
            let input = [Token::Address(to), Token::Uint(token_id)];
            encoded.extend(&ethabi::encode(&input));
            encoded
        }
    }
}

これは、XVMを使用してEVM環境でERC721 Solidityコントラクトを制御することができるink!スマートコントラクトです。これは、XVM SDKコントラクトリポジトリから直接取得したものです。コントラクト自体は大したものではないことがわかりますが、これを少し詳しく見ていきましょう。

/// EVM ID (from astar runtime)
const EVM_ID: u8 = 0x0F;

/// The EVM ERC721 delegation contract.
#[ink::contract(env = xvm_environment::XvmDefaultEnvironment)]
mod erc721 {
    const APPROVE_SELECTOR: [u8; 4] = hex!["095ea7b3"];
    const TRANSFER_FROM_SELECTOR: [u8; 4] = hex!["23b872dd"];
    const MINT_SELECTOR: [u8; 4] = hex!["40c10f19"];

EVM_IDはVMのIDを指し、XVMがこのコントラクトがどのVMをターゲットにするかを理解するために必要です。IDなので、XVMを拡張して、いくつものスマートコントラクトVMをサポートし、それらが互いに通信できるようにすることができます。

スニペットの後半は、このコントラクトが使用する関数セレクタを定数として定義しています。

    #[ink(storage)]
    pub struct Erc721 {
        evm_address: [u8; 20],
    }

    impl Erc721 {
        /// Create new ERC721 abstraction from given contract address.
        #[ink(constructor)]
        pub fn new(evm_address: [u8; 20]) -> Self {
            Self { evm_address }
        }

次の部分では、メッセージの送信先であるH160アドレス([u8; 20]は20byte長の配列という意味で、160bitであることに注意してください)を定義しています。この例では、コンストラクタで展開時にアドレスを定義するようにしていますが、有効なEVMアドレスがある限り、この動作は完全にカスタマイズ可能です。

        #[ink(message)]
        pub fn transfer_from(&mut self, from: [u8; 20], to: [u8; 20], token_id: u128) -> bool {
            let encoded_input = Self::transfer_from_encode(from.into(), to.into(), token_id.into());
            self.env()
                .extension()
                .xvm_call(
                    super::EVM_ID,
                    Vec::from(self.evm_address.as_ref()),
                    encoded_input,
                )
                .is_ok()
        }

        #[ink(message)]
        pub fn approve(&mut self, to: [u8; 20], token_id: u128) -> bool {
            let encoded_input = Self::approve_encode(to.into(), token_id.into());
            self.env()
                .extension()
                .xvm_call(
                    super::EVM_ID,
                    Vec::from(self.evm_address.as_ref()),
                    encoded_input,
                )
                .is_ok()
        }

        #[ink(message)]
        pub fn mint(&mut self, to: [u8; 20], token_id: u128) -> bool {
            let encoded_input = Self::mint_encode(to.into(), token_id.into());
            self.env()
                .extension()
                .xvm_call(
                    super::EVM_ID,
                    Vec::from(self.evm_address.as_ref()),
                    encoded_input,
                )
                .is_ok()
        }

次のセクションでは、クライアントが相互作用する呼び出し可能なパブリックコントラクト関数を宣言しています。この関数は、コントラクトがチェーンエクステンションを経由してXVMパレットを呼び出すところです。

            self.env()
                .extension()
                .xvm_call(
                    super::EVM_ID,
                    Vec::from(self.evm_address.as_ref()),
                    encoded_input,
                )
                .is_ok()

XVMの引数は、単純明快です。VM ID、対話したいコントラクトのアドレス、そしてそのセレクタを含む関数のエンコードされた引数を渡します。その後、XVMパレットはEVM側でコントラクトへの呼び出しを行います。しかし、エンコーディングはどのように行われるのでしょうか?

        fn transfer_from_encode(from: H160, to: H160, token_id: U256) -> Vec<u8> {
            let mut encoded = TRANSFER_FROM_SELECTOR.to_vec();
            let input = [
                Token::Address(from),
                Token::Address(to),
                Token::Uint(token_id),
            ];
            encoded.extend(&ethabi::encode(&input));
            encoded
        }

        fn approve_encode(to: H160, token_id: U256) -> Vec<u8> {
            let mut encoded = APPROVE_SELECTOR.to_vec();
            let input = [Token::Address(to), Token::Uint(token_id)];
            encoded.extend(&ethabi::encode(&input));
            encoded
        }

        fn mint_encode(to: H160, token_id: U256) -> Vec<u8> {
            let mut encoded = MINT_SELECTOR.to_vec();
            let input = [Token::Address(to), Token::Uint(token_id)];
            encoded.extend(&ethabi::encode(&input));
            encoded
        }

コードの最後のセクションでは、すべてのエンコードが処理されます。エンコードスキームは、ethabi Rustライブラリを介してエンコードされた引数の配列で関数セレクタを追加していることがわかります。

Try it Now

XVMは現在、公開テストネットのShibuyaで利用可能です! この最新機能はすぐにでも試すことができます。また、XVMを使いたい開発者のために、ブートストラップ用のリポジトリもいくつか用意しました。

Ink! XVM SDK

前のセクションで説明した通り、スマートコントラクトからXVMを使用するのは簡単です。しかし、開発プロセスをさらに簡単にするために、EVMとWASM VMのでよく使われるインターフェース用としてXVM SDKを用意しました。

ERC20、ERC721などを制御できるink!コントラクトを作成するために、ink! XVM SDKレポジトリをご覧ください。コミュニティの助けを借りて、SDKを拡張してより多くのインターフェースをサポートし、SolidityやAsk!用のSDKを作成し、XVMを活用できるサンプルdAppsを作成することができます。

Sub0 XVM Workshop dApp

フルスタックdAppで動作するXVMの詳細を知りたい場合は、Sub 0 XVM Workshopリポジトリを参照してください。Sub 0 XVM Workshopリポジトリは、Sub 0で初めてXVMの機能を公開するために使用したプロジェクトのものです。このシンプルなdAppは、EVMとSubstrateネイティブ両方の署名者からERC 20トークンを制御する方法を示しています。XVMについてのAstar Tech Talkでも確認できます。

Applications

XVMのシンプルさにもかかわらず、EVMからWASM VMへの流動性のブリッジ以上の、多くの潜在的なアプリケーションを作成できます。XVMを使えば、異なる環境に存在する資産の所有権を、異なるアカウント方式から証明することができます(例:Polkadot-jsウォレットのみを使用してEVM ERC20トークンの所有権移行を行う場合)。つまり、すべてのアセットを管理するために、環境ごとに新しいウォレットを作成する必要がないのです。単一の署名者でユニバーサルなアセットコントローラーを作ることができるのです。

例えば、現在多くのNFTマーケットプレイスでは、MetaMaskのようなEVMの署名しか認められていません。例外はKusamaのSingularです。そのため、Polkadot-jsを使ったERC721 NFTや、MetaMaskを使ったRMRK NFTの取引やオークションはできません。XVMを使えば、それぞれの署名がEVMとWASMの両方のVM上であらゆるNFT規格の所有権を扱い、譲渡できるようにすることで、この問題を解決することができるのです。より広範なUXの機会を可能にします。つまり、ユーザーはお気に入りのウォレットインターフェースを離れることなく、複数のマーケットプレイスでさまざまな種類のNFTを探索することができるのです。

他のアプリケーションはクロスチェーン dApps を介しており、XVM と同じエンコーディング スキームを採用しています。 Polkadot の XCMP のような安全なCross-consensus message-passing protocolがあれば、Astar Network を通じて、dApps は Solana や Near のような完全に外部の環境でスマート コントラクトと対話できます。

XVM に関しては無限の可能性があります。これにより、将来のスマート コントラクトが、記述されている言語や使用する環境/RPCに関係なくシームレスに機能することを期待できます。

The Future

現在、XVMはv2であり、v3の作成に取り組んでいます。v2の制限の1つは、XVMストレージのクエリとエラーメッセージがないことです。スマートコントラクトと対話するとき、開発者はアプリケーションロジックの一部として、アカウントが保有するERC20トークンの量など特定の値をクエリすることを期待しています。v3では、スマートコントラクトが別の環境からスマートコントラクトのストレージ値を読み取ることができるようにします。エラーメッセージと同様、開発者はトランザクションが成功したかどうかしかわかりません。しかし、改善されたエラーメッセージにより、プロジェクトが彼らのdAppのコーナーケースを適切に処理できるようになります。

XVMの将来的には、これをXCMPと統合し、Astar上のスマートコントラクトが、どのVMを使用しているかにかかわらず、他のParachain上のスマートコントラクトを呼び出せるようにしたいと考えています。これによって、開発者は真にクロスチェーンのネイティブなdAppを作ることができ、スマートコントラクトの機能を今までできなかったものにまで拡大することができます。

最後に、EVMとコントラクトパレットだけでは、マルチVMチェーンとは呼べません。将来的には、スマートコントラクトの非同期性をネイティブに処理できる別のVMを追加し、クロスチェーンの呼び出しを非同期関数として抽象化する予定です。このVMはXVMと互換性があり、Astar Network上のあらゆるdAppが、ユーザーに別のチェーンで別のアカウントを作らせたり、別のdAppをデプロイさせたりすることなく、クロスチェーン機能の能力を完全に活用できるようにします。

Closing

XVMを使えば、EVMが支配する従来のブロックチェーンエコシステムを融合する際に発生する問題を解消し、EVMが提供する広大なエコシステムへのアクセスを犠牲にすることなく、新しいパラダイムのdAppプロジェクトが我々のエコシステムに参入できることがおわかりいただけると思います。

WASMのスマートコントラクトにより、プロジェクトはシンプルな非同期関数で他のブロックチェーンにアクセスして使用することができ、プロジェクトはスマートコントラクトを開発する際にSolidityに欠けている型安全性を恐れる必要がなく、WASMの拡張言語機能により人材とプロジェクトの多様性を高めることができる未来が見えています。

また、XVMを通じて、プロジェクトはWASMで構築することで何が失われるかを心配することなく、エンドユーザーに価値をもたらすものの構築に集中することができるようになります。

Astar Networkは、あなたのイノベーションが始まる場所です。

About Astar

Astar Network - The Future of Smart Contracts for Multichain.

Astar Networkは、EVMおよびWASMスマートコントラクトによるdAppsの構築をサポートし、 Cross-consensus messaging(XCM)による真の相互運用性を開発者に提供します。Astar独自のBuild2Earnモデルは、開発者が自分のコードと構築したdAppに対して、dApp stakingメカニズムを通じて報酬を得ることを可能にします。

Astarの活気あるエコシステムは、すべての主要取引所とティア1 VCによってサポートされ、世界的にPolkadotの主要Parachainになっています。Astarは、開発者がdAppの構築を開始するために、すべてのEthereumとWASMのツールの柔軟性を提供します。PolkadotとKusama Networksでの成長を加速させるために、Astar SpaceLabsはトップTVL dAppsのためのインキュベーションハブを提供しています。

Website | Twitter | Discord | Telegram | GitHub | Reddit


この記事が気に入ったらサポートをしてみませんか?