-
Notifications
You must be signed in to change notification settings - Fork 1
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
Allow IPFS URLs to Contain Path Elements #12
base: dev
Are you sure you want to change the base?
Changes from 3 commits
a4fd3cb
64f8b57
129fb99
a51bd00
9ff49bf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,8 +3,8 @@ | |
"version": "0.1.0", | ||
"license": "GPL-3.0", | ||
"devDependencies": { | ||
"@graphprotocol/graph-cli": "0.71.1", | ||
"@graphprotocol/graph-ts": "0.35.1", | ||
"@graphprotocol/graph-cli": "^0.91.1", | ||
"@graphprotocol/graph-ts": "^0.36.0", | ||
"husky": "^9.0.11", | ||
"lint-staged": "^15.2.2", | ||
"mustache": "^4.2.0", | ||
|
@@ -43,5 +43,6 @@ | |
"*.{json,yml,yaml,md,ts}": [ | ||
"prettier --write" | ||
] | ||
} | ||
}, | ||
"packageManager": "[email protected]+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
export * from './constants'; | ||
export * from './ipfs'; | ||
export { Metadata } from './ipfs'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Barrel files that don't use named exports will break tree-shaking in bundlers. |
||
export * from './network'; | ||
export * from './strings'; | ||
export * from './schema'; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,75 +1,72 @@ | ||
import { ipfs, json, log } from '@graphprotocol/graph-ts'; | ||
import { ipfs, json, JSONValue, log, TypedMap } from '@graphprotocol/graph-ts'; | ||
|
||
class Metadata { | ||
name: string | null; | ||
description: string | null; | ||
imageUrl: string | null; | ||
animationUrl: string | null; | ||
externalUrl: string | null; | ||
mimeType: string | null; | ||
slug: string | null; | ||
categories: string[] | null; | ||
export class Metadata { | ||
name: string | null = null; | ||
description: string | null = null; | ||
imageUrl: string | null = null; | ||
animationUrl: string | null = null; | ||
externalUrl: string | null = null; | ||
mimeType: string | null = null; | ||
slug: string | null = null; | ||
categories: string[] | null = null; | ||
|
||
constructor() { | ||
this.name = null; | ||
this.description = null; | ||
this.imageUrl = null; | ||
this.animationUrl = null; | ||
this.externalUrl = null; | ||
this.mimeType = null; | ||
this.slug = null; | ||
static from(detailsURL: string): Metadata { | ||
const metadata = new Metadata(); | ||
const path = stripProtocol(detailsURL); | ||
if (path != null) { | ||
const data = fetchIPFSData(path); | ||
if (data != null) { | ||
metadata.name = getString(data, 'name'); | ||
metadata.description = getString(data, 'description'); | ||
metadata.imageUrl = getString(data, 'image_url'); | ||
metadata.animationUrl = getString(data, 'animation_url'); | ||
metadata.externalUrl = getString(data, 'external_url'); | ||
metadata.mimeType = getString(data, 'mime_type'); | ||
metadata.slug = getString(data, 'slug'); | ||
metadata.categories = getArray(data, 'categories'); | ||
} | ||
} | ||
return metadata; | ||
} | ||
} | ||
|
||
|
||
function fetchHash(details: string): string { | ||
let parts = details.split('/'); | ||
return parts.length > 0 ? parts[parts.length - 1] : ''; | ||
function stripProtocol(details: string): string { | ||
if (details.toLowerCase().startsWith('ipfs://')) { | ||
details = details.slice(7); | ||
} | ||
return details; | ||
} | ||
|
||
function fetchIpfsData(hash: string) { | ||
let ipfsData = ipfs.cat(hash); | ||
if (ipfsData) { | ||
log.info('IPFS details from hash {}, data {}', [hash, ipfsData.toString()]); | ||
return json.fromBytes(ipfsData).toObject(); | ||
} else { | ||
log.warning('could not get IPFS details from hash {}', [hash]); | ||
return null; | ||
function fetchIPFSData(path: string): TypedMap<string, JSONValue> | null { | ||
const raw = ipfs.cat(path); | ||
if (raw) { | ||
log.info(`Details from "${path}": ${raw}`, []); | ||
return json.fromBytes(raw).toObject(); | ||
} | ||
log.warning(`Couldn't get details from "${path}"`, []); | ||
return null; | ||
} | ||
|
||
function assignMetadataValue(data: any, key: string): string | null { | ||
let value = data.get(key); | ||
function getString( | ||
data: TypedMap<string, JSONValue>, | ||
key: string, | ||
): string | null { | ||
const value = data.get(key); | ||
return value != null && !value.isNull() ? value.toString() : null; | ||
} | ||
|
||
function assignMetadataCategories(data: any): string[] | null { | ||
let categories = data.get('categories'); | ||
if (categories != null && !categories.isNull()) { | ||
let categoryArray = categories.toArray(); | ||
return categoryArray.map(category => category.toString()); | ||
function getArray( | ||
data: TypedMap<string, JSONValue>, | ||
key: string, | ||
): string[] | null { | ||
const value = data.get(key); | ||
if (value != null && !value.isNull()) { | ||
const array = value.toArray(); | ||
return array.map<string>((elem: JSONValue) => elem.toString()); | ||
} | ||
return null; | ||
} | ||
|
||
export function fetchMetadata(details: string): Metadata { | ||
let metadata = new Metadata(); | ||
if (details == '') return metadata; | ||
|
||
let hash = fetchHash(details); | ||
if (hash != '') { | ||
let data = fetchIpfsData(hash); | ||
if (data) { | ||
metadata.name = assignMetadataValue(data, 'name'); | ||
metadata.description = assignMetadataValue(data, 'description'); | ||
metadata.imageUrl = assignMetadataValue(data, 'image_url'); | ||
metadata.animationUrl = assignMetadataValue(data, 'animation_url'); | ||
metadata.externalUrl = assignMetadataValue(data, 'external_url'); | ||
metadata.mimeType = assignMetadataValue(data, 'mime_type'); | ||
metadata.slug = assignMetadataValue(data, 'slug'); | ||
metadata.categories = assignMetadataCategories(data); | ||
} | ||
} | ||
|
||
return metadata; | ||
function snakeToCamel(str: string): string { | ||
return str.replace(/_([a-z])/gi, (_, char) => char.toUpperCase()); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,24 @@ | ||
import { dataSource } from '@graphprotocol/graph-ts'; | ||
import { dataSource, TypedMap } from '@graphprotocol/graph-ts'; | ||
|
||
export function getNetwork(): string { | ||
const network = dataSource.network(); | ||
const networkMap: { [key: string]: string } = { | ||
'mainnet': '0x1', | ||
'kovan': '0x2a', | ||
'rinkeby': '0x4', | ||
'ropsten': '0x3', | ||
'goerli': '0x5', | ||
'poa-core': '0x63', | ||
'poa-sokol': '0x4d', | ||
'gnosis': '0x64', | ||
'matic': '0x89', | ||
'mumbai': '0x13881', | ||
'arbitrum-one': '0xa4b1', | ||
'arbitrum-goerli': '0x66eed', | ||
'optimism': '0xa', | ||
'optimism-kovan': '0x45', | ||
'aurora': '0x4e454152', | ||
'aurora-testnet': '0x4e454153', | ||
'sepolia': '0xaa36a7', | ||
'holesky': '0x4268' | ||
}; | ||
|
||
return networkMap[network] || 'unknown'; | ||
if (network === 'mainnet') return '0x1'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It bitched alot about the eight different ways I tried to type the object literal & the AIs said they don't exist in AssemblyScript. |
||
if (network === 'kovan') return '0x2a'; | ||
if (network === 'rinkeby') return '0x4'; | ||
if (network === 'ropsten') return '0x3'; | ||
if (network === 'goerli') return '0x5'; | ||
if (network === 'poa-core') return '0x63'; | ||
if (network === 'poa-sokol') return '0x4d'; | ||
if (network === 'gnosis') return '0x64'; | ||
if (network === 'matic') return '0x89'; | ||
if (network === 'mumbai') return '0x13881'; | ||
if (network === 'arbitrum-one') return '0xa4b1'; | ||
if (network === 'arbitrum-goerli') return '0x66eed'; | ||
if (network === 'optimism') return '0xa'; | ||
if (network === 'optimism-kovan') return '0x45'; | ||
if (network === 'aurora') return '0x4e454152'; | ||
if (network === 'aurora-testnet') return '0x4e454153'; | ||
if (network === 'sepolia') return '0xaa36a7'; | ||
if (network === 'holesky') return '0x4268'; | ||
return 'unknown'; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,12 +5,7 @@ import { | |
TransferSingle as TransferSingleEvent, | ||
URI as URIEvent, | ||
} from '../../types/templates/QuestChainTokenV0/QuestChainTokenV0'; | ||
import { | ||
ADDRESS_ZERO, | ||
removeFromArray, | ||
fetchMetadata, | ||
getUser, | ||
} from '../helpers'; | ||
import { ADDRESS_ZERO, removeFromArray, Metadata, getUser } from '../helpers'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prettier squished this line. |
||
|
||
export function handleTransferSingle(event: TransferSingleEvent): void { | ||
let tokenId = event.address | ||
|
@@ -52,7 +47,7 @@ export function handleURIUpdated(event: URIEvent): void { | |
token.tokenAddress = event.address; | ||
|
||
let details = event.params.value; | ||
let metadata = fetchMetadata(details); | ||
const metadata = Metadata.from(details); | ||
token.details = details; | ||
token.name = metadata.name; | ||
token.description = metadata.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.
I updated these trying to get the
yarn deploy-local
task to run.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.
This repo is using really old versions of graphprotocol as you can see, so lot of things might break as you upgrade since they often introduce some breaking changes
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 AssemblyScript doesn't support iterators, it seems like it never would have supported itertators. It'd be weird to remove support for something like that…
In any case, I replaced the iterators with a
for
loop & the AssemblyScript will now compile to WASM. I deployed the code to the Subgraph Studio & everything seems to work, if you'd like use it.We're about to redeploy the contracts so the spurious entries will stop showing up in questchains.xyz.