@xenea-dacs/sdk
v0.2.0
Published
Xenea Decentralized Autonomous Contents Storage (DACS) client SDK
Maintainers
Readme
@xenea-dacs/sdk
Version: v0.2.0 — Last updated: 2026-04-03
JavaScript/TypeScript SDK for Xenea DACS — Decentralized Autonomous Contents Storage on the Xenea blockchain.
Upload files to IPFS and register their CIDs on-chain in one step.
Installation
npm install @xenea-dacs/sdk
# or
yarn add @xenea-dacs/sdk
# or
bun add @xenea-dacs/sdkGetting Started
You'll need an API key. Contact the Xenea team to register your contract and receive one.
Core Client
Works in both browser and Node.js.
import { DACSClient } from '@xenea-dacs/sdk';
const client = new DACSClient({
endpoint: 'https://ipfs.xenea.io',
apiKey: 'your-api-key',
timeoutMs: 30_000, // optional, default 30000ms
});Upload
const file = new File(['hello world'], 'hello.txt', { type: 'text/plain' });
const result = await client.upload(file);
console.log(result.cid); // QmXxx...
console.log(result.name); // hello.txt
console.log(result.size); // 11Download
const blob = await client.download('QmXxx...');List files
Returns files uploaded under your API key, sorted newest first.
const files = await client.list();
// [{ cid, filename, size, uploadedAt }, ...]Health check
const health = await client.health();
// { status: 'ok', ipfs: { connected: true }, xenea: { connected: true, chainId: '0x448' } }Quota
Returns storage and daily request usage for the current API key.
const quota = await client.quota();
// {
// contractAddress: '0x...',
// storage: { usedBytes, usedGB, limitGB, remaining },
// requests: { today, limitDay },
// fileSizeLimitMB: 100,
// }Error handling
All methods throw an Error with the server's error message on non-2xx responses.
| HTTP Status | Meaning |
|---|---|
| 401 | Missing or invalid API key |
| 403 | File belongs to a different contract |
| 413 | File too large or storage quota exceeded |
| 429 | Daily request limit exceeded |
| 500 | Internal server / IPFS error |
try {
const result = await client.upload(file);
} catch (err) {
console.error(err.message); // e.g. "Quota exceeded: daily request limit reached"
}Framework-Agnostic: uploadAndRegister()
Works in any environment — Node.js scripts, Vue, Svelte, Angular, Deno, and more.
Uses viem WalletClient + PublicClient directly (no React required).
import { DACSClient, uploadAndRegister } from '@xenea-dacs/sdk';
import { createWalletClient, createPublicClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
const gatewayUrl = process.env.DACS_ENDPOINT; // e.g. https://ipfs.xenea.io
const apiKey = process.env.DACS_API_KEY;
const rpcUrl = process.env.XENEA_RPC_URL; // e.g. https://rpc-ubusuna.xeneascan.com
const privateKey = process.env.DEPLOYER_PRIVATE_KEY as `0x${string}`;
const CONTRACT = '0x56Cf33F7DDE7727FdBe43ECcf7AEbC4d08a59987';
const client = new DACSClient({ endpoint: gatewayUrl, apiKey });
const account = privateKeyToAccount(privateKey);
const walletClient = createWalletClient({ account, transport: http(rpcUrl) });
const publicClient = createPublicClient({ transport: http(rpcUrl) });
const file = new Blob(['hello world'], { type: 'text/plain' });
const result = await uploadAndRegister(client, walletClient, publicClient, CONTRACT, file, 'hello.txt');
console.log(result.cid); // QmXxx...
console.log(result.txHash); // 0x... (null if already registered)
console.log(result.alreadyRegistered); // false (true = file was already safely stored)Returns:
| Field | Type | Description |
|---|---|---|
| cid | string | IPFS CID of the uploaded file |
| txHash | Hash \| null | On-chain transaction hash. null if already registered |
| receipt | TransactionReceipt \| null | Receipt once confirmed. null if already registered |
| alreadyRegistered | boolean | true means file was already safely stored — treated as success |
| uploadResult | UploadResult | Full IPFS upload response |
React/wagmi users: Use
useDACSUploadfrom@xenea-dacs/sdk/wagmiinstead.
React Hooks
import { useDACSClient, useUpload, useFiles, useDownload, useHealth } from '@xenea-dacs/sdk/react';useUpload
function UploadButton() {
const client = useDACSClient({ endpoint: 'https://ipfs.xenea.io', apiKey: 'your-api-key' });
const { upload, uploading, result, error } = useUpload(client);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file) upload(file);
};
return (
<div>
<input type="file" onChange={handleChange} disabled={uploading} />
{uploading && <p>Uploading...</p>}
{result && <p>CID: {result.cid}</p>}
{error && <p>Error: {error}</p>}
</div>
);
}useFiles
function FileList() {
const client = useDACSClient({ endpoint: 'https://ipfs.xenea.io', apiKey: 'your-api-key' });
const { files, loading, refresh } = useFiles(client);
return (
<ul>
{files.map(f => <li key={f.cid}>{f.filename} — {f.cid}</li>)}
</ul>
);
}useDownload
function DownloadButton({ cid, filename }: { cid: string; filename: string }) {
const client = useDACSClient({ endpoint: 'https://ipfs.xenea.io', apiKey: 'your-api-key' });
const { download, downloading } = useDownload(client);
return (
<button onClick={() => download(cid, filename)} disabled={downloading}>
{downloading ? 'Downloading...' : 'Download'}
</button>
);
}useHealth
Polls /health every 30 seconds by default.
function StatusBadge() {
const client = useDACSClient({ endpoint: 'https://ipfs.xenea.io', apiKey: 'your-api-key' });
const { health } = useHealth(client);
return <span>{health?.status === 'ok' ? '✅ Online' : '⚠️ Degraded'}</span>;
}Gas Fees
| Operation | Gas Required | Notes |
|---|---|---|
| client.upload() | No | IPFS storage is off-chain |
| register() on-chain | Yes | Requires TXENE on testnet |
| getEntry(), isRegistered(), getUploadsByAddress() | No | Read-only view calls |
Uploading a file to IPFS via the SDK is free. Registering a CID on-chain via useDACSUpload or calling register() directly requires a small amount of TXENE to pay for the transaction.
wagmi Integration (React + on-chain registration)
Requires wagmi >= 2 and viem >= 2.
import { useDACSUpload, useDACSEntry, useDACSUploads, DACS_REGISTRY_ABI } from '@xenea-dacs/sdk/wagmi';useDACSUpload
Uploads to IPFS and registers the CID on-chain in a single call.
const CONTRACT = '0x56Cf33F7DDE7727FdBe43ECcf7AEbC4d08a59987';
function UploadAndRegister() {
const client = useDACSClient({ endpoint: 'https://ipfs.xenea.io', apiKey: 'your-api-key' });
const { upload, step, cid, txHash, error } = useDACSUpload(client, CONTRACT);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file) upload(file);
};
return (
<div>
<input type="file" onChange={handleChange} disabled={step !== 'idle'} />
{step === 'uploading' && <p>Uploading to IPFS...</p>}
{step === 'registering' && <p>Sending transaction...</p>}
{step === 'confirming' && <p>Waiting for confirmation...</p>}
{step === 'done' && <p>Done! CID: {cid}</p>}
{step === 'error' && <p>Error: {error}</p>}
</div>
);
}Steps: idle → uploading → registering → confirming → done
useDACSEntry
Read a single on-chain entry by CID.
const { entry } = useDACSEntry(CONTRACT, 'QmXxx...');
// entry: { cid, filename, size, uploadedAt, uploader }useDACSUploads
Get all CIDs registered by a wallet address.
const { cids } = useDACSUploads(CONTRACT, '0xYourAddress');DACS_REGISTRY_ABI
The full ABI for the DACSRegistry contract, exported for direct use with viem or wagmi.
import { DACS_REGISTRY_ABI } from '@xenea-dacs/sdk/wagmi';Xenea Chain Config
import { defineChain } from 'viem';
export const xenea = defineChain({
id: 1096,
name: 'Xenea Testnet',
nativeCurrency: { name: 'TXENE', symbol: 'TXENE', decimals: 18 },
rpcUrls: { default: { http: ['https://rpc-ubusuna.xeneascan.com'] } },
});Limits (Testnet)
| Resource | Default Limit | |---|---| | Storage per contract | 200 GB | | Max file size | 100 MB | | Requests per day | 1,000 |
These are the default limits for the testnet. All limits are tunable server-side via environment variables.
Contract Addresses
| Network | Contract | Address |
|---|---|---|
| Xenea Testnet (Chain ID 1096) | DACSRegistry | 0x56Cf33F7DDE7727FdBe43ECcf7AEbC4d08a59987 |
API Endpoint
| Environment | URL |
|---|---|
| Testnet | https://ipfs.xenea.io |
