Skip to content

Cypher-Laboratory/Alice-s-Ring-snap

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Metamask Snap for SAG and LSAG signatures

Overview

This simple snap uses our SAG and LSAG implementation to sign a message with a keypair generated by Metamask. The message is signed in the snap and then can be verified in the browser, in a backend or onChain.

More about ring signatures here.

Features

  • Create an ethereum account
  • Import an ethereum account using a mnemonic
  • export the snap addresses
  • sign a message using LSAG with the snap

Installation & usage

Here are some function you can use to install and interact with the snap:

Note: The snap is not yet published on the snap store, so you need to install in the development application: metamask Flask Make sure you only have 1 version of metamask installed, otherwise they will compete and you will not be able to use the snap.

We also created a toolkit to ease your interaction with the snap. You can check it out here. it can be installed from npmjs: npm i @cypher-laboratory/alicesring-snap-sdk or yarn add @cypher-laboratory/alicesring-snap-sdk

import detectEthereumProvider from '@metamask/detect-provider';

const PACKAGE_NAME = '@cypher-laboratory/alicesring-snap';

declare global {
  interface Window {
    ethereum?: any; // Use `any` if you don't have a specific type to use
  }
}

export async function installSnap(): Promise<boolean> {
  // This resolves to the value of window.ethereum or null
  const provider: any = await detectEthereumProvider();

  // web3_clientVersion returns the installed MetaMask version as a string
  const isFlask = (
    await provider?.request({ method: 'web3_clientVersion' })
  )?.includes('flask'); // todo: once snap allowed by metamask, remove this check

  if (provider && isFlask) {

    try {
      // install snap
      await window.ethereum.request({
        "method": "wallet_requestSnaps",
        "params": {
          [`npm:${PACKAGE_NAME}`]: {},
        }
      });
      console.log('MetaMask Flask & airdrop claimer SNAP successfully detected!');
    } catch (error) {
      console.error(`Error while installing ${PACKAGE_NAME}`);
    }

    // check if snap is installed
    if (!detectPrivateClaimSnap()) {
      console.error('Snap not installed. Please try again.');
      return false;
    }
    return true;
  } else {
    console.error('Please install MetaMask flask first');
    return false;
  }
};


export async function detectPrivateClaimSnap(): Promise<boolean> {
  const provider: any = await detectEthereumProvider();
  const snaps = await provider?.request({
    method: 'wallet_getSnaps'
  });

  const isMySnapInstalled = Object.keys(snaps).includes(`npm:${PACKAGE_NAME}`);

  if (isMySnapInstalled) {
    // console.log('privateClaim Snap is installed');
    return true;
  } else {
    // console.log('privateClaim Snap is not installed');
    return false
  }

}

// generate new account: "newAccount"
export async function generateAccount() {
  try {
    await window.ethereum.request({
      method: 'wallet_invokeSnap',
      params: {
        snapId: `npm:${PACKAGE_NAME}`,
        request: {
          method: "newAccount",
        },
      },
    });
    // alert('Account generated successfully!');
  } catch (error) {
    console.error('Error while generating account');
    return false;
  }
  return true;
}

// import account: "importAccount"
export async function importAccount(): Promise<boolean> {
  try {
    await window.ethereum.request({
      method: 'wallet_invokeSnap',
      params: {
        snapId: `npm:${PACKAGE_NAME}`,
        request: {
          method: "importAccount",
          // params,
        },
      },
    });
    // console.log('account:', account);
    // alert('Account imported successfully!');
  } catch (error) {
    console.error('Error while importing account');
    return false;
  }
  return true;
}

// get addresses of all accounts: "getAddresses"
export async function getAddresses(): Promise<string[]> {
  try {
    const addresses = await window.ethereum.request({
      method: 'wallet_invokeSnap',
      params: {
        snapId: `npm:${PACKAGE_NAME}`,
        request: {
          method: "getAddresses",
          // params,
        },
      },
    });
    console.log('addresses:', JSON.parse(addresses).addresses);
    return JSON.parse(addresses).addresses;
  } catch (error) {
    console.error('Error while getting addresses');
    return [];
  }
}

// lsag sign message: "LSAG_signature"
export async function LSAG_signature(ring: string[], message: string, addressToUse: string, linkabilityFlag: string): Promise<string> {
  try {
    const signature = await window.ethereum.request({
      method: 'wallet_invokeSnap',
      params: {
        snapId: `npm:${PACKAGE_NAME}`,
        request: {
          method: "LSAG_Signature",
          params: {
            ring,
            message,
            addressToUse,
            linkabilityFlag,
          },
        },
      },
    });
    console.log('signature:', signature);
    // alert('Message signed successfully!');
    return signature;
  } catch (error) {
    console.error('Error while signing message');
    return '';
  }
}

// lsag sign message: "LSAG_signature"
export async function PAC_LSAG_Signature(ring: string[], claim_contract_address: string, addressToUse: string, airdropTier: string, chainId: string): Promise<string> {
  try {
    const signature = await window.ethereum.request({
      method: 'wallet_invokeSnap',
      params: {
        snapId: `npm:${PACKAGE_NAME}`,
        request: {
          method: "PrivateAirdropClaim_LSAG_Signature",
          params: {
            ring,
            claim_contract_address,
            addressToUse,
            airdropTier,
            chainId,
          },
        },
      },
    });
    console.log('signature:', signature);
    // alert('Message signed successfully!');
    return signature;
  } catch (error) {
    console.error('Error while signing message');
    return '';
  }
}

export async function exportKeyImages(addresses: string[], linkabilityFlag: string): Promise<{ address: string, keyImage: string, linkabilityFlag: string }[] | null> {
  try {
    const keyImages = await window.ethereum.request({
      method: 'wallet_invokeSnap',
      params: {
        snapId: `npm:${PACKAGE_NAME}`,
        request: {
          method: "ExportKeyImages",
          params: {
            addresses,
            linkabilityFactor: linkabilityFlag,
          },
        },
      },
    });
    // console.log('keyImage:', JSON.parse(addresses).addresses);
    return keyImages;

  } catch (error) {
    console.error('Error while getting addresses');
    return null;
  }
}

// sag sign message: "SAG_signature"
export async function SAG_signature(ring: string[], message: string, addressToUse: string): Promise<string> {
  try {
    const signature = await window.ethereum.request({
      method: 'wallet_invokeSnap',
      params: {
        snapId: `npm:${PACKAGE_NAME}`,
        request: {
          method: "SAG_Signature",
          params: {
            ring,
            message,
            addressToUse,
          },
        },
      },
    });
    console.log('signature:', signature);
    // alert('Message signed successfully!');
    return signature;
  } catch (error) {
    console.error('Error while signing message');
    return '';
  }
}

About

No description, website, or topics provided.

Resources

License

Apache-2.0, MIT-0 licenses found

Licenses found

Apache-2.0
LICENSE.APACHE2
MIT-0
LICENSE.MIT0

Stars

Watchers

Forks

Releases

No releases published

Sponsor this project

Packages

No packages published