Skip to content

Commit 15d9bdf

Browse files
committed
Backdated commit to 2025-03-01 00:14:04
1 parent 3142d32 commit 15d9bdf

File tree

12 files changed

+1280
-54
lines changed

12 files changed

+1280
-54
lines changed

bun.lockb

17.5 KB
Binary file not shown.

components/choices/index.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
const mongoose = require("mongoose");
12
const express = require("express");
23
const md5 = require("md5");
34
// This will help us connect to the database
@@ -61,8 +62,13 @@ const updateChoiceById = async (req, response) => {
6162
if (timeNow > Number(poll.endTime)) {
6263
throw new Error("Proposal Already Ended");
6364
}
64-
65-
const dao = await DAOModel.findById(poll.daoID)
65+
const daoFindQuery = {}
66+
if(mongoose.isValidObjectId(poll.daoID)){
67+
daoFindQuery._id = poll.daoID
68+
} else {
69+
daoFindQuery.address = { $regex: new RegExp(`^${poll.daoID}$`, 'i') };
70+
}
71+
const dao = await DAOModel.findOne(daoFindQuery)
6672
if (!dao) throw new Error(`DAO not found: ${poll.daoID}`)
6773

6874
const token = await TokenModel.findOne({ tokenAddress: dao.tokenAddress })
@@ -83,7 +89,7 @@ const updateChoiceById = async (req, response) => {
8389
);
8490
if (duplicates.length > 0) throw new Error("Duplicate choices found");
8591

86-
const total = await getEthUserBalanceAtLevel(dao.network, address, dao.tokenAddress, block)
92+
const total = await getEthUserBalanceAtLevel(dao.network || network, address, dao.tokenAddress, block)
8793
console.log("EthTotal_UserBalance: ", total)
8894

8995
if (!total) {

components/daos/index.js

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const dbo = require("../../db/conn");
1818
const { getPkhfromPk } = require("@taquito/utils");
1919
const DaoModel = require("../../db/models/Dao.model");
2020
const TokenModel = require("../../db/models/Token.model");
21-
21+
const PollModel = require("../../db/models/Poll.model");
2222
const getAllLiteOnlyDAOs = async (req, response) => {
2323
const network = req.body?.network || req.query.network;
2424

@@ -120,11 +120,31 @@ const getDAOFromContractAddress = async (req, response) => {
120120

121121
const getDAOById = async (req, response) => {
122122
const { id } = req.params;
123-
const daoDao = await DaoModel.findById(id);
124-
console.log({ id, daoDao })
123+
const include = req.query.include
124+
const query = {}
125+
if(mongoose.isValidObjectId(id)) {
126+
query._id = new mongoose.Types.ObjectId(id);
127+
} else {
128+
// query.type = "onchain";
129+
query.address = { $regex: new RegExp(`^${id}$`, 'i') };
130+
}
131+
let daoDao = await DaoModel.findOne(query)
132+
daoDao = await daoDao.toObject()
133+
134+
if(include === "polls"){
135+
136+
console.log("Include Polls")
137+
const pollIds = daoDao.polls.map(poll => poll._id);
138+
console.log("Poll IDs", pollIds)
139+
140+
const polls = await PollModel.find({ daoID: { $regex: new RegExp(`^${id}$`, 'i') } }).populate('choices').lean();
141+
console.log("Polls", polls)
142+
143+
daoDao.polls = polls;
144+
}
125145
if (daoDao) {
126146
return response.json({
127-
...daoDao.toJSON(),
147+
...daoDao,
128148
description: daoDao.description?.replace(/<[^>]*>/g, ''),
129149
});
130150
}

components/polls/index.js

Lines changed: 140 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const {
1111
getIPFSProofFromPayload,
1212
} = require("../../utils");
1313

14+
const axios = require("axios");
1415
const { uploadToIPFS } = require("../../services/ipfs.service");
1516
const DaoModel = require("../../db/models/Dao.model");
1617
const TokenModel = require("../../db/models/Token.model");
@@ -21,6 +22,85 @@ const { getEthCurrentBlockNumber, getEthTotalSupply } = require("../../utils-eth
2122

2223
const ObjectId = require("mongodb").ObjectId;
2324

25+
async function _getPollData(mode="lite", {
26+
daoId, network, tokenAddress = null, authorAddress = null, payloadBytes = null
27+
}){
28+
if(!network?.startsWith("etherlink"))
29+
throw new Error("Network is not supported");
30+
31+
const currentTime = new Date().valueOf();
32+
33+
if(mode == "onchain"){
34+
35+
console.log("tokenAddress", tokenAddress)
36+
const [userTokenBalance, tokenTotalSupply, block] = await Promise.all([
37+
axios.get(`https://testnet.explorer.etherlink.com/api/v2/tokens/${tokenAddress}/holders`).then(res => res.data).catch(err => ({error: err.message})),
38+
axios.get(`https://testnet.explorer.etherlink.com/api/v2/tokens/${tokenAddress}`).then(res => res.data).catch(err => ({error: err.message})),
39+
getEthCurrentBlockNumber(network).catch(err => ({error: err.message}))
40+
]);
41+
42+
console.log(JSON.stringify({userTokenBalance, tokenTotalSupply, block}, null, 2));
43+
44+
const payloadBytesHash = md5(payloadBytes);
45+
const doesPollExists = await PollModel.findOne({ payloadBytesHash });
46+
if (doesPollExists)
47+
throw new Error("Invalid Signature, Poll already exists");
48+
49+
50+
return {
51+
startTime: currentTime,
52+
referenceBlock: block,
53+
totalSupplyAtReferenceBlock: tokenTotalSupply.total_supply,
54+
payloadBytesHash,
55+
doesPollExists
56+
}
57+
}
58+
else{
59+
60+
const dao = await DaoModel.findById(daoId);
61+
if(!dao) throw new Error("DAO Does not exist");
62+
63+
const token = await TokenModel.findOne({ tokenAddress: dao.tokenAddress });
64+
if (!token) throw new Error("DAO Token Does not exist in system");
65+
66+
const block = await getEthCurrentBlockNumber(dao.network);
67+
const totalSupply = await getEthTotalSupply(
68+
dao.network,
69+
dao.tokenAddress,
70+
block
71+
);
72+
// TODO: @ashutoshpw To be Implemented
73+
// const userVotingPowerAtCurrentLevel =
74+
// await getUserTotalVotingPowerAtReferenceBlock(
75+
// dao.network,
76+
// dao.tokenAddress,
77+
// dao.daoContract,
78+
// token.tokenID,
79+
// block,
80+
// author
81+
// );
82+
83+
// if (userVotingPowerAtCurrentLevel.eq(0) && dao.requiredTokenOwnership) {
84+
// throw new Error(
85+
// "User Doesnt have balance at this level to create proposal"
86+
// );
87+
// }
88+
const payloadBytesHash = md5(payloadBytes);
89+
const doesPollExists = await PollModel.findOne({ payloadBytesHash });
90+
if (doesPollExists)
91+
throw new Error("Invalid Signature, Poll already exists");
92+
93+
return {
94+
daoId,
95+
startTime: currentTime,
96+
referenceBlock: block,
97+
totalSupplyAtReferenceBlock: totalSupply,
98+
payloadBytesHash,
99+
doesPollExists
100+
}
101+
}
102+
}
103+
24104
const getPollById = async (req, response) => {
25105
const { id } = req.params;
26106

@@ -29,7 +109,11 @@ const getPollById = async (req, response) => {
29109
let pollId = { _id: ObjectId(id) };
30110

31111
const result = await db_connect.collection("Polls").findOne(pollId);
32-
response.json(result);
112+
response.json({
113+
...result,
114+
name: result.name?.replace(/<[^>]*>/g, ''),
115+
description: result.description?.replace(/<[^>]*>/g, ''),
116+
});
33117
} catch (error) {
34118
console.log("error: ", error);
35119
response.status(400).send({
@@ -65,18 +149,21 @@ const addPoll = async (req, response) => {
65149

66150
if (network?.startsWith("etherlink")) {
67151
try {
68-
const payload = req.payloadObj;
152+
let payload = req.payloadObj;
153+
if(!payload){
154+
payload = getInputFromSigPayload(payloadBytes);
155+
}
69156
const {
70157
choices,
71-
daoID,
72158
name,
73159
description,
74160
externalLink,
75161
endTime,
76162
votingStrategy,
77163
isXTZ,
78164
} = payload;
79-
165+
const daoID = payload?.daoID || payload?.daoId;
166+
console.log("Payload", payload)
80167
if (choices.length === 0) {
81168
throw new Error("No choices sent in the request");
82169
}
@@ -94,43 +181,29 @@ const addPoll = async (req, response) => {
94181
throw new Error("Duplicate choices found");
95182
}
96183

97-
const dao = await DaoModel.findById(daoID);
98-
if (!dao) throw new Error("DAO Does not exist");
99-
100-
const token = await TokenModel.findOne({ tokenAddress: dao.tokenAddress });
101-
if (!token) throw new Error("DAO Token Does not exist in system");
184+
/**
185+
* @ashutoshpw
186+
*
187+
* For Offchain Debate
188+
* - Get token Addresswithin the payload
189+
* = Get the User Token Balance by following API: https://testnet.explorer.etherlink.com/api/v2/tokens/0xBDAc0fBE8cf84eA51cB9436719f6074dA474ef5D/holders
190+
* - Get token Total Supplyw ith this: https://testnet.explorer.etherlink.com/api/v2/tokens/0xBDAc0fBE8cf84eA51cB9436719f6074dA474ef5D
191+
*/
102192

103-
const block = await getEthCurrentBlockNumber(dao.network);
104193
const author = publicKey;
105-
const startTime = currentTime;
106-
const totalSupply = await getEthTotalSupply(
107-
dao.network,
108-
dao.tokenAddress,
109-
block
110-
);
111194

112-
// TODO: @ashutoshpw To be Implemented
113-
// const userVotingPowerAtCurrentLevel =
114-
// await getUserTotalVotingPowerAtReferenceBlock(
115-
// dao.network,
116-
// dao.tokenAddress,
117-
// dao.daoContract,
118-
// token.tokenID,
119-
// block,
120-
// author
121-
// );
122-
123-
// if (userVotingPowerAtCurrentLevel.eq(0) && dao.requiredTokenOwnership) {
124-
// throw new Error(
125-
// "User Doesnt have balance at this level to create proposal"
126-
// );
127-
// }
195+
const daoMode = daoID?.startsWith("0x") ? "onchain" : "lite";
196+
const { startTime, referenceBlock, totalSupplyAtReferenceBlock, payloadBytesHash, doesPollExists} = await _getPollData(daoMode, {
197+
daoId: daoID,
198+
network,
199+
authorAddress: publicKey,
200+
tokenAddress: payload?.tokenAddress,
201+
payloadBytes
202+
});
128203

129-
const payloadBytesHash = md5(payloadBytes);
130-
const doesPollExists = await PollModel.findOne({ payloadBytesHash });
131-
if (doesPollExists)
204+
if(doesPollExists)
132205
throw new Error("Invalid Signature, Poll already exists");
133-
206+
134207
const PollData = {
135208
name,
136209
author,
@@ -139,10 +212,11 @@ const addPoll = async (req, response) => {
139212
startTime,
140213
endTime,
141214
daoID,
142-
referenceBlock: block,
143-
totalSupplyAtReferenceBlock: totalSupply,
215+
referenceBlock,
216+
totalSupplyAtReferenceBlock,
144217
signature,
145-
votingStrategy,
218+
votingStrategy: payload?.votingStrategy || 0,
219+
isXTZ: payload?.isXTZ || false,
146220
payloadBytes,
147221
payloadBytesHash,
148222
cidLink: "",
@@ -159,14 +233,35 @@ const addPoll = async (req, response) => {
159233
};
160234
});
161235

162-
await ChoiceModel.insertMany(choicesData);
236+
const choicesObj = await ChoiceModel.insertMany(choicesData);
237+
const choicesIds = choicesObj.map(choice => choice._id);
238+
console.log({choicesIds})
163239

164-
await DaoModel.updateOne(
165-
{ _id: ObjectId(daoID) },
166-
{
167-
$push: { polls: pollId },
168-
}
240+
await PollModel.updateOne(
241+
{ _id: pollId },
242+
{ $set: { choices: choicesIds } }
169243
);
244+
245+
if(daoMode == "lite"){
246+
await DaoModel.updateOne(
247+
{ _id: ObjectId(daoID) },
248+
{
249+
$push: { polls: pollId },
250+
}
251+
);
252+
}else{
253+
await DaoModel.findOneAndUpdate(
254+
{ address: daoID },
255+
{
256+
name: daoID,
257+
tokenAddress: payload?.tokenAddress,
258+
tokenType:"erc20",
259+
$push: { polls: pollId },
260+
votingAddressesCount: 0 // TODO: @ashutoshpw
261+
},
262+
{ upsert: true, new: true }
263+
);
264+
}
170265
return response.status(200).send({
171266
message: "Poll Created Successfully",
172267
pollId,

db/models/Dao.model.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,22 @@ const Schema = mongoose.Schema;
66
const PollSchema = new Schema({
77
oid: {
88
type: mongoose.Schema.Types.ObjectId,
9+
ref: "Poll",
910
required: true,
1011
},
1112
});
1213

1314
const DaoModelSchema = new Schema({
15+
type:{
16+
type: String,
17+
enum:["onchain","lite"],
18+
default: "lite",
19+
},
20+
address:{
21+
type: String,
22+
index: true,
23+
sparse: true
24+
},
1425
name: {
1526
type: String,
1627
required: true,

db/models/Poll.model.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const PollModelSchema = new Schema({
3030
choices: [{
3131
type: mongoose.Schema.Types.ObjectId,
3232
required: true,
33+
ref: 'Choice',
3334
}],
3435
totalSupplyAtReferenceBlock: {
3536
type: String,

middlewares/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const { verifySignature, bytes2Char } = require("@taquito/utils");
22
const { verityEthSignture } = require("../utils-eth");
3+
const securePayload = require("./secure-payload");
34

45
function splitAtBrace(inputString) {
56
const squareBracketIndex = inputString.indexOf('[');
@@ -74,4 +75,5 @@ const requireSignature = async (request, response, next) => {
7475

7576
module.exports = {
7677
requireSignature,
78+
securePayload,
7779
};

0 commit comments

Comments
 (0)