MetaMask Snaps est la feuille de route pour faire de MetaMask le wallet le plus extensible au monde. En tant que développeur, vous pouvez intégrer vos fonctionnalités et vos API à MetaMask de manières totalement inédites. Les développeurs Web3 sont au cœur de cette croissance, et cette série vise à mettre en lumière les MetaMask Snaps innovants en cours de développement.
CoinChoice Snap
Snap Repo : https://github.com/coinchoice/coinchoice/
Pourquoi l'avez-vous développé ?
CoinChoice est né d'un problème à la fois mineur et fastidieux, mais très répandu : un utilisateur Web3 peut posséder un wallet contenant des tokens de valeur, sans pour autant disposer de la devise de gas nécessaire pour effectuer des transactions.
Ce problème est particulièrement marqué pour les utilisateurs dont la liquidité est fragmentée. Un utilisateur gérant plusieurs wallets et saisissant des opportunités sur différents écosystèmes blockchain se retrouve à répartir ses tokens de gas entre chacun de ses wallets, immobilisant ainsi des capitaux qui auraient pu être investis, simplement pour faciliter la gestion de ses actifs numériques et de ses transactions. Au-delà de la gestion du gas, les tokens transférés vers un réseau sur lequel l'utilisateur ne possède pas de gas l'obligent à en obtenir avant de pouvoir effectuer toute autre action. Cela implique généralement de passer par un Exchange Centralisé pour acquérir et retirer du gas, exposant ainsi l'utilisateur aux frais de retrait des CEX.
Fondamentalement, cette expérience est défaillante. Les utilisateurs ne devraient pas dépendre des exchanges centralisés pour accéder au Web3. Ils ne devraient pas avoir à se soucier de la gestion de leur gas, mais devraient simplement pouvoir interagir avec des systèmes décentralisés. Cela ne signifie pas pour autant que le gas devrait être supprimé. Le gas remplit un rôle essentiel en récompensant les opérateurs d'un réseau et en prévenant le spam et les attaques DDoS. Le gas devrait simplement être plus flexible. Si un développeur de dApp ou de jeu dispose d'un token natif, ce token devrait pouvoir servir de devise pour payer le gas.
C'est avec cette philosophie en tête que CoinChoice a été développé.
CoinChoice s'intègre directement dans le navigateur de l'utilisateur, en ajoutant à chaque transaction la possibilité de gérer le gas dans la devise de son choix. Si l'utilisateur préfère détenir des USDC plutôt que de l'ETH, le gas peut être payé en USDC.
Le MetaMask Snap de CoinChoice vient compléter cette expérience. Directement depuis l'extension navigateur MetaMask, les utilisateurs peuvent recharger leur ETH en échange de la devise de gas de leur choix. MetaMask devient ainsi une solution qui remplace le recours à un Exchange Centralisé, en consolidant et en simplifiant l'expérience Web3, et en permettant aux nouveaux utilisateurs Web3 de se familiariser avec un sous-ensemble de systèmes sans être submergés par la multitude croissante de services et de plateformes.
Pouvez-vous nous présenter l'implémentation technique ?
CoinChoice est une extension MetaMask et navigateur qui vous laisse choisir quels tokens utiliser pour payer le gas.
Packages
backend : Un serveur Web NestJS chargé de simuler les transactions via l'API Tenderly et l'API 0x Quote afin d'estimer le gas dans la devise choisie
recevoir et relayer les messages entre le MetaMask Snap et l'extension navigateur du client
recevoir les meta-transactions à transmettre aux contrats relayeurs
browser-extension : Une extension navigateur propulsée par le framework Plasmo qui intercepte les requêtes RPC vers MetaMask afin d'injecter des swaps vers ETH pour le financement du gas
propose une popup permettant de sélectionner le Gas Coin
propose une popup pour la gestion des tokens, propulsée par le SDK Cypher Onboarding
toutes les données sont transmises au service backend où les interactions et simulations blockchain sont gérées
contracts : Smart Contracts assurant le relayage des meta-transactions pour faciliter les swaps sur le protocole 0x.
frpc : Un package permettant d'exploiter le fRPC Gateway du réseau Fluence
meta-mask : Un package contenant un site React.js et le MetaMask Snap associé.
Le Snap se charge de proposer des swaps ETH directement dans l'interface MetaMask, en affichant le message « Need ETH? »
Le Snap fonctionne en envoyant une requête au backend afin qu'un message soit transmis à l'extension navigateur du client, créant ainsi une expérience où le MetaMask Snap peut initier l'extension navigateur
Le site associé permet l'installation du MetaMask Snap
Configuration technique
CoinChoice est une extension navigateur qui enrichit les transactions en offrant la possibilité de recharger le gas avec la devise de son choix.
L'extension navigateur est conçue pour inviter l'utilisateur à payer le gas dans la devise sélectionnée avant chaque transaction.
Si l'utilisateur accepte, une meta-transaction est capturée pour convertir un montant estimé du token choisi en ETH.
Cette meta-transaction est transmise au service backend, qui la transfère au Smart Contract relayeur où elle est exécutée.
Une fois la meta-transaction finalisée, la transaction initiale de l'utilisateur est déclenchée et accessible grâce au dépôt du montant de gas approprié.
Le MetaMask Snap est conçu pour transmettre une transaction qui serait autrement isolée dans l'extension MetaMask vers l'extension CoinChoice. Pour ce faire, il :
soumet une requête contenant les détails de la transaction au service backend
le backend transmet ensuite les données de la transaction à l'extension navigateur via une connexion websocket
dès que l'extension navigateur reçoit ce message websocket, elle déclenche son processus de recharge automatique d'un montant de gas estimé en échange d'une devise sélectionnée.
Le backend comme bus de messages
CoinChoice a opté pour l'utilisation d'un backend comme bus de messages entre les deux composants frontend, en raison de la nature isolée du MetaMask Snap.
L'isolation du code du Snap empêche toute communication avec des composants frontend résidant dans des contextes extérieurs à l'extension MetaMask.
Cependant, les Snaps peuvent effectuer des requêtes côté serveur, ce qui permet d'utiliser un service backend capable de gérer les sessions utilisateurs pour faire transiter les messages entre les différents contextes frontend.
Un exemple concret est illustré dans notre code source.
Dans le MetaMask Snap, nous soumettons une requête au serveur.
Voir 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}**`),
]),
};
};
Ensuite, au niveau du serveur, nous utilisons le paramètre from contenu dans le payload de la transaction reçue pour identifier le wallet et l'identifiant de session associé.
Voir : 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');
}
Enfin, au niveau de l'extension navigateur, nous nous connectons au service backend via une connexion websocket, la connexion elle-même établissant l'identifiant de session de l'utilisateur. Voir : 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] });
});
Dans cet extrait de code, nous pouvons voir comment les données de transaction reçues via le message onMetamask déclenchent l'invite de signature (meta-transaction).
Site web pour l'installation du Snap
Pour installer un MetaMask Snap, un site web doit appeler le endpoint JSON RPC approprié.
export const connectSnap = async (
snapId: string = defaultSnapOrigin,
params: Record<'version' | string, unknown> = {},
) => {
await window.ethereum.request({
method: 'wallet_requestSnaps',
params: {
[snapId]: params,
},
});
};
Le site web de CoinChoice permettant d'installer le MetaMask Snap, hébergé à l'adresse https://cchoice.xyz/, s'est inspiré du dépôt de l'équipe MetaMask : https://github.com/ziad-saab/snappy-recovery
Démarrer avec CoinChoice
Pour commencer, vous pouvez installer la version testnet de CoinChoice en suivant le guide disponible à l'adresse : https://app.coinchoice.link/
Quelles sont les prochaines étapes si vous deviez poursuivre ce projet ?
CoinChoice a été implémenté et testé sur le testnet Goerli d'Ethereum, bien que de manière encore expérimentale.
Si les conditions sont réunies pour permettre la poursuite du développement de CoinChoice, les prochaines étapes consisteraient à rendre CoinChoice compatible avec toutes les principales blockchains compatibles EVM, puis à mettre l'extension navigateur entre les mains du plus grand nombre d'utilisateurs possible.
La visibilité et la distribution représentent toujours un défi, et nécessiteront donc des investissements dans le développement communautaire ainsi que des partenariats avec des plateformes Web3, notamment des plateformes cross-chain, afin de lever les contraintes liées aux exigences en matière de gas.
Une fois l'application utilisée et les retours des utilisateurs finaux collectés, des corrections de bugs et d'autres améliorations pourront être identifiées et appliquées pour améliorer davantage l'expérience utilisateur.
En ce qui concerne les développements futurs, une réflexion préliminaire sur l'Account Abstraction, qui n'avait pas été mise en œuvre en raison de problèmes liés au contexte d'appel, pourrait être reconsidérée. La fonctionnalité principale de CoinChoice pourrait également être modularisée pour permettre aux développeurs de dApp d'intégrer simplement la gestion du gas dans leurs applications.
Pouvez-vous nous parler un peu de vous et de votre équipe ?
L'équipe CoinChoice est très diverse, issue de parcours très différents, mais partageant le même objectif commun : créer des logiciels exceptionnels pour un avenir décentralisé.
Je m'appelle Ryan, l'ingénieur qui a créé l'extension navigateur CoinChoice et soutenu l'architecture de la solution. J'ai recruté des membres d'équipe via le Discord d'EthDenver. C'est à Denver que tous les membres de l'équipe se sont rencontrés en personne pour la première fois. Chacun d'entre nous apporte des compétences uniques qui nous ont permis de très bien travailler ensemble. Les désaccords et les problèmes ont été affrontés de front, et les responsabilités comme les succès ont été partagés équitablement entre tous les membres. À l'issue de cette expérience de hackathon, l'équipe peut affirmer sans hésitation que ce fut un plaisir de travailler ensemble. Si des opportunités venaient à émerger de cette aventure, nous serions tous disponibles pour nous soutenir mutuellement.
En ce qui concerne l'expérience de l'équipe, Achim est le meilleur exemple d'un ingénieur à l'intersection de l'économie et des mathématiques. Achim a développé un protocole DeFi nommé 1Delta.io qui repousse les limites de ce qui est possible en matière de gestion d'actifs numériques à effet de levier. Cette expérience a été déterminante pour développer et déployer les Smart Contracts de CoinChoice avec un niveau de sécurité digne de la production.
Andre vient d'un background Web2 et était donc le candidat idéal pour développer et gérer les processus côté serveur, essentiels à la gestion et à l'exécution des meta-transactions, ainsi que d'autres données applicatives. Andrew dirige Web Eleven, une agence Web2 au Brésil.
Christie a apporté son soutien non technique à l'équipe à travers la création de présentations, le branding, la production de contenu et la gestion de projet. Christie dirige Web Doodle, une agence Web2 en Australie.
Pour ma part, j'ai un background en architecture de solutions et en ingénierie. Je dirige une startup Web3 nommée Usher.so où nous avons développé une plateforme de programmes partenaires, et explorons actuellement de nouvelles infrastructures décentralisées pour soutenir une telle plateforme. Tout en étant responsable du développement front-end et de l'architecture des solutions, j'ai pu mettre à profit mon expérience dans la coordination de projets et d'équipes lors du hackathon EthDenver.
Quelles opportunités voyez-vous dans MetaMask Snaps et les possibilités qu'il ouvre pour l'espace Web3 ?
MetaMask se positionne parmi les premières applications avec lesquelles un utilisateur interagit pour accéder au Web3. En permettant l'extensibilité de l'expérience utilisateur, MetaMask offre aux développeurs la possibilité d'introduire leur proposition de valeur à un point de contact précoce et familier. Cela devient d'autant plus important lorsqu'une consolidation des passerelles vers le Web3 s'opère, notamment pour la prochaine génération d'utilisateurs Web3. C'est analogue à la consolidation des passerelles vers internet que nous connaissons tous, où des applications grand public comme les réseaux sociaux ou les moteurs de recherche sont devenus le premier point d'interaction pour de nombreux internautes.
MetaMask Snaps permet des expériences plus contextuelles. Un exemple concret pourrait être un Snap qui se comporte différemment selon la dApp avec laquelle le wallet MetaMask interagit. En permettant aux développeurs de construire sur la couche d'interface utilisateur du Web3, des développements plus innovants peuvent être intégrés, modifiant fondamentalement la manière dont on interagit avec le Web3. Contrairement à une dApp qui propose une interface pour un protocole spécifique, les développeurs de Snaps peuvent modifier la façon dont tous les protocoles sont utilisés, car l'innovation réside dans le wallet qui rend ces interactions possibles.
Enfin, les MetaMask Snaps visant à accroître la transparence des transactions, à simplifier les interactions Web3 et à renforcer la sécurité des utilisateurs finaux rendront fondamentalement le Web3 plus sûr et plus accessible à un grand nombre d'utilisateurs.
Avez-vous des conseils à partager avec les développeurs souhaitant se lancer dans MetaMask Snaps ?
Consultez le code source brut qui implémente MetaMask Snaps pour mieux comprendre le fonctionnement de ces nouvelles fonctionnalités. L'équipe MetaMask Snaps a fait un excellent travail en rendant public un code bien développé qui illustre MetaMask Snaps dans le cadre d'un projet. Si la documentation offre une vue d'ensemble des fonctionnalités, le code source montre comment ces fonctionnalités sont implémentées et utilisées.
Revoyez vos attentes à la baisse quant aux capacités du framework Snaps durant les premières phases de développement. Bien que MetaMask Snaps finisse par permettre une extensibilité complète de MetaMask, l'accès aux différents composants du framework Snaps sera déployé progressivement. MetaMask devra trouver un équilibre pour maximiser la sécurité des utilisateurs finaux, ce qui signifie que certaines fonctionnalités incluses dans les premières versions pourraient être reconsidérées. Si votre solution nécessite un accès plus étendu au contexte navigateur de l'utilisateur, envisagez de consulter le code source de CoinChoice pour développer une extension navigateur déclenchée par une action dans un MetaMask Snap.
Contactez l'équipe MetaMask. L'équipe MetaMask est très impliquée dans la livraison de l'extensibilité et recherche activement des retours ainsi que des opportunités pour mieux répondre à cette proposition de valeur.
Développer avec MetaMask Snaps
Pour démarrer avec MetaMask Snaps :
Consultez la documentation développeur
Installez MetaMask Flask
Consultez un guide MetaMask Snaps
Restez connecté avec nous sur Twitter, les discussions GitHub et Discord
Guettez notre équipe lors du prochain hackathon près de chez vous ! Bonne construction ⚒️
Avertissement : Les MetaMask Snaps sont généralement développés par des tiers autres que Consensys Software. L'utilisation de MetaMask Snaps développés par des tiers se fait à votre seule discrétion et à vos propres risques, et implique votre accord selon lequel vous serez seul responsable de toute perte ou dommage résultant de ces activités. Consensys ne donne aucune garantie expresse ou implicite, qu'elle soit orale ou écrite, concernant les MetaMask Snaps développés par des tiers, et décline toute responsabilité pour les Snaps développés par des tiers. L'utilisation de logiciels liés à la blockchain comporte des risques, que vous assumez en totalité lors de l'utilisation de MetaMask Snaps.