IPFS
Every BAMFS root has a canonical IPFS CIDv1, derived identically on-chain and off.
Every BAMFS file and directory has a canonical IPFS CIDv1, computable both
on-chain (IpfsCidResolver) and off-chain (@bamfs/sdk). The two agree
byte-for-byte.
This is not a mirror. Nothing is copied anywhere — it is the address the same content would have on IPFS, which is what lets an independent pin land on an address the chain already knows.
The profile
| Parameter | Value |
|---|---|
| CID version | v1 |
| Multihash | sha2-256 |
| File codec | raw for single-block, dag-pb for multi-block |
| Directory codec | dag-pb |
| Chunk size | 262,144 bytes (256 KiB) |
| DAG shape | Balanced, raw leaves |
| Max links per node | 174 |
| Entry ordering | Lexicographic by name |
| Base encoding | base32, lowercase, unpadded |
These are the IPFS defaults for ipfs add --cid-version=1 --raw-leaves, so the
CID matches what a stock IPFS client produces.
A file that fits in one 256 KiB block is CIDv1(raw, sha256(bytes)). Larger
files fold into a balanced DAG: 256 KiB raw leaves, wrapped in groups of ≤174
links, recursing to a single root.
There is no protocol-level size cap on the resolver. What bounds it is the
eth_call gas budget of the node serving the read — a provider setting, not a
chain one, so the ceiling moves with your endpoint. See
Deployments.
Compression is invisible to it
An IPFS CID is computed over a file's logical bytes. The same content stored compressed and uncompressed yields the same IPFS CID, even though its BAMFS CIDs differ — a BAMFS CID commits to the stored bytes.
The asymmetry runs opposite to intuition:
| Codec | On-chain resolver | Off-chain SDK |
|---|---|---|
none | yes | yes |
fastlz | yes | yes |
gzip, brotli | CompressionNotSupported | yes |
The resolver can inflate exactly the codecs with a Solidity decompressor registered. FastLZ has one. gzip would need DEFLATE with Huffman decoding in Solidity — possible, large, gas-expensive, and not planned.
So a gzip root does have an ordinary IPFS CID; the chain just cannot derive it for you. The SDK, CLI, and web app all do it off-chain. The limit is on-chain decompression, not the protocol and not IPFS.
Addressing the compressed bytes instead would sidestep this, and is
deliberately not done: gateways serve the bytes a CID addresses, so a visitor
would get a .gz file instead of the page.
Pinning
Nothing pins your content automatically. BAMFS runs no pinner. Content resolves from contract storage whether or not it is on IPFS, so pinning is a speed optimisation and never a durability requirement.
The CLI pins and then verifies the result:
bamfs pin --project-id <id> --provider local
bamfs pin --project-id <id> --provider pinata --api-key <JWT>
bamfs pin --project-id <id> --provider web3storage --api-key <key>It reads the tree from chain, pins it, and checks the provider's reported root against the CID BAMFS computed.
By hand, over the same files:
ipfs add -r --cid-version=1 ./your-projectThat reproduces the profile exactly — --cid-version=1 is what implies raw
leaves. Verified against a live project: the importer and the on-chain resolver
return the same CID.
Once pinned, set the project's bamfs.gateway so
the gateway tries your pin before rebuilding from chain.
Checking
bamfs verify <cid> # on-chain and local, compared
bamfs verify <cid> --local # off-chain only, works for gzip roots