EVM (BASE) Outpost Quickstart

Jackal Outposts are smart contracts that allow other blockchains to connect to the Jackal data layer.

Note: Jackal EVM Outposts are currently available only on BASE mainnet network.

Jackal Outposts are in an open beta state. Please be aware that this documentation might change.

Quickstart

  1. Deploy bridge contract or find a bridge from EVM chain -> Jackal

  2. Using Wagmi to connect React to the EVM chain is recommended

    npm install wagmi viem@2.x @tanstack/react-query
    
  3. Configure Wagmi as recommended or use the demo config

  4. Import the hooks useReadContract and useWriteContract

    import { useReadContract, useWriteContract } from "wagmi";
    
    
    const { data, error, isPending, writeContract } = useWriteContract();
    
  5. Locate the ABI for the bridge contract ( RootABI here)

  6. Export the ABI for your storage contract (Vyper instructions)

    forge inspect [contract name] abi
    
  7. Check if the user already has an allowance set with useReadContract

    const {refetch, data, isFetched} = useReadContract({
        abi: [bridge contract abi],
        address: [bridge contract address],
        functionName: 'getAllowance',
        args: [[storage contract address], [user address]], // keep outer brackets 
        chainId: [network id],
    })
    
  8. If not, set an allowance for the user using writeContract

    await writeContract({
        abi: [bridge contract abi],
        address: [bridge contract address],
        functionName: 'addAllowance',
        args: [[storage contract address]], // keep outer brackets 
        chainId: [network id],
    })
    
  9. After that, you can call any storage contract function

  10. Here we call upload from the example contract

    await writeContract({
        abi: [storage contract abi],
        address: [bridge contract address],
        functionName: 'upload',
        args: [[file content], [file size]], // keep outer brackets 
        value: [user fee to contract],
        chainId: [network id],
    })
    
  11. Now you can use typescript to interact directly with Jackal.

    import { Merkletree } from "@jackallabs/dogwood-tree";
    
    
    // Builds dogwood tree from file
    // react ex:
    // const [file, setFile] = useState<File>(new File([""], ""));
    const tree = await Merkletree.grow({
        seed: await file.arrayBuffer(),
        chunkSize: 10240,
        preserve: false,
    });
    const root = tree.getRootAsHex();
    
    
    // Create a new WebSocket connection
    const socket = new WebSocket("wss://rpc.jackalprotocol.com/websocket");
    
    
    // Open websocket connection to RPC node
    socket.addEventListener("open", (event) => {
        const subscriptionMessage = JSON.stringify({
            jsonrpc: "2.0",
            method: "subscribe",
            id: "1",
            params: {
                query: `tm.event='Tx' AND post_file.file='${root}'`,
            },
        });
        socket.send(subscriptionMessage);
    });
    
    
    // Listen for the EVM chain -> Jackal tx
    socket.addEventListener("message", async (event) => {
        const data = JSON.parse(event.data);
        if (Object.keys(data.result).length == 0) {
            return;
        }
    
    
        // URL of provider we upload to
        const url = "https://mprov01.jackallabs.io/upload"; 
        // view all of them (https://api.jackalprotocol.com/jackal/canine-chain/storage/active_providers)
    
    
        // Build our FormData object
        const formData = new FormData();
        formData.append("file", file);
        formData.append("sender", data.result.events["post_file.signer"][0]);
        formData.append("merkle", root);
        formData.append("start", data.result.events["post_file.start"][0]);
    
    
        // Upload file to provider
        const request = new Request(url, {
            method: "POST",
            body: formData,
        });
    
    
        // Handle the response
        const response = await fetch(request);
        if (!response.ok) {
            throw new Error(`Upload failed with status: ${response.status}`);
        }
        console.log(response.json());
    });