DEV Community

KYOHEI ITO for Arweave Japan

Posted on

Arweave AO Bootcamp 3/8 Arweave Fundamentals

What You'll Learn in This Chapter

In this chapter, you'll learn the fundamentals of Arweave and how to interact with it.
Arweave is a blockchain-based decentralized storage protocol that enables truly permanent data storage — once uploaded, your data lives on forever.

This section lays the foundational skills you’ll need to build AO applications on top of Arweave.

By the end of this chapter, you’ll be able to:

  • Understand Arweave's core architecture (Blockweave, SPoRA, and more)
  • Connect to a local Arweave gateway and generate wallets
  • Mint and send AR tokens, and check wallet balances
  • Save arbitrary data (text, images) to Arweave
  • Use GraphQL to query and retrieve transaction metadata
  • Bundle and nest transactions for scalable batch processing

Mastering these basics will give you a concrete understanding of how to design and build robust data layers for decentralized applications.

Arweave Fundamentals

Arweave as Decentralized Storage

Arweave is a blockchain-based decentralized storage network that enables the "Permaweb." Unlike traditional blockchains or storage systems, Arweave has several unique features:

  1. Permanent Storage with One-Time Payment: Once data is uploaded and paid for, it remains permanently stored. No recurring fees required!

  2. Blockweave Structure: Unlike the linear structure of traditional blockchains, Arweave uses a "blockweave" which allows more efficient data access and validation.

  3. SPoRA (Succinct Proofs of Random Access): Miners must prove they can access randomly selected past data, ensuring stored data remains available and verifiable.

  4. Data Permanence and Availability: Arweave is designed to "never forget." Data is permanently stored and protected from tampering.

  5. Economic Sustainability: Through its endowment mechanism, Arweave leverages decreasing storage costs over time to support long-term data persistence.

Thanks to these features, Arweave is especially suitable for archiving, censorship-resistant content, and preserving long-term historical records.

Connecting to the Arweave Gateway

First, install the Arweave JavaScript library:

npm i arweave
Enter fullscreen mode Exit fullscreen mode

Then, connect to the local Arweave gateway:

const arweave = require("arweave").init({ port: 4000 });
Enter fullscreen mode Exit fullscreen mode

To connect to the mainnet, use the default settings:

const arweave = require("arweave").init();
Enter fullscreen mode Exit fullscreen mode

Creating an Arweave Wallet

Arweave accounts use RSA key pairs. Wallet addresses are SHA-256 hashes of public keys and are 43 characters long. Keys are usually generated in JWK format:

const addr = async (jwk) => arweave.wallets.jwkToAddress(jwk);

const gen = async () => {
  const jwk = await arweave.wallets.generate();
  return { jwk, addr: await addr(jwk) };
};
Enter fullscreen mode Exit fullscreen mode

A generated JWK will look like this:

{
  "kty": "RSA",
  "n": "o1kvT...",
  "e": "AQAB",
  "d": "Ohpdn...",
  "p": "ymLt9...",
  "q": "zp7X_...",
  "dp": "pyN6W...",
  "dq": "wkpHn....",
  "qi": "Zvbxf..."
}
Enter fullscreen mode Exit fullscreen mode

Here, n is the public key, and d is the private key. The other fields (p, q, dp, dq, qi) are used to optimize cryptographic operations.

Minting AR Tokens

In local environments (ArLocal), AR tokens can be minted freely. Note that you must manually call the /mine API to confirm transactions.

const mine = async () => await arweave.api.get(`/mine`);

const bal = async (addr) => {
  return arweave.ar.winstonToAr(await arweave.wallets.getBalance(addr));
};

const mint = async (addr, amount = "1.0") => {
  await arweave.api.get(`/mint/${addr}/${arweave.ar.arToWinston(amount)}`);
  await mine();
  return await bal(addr);
};
Enter fullscreen mode Exit fullscreen mode

Example usage:

const { jwk, addr } = await gen();
const balance = await mint(addr, "10.0");
console.log(`New wallet balance: ${balance} AR`);
Enter fullscreen mode Exit fullscreen mode

Sending AR Tokens

The basic flow for sending tokens involves createTransaction, sign, and post. For a transfer, specify target and quantity:

const postTx = async (tx, jwk) => {
  await arweave.transactions.sign(tx, jwk);
  await arweave.transactions.post(tx);
  await mine();
  return tx.id;
};

const transfer = async (amount, to, jwk) => {
  let tx = await arweave.createTransaction({
    target: to,
    quantity: arweave.ar.arToWinston(amount),
  });
  return await postTx(tx, jwk);
};
Enter fullscreen mode Exit fullscreen mode

Example usage:

const { addr: addr1, jwk } = await gen();
const { addr: addr2 } = await gen();
await mint(addr1, "1.0");
const txid = await transfer("0.5", addr2, jwk);
console.log(`Transfer transaction ID: ${txid}`);
Enter fullscreen mode Exit fullscreen mode

Saving Data

You can save raw data to Arweave directly. Here's an example of saving Markdown text:

const saveMD = async (md, jwk) => {
  let tx = await arweave.createTransaction({ data: md });
  tx.addTag("Content-Type", "text/markdown");
  return await postTx(tx, jwk);
};
Enter fullscreen mode Exit fullscreen mode

Example usage:

const txid = await saveMD("# This is markdown", jwk);
console.log(`Saved markdown TX ID: ${txid}`);
Enter fullscreen mode Exit fullscreen mode

To save image data (like base64-encoded SVG):

const saveSVG = async (svg, jwk) => {
  let tx = await arweave.createTransaction({
    data: Buffer.from(svg, "base64"),
  });
  tx.addTag("Content-Type", "image/svg+xml");
  return await postTx(tx, jwk);
};

const ao = "<base64-encoded-SVG>";
const txid = await saveSVG(ao, jwk);
console.log(`Saved SVG TX ID: ${txid}`);
Enter fullscreen mode Exit fullscreen mode

Querying Transactions with GraphQL

One of Arweave's strongest features is its ability to tag transactions and query them with GraphQL:

const q = (txid) => `query {
  transactions(ids: ["${txid}"]) {
    edges {
      node { id tags { name value } owner { address } }
    }
  }
}`;

const getTx = async (txid) => {
  const json = await fetch("http://localhost:4000/graphql", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ query: q(txid) }),
  }).then((r) => r.json());
  return json.data.transactions.edges.map((v) => v.node)[0];
};
Enter fullscreen mode Exit fullscreen mode

Example usage:

const tx = await getTx(txid);
console.log(tx);
Enter fullscreen mode Exit fullscreen mode

To retrieve the actual data:

// Using arweave.js
const data = await arweave.transactions.getData(txid, {
  decode: true,
  string: true,
});

// Using HTTP request
const data = await fetch(`http://localhost:4000/${txid}`).then((r) => r.text());
Enter fullscreen mode Exit fullscreen mode

Nesting and Bundling Transactions

Using the ANS-104 Bundled Data v2.0 spec, Arweave allows multiple transactions to be nested and bundled into a single one:

npm i arbundles
Enter fullscreen mode Exit fullscreen mode
const { ArweaveSigner, bundleAndSignData, createData } = require("arbundles");

const bundle = async (_items, jwk) => {
  const signer = new ArweaveSigner(jwk);
  const items = _items.map((v) => {
    let tags = [];
    for (const k in v[1] || {}) tags.push({ name: k, value: v[1][k] });
    return createData(v[0], signer, { tags });
  });
  const bundle = await bundleAndSignData(items, signer);
  const tx = await bundle.toTransaction({}, arweave, jwk);
  await postTx(tx, jwk);
  return { items, tx };
};
Enter fullscreen mode Exit fullscreen mode

Example usage:

const { items, tx } = await bundle(
  [
    ["# This is markdown!", { Content_Type: "text/markdown" }],
    [Buffer.from(ao, "base64"), { Content_Type: "image/svg+xml" }],
  ],
  jwk
);
console.log(`Bundled transaction ID: ${tx.id}`);
Enter fullscreen mode Exit fullscreen mode

This bundling feature is one of the core underpinnings of the AO protocol.

Top comments (0)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.