
Security News
Re-Enabled GitHub Actions Expose Thousands of Repositories to Mini Shai-Hulud
Two compromised GitHub Actions were re-enabled with malicious tags intact, exposing thousands of downstream repositories to Mini Shai-Hulud.
@datafund/swarm-provenance
Advanced tools
TypeScript SDK for Swarm Provenance - store and retrieve provenance data via the Swarm network
TypeScript SDK for storing and retrieving provenance data via the Swarm network.
# From GitHub (current)
pnpm add datafund/swarm_provenance_SDK
# From npm (coming soon)
pnpm add @datafund/swarm-provenance
import { ProvenanceClient } from '@datafund/swarm-provenance';
const client = new ProvenanceClient();
// Upload data
const result = await client.upload('Hello, World!', {
standard: 'my-provenance-v1',
});
console.log('Uploaded:', result.reference);
// Download data
const downloaded = await client.download(result.reference);
console.log('Content:', new TextDecoder().decode(downloaded.file));
import { ChainClient, fromPrivateKey } from '@datafund/swarm-provenance/chain';
// Read-only (no wallet needed)
const chain = new ChainClient({ chain: 'base-sepolia' });
const exists = await chain.verifyOnChain(contentHash);
const record = await chain.getDataRecord(contentHash);
// With wallet (browser)
import { fromEip1193Provider } from '@datafund/swarm-provenance/chain';
const signer = await fromEip1193Provider(window.ethereum);
const chain = new ChainClient({ chain: 'base-sepolia', signer });
const result = await chain.anchor(contentHash, 'dataset');
// With private key (Node.js)
const signer = await fromPrivateKey('0x...', 'https://sepolia.base.org');
const chain = new ChainClient({ chain: 'base-sepolia', signer });
await chain.anchor(contentHash, 'dataset');
upload() and download() methods handle the full workflowfetchProvenanceClientconst client = new ProvenanceClient({
gatewayUrl?: string, // default: https://provenance-gateway.datafund.io
timeout?: number, // default: 30000ms
});
const result = await client.upload(content, {
sign?: 'notary', // Enable notary signing
standard?: string, // Provenance standard identifier
stampId?: string, // Use existing stamp (skip pool)
poolSize?: 'small' | 'medium' | 'large', // Pool size preset
contentType?: string, // Content type
});
// Returns:
// {
// reference: string, // Swarm hash
// metadata: ProvenanceMetadata,
// signedDocument?: SignedDocument,
// }
const result = await client.download(reference, {
verify?: boolean, // Verify notary signature (default: true)
});
// Returns:
// {
// file: Uint8Array, // Decoded content
// metadata: ProvenanceMetadata,
// verified?: boolean,
// signatures?: NotarySignature[],
// }
// Health check
await client.health(); // => boolean
// Notary info
await client.notaryInfo();
// => { enabled: boolean, available: boolean, address?: string }
// Pool status
await client.poolStatus();
// => { enabled: boolean, available: Record<string, number>, reserve: Record<string, number> }
// Acquire stamp directly
await client.acquireStamp('small');
// => { batchId: string, depth: number, sizeName: string, fallbackUsed: boolean }
import {
ProvenanceError,
GatewayConnectionError,
StampError,
NotaryError,
VerificationError,
} from '@datafund/swarm-provenance';
try {
await client.upload(content);
} catch (error) {
if (error instanceof StampError) {
console.error('Stamp acquisition failed:', error.message);
} else if (error instanceof GatewayConnectionError) {
console.error('Gateway error:', error.statusCode, error.message);
}
}
import {
buildMetadata,
extractContent,
verifyContentHash,
sha256Hex,
bytesToBase64,
base64ToBytes,
} from '@datafund/swarm-provenance';
// Build metadata manually
const metadata = buildMetadata(content, {
stampId: 'my-stamp',
standard: 'v1',
});
// Extract and verify
const originalContent = extractContent(metadata);
const isValid = verifyContentHash(metadata);
import {
verifySignature,
verifyAllSignatures,
} from '@datafund/swarm-provenance';
const result = verifySignature(signature, metadata, expectedSigner);
// => { valid: boolean, dataHashValid: boolean, signerValid?: boolean }
/chain)The chain module provides on-chain data provenance via a DataProvenance smart contract. It uses viem as an optional peer dependency.
pnpm add viem
ChainClientimport { ChainClient } from '@datafund/swarm-provenance/chain';
const chain = new ChainClient({
chain: 'base-sepolia', // or 'base' for mainnet, or a custom ChainPreset
rpcUrl?: string, // override RPC endpoint
signer?: ChainSigner, // required for write operations
});
// Check if a hash is registered on-chain
await chain.verifyOnChain(dataHash); // => boolean
// Get full provenance record
await chain.getDataRecord(dataHash);
// => { dataHash, owner, timestamp, dataType, status, accessors, transformations }
// Get all records owned by an address
await chain.getUserDataRecords('0x...'); // => string[]
// Check if an address has accessed a hash
await chain.hasAddressAccessed(dataHash, '0x...'); // => boolean
// Check delegate authorization
await chain.isAuthorizedDelegate(owner, delegate); // => boolean
// Anchor a data hash on-chain
const result = await chain.anchor(dataHash, 'dataset');
// => { txHash, blockNumber, gasUsed, explorerUrl, dataHash, dataType, owner }
// Anchor on behalf of another owner (operator only)
await chain.anchorFor(dataHash, 'dataset', ownerAddress);
// Record access
await chain.recordAccess(dataHash);
// => { txHash, blockNumber, gasUsed, explorerUrl, dataHash, accessor }
// Record transformation
await chain.recordTransformation(originalHash, newHash, 'filtered PII');
// Set data status (ACTIVE=0, RESTRICTED=1, DELETED=2)
import { DataStatus } from '@datafund/swarm-provenance/chain';
await chain.setDataStatus(dataHash, DataStatus.RESTRICTED);
// Transfer ownership
await chain.transferOwnership(dataHash, newOwnerAddress);
// Manage delegates
await chain.setDelegate(delegateAddress, true); // authorize
await chain.setDelegate(delegateAddress, false); // revoke
// Batch operations
await chain.batchAnchor([
{ dataHash: hash1, dataType: 'dataset' },
{ dataHash: hash2, dataType: 'model' },
]);
await chain.batchRecordAccess([hash1, hash2]);
await chain.batchSetDataStatus([
{ dataHash: hash1, status: DataStatus.RESTRICTED },
]);
import {
fromEip1193Provider,
fromPrivateKey,
fromViemWalletClient,
} from '@datafund/swarm-provenance/chain';
// Browser wallet (MetaMask, etc.)
const signer = await fromEip1193Provider(window.ethereum);
// Private key (Node.js / scripts)
const signer = await fromPrivateKey('0x...', 'https://sepolia.base.org');
// Existing viem WalletClient
const signer = fromViemWalletClient(walletClient);
import {
ChainConnectionError,
ChainTransactionError,
DataNotRegisteredError,
SignerRequiredError,
} from '@datafund/swarm-provenance/chain';
try {
await chain.anchor(hash, 'dataset');
} catch (error) {
if (error instanceof SignerRequiredError) {
console.error('Connect a wallet first');
} else if (error instanceof ChainTransactionError) {
console.error('Transaction failed:', error.txHash);
}
}
| Network | Preset | Contract |
|---|---|---|
| Base Sepolia (testnet) | base-sepolia | 0x9a3c6F47B69211F05891CCb7aD33596290b9fE64 |
| Base (mainnet) | base | Not yet deployed |
A reference React app is available at examples/web-app/ with upload, download, notary signing, and blockchain anchoring:
cd examples/web-app
pnpm install
pnpm dev
Open http://localhost:5173 to try the full workflow.
# Install dependencies
pnpm install
# Build
pnpm build
# Unit tests
pnpm test
# Integration tests (requires gateway / Hardhat)
pnpm test:integration
# E2E tests (Playwright)
cd examples/web-app && pnpm test
# Type check
pnpm typecheck
# Lint
pnpm lint
MIT
FAQs
TypeScript SDK for Swarm Provenance - store and retrieve provenance data via the Swarm network
The npm package @datafund/swarm-provenance receives a total of 5 weekly downloads. As such, @datafund/swarm-provenance popularity was classified as not popular.
We found that @datafund/swarm-provenance demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 3 open source maintainers collaborating on the project.

Security News
Two compromised GitHub Actions were re-enabled with malicious tags intact, exposing thousands of downstream repositories to Mini Shai-Hulud.

Research
/Security News
A malicious Firefox extension fetches its payload after installation to evade detection, steal Google session cookies, and automate account takeover.

Research
/Security News
The compromise affects MemTensor's MemOS, an open source memory framework for large language models (LLMs) and AI agents. Both npm package @memtensor/memos-cloud-openclaw-plugin and the PyPI package MemoryOS are compromised. They drop cross-platform Go binaries that exfiltrate developer secrets.