# 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
andwindow.ethereum
methods become available. If the extension is installed correctly and those methods are available,setIsInstalled
will betrue
, andsetPaliUtxoProvider
andsetPaliEvmProvider
will be set with the methods available inwindow.pali
andwindow.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.