Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decide on hypercert claim schema #98

Closed
ryscheng opened this issue Jan 5, 2023 · 31 comments
Closed

Decide on hypercert claim schema #98

ryscheng opened this issue Jan 5, 2023 · 31 comments
Assignees
Labels
category:offchain Any off-chain backends (e.g. IPFS or cloud) p0:urgent Must address immediately

Comments

@ryscheng
Copy link
Member

ryscheng commented Jan 5, 2023

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?
#96

We should decide on the schema soon.

@ryscheng ryscheng added p1:ready Ready for work category:offchain Any off-chain backends (e.g. IPFS or cloud) labels Jan 5, 2023
@ryscheng ryscheng added this to the protocol: Mainnet launch milestone Jan 5, 2023
@holkexyz
Copy link
Member

holkexyz commented Jan 6, 2023

Just to clarify (are these statements correct?):

  • in the current implementation each impact scope and each work scope is a string. And each hypercert can have as many scopes as the minter assigns
  • in the current implementation the impact and work timeframe is a combination of two numbers that each represents a date
  • in the current implementation the contributors are an ordered list of strings

Technical questions, esp. @ryscheng

  • Is it currently possible for the end of the "time of impact" to be infinity?
  • Is there a technical hurdle to include the positive/negative boolean for the scopes?
  • The scope tags aren't currently ordered lists, right?
  • What does "unknown" stand for on the contributor implementation?

Non-technical questions, esp. @ccerv1

  • Should the scope tags also be ordered lists? That would allow to define which scopes are shown on the front of the hypercert if not all can be shown

@ryscheng
Copy link
Member Author

ryscheng commented Jan 6, 2023

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.

@ryscheng
Copy link
Member Author

ryscheng commented Jan 6, 2023

Clarified with Holke. by positive and negative, I think what he means is include vs exclude.
e.g. Include "IPFS" but exclude "kubo implementation"

@ccerv1
Copy link
Contributor

ccerv1 commented Jan 8, 2023

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:

ERC-1155 properties

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.

Hypercert-specific properties

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:

@holkexyz
Copy link
Member

holkexyz commented Jan 8, 2023

@bitbeckers @ryscheng we are not using the global list of scope tags anymore (as previously implemented), right?

@bitbeckers
Copy link
Contributor

Nope, there is nothing really defined at the moment

@holkexyz
Copy link
Member

holkexyz commented Jan 8, 2023

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

@bitbeckers
Copy link
Contributor

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.

@ccerv1
Copy link
Contributor

ccerv1 commented Jan 8, 2023

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?

@holkexyz
Copy link
Member

holkexyz commented Jan 8, 2023

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}>?

@ryscheng
Copy link
Member Author

ryscheng commented Jan 9, 2023

@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.

@ryscheng
Copy link
Member Author

ryscheng commented Jan 9, 2023

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:

  • 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?
  • How do arrays show up on OpenSea?
  • Does our schema line up with what OpenSea calls a "rich_property"?

Worth experimenting a bit to see before we finalize

CC @bitbeckers

@bitbeckers
Copy link
Contributor

@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.

@ccerv1
Copy link
Contributor

ccerv1 commented Jan 10, 2023

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.

@ccerv1
Copy link
Contributor

ccerv1 commented Jan 12, 2023

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"
    }
}

@bitbeckers
Copy link
Contributor

We'll set up a simple contract on Goerli for testing JSON implementations

@ccerv1
Copy link
Contributor

ccerv1 commented Jan 17, 2023

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"
    }
}

Image

@ryscheng
Copy link
Member Author

Can we add a version number somewhere?
In case we change the schema in the future?

@ccerv1
Copy link
Contributor

ccerv1 commented Jan 26, 2023

Here's a new proposed schema, updated per latest discussions with @holkeb and incorporating davidad's feedback.

Changes:

  • ERC-1155 properties have been removed (OpenSea will not dispaly any properties)
  • The six required hypercert dimensions are clearly enumerated
    • the base case for impact_scope has a value of [], conveying an empty set or effectively a claim to "all" impact
    • all other dimensions are captured as arrays, with display_value fields set via the frontend interface
  • A set of creator_properties have been added, which creators and frontend interfaces can define per their needs
  • A metadata version 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"
}

@ccerv1 ccerv1 added p0:urgent Must address immediately and removed p1:ready Ready for work labels Jan 26, 2023
@ryscheng
Copy link
Member Author

Thanks! this is helpful, couple questions:

  1. I'm curious why OpenSea won't display properties? I'm trying to reconcile this comment with the screenshot above.
  2. I'm curious if it makes sense to use an explicit "any" or "all" impact scope? An empty array to me implies a null/empty set, rather than everything to me...

@holkexyz
Copy link
Member

on 2.: Yes, we can use an explicit "all"

@bitbeckers
Copy link
Contributor

@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.

@ccerv1
Copy link
Contributor

ccerv1 commented Jan 27, 2023

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.

@ccerv1
Copy link
Contributor

ccerv1 commented Jan 27, 2023

Alright! I think we finally have it!

This is what it looks like on OpenSea: https://testnets.opensea.io/assets/goerli/0xffb1fbff7a40ea441aeae8036812af116f593995/57

Updates:

  • Removed the creator properties
  • Promoted optional curation properties so they can be displayed on OpenSea as details
  • Updated hypercert 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"
        }
    }
}

@holkexyz
Copy link
Member

@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

@ryscheng
Copy link
Member Author

ryscheng commented Feb 1, 2023

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.

@holkexyz
Copy link
Member

holkexyz commented Feb 1, 2023

@ccerv1 Regarding the display value of the conjunctive clauses

  • Option 1 (as you had it): "Art Design & Metadata Standards"
  • Option 2 (as an alternative) "Art Design ∧ Metadata Standards"

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 "&"

@ccerv1
Copy link
Contributor

ccerv1 commented Feb 2, 2023

@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"
}

@ccerv1
Copy link
Contributor

ccerv1 commented Feb 5, 2023

Adding an example of a project's metadata here

@ryscheng
Copy link
Member Author

ryscheng commented Feb 6, 2023

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:

  1. having includes, excludes AND values. - I'm generally not in favor of this, redundant data usually means inconsistent data
  2. renaming values in our current implementation to includes. This makes it more explicit and we would NOT have a values field.

@ryscheng
Copy link
Member Author

ryscheng commented Feb 6, 2023

@ryscheng ryscheng closed this as completed Feb 6, 2023
@ryscheng ryscheng self-assigned this Feb 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
category:offchain Any off-chain backends (e.g. IPFS or cloud) p0:urgent Must address immediately
Projects
None yet
Development

No branches or pull requests

4 participants