# Jackal.js | Jackal Chain Docs
Implements Jacakl.js-protos

Skip to main content

# Jackal.js

Implements Jacakl.js-protos

Full method documentation

## Quickstart​

To get started using Jackal in the browser, you'll need a few things!

### Pre-requesites​

- Nodejs v20+
- Vue.js or React
- Jackal.js
- Vite
- Chromium-family browser (Chrome, Brave, Edge, etc)
- Keplr or Leap wallet extension

### Setting Up​

To get started, make sure you start your project using Vite. If you have an existing React app for example, re-init the project using Vite.

Install dependencies:

    npm create vite@latest
    npm install @jackallabs/jackal.js-protos @cosmjs/proto-signing
    npm install -D vite-plugin-node-stdlib-browser

Jackal.js requires Node v20+. The easiest way to manage this is with NVM.

    nvm use 20

#### Updating Vite Config​

    // In vite.config.js:
    import { defineConfig } from 'vite'
    import nodePolyfills from 'vite-plugin-node-stdlib-browser'

    export default defineConfig({
      plugins: [
        nodePolyfills()
      ],
    })

### Connecting Your Wallet​

Custom chain configurations are required for Testnet, and for Keplr on Mainnet. The following are the correct options to use. Jackal.js additionally supports app-level overrides to the chain default settings. This requires some redundancy, but allows for greater flexibility in projects.

#### Wallet Selection​

Currently Jackal,js supports Keplr and Leap wallets. Only a single wallet can be used at any time, but you can switch between them as desired.

    const selectedWallet = 'keplr'
    // OR
    const selectedWallet = 'leap'

#### Testnet Configuration​

    const chainConfig = {
      chainId: 'lupulella-2',
      chainName: 'Jackal Testnet II',
      rpc: 'https://testnet-rpc.jackalprotocol.com',
      rest: 'https://testnet-api.jackalprotocol.com',
      bip44: {
        coinType: 118
      },
      coinType: 118,
      stakeCurrency: {
        coinDenom: 'JKL',
        coinMinimalDenom: 'ujkl',
        coinDecimals: 6
      },
      bech32Config: {
        bech32PrefixAccAddr: 'jkl',
        bech32PrefixAccPub: 'jklpub',
        bech32PrefixValAddr: 'jklvaloper',
        bech32PrefixValPub: 'jklvaloperpub',
        bech32PrefixConsAddr: 'jklvalcons',
        bech32PrefixConsPub: 'jklvalconspub'
      },
      currencies: [
        {
          coinDenom: 'JKL',
          coinMinimalDenom: 'ujkl',
          coinDecimals: 6
        }
      ],
      feeCurrencies: [
        {
          coinDenom: 'JKL',
          coinMinimalDenom: 'ujkl',
          coinDecimals: 6,
          gasPriceStep: {
            low: 0.002,
            average: 0.002,
            high: 0.02
          }
        }
      ],
      features: []
    }

    const appConfig = {
      signerChain: 'lupulella-2',
      enabledChains: ['lupulella-2'],
      queryAddr: 'https://testnet-grpc.jackalprotocol.com',
      txAddr: 'https://testnet-rpc.jackalprotocol.com'
    }

#### Mainnet Configuration​

    const chainConfig = {
      chainId: 'jackal-1',
      chainName: 'Jackal Mainnet',
      rpc: 'https://rpc.jackalprotocol.com',
      rest: 'https://api.jackalprotocol.com',
      bip44: {
        coinType: 118
      },
      coinType: 118,
      stakeCurrency: {
        coinDenom: 'JKL',
        coinMinimalDenom: 'ujkl',
        coinDecimals: 6
      },
      bech32Config: {
        bech32PrefixAccAddr: 'jkl',
        bech32PrefixAccPub: 'jklpub',
        bech32PrefixValAddr: 'jklvaloper',
        bech32PrefixValPub: 'jklvaloperpub',
        bech32PrefixConsAddr: 'jklvalcons',
        bech32PrefixConsPub: 'jklvalconspub'
      },
      currencies: [
        {
          coinDenom: 'JKL',
          coinMinimalDenom: 'ujkl',
          coinDecimals: 6
        }
      ],
      feeCurrencies: [
        {
          coinDenom: 'JKL',
          coinMinimalDenom: 'ujkl',
          coinDecimals: 6,
          gasPriceStep: {
            low: 0.002,
            average: 0.002,
            high: 0.02
          }
        }
      ],
      features: []
    }

    const appConfig = {
      signerChain: 'jackal-1',
      enabledChains: ['jackal-1'],
      queryAddr: 'https://grpc.jackalprotocol.com',
      txAddr: 'https://rpc.jackalprotocol.com'
    }

#### Bringing the full config together​

    const finalWalletConfig = {
      selectedWallet,
      ...appConfig,
      chainConfig
    }
    // Hooking up the wallet to your app
    const wallet = await WalletHandler.trackWallet(finalWalletConfig)

Additionally, a query-only mode for the wallet can get accessed via the following:

    const wallet = await WalletHandler.trackQueryWallet('https://grpc.jackalprotocol.com') // Use the gRPC-web address of your choice

### Buying Storage Space​

Every account that wishes to use the Jackal Protocol to store data needs to have a paid storage account. This means giving the protocol $8 USD per month per tb. We can do this with Jackal.js!

    const storage = await StorageHandler.trackStorage(wallet)
    // (Wallet address)
    // duration in months (min 1)
    // space in terabytes (min .001)
    // 2 TB for 1 year:
    await storage.buyStorage(WALLET_ADDRESS, 12, 2)

### Creating a Root Folder​

    const minimumProviderVersion = '1.0.9'
    const fileIo = await FileIo.trackIo(wallet, minimumProviderVersion)
    const listOfRootFolders = ["Home", ...]
    // you can create as many root folders as you would like this way. Home is the Jackal Dashboard default root directory.
    // The first time a user connects, they must init the system
    const storage = await StorageHandler.trackStorage(wallet)
    const msg = storage.makeStorageInitMsg()
    await fileIo.generateInitialDirs(msg, listOfRootFolders)
    // after the first time, this code can be used instead. this will only create new root folders if they don't already exist
    const newFolderCount = await fileIo.verifyFoldersExist(listOfRootFolders)

### Creating a Child Folder​

    const fileIo = await FileIo.trackIo(wallet)
    const parentFolderPath = PARENT_FOLDER_NAME_AND_PATH // for example Dashboard's root folder path is s/Home
    const parent = await fileIo.downloadFolder(parentFolderPath)
    const listOfChildFolders = ["Movies", "Pictures", ...]
    await fileIo.createFolders(parent, listOfChildFolders)

### Uploading a File​

    const fileIo = await FileIo.trackIo(wallet)
    const parentFolderPath = PARENT_FOLDER_NAME_AND_PATH // for example Dashboard's root folder path is s/Home
    const parent = await fileIo.downloadFolder(parentFolderPath)
    const file = FILE_OBJECT // this MUST be an instance of File() that is in the browser memory
    const fileName = file.name
    const handler = await FileUploadHandler.trackFile(file, parentFolderPath)
    const uploadList = {}
    uploadList[fileName] = {
      data: null,
      exists: false,
      handler: handler,
      key: fileName,
      uploadable: await handler.getForUpload()
    }
    await fileIo.staggeredUploadFiles(uploadList, parent, {counter: 0, complete: 0})

### Downloading a File​

    const fileIo = await FileIo.trackIo(wallet)
    /* optional */
    const parentFolderPath = PARENT_FOLDER_NAME_AND_PATH // for example Dashboard's root folder path is s/Home
    const parent = await fileIo.downloadFolder(parentFolderPath)
    const childrenFiles = parent.getChildFiles()
    const pathOfFirstChild = parent.getMyChildPath(childrenFiles[0].name)
    /* end optional */
    const downloadDetails = {
      rawPath: FILE_PATH, // manual complete file path OR pathOfFirstChild
      owner: OWNER_ADDRESS, // JKL address of file owner
      isFolder: false
    }
    const fileHanlder = await fileIo.downloadFile(downloadDetails, {track: 0})
    const file = fileHanlder.receiveBacon()
    // do what you want with the File object returned by receiveBacon