-
Notifications
You must be signed in to change notification settings - Fork 39
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
IPFS metadata storage #86
Conversation
fd048be
to
76262b4
Compare
Great start @wildmolasses! Before making any changes to the frontend, be sure to rebase to |
cbb988c
to
1e8218d
Compare
b174305
to
bdd8f0d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
left a couple of comments
return ipfsFetch({ | ||
cid: url.split('/').reverse()[0], | ||
}); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^ would it be worth adding comments to the functions on
- what it does
- what are the arguments
It would be useful if we decide to add in auto doc generation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, more comments would be useful!
Re docgen, personally I have not been using NatSpec everywhere, so we'll need some comments cleanup before we do docgen, but you're right that is probably best practice going forward
app/src/store/data.ts
Outdated
@@ -159,6 +161,28 @@ export default function useDataStore() { | |||
lastBlockTimestamp.value = (timestamp as BigNumber).toNumber(); | |||
grants.value = grantsList as Grant[]; | |||
grantRounds.value = grantRoundsList as GrantRound[]; | |||
const metaPtrs = grants.value.map((grant) => grant.metaPtr); | |||
const newMetadata = metaPtrs | |||
.filter((metaPtr) => !grantMetadata.value[metaPtr]) // only want new metaPtrs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just double checking -> it looks like a grant can have multiple metadata but we want only the which as status as pending ?
not super clear on what we are doing here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'll try to add some comments!
@@ -28,6 +28,10 @@ export function isValidAddress(val: string | undefined) { | |||
return val && isAddress(val); | |||
} | |||
|
|||
export function isDefined(val: unknown) { | |||
return !!val; | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd recommend moving this to utils
package
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should hold off on this for now per #114.
Though it also feels like this function is simple enough that it can be removed which might even be more readable (e.g. people know what Boolean()
or !!
does, but would have to look up what isDefined
does
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm using it for form validation; would Boolean()
work just as well? I like how "isDefined" makes things a little more explicit but could defer to you guys!
const form = ref<{ owner: string; payee: string; name: string; description: string }>({ | ||
owner: '', | ||
payee: '', | ||
metaPtr: '', | ||
name: '', | ||
description: '', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we define a local Form
type, since I imagine we'll be adding more fields later too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's only used once I don't think it's necessary, but would defer to you guys
const metaPtr = await ipfs | ||
.createGrant({ name, description }) | ||
.then((cid) => ipfs.createMetaPtr({ cid: cid.toString() })); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just curious why you use a .then
instead of
const metaPtr = await ipfs | |
.createGrant({ name, description }) | |
.then((cid) => ipfs.createMetaPtr({ cid: cid.toString() })); | |
const cid = await ipfs.createGrant({ name, description }) | |
const metaPtr = await ipfs.createMetaPtr({ cid: cid.toString() })); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
my general rule is that if something is used once there's no reason to declare it, i.e. since we don't use cid
elsewhere there's no reason to declare it. i break this sometimes for readability's sake, but then
clauses are pretty readable to me. Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looking and working great, @wildmolasses. Nice job getting this going.
My only comment is on the way we're processing the metaPtr URI. Instead of hacking off the CID from the end— and assuming it's there in the first place— I think we should just have a whitelisted set of endpoints from which the app will fetch content from. This should be separate from the concern of whether the endpoint is an IPFS gateway or not.
In other words, we should have a hardcoded list of valid endpoints, which can include just https://ipfs-api.dev.fleek.cool
for now (or also https://cloudflare-ipfs.com
if we want) and when the metaPtr has a url at one of those endpoints, we should fetch the contents. If it doesn't, it shouldn't fetch, and should probably have an error message like "Unsupported source for grant metadata" or something like that.
Curious to hear what others think of this approach cc @thelostone-mc @mds1 @gdixon
In principle I know that's correct, however different endpoints have different auth models -- well, really, fleek is the one where we need an api key in order to fetch. So if we're going to use the fleek endpoint as our metaPtr, do we want to write conditional logic where if the metaPtr is fleek (which is currently the case for any grant created by this app) then use an api key, and otherwise proceed without auth token? it starts to feel a little weird, but maybe this is acceptable. |
Per our discussion offline, I think the right approach here is to use keep metaptr fetching dumb, so an http endpoint that requires an API key should not be used. For the immediate term, we can use a whitelisted cloudflare (or another open IPFS gateway) as the metaPtr URL, therefore allowing us to fetch without any authentication. |
5762326
to
8189da3
Compare
8189da3
to
0299e5f
Compare
This PR resolves #67
Important note: This PR uses a trick to accomplish the metaPtr resolution. Instead of resolving the metaPtr directly, it splits the URL, takes the CID, and resolves that with our fleek ipfs connection instance. Even if a metaPtr specified the cloudflare gateway, it would still use fleek to resolve. If a metaPtr did not have a CID in the last position of the URL, the fetch would completely fail.
The metadata fetching isn't robust. If the fetch fails, the metadata status will be 'error' and it will not reattempt a fetch.
There are no UI states yet corresponding to the metadata fetch status states of "pending", "resolved", "error"