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:
Permanent Storage with One-Time Payment: Once data is uploaded and paid for, it remains permanently stored. No recurring fees required!
Blockweave Structure: Unlike the linear structure of traditional blockchains, Arweave uses a "blockweave" which allows more efficient data access and validation.
SPoRA (Succinct Proofs of Random Access): Miners must prove they can access randomly selected past data, ensuring stored data remains available and verifiable.
Data Permanence and Availability: Arweave is designed to "never forget." Data is permanently stored and protected from tampering.
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
Then, connect to the local Arweave gateway:
const arweave = require("arweave").init({ port: 4000 });
To connect to the mainnet, use the default settings:
const arweave = require("arweave").init();
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) };
};
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..."
}
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);
};
Example usage:
const { jwk, addr } = await gen();
const balance = await mint(addr, "10.0");
console.log(`New wallet balance: ${balance} AR`);
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);
};
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}`);
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);
};
Example usage:
const txid = await saveMD("# This is markdown", jwk);
console.log(`Saved markdown TX ID: ${txid}`);
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}`);
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];
};
Example usage:
const tx = await getTx(txid);
console.log(tx);
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());
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
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 };
};
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}`);
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.