Blackbelt Snap: Real-Time Self Defense Against Scams

An ETHBogota Hackathon Snap

by MetaMaskNovember 10, 2022
feature

MetaMask Snaps is the roadmap to making MetaMask the most extensible wallet in the world. As a developer, you can bring your features and APIs to MetaMask in totally new ways. Web3 developers are the core of this growth and this series aims to showcase the novel MetaMask Snaps being built today.

Blackbelt Snap

Snap Repo: https://github.com/s-a-malik/blackbelt

Why did you build it?

We wanted to make interactions on blockchains more secure for end users. Especially new and non-tech savvy users that are afraid to fall victim to scams and exploits. Therefore, we thought of a way to provide real-time risks assessment for smart contract interactions.

Can you walk us through the technical implementation?

The technical setup

Blackbelt consists of three elements: our server, the MetaMask snap, and our website front-end. The server retrieves data and calculates the smart contract risk scores. The MetaMask snap as well as our website call the server and supply the specific contract address within the https request. The full implementation of our project can be found here.

The server

Our server consists of a flask back-end that returns security scores and metadata as json. When a GET request is initiate to the route /security_score, the function security_score() is called. First, all supplied parameters, such as contract address, user address, chain id, and caller origin, will be unpacked and then partially parsed into the function compute_security_score(contract_address, chain) which will retrieve on-chain data and computes security scores for multiple variable (e.g., contract age). To speed up data retrieval inside MetaMask Snaps, we provide cached results if available when the server is called via MetaMask Snaps (see variable is_snaps).

def security_score():
    """
    Returns the security score and the metadata used to compute it for a given contract address.
    Saves result to ipfs and local storage.
    Params:
    - user_address: the address of the user to check
    - contract_address (str): eth address of the contract
    - chain_id (int): chain to check the contract on
    Returns:
    - score (int): The security score (0-100)
    - contract_info (dict):        
    """
    user_address = request.args.get('user_address', type=str)
    contract_address = request.args.get('contract_address', type=str)
    chain_id = request.args.get('chain', default=1, type=int)
    is_snaps = request.args.get('is_snaps', default=False, type=str)

    #Check if chached results should be provided
    is_snaps = True if is_snaps == "true" else False
    if is_snaps and contract_address in contract_to_score:
        #Retrieve from cache and return
        return contract_to_score[contract_address][0]
    else:
        chain = "mainnet" if chain_id == 1 else "goerli"

        #Calculate new security score
        output = compute_security_score(contract_address, chain)
        if output["status"] != "ok":
            return output

        #Add to the server cache
        contract_to_score[contract_address].append(output)
        user_to_transactions[user_address].append(output)

    return output

The compute_security_score function (in the logic.py file) calculates a heuristic risk score based on on-chain data from Coinbase Cloud APIs, etherscan APIs, and our own community-curated server-side database of reported malicious addresses. A few examples of the type of factors used to compute the score is shown in the snippet below. For example, we check if the contract is declared as verified and audited on etherscan, and how old the contract is.

# in the compute_security_score function:
# ...
verified = is_verified(contract_address, chain)
audited = is_audited(contract_address, chain)
transactions, users, deployed_date_unix = numberOfTransactionsAndUsersAndAge(contract_address)
min_age_of_contract_in_days = (time.time() - deployed_date_unix) / 86400
num_times_reported = blacklist_dict[contract_address]
# ...

In the future, we plan to integrate more sources of information that could help identify malicious contracts (such as automated verification tools and existing blacklist databases), and also employ more nuanced computation of the risk score, for example, using machine learning methods.

The snap

For the snap we use the transactions insights API which is triggered whenever a transaction is happening. The snap consists of four steps. First, the transaction key details are retrieved from the transaction struct. Second, the tx details are send to our server and we retrieve the security score plus metadata. Third, we check the request status and handle any errors. Fourth, we return the security score and metadata as json object within MetaMask Snaps.


export const onTransaction: OnTransactionHandler = async ({
  transaction,
  chainId,
}) => {

  // Get tx data
  const user_address = transaction.from;
  const contract_address =  transaction.to;
  const chain_id =  chainId.split(":")[1];

  // Call api for risk assessment
  const url = 'https://blackbelt.xyz/security_score?contract_address='+contract_address+'&user_address='+user_address+'&chain='+chain_id+'&is_snaps=true';
  let x = await fetch(url);
  let data = await x.json();

  // Cases for returning insights
  if (data.status == "ok"){
    const individual_scores = stringify_json('individual_scores', data)
    const individual_details = stringify_json('contract_info', data)
    return {
      insights: {"Risk Assessment": data.risk_level, "Security Score": data.security_score, "Recommendation": data.recommendation, "Details": individual_details, "Individual Scores": individual_scores, "Assessment Timestamp": data.risk_assessment_timestamp, "IPFS Storage Hash": data.ipfs_hash},
    };
  } else if(data.status =='error, not a contract address'){
    return {
      insights: {"No Score Available": "No interaction with a smart contract detected.", "Assessment Timestamp": data.risk_assessment_timestamp},
    };
  } else if(data.status =='error, unsupported chain'){
    return {
      insights: {"Chain Not Supported": "We are currently supporting Ethereum and Goerli only. We are working on adding more networks."},
    };
  } else {
    return {
      insights: {"Unknown Error": "An unknown error occured. Please contact the team and try again later."},
    };
  }
};

The website

The website is written in react and is used to quickly test our feature before adding it to MetaMask. Users can try our feature by supplying a contract address and pressing “Rate now”. If users like our application, they can add it to their MetaMask by clicking “Add MetaMask Snap” at the top right corner.

JIbf7E2

What are the next steps if you would implement this?

The next steps would be to improve our backend and analytical capabilities to detect risky contracts more reliably. Currently, our assessment is based on heuristic, such as the number of DAU or transactions (the higher the better), but we would like to include some more advanced technique like machine learning to calculate the risk score more accurately, After improving the analytics, we would focus on speeding up the whole risk assessment process to make the user experience as seamless as possible - this could be done through caching or faster data retrieval procedures.

Can you tell us a little bit about yourself and your team?

We are a team consisting of three Oxford PhD students and one Oxford graduate. We are affiliated with the Oxford Blockchain Society and met during the ETHBogota hackathon, where we formed our team.

team photo

Lucas Schneider: Lucas is a DPhil candidate in Computer Science at the University of Oxford focusing on computational and machine learning models to predict gene editing outcomes in CRISPR systems. Before starting his DPhil, Lucas worked as an Analyst at Barclays Investment Bank in London in the Securitised Products Structuring Group where he was involved in multiple esoteric structured credit transactions and financings of non-performing loans and commercial real estate portfolios. He holds an MSc in Finance from the London School of Economics and Political Science and a BA in Economics with a focus on quantitative methods from the Friedrich-Alexander University Erlangen-Nuremberg.

Shreshth Malik: Shreshth is a DPhil candidate in Machine Learning at the University of Oxford focusing on making deep learning methods more robust and reliable to enable more trustworthy real-world applications. He has also worked at a number of AI startups and a london-based seed-stage VC fund. He holds Master’s degrees in Machine Learning (UCL) and Physical Natural Sciences (University of Cambridge).

Paweł Narkiewicz: Paweł is a serial entrepreneur, scientist and technology freak. At the age of 18 he published his first research paper in number theory together with the smartest mathematicians from Stanford and Harvard. One year later, he founded a successful edtech startup to accelerate the technology skills development in Poland. The business became self-financing venture after 3 months. Simultaneously, Pawel joined a medtech startup as an operating shareholder and ML engineer to lead the development of one of the core features of the startup's technology. He directly cooperated with the best researchers from Oxford, Stanford & Harvard. The startup received funding of 770k$ in pre-seed round and 3.2M£ in seed round. He holds Bachelor’s degree in Mathematics and Computer Science from Oxford.

Jessica Pointing: Jessica is pursuing her PhD in Physics at the University of Oxford specialising in quantum computing, and previously was a PhD student in Computer Science at Stanford University as a Knight-Hennessy Scholar. She received her bachelor's degree in Physics and Computer Science at Harvard University with high honors as a John Harvard Scholar, after being a bachelors student at MIT. Jessica was selected for Forbes 30 under 30 in Science and was selected to be the council fellow for the World Economic Forum’s Global Future Council on Quantum Applications. She was selected to be a TEDx speaker and has given keynote talks at tech conferences internationally, include IBM’s Think conference and Oracle Code One conference. She has interned as a quantum researcher at KBR at NASA Ames Research Center, software engineer at Google, management consultant at McKinsey and Company, investment banker at Goldman Sachs, and strategist at Morgan Stanley. Jessica founded the Stanford Quantum Computing Association and the Harvard College Quantum Computing Association. She won the IBM Q Quantum Computing Award for winning, with a team, IBM's first quantum computing hackathon. She was also a prize-winner at the Creative Destruction Lab quantum computing hackathon. Jessica attended ETHAmsterdam, an Ethereum hackathon, and her team won the grand finalist prize as well as sponsor prizes. She has been awarded the McKinsey Women's Impact Award and has been named a Google Anita Borg Scholar. She has also won scholarships from Microsoft, Palantir, Adobe Research, Morgan Stanley, Goldman Sachs, Neo, Society of Women Engineers Scholar and Society of Geophysicists.

When were you first introduced to MetaMask Snaps and what was your experience like?

We got first introduced to MetaMask Snaps at ETHBogota. It was the perfect feature to bring Blackbelt to life in the most user-friendly way. Overall, the experience with MetaMask Snaps was pleasant as MetaMask Snaps are fairly easy to use. Given the novelty of MetaMask Snaps there are still some minor hiccups that occasionally caused us some headache during the hackathon but nothing really major.

What makes MetaMask Snaps different from other wallets?

MetaMask Snaps is a great way to open source the development of wallet extensions and to enable diverse and individual solutions for end-users with different needs. As far as we know - MetaMask is the only wallet provider so far that supports custom plugins.

Tell us about what building Snaps with MetaMask is like for you and your team?

Building with MetaMask Snaps was fairly easy. We started with one of the example projects that helped us to better understand the mechanics of MetaMask Snaps and then build on top of the example code. Building in MetaMask Snaps was fun but occasionally some bugs really challenged us, especially given the tight deadline during the hackathon.

What does MetaMask Snaps mean to you?

MetaMask Snaps is the feature we always wished we had in our wallets. For a developer, it unlocks a wide variety of opportunities for innovation.

What opportunities do you see with MetaMask Snaps and the possibilities it unlocks for the Web3 space?

MetaMask Snaps will enable greater customizability across the whole Web3 ecosystem and thus also improve the overall user experience as users can decide what features they want.

Any advice you would like to share with developers keen to try MetaMask Snaps?

Just play around with MetaMask Snaps. It’s easiest to start with one of the example projects to understand how MetaMask Snaps works and then build on it. If any unknown issues arise, you can always post the issue on the MetaMask Snaps git to get help from the MetaMask Snaps developers.

Building with MetaMask Snaps

To get started with MetaMask Snaps:

  1. Checkout the developer docs
  2. Install MetaMask Flask
  3. Check out a MetaMask Snaps guide
  4. Stay connected with us on Twitter, GitHub discussions, and Discord

Keep an eye out for our team at the next hackathon in an area near you! Happy BUIDLing ⚒️

Disclaimer: MetaMask Snaps are generally developed by third parties other the ConsenSys Software. Use of third-party-developed MetaMask Snaps is done at your own discretion and risk and with agreement that you will solely be responsible for any loss or damage that results from such activities. ConsenSys makes no express or implied warranty, whether oral or written, regarding any third-party-developed MetaMask Snaps and disclaims all liability for third-party developed MetaMask Snaps. Use of blockchain-related software carries risks, and you assume them in full when using MetaMask Snaps.

Receive our Newsletter