Closed ryscheng closed 1 year ago
Just to clarify (are these statements correct?):
Technical questions, esp. @ryscheng
Non-technical questions, esp. @ccerv1
Is it currently possible for the end of the "time of impact" to be infinity?
Yes, we currently use the value 0
to denote unspecified
Is there a technical hurdle to include the positive/negative boolean for the scopes?
That's easy to add, but can you clarify, this is for the minter to specify if this is a positive or negative contribution or impact? Shouldn't we leave that to the evaluation?
The scope tags aren't currently ordered lists, right?
It's an array right now, so they're ordered.
What does "unknown" stand for on the contributor implementation?
Contributors are an array of strings. The unknown
refers to any number of additional fields we may want to add in the future, but don't want to specify it quite yet.
Clarified with Holke. by positive and negative, I think what he means is include vs exclude. e.g. Include "IPFS" but exclude "kubo implementation"
I've created a draft metadata spec. You can view/comment on it here.
I'm also copying the most relevant parts below for easy access:
Property | Description |
---|---|
name |
Name of the hypercert. Given that a project may create numerous hypercerts over time, consider giving the hypercert a name that represents a discrete phase or output. |
external_url |
[optional] A URL that can be displayed next to the hypercert on webpages like OpenSea and links users to a website that has more information about the project or impact claim. |
description |
A human readable description of the hypercert. Markdown is supported. Consider adding additional external URLs (e.g. to social media profiles) to the description. |
image |
A URI pointing to a resource with mime type image/* that represents the hypercert's artwork, i.e. ipfs://<CID> . We recommend images at a width between 320 and 1080 pixels and aspect ratio between 1.91:1 and 4:5 inclusive. |
background_color |
[optional] Background color of the item for display on OpenSea. Must be a six-character hexadecimal without a pre-pended #. |
properties |
The unique dimensions of the hypercert's impact claim (see below). |
In order to perform hypercert-specific operations, including split and merge functions, and for your hypercert to robustly claim a set of coordinates in the impact space, there are six additional properties
that must be included in your metadata.
Property | Description |
---|---|
impact_scope |
An ordered list of impact scope tags. The - prefix may be used to indicate an impact scope that is explicitly excluded from the claim. The default claim is to "all" impact, giving the owner rights to claim all potential impact created by the project. |
work_scope |
An ordered list of work scope tags. The - prefix may be used to indicate a work scope that is explicitly excluded from the claim. |
work_timeframe |
Date range from the start to the end of the work. |
impact_timeframe |
Date range from the start to the end of the impact. The default claim is from the start date of work until forever . |
contributors |
An ordered list of contributors. Contributors may be itemized as wallet addresses, ENS names, names / pseudonyms, or organizations / teams. The default claim is to the wallet address that created the hypercert contract. |
rights |
An unordered list of usage rights tags. The default claim is solely to "public display" of the hypercert, i.e. all other rights remain with the contributors. |
collection |
[optional] The name of a collection of related hypercerts that this hypercert belongs to. Purely for display and indexing purposes. |
Here is an example of a complete set of properties included in a hypercert's metadata:
"properties": {
"array_property": {
"name": "Impact Scope",
"value": ["Decentralized web infrastructure"],
"display_value": "Decentralized web infrastructure"
},
"array_property": {
"name": "Work Scope",
"value": ["IPFS", "-go-ipfs"],
"display_value": "IPFS (excludes go-ipfs)"
},
"array_property": {
"name": "Work Timeframe",
"value": [1380585600, 1388534399],
"display_value": "2013-10-01 to 2013-12-31"
},
"array_property": {
"name": "Impact Timeframe",
"value": [1380585600, 0],
"display_value": "2013-10-01 to Forever"
},
"array_property": {
"name": "Contributors",
"value": ["0xa1fa1fa000000000000000000000000000000000", "ipfsinventor.eth" , "idonthaveawallet@email.com", "Phil the Corgi"],
"display_value": "0xa1fa1fa000000000000000000000000000000000, ipfsinventor.eth, and 2 others"
},
"array_property": {
"name": "Rights",
"value": ["public-display", "-transfers"],
"display_value": "Public display"
}
}
See also:
@bitbeckers @ryscheng we are not using the global list of scope tags anymore (as previously implemented), right?
Nope, there is nothing really defined at the moment
Does the - prefix do the job to negate scopes? Or would it be easier to have an array with an attribute that is a boolean (splitting the scope tag from the positive or negative boolean)? Also thinking about data analytics later on
Depends on the input. If it's manual, and somebody fat-fingers a space, suddenly 'public-display' becomes 'public' and '-display'. Or parsing mishaps?
Defining two seperate structures might be safer.
Would the input options be limited as well? As in, will it be drop-down/autofill or is it a textual greenfield? Because that kinda underlines or solves the point on typos.
Would the input options be limited as well? As in, will it be drop-down/autofill or is it a textual greenfield? Because that kinda underlines or solves the point on typos.
Yes the current UI will be drop-down/autofill. Open question as to whether we want a drop-down for includes
and a separate one for excludes
. I'd like to see how this affects the user experience though. (There are already a lot of fields in the form.)
Defining two seperate structures might be safer.
So turning work_scope
into an object with an includes
array and an excludes
array?
That will depend on the frontends. Since other can create different frontends in the future, we might see both at some point. The frontend could still work with prefix -, even if we store it differently. But the UI should prevent accidental negations.
I like the data structure better that makes it more explicit, but ultimately that should be a technical decision.
@ccerv1 is there an advantage of "object with an includes array and an excludes array" over array<{positive_or_negative: boolean, scope_tag: string}>?
@holkeb I think array<{positive_or_negative: boolean, scope_tag: string}>
makes it easier to interpret. Basically you define the scope reading the array in order.
e.g. yes IPFS, not kubo, yes kubo financial support.
One factor to keep in mind, is that we want to make sure it looks right on OpenSea.
properties
should show up as attributes on OpenSea. (see https://docs.opensea.io/docs/metadata-standards)
So 3 followup questions:
collection
and allowlist_uri
somewhere else in the metadata so it doesn't show up in the NFT attributes?Worth experimenting a bit to see before we finalize
CC @bitbeckers
@ryscheng we can experiment with this. If we go for traits like the rich properties
facilitate we have a lot to play with : https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md#erc-1155-metadata-uri-json-schema
Do note the 'Array property' that displays a single value. If that is correct, we should split the positives and negatives in two separate arrays.
re: Does it make sense to hide collection and allowlist_uri somewhere else in the metadata so it doesn't show up in the NFT attributes? We could put them on the top level instead of the properties, but eventually the display is compiled by the front-end so we don't have control over that. Also, if it's a collection I think OpenSea can handle similar traits between tokens within the same contract. So that could work in our advantage.
Update: I've worked through the metadata schema and moved allowlist
and collection
to optional properties at the end of the doc: https://hackmd.io/@ccerv1/hypercerts-metadata.
I agree with @bitbeckers that it would be helpful more often than not for the collection
to display on OpenSea.
Next step: let's play with some different json blob formats (fields in properties
vs top level) and see what looks best.
Sample JSON with some pseudo-dummy metadata:
{
"name": "\ud83c\udfd7 Scaffold-ETH",
"description": "\ud83c\udfd7 Scaffold-ETH is a decentralized application template.\r\n\r\n\ud83e\uddd1\u200d\ud83c\udfeb It helps new builders learn (SpeedRunEthereum.com).\r\n\r\n\ud83d\ude80 It also makes going to production faster and prototyping easier. \r\n\r\n\ud83d\udd2d Thousands of forks later, it has become the starter kit of web3 starter kits.\r\n\r\n\ud83d\udc49 https://github.com/scaffold-eth/scaffold-eth#-scaffold-eth\r\n\r\n\ud83d\udc5b Funding will go to \ud83c\udff0BuidlGuidl builders improving \ud83c\udfd7 Scaffold-ETH and providing more educational material for the Ethereum developer ecosystem!!!",
"external_url": "https://gitcoin.co/grants/2851/scaffold-eth",
"image": "ipfs://QmaiaFjTYmrt97Pd5jSbKq3enfE3wcSriJy96d1Fbgyfeb",
"background_color": "412022",
"properties": {
"impact_scope": {
"name": "Impact Scope",
"value": [
"ETH Infra"
],
"display_value": "ETH Infra"
},
"work_scope": {
"name": "Work Scope",
"value": [
"application",
"builders",
"builders-learn-speedrunethereumcom",
"decentralized-application-template",
"developer",
"easier",
"ethereum-developer-ecosystem",
"production-faster",
"prototyping-easier-thousands",
"starter",
"starter-kits-funding"
],
"display_value": "application, builders, builders-learn-speedrunethereumcom, decentralized-application-template, developer, easier, ethereum-developer-ecosystem, production-faster, prototyping-easier-thousands, starter, starter-kits-funding"
},
"work_timeframe": {
"name": "Work Timeframe",
"value": [
1380585600,
1388534399
],
"display_value": "2013-10-01 to 2013-12-31"
},
"impact_timeframe": {
"name": "Impact Timeframe",
"value": [
1380585600,
0
],
"display_value": "2013-10-01 to Forever"
},
"contributors": {
"name": "Contributors",
"value": [
"0xa1fa1fa000000000000000000000000000000000",
"ipfsinventor.eth",
"idonthaveawallet@email.com",
"Phil the Corgi"
],
"display_value": "0xa1fa1fa000000000000000000000000000000000, ipfsinventor.eth, and 2 others"
},
"rights": {
"name": "Rights",
"value": [
"public-display",
"-transfers"
],
"display_value": "Public display"
}
},
"attributes": {
"collection": "Gitcoin Alpha Round",
"allowlist": "ipfs://bafkreiaxdog4clqiitnarc4rrzpgdlcjsg6k2nr2n2t4thwklccza34ubi"
}
}
We'll set up a simple contract on Goerli for testing JSON implementations
I played around with metadata properties, and the following schema works, though I have some concerns with it.
View it on OpenSea here
Metadata here
And the JSON copied for discussion:
{
"name": "Test Project",
"description": "## Hypercerts\n\n \u26a1\u26a1 Hypercerts: A new primitive for impact funding systems\n\nHypercerts are an interoperable data layer for impact funding mechanisms.\n\nA single hypercert is a semi-fungible token that accounts for work that is supposed to be impactful whose ownership is fractionizable and transferable (under specific conditions).\n\nHypercerts don’t impose any specific funding mechanisms, but provide baseline invariant guarantees such that claims will not be forgotten as different mechanisms come into and out of fashion. This is also why hypercerts are especially useful for any retrospective funding mechanisms – funding can be applied to claims of the past.",
"external_url": "https://hypercerts.xyz/",
"image": "ipfs://bafkreib2qqcsf7si3rqivgpekniyjkz3q2txvao2pll4zi26e4mv7q6yde",
"background_color": "00A9B7",
"attributes": {
"collection": "Gitcoin Alpha Round",
"impact_scope": {
"name": "Impact Scope",
"value": [
"hypercerts protocol"
],
"display_value": "hypercerts protocol"
},
"work_scope": {
"name": "Work Scope",
"value": [
"metadata experimentation",
"goerli testnet",
"alpha launch prep"
],
"display_value": "metadata experimentation, goerli testnet, alpha launch prep"
},
"work_timeframe": {
"name": "Work Timeframe",
"value": [
1380585600,
1388534399
],
"display_value": "2013-10-01 to 2013-12-31"
},
"impact_timeframe": {
"name": "Impact Timeframe",
"value": [
1380585600,
0
],
"display_value": "2013-10-01 to Forever"
},
"contributors": {
"name": "Contributors",
"value": [
"0xa1fa1fa000000000000000000000000000000000",
"ipfsinventor.eth",
"idonthaveawallet@email.com",
"Phil the Corgi"
],
"display_value": "0xa1fa1fa000000000000000000000000000000000, ipfsinventor.eth, and 2 others"
},
"rights": {
"name": "Rights",
"value": [
"public-display",
"-transfers"
],
"display_value": "Public display"
},
"allowlist": "ipfs://bafkreiaxdog4clqiitnarc4rrzpgdlcjsg6k2nr2n2t4thwklccza34ubi"
}
}
Can we add a version number somewhere? In case we change the schema in the future?
Here's a new proposed schema, updated per latest discussions with @holkeb and incorporating davidad's feedback.
Changes:
properties
have been removed (OpenSea will not dispaly any properties)hypercert
dimensions are clearly enumerated
impact_scope
has a value of [], conveying an empty set or effectively a claim to "all" impact display_value
fields set via the frontend interfacecreator_properties
have been added, which creators and frontend interfaces can define per their needsversion
is recommended for compatibility{
"name": "Project Name",
"description": "add your markdown formatted text here",
"external_url": "https://hypercerts.xyz",
"image": "ipfs://bafkreicchjbpbb2hfcg5mtmlz3zktf2wt5dnux2rzx33ta7b6bhrozlbgi",
"hypercert": {
"impact_scope": {
"name": "Impact Scope",
"value": [],
"display_value": "All",
},
"work_scope": {
"name": "Work Scope",
"value": ["Project Name"],
"display_value": "Project Name",
},
"work_timeframe": {
"name": "Work Timeframe",
"value": [1663819200, 1673163072],
"display_value": "2022-09-22 \u2192 2023-01-08"
},
"impact_timeframe": {
"name": "Impact Timeframe",
"value": [1673163072, 0],
"display_value": "2023-01-08 \u2192 Indefinite"
},
"contributors": {
"name": "Contributors",
"value": ["0x799B774204A348E1182fE01074C51444bA70A149"],
"display_value": "0x799...149"
},
"rights": {
"name": "Rights",
"value": ["public-display", "-transfers"],
"display_value": "Public display"
}
},
"creator_properties": {
"tags": ["Gitcoin", "Alpha Round", "Open Source Software"],
"icon": "ipfs://bafkreigdv5xynidonbbjmfeqiamlbbg3ae42zz5ckd3zbuibicziddnc7y",
"banner": "ipfs://bafybeicecz5fdbadlzyx4gfzwqaxpm2ngvqrkhybuizkwkd5wmm2wlixam",
"allowlist": "ipfs://bafkreiaxdog4clqiitnarc4rrzpgdlcjsg6k2nr2n2t4thwklccza34ubi"
},
"version": "1.0.0"
}
Thanks! this is helpful, couple questions:
on 2.: Yes, we can use an explicit "all"
@ryscheng my understanding is that OpenSea prioritises attributes
over properties
and that either route supports different patterns: https://docs.opensea.io/docs/metadata-standards. But, I haven't gone through the itterations like Carl did.
@ccerv1 how is the metadata rendered on non-OpenSea platforms like Rarible and Nifty Gateway? The reason I ask is to prevent optimising for OpenSea.
OpenSea's documentation is very vague on how this works.
For instance, this metadata displays correctly (here) but doesn't show any properties.
@ccerv1 how is the metadata rendered on non-OpenSea platforms like Rarible and Nifty Gateway? The reason I ask is to prevent optimising for OpenSea.
I haven't tried other platforms. I'm going to keep playing with this today. I also have all the draft hypercerts artwork combos from Sascha to experiment with.
Anyway, I'd like this issue to be done and dusted by Monday morning.
Alright! I think we finally have it!
This is what it looks like on OpenSea: https://testnets.opensea.io/assets/goerli/0xffb1fbff7a40ea441aeae8036812af116f593995/57
Updates:
values
and display_values
to make the intended behavior more explicit (eg, case where impact_scope: ["all"]
, showing that multiple scopes are conjunctive){
"name": "Example Hypercert",
"description": "This is where the description of the hypercert will go.",
"external_url": "https://hypercerts.xyz",
"image": "ipfs://bafybeifs7abhcooeelyjxmnlrcd5kuupfl5czhtyub2imzxzccrhzz3bem",
"version": "1.0.0",
"properties": [
{
"trait_type": "Example Property 1",
"value": "Some text here"
},
{
"trait_type": "Example Property 2",
"value": "More text here"
}
],
"hypercert": {
"impact_scope": {
"name": "Impact Scope",
"value": ["all"],
"display_value": "All"
},
"work_scope": {
"name": "Work Scope",
"value": ["art design", "metadata standards"],
"display_value": "Art Design & Metadata Standards"
},
"work_timeframe": {
"name": "Work Timeframe",
"value": [1663819200, 1673163072],
"display_value": "2022-09-22 \u2192 2023-01-08"
},
"impact_timeframe": {
"name": "Impact Timeframe",
"value": [1673163072, 0],
"display_value": "2023-01-08 \u2192 Indefinite"
},
"contributors": {
"name": "Contributors",
"value": ["0x799B774204A348E1182fE01074C51444bA70A149"],
"display_value": "0x799...149"
},
"rights": {
"name": "Rights",
"value": ["public display", "¬transfers"],
"display_value": "Public display"
}
}
}
@ccerv1 how do we currently deal with time in the date range?
Comment from davidad:
Although I don’t want to make people fiddle with a time picker or have to think about time zones, I do think we ought to standardize by fiat that the start date is implicitly attributed 00:00:00 UTC and the end date is implicitly attributed 23:59:59 UTC. If hypercerts are successful, this will eventually become relevant for a dispute at least once, and it will be really good to have a pre-existing official answer that makes sense
From our conversation today, I think the most recent iteration is mostly it, the only thing we're missing is a
excludes: ["this", "that"],
that should be included with rights, impact_scopes, and work_scopes.
@ccerv1 Regarding the display value of the conjunctive clauses
Option 2 really would indicate a conjunctive clause. I know that many won't really know what to do with it, but I also believe it isn't distracting. Especially as we include negative terms, this makes more sense than the "&"
@ryscheng I have created explicit includes/excludes list for those fields. @holkeb I have gone with the Option 2 for the display notation but with the kebab case that you had in the whitepaper, ie, "Art-Design ∧ Metadata-Standards" or "Public-Display ∧ ¬ Transfers"
The metadata for such a property would be as follows:
{
"name": "Rights",
"includes": ["Public Display"],
"excludes": ["Transfers"],
"value": ["Public Display", "¬Transfers"],
"display_value": "Public-Display ∧ ¬Transfers"
}
Here is the current schema https://github.com/Network-Goods/hypercerts-sdk/blob/main/src/types/metadata.d.ts https://github.com/Network-Goods/hypercerts-sdk/blob/main/src/types/claimdata.d.ts
Currently we just have values
and excludes
, where values
is implicitly just the includes
. In your example, it'd look like this:
{
"name": "Rights",
"value": ["Public Display"],
"excludes": ["Transfers"],
"display_value": "Public-Display ∧ ¬Transfers"
}
In the interest of not having this issue turn into a forever issue where we are constantly just evolving the schema, I'm going to close this out. CC @ccerv1 @holkeb If this is okay with you, we can leave it closed.
If you prefer one of the following options, feel free to open a new issue:
includes
, excludes
AND values
. - I'm generally not in favor of this, redundant data usually means inconsistent datavalues
in our current implementation to includes
. This makes it more explicit and we would NOT have a values
field.
This is what we have right now https://github.com/Network-Goods/hypercerts-sdk/blob/main/types/claimdata.d.ts
This is what's written in the paper https://docs.google.com/document/d/1456v3OWTnkQXQIo4lmud7b2qOXqsYwQo1EuN-GbsJU8/edit?disco=AAAAmz4v61w
Related to what is optional/required? https://github.com/Network-Goods/hypercerts/issues/96
We should decide on the schema soon.