Skip to content

Commit

Permalink
Merge pull request #33 from State-Channel-4/feat/nico/sync-contract
Browse files Browse the repository at this point in the history
Feat/nico/sync contract
  • Loading branch information
NicoSerranoP authored Oct 23, 2023
2 parents 1d9d0e4 + dc18653 commit 9fb7300
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 59 deletions.
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ PORT=8000
MONGO_URI=mongodb://localhost:27017
JWT_SECRET=secret
LOGIN_SECRET="login to backend"
DB_NAME="channel4"
PRIVATE_KEY=0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6
RPC_URL=https://goerli.infura.io/v3/<YOUR_PROJECT_ID>
CONTRACT_ADDRESS=0xE2A943638d71c26cEE411d3432a3A95Bd0F4a1a9
CONTRACT_ADDRESS=0x6189a62161FEDfFeBc5A56ffA419978937618843
2 changes: 1 addition & 1 deletion .env.local.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ LOGIN_SECRET="login to backend"
DB_NAME="channel4"
PRIVATE_KEY=0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6
RPC_URL=http://localhost:8545
CONTRACT_ADDRESS=0x700b6A60ce7EaaEA56F065753d8dcB9653dbAD35
CONTRACT_ADDRESS=0x6189a62161FEDfFeBc5A56ffA419978937618843
8 changes: 3 additions & 5 deletions src/controllers/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,17 @@ const syncDataToSmartContract = async (_req: Request, res: Response) => {

// Submit a batch of data to the smart contract to sync
try {
/* TODO: uncomment this
let tx = await contract.syncState(users, tags, urls, likes);
await tx.wait();
*/
} catch (error: any) {
console.error("error: ", error);
return res.status(500).json({ error: `Failed to sync state: ${error.message}` });
}

// Mark all as synced
await UserControl.markSynced(users);
await TagControl.markSynced(tags);
await URLControl.markSynced(urls);
await UserControl.markSynced(users.map(user => user.userAddress as string));
await TagControl.markSynced(tags.map(tag => tag.name));
await URLControl.markSynced(urls.map(url => url.url));
await LikeControl.markSynced();

// Return success on syncing smart contract with backend state
Expand Down
1 change: 1 addition & 0 deletions src/controllers/likes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export const handleLike = async (req: Request, res: Response) => {
}

// update the # of likes on the content
content.syncedToBlockchain = false;
content.likes += liked ? 1 : -1;
await content.save();

Expand Down
39 changes: 22 additions & 17 deletions src/controllers/tags.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Request, Response } from 'express';
import { Types } from 'mongoose';
import { Tag, TagDocument, UserDocument } from '../models/schema';
import { TagToSync } from '../types/contract';
import { Tag, TagDocument, URLDocument, UserDocument } from '../models/schema';
import { Data } from '../types/typechain/Channel4';

export const createTag = async (req: Request, res: Response) => {
try {
Expand Down Expand Up @@ -40,6 +40,7 @@ export const attachURL = async (tags: Types.ObjectId[], urlId: Types.ObjectId) =
const tag: TagDocument | null = await Tag.findById(tagId);
if (tag) {
tag.urls.push(urlId);
tag.syncedToBlockchain = false;
await tag.save();
}
}
Expand All @@ -52,29 +53,33 @@ export const detachURL = async (tags: Types.ObjectId[], urlId: Types.ObjectId) =
const index = tag.urls.indexOf(urlId);
if (index > -1) {
tag.urls.splice(index, 1);
tag.syncedToBlockchain = false;
await tag.save();
}
}
}
};

export const getTagsToSync = async () : Promise<TagToSync[]> => {
return Tag.find({ syncedToBlockchain: false })
.populate({
path: 'createdBy',
model: 'User',
select: 'walletAddress'
})
.then(tags => tags.map(tag => {
const createdBy = (tag.createdBy as unknown) as UserDocument
return {
name: tag.name,
createdBy: createdBy.walletAddress,
}
}));
export const getTagsToSync = async () : Promise<Data.TagToSyncStruct[]> => {
const tags = await Tag.find({ syncedToBlockchain: false }).populate({
path: 'createdBy',
model: 'User',
select: 'walletAddress',
}).populate({
path: 'urls',
model: 'Url',
select: 'title',
});
return tags.map(tag => {
return {
name: tag.name,
createdBy: (tag.createdBy as unknown as UserDocument).walletAddress,
contentIds: (tag.urls as unknown as URLDocument[]).map(url => url.title),
};
});
}

export const markSynced = async (tags: TagToSync[]) => {
export const markSynced = async (tags: string[]) => {
await Tag.updateMany(
{ name: { $in: tags } },
{ syncedToBlockchain: true }
Expand Down
51 changes: 24 additions & 27 deletions src/controllers/urls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { shuffle } from '../lib/utils';
import * as TagControl from './tags';
import * as UserControl from './users';
import { UserDocument, TagDocument } from '../models/schema';
import { UrlToSync } from '../types/contract';
import { Data } from '../types/typechain/Channel4';


const createURL = async (req: Request, res: Response) => {
Expand Down Expand Up @@ -101,35 +101,32 @@ const getMixedURLs = async (req: Request, res: Response) => {
}
};

const getContentToSync = async (): Promise<UrlToSync[]> => {
return await Url.find({ syncedToBlockchain: false })
.populate({
path: 'submittedBy',
model: 'User',
select: 'walletAddress'
})
.populate({
path: 'tags',
model: 'Tag',
select: 'name'
})
.then(urls => urls.map(url => {
const userDoc = (url.submittedBy as unknown) as UserDocument
return {
title: url.title,
url: url.url,
submittedBy: userDoc.walletAddress,
tagIds: url.tags.map(tag => {
const tagDoc = (tag as unknown) as TagDocument
return tagDoc.name
})
}
}));
const getContentToSync = async (): Promise<Data.ContentToSyncStruct[]> => {
const contents = await Url.find({ syncedToBlockchain: false }).populate({
path: "submittedBy",
model: "User",
select: "walletAddress",
}).populate({
path: "tags",
model: "Tag",
select: "name",
});
return contents.map((content) => {
return {
title: content.title,
url: content.url,
submittedBy: (content.submittedBy as unknown as UserDocument).walletAddress,
likes: content.likes,
tagIds: content.tags.map((tag) => {
return (tag as unknown as TagDocument).name;
}),
};
});
};

const markSynced = async (urls: UrlToSync[]) => {
const markSynced = async (urls: string[]) => {
await Url.updateMany(
{ title: { $in: urls } },
{ url: { $in: urls } },
{ syncedToBlockchain: true }
);
};
Expand Down
21 changes: 16 additions & 5 deletions src/controllers/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const { User } = require("../models/schema");
import { Request, Response } from 'express';
import { Types } from 'mongoose';
import { UserDocument, URLDocument } from '../models/schema';
import { Data } from '../types/typechain/Channel4';


export const createUser = async (req: Request, res: Response) => {
Expand Down Expand Up @@ -66,6 +67,7 @@ export const attachURL = async (userId : Types.ObjectId, urlId: Types.ObjectId)
const user = await User.findById(userId);
if (user) {
user.submittedUrls.push(urlId);
user.syncedToBlockchain = false;
await user.save();
}
};
Expand All @@ -76,25 +78,34 @@ export const detachURL = async (userId: Types.ObjectId, urlId: Types.ObjectId) =
const index = user.submittedUrls.indexOf(urlId);
if (index > -1) {
user.submittedUrls.splice(index, 1);
user.syncedToBlockchain = false;
await user.save();
}
}
};

export const getUsersToSync = async () : Promise<string[]> => {
export const getUsersToSync = async () : Promise<Data.UserStruct[]> => {
const users: UserDocument[] = await User.find({ syncedToBlockchain: false }).populate({
path: 'submittedUrls',
model: 'Url',
});
console.log(users);

return users.map(user => user.walletAddress);
return users.map((user) => {
// TODO: save the contract index of each content
const submittedContent = (user.submittedUrls as unknown as URLDocument[]).map((_url, index) => index);
return {
userAddress: user.walletAddress,
numberOfLikes: user.likedUrls.length,
submittedContent: submittedContent,
registeredAt: Math.floor(user.createdAt.getTime() / 1000),
numberOfLikesInPeriod: 0,
};
});
}

export const markSynced = async (users: string[]) => {
await User.updateMany(
{ walletAddress: { $in: users } },
{ syncedToBlockchain: false }
{ syncedToBlockchain: true }
);
}
// dow we need url param in getNonce?
Expand Down
14 changes: 11 additions & 3 deletions src/types/contract.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
// These types are generated from the typechain package. Try importing them from there

export interface TagToSync {
name: string,
createdBy: string,
contentIds: string[],
}

export interface LikeToSync {
export interface LikeToSync {
url: string,
liked: boolean,
nonce: number,
submittedBy: string,
}

export interface UserToSync {
walletAddress: string,
export interface UserToSync {
userAddress: string,
numberOfLikes: number,
submittedUrls: number[],
registeredAt: number,
numberofLikesInPeriod: number,
}

export interface UrlToSync {
title: string,
url: string,
submittedBy: string,
likes: number,
tagIds: string[],
}

0 comments on commit 9fb7300

Please sign in to comment.