Skip to content

Commit

Permalink
feat: in progress work on nft-get deals info
Browse files Browse the repository at this point in the history
  • Loading branch information
travis committed Apr 10, 2024
1 parent 6051232 commit c8ad87d
Show file tree
Hide file tree
Showing 8 changed files with 208 additions and 11 deletions.
1 change: 1 addition & 0 deletions packages/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"@ucanto/server": "^9.0.1",
"@web3-storage/access": "^18.2.0",
"@web3-storage/car-block-validator": "^1.2.0",
"@web3-storage/content-claims": "^4.0.4",
"@web3-storage/upload-client": "^13.2.0",
"@web3-storage/w3up-client": "^12.5.0",
"cardex": "^1.0.0",
Expand Down
8 changes: 7 additions & 1 deletion packages/api/src/routes/nfts-get.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { JSONResponse } from '../utils/json-response.js'
import { checkAuth, validate } from '../utils/auth.js'
import { parseCid } from '../utils/utils.js'
import { toNFTResponse } from '../utils/db-transforms.js'
import { getW3upDeals } from '../utils/w3up.js'

/**
* @typedef {import('../bindings').Deal} Deal
Expand All @@ -13,8 +14,13 @@ export const nftGet = async (event, ctx) => {
const { params, db } = ctx
const { user } = checkAuth(ctx)
const cid = parseCid(params.cid)
const nft = await db.getUpload(cid.sourceCid, user.id)
const [nft, w3upDeals] = await Promise.all([
db.getUpload(cid.sourceCid, user.id),
ctx.w3up ? getW3upDeals(ctx.w3up, cid.contentCid) : [],
])
if (nft) {
// merge deals from dagcargo with deals from w3up
nft.deals = [...nft?.deals, ...(w3upDeals || [])]
return new JSONResponse({
ok: true,
value: toNFTResponse(nft, cid.sourceCid),
Expand Down
6 changes: 3 additions & 3 deletions packages/api/src/utils/db-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ export class DBClient {

const cids = uploads?.map((u) => u.content_cid)

const deals = await this.getDealsForCids(cids)
const deals = await this.getDealsFromDagcargoFDW(cids)

return uploads?.map((u) => {
return {
Expand Down Expand Up @@ -515,7 +515,7 @@ export class DBClient {
* @returns {Promise<import('./../bindings').Deal[]>}
*/
async getDeals(cid) {
const deals = await this.getDealsForCids([cid])
const deals = await this.getDealsFromDagcargoFDW([cid])

return deals[cid] ? deals[cid] : []
}
Expand All @@ -527,7 +527,7 @@ export class DBClient {
*
* @param {string[]} cids
*/
async getDealsForCids(cids = []) {
async getDealsFromDagcargoFDW(cids = []) {
try {
const rsp = await this.client.rpc('find_deals_by_content_cids', {
cids,
Expand Down
80 changes: 80 additions & 0 deletions packages/api/src/utils/w3up.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import * as W3UP from '@web3-storage/w3up-client'
import * as ed25519 from '@ucanto/principal/ed25519'
import { StoreMemory } from '@web3-storage/access/stores/store-memory'
import contentClaims from '@web3-storage/content-claims/client'
import { CID } from 'multiformats/cid'
import { base64 } from 'multiformats/bases/base64'
import { identity } from 'multiformats/hashes/identity'
import { CarReader } from '@ipld/car'
import { importDAG } from '@ucanto/core/delegation'
import * as W3upClient from '@web3-storage/w3up-client'
import { parseLink } from '@ucanto/core'
import { connect } from '@ucanto/client'
import { CAR, HTTP } from '@ucanto/transport'

Expand Down Expand Up @@ -106,3 +108,81 @@ export async function createW3upClientFromConfig(options) {
await w3up.addSpace(await parseW3Proof(options.proof))
return w3up
}

/**
*
* @param {W3upClient.Client} client
* @param {import('@web3-storage/upload-client/types').UploadListItem} upload
* @returns {Promise<import('@web3-storage/access').Result<import('@web3-storage/access').FilecoinInfoSuccess>[]>}
*/
async function getFilecoinInfos(client, upload) {
return await Promise.all(
// for each shard of the upload
upload.shards
? upload.shards.map(async (shard) => {
// find the equivalent piece link
const pieceClaims = await contentClaims.read(shard)
const pieceClaim =
/** @type {import('@web3-storage/content-claims/client/api').EqualsClaim} */ (
pieceClaims.find((c) => c.type === 'assert/equals')
)
if (pieceClaim) {
const pieceLink = pieceClaim.equals
// and get filecoin info for it
const filecoinInfo = await client.capability.filecoin.info(
/** @type {import('@web3-storage/access').PieceLink} */ (
pieceLink
)
)
return filecoinInfo.out
} else {
return {
error: {
name: 'PieceLinkClaimNotFound',
message: `could not find piece link equivalent of ${shard}`,
},
}
}
})
: []
)
}

/**
*
* @param {W3upClient.Client | undefined} client
* @param {string} contentCid
* @returns {Promise<import('../bindings').Deal[]>}
*/
export async function getW3upDeals(client, contentCid) {
if (client) {
const link = parseLink(contentCid)
// get the upload
const upload = await client.capability.upload.get(link)
const filecoinInfoResults = await getFilecoinInfos(client, upload)
/**
* @type {import('../bindings').Deal[]}
*/
const filecoinInfos = []
for (const result of filecoinInfoResults) {
if (result.ok) {
const info = result.ok
for (const deal of info.deals) {
filecoinInfos.push({
pieceCid: info.piece.toString(),
status: 'published',
// TODO: figure these two out
datamodelSelector: '',
batchRootCid: deal.aggregate,
})
}
} else {
// @ts-expect-error - in practice this will just be undefined if message doesn't exist
console.warn(`error getting filecoininfo: ${result.error.message}`)
}
}
return filecoinInfos
} else {
return []
}
}
9 changes: 9 additions & 0 deletions packages/api/test/nfts-get.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,20 @@ import {
getMiniflareContext,
setupMiniflareContext,
} from './scripts/test-context.js'
import { read } from '@web3-storage/content-claims/client'
import { parseLink } from '@ucanto/core'

test.before(async (t) => {
await setupMiniflareContext(t)
})

test.only('should fetch deal details from w3up', async (t) => {
const testCid = 'bafybeiccy35oi3gajocq5bbg7pnaxb3kv5ibtdz3tc3kari53qhbjotzey'
const link = parseLink(testCid)
const claims = await read(link)
console.log('CLAIMS', claims)
})

test.serial('should return proper response for cid v1', async (t) => {
const cid = 'bafybeiaj5yqocsg5cxsuhtvclnh4ulmrgsmnfbhbrfxrc3u2kkh35mts4e'
const client = await createClientWithUser(t)
Expand Down
23 changes: 23 additions & 0 deletions packages/website/lib/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,29 @@ export async function getNfts({ limit, before }) {
}
}

/**
* Get NFTs
*
* @param {{cid: string }} query
*/
export async function getNft({ cid }) {
const res = await fetch(`${API}/cid/${cid}}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + (await getToken()),
},
})

const body = await res.json()

if (body.ok) {
return body.value
} else {
throw new Error(body.error.message)
}
}

export async function getUserTags() {
const res = await fetch(`${API}/user/tags`, {
method: 'GET',
Expand Down
3 changes: 3 additions & 0 deletions packages/website/pages/files.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@ export default function Files({ user }) {

const dealsHidden = deals.splice(3)

const [w3upDeals, setW3upDeals] = useState([])
async function loadW3upDeals() {}

if (!nft.deals.length) {
deals.push(
<span
Expand Down
89 changes: 82 additions & 7 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2555,7 +2555,7 @@
cborg "^1.6.0"
multiformats "^9.5.4"

"@ipld/dag-cbor@^9.0.0", "@ipld/dag-cbor@^9.0.5", "@ipld/dag-cbor@^9.0.6", "@ipld/dag-cbor@^9.0.7":
"@ipld/dag-cbor@^9.0.0", "@ipld/dag-cbor@^9.0.3", "@ipld/dag-cbor@^9.0.5", "@ipld/dag-cbor@^9.0.6", "@ipld/dag-cbor@^9.0.7":
version "9.2.0"
resolved "https://registry.yarnpkg.com/@ipld/dag-cbor/-/dag-cbor-9.2.0.tgz#3a3f0bee02d7e1c2f15582e896843d5b00fbba9f"
integrity sha512-N14oMy0q4gM6OuZkIpisKe0JBSjf1Jb39VI+7jMLiWX9124u1Z3Fdj/Tag1NA0cVxxqWDh0CqsjcVfOKtelPDA==
Expand Down Expand Up @@ -5496,6 +5496,25 @@
"@ucanto/core" "^9.0.0"
"@ucanto/interface" "^9.0.0"

"@ucanto/client@^9.0.1":
version "9.0.1"
resolved "https://registry.yarnpkg.com/@ucanto/client/-/client-9.0.1.tgz#ecff79d4f1f56915db11cb6be083764b612afe2b"
integrity sha512-cV8w3AnaZaYCdUmyFFICj8YhFckDoy2DvWgAzGDMkPz0WbUW4lw9Tjm4hEE8x5kiP47wYej/pHKWCcoELiU0qw==
dependencies:
"@ucanto/core" "^10.0.0"
"@ucanto/interface" "^10.0.0"

"@ucanto/core@^10.0.0":
version "10.0.1"
resolved "https://registry.yarnpkg.com/@ucanto/core/-/core-10.0.1.tgz#3df9c875742e8c38461d628878a94b4a1c8a3b4f"
integrity sha512-1BfUaJu0/c9Rl/WdZSDbScJJLsPsPe1g4ynl5kubUj3xDD/lyp/Q12PQVQ2X7hDiWwkpwmxCkRMkOxwc70iNKQ==
dependencies:
"@ipld/car" "^5.1.0"
"@ipld/dag-cbor" "^9.0.0"
"@ipld/dag-ucan" "^3.4.0"
"@ucanto/interface" "^10.0.1"
multiformats "^11.0.2"

"@ucanto/core@^9.0.0", "@ucanto/core@^9.0.1":
version "9.0.1"
resolved "https://registry.yarnpkg.com/@ucanto/core/-/core-9.0.1.tgz#5de481c5d63acc50e287580ee06ac6f2872036ec"
Expand All @@ -5507,6 +5526,14 @@
"@ucanto/interface" "^9.0.0"
multiformats "^11.0.2"

"@ucanto/interface@^10.0.0", "@ucanto/interface@^10.0.1":
version "10.0.1"
resolved "https://registry.yarnpkg.com/@ucanto/interface/-/interface-10.0.1.tgz#939f62237e8b0c1cf0e7f7f2c4753fe3bbfc505b"
integrity sha512-+Vr/N4mLsdynV9/bqtdFiq7WsUf3265/Qx2aHJmPtXo9/QvWKthJtpe0g8U4NWkWpVfqIFvyAO2db6D9zWQfQw==
dependencies:
"@ipld/dag-ucan" "^3.4.0"
multiformats "^11.0.2"

"@ucanto/interface@^9.0.0":
version "9.0.0"
resolved "https://registry.yarnpkg.com/@ucanto/interface/-/interface-9.0.0.tgz#0ba5d1fcfe8a80d829805408d5fda54c344701c1"
Expand All @@ -5528,6 +5555,16 @@
multiformats "^11.0.2"
one-webcrypto "^1.0.3"

"@ucanto/server@^10.0.0":
version "10.0.0"
resolved "https://registry.yarnpkg.com/@ucanto/server/-/server-10.0.0.tgz#b3409c38cb792319418d7b7519fa890e89c025dd"
integrity sha512-JMDMT3tFRE0S1cdtx/Hhh7v9FizV6IS0fPrh6pcli7AzKvXVy8Xu6EQ/66Fax4AQM2tkGxNNxjj2wHM7P4CqAg==
dependencies:
"@ucanto/core" "^10.0.0"
"@ucanto/interface" "^10.0.0"
"@ucanto/principal" "^9.0.0"
"@ucanto/validator" "^9.0.1"

"@ucanto/server@^9.0.1":
version "9.0.1"
resolved "https://registry.yarnpkg.com/@ucanto/server/-/server-9.0.1.tgz#949d38bd2dad30991220f5839608434d400c0bfc"
Expand All @@ -5546,6 +5583,14 @@
"@ucanto/core" "^9.0.1"
"@ucanto/interface" "^9.0.0"

"@ucanto/transport@^9.1.1":
version "9.1.1"
resolved "https://registry.yarnpkg.com/@ucanto/transport/-/transport-9.1.1.tgz#05f1246982a46365d051242d750948e07be29376"
integrity sha512-3CR17nEemOVaTuMZa6waWgVL4sLxSPcxYvpaNeJ6NZo1rfsqdyRXOtbVV/RcI2BtUL0Cao6JM6P9+gdghfc5ng==
dependencies:
"@ucanto/core" "^10.0.0"
"@ucanto/interface" "^10.0.0"

"@ucanto/validator@^9.0.0", "@ucanto/validator@^9.0.1":
version "9.0.1"
resolved "https://registry.yarnpkg.com/@ucanto/validator/-/validator-9.0.1.tgz#ab6458e4400365645119f1b843805fca80ea46b3"
Expand Down Expand Up @@ -5691,6 +5736,18 @@
multiformats "9.9.0"
uint8arrays "^3.1.1"

"@web3-storage/content-claims@^4.0.4":
version "4.0.4"
resolved "https://registry.yarnpkg.com/@web3-storage/content-claims/-/content-claims-4.0.4.tgz#f92d74979baa4fdaba0fb6a75d393e1da8fc8843"
integrity sha512-zt5psR3SkLbPPHzGzhFXYSJEssDl/ELYbNhEez+tNZLZiagv3Vl0RSt+x3CFFgR5ovO6Zn+pLJJcMjpMiHw0Yw==
dependencies:
"@ucanto/client" "^9.0.1"
"@ucanto/interface" "^10.0.0"
"@ucanto/server" "^10.0.0"
"@ucanto/transport" "^9.1.1"
carstream "^1.0.2"
multiformats "^12.0.1"

"@web3-storage/data-segment@^3.2.0":
version "3.2.0"
resolved "https://registry.yarnpkg.com/@web3-storage/data-segment/-/data-segment-3.2.0.tgz#62d109a01fb800486c270e65fb2e482a4bc40b47"
Expand Down Expand Up @@ -7729,6 +7786,15 @@ cardex@^1.0.0:
uint8arrays "^3.0.0"
varint "^6.0.0"

carstream@^1.0.2:
version "1.1.1"
resolved "https://registry.yarnpkg.com/carstream/-/carstream-1.1.1.tgz#4a088015d0b39436baa9e1afc205c0284bd1d111"
integrity sha512-cgn3TqHo6SPsHBTfM5QgXngv6HtwgO1bKCHcdS35vBrweLcYrIG/+UboCbvnIGA0k8NtAYl/DvDdej/9pZGZxQ==
dependencies:
"@ipld/dag-cbor" "^9.0.3"
multiformats "^12.0.1"
uint8arraylist "^2.4.3"

case-sensitive-paths-webpack-plugin@^2.3.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4"
Expand Down Expand Up @@ -18208,16 +18274,11 @@ prettier-linter-helpers@^1.0.0:
dependencies:
fast-diff "^1.1.2"

[email protected], prettier@^2.5.1:
[email protected], "prettier@>=2.2.1 <=2.3.0", prettier@^2.5.1:
version "2.5.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a"
integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==

"prettier@>=2.2.1 <=2.3.0":
version "2.3.0"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.0.tgz#b6a5bf1284026ae640f17f7ff5658a7567fc0d18"
integrity sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==

pretty-error@^2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.2.tgz#be89f82d81b1c86ec8fdfbc385045882727f93b6"
Expand Down Expand Up @@ -21703,6 +21764,13 @@ uglify-js@^3.1.4:
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.0.tgz#55bd6e9d19ce5eef0d5ad17cd1f587d85b180a85"
integrity sha512-aTeNPVmgIMPpm1cxXr2Q/nEbvkmV8yq66F3om7X3P/cvOXQ0TMQ64Wk63iyT1gPlmdmGzjGpyLh1f3y8MZWXGg==

uint8arraylist@^2.4.3:
version "2.4.8"
resolved "https://registry.yarnpkg.com/uint8arraylist/-/uint8arraylist-2.4.8.tgz#5a4d17f4defd77799cb38e93fd5db0f0dceddc12"
integrity sha512-vc1PlGOzglLF0eae1M8mLRTBivsvrGsdmJ5RbK3e+QRvRLOZfZhQROTwH/OfyF3+ZVUg9/8hE8bmKP2CvP9quQ==
dependencies:
uint8arrays "^5.0.1"

uint8arrays@^2.0.5, uint8arrays@^2.1.3, uint8arrays@^2.1.5:
version "2.1.10"
resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-2.1.10.tgz#34d023c843a327c676e48576295ca373c56e286a"
Expand Down Expand Up @@ -21731,6 +21799,13 @@ uint8arrays@^4.0.6:
dependencies:
multiformats "^12.0.1"

uint8arrays@^5.0.1:
version "5.0.3"
resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-5.0.3.tgz#92b894d9c4269ba97c51544d6e1f279fe6f80d1f"
integrity sha512-6LBuKji28kHjgPJMkQ6GDaBb1lRwIhyOYq6pDGwYMoDPfImE9SkuYENVmR0yu9yGgs2clHUSY9fKDukR+AXfqQ==
dependencies:
multiformats "^13.0.0"

unbox-primitive@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"
Expand Down

0 comments on commit c8ad87d

Please sign in to comment.