# Getting Started

First, make sure you have installed the Pali Wallet extension (opens new window) in your browser.

Once the extension is installed you should be able to see two specfics methods in your browser console: window.pali and window.ethereum. All functions detailed in "EVM ContentScripts" and "UTXO ContentScripts" window should now be available.

TIP

Make sure that once the wallet is connected that you are actually on Syscoin Testnet. Use it to test all methods availables without spending your funds.

# Building Extension locally

To build the extension on your computer, first, clone the code from our Github page (opens new window) or access it on the top right corner of this page.

Once you have cloned it to your desired directory, the files should be organized similar as follows:

│
├── docs
├── tests
├── manifest.json
├── node_modules
├── package.json
├── source
├── tsconfig.json
├── views
├── webpack.config.js
└── yarn.lock
.
.
.
.

At your directory root, run the following command:

yarn install

This command might take a couple of minutes to complete. For the current version of this project, it is expected that your node version is at 12.0 or higher. If it is not, here is a guide for updating NodeJS (opens new window).

When yarn install has completed, run

yarn run dev:chrome

This command should work if you are using chrome-based browsers (e.g. brave, chrome, chromium). Otherwise, examine the package.json file to see what other browsers are supported. For example, dev:firefox should work on firefox.

Wait for the extension to be fully running. Once it has completed (if you're in doubt you can check at the generated build folder if there is a directory with the name of your targeted mode), go to the extensions page on your browser (i.e. chrome://extensions). On the top right corner, you should see a toogle buttom for developer mode option; toggle it ON. There should now be, at the top left corner, a button load unpacked ; click it and set the path as your_path/pali_wallet/build/chrome . Now you should see the extension installed in your browser.

You can now use, enjoy or customise further the multiple pali features for UTXO and EVM chains. Next, we will learn how to build your first application and test the wallet functions.

# Building your first DApp

TIP

All of the considerations below follow up closely on a test App that is available at Pollum labs repository (opens new window). Please feel free to download it and try to play with it locally.

The first important piece of information is that our test App is built on top of React. Therefore, the useState and useEffect hooks can be directly imported in this fashion:

import { useEffect, useState, useCallback } from "react";

Since we're working with React, you can declare useState variables and function. Some of these are especially relevant for this example:

const [PaliUtxoProvider, setPaliUtxoProvider] = useState(null);
const [PaliEvmProvider, setPaliEvmProvider] = useState(null);
const [isInstalled, setIsInstalled] = useState(false);

To begin, we will use the useEffect hook and, inside it, we will verify if Pali is installed in the client browser correctly and set the provider for dApp-Pali interaction:

const App = () => {
    ...
    ...
    ...
    useEffect(() => {
        if (window.pali && window.ethereum) {
            setPaliUtxoProvider(window.pali);
            setPaliEvmProvider(window.ethereum);
            setIsInstalled(true);
            console.log('Pali was installed successfully. Providers are set.')
        } else console.log('Not installed');
    }, [])

       return (
          <>
            ...output
            ...
            ...
            ...
          </>
      )
};

There is a lot to get from this small snippet; let's do that one step at a time. Now buckle up, we're goint into details of how the code above works and an idea of what the output can be:

The first part is related to useEffect hook and its functionality in the way it is structured (If you're in doubt React docs (opens new window)) have awesome explanations for the pattern being applied here. But it basically runs at component mount and check if pali is installed. That is the first thing that will run once the DApp is online.

What is happening in the background here:

The extension injects the Pali script into all open pages in the browser (your DApp included). When this happens, the window.pali and window.ethereum methods become available. If the extension is installed correctly and those methods are available, setIsInstalled will be true, and setPaliUtxoProvider and setPaliEvmProvider will be set with the methods available in window.pali and window.ethereum, respectively.

If successful, the isInstalled variable will be set to true and "Pali was installed successfully" will print to the console. Furthermore, we define the paliUtxoProvider and paliEvmProvider variables as our actual window.pali and window.ethereum methods for wallet functions. So now, if you wish to call the functions in window.pali or window.ethereum you can simply use the following:

paliUtxoProvider.function();

or

paliEvmProvider.function();

Otherwise, if the connection is not established (e.g. the Pali Wallet Extension is not installed, and window.pali/window.ethereum returns undefined), the console simply prints "Not installed". If this is the case, then simply try to reinstall the extension or reload the webpage.

Finally, your dApp will be able to interact with Pali and use all methods availables from the extension providers.

The output should be your UI with the design, buttons, and logic that you want additionally for any web3 or UTXO interaction, you can rely on pali providers accessible through paliEvmProvider and paliUtxoProvider. One could replace the output in the above code to something like:

return (
  <div className="app">
    <h2 className="app__title">Pali Wallet demo</h2>
    <div className="app__actions">
      <button
        className="app__button"
        disabled={!isInstalled}
        onClick={handleConnectWallet}
      >
        Connect/Change wallet
      </button>

      <button
        className="app__button"
        onClick={handleMakeSomething}
        disabled={!controller || !connectedAccount}
      >
        Make something
      </button>
    </div>
  </div>
);

It should be clear for Javascript users that these are simply buttons that execute certain functions that modify variables when clicked. Let's clarify how these functions can look by demonstrating a case example.

# Testing functions on your DApp

Now that we have checked if the extension is installed, let's take the next step; provide a button to connect our wallet. We can define exactly what our buttons do.

To connect the wallet one simply has to call:

For UTXO dApps:

await paliUtxoProvider.request({ method: "sys_requestAccounts", params: [] });

For EVM dApps:

await paliEvmProvider.request({ method: "eth_requestAccounts", params: [] });

This function should create a pop-up from the extension that will ask user approval and which account he desires to connect. Note that if the user reject the request or you ask to connect to EVM provider on a UTXO chain or vice-versa the response you be receiving will be errors and you must be prepared to handle those. You may realize, by checking the Wallet functions that paliUtxoProvider/paliEvmProvider are actually async() calls and waits on a Promise, so a better way to call it, would be through:

const handleConnectWallet = async (event, type) => {
  event.preventDefault();

  switch (type) {
    case "utxo":
      if (paliUtxoProvider)
        await paliUtxoProvider.request({
          method: "sys_requestAccounts",
          params: [],
        });
      break;
    case "evm":
      if (paliEvmProvider)
        await paliEvmProvider.request({
          method: "eth_requestAccounts",
          params: [],
        });
      break;
    default:
      break;
  }
};

You should now be able to connect the wallet within your DApp. Also, according with the way our buttons are defined, once the wallet is connected, a test button should appear. When the button is used it will call whichever function you have defined inside its scope:

const handleMakeSomething = async () => {
  if (yourPreferedProvider) {
    await yourPreferredProvider.function();
  }
};

# Example 1: Retrieving an Array with the wallet address.

The provider methods paliEvmProvider.request({method:'eth_requestAccounts'}) and paliUtxoProvider.request({method:'sys_requestAccounts'}) should return an array with the current account address, so we can also call these methods on our test button to get a value and modify the variables we have already declared. Since we now have a button for testing functions, the following snippet is an example on how to retrieve an Array (in this case, result), and further how to pick its return and have it saved on your dApp state (just as Pegasys displays your address on the top right corner). We can modify the handleConnectWallet function created in the last example to set the current wallet address connected in your dApp.

const [connectedAccount, setConnectedAccount] = useState("");

const handleConnectWallet = async (event, type) => {
  event.preventDefault();

  switch (type) {
    case "utxo":
      if (paliUtxoProvider) {
        const address = await paliUtxoProvider.request({
          method: "sys_requestAccounts",
          params: [],
        });
        setConnectedAccount(address);
      }
      break;
    case "evm":
      if (paliEvmProvider) {
        const address = await paliEvmProvider.request({
          method: "eth_requestAccounts",
          params: [],
        });
        setConnectedAccount(address);
      }
      break;
    default:
      break;
  }

  console.log(`connected account address: ${connectedAccount}}`);
};

your console output should look something like this

For UTXO dApps:

connected account address: sys1qcwpazhvtn4m3g0nue20r2e4hls78ycmwds9xvx

For EVM dApps:

connected account address: 0x...

# Example 2: Sending a Transaction

To send a transaction directly from your script, you could refactor the handleMakeSomething function as:

const handleMakeSomething = async () => {
  const evmTx = {
    from: connectedAccount,
    to: "0x0c54FcCd2e384b4BB6f2E405Bf5Cbc15a017AaFb",
    value: "0x0",
    gasLimit: "0x5028",
    gasPrice: "0x2540be400",
    type: "0x0",
  };

  if (paliEvmProvider) {
    await paliEvmProvider.request({
      method: "eth_sendTransaction",
      params: [evmTx],
    });
  }
};

This function call should create a pop-up that will ask the user to confirm/approve the transaction you created.