# Pera Connect

![View at GitHub - View at NPM - View at Yarn](https://96496224-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4vifTUgliUpqzu4s88gd%2Fuploads%2FmniGRSgqiO23h3KsZjWx%2Fpera-connect.png?alt=media\&token=a758846a-252c-49a5-ad34-8099acdde562)

## What is `@perawallet/connect`?

`@perawallet/connect` is a JavaScript SDK for integrating [**Pera Wallet**](https://perawallet.app/) to web applications. You can use this SDK to connect to a dApp, sign transactions, etc. using [**Pera Wallet**](https://perawallet.app/).

`@perawallet/connect` is maintained by the [**Pera Team**](https://perawallet.app/). For more detailed information you can read this document or the [GitHub readme](https://github.com/perawallet/connect/blob/main/README.md).

Check the [Migrating to @perawallet/connect@1.0.0](https://github.com/perawallet/connect/releases/tag/1.0.0) guide before migrating to V1 or higher.

### Quick Start

Let's look at how we can connect Pera Wallet to our dApp using `**@perawallet/connect**`. We will use React for these examples, but you can also use `**@perawallet/connect**` with other frameworks. For this, you can take a look at the example applications section. Let’s start!

1. **First, install `@perawallet/connect`**

```bash
npm install --save @perawallet/connect
-- or --
yarn add @perawallet/connect
```

After that you can import the SDK into your React app like this using:

```jsx
 import {PeraWalletConnect} from "@perawallet/connect"
```

**2. Create the `PeraWalletConnect` instance:**

```jsx
const peraWallet = new PeraWalletConnect();
```

When creating a new instance, you can use different options:

```tsx
interface PeraWalletConnectOptions {
  shouldShowSignTxnToast?: boolean;
  chainId?: AlgorandChainIDs;
}
```

* **chainId**

  Determines which Algorand network your dApp uses.

  **MainNet**: 416001

  **TestNet**: 416002

  **BetaNet**: 416003

  **All Networks**: 4160

  ```tsx
  type AlgorandChainIDs = 416001 | 416002 | 416003 | 4160;

  const peraWallet = new PeraWalletConnect({
      // Default chainId is "4160"
      chainId: "416001"
  });
  ```
* **shouldShowSignTxnToast**

  ![](https://96496224-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4vifTUgliUpqzu4s88gd%2Fuploads%2FtJYWGDSIsOWr9FYUJqfw%2FGroup%2048096937.png?alt=media\&token=9a7f164e-8a28-45c4-a6f0-956b10fd0376)

It's enabled by default but in some cases, you may not need the toast message (e.g. you already have signing guidance for users). To disable it, use the shouldShowSignTxnToast option:

```jsx
const peraWallet = new PeraWalletConnect({
    shouldShowSignTxnToast: false
});
```

**3. Create connect example button for wallet connection:**

```jsx
function App() {
  // Store account address which is connected dApp with Pera Wallet
  const [accountAddress, setAccountAddress] = (useState < string) | (null > null);
  // Check app is connected with Pera Wallet
  const isConnectedToPeraWallet = !!accountAddress;

  return (
    <button
      onClick={
        isConnectedToPeraWallet ? handleDisconnectWalletClick : handleConnectWalletClick
      }>
      {isConnectedToPeraWallet ? "Disconnect" : "Connect to Pera Wallet"}
    </button>
  );
}
```

**4. Create handler methods for Pera Wallet connection:**

**`handleWalletConnectClick()`**

```typescript
function handleConnectWalletClick() {
    peraWallet
      .connect()
      .then((newAccounts) => {
        // Setup the disconnect event listener
        peraWallet.connector?.on("disconnect", handleDisconnectWalletClick);

        setAccountAddress(newAccounts[0]);
      })
      .reject((error) => {
        // You MUST handle the reject because once the user closes the modal, peraWallet.connect() promise will be rejected.
        // For the async/await syntax you MUST use try/catch
        if (error?.data?.type !== "CONNECT_MODAL_CLOSED") {
          // log the necessary errors
        }
      });
  }

```

**`handleDisconnectWalletClick()`**

```typescript
function handleDisconnectWalletClick() {
   peraWallet.disconnect();
   setAccountAddress(null);
}
```

We use them in the onClick event of the button that we created in the previous step. If there is an account connected to the dApp, we use the `handleDisconnectWalletClick()` function, if there is no account connected, we use the `handleWalletConnectClick()` function.

**5. If you don't want the user's account information to be lost by the dApp when the user closes the browser with with the wallet connection to the dApp, you need to handle the reconnect session status. You can do this in the following way:**

```jsx
useEffect(() => {
    // Reconnect to the session when the component is mounted
    peraWallet.reconnectSession().then((accounts) => {
      // Setup the disconnect event listener
      peraWallet.connector?.on("disconnect", handleDisconnectWalletClick);

      if (peraWallet.isConnected && accounts.length) {
        setAccountAddress(accounts[0]);
      }
    }).catch(error) {
				console.log(error);
			};
  }, []);
```

After these 5 steps, you can use your dApp making new transactions with Pera Wallet 🎊. Your `App.tsx` file will look like this.

```jsx
import {PeraWalletConnect} from "@perawallet/connect";

// Create the PeraWalletConnect instance outside of the component
const peraWallet = new PeraWalletConnect();

function App() {
  const [accountAddress, setAccountAddress] = (useState < string) | (null > null);
  const isConnectedToPeraWallet = !!accountAddress;

  useEffect(() => {
    // Reconnect to the session when the component is mounted
    peraWallet.reconnectSession().then((accounts) => {
      // Setup the disconnect event listener
      peraWallet.connector?.on("disconnect", handleDisconnectWalletClick);

      if (accounts.length) {
        setAccountAddress(accounts[0]);
      }
    });
  }, []);

  return (
    <button
      onClick={
        isConnectedToPeraWallet ? handleDisconnectWalletClick : handleConnectWalletClick
      }>
      {isConnectedToPeraWallet ? "Disconnect" : "Connect to Pera Wallet"}
    </button>
  );

  function handleConnectWalletClick() {
    peraWallet
      .connect()
      .then((newAccounts) => {
        // Setup the disconnect event listener
        peraWallet.connector?.on("disconnect", handleDisconnectWalletClick);

        setAccountAddress(newAccounts[0]);
      })
      .reject((error) => {
        // You MUST handle the reject because once the user closes the modal, peraWallet.connect() promise will be rejected.
        // For the async/await syntax you MUST use try/catch
        if (error?.data?.type !== "CONNECT_MODAL_CLOSED") {
          // log the necessary errors
        }
      });
  }

  function handleDisconnectWalletClick() {
    peraWallet.disconnect();

    setAccountAddress(null);
  }
}
```

#### Using with `React@18`

When you want to use `@perawallet/connect` library with `React 18`, you need to make some changes. `react-scripts` stopped polyfilling some of the packages with the `react-scripts@5.x` version. After creating a new app with `npx create-react-app my-app` or in your react application, the following changes should be made.

1. Firstly, install the following packages

```bash
npm install buffer
npm install crypto-browserify
npm install process
npm install react-app-rewired
npm install stream-browserify
```

2\. After that you need to override some **`webpack`** features. Create the following file in the root directory of the project and copy the following code block into it.

`config-overrides.js`

```jsx
// eslint-disable-next-line @typescript-eslint/no-var-requires
const webpack = require('webpack');

module.exports = function override(config) {
  const fallback = config.resolve.fallback || {};

  Object.assign(fallback, {
    crypto: require.resolve('crypto-browserify'),
    stream: require.resolve('stream-browserify'),
  });
  config.resolve.fallback = fallback;
  // ignore warning about source map of perawallet/connect

  config.ignoreWarnings = [/Failed to parse source map/];
  config.plugins = (config.plugins || []).concat([
    new webpack.ProvidePlugin({
      process: 'process/browser',
      Buffer: ['buffer', 'Buffer'],
    }),
  ]);
  return config;
};
```

3\. You need to update `react-scripts` version to `5.0.1` or higher.

```json
{
    "react-scripts": "5.0.1",
}
```

4\. Finally, you need to update the `npm scripts`.

```json
{
    "start": "react-app-rewired start",
    "build": "react-app-rewired build"
}
```

After that, you are good to go! 🎊

### Methods

```tsx
PeraWalletConnect.connect(): Promise<string[]>
```

* Starts the initial connection flow and returns the array of account addresses.

```tsx
PeraWalletConnect.reconnectSession(): Promise<string[]>
```

* Reconnects to the wallet if there is any active connection and returns the array of account addresses.

```tsx
PeraWalletConnect.disconnect(): Promise<void | undefined>
```

* Disconnects from the wallet and resets the related storage items.

```tsx
PeraWalletConnect.platform: PeraWalletPlatformType
```

* Returns the platform of the active session. Possible responses: *`mobile | web | null`*

```tsx
PeraWalletConnect.isConnected: boolean
```

* Checks if there's any active session regardless of platform. Possible responses: *`true | false`*

```tsx
PeraWalletConnect.signTransaction(txGroups: SignerTransaction[][], signerAddress?: string): Promise<Uint8Array[]>
```

* Starts the sign process and returns the signed transaction in `Uint8Array`

### Signing Transactions

`@perawallet/connect` also allows signing transactions using the Pera Wallet application. Once the `signTransaction` method is triggered, if the user is on a mobile browser, the Pera Wallet app will be launched automatically. If the browser blocks the redirection there's also a popup that links to the Pera Wallet app. There's an option called `shouldShowSignTxnToast` to disable it, see the example below:

```jsx
const peraWallet = new PeraWalletConnect({shouldShowSignTxnToast: false});
```

You can also call the `closePeraWalletSignTxnToast` function to hide the toast.

```jsx
import {closePeraWalletSignTxnToast} from "@perawallet/connect";

// ...Business logic

// Close the toast message
closePeraWalletSignTxnToast();
```

`signTransaction` accepts `SignerTransaction[][]` the type can be find below:

```jsx
import {Transaction} from "algosdk";

export interface SignerTransaction {
  txn: Transaction;
  /**
   * Optional list of addresses that must sign the transactions.
   * Wallet skips to sign this txn if signers is empty array.
   * If undefined, wallet tries to sign it.
   */
  signers?: string[];
}
```

You have to follow these steps to a sign transaction.

1. Set up `algosdk` client

```jsx
const algod = new algosdk.Algodv2("", CLIENT_SERVER_URL, CLIENT_SERVER_PORT);
```

2\. Set up `Transactions`

```jsx
const suggestedParams = await algod.getTransactionParams().do();
const optInTxn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({
  from: FROM_ADDRESS,
  to: FROM_ADDRESS,
  assetIndex: ASSET_ID,
  amount: 0,
  suggestedParams
});
const optInTxn2 = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({
  from: FROM_ADDRESS,
  to: FROM_ADDRESS,
  assetIndex: ASSET_ID,
  amount: 0,
  suggestedParams
});
```

3\. Map `Transaction` to `SignerTransaction[]`

```jsx
const singleTxnGroups = [{txn: optInTxn, signers: [FROM_ADDRESS]}];
const multipleTxnGroups = [
  {txn: optInTxn, signers: [FROM_ADDRESS]},
  {txn: optInTxn2, signers: [FROM_ADDRESS]}
];
```

4\. (Optional step) Create some utility functions to create the transaction before the sign transaction function

**`generateOptIntoAssetTxns({assetID, initiatorAddr})`**

```typescript
async function generateOptIntoAssetTxns({
  assetID,
  initiatorAddr
}: {
  assetID: number;
  initiatorAddr: string;
}): Promise<SignerTransaction[]> {
  const suggestedParams = await algod.getTransactionParams().do();
  const optInTxn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({
    from: initiatorAddr,
    to: initiatorAddr,
    assetIndex: assetID,
    amount: 0,
    suggestedParams
  });

  return [{txn: optInTxn, signers: [initiatorAddr]}];
}

generatePaymentTxns({to, initiatorAddr})

async function generatePaymentTxns({
  to,
  initiatorAddr
}: {
  to: string;
  initiatorAddr: string;
}) {
  const suggestedParams = await algod.getTransactionParams().do();

  const txn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
    from: initiatorAddr,
    to,
    amount: 1,
    suggestedParams
  });

  return [{txn, signers: [initiatorAddr]}];
}
```

**`generateAssetTransferTxns({to, assetID, initiatorAddr})`**

```jsx
async function generateAssetTransferTxns({
  to,
  assetID,
  initiatorAddr
}: {
  to: string;
  assetID: number;
  initiatorAddr: string;
}) {
  const suggestedParams = await algod.getTransactionParams().do();

  const txn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({
    from: initiatorAddr,
    to,
    assetIndex: assetID,
    amount: 1,
    suggestedParams
  });

  return [{txn, signers: [initiatorAddr]}];
}
```

5\. After this, you can sign a single transaction or group transaction using promises

**Single Transaction**

```jsx
try {
  const signedTxn = await peraWallet.signTransaction([singleTxnGroups]);
} catch (error) {
  console.log("Couldn't sign Opt-in txns", error);
}
```

**Group Transaction**

```jsx
try {
  const signedTxns = await peraWallet.signTransaction([multipleTxnGroups]);
} catch (error) {
  console.log("Couldn't sign Opt-in txns", error);
}
```

**Payment Transactions**

```jsx
const txGroups = await generatePaymentTxns({
	to: "GD64YIY3TWGDMCNPP553DZPPR6LDUSFQOIJVFDPPXWEG3FVOJCCDBBHU5A",
  initiatorAddr: accountAddress!
});

try {
  const signedTxnGroup = await peraWallet.signTransaction([txGroups]);
  const {txId} = await algod.sendRawTransaction(signedTxnGroup).do();
} catch (error) {
  console.log("Couldn't sign payment txns",error);
}
```

**Asset Transfer Transactions**

```jsx
const txGroups = await generateAssetTransferTxns({
  to: "GD64YIY3TWGDMCNPP553DZPPR6LDUSFQOIJVFDPPXWEG3FVOJCCDBBHU5A",
  assetID: 10458941,
  initiatorAddr: accountAddress!
});

try {
  const signedTxnGroup = await peraWallet.signTransaction([txGroups]);
  console.log(signedTxnGroup);
  
  const {txId} = await algod.sendRawTransaction(signedTxnGroup).do();
} catch (error) {
  console.log("Couldn't sign asset transfer txns",error);
}
```

**Opt-In Asset Transactions**

```jsx
const txGroups = await generateOptIntoAssetTxns({
  assetID: 10458941,
  initiatorAddr: accountAddress!
});

try {
  await peraWallet.signTransaction([txGroups]);
} catch (error) {
  console.log("Couldn't sign Opt-in txns",error);
}
```

**Multiple Transactions**

```jsx
const optinTxGroups = await generateOptIntoAssetTxns({
  assetID: 10458941,
  initiatorAddr: accountAddress!
});
const transferTxGroups = await generateAssetTransferTxns({
  to: "GD64YIY3TWGDMCNPP553DZPPR6LDUSFQOIJVFDPPXWEG3FVOJCCDBBHU5A",
  assetID: 10458941,
  initiatorAddr: accountAddress!
 });

try {
  const signedTxnGroups = await peraWallet.signTransaction([
    optinTxGroups,
    transferTxGroups
  ]);

  console.log(signedTxnGroups);

  // Sign every txn in the group
  for (const signedTxnGroup of signedTxnGroups) {
    const {txId} = await algod.sendRawTransaction(signedTxnGroup).do();

    console.log(`txns signed successfully! - txID: ${txId}`);
  }
} catch (error) {
  console.log("Couldn't sign all txns",error);
}
```

### Customization

`@perawallet/connect` lets you UI change a few things based on your dApp's needs.

1. Change **Pera Wallet Connect Modal** `z-index` to avoid conflicts

```scss
.pera-wallet-modal {
    // The default value of z-index is 10. You can lower and raise it as much as you want.
    z-index: 11;
}
```

2\. Remove **Sign Guidance Toast**

```jsx
const peraWallet = new PeraWalletConnect({
    shouldShowSignTxnToast: false
});
```

3\. Close **Sign Guidance Toast**

```jsx
import {closePeraWalletSignTxnToast} from "@perawallet/connect";

// ...Business logic

// Close the toast message
closePeraWalletSignTxnToast();
```

4\. Your app name on `Pera Wallet`

By default, the connect wallet drawer on **Pera Wallet** gets the app name from `document.title`

In some cases, you may want to customize it. You can achieve this by adding a meta tag to your HTML between the `head` tag.

```html
<meta name="name" content="My dApp" />
```

### Example Applications

* [Using React Hooks](https://codesandbox.io/s/perawallet-connect-react-demo-zlvokc)
* [Using React Hooks with React@18](https://codesandbox.io/s/perawallet-connect-react-18-demo-tig2md)
* [Using Vue3](https://codesandbox.io/s/perawallet-connect-vue3-demo-yiyw4b)
* [Using Svelte](https://codesandbox.io/s/perawallet-connect-svelte-demo-ys1m4x)
* [Using Next.js](https://codesandbox.io/s/perawallet-connect-next-js-demo-ryhbdb)
* [Using Nuxt.js](https://codesandbox.io/s/perawallet-connect-nuxt-js-demo-s65z58)
* [Vanilla JS](https://codesandbox.io/s/perawallet-connect-vanillajs-demo-s5pjeo)

### **Brand Guidelines**

Please follow our brand guidelines when using `@perawallet/connect` in your dApp. To download our Media Kit that includes useful assets such as the official Pera logo, App images, roadmap, and official links, please visit our [website](https://perawallet.app/media-kit/).
