Irys in the Browser

Overview

The Irys SDK minimizes dependency bloat by offering dedicated packages for each token. Installation statements, import code, and connection procedures vary based on the payment token and provider selection.

Note
Note
If you're using Irys with React, follow the React setup steps. If you're using Irys with Vite, follow the Vite setup steps.

EVM Chains

When connecting from EVM chains, connection code differs based on token selection. The following examples use Ethereum with the WebEthereum class.

TokenClass Name
EthereumWebEthereum
PolygonWebMatic
Binance CoinWebBNB
Avalanche C-ChainWebAvalanche
Base EthereumWebBaseEth
USDC (Ethereum)WebUSDCEth
ArbitrumWebArbitrum
ChainlinkWebChainlink
USDC (Polygon)WebUSDCPolygon
BerachainWebBera
Scroll EthereumWebScrollEth
Linea EthereumWebLineaEth
IoTeXWebIotex

Ethers v5

Installation:

npm install \
    @irys/web-upload \
    @irys/web-upload-ethereum \
    ethers@5

Importing and configuring:

import { WebUploader } from "@irys/web-upload";
import { WebEthereum } from "@irys/web-upload-ethereum";

const getIrysUploader = async () => {
  const provider = new ethers.providers.Web3Provider(window.ethereum);
  const irysUploader = await WebUploader(WebEthereum).withProvider(provider);

  return irysUploader;
};

Ethers v6

Installation:

npm install \
    @irys/web-upload \
    @irys/web-upload-ethereum \
    @irys/web-upload-ethereum-ethers-v6 \
    ethers@6

Importing and configuring:

import { WebUploader } from "@irys/web-upload";
import { WebEthereum } from "@irys/web-upload-ethereum";
import { EthersV6Adapter } from "@irys/web-upload-ethereum-ethers-v6";
import { ethers } from "ethers";

const getIrysUploader = async () => {
  const provider = new ethers.BrowserProvider(window.ethereum);
  const irysUploader = await WebUploader(WebEthereum).withAdapter(EthersV6Adapter(provider));

  return irysUploader;
};

Viem v2

Installation:

npm install \
    @irys/web-upload \
    @irys/web-upload-ethereum \
    @irys/web-upload-ethereum-viem-v2 \
    viem

Importing and configuring:

import { WebUploader } from "@irys/web-upload";
import { WebEthereum } from "@irys/web-upload-ethereum";
import { ViemV2Adapter } from "@irys/web-upload-ethereum-viem-v2";

const getIrysUploader = async () => {
  const [account] = await window.ethereum.request({ method: "eth_requestAccounts" });

  const provider = createWalletClient({
    account,
    chain: sepolia,
    transport: custom(window.ethereum),
  });

  const publicClient = createPublicClient({
    chain: sepolia,
    transport: custom(window.ethereum),
  });

  const irysUploader = await WebUploader(WebEthereum).withAdapter(ViemV2Adapter(provider, { publicClient }));

  return irysUploader;
};

Solana

Installation:

npm install \
    @irys/web-upload \
    @irys/web-upload-solana \
    @solana/wallet-adapter-base \
    @solana/wallet-adapter-react \
    @solana/wallet-adapter-react-ui \
    @solana/wallet-adapter-wallets \
    @solana/web3.js

ClientProviders Setup

Create a top-level file named ClientProviders.tsx:

"use client";

import { ReactNode, useMemo } from "react";
import { ConnectionProvider, WalletProvider } from "@solana/wallet-adapter-react";
import { WalletAdapterNetwork } from "@solana/wallet-adapter-base";
import { UnsafeBurnerWalletAdapter } from "@solana/wallet-adapter-wallets";
import { WalletModalProvider } from "@solana/wallet-adapter-react-ui";
import { clusterApiUrl } from "@solana/web3.js";

require("@solana/wallet-adapter-react-ui/styles.css");

export default function ClientProviders({ children }: { children: ReactNode }) {
  const network = WalletAdapterNetwork.Devnet;

  const endpoint = useMemo(() => clusterApiUrl(network), [network]);
  const wallets = useMemo(
    () => [new UnsafeBurnerWalletAdapter()],
    [network]
  );

  return (
    <ConnectionProvider endpoint={endpoint}>
      <WalletProvider wallets={wallets} autoConnect>
        <WalletModalProvider>
          {children}
        </WalletModalProvider>
      </WalletProvider>
    </ConnectionProvider>
  );
}

Layout Setup

Load the ClientProviders component via layout.tsx:

import type { Metadata } from "next";
import ClientProviders from "@/app/components/ClientProviders";
import { Inter } from "next/font/google";
const inter = Inter({ subsets: ["latin"] });

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <ClientProviders>
          {children}
        </ClientProviders>
      </body>
    </html>
  );
}

Wallet Connection Component

Create a wallet connection component ConnectSolana.tsx:

"use client";

import React, { useEffect, useState } from "react";
import { WalletMultiButton, WalletDisconnectButton } from "@solana/wallet-adapter-react-ui";

import "@solana/wallet-adapter-react-ui/styles.css";

const ConnectSolana: React.FC = () => {
  const [isClient, setIsClient] = useState(false);

  // Prevent hydration errors by ensuring this runs only on the client side
  useEffect(() => {
    setIsClient(true);
  }, []);

  if (!isClient) {
    return null;
  }

  return (
    <div className="border-2 border-primary rounded-2xl p-4 w-full max-w-md">
      {/* Solana wallet connect button */}
      <div className="mr-5">
        <WalletMultiButton />
      </div>
      {/* Solana wallet disconnect button */}
      <div className="ml-5">
        <WalletDisconnectButton />
      </div>
    </div>
  );
};

export default ConnectSolana;

Irys Connection Component

Create an Irys connection component ConnectIrys.tsx:

"use client";

import { useState } from "react";
import { useWallet } from "@solana/wallet-adapter-react";
import { WebUploader } from "@irys/web-upload";
import { WebSolana } from "@irys/web-upload-solana";

const getIrysUploader = async (wallet: any) => {
  try {
    const irysUploader = await WebUploader(WebSolana).withProvider(wallet);

    return irysUploader;
  } catch (error) {
    console.error("Error connecting to Irys:", error);
    throw new Error("Error connecting to Irys");
  }
};

const ConnectIrys = (): JSX.Element => {
  const wallet = useWallet();
  const [isConnected, setIsConnected] = useState<boolean>(false);

  const connectToIrys = async () => {
    if (!wallet) {
      console.log("Wallet not connected");
      return;
    }

    try {
      const irysUploader = await getIrysUploader(wallet);
      console.log(`Connected to Irys from ${irysUploader.address}`);
      setIsConnected(true);
    } catch (error) {
      console.log("Error connecting to Irys");
    }
  };

  return (
    <div>
      <button onClick={connectToIrys}>
        {isConnected ? "Connected to Irys" : "Connect Irys"}
      </button>
    </div>
  );
};

export default ConnectIrys;

Page Setup

Load the components through page.tsx:

import Image from "next/image";
import ConnectSolana from "./components/ConnectSolana";
import ConnectIrys from "./components/ConnectIrys";

export default function Home() {
  return (
    <main className="flex min-h-screen flex-col justify-around items-center p-24 bg-black">
      <ConnectSolana />
      <ConnectIrys />
    </main>
  );
}

Aptos

Start with scaffolding:

npx create-aptos-dapp

Package installation:

npm install \
    @irys/web-upload \
    @irys/web-upload-aptos \
    axios

App.tsx Configuration

import React, { useState } from "react";
import { useWallet } from "@aptos-labs/wallet-adapter-react";
import { WebUploader } from "@irys/web-upload";
import { WebAptos } from "@irys/web-upload-aptos";

import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Header } from "@/components/Header";

function App() {
  const { connected } = useWallet();
  const wallet = useWallet();
  const [irysStatus, setIrysStatus] = useState("Not connected");

  const connectIrys = async () => {
    console.log("connect irys called");
    console.log({ wallet });
    try {
      const irysUploader = await WebUploader(WebAptos).withProvider(wallet);
      console.log({ irysUploader });

      setIrysStatus(`Connected to Irys: ${irysUploader.address}`);
    } catch (error) {
      console.error("Error connecting to Irys:", error);
      setIrysStatus("Error connecting to Irys");
    }
  };

  return (
    <>
      <Header />
      <div className="flex items-center justify-center flex-col">
        <Card className="mt-6">
          <CardHeader>
            {connected ? (
              <CardTitle>
                <button onClick={connectIrys}>
                  {irysStatus === "Not connected" ? "Connect Irys" : irysStatus}
                </button>
              </CardTitle>
            ) : (
              <CardTitle>To get started, connect a wallet</CardTitle>
            )}
          </CardHeader>
        </Card>
      </div>
    </>
  );
}

export default App;

Vite Configuration

Install polyfill packages:

npm install --save-dev \
    crypto-browserify \
    stream-browserify \
    os-browserify \
    path-browserify \
    vite-plugin-node-polyfills

Update vite.config.js:

import path from "path";
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { nodePolyfills } from "vite-plugin-node-polyfills";

export default defineConfig({
  plugins: [
    react(),
    nodePolyfills({
      globals: {
        Buffer: true,
        global: true,
        process: true,
      },
      protocolImports: true,
    }),
  ],
  resolve: {
    alias: {
      crypto: "crypto-browserify",
      stream: "stream-browserify",
      os: "os-browserify/browser",
      path: "path-browserify",
      "@": path.resolve(__dirname, "./frontend"),
    },
  },
  build: {
    outDir: "dist",
  },
  server: {
    open: true,
  },
});

After configuration, restart the development server with npm run dev.