This is a project where Organizations can create an event with a prize pool. The prize will be distributed to the projects listed under it within a specific time period. Users can list their projects and enter the competition. Each user (those who have listed their projects under the competition) will receive 100 votes, which can be distributed to other listed projects, with the condition that they cannot vote for their own project. After the voting period ends, the organization publishes the results, and users can withdraw the amount they won based on the received votes.
- Reverse Lookups
- Data Source Templates for Dynamically Created Contracts
- File Data Sources
I have created custom smart contracts for this project and it consists of 2 contracts. One implementaion contract FundingContract.sol
and one Factory contract FundingFactory.sol
which deploys new FundingContract.sol
contract. Both contracts are in folder contracts
in this repository.
Note: The Project and Event details (name,description,link) are stored on IPFS and IPFS CID is strored on contract instead to storing all variables.
Contract | Address | Explorer Link |
---|---|---|
FundingFactory | 0x151D0545647B710Cb7B16D33f9c9CBb2dE3553Cf | Link |
FundingContract | 0xD0ddBe3c8C5D3Baa122D1317723cdD37ED313e18 | Link |
Contracts are deployed on Sepolia Testnet.
There are total 5 events emitted.
- When an Organization is creating a new event. (A new contract will be deployed from Factory Contract)
event newFundingCreated(address indexed owner, uint256 prizePool, address cloneAddress, string eventCID);
- When a new project is listed for an event(competition)
event projectListed(address indexed owner, string projectCID, uint256 projectId);
- When a user votes for a project
event voted(address indexed user, uint256 voteCount, uint256 projectId);
- When the organization publishes result
event resultPublished(uint256 dateEnded,uint256 totalProjects);
- When a user withdraw the funds won from a project
event fundsWithdrawn(uint256 indexed projectId, uint256 amount, uint256 date, address owner);
Enums used
enum EventStatus{
Active
Ended
}
Total 7 Entities are defined in schema.graphql
- Event Creator Details
type EventCreator @entity(immutable: true) {
id: ID! # Wallet Address of Event Creator
createdEvents: [FundingEvent!] @derivedFrom(field: "owner")
}
- User Details
type User @entity {
id: ID! # User Wallet Address
participatedEvents: [UserFundingEvent!] @derivedFrom(field: "user")
projects: [Project!] @derivedFrom(field: "owner")
votesLeft: BigInt!
completedVotes: [Vote!] @derivedFrom(field: "user")
earnings: BigInt!
}
- Event/Competition Details
type FundingEvent @entity {
id: ID! # Implementation Contract Address
eventCID: String!
eventDetails: IpfsMetadataDetails
owner: EventCreator!
status: EventStatus
prizePool: BigInt!
users: [UserFundingEvent!] @derivedFrom(field: "event")
projects: [Project!] @derivedFrom(field: "event")
}
type UserFundingEvent @entity(immutable: true) {
id: ID!
user: User!
event: FundingEvent!
}
- Listed Project Details
type Project @entity {
id: ID! # Project ID
owner: User!
event: FundingEvent!
projectCID: String!
projectDetails: IpfsMetadataDetails
amountWon: BigInt!
amountWithdrawn: Boolean!
votes: [Vote!] @derivedFrom(field: "project")
}
- Vote Details
type Vote @entity(immutable: true) {
id: ID! # Transaction Hash
project: Project!
user: User!
voteCount: BigInt!
}
- Project/Event IPFS Metadata Details (Used File Data Source to Index)
type IpfsMetadataDetails @entity {
id: ID! # IPFS URI
name: String!
description: String!
link: String!
}
- Data Source (Events from factory contract) - Event handlers are defined in
src/mappings.ts
- event: newFundingCreated(indexed address,uint256,address,string)
handler: handleNewFundingCreated
- Templates (Events from implementation contract) - Event handlers are defined in
src/mappings.ts
- event: projectListed(indexed address,string,uint256)
handler: handleProjectListed
- event: voted(indexed address,uint256,uint256)
handler: handleVoted
- event: fundsWithdrawn(indexed uint256,uint256,uint256,address)
handler: handleFundsWithdrawn
- event: resultPublished(uint256,uint256)
handler: handleResultPublished
- File Data Source (To index metadata for Event & Project details) - Defined in
src/map-ipfs.ts
import { Bytes, dataSource, json } from "@graphprotocol/graph-ts";
import { IpfsMetadataDetails } from "../generated/schema";
export function handleMetadata(content: Bytes): void {
let ipfsData = new IpfsMetadataDetails(dataSource.stringParam())
const val = json.fromBytes(content).toObject()
const name = val.get("name")!.toString()
const description = val.get("description")!.toString()
const link = val.get("link")!.toString()
ipfsData.description = description
ipfsData.name = name
ipfsData.link = link
ipfsData.save()
}
- Created a custom Factory contract & Implementation contract for Project Funding and deployed to
Sepolia Testnet
- Defined Schema in the most optimized form using Reverse Lookups
- Configured event handlers in
subgraph.yaml
for Factory Contract(Data Source) & Implementation Contract(Templates) - Defined event handlers in
src/mappings.ts
and deployed subgraph toSubgraph Studio
- Used File Data Source to index metadata from IPFS -
src/map-ipfs.ts
Subgraph URL - Link
- Events(Competition) created by all event creators - Link
- User and Project submitted for all Events(Many-to-Many Relation) - Link
- Event Details & Submitted Projects Details (Indexed using File Data Source) - Link
If anymore details required, feel free to contact [email protected]