Git Product home page Git Product logo

browser-extension's Introduction

Solana Wallet - Browser Extension

Development

yarn install
yarn start

Note You can safely discard the browser page opening on localhost:3000 (we tried to disable it but did not succeed yet)

In this mode, each time you save a file, development server will re-compile the files and you can simply reload to see the changes (no need to unload).

For background page, from the Inspect view, simply hit reload shortcut (⌘-R on Apple, or Ctrl-R). For the popup, either close it and re-open or from Inspect view, hit reload shortcut (same as above).

Add extension to Chrome

Important Unload any previously loaded Solana Wallet extension, only one extension can be loaded at one time.

  • Go to chrome://extensions
  • Enable developer mode
  • Click "Load Unpacked"
  • Browse to this project ./dist, hit select

Open Extensions Pages (Chrome only)

You can open background and popup page (in full view) using simply:

./bin/open_ext.sh <extension_id>

Where <extension_id> is the value reported by Chrome Extension manager for you loaded unpacked extension. To ease your life, you can also define SOLANA_EXTENSION_ID as an enviornment variable and it will be use as the default value for <extension_id> parameter, so you can do ./bin/open_ext.sh.

Production

yarn install
yarn build

Add extension to Chrome

Important Unload any previously loaded Solana Wallet extension, only one extension can be loaded at one time.

  • Go to chrome://extensions
  • Enable developer mode
  • Click "Load Unpacked"
  • Browse to this project ./build, hit select

Configuring IDE

Prettier

This project expects all contributors to have a suitable format on save that uses Prettier config to run.

Follow the links IDE to fromat on save using Prettier:

Enable debug

  • Open chrome dev tools (background, popup or content-script)
  • Go to Application
  • Add a Local Storage entry: Key:debug, Value:*

Disable JS minification

config.optimization.minimize = false in rewire-webex.js

Usage

// @ts-ignore
import bs58 from "bs58"
import { Connection, LAMPORTS_PER_SOL, PublicKey, SystemProgram } from "@solana/web3.js"

type WalletState = {
  state: "locked" | "unlocked" | "uninitialized"
}

type Cluster = {
  title: string
  endpoint: string
  cluster: string
}

window.addEventListener("solana#initialized", function (event) {
  // @ts-ignore
  solana = window.solana
  solana.on("stateChanged", async (state: WalletState) => {
    if (state.state === "unlocked") {
      const { cluster } = await solana.request({ method: "wallet_getCluster", params: {} })
      const connection = new Connection(cluster.endpoint)

      await sendTransaction(connection)
    }
  })
})

async function sendTransaction(connection: Connection) {
  let { accountResult } = await solana.request({ method: "wallet_requestAccounts", params: {} })
  const accounts = accountResult.accounts as string[]

  const transaction = SystemProgram.transfer({
    fromPubkey: new PublicKey(accounts[0]),
    toPubkey: new PublicKey(accounts[0]),
    lamports: 2 * LAMPORTS_PER_SOL,
  })

  const { blockhash } = await connection.getRecentBlockhash()
  transaction.recentBlockhash = blockhash

  const message = bs58.encode(transaction.serializeMessage())
  const { result } = await solana.request({
    method: "wallet_signTransaction",
    params: { message: message, signer: accounts },
  })

  result.signatureResults.forEach((signatureResult: any) => {
    transaction.addSignature(
      new PublicKey(signatureResult.publicKey),
      bs58.decode(signatureResult.signature)
    )
  })

  let transactionID = await connection.sendRawTransaction(transaction.serialize())
  await connection.confirmTransaction(transactionID)
}

First you need to add a window event listener for the event solana#initialized. That event will be triggered when the solana extension is done injecting the solana client into the window object.

window.addEventListener("solana#initialized", function (event) {
  solana = window.solana
})

Once you got access to the solana client, you should fetch the extension state using wallet_getState request.

const { result } = await solana.request({ method: "wallet_getState", params: {} })
if (result.state === "unlocked") {
  // you are now granted to access user accounts
}

When your web application granted with the permission to access users account you can retrieve them using the wallet_requestAccounts request.

let { accountResult } = await solana.request({ method: "wallet_requestAccounts", params: {} })
const accounts = accountResult.accounts as string[]

Use the wallet_getCluster request to get the cluster selected by users and set your solana web3 connection accordenly

const { cluster } = await solana.request({ method: "wallet_getCluster", params: {} })

wallet_signTransaction request is used to sign transaction messages by a list of signer account keys. Signatures need to be added to the transaction from which the message was serialized before being sent as raw using solana web3 connection.

const message = bs58.encode(transaction.serializeMessage())
const { result } = await solana.request({
  method: "wallet_signTransaction",
  params: { message: message, signer: accounts },
})

result.signatureResults.forEach((signatureResult: any) => {
  transaction.addSignature(
    new PublicKey(signatureResult.publicKey),
    bs58.decode(signatureResult.signature)
  )
})

Handling events from extension

stateChanged event is triggered when extension state change (uninitialized | locked | unlocked). Only when state is unlocked then your web application will be able to access the accounts of the user and sign transactions. The state will change to unlocked once the user unlocks is wallet and grant your web application access to is accounts.

solana.on("stateChanged", async (state: WalletState) => {
  if (state.state === "unlocked") {
    // you are now granted to access user accounts
  }
})

The clusterChanged event will happen when cluster configuration is changed by the user in the extension. That’s when you should reset your solana web3 connection.

solana.on("clusterChanged", (cluster: Cluster) => {
  connection = new Connection(cluster.endpoint)
})

The accountsChanged event is triggered when users add or remove accounts from their wallets from the extension. You will then receive an up-to-date list of account public keys encoded in base58

solana.on("accountsChanged", (updatedAccounts: string[]) => {
  accounts = updatedAccounts
})

browser-extension's People

Contributors

jubeless avatar billettc avatar errows avatar fproulx-dfuse avatar abourget avatar ario2mahb avatar

Stargazers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.