> Why did you build it?
In our views the wallet experience in Polkadot ecosystem is still lacking. On the other hand, integrating with MetaMask Snaps could help onboard an existing population of web3 users to Alpeh Zero network.
> Put your walkthrough video
https://www.youtube.com/watch?v=lS5-YwOy9gE
> Can you walk us through the technical implementation?
## The adapter
Our snap is composed from two parts. First is a website that users interact with. The second one is the actual Snap. Those two elements work in a way similar to client-server architecture, where the snap is a server and the website is the client. To reflect this natural boundary we have extracted snap API to a separate package named `adapter`. It exposes all possible methods the website may use to interact with the snap. Such a layer of abstraction, ease usage of the Snap by other clients (websites). Our API can be described by four methods, which names are pretty self-explanatory. If u want to deep dive, here is the full [code](https://github.com/piotr-roslaniec/ethwarsaw-2022/tree/main/azero-snap/packages/snap-adapter).
```javascript=
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", []);
}
```
## The App
So, we explained the glue between our layers, let’s move on to the first layer - website. We have forked the official browser based [polkadot app](https://github.com/Cardinal-Cryptography/apps). Then we had to replace core functionalites like signing transactions, creating accounts or recovering them, from browser based wallet to the Snap based. For example to sign transactions inside MetaMask we changed implementation of [QrSigner](https://github.com/piotr-roslaniec/ethwarsaw-2022/blob/ed9f12e54c9c721685692f75b78e2f3e1d8b546b/polkadot-apps/packages/react-signer/src/signers/QrSigner.ts#L20) to use Snap `signTransaction` instead.
Integrating MetaMask Snap with the polkadot app introduced two improvments.
Firstly, it allowed to inherit the security model from the MetaMask extension instead of using the polkadot app wallet, which is based on local storage.
Secondly, we could use MetaMask seed to create a polkadot app in a deterministic way, so whenever we export our seed, the Aleph Zero key will be also exported.
## The MetaMask API
MetaMask provides [API calls](https://docs.metamask.io/guide/snaps-rpc-api.html#restricted-methods), which can be used by snaps if permitted by user. In this case we have levarged two of them:
`snap_manageState` - which allow as two store encrypted data inside MeteMask. For instance we use it to store created accounts. Interacting with state is very easy and can be simplified to:
```typescript
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_` - to get entropy from MetaMask seed. [docs](https://docs.metamask.io/guide/snaps-rpc-api.html#snap-getbip44entropy)
It is worth to mention that there exists very cool MetaMask library [passworder](https://www.npmjs.com/package/@metamask/browser-passworder), which allow us to easly encrypt and decrypt state. In our case as a symetric key to encrypt state we have used entropy from MetaMask seed once again.
## The SDK
So let's recap, we have hacked polkadot app by injecting some javascript here and there enabling usage of the Snap. The Snap can get entropy from the seed inside MetaMask and manage encrypted state. So the last step would be to integrate with the SDK for the Aleph Zero - [polkadotjs](https://polkadot.js.org/docs/api/).
That seems like a easy task, just run `npm install @polkadot/api` and import it. However importing dependencies to Snap can be challening. This difficulties appears, because Snap is not evaluated directly on javascript virtual machine, it first has to be sandboxed in Secure Ecma Script (SES). In short, code which normally compile without any problems could fail when loading in [SES](https://docs.metamask.io/guide/snaps-development-guide.html#fixing-build-eval-issues).
When working with most of the librariers we wont have any problems, but it wasn't case for us. We had two issues with evaluating `polkadotjs SDK` inside SES, to mitigate them we have written two scripts which were run on bundled source code.
First of them was caused by incorrectly formatted wasm code embedded inside javascript file. Here is the fixing script:
```javascript=
const fs = require('fs').promises;
const path = require('path');
const dirPath =
'../../../../node_modules/@substrate/smoldot-light/dist/cjs/instance/autogen';
// SES doesn't like double slashes in strings so we need to replace them with single slashes
// and string concatenation.
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();
```
Second issue was also caused, by polkadot extension, which was trying to access `window.addEventListener` method, which is forbidden in SES. It was also trivally solved with simple
```javascript=
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';
// Looking for a first breakline after the first line of the file
// This is where we can safely inject our code
const fixed = contents.replace('\n\n', replaceMissingTypes);
await fs.writeFile(bundlePath, fixed);
}
fix();
```
> What are the next steps if you would implement this?
We'd love to make make our snap fully compatible with polkadot.js and viable as a web wallet in Polkadot ecosystem.
> Your Story
> Can you tell us a little bit about yourself and your team?
Micheal is a programmer in a Polish bank working on a daily basis with blockchain technology. He loves programming and learning new stuff.
Piotr is a software engineer working in NuCypher. He’s interested in privacy, data, and distributed systems.
> When were you first introduced to MetaMask Snaps and what was your experience like?
Piotr - Initially learned about snaps during Devcon in Osaka. The topic resurfaced earlier this year, shortly before EthDenver hackathon.
Michał - Piotr introduced me to Snaps, shortly after EthDenver.
> What makes MetaMask Snaps different from other wallets?
An ability to access application-specific cryptography/private keys in your dapp - It enables building new user flows on top of a familiar browser-wallet experience.
> Tell us about what building Snaps with MetaMask is like for you and your team?
The basics are there, but building more sophisticated snaps, especially ones that require custom UI elements, is tricky. We spent a lot of time figuring out how to fit our mental model of web developer experience into snaps - things like deployment, testing, etc.
> What does Snaps mean to you?
It is a tool which gives real power to the community, everyone for themself decides, what features should their MetaMask have. Plugins allows to democratize development and enable faster growth.
> What opportunities do you see with MetaMask Snaps and the possibilities it unlocks for the Web3 space?
Access to more network (especially non-EVM ones); An ability to tap into transaction lifecycle and add custom logic (like safety checks) or customize the UX; Encrypted storage in the browser for dapp-specific sensitive content, and also an ability to "bring your own cryptography" to your users with snaps.
> Any advice you would like to share with developers keen to try MetaMask Snaps?
Compiling JS libraries in SES could be difficult, but from our experience it's not impossible. Feedback loop in developing metamask is pretty long, so we be sure to write unit tests.
There is a small but active developers community in MetaMask snaps - visiting Discord, GitHub discussions etc. can be very rewarding, especially that the product is still new and there is little education avalible outside this bubble.
>Article Structure:
Video
Intro the team and what was your roles
Technical walkthrough
The mission of the snap
Future builds and next steps in the development
> Notes to deliver a better blog post:
Add a lot of screenshots of the demo
Add the walkthrough video - https://www.youtube.com/watch?v=lS5-YwOy9gE
Screenshots of the code, main parts with an explanation
Add tons of links referring to the snaps documentation or talks
CTA where devs can check your repos etc
>Deliverables to Snaps Team:
Team picture
Pictures from the event
Link to Snap repo - https://github.com/piotr-roslaniec/ethwarsaw-2022
Link to personal/team website - https://devpost.com/software/aleph-zero-snap
Team members Twitter handles - https://twitter.com/piotrroslaniec, https://twitter.com/konopek68
Sample posts:
https://consensys.net/blog/metamask/metamasks-community-at-the-core-of-its-growth/