The Ceramic Points Working Group (WG) had its first kickoff meeting on Feb 5, 2024 to discuss the opportunity for points within the Ceramic ecosystem, assign tasks, and discuss next steps. We have modified the notes from that original meeting into this document, which continues to improve with additional community exploration and contribution.
There is now also a Ceramic Points WG Telegram. Comment to be invited.
Collaborators: Sena (3Box Labs, cofounder), Rohhan (3Box Labs, product), Mark (3Box Labs, Partner Engineer), Billy (Intuition, founder), Charles (Orbis, cofounder), Walter (Disco, PM), Yannick (Oamo, CEO), Hira (Plurality, Cofounder), Ludo (Pact Social), Liang (US3R), Eshaan, Sofiane (Newcoin), Donat (Orbis)… list growing 😅.
Points are like scorecards: one or more values assigned to a subject by an issuer, typically determined by computing an algorithm over various sources of onchain and offchain data.
Currently, points are being implemented by almost every major web3 project in a trustful, opaque, web2, Postgres way. Not only does this have obvious centralization downsides and risks, but it also makes it impossible for other projects to compose and reuse the points elsewhere, making it impossible for users to have any ownership and agency over their points data.
We believe that points can be the ERC-20 moment for Ceramic and the verifiable web. The opportunity before us is to specify a simple, standard points abstraction that everyone can integrate with and customize for their use case. Ultimately, this will provide the early standardization required to give birth to a new composable web3 data primitive and ecosystem. As a result, we expect the universal points standard (and its implementations) to generate a flurry of developer activity and experimentation using points on Ceramic as the backbone.
Points are an extremely useful primitive that have applications across a variety of industries and use cases. Here are some of the ones already relevant to Web3. Rohhan is compiling a list of projects and will be reaching out to conduct research and validation.
Loyalty & Marketing
Points vs Traditional Airdrops?
Points are an improvement over the existing system since they enable projects to target more genuine long term users as opposed to short term speculators.
Example: Current implementation of 🌈 Rainbow Points
Composable Reputation
Example: 👩🚀 Gitcoin Passport as Points
Trust & Safety
Protocol design is all about tradeoffs; here's what we strongly considered for UPS. To support the use cases above, we believe that points need to be:
The points stantard consists of the points protocol and an ecosystem of data sources and integrations that can be used by points developers.
This working group recognizes that multiple formats/interfaces for points will exist and aims to support the most common and useful ones. Keep in mind that even if one or two popular points interfaces per format emerge, it's still possible to transform between different schemas using some compute service such as Orbis plugins. The goal though is to have as few interfaces as required.
Points should be stored on Ceramic as model instance documents that conform to the following model interface:
Here's a quick example designed using Ceramic GraphQL Models. "Been messing around with building a simple local package using a 'site trigger' as a specific type that would implement a generic point":
interface Point
@createModel(description: "A point interface") {
controller: DID! @documentAccount
recipient: DID! @accountReference
issuanceDate: DateTime!
}
type SiteTriggerPoint implements Point
@createModel(accountRelation: LIST, description: "An implementation of a point related to a trigger that occurred on a website")
@createIndex(fields: [{ path: "issuanceDate" }])
@createIndex(fields: [{ path: "page" }])
{
controller: DID! @documentAccount
recipient: DID! @accountReference
issuanceDate: DateTime!
page: String! @string(maxLength: 100)
trigger: SiteTrigger
}
enum SiteTrigger {
PAGEVIEW
QUERY
CONVERSION
}
Then I was thinking it might be nice to have a "context" that could serve as the point of entry (representing an app or something even more granular):
interface Context
@createModel(description: "A context interface for points")
{
controller: DID! @documentAccount
description: String @string(maxLength: 1000)
}
enum SiteTrigger {
PAGEVIEW
QUERY
CONVERSION
}
type SiteContext implements Context
@createModel(accountRelation: SINGLE, description: "An implementation of a site context for the Ceramic website")
@createIndex(fields: [{ path: "uri" }])
@createIndex(fields: [{ path: "trigger" }])
{
controller: DID! @documentAccount
uri: String! @string(maxLength: 1000)
description: String @string(maxLength: 1000)
trigger: SiteTrigger!
}
interface Point
@createModel(description: "A point interface") {
controller: DID! @documentAccount
recipient: DID! @accountReference
issuanceDate: DateTime!
}
type SitePoint implements Point
@createModel(accountRelation: LIST, description: "An implementation of a point related to action that occurred on a website")
@createIndex(fields: [{ path: "issuanceDate" }])
{
controller: DID! @documentAccount
recipient: DID! @accountReference
issuanceDate: DateTime!
contextId: StreamID! @documentReference(model: "SiteContext")
context: SiteContext! @relationDocument(property: "contextId")
}
Load the relation back to all points for the context:
type SitePoint @loadModel(id: "$POINT_ID") {
id: ID!
}
type SiteContext @loadModel(id: "$CONTEXT_ID") {
points: [SitePoint] @relationFrom(model: "SitePoint", property: "contextId")
}
Newcoin has an interesting approach they've been working to specify called Immutable Points Standard Protocol (IPSP) (video) that makes use of verifiable credentials (JSON-LD) to model points that are then stored on Ceramic.
{
"@context": "https://www.example.com/ipsp-context.jsonld",
"templateID": "ipsp:1234567890",
"issuer": {
"id": "did:example:issuer123456"
},
"issuanceDate": "2023-12-01T02:33:55Z",
"credentialSubject": {
"id": "did:example:subject67890",
"interaction": {
"targetID": "https://example.com/content/1234",
"timestamp": "2023-12-01T01:23:45Z"
}
},
"proof": {
"type": "Ed25519Signature2018",
"verificationMethod": "did:example:issuer123456#keys-1",
"signature": "ExampleDigitalSignature123456"
},
"provenance": {
"author": "did:example:author98765",
"normalizationProcess": "Normalized using standard algorithm XYZ"
}
}
{
"@context": {
"@version": 1.1,
"@vocab": "http://example.com/vocab#",
"issuerType":
{"@id": "vocab:issuerType", "@type": "@vocab"},
"meritType":
{"@id": "vocab:meritType", "@type": "@vocab"},
"verifiabilityType":
{"@id": "vocab:verifiabilityType", "@type": "@vocab"},
"environment":
{"@id": "vocab:environment", "@type": "@vocab"},
"realWorldEnvironment":
{"@id": "vocab:realWorldEnvironment", "@type": "@vocab"},
"internetEnvironment":
{"@id": "vocab:internetEnvironment", "@type": "@vocab"}
}
}
Issuer Types
{
"@context": {
"@vocab": "http://example.com/vocab#",
"schema": "http://schema.org/"
},
"@id": "http://example.com/vocab/IssuerType",
"@type": "schema:Class",
"schema:name": "IssuerType",
"schema:description": "The type of entity that issues the points, which can be a person, organization, mechanism, or algorithm.",
"subClassOf": {
"@id": "schema:Thing"
},
"properties": {
"Person": {
"@id": "schema:Person",
"@type": "schema:Class"
},
"Organization": {
"@id": "schema:Organization",
"@type": "schema:Class"
},
"Mechanism": {
"@id": "http://example.com/vocab/Mechanism",
"@type": "schema:Class"
},
"Algorithm": {
"@id": "http://example.com/vocab/Algorithm",
"@type": "schema:Class"
}
}
}
Merit Types
{
"@context": {
"@vocab": "http://example.com/vocab#",
"schema": "http://schema.org/"
},
"@id": "http://example.com/vocab/MeritType",
"@type": "schema:Class",
"schema:name": "MeritType",
"schema:description": "The type of merit the credential represents, such as personhood, participation, or knowledge.",
"subClassOf": {
"@id": "schema:Thing"
},
"properties": {
"Personhood": {
"@id": "http://example.com/vocab/Personhood",
"@type": "schema:Property"
},
"Participation": {
"@id": "http://example.com/vocab/Participation",
"@type": "schema:Property"
},
// Additional properties as needed...
}
}
Verifiability Types
{
"@context": {
"@vocab": "http://example.com/vocab#",
"schema": "http://schema.org/"
},
"@id": "http://example.com/vocab/VerifiabilityType",
"@type": "schema:Class",
"schema:name": "VerifiabilityType",
"schema:description": "The nature of the verifiability applied to the credential, including mechanistic, optimistic, or agentic types.",
"subClassOf": {
"@id": "schema:Thing"
},
"properties": {
"Mechanistic": {
"@id": "http://example.com/vocab/Mechanistic",
"@type": "schema:Property"
},
"Optimistic": {
"@id": "http://example.com/vocab/Optimistic",
"@type": "schema:Property"
},
"Agentic": {
"@id": "http://example.com/vocab/Agentic",
"@type": "schema:Property"
}
}
}
Environment Types
{
"@context": {
"@vocab": "http://example.com/vocab#",
"schema": "http://schema.org/"
},
"@id": "http://example.com/vocab/VerifiabilityType",
"@type": "schema:Class",
"schema:name": "VerifiabilityType",
"schema:description": "The nature of the verifiability applied to the credential, including mechanistic, optimistic, or agentic types.",
"subClassOf": {
"@id": "schema:Thing"
},
"properties": {
"Mechanistic": {
"@id": "http://example.com/vocab/Mechanistic",
"@type": "schema:Property"
},
"Optimistic": {
"@id": "http://example.com/vocab/Optimistic",
"@type": "schema:Property"
},
"Agentic": {
"@id": "http://example.com/vocab/Agentic",
"@type": "schema:Property"
}
}
}
{
"@context": {
"@vocab": "http://example.com/vocab#",
"schema": "http://schema.org/"
},
"@id": "http://example.com/vocab/InternetEnvironment",
"@type": "schema:Class",
"schema:name": "InternetEnvironmentType",
"schema:description": "Covers various online contexts where the credential may be relevant, such as social networks, e-commerce platforms, or educational sites.",
"subClassOf": {
"@id": "schema:Thing"
},
"properties": {
"SocialNetwork": {
"@id": "http://example.com/vocab/SocialNetwork",
"@type": "schema:Property"
},
"ECommerce": {
"@id": "http://example.com/vocab/ECommerce",
"@type": "schema:Property"
},
"Educational": {
"@id": "http://example.com/vocab/Educational",
"@type": "schema:Property"
},
"SearchEngine": {
"@id": "http://example.com/vocab/SearchEngine",
"@type": "schema:Property"
},
"RLHF": {
"@id": "http://example.com/vocab/RLHF",
"@type": "schema:Property"
},
"Podcast": {
"@id": "http://example.com/vocab/Podcast",
"@type": "schema:Property"
}
// Additional internet environment properties can be included here...
}
}
Ludo committed to working on an interface design, I think based on VCs.
Eshaan took on the task of thinking through the EAS inplementation.
There are four primary roles: issuer, subject, consumer and verifier.
Points issuers are services that source data, run their algorithm, compute points, and write scores back to Ceramic. Points issuers are in the business of producing points with their algorithm. In order for their algorithm to work, they need to inregrate with data sources, either proprietary or third-party. One big opportunity to explore in this area is automating point generation/creation.
Points algorithms are essentially reputation algorithms that have parameters/weights assigned to various data sources. In this protocol, the aim is to have points algorithms be configurable. Not all points issuers need to make their algorithm public, so this is completely up to each implementer.
A fairly large open question in this area is the role of reputation for points issuers…
Consumers are entities that consume points data.
Points consumers are often required perform extra verification beyond signature verification when considering how to evaluate the merits of a point. In many cases, consumers need to consider additional metadata about the issuer such as identity and reputation.
Theoretically, consumers can be their own point verifier; this is likely true in only the most simplistic cases. Most verifications will be performed by specialized verifiers (reputation services) who provide additional context. Additional reputation-based verification methods are out of band of the core protocol. However, the existence of one or more verifier/issuer identity/reputation services would certainly be useful to the overall protocol. In the most basic sense, these could be delivered as an API, SDK, plugin, dataset, etc that expose additional issuer and verification metadata that complements and augments the original points dataset.
In order to have a maximally useful points protocol, we should ensure that there are a large variety of data sources and integrations available for points developers to use. Points developers may use one or more data sources at a time.
This option describes integrating with the Verifiable Event
dataset on Ceramic. This dataset allows Ceramic to function as a universal data integration layer and middleware, enabling all kinds of indirect data integrations.
Many different kinds of data sources can be used by points algorithms: some verifiable and some not, some onchain and some offchain, some served by web2 API, etc… which presents a challenge. How can I prepare an/my input data source/dataset for maximum integration with as many points systems as possible?
On Ceramic we need to collectively generate a new dataset, defined by the following model interface, which stores verifiable events using Ceramic as a data warehouse – an intermediate step for later computing these events into points.
Verifiable Event
InterfaceCan we create a simple schema/interface for events that is universal so that all new builds can work from a used standard (similar to ERC20/ERC721)? One approach could be storing all input datasets as events in a larger, global Verifiable Event Dataset on Ceramic. Ceramic as a decentralized, verifiable event warehouse. In this model, points issuers would consume their data from Ceramic in the form of a universal verifiable event. Can we design a model interface that can provide the required information for a historical event such that a third party can trustlessly take it and use it?
Specify the universal event interface
Although it would be nice for everything to be intermediately stored on Ceramic as a middle transformation layer, that's unlikely. Let's continue to explore other options for integrating data sources into your points algorithm.
Technically all Ceramic data is already fully-verifiable so can be considered a legitimate data source for use by points developers. Since the data already exists on the network but is not part of the Verifiable Event dataset, devs will have to do more manual work when gathering the dataset, applying content and meaning, and computing over it, since schemas could differ.
Onchain data is already strongly verifiable, so as long as you can easily query the onchain dataset(s) you need for your point algorithm, there's no explicit need to store data intermediately as an event on Ceramic. For onchain data, developers will usually consume data directly from chain or some index of the chain, such as The Graph's subgraphs.
One highly relevant onchain dataset is EAS attestations. In this case, I'm not referring to the attestations stored on Ceramic; I'm referring to the ones stored onchain.
Offchain data is all the data generated and/or used by applications that does not exist on a public blockchain network. Can offchain data be quantified in a standard format to be used as input for points? (e.g., interests). In these cases, it might be easier to use Ceramic's Verifiable Event dataset to facilitate these integrations.
It might be a good idea to dogfood the MVP ourselves, by logging offchain interactions with the Ceramic Docs site, so that we can give points to our top engagers. In my mind, it could be extremely simple andd straightforward to create an MVP to serve this use case with the following components:
Onchain Data
What are the business models enabled by this standard? How can an ecosystem of valuable businesses develop? What are the possible incentives?