# Getting Started (DApp)

# Setup

First, you need to install the beacon-sdk package.

npm install --save @airgap/beacon-sdk

# Introduction and concept

The beacon-sdk handles almost everything for you. It detects whether or not a browser extension is installed, tracks what connections have been established and the accounts that have been shared.

Generally, you only have to initialize a DAppClient instance (see below), the rest should be handled for you.

There are some corner cases that are hard to detect, for example when the wallet is changed or an account is removed in the wallet. Please refer to the FAQ to read more about how to handle these cases. The Security page outlines additional security considerations.

# Permission Request

After that you need to import the Beacon SDK in your code and initialize the DAppClient.

import { ErrorResponse, DAppClient, PermissionResponseOutput } from '..' // Replace '..' with '@airgap/beacon-sdk'

const client = new DAppClient({ name: 'My Sample DApp' })

client
  .requestPermissions()
  .then((response: PermissionResponseOutput) => {
    console.log('permissions', response)
  })
  .catch((permissionError: ErrorResponse) => console.error(permissionError))

Ther permission request only has to be done once. When a successful permission response is received, the permissions are stored locally and will be re-used later.

# Setting the network

By default, permission will be requested on mainnet. This can be changed by providing a network in the permission request.

// Mainnet
const permissionResponse = await client.requestPermissions()

// Mainnet with different rpcUrl
const permissionResponse = await client.requestPermissions({
  network: {
    type: NetworkType.MAINNET,
    rpcUrl: 'https://mainnet-tezos.giganode.io/'
  }
})

// Delphinet with default rpcUrl
const permissionResponse = await client.requestPermissions({
  network: {
    type: NetworkType.DELPHINET
  }
})

// Delphinet with different rpcUrl
const permissionResponse = await client.requestPermissions({
  network: {
    type: NetworkType.DELPHINET,
    rpcUrl: 'https://testnet-tezos.giganode.io/'
  }
})

// Custom network (eg. local development)
const permissionResponse = await client.requestPermissions({
  network: {
    type: NetworkType.CUSTOM,
    name: 'Local Node',
    rpcUrl: 'http://localhost:8732/'
  }
})

When using type MAINNET, DELPHINET or EDONET, the block explorer links will point towards a working block explorer to check your transactions. When using type CUSTOM, there is currently no working block explorer available.

Please note that ALL properties (type, name, rpcUrl) have to match in order to use existing permissions. If you change any of the properties, the permissions will not be found anymore and you have to do a new permission request.

import {
  ErrorResponse,
  DAppClient,
  Network,
  NetworkType,
  PermissionScope,
  TezosOperationType,
  OperationResponseOutput,
  PermissionResponseOutput,
  PartialTezosTransactionOperation
} from '..' // Replace '..' with '@airgap/beacon-sdk'

const client = new DAppClient({ name: 'My Sample DApp' })

const network: Network = {
  type: NetworkType.CUSTOM,
  name: 'MyLocalNetwork',
  rpcUrl: 'http://localhost:8888/'
}

const scopes: PermissionScope[] = [
  PermissionScope.OPERATION_REQUEST,
  PermissionScope.SIGN,
  PermissionScope.THRESHOLD
]

client
  .requestPermissions({
    network,
    scopes
  })
  .then(async (permissionResponse: PermissionResponseOutput) => {
    if (
      permissionResponse.scopes.some(
        (permission: PermissionScope) => permission === PermissionScope.OPERATION_REQUEST
      )
    ) {
      const operation: PartialTezosTransactionOperation = {
        kind: TezosOperationType.TRANSACTION,
        amount: '1234567',
        destination: 'tz1MJx9vhaNRSimcuXPK2rW4fLccQnDAnVKJ'
      }
      const operationResponse: OperationResponseOutput = await client.requestOperation({
        operationDetails: [operation]
      })

      console.log(
        'operation was successfully broadcast to the network with the hash: ',
        operationResponse.transactionHash
      )
    }
  })
  .catch((permissionError: ErrorResponse) => console.error(permissionError))

# Other

The beacon-sdk will automatically try to establish a connection.

If a chrome extension is detected, all requests will be directed to the chrome extension.

If no chrome extension is detected, it will fall back to the beacon p2p transport layer, which means that a QR code is shown that has to be scanned by a compatible wallet. As of now, the only mobile wallet with Beacon supprt is AirGap Wallet. You can download the app from Github or the Play Store (Android) or the AppStore (iOS).

More complex examples can be found here

# Using a different blockexplorer

You can configure the beacon-sdk to use a blockexplorer other than tezblock.io.

import {
  BlockExplorer,
  DAppClient,
  ErrorResponse,
  PermissionResponseOutput,
  NetworkType,
  Network
} from '..' // Replace '..' with '@airgap/beacon-sdk'

class TzStatsBlockExplorer extends BlockExplorer {
  constructor(
    public readonly rpcUrls: { [key in NetworkType]: string } = {
      [NetworkType.MAINNET]: 'https://tzstats.com/',
      [NetworkType.DELPHINET]: 'https://delphi.tzstats.com/',
      [NetworkType.EDONET]: 'https://edo.tzstats.com/',
      [NetworkType.CUSTOM]: 'https://edo.tzstats.com/'
    }
  ) {
    super(rpcUrls)
  }

  public async getAddressLink(address: string, network: Network): Promise<string> {
    const blockExplorer = await this.getLinkForNetwork(network)

    return `${blockExplorer}/${address}`
  }
  public async getTransactionLink(transactionId: string, network: Network): Promise<string> {
    const blockExplorer = await this.getLinkForNetwork(network)

    return `${blockExplorer}/${transactionId}`
  }
}

const client = new DAppClient({ name: 'My Sample DApp', blockExplorer: new TzStatsBlockExplorer() })

client
  .requestPermissions()
  .then((response: PermissionResponseOutput) => {
    console.log('permissions', response)
  })
  .catch((permissionError: ErrorResponse) => console.error(permissionError))
Last Updated: 2/3/2021, 5:43:54 PM