MetaMask Snaps ist der Fahrplan, um MetaMask zur erweiterbarsten Wallet der Welt zu machen. Als Entwickler kannst du deine Features und APIs auf völlig neue Weise in MetaMask einbringen. Web3-Entwickler sind der Kern dieses Wachstums, und diese Serie soll die innovativen MetaMask Snaps vorstellen, die heute entwickelt werden.
CoinChoice Snap
Snap Repo: https://github.com/coinchoice/coinchoice/
Warum habt ihr es entwickelt?
CoinChoice entstand aus einem kleinen, mühsamen, aber weit verbreiteten Problem: Ein Web3-Nutzer besitzt möglicherweise eine Wallet mit wertvollen Token, aber keine Gas-Währung, um Transaktionen durchzuführen.
Dieses Problem tritt besonders bei Nutzern mit aufgeteilter Liquidität zutage. Ein Nutzer, der mehrere Wallets verwaltet und Möglichkeiten in verschiedenen Blockchain-Ökosystemen nutzt, muss seine Gas-Token auf jede seiner Wallets aufteilen und dabei Kapital reservieren, das eigentlich für Investitionen gedacht wäre, um seine digitalen Assets und Transaktionen zu ermöglichen. Über das Gas-Management hinaus erfordern Token, die in ein Netzwerk übertragen werden, in dem kein Gas vorhanden ist, dass der Nutzer zunächst Gas beschafft, bevor weitere Aktionen möglich sind. In der Regel bedeutet das, dass der Nutzer eine zentralisierte Börse aufsuchen muss, um Gas zu erhalten und abzuheben – was CEX-Auszahlungsgebühren mit sich bringt.
Im Kern ist diese Erfahrung fehlerhaft. Es sollte keine Abhängigkeit von zentralisierten Börsen geben, damit Nutzer auf Web3 zugreifen können. Nutzer sollten sich keine Gedanken über die Verwaltung ihres Gases machen müssen, sondern einfach mit dezentralisierten Systemen interagieren können. Das bedeutet nicht, dass Gas nicht erforderlich sein sollte. Gas erfüllt einen hervorragenden Zweck, indem es Betreiber eines Netzwerks belohnt und Spam/DDoS verhindert. Gas sollte einfach flexibler sein. Wenn ein dApp- oder Spieleentwickler einen nativen Token hat, sollte dieser Token als Währung zur Bezahlung von Gas ausreichen.
Mit dieser Philosophie im Hinterkopf wurde CoinChoice entwickelt.
CoinChoice läuft im Browser des Nutzers und ergänzt jede Transaktion mit der Möglichkeit, Gas in einer vom Nutzer gewünschten Währung zu verwalten. Wenn der Nutzer lieber USDC statt ETH hält, kann Gas in USDC bezahlt werden.
Der MetaMask Snap von CoinChoice ergänzt das Erlebnis zusätzlich. Direkt in der MetaMask Browser-Erweiterung können Nutzer ihr ETH im Austausch gegen ihre gewählte Gas-Währung aufstocken. Dadurch wird MetaMask zu einer Lösung, die den Besuch einer zentralisierten Börse ersetzt, das Web3-Erlebnis konsolidiert und vereinfacht und neuen Web3-Nutzern ermöglicht, sich mit einem Teil der Systeme vertraut zu machen, ohne von der wachsenden Fülle an Diensten und Plattformen überwältigt zu werden.
Erklärt uns die technische Umsetzung.
CoinChoice ist eine MetaMask- und Browser-Erweiterung, die dir die Wahl lässt, welche Coins zur Bezahlung von Gas verwendet werden.
Pakete
backend: Ein NestJS-Webserver, der für Folgendes zuständig ist: Simulation von Transaktionen gegen die Tenderly API und 0x Quote API zur Ermittlung von Gas-Schätzungen in der gewählten Währung
Empfang und Verteilung von Nachrichten zwischen dem MetaMask Snap und der Browser-Erweiterung des Clients
Empfang von Meta-Transaktionen zur Weiterleitung an Relayer-Contracts
browser-extension: Eine Browser-Erweiterung auf Basis des Plasmo Frameworks – fängt RPC-Anfragen an MetaMask ab, um Swaps zu ETH für die Gas-Finanzierung einzuschleusen
bietet ein Popup zur Auswahl der Gas-Coin
bietet ein Popup für das Token-Management, betrieben durch das Cypher Onboarding SDK
alle Daten werden an den Backend-Dienst übermittelt, wo Blockchain-Interaktionen und Simulationen verwaltet werden
contracts: Smart Contracts, die das Weiterleiten von Meta-Transaktionen ermöglichen, um Swaps auf dem 0x Protocol durchzuführen
frpc: Ein Paket zur Nutzung des fRPC Gateways des Fluence Network
meta-mask: Ein Paket, das eine React.js-Website und den zugehörigen MetaMask Snap enthält – der Snap ist dafür zuständig, ETH-Swaps direkt in der MetaMask-Oberfläche anzubieten, indem die Nachricht „Need ETH?" angezeigt wird
Der Snap funktioniert, indem er eine Anfrage an das Backend stellt, damit eine Nachricht an die Browser-Erweiterung des Clients weitergeleitet wird – so kann der MetaMask Snap die Browser-Erweiterung initiieren
Die zugehörige Website dient zur Installation des MetaMask Snaps
Technisches Setup
CoinChoice ist eine Browser-Erweiterung, die Transaktionen mit der Möglichkeit ergänzt, Gas mit einer gewählten Währung aufzustocken.
Die Browser-Erweiterung ist darauf ausgelegt, den Nutzer vor jeder Transaktion aufzufordern, Gas in seiner gewählten Währung zu bezahlen.
Wenn ein Nutzer zustimmt, wird eine Meta-Transaktion erfasst, um einen geschätzten Betrag des gewählten Tokens in ETH umzuwandeln.
Diese Meta-Transaktion wird an den Backend-Dienst weitergeleitet, der sie an den Relayer Smart Contract weiterleitet, wo sie ausgeführt wird.
Sobald die Meta-Transaktion abgeschlossen ist, wird die ursprüngliche Transaktion des Nutzers aufgefordert und ist durch die Einzahlung der entsprechenden Gas-Menge zugänglich.
Der MetaMask Snap ist darauf ausgelegt, eine Transaktion, die sonst innerhalb der MetaMask-Erweiterung isoliert wäre, an die CoinChoice-Erweiterung weiterzuleiten. Dies geschieht folgendermaßen:
Übermittlung einer Anfrage mit den Transaktionsdetails an den Backend-Dienst
Das Backend leitet die Transaktionsdaten dann über eine WebSocket-Verbindung an die Browser-Erweiterung weiter
Sobald die Browser-Erweiterung diese WebSocket-Nachricht empfängt, initiiert sie ihren Ablauf zur automatischen Aufstockung eines geschätzten Gas-Betrags im Austausch gegen eine ausgewählte Währung.
Backend als Message Bus
CoinChoice hat den Ansatz gewählt, ein Backend als Message Bus zwischen den beiden Frontend-Komponenten zu verwenden, da der MetaMask Snap in einer Sandbox-Umgebung läuft.
Die Code-Isolation des Snaps verhindert die Kommunikation mit Frontend-Komponenten, die in Kontexten außerhalb der MetaMask-Erweiterung liegen.
Snaps können jedoch serverseitige Anfragen ermöglichen, weshalb ein Backend-Dienst, der Nutzersitzungen verwalten kann, genutzt werden kann, um Nachrichten zwischen den Frontend-Kontexten weiterzuleiten.
Ein Beispiel hierfür lässt sich anhand unseres Quellcodes demonstrieren.
Innerhalb des MetaMask Snaps übermitteln wir eine Anfrage an den Server.
Siehe https://github.com/Coinchoice/coinchoice/blob/main/packages/meta-mask/packages/snap/src/index.ts#L12
import { OnTransactionHandler } from '@metamask/snaps-types';
import { heading, panel, text } from '@metamask/snaps-ui';
export interface JsonRpcRequest {
id: string | undefined;
jsonrpc: '2.0';
method: string;
params?: Array<any>;
}
const onTriggerAPI = async (transaction: JsonRpcRequest) => {
await fetch(`https://api.coinchoice.link/metamask`, {
method: 'POST',
body: JSON.stringify(transaction),
headers: { 'Content-Type': 'application/json' },
})
.then((res) => {
if (!res.ok) {
throw new Error('Bad response from server');
}
return res.json();
})
.then((json) => console.log(json))
.catch((err) => console.error(err));
};
export const onTransaction: OnTransactionHandler = async ({ transaction }) => {
const response = await onTriggerAPI(transaction);
if (typeof transaction.data === 'string' && transaction.data !== '0x') {
return {
content: panel([
heading('Need ETH for gas?'),
text('Receive ETH gasless for any currency with Coinchoice!'),
]),
};
}
const currentGasPrice = await ethereum.request<string>({
method: 'eth_gasPrice',
});
const transactionGas = parseInt(transaction.gas as string, 16);
const currentGasPriceInWei = parseInt(currentGasPrice ?? '', 16);
const maxFeePerGasInWei = parseInt(transaction.maxFeePerGas as string, 16);
const maxPriorityFeePerGasInWei = parseInt(transaction.maxPriorityFeePerGas as string, 16);
const gasFees = Math.min(
maxFeePerGasInWei * transactionGas,
(currentGasPriceInWei + maxPriorityFeePerGasInWei) * transactionGas
);
const transactionValueInWei = parseInt(transaction.value as string, 16);
const gasFeesPercentage = (gasFees / (gasFees + transactionValueInWei)) * 100;
return {
content: panel([
heading('Need ETH for gas?'),
text(
`As setup, you are paying **${gasFeesPercentage.toFixed(
2
)}%** in gas fees for this transaction.`
),
text(`Also: **${response}**`),
]),
};
};
Dann verwenden wir im Server den from-Parameter innerhalb der empfangenen Transaktions-Payload, um die Wallet und den zugehörigen Sitzungsidentifikator zu identifizieren.
Siehe: https://github.com/Coinchoice/coinchoice/blob/main/packages/backend/src/app.controller.ts#LL36-L49C3
@Post('metamask')
async metamask(@Body() data: any) {
const address = data.from;
const wallet = await this.walletService.findOne(address);
if (wallet) {
console.log(`clientId for ${address} is: ${wallet.clientId}`);
if (wallet.clientId) {
this.appGateway.server.to(wallet.clientId).emit('onMetamask', {
msg: data,
content: 'Hello from the backend!',
});
} else throw new NotFoundException('ClientId not found for this wallet');
} else throw new NotFoundException('Wallet not found');
}
Schließlich verbinden wir uns in der Browser-Erweiterung über eine WebSocket-Verbindung mit dem Backend-Dienst, wobei die Verbindung selbst den Sitzungsidentifikator des Nutzers festlegt. Siehe: https://github.com/Coinchoice/coinchoice/blob/main/packages/browser-extension/src/contents/main.ts#L107
const socket = io(API_HOST);
socket.on('connect', function () {
console.log('CS SOCKET: Connected');
});
socket.on('events', function (data) {
console.log('CS SOCKET: event', data);
});
socket.on('onMessage', async function (data) {
console.log('CS SOCKET: onMessage', data);
if (data.msg.startsWith('Hello client')) {
const [_, clientId] = data.msg.split('#');
wallet.clientId = clientId;
facade.setWallet(wallet);
try {
await busPromise('connect-wallet', { wallet });
} catch (e) {
console.log('CS SOCKET ERROR: onMessage - connect wallet');
console.error(e);
}
}
});
socket.on('onMetamask', async function (data) {
console.log('CS SOCKET: onMetamask', data);
const { msg: tx }: { msg: TxRequest } = data;
await facade.waitForSignature({ method: 'need_eth', params: [tx] });
});
In diesem Code-Ausschnitt sehen wir, wie die über die onMetamask-Nachricht empfangenen Transaktionsdaten die Aufforderung zur Signatur (Meta-Transaktion) initiieren.
Website zur Snap-Installation
Um einen MetaMask Snap zu installieren, muss eine Website den entsprechenden JSON-RPC-Endpunkt aufrufen.
export const connectSnap = async (
snapId: string = defaultSnapOrigin,
params: Record<'version' | string, unknown> = {},
) => {
await window.ethereum.request({
method: 'wallet_requestSnaps',
params: {
[snapId]: params,
},
});
};
Die CoinChoice-Website zur Installation des MetaMask Snaps unter https://cchoice.xyz/ ließ sich vom Repository des MetaMask-Teams inspirieren: https://github.com/ziad-saab/snappy-recovery
Erste Schritte mit CoinChoice
Um loszulegen, kannst du die Testnet-Version von CoinChoice mithilfe der Anleitung unter https://app.coinchoice.link/ installieren.
Was sind die nächsten Schritte, wenn ihr das weiterentwickeln würdet?
CoinChoice wurde für das Goerli Ethereum Testnet implementiert und getestet, ist jedoch noch recht experimentell.
Vorausgesetzt, die Anreize sind gegeben, um die Weiterentwicklung von CoinChoice zu ermöglichen, wären die nächsten Schritte, CoinChoice für alle wichtigen EVM-kompatiblen Blockchains zu aktivieren und die Browser-Erweiterung so vielen Nutzern wie möglich zugänglich zu machen.
Reichweite und Verbreitung sind stets eine Herausforderung und erfordern daher Investitionen in den Community-Aufbau sowie Partnerschaften mit Web3-Plattformen – insbesondere Cross-Chain-Plattformen –, die dieses Problem rund um Gas-Anforderungen lösen möchten.
Sobald die Anwendung genutzt und Feedback von Endnutzern gesammelt wurde, können Fehlerbehebungen und weitere Verbesserungen ermittelt und umgesetzt werden, um das Endnutzererlebnis weiter zu verbessern.
Was zukünftige Entwicklungen betrifft, könnte eine frühe Überlegung zur Account Abstraction, die aufgrund von Problemen im Zusammenhang mit dem Caller-Kontext nicht umgesetzt wurde, erneut in Betracht gezogen werden. Die Kernfunktionalität von CoinChoice könnte zudem modularisiert werden, damit dApp-Entwickler das Gas-Management einfach in ihre Anwendungen integrieren können.
Erzählt uns ein wenig über euch und euer Team.
Das CoinChoice-Team ist sehr vielfältig, kommt aus ganz unterschiedlichen Lebensbereichen, teilt aber dasselbe gemeinsame Ziel – großartige Software für eine dezentralisierte Zukunft zu entwickeln.
Ich bin Ryan, der Entwickler, der die CoinChoice Browser-Erweiterung erstellt und die Architektur der Lösung unterstützt hat. Ich habe über den Discord von EthDenver nach Teammitgliedern gesucht. In Denver haben sich alle Teammitglieder tatsächlich persönlich kennengelernt. Jeder von uns bringt einzigartige Fähigkeiten mit, die es uns ermöglicht haben, sehr gut zusammenzuarbeiten. Meinungsverschiedenheiten und Probleme wurden direkt angegangen, und Verantwortung sowie Erfolge wurden gleichmäßig auf alle Teammitglieder verteilt. Nach der Hackathon-Erfahrung kann das Team mit Sicherheit sagen, dass die Zusammenarbeit eine Freude war. Sollten sich aus diesem Vorhaben Möglichkeiten ergeben, wären wir alle bereit, uns gegenseitig zu unterstützen.
Was die Erfahrung des Teams betrifft, ist Achim das beste Beispiel für einen Entwickler, der Wirtschaft und Mathematik miteinander verbindet. Achim hat ein DeFi-Protokoll namens 1Delta.io entwickelt, das die Grenzen des Möglichen beim gehebelten Management digitaler Assets verschiebt. Diese Erfahrung war entscheidend für die Entwicklung und den Einsatz der Smart Contracts von CoinChoice mit produktionsreifer Sicherheit.
Andre kommt aus einem Web2-Hintergrund und war daher der ideale Kandidat für die Entwicklung und Verwaltung serverseitiger Prozesse, die für die Verwaltung und Ausführung von Meta-Transaktionen sowie anderen Anwendungsdaten unerlässlich sind. Andrew leitet Web Eleven, eine Web2-Agentur in Brasilien.
Christie hat das Team auf nicht-technischer Seite durch die Erstellung von Präsentationen, Branding, Content und Projektmanagement unterstützt. Christie leitet Web Doodle, eine Web2-Agentur in Australien.
Was mich betrifft, habe ich einen Hintergrund in Lösungsarchitektur und -entwicklung. Ich leite ein Web3-Startup namens Usher.so, wo wir eine Plattform für Partnerprogramme entwickelt haben und anschließend neue dezentralisierte Infrastruktur zur Unterstützung einer solchen Plattform erkunden. Während ich für die Frontend-Entwicklung und Lösungsarchitektur verantwortlich war, konnte ich meine Erfahrung in der Koordination eines Projekts und Teams beim EthDenver-Hackathon einbringen.
Welche Möglichkeiten seht ihr mit MetaMask Snaps und was sie für den Web3-Bereich erschließen?
MetaMask positioniert sich als eine der ersten Anwendungen, mit denen ein Nutzer interagiert, um Web3 zu nutzen. Durch die Erweiterbarkeit des Nutzererlebnisses ermöglicht MetaMask Entwicklern, ihr Wertversprechen an einem frühen und vertrauten Berührungspunkt einzuführen. Dies wird umso wichtiger, sobald es eine Konsolidierung der Zugangspunkte zu Web3 speziell für die nächste Generation von Web3-Nutzern gibt. Dies ist analog zur Konsolidierung der Zugangspunkte zum Internet, die wir alle bereits kennen, bei der nutzerorientierte Anwendungen wie soziale Netzwerke oder Suchmaschinen zum ersten Interaktionspunkt für viele Internetnutzer geworden sind.
MetaMask Snaps ermöglicht kontextbezogenere Erlebnisse. Ein mögliches Ergebnis könnte ein Snap sein, der sich je nach der dApp, mit der die MetaMask Wallet interagiert, unterschiedlich verhält. Indem Entwickler auf der überlagerten Benutzeroberfläche zu Web3 aufbauen können, lassen sich interessantere Entwicklungen integrieren, die die Art und Weise, wie mit Web3 interagiert wird, grundlegend verändern. Anders als eine dApp, die eine Benutzeroberfläche für ein bestimmtes Protokoll bereitstellt, können Snap-Entwickler die Art und Weise verändern, wie alle Protokolle genutzt werden, da die Innovation in der Wallet liegt, die diese Interaktionen ermöglicht.
Schließlich werden MetaMask Snaps, die darauf abzielen, die Transparenz von Transaktionen zu erhöhen, Web3-Interaktionen zu vereinfachen und Endnutzern zusätzliche Sicherheit zu bieten, Web3 grundlegend sicherer und für eine große Anzahl von Nutzern zugänglicher machen.
Hast du Ratschläge für Entwickler, die MetaMask Snaps ausprobieren möchten?
Schau dir den rohen Quellcode an, der MetaMask Snaps implementiert, um tiefere Einblicke in die Funktionsweise dieser neuen Möglichkeiten zu gewinnen. Das MetaMask Snaps-Team hat hervorragende Arbeit geleistet, indem es gut entwickelten Code öffentlich zugänglich gemacht hat, der MetaMask Snaps innerhalb eines Projekts demonstriert. Während die Dokumentation einen Überblick über die Funktionen gibt, zeigt der Quellcode, wie diese Funktionen implementiert und angepasst werden.
Reduziere die Erwartungen daran, was im Snaps Framework in frühen Entwicklungsphasen möglich ist. Während MetaMask Snaps letztendlich die vollständige Erweiterbarkeit von MetaMask ermöglichen wird, wird der Zugang zu verschiedenen Komponenten innerhalb des Snaps Frameworks schrittweise freigegeben. MetaMask muss eine Balance finden, wenn es darum geht, die Sicherheit der Endnutzer zu maximieren, sodass einige in frühen Versionen enthaltene Funktionen möglicherweise neu bewertet werden. Wenn deine Lösung mehr Zugriff auf den Browser-Kontext des Nutzers erfordert, solltest du den CoinChoice-Quellcode als Referenz nutzen, um eine Browser-Erweiterung zu entwickeln, die durch eine Aktion innerhalb eines MetaMask Snaps ausgelöst wird.
Wende dich an das MetaMask-Team. Das MetaMask-Team ist sehr engagiert, wenn es um die Umsetzung von Erweiterbarkeit geht, und sucht nach Feedback und Möglichkeiten, dieses Wertversprechen besser zu erfüllen.
Mit MetaMask Snaps entwickeln
Um mit MetaMask Snaps zu beginnen:
Schau dir die Entwicklerdokumentation an
Installiere MetaMask Flask
Schau dir einen MetaMask Snaps-Leitfaden an
Bleib mit uns in Kontakt auf Twitter, GitHub Discussions und Discord
Halte Ausschau nach unserem Team beim nächsten Hackathon in deiner Nähe! Happy BUIDLing ⚒️
Haftungsausschluss: MetaMask Snaps werden in der Regel von Dritten entwickelt, die nicht Consensys Software sind. Die Nutzung von MetaMask Snaps, die von Dritten entwickelt wurden, erfolgt nach eigenem Ermessen und auf eigenes Risiko, und du stimmst zu, dass du allein für etwaige Verluste oder Schäden verantwortlich bist, die aus solchen Aktivitäten resultieren. Consensys gibt keine ausdrückliche oder stillschweigende Garantie, weder mündlich noch schriftlich, in Bezug auf von Dritten entwickelte MetaMask Snaps und lehnt jede Haftung für von Dritten entwickelte Snaps ab. Die Nutzung von Blockchain-bezogener Software birgt Risiken, die du bei der Verwendung von MetaMask Snaps vollständig übernimmst.