Perma-Calendar is a demo app for HollowDB. It is client-side only, and every user deploys their contract & their keys. It does not use proofs and only uses whitelisting.
The FullCalendar framework is used for calendar rendering.
You can check out the live demo here.
Head to the GitHub repo to see the implementation or jump to the Code Snippets section to have a quick look.
The Calendar App
As HollowDB supports both ZK-based inputs and whitelists, it can be used like any other database. This simple example demonstrates how it can be used as a calendar application only using client side code.
As mentioned, for a calendar app every user has to deploy their own HollowDB contract. Users' wallet is added to the whitelist automatically, meaning only they can do write operations.
After you connect your wallet, you will see either a Deploy or Redeploy button depending on if a previously deployed contract exists or not.
Add Calendar Events
You can click on any date to create an event. After submitting the event, the user receives a transaction to write the event to the HollowDB contract. After a successful event creation, the event will be shown on the calendar.
Enter Event Name
Sign the Transaction
Ta-da!
Delete Event
To delete an event, simply click on the event and sign the transaction.
Code Snippets
The folder structure of the application is as follows:
.
├─ src
│ ├── components (header and layout)
│ ├── constants (source tx id of the contract to be deployed)
│ ├── context (wallet connection and contract deploy logic)
│ ├── pages (home page and react/nextjs defaults)
│
└── ...
Contract Deployment
// srcTx type is created, it requires srcTxID, deployer address and signer// signer for metamask is retrieved from InjectedEthereumSigner and window.ethereum// signer for arweave is retrieved from InjectedArweaveSignerconstsrcTx:FromSrcTxContractData=generateContractInfo(HOLLOWDB_SRCTXID, address, userSigner );// HollowDB deployedconstdeployTx=awaitwarp.deployFromSourceTx(srcTx);// HollowDB instance is created using SDK and deploy tx informationconsthollowdb=newSDK("use_wallet",deployTx.contractTxId, warp);// The instance is stored and shared accross the web-appsetHollowdb(hollowdb);
Put Operation
asyncfunctionput(key:string, value: {}) {/* ... some checks ... */awaithollowdb?.put(key,JSON.stringify(value)); }consthandleDateSelect= (selectInfo:DateSelectArg) => {/* ... some checks ... */let title =prompt("Please enter a new title for your event");let calendarApi =selectInfo.view.calendar;// The event is added to both calendarApi and HollowDBif (title) {consteventId=createEventId();conststart=selectInfo.startStr;constend=selectInfo.endStr;constallDay=selectInfo.allDay;calendarApi.addEvent({ id: eventId, title, start: start, end: end, allDay: allDay, });put(eventId, { title: title, start: start, end: end, allDay: allDay }); } };
Remove Operation
asyncfunctionremove(key:string) {if (!isConnected) {return; }// Empty event object// We check for empty events using empty stringconstemptyValue=JSON.stringify({ title:"", start:"", end:"", allDay:"", });awaithollowdb?.update(key, emptyValue); }consthandleEventClick= (clickInfo:EventClickArg) => {/* ... some checks ... */// The event is removed from both calendarApi and HollowDBremove(clickInfo.event.id);clickInfo.event.remove(); };
Handling Previously Deployed Contracts
constcheckPrevEvents=async () => {if (hollowdb?.contractTxId ==""||!isConnected) return;// clean up the calendar (helps with redeployment)removeAll();let oldEventKeys:Array<string> = [];let oldEvents:Array<any> = [];// get all existing keys on the hollowdb contractawaithollowdb?.getAllKeys().then((keys: []) => {if (keys) { oldEventKeys =Array.from(keys.values()); } });// get all existing values on the hollowdb contract then convert it to an arrayconsteventValues=awaithollowdb?.getStorageValues(oldEventKeys);constmappedEvents=eventValues?.cachedValue;if (mappedEvents) { oldEvents =Array.from(mappedEvents.values()); }// filter empty events oldEvents =oldEvents.filter((elements) => {return elements !==null; });// Obtain a calendar api instance to add previous events to the calendarconstcalendarApi=CalendarRef.current.getApi();for (let i =0; i <oldEvents.length; i++) { oldEvents[i] =awaitJSON.parse(oldEvents[i]);consteventId=createEventId();if (oldEvents[i].title !="")calendarApi.addEvent({ id: eventId, title: oldEvents[i].title, start:newDate(oldEvents[i].start), end:newDate(oldEvents[i].end), allDay:newDate(oldEvents[i].allDay), }); } };
Congrats! You have successfully learned how to deploy and use an HollowDB contract.