
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
Deploy bridge contract or find a bridge from EVM chain -> Jackal
Using Wagmi to connect React to the EVM chain is recommended
npm install wagmi viem@2.x @tanstack/react-query
Configure Wagmi as recommended or use the demo config
Import the hooks useReadContract and useWriteContract
import { useReadContract, useWriteContract } from "wagmi"; const { data, error, isPending, writeContract } = useWriteContract();
Export the ABI for your storage contract (Vyper instructions)
forge inspect [contract name] abi
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], })
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], })
After that, you can call any storage contract function
Here we call
upload
from the example contractawait 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], })
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()); });