Preserving community memories forever on the blockchain
Memoria is a decentralized memory archive system designed at ETH Dublin Hackathon 2025. The project enables communities to preserve memories—stories, images, songs, recipes, and cultural artifacts—permanently on-chain and on Arweave, creating an unstoppable record of human heritage.
It's live here
You can check out the archives here or you can check out the memories in an archive here
Across the world, local histories are often erased, censored, or forgotten. Centralized institutions (governments, media, museums) frequently fail to preserve emotional, oral, and grassroots stories. Memoria enables decentralized, trust-anchored preservation of human memory with permanent storage on Arweave and immutable verification on Ethereum.
Example Use Cases:
- 🇮🇪 Preserving rare Irish dialects through audio recordings and cultural context
- 📖 Collecting family recipes and traditional cooking methods before they're lost
- 🎵 Archiving indigenous music and oral histories
- 📸 Documenting community events and local celebrations
- 🏘️ Recording neighborhood stories and urban development history
Our goal is to create a public goods incentive structure to fund cultural preservation. Users who build archives can receive donations from other users, and use the donations to directly fund artifacts/memories submitted to Arweave. This model fosters greater transparency, and more easily funds those directly involved in cultural preservation.
Also, the donors and participants in this project will receive ERC-1155 NFTs minted to them as backers of the archives, and do function as a badge for supporting the project
Memoria consists of two main smart contracts built on Ethereum:
The factory contract that deploys and indexes community archives.
Key Features:
- Deploy new Archive contracts for communities
- Index all archives with pagination support
- Emit events for archive creation tracking
- Input validation for archive parameters
Individual community memory vaults that store artifact metadata and manage rewards.
Key Features:
- Artifact Management: Submit, review, accept/reject community memories
- NFT Minting: ERC-1155 tokens minted for accepted artifacts
- Donor Tracking: Complete donor management with statistics and rewards
- Metadata Generation: On-chain base64-encoded JSON metadata
- Admin Controls: Secure admin functions with proper access control
You can view our contracts live on Etherscan Sepolia
// Submit a new artifact for review
function submitArtifact(
string calldata _title,
string calldata _arweaveURI,
string calldata _mimeType
) external returns (uint256 id)
// Admin accepts artifact and mints NFT
function acceptArtifact(uint256 _id, uint256 _rewardWei) external onlyAdmin
// Admin rejects artifact
function rejectArtifact(uint256 _id) external onlyAdmin// Donate with a message
function receiveDonation(string calldata _message) external payable
// Anonymous donations via receive function
receive() external payable
// View donor information
function donorInfo(address donor) external view returns (Donor memory)
function getDonors(uint256 offset, uint256 limit) external view returns (Donor[] memory)
function totalDonors() external view returns (uint256)// Transfer admin rights
function transferAdmin(address _newAdmin) external onlyAdmin// Create a new community archive
function createArchive(
string calldata _name,
string calldata _description,
string calldata _baseUri
) external returns (address archiveAddr)
// View archives with pagination
function getArchives(uint256 offset, uint256 limit) external view returns (ArchiveInfo[] memory)
function totalArchives() external view returns (uint256)- 📤 Submission: Community members submit artifacts with title, Arweave URI, and MIME type
- 👀 Review: Archive admin reviews submissions for quality and relevance
- ✅ Acceptance: Admin accepts artifact, mints ERC-1155 NFT to submitter, and optionally rewards ETH
- 🏆 Collection: Submitter receives unique NFT representing their contribution
- 🌐 Discovery: Artifact becomes publicly viewable with on-chain metadata
- ReentrancyGuard: Protection against reentrancy attacks
- Input Validation: Comprehensive validation for all string inputs
- Safe ETH Transfers: Uses
call()instead oftransfer()for compatibility - Access Control: Admin-only functions with proper validation
- Zero Address Protection: Prevents invalid address assignments
- Clone the repository:
git clone <repository-url>
cd memoria- Install dependencies:
yarn install- Start local blockchain:
yarn chain- Deploy contracts:
yarn deploy- Start the frontend:
yarn startVisit http://localhost:3000 to interact with your deployed contracts.
Memoria includes comprehensive test coverage with 36 tests covering all functionality:
# Run all tests
yarn foundry:test
# Run tests with verbose output
yarn foundry:test -vv
# Generate coverage report
yarn foundry:coverageTest Coverage:
- Archive Contract: 100% function coverage, 93.33% branch coverage
- ArchiveFactory Contract: 100% coverage across all metrics
# Deploy to local network
forge script script/DeployLocal.s.sol --broadcast --rpc-url localhost# Set environment variables
export PRIVATE_KEY="your-private-key"
export RPC_URL="your-rpc-url"
# Deploy with verification
forge script script/DeployMemoria.s.sol --broadcast --rpc-url $RPC_URL --verifymemoria/
├── packages/
│ ├── foundry/ # Smart contracts
│ │ ├── contracts/
│ │ │ ├── Archive.sol # Main archive contract
│ │ │ └── ArchiveFactory.sol # Factory contract
│ │ ├── test/ # Contract tests
│ │ ├── script/ # Deployment scripts
│ │ └── foundry.toml # Foundry config
│ └── nextjs/ # Frontend application
│ ├── app/ # Next.js app router
│ ├── components/ # React components
│ └── hooks/ # Wagmi hooks
Edit packages/foundry/foundry.toml for:
- Solidity compiler settings
- Network configurations
- Gas optimization settings
Edit packages/nextjs/scaffold.config.ts for:
- Target network selection
- UI customization
- Contract integration settings
We welcome contributions to Memoria! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
- Follow Solidity best practices
- Maintain 100% test coverage for new features
- Add comprehensive documentation
- Use conventional commit messages
This project is licensed under the MIT License - see the LICENSE file for details.
- Built on Scaffold-ETH 2 framework
- Uses OpenZeppelin security standards
- Developed at ETH Dublin Hackathon 2025
- Inspired by the need to preserve cultural heritage globally
Preserving memories, one artifact at a time 🌟
This section provides comprehensive documentation for developers and designers working with Memoria's smart contracts. All functions, data structures, events, and integration patterns are documented in detail.
- Contract Addresses
- ArchiveFactory Contract
- Archive Contract (ERC-1155)
- Data Structures
- Events Reference
- Error Codes
- Gas Estimates
- Integration Examples
The factory contract manages the deployment and indexing of all community archives in the Memoria ecosystem.
contract ArchiveFactory {
address[] public archives; // All deployed archive addresses
}function createArchive(
string calldata _name,
string calldata _description,
string calldata _baseUri
) external returns (address archiveAddr)Description: Creates a new Archive contract for a community. The caller automatically becomes the admin.
Parameters:
_name(string): Human-readable name of the archive (e.g., "Dublin Folk Memories")_description(string): Short description shown in UI (e.g., "Preserving stories from Dublin's communities")_baseUri(string): ERC-1155 base URI (optional, can be empty string)
Returns:
archiveAddr(address): Address of the newly deployed Archive contract
Access Control: Public - anyone can create an archive
Gas Cost: ~2,100,000 gas (deploys new contract)
Requirements:
_namemust not be empty string- Will revert if deployment fails
Events Emitted: ArchiveCreated(address indexed archive, string name, address indexed admin)
Example Usage:
const tx = await archiveFactory.createArchive(
"Dublin Folk Memories",
"Preserving stories from Dublin's communities",
""
);
const receipt = await tx.wait();
const archiveAddress = receipt.events[0].args.archive;function totalArchives() external view returns (uint256)Description: Returns the total number of archives created through this factory.
Parameters: None
Returns:
uint256: Total count of deployed archives
Access Control: Public view
Gas Cost: ~2,400 gas
Example Usage:
const total = await archiveFactory.totalArchives();
console.log(`Total archives: ${total}`);function archives(uint256 index) external view returns (address)Description: Public array getter to access archive addresses by index.
Parameters:
index(uint256): Zero-based index in the archives array
Returns:
address: Archive contract address at the given index
Access Control: Public view
Gas Cost: ~2,600 gas
Requirements:
indexmust be less thantotalArchives()
Example Usage:
// Get the first archive
const firstArchive = await archiveFactory.archives(0);
// Get all archives
const total = await archiveFactory.totalArchives();
const allArchives = [];
for (let i = 0; i < total; i++) {
allArchives.push(await archiveFactory.archives(i));
}Individual community memory vaults that store artifact metadata, manage donations, and mint NFTs for accepted memories.
contract Archive is ERC1155, ReentrancyGuard {
string public name; // Archive name
string public description; // Archive description
address public admin; // Archive administrator
// Artifact tracking
uint256 private _nextId = 1; // Next artifact ID (starts at 1)
mapping(uint256 => ArtifactMetadata) public metadata;
// Donor tracking
address[] public donors;
mapping(address => uint256) public donorIndex;
mapping(address => Donor) public donorInfo;
}enum Status {
Pending, // 0 - Awaiting admin review
Accepted, // 1 - Approved and NFT minted
Rejected // 2 - Rejected by admin
}struct ArtifactMetadata {
string title; // Human-readable title
string arweaveURI; // Arweave storage URI
string mimeType; // Content MIME type (e.g., "image/jpeg")
uint256 timestamp; // Submission timestamp
address submitter; // Who submitted this artifact
Status status; // Current status (Pending/Accepted/Rejected)
}struct Donor {
address donor; // Donor's address
uint256 totalDonated; // Total ETH donated (in wei)
uint256 donationCount; // Number of separate donations
}string public name;Description: Human-readable name of the archive
Example: "Dublin Folk Memories"
string public description;Description: Short description of the archive's purpose
Example: "Preserving stories from Dublin's communities"
address public admin;Description: Address with administrative privileges (can accept/reject artifacts)
mapping(uint256 => ArtifactMetadata) public metadata;Description: Maps artifact IDs to their metadata
Usage: metadata[1] returns the metadata for artifact ID 1
address[] public donors;Description: Array of all unique donor addresses (ordered by first donation)
mapping(address => uint256) public donorIndex;Description: Maps donor address to their index in the donors array (1-based, 0 means not found)
mapping(address => Donor) public donorInfo;Description: Maps donor address to their donation statistics
function submitArtifact(
string calldata _title,
string calldata _arweaveURI,
string calldata _mimeType
) external returns (uint256 id)Description: Submit a new artifact for admin review. Creates a pending artifact with a unique ID.
Parameters:
_title(string): Human-readable title (e.g., "My Grandmother's Recipe")_arweaveURI(string): Arweave URI where content is stored (e.g., "ar://abc123...")_mimeType(string): MIME type of the content (e.g., "image/jpeg", "audio/mp3", "application/pdf")
Returns:
id(uint256): Unique identifier for the submitted artifact
Access Control: Public - anyone can submit
Gas Cost: ~85,000 gas
Requirements:
- All string parameters must be non-empty
- No duplicate checking (same content can be submitted multiple times)
Events Emitted: ArtifactSubmitted(uint256 indexed id, address indexed submitter)
Example Usage:
const tx = await archive.submitArtifact(
"My Grandmother's Irish Stew Recipe",
"ar://bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi",
"application/pdf"
);
const receipt = await tx.wait();
const artifactId = receipt.events[0].args.id;function acceptArtifact(uint256 _id, uint256 _rewardWei) external onlyAdmin nonReentrantDescription: Admin accepts a pending artifact, mints an ERC-1155 NFT to the submitter, and optionally sends ETH reward.
Parameters:
_id(uint256): ID of the artifact to accept_rewardWei(uint256): Amount of ETH to send as reward (in wei, can be 0)
Returns: None
Access Control: Admin only
Gas Cost: ~180,000 gas (includes NFT minting and potential ETH transfer)
Requirements:
- Artifact must exist and be in Pending status
- If
_rewardWei > 0, contract must have sufficient balance - Artifact cannot already be finalized (accepted or rejected)
Events Emitted:
ArtifactAccepted(uint256 indexed id, address indexed submitter, uint256 reward)- ERC-1155
TransferSingleevent from minting
Side Effects:
- Mints 1 ERC-1155 token with ID
_idto the submitter - Transfers
_rewardWeiETH to submitter (if > 0) - Changes artifact status to Accepted
Example Usage:
// Accept artifact and reward with 0.1 ETH
const rewardAmount = ethers.utils.parseEther("0.1");
await archive.acceptArtifact(artifactId, rewardAmount);
// Accept without reward
await archive.acceptArtifact(artifactId, 0);function rejectArtifact(uint256 _id) external onlyAdminDescription: Admin rejects a pending artifact. No NFT is minted and no reward is given.
Parameters:
_id(uint256): ID of the artifact to reject
Returns: None
Access Control: Admin only
Gas Cost: ~25,000 gas
Requirements:
- Artifact must exist and be in Pending status
- Artifact cannot already be finalized
Events Emitted: ArtifactRejected(uint256 indexed id, address indexed submitter)
Side Effects:
- Changes artifact status to Rejected
- Artifact becomes permanently rejected (cannot be re-reviewed)
Example Usage:
await archive.rejectArtifact(artifactId);function receiveDonation(string calldata _message) external payableDescription: Accept a donation with an optional message. Updates donor statistics.
Parameters:
_message(string): Optional message from donor (not stored on-chain, only for events)
Returns: None
Access Control: Public payable
Gas Cost: ~65,000 gas (first donation), ~45,000 gas (subsequent donations)
Requirements:
msg.valuemust be greater than 0
Events Emitted: DonationReceived(address indexed from, uint256 amount)
Side Effects:
- Adds ETH to contract balance
- Updates or creates donor record
- If first donation from address, adds to donors array
Example Usage:
const donationAmount = ethers.utils.parseEther("0.5");
await archive.receiveDonation("Keep up the great work!", {
value: donationAmount,
});receive() external payableDescription: Fallback function for anonymous donations (when sending ETH directly to contract).
Parameters: None (ETH value via msg.value)
Returns: None
Access Control: Public payable
Gas Cost: ~65,000 gas (first donation), ~45,000 gas (subsequent donations)
Requirements:
msg.valuemust be greater than 0
Events Emitted: DonationReceived(address indexed from, uint256 amount)
Side Effects: Same as receiveDonation but without message
Example Usage:
// Send ETH directly to contract
await signer.sendTransaction({
to: archiveAddress,
value: ethers.utils.parseEther("0.25"),
});function uri(uint256 _id) public view override returns (string memory)Description: Returns base64-encoded JSON metadata for accepted artifacts (ERC-1155 standard).
Parameters:
_id(uint256): Token/artifact ID
Returns:
string: Data URI with base64-encoded JSON metadata
Access Control: Public view
Gas Cost: ~15,000 gas
Requirements:
- Artifact must exist and be in Accepted status
Metadata Format:
{
"name": "Artifact Title",
"description": "Artifact stored in Archive Name",
"image": "ar://arweave-uri",
"mimeType": "image/jpeg",
"timestamp": 1641024000
}Example Usage:
const tokenURI = await archive.uri(artifactId);
// Returns: "data:application/json;base64,eyJuYW1lIjoi..."
// To decode:
const base64Data = tokenURI.split(",")[1];
const jsonString = atob(base64Data);
const metadata = JSON.parse(jsonString);function totalDonors() external view returns (uint256)Description: Returns the total number of unique donors.
Parameters: None
Returns:
uint256: Number of unique addresses that have donated
Access Control: Public view
Gas Cost: ~2,400 gas
Example Usage:
const donorCount = await archive.totalDonors();function getDonors(uint256 offset, uint256 limit) external view returns (Donor[] memory slice)Description: Returns a paginated list of donors with their statistics.
Parameters:
offset(uint256): Starting index (0-based)limit(uint256): Maximum number of donors to return
Returns:
slice(Donor[]): Array of Donor structs
Access Control: Public view
Gas Cost: ~5,000 + (1,000 * returned donors) gas
Example Usage:
// Get first 10 donors
const firstDonors = await archive.getDonors(0, 10);
// Get all donors (if you know the total)
const total = await archive.totalDonors();
const allDonors = await archive.getDonors(0, total);
// Pagination example
const pageSize = 20;
const page2Donors = await archive.getDonors(20, pageSize);function getTotalArtifacts() external view returns (uint256)Description: Returns the total number of artifacts submitted (regardless of status).
Parameters: None
Returns:
uint256: Total number of artifacts submitted
Access Control: Public view
Gas Cost: ~2,300 gas
Example Usage:
const totalArtifacts = await archive.getTotalArtifacts();function getArtifactsByStatus(Status _status, uint256 limit) external view returns (uint256[] memory ids)Description: Returns artifact IDs filtered by status, up to a specified limit.
Parameters:
_status(Status): Status to filter by (0=Pending, 1=Accepted, 2=Rejected)limit(uint256): Maximum number of IDs to return
Returns:
ids(uint256[]): Array of artifact IDs matching the status
Access Control: Public view
Gas Cost: ~5,000 + (500 * checked artifacts) gas
Note: This function scans from ID 1 up to _nextId, so gas cost increases with total artifacts
Example Usage:
// Get pending artifacts for admin review
const pendingIds = await archive.getArtifactsByStatus(0, 50);
// Get accepted artifacts for display
const acceptedIds = await archive.getArtifactsByStatus(1, 100);
// Get rejected artifacts
const rejectedIds = await archive.getArtifactsByStatus(2, 25);function getArchiveStats() external view returns (
uint256 totalArtifacts,
uint256 totalDonationsWei,
uint256 totalDonorCount
)Description: Returns key statistics about the archive in a single call.
Parameters: None
Returns:
totalArtifacts(uint256): Total number of artifacts submittedtotalDonationsWei(uint256): Current contract balance (total donations minus rewards)totalDonorCount(uint256): Number of unique donors
Access Control: Public view
Gas Cost: ~4,500 gas
Example Usage:
const [totalArtifacts, totalDonations, totalDonors] =
await archive.getArchiveStats();
console.log(
`Stats: ${totalArtifacts} artifacts, ${ethers.utils.formatEther(
totalDonations
)} ETH, ${totalDonors} donors`
);function transferAdmin(address _newAdmin) external onlyAdminDescription: Transfer administrative rights to another address.
Parameters:
_newAdmin(address): New admin address
Returns: None
Access Control: Admin only
Gas Cost: ~28,000 gas
Requirements:
_newAdmincannot be zero address- Only current admin can call
Events Emitted: AdminTransferred(address indexed oldAdmin, address indexed newAdmin)
Side Effects:
- Immediately transfers all admin privileges
- Original admin loses all admin access
Example Usage:
await archive.transferAdmin("0x742d35Cc6634C0532925a3b8D7389d12345678901");event ArchiveCreated(address indexed archive, string name, address indexed admin);Description: Emitted when a new archive is created Parameters:
archive(indexed): Address of the new archive contractname: Name of the archiveadmin(indexed): Address of the archive admin
event ArtifactSubmitted(uint256 indexed id, address indexed submitter);Description: Emitted when a new artifact is submitted Parameters:
id(indexed): Unique artifact IDsubmitter(indexed): Address that submitted the artifact
event ArtifactAccepted(uint256 indexed id, address indexed submitter, uint256 reward);Description: Emitted when an artifact is accepted by admin Parameters:
id(indexed): Artifact IDsubmitter(indexed): Address that submitted the artifactreward: ETH reward amount in wei (can be 0)
event ArtifactRejected(uint256 indexed id, address indexed submitter);Description: Emitted when an artifact is rejected by admin Parameters:
id(indexed): Artifact IDsubmitter(indexed): Address that submitted the artifact
event DonationReceived(address indexed from, uint256 amount);Description: Emitted when a donation is received Parameters:
from(indexed): Donor addressamount: Donation amount in wei
event AdminTransferred(address indexed oldAdmin, address indexed newAdmin);Description: Emitted when admin rights are transferred Parameters:
oldAdmin(indexed): Previous admin addressnewAdmin(indexed): New admin address
"ArchiveFactory: empty name"- Archive name cannot be empty string
"Archive: not admin"- Function requires admin privileges"Archive: empty string"- String parameter cannot be empty"Archive: zero admin address"- Admin address cannot be zero"Archive: empty name"- Archive name cannot be empty"Archive: already finalised"- Artifact status already set (accepted/rejected)"Archive: invalid artifact"- Artifact doesn't exist or has zero submitter"Archive: insufficient balance"- Not enough ETH for reward payment"Archive: zero donation"- Donation amount must be greater than 0"Archive: not accepted"- Artifact must be accepted to access metadata"Archive: zero address"- Address parameter cannot be zero"Archive: ETH transfer failed"- ETH transfer to recipient failed
| Function | Gas Cost | Notes |
|---|---|---|
createArchive |
~2,100,000 | Deploys new contract |
totalArchives |
~2,400 | Simple storage read |
archives[i] |
~2,600 | Array access |
| Function | First Call | Subsequent Calls | Notes |
|---|---|---|---|
submitArtifact |
~85,000 | ~85,000 | Consistent cost |
acceptArtifact |
~180,000 | ~180,000 | Includes NFT mint |
rejectArtifact |
~25,000 | ~25,000 | Simple state change |
receiveDonation |
~65,000 | ~45,000 | First adds to array |
receive |
~65,000 | ~45,000 | Same as receiveDonation |
uri |
~15,000 | ~15,000 | String manipulation |
totalDonors |
~2,400 | ~2,400 | Simple read |
getDonors |
~5,000 + (1k × items) | Same | Scales with results |
getTotalArtifacts |
~2,300 | ~2,300 | Simple read |
getArtifactsByStatus |
~5,000 + (500 × total) | Same | Scans all artifacts |
getArchiveStats |
~4,500 | ~4,500 | Multiple reads |
transferAdmin |
~28,000 | ~28,000 | Event emission |
import { useScaffoldReadContract } from "~~/hooks/scaffold-eth";
// Get archive basic info
const { data: archiveName } = useScaffoldReadContract({
contractName: "Archive",
functionName: "name",
});
// Get archive stats
const { data: stats } = useScaffoldReadContract({
contractName: "Archive",
functionName: "getArchiveStats",
});
// Get pending artifacts for admin
const { data: pendingIds } = useScaffoldReadContract({
contractName: "Archive",
functionName: "getArtifactsByStatus",
args: [0, 50], // Status.Pending, limit 50
});
// Get specific artifact metadata
const { data: artifactData } = useScaffoldReadContract({
contractName: "Archive",
functionName: "metadata",
args: [artifactId],
});import { useScaffoldWriteContract } from "~~/hooks/scaffold-eth";
const { writeContractAsync: writeArchive } = useScaffoldWriteContract({
contractName: "Archive",
});
// Submit new artifact
const submitArtifact = async (
title: string,
arweaveUri: string,
mimeType: string
) => {
try {
const result = await writeArchive({
functionName: "submitArtifact",
args: [title, arweaveUri, mimeType],
});
console.log("Artifact submitted:", result);
} catch (error) {
console.error("Error submitting:", error);
}
};
// Make donation
const donate = async (amount: string, message: string) => {
try {
const result = await writeArchive({
functionName: "receiveDonation",
args: [message],
value: parseEther(amount),
});
console.log("Donation sent:", result);
} catch (error) {
console.error("Error donating:", error);
}
};
// Admin: Accept artifact with reward
const acceptArtifact = async (id: number, rewardEth: string) => {
try {
const result = await writeArchive({
functionName: "acceptArtifact",
args: [id, parseEther(rewardEth)],
});
console.log("Artifact accepted:", result);
} catch (error) {
console.error("Error accepting:", error);
}
};import { useScaffoldEventHistory } from "~~/hooks/scaffold-eth";
// Listen for new artifacts
const { data: artifactEvents } = useScaffoldEventHistory({
contractName: "Archive",
eventName: "ArtifactSubmitted",
fromBlock: 0n,
});
// Listen for donations
const { data: donationEvents } = useScaffoldEventHistory({
contractName: "Archive",
eventName: "DonationReceived",
fromBlock: 0n,
});// Get multiple artifacts with their metadata
const getArtifactsWithMetadata = async (ids: number[]) => {
const promises = ids.map((id) =>
readContract({
address: archiveAddress,
abi: archiveAbi,
functionName: "metadata",
args: [id],
})
);
return Promise.all(promises);
};
// Get paginated donors
const getAllDonors = async () => {
const total = await readContract({
address: archiveAddress,
abi: archiveAbi,
functionName: "totalDonors",
});
return readContract({
address: archiveAddress,
abi: archiveAbi,
functionName: "getDonors",
args: [0, total],
});
};// Create new archive
const { writeContractAsync: writeFactory } = useScaffoldWriteContract({
contractName: "ArchiveFactory",
});
const createArchive = async (name: string, description: string) => {
try {
const result = await writeFactory({
functionName: "createArchive",
args: [name, description, ""], // Empty baseUri
});
// Get archive address from event
const receipt = await result.wait();
const event = receipt.events?.find((e) => e.event === "ArchiveCreated");
const archiveAddress = event?.args?.archive;
return archiveAddress;
} catch (error) {
console.error("Error creating archive:", error);
}
};
// Get all archives
const getAllArchives = async () => {
const total = await readContract({
address: factoryAddress,
abi: factoryAbi,
functionName: "totalArchives",
});
const promises = [];
for (let i = 0; i < total; i++) {
promises.push(
readContract({
address: factoryAddress,
abi: factoryAbi,
functionName: "archives",
args: [i],
})
);
}
return Promise.all(promises);
};This comprehensive documentation provides all the information needed for developers and designers to integrate with Memoria's smart contracts. Each function includes parameter types, return values, gas costs, access control requirements, and practical usage examples.