MetaMask under the hood—not just a crypto wallet
This is the first article in a two-part series.
- MetaMask under the hood. <– You are here.
- Fault-tolerant transactions with MetaMask and Chainstack.
MetaMask is a widely popular browser extension, with more than 30 million monthly users as of the beginning of 2022. MetaMask opened the doors to Web3 for the masses. But how does it work? How does it help us connect to and interact with a blockchain? Is there anything we can do to improve it and make it even more reliable?
Defined as a non-custodial wallet, MetaMask allows you to have full control of your access keys. This is great because you can manage your assets how you want, but it also means that there is no “complaints department” to contact if you lose access to your funds or if you send them to the wrong place. Therefore, we want to explain how MetaMask works.
This series is divided into two parts and will answer all these questions. You will have a much better idea of what happens behind the curtains when you use MetaMask. This article is the first part of the series where we dive deep into the inner workings, while the second part will show you how to make MetaMask more efficient and reliable using Chainstack.
What is MetaMask?
MetaMask is a tool that allows you to store tokens, interact with decentralized applications (DApps), and experience Web3. MetaMask is available as a browser extension and as a mobile app on iOS and Android. It was created to help users have a secure, reliable, and easy connection to Ethereum-based blockchains.
More than just a wallet
Most people know MetaMask as a crypto wallet, but it is much more than just that. You can consider it a cryptographic account manager that uses cryptography to keep the keys of your account secure. When you create a new account on MetaMask, it generates a new pair consisting of a private and a public key. These keys are essential to guarantee that the transactions executed are legitimately done by the account’s owner, and the user can manage the keys in a variety of ways. An example is a hardware wallet that separates the wallet from the Web3 environment and keeps it safer.
Public and private keys
The public key, also known as an address in the Web3 environment, is an alphanumeric character string used to encrypt the transactions that the account makes; and it is available to anyone to see. In Ethereum-based environments, the address begins with
The private key is also an alphanumeric string of data, but MetaMask associates it to a single account in a wallet. When an account receives a transaction, it uses the private key to decode it and access the funds, and because the private key is unique to that account, other accounts cannot access it. Note that whoever controls the private key controls the account funds. If you lose your private key, you lose access to the account and the funds in it.
In short, we can compare the public and private keys to login information for a website, where the public key is your username, and the private key is the password. But in this case you are the holder of the keys, as opposed to the traditional system where the website holds your login information somewhere on a server under their control. And this is one of the things that make Web3 applications different from the traditional Web2 applications.
How does MetaMask work?
window.ethereum object allows websites to read data from blockchains the user connects to, suggest that the user sign messages and transactions, and so on. MetaMask uses this API to identify a Web3 user and what Ethereum network is trying to interact with.
Important methods that MetaMask uses from this API include:
- Retrieve an account’s balance – eth_getBalance
- Send a transaction – eth_sendTransaction
- Sign messages using the private key – eth_sign
You can find a complete list of Ethereum JSON-RPC API methods in the Ethereum wiki.
Interact with DApps
One of the use cases for a tool like MetaMask is to allow its users to interact with decentralized applications, such as DeFi platforms, decentralized exchanges, NFT marketplaces, game applications on a blockchain, and more. MetaMask manages this by allowing you to permit the DApp to retrieve your address to interact with it.
Which will look something like this:
This is an important feature in MetaMask because it allows you to be in control of what you approve of. Note that anyone can deploy a token’s smart contract, so you should be careful making sure that you are only approving legitimate smart contracts that you recognize. If you approve a malicious smart contract, you risk allowing it to transfer your funds out of your account.
Transactions in MetaMask
Transactions are sent through a node and are formal actions that can result in simply swapping a token for another, creating a new smart contract, or any other interaction that changes the state of the blockchain. When you interact with a smart contract calling a function that changes the state of the network, MetaMask will initiate the transaction by calling the eth_sendTransaction method.
MetaMask will use the ethereum.request method directly to send a transaction.
Many parameters compose a transaction, and MetaMask takes care of setting it up automatically, but let’s see what the parameters are and how MetaMaks constructs them.
The nonce is a number showing how many transactions an account has made so far. Transactions are always processed in order, and to be valid, the nonce must either be 0 or greater than a previously processed transaction. It is a sensitive parameter, especially if users interact with different DApps from the same account. When initiating a transaction, Metamask will call the eth_getTransactionCount method, which will return the current nonce. If a transaction is sent with a previously used nonce, the transaction will fail.
For these reasons, MetaMask currently does not provide application developers with any way to customize the nonce. But as a user, you can set a custom nonce number when you send a transaction. You will need to activate this feature in the advanced settings on MetaMask.
Gas limit is a parameter that MetaMask sets up automatically. It is simply the maximum units of gas that you are willing to pay for a transaction. 21000 units is the standard in EVM compatible networks, and you can retrieved it by using the eth_EstimateGas method.
This is the fee you pay to the network to process the transaction. Generally, the network processes the transaction based on how profitable is for miners or validators. MetaMask makes an estimate likely to include the transaction in the block. The gas price is expressed in Gwei, and you can calculate it by adding the base fee with the priority fee (miner tip).
By calling the eth_getBlockByNumber method, MetaMask receives the base fee from the network, calculated based on the demand for block space.
The priority fee is generally a minimum of 2 Gwei, and this is what MetaMask selects as standard (on Ethereum).
Based on this, MetaMask estimates the gas price as follows:
(Base fee + priority fee) x gas limit
Taking Ethereum as an example, assuming that the base fee is 50 Gwei, your gas price will be:
(50 + 2) x 21000 = 1,092,000 Gwei = 0.001092 ETH
So summarizing, if you try to send 1 ETH to another address, you will spend a total of 1ETH + gas price, for a total of 1.001092 ETH. You can send a higher priority fee to incentivize the miners and validators to process your transaction faster.
This is the address that receives the transaction. It is a hex-encoded Ethereum address, and it is always present except when creating a new smart contract.
Value is the amount of native currency to send, and it is encoded in hex.
MetaMask uses this parameter when it creates or interacts with a smart contract. Most smart contracts are written in solidity, and applications use an application binary interface (ABI) to interpret the content. When you call a smart contract function, Metamask will use this parameter to tell which function to call by encoding the method and the parameters from the ABI into hex.
As an example, we want to call this function, passing 20 as the parameter.
MetaMask will send a transaction with the following data parameter:
This is how to encode a function call:
- The first four bytes represent the hashed name of the function and the argument.
- Then encode the parameter in hex, pad to 32 bytes, and add at the end. The number 20 is converted to Wei (20000000000000000000).
If we check the transaction in the block explorer, we can see how it is encoded:
Currently ignored by MetaMask. The Chain ID is a number used during the process of signing and verifying transactions (different from the private key). It distinguishes the different chains and avoid replay attacks, so that transactions are not duplicated on another chain. You can retrieve this data by using the eth_getChainId method.
Now, you should have a better idea of how MetaMask works behind the scenes, why it is so powerful and why so many people use it. I am sure you will not look at it as “just my crypto wallet” anymore. The second part of this article will show you how to make your MetaMask even better and more reliable using Chainstack as an endpoint provider!
- Connect to the Ethereum, Polygon, BNB Smart Chain, Avalanche, Fantom, Solana, Harmony, Tezos and StarkNet mainnet or testnets through the interface designed to help you get the job done.
- Get access to the Ethereum, Polygon, BNB Smart Chain, Avalanche, Fantom, and Tezos archive nodes to query the entire history of the mainnet—starting at just $49 per month.
- Choose where you want to deploy, and we will provide you with the dedicated managed infrastructure that can handle high-volume, high-velocity read/write access to the network.
- To learn more about Chainstack, visit our Knowledge Center or join our Discord server and Telegram group.
Have you already explored what you can achieve with Chainstack? Get started for free today.