MetaMask Snapsは、MetaMaskを世界で最も拡張性の高いウォレットにするためのロードマップです。開発者として、まったく新しい方法でMetaMaskに機能やAPIを追加することができます。Web3開発者はこの成長の中核を担っており、このシリーズでは現在開発中の革新的なMetaMask Snapsを紹介することを目的としています。
PiotrとMichaelによるAleph Zero Snap
ETHWarsawハッカソンでAleph Zero Snapを構築したWeb3開発者のPiotrとMichaelにお話を伺いました。
Snap リポジトリ: https://github.com/piotr-roslaniec/ethwarsaw-2022/tree/main/azero-snap/packages/snap-adapter
なぜ構築したのですか?
私たちの見解では、Polkadotエコシステムにおけるウォレット体験はまだ十分ではありません。一方で、MetaMask Snapsとの統合により、既存のweb3ユーザーをAleph Zeroネットワークへ誘導できると考えました。
技術的な実装について説明していただけますか?
アダプター
私たちのSnapは2つのパーツで構成されています。1つ目はユーザーが操作するウェブサイト、2つ目は実際のSnapです。この2つの要素は、Snapがサーバー、ウェブサイトがクライアントとなるクライアント・サーバーアーキテクチャに似た形で機能します。この自然な境界を反映するため、Snap APIをadapterという名前の独立したパッケージとして切り出しました。これにより、ウェブサイトがSnapと連携するために使用できるすべてのメソッドが公開されます。このような抽象化レイヤーにより、他のクライアント(ウェブサイト)からのSnapの利用が容易になります。私たちのAPIは4つのメソッドで説明でき、その名前は非常に直感的です。詳しく知りたい方は、完全なコードをご覧ください。
export const getAccountFromSeed = async (seed: string): Promise<PublicAccount> => {
return await requestSnap("getAccountFromSeed", [seed]);
}
export const generateNewAccount = async (): Promise<PublicAccount> => {
return await requestSnap("generateNewAccount", []);
}
export const signTransaction = async (transaction: SignerPayloadJSON): Promise<{ signature: string }> => {
return await requestSnap("signTransaction", [transaction as unknown as string]);
}
export const getAccounts = async (): Promise<string[]> => {
return await requestSnap("getAccounts", []);
}
アプリ
各レイヤー間の接着剤について説明しましたので、次は第1レイヤーであるウェブサイトに移りましょう。私たちは公式のブラウザベースのpolkadot appをフォークしました。その後、トランザクションの署名、アカウントの作成や復元といったコア機能を、ブラウザベースのウォレットからSnapベースのものに置き換える必要がありました。例えば、MetaMask内でトランザクションに署名するために、QrSignerの実装をSnapのsignTransactionを使用するように変更しました。
MetaMask SnapをPolkadot appに統合することで、2つの改善がもたらされました:
まず、ローカルストレージをベースとするPolkadot appのウォレットの代わりに、MetaMask拡張機能のセキュリティモデルを継承できるようになりました。
次に、MetaMaskのシードを使用してPolkadot appを決定論的な方法で作成できるようになり、シードをエクスポートする際にAleph Zeroのキーも同時にエクスポートされるようになりました。
MetaMask API
MetaMaskは、ユーザーの許可があればMetaMask Snapsが使用できるAPIコールを提供しています。今回は以下の2つを活用しました:
snap_manageState - MetaMaskの内部に暗号化されたデータを保存できます。例えば、作成したアカウントの保存に使用しています。状態との連携は非常に簡単で、以下のように簡略化できます:
const request = async (method: 'clear' | 'get' | 'update', newState?: unknown): Promise<any> => {
if (['get', 'clear'].includes(method) && newState) {
throw new Error(`Cannot ${method} with newState`);
}
if (method == 'update' && !newState) {
throw new Error('Cannot call update without newState');
}
const params = newState ? [method, newState] : [method];
return await wallet.request({
method: `snap_manageState`,
params,
});
}
snap_getBip44Entropy_ - MetaMaskのシードからエントロピーを取得します。ドキュメント
MetaMaskにはpassworderという非常に優れたライブラリがあり、状態の暗号化・復号化を簡単に行えることも特筆に値します。今回は、状態を暗号化するための対称鍵として、再びMetaMaskシードのエントロピーを使用しました。
SDK
まとめると、私たちはPolkadot appにJavaScriptを随所に注入してハックし、Snapの使用を可能にしました。SnapはMetaMask内のシードからエントロピーを取得し、暗号化された状態を管理できます。最後のステップは、Aleph Zero用のSDKであるpolkadotjsとの統合です。
一見簡単な作業に思えます。npm install @polkadot/apiを実行してインポートするだけです。しかし、Snapへの依存関係のインポートは難しい場合があります。この困難が生じるのは、SnapがJavaScript仮想マシン上で直接評価されるのではなく、まずSecure ECMAScript(SES)内でサンドボックス化される必要があるためです。簡単に言うと、通常は問題なくコンパイルされるコードが、SESでのロード時に失敗する可能性があります。
コード
ほとんどのライブラリでは問題は発生しませんが、私たちの場合はそうではありませんでした。SES内でpolkadotjs SDKを評価する際に2つの問題が発生し、それを解決するためにバンドルされたソースコードに対して実行する2つのスクリプトを作成しました。
1つ目の問題は、JavaScriptファイル内に埋め込まれたwasmコードのフォーマットが不正であることが原因でした。修正スクリプトはこちらです:
const fs = require('fs').promises;
const path = require('path');
const dirPath =
'../../../../node_modules/@substrate/smoldot-light/dist/cjs/instance/autogen';
async function fixDoubleSlash() {
const files = ['wasm0.js', 'wasm1.js', 'wasm2.js'];
for (const file of files) {
console.log('Fixing ${file}');
const filePath = path.join(__dirname, dirPath, file);
const contents = await fs.readFile(filePath, 'utf8');
let fixedContents = contents;
while (fixedContents.includes('//')) {
fixedContents = fixedContents.split('//').join('/"+"/');
}
await fs.writeFile(filePath, fixedContents);
}
}
fixDoubleSlash();
2つ目の問題も、SESで禁止されているwindow.addEventListenerメソッドにアクセスしようとするPolkadot拡張機能が原因でした。こちらも以下のシンプルな方法で簡単に解決できました:
const fs = require('fs').promises;
const path = require('path');
const bundlePath = path.join(__dirname, '../dist/bundle.js');
async function fix() {
console.log(`Fixing ${bundlePath}`);
const contents = await fs.readFile(bundlePath, 'utf8');
const replaceMissingTypes = '\n\nwindow.addEventListener = function(){};\n\n';
const fixed = contents.replace('\n\n', replaceMissingTypes);
await fs.writeFile(bundlePath, fixed);
}
fix();
今後このSnapを実装するとしたら、次のステップは何ですか?
私たちのSnapをpolkadot.jsと完全に互換性を持たせ、Polkadotエコシステムにおけるウェブウォレットとして実用的なものにしたいと考えています。
あなたとチームについて少し教えていただけますか?
Michaelはポーランドの銀行でプログラマーとして働き、日常的にブロックチェーン技術に携わっています。プログラミングと新しいことを学ぶことが大好きです。
PiotrはソフトウェアエンジニアとしてNuCypherで働いています。プライバシー、データ、分散システムに興味を持っています。
MetaMask Snapsを初めて知ったのはいつで、どのような体験でしたか?
Piotr - 大阪で開催されたDevconでMetaMask Snapsについて初めて知りました。その後、EthDenverハッカソンの少し前に再び話題になりました。
Michaeł - EthDenverの直後に、PiotrからMetaMask Snapsを紹介してもらいました。
MetaMask Snapsが他のウォレットと異なる点は何ですか?
dapp内でアプリケーション固有の暗号技術/秘密鍵にアクセスできる機能です。これにより、使い慣れたブラウザウォレット体験の上に新しいユーザーフローを構築することが可能になります。
MetaMask Snapsの構築はあなたとチームにとってどのような体験ですか?
基本的な部分は整っていますが、特にカスタムUI要素を必要とする高度なMetaMask Snapsの構築は難しいです。ウェブ開発者としての経験をSnapsに落とし込む方法、例えばデプロイやテストなどを理解するのに多くの時間を費やしました。
MetaMask Snapsはあなたにとって何を意味しますか?
コミュニティに真の力を与えるツールです。誰もが自分のMetaMaskにどのような機能を持たせるかを自分で決められます。プラグインにより開発の民主化が実現し、より速い成長が可能になります。
MetaMask SnapsがWeb3空間にもたらす可能性と機会についてどのようにお考えですか?
より多くのネットワーク(特に非EVMのもの)へのアクセス、トランザクションのライフサイクルに介入してカスタムロジック(安全性チェックなど)を追加したりUXをカスタマイズする機能、dapp固有の機密コンテンツのためのブラウザ内暗号化ストレージ、そしてMetaMask Snapsを通じてユーザーに「独自の暗号技術を持ち込む」機能などが挙げられます。
MetaMask Snapsを試したい開発者へのアドバイスはありますか?
SES内でJSライブラリをコンパイルするのは難しい場合がありますが、私たちの経験上、不可能ではありません。MetaMask開発のフィードバックループはかなり長いので、ユニットテストを必ず書くようにしてください。
MetaMask Snapsには小規模ながら活発な開発者コミュニティがあります。Discord、GitHubのディスカッションなどを訪れることは非常に有益です。特にこのプロダクトはまだ新しく、このコミュニティの外では利用できる情報が少ないため、なおさらです。
MetaMask Snapsで構築する
MetaMask Snapsを始めるには:
開発者ドキュメントをご確認ください
MetaMask Flaskをインストールしてください
MetaMask Snapsガイドをご覧ください
Twitter、GitHubディスカッション、Discordで私たちとつながり続けてください
お近くで開催される次のハッカソンでも私たちのチームにご注目ください!Happy BUIDLing ⚒️
免責事項:MetaMask Snapsは一般的に、Consensys Software以外のサードパーティによって開発されています。サードパーティが開発したMetaMask Snapsの使用は、お客様自身の判断とリスクのもとで行われ、そのような活動から生じる損失や損害についてはお客様が単独で責任を負うことに同意したものとみなされます。Consensysはサードパーティが開発したMetaMask Snapsについて、口頭または書面による明示的または黙示的な保証を一切行わず、サードパーティが開発したMetaMask Snapsに関するすべての責任を否認します。ブロックチェーン関連ソフトウェアの使用にはリスクが伴い、MetaMask Snapsを使用する際にはそのリスクをすべて自己負担するものとします。