Skip to content

Commit c394586

Browse files
authored
Merge pull request #340 from kleros/chore/upload-to-ipfs-function-point-to-court-functions
chore: point-upload-to-ipfs-function-to-court-function
2 parents a48d49f + 5977db2 commit c394586

File tree

8 files changed

+44
-2268
lines changed

8 files changed

+44
-2268
lines changed

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ REACT_APP_METAMASK_SITE_URL=https://metamask.io
55
REACT_APP_TRUST_SITE_URL=https://trustwallet.com
66
REACT_APP_DEFAULT_NETWORK=1
77
REACT_APP_REJECT_ALL_POLICY_URI="/ipfs/QmZ7RVU7re1g8nXDbAFMHV99pyie3dn4cY7Ga2X4h8mDpV/reject-all-policy.pdf"
8+
REACT_APP_COURT_FUNCTIONS_URL=https://kleros-api.netlify.app
89

910
# All fields below this line are optional -------------
1011

netlify.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
[build.environment]
66
NODE_VERSION='16.20.2'
77
REACT_APP_IPFS_GATEWAY="https://cdn.kleros.link"
8-
REACT_APP_HOSTED_GRAPH_IPFS_ENDPOINT="https://api.thegraph.com/ipfs"
98
REACT_APP_DEFAULT_NETWORK="1"
109

1110
REACT_APP_REJECT_ALL_POLICY_URI='/ipfs/QmZ7RVU7re1g8nXDbAFMHV99pyie3dn4cY7Ga2X4h8mDpV/reject-all-policy.pdf'
1211
REACT_APP_METAMASK_SITE_URL='https://metamask.io'
1312
REACT_APP_TRUST_SITE_URL='https://trustwallet.com'
1413
REACT_APP_WALLETCONNECT_BRIDGE_URL='https://bridge.walletconnect.org'
1514
REACT_APP_INSTRUCTION_VIDEO='https://www.youtube.com/embed/DKPVWzhh8Y8'
15+
REACT_APP_COURT_FUNCTIONS_URL='https://kleros-api.netlify.app'
1616

1717
[[redirects]]
1818
from = "/*"

netlify/functions/uploadToIPFS.ts

Lines changed: 0 additions & 123 deletions
This file was deleted.

package.json

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
},
1616
"dependencies": {
1717
"@apollo/client": "^3.4.8",
18-
"@filebase/client": "^0.0.5",
1918
"@fortawesome/fontawesome-svg-core": "^1.2.25",
2019
"@fortawesome/free-brands-svg-icons": "^5.9.0",
2120
"@fortawesome/free-solid-svg-icons": "^5.11.2",
@@ -28,11 +27,9 @@
2827
"@loadable/component": "^5.10.1",
2928
"@walletconnect/qrcode-modal": "^1.0.0-beta.35",
3029
"@walletconnect/web3-subprovider": "^1.0.0-beta.35",
31-
"amqplib": "^0.10.3",
3230
"antd": "^3.20.1",
3331
"bn.js": "^5.0.0",
3432
"body-scroll-lock": "^3.0.2",
35-
"busboy": "^1.6.0",
3633
"cross-fetch": "^4.0.0",
3734
"ethers": "^4.0.33",
3835
"fast-deep-equal": "^3.1.3",
@@ -67,9 +64,6 @@
6764
"@babel/helper-define-map": "^7.15.4",
6865
"@commitlint/cli": "^8.0.0",
6966
"@commitlint/config-conventional": "^8.0.0",
70-
"@netlify/functions": "^1.6.0",
71-
"@types/amqplib": "^0.10.4",
72-
"@types/busboy": "^1.5.3",
7367
"@types/humanize-duration": "^3.27.1",
7468
"@types/loadable__component": "^5.13.4",
7569
"@types/mime": "^3.0.0",

src/utils/get-ipfs-path.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,12 @@ export interface IPFSResultObject {
33
}
44

55
export const getIPFSPath = (ipfsResultObject: IPFSResultObject): string =>
6-
`/ipfs/${ipfsResultObject.cids[0].split('ipfs://')[1]}`
6+
getFormattedPath(ipfsResultObject.cids[0])
7+
8+
/**
9+
*
10+
* @param url an ipfs cid
11+
* @returns formats an ipfs cid to be in /ipfs/hash format, reolaces ipfs://, ipfs/, with /ipfs/
12+
*/
13+
export const getFormattedPath = (url: string) =>
14+
url.replace(/^(ipfs:\/\/|ipfs\/?)/, '/ipfs/')

src/utils/ipfs-publish.js

Lines changed: 5 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import deepEqual from 'fast-deep-equal/es6'
21
import { uploadFormDataToIPFS } from './upload-form-data-to-ipfs'
32

43
const mirroredExtensions = ['.json']
@@ -19,102 +18,18 @@ export default async function ipfsPublish(fileName, data) {
1918
fileFormData.append('data', blobFile, fileName)
2019

2120
if (!mirroredExtensions.some(ext => fileName.endsWith(ext))) {
22-
const klerosResult = await uploadFormDataToIPFS(fileFormData)
23-
const klerosResultJSON = await klerosResult.json()
24-
return klerosResultJSON
21+
const result = await uploadFormDataToIPFS(fileFormData)
22+
return result
2523
}
2624

27-
const [klerosResult, theGraphResult] = await Promise.all([
28-
uploadFormDataToIPFS(fileFormData),
29-
publishToTheGraphNode(fileName, data)
30-
])
25+
const result = await uploadFormDataToIPFS(fileFormData, 'file', true)
3126

32-
const klerosResultJSON = await klerosResult.json()
33-
const klerosHash = klerosResultJSON.cids[0].split('ipfs://')[1].split('/')[0]
34-
35-
const normalizedKlerosResult = {
36-
hash: klerosHash
37-
}
38-
39-
const normalizedTheGraphResult = {
40-
hash: theGraphResult[1].hash
41-
}
42-
43-
if (!deepEqual(normalizedKlerosResult, normalizedTheGraphResult)) {
27+
if (result.inconsistentCids.length > 0) {
4428
console.warn('IPFS upload result is different:', {
45-
kleros: normalizedKlerosResult,
46-
theGraph: normalizedTheGraphResult
29+
inconsistentCids: result.inconsistentCids
4730
})
4831
throw new Error('IPFS upload result is different.')
4932
}
5033

51-
return klerosResultJSON
52-
}
53-
54-
/**
55-
* Send file to IPFS network via The Graph hosted IPFS node
56-
* @param {string} fileName - The name that will be used to store the file. This is useful to preserve extension type.
57-
* @param {ArrayBuffer} data - The raw data from the file to upload.
58-
* @returns {object} ipfs response. Should include the hash and path of the stored item.
59-
*/
60-
async function publishToTheGraphNode(fileName, data) {
61-
const url = `${process.env.REACT_APP_HOSTED_GRAPH_IPFS_ENDPOINT}/api/v0/add?wrap-with-directory=true`
62-
63-
const payload = new FormData()
64-
payload.append('file', new Blob([data]), fileName)
65-
66-
const response = await fetch(url, {
67-
method: 'POST',
68-
body: payload
69-
})
70-
71-
const result = await jsonStreamToPromise(response.body)
72-
73-
return result.map(({ Name, Hash }) => ({
74-
hash: Hash,
75-
path: `/${Name}`
76-
}))
77-
}
78-
79-
/**
80-
* Accumulates a JSON stream body into an array of JSON objects.
81-
* @param {ReadableStream} stream The stream to read from.
82-
* @returns {Promise<any>} An array of all JSON objects emitted by the stream.
83-
*/
84-
async function jsonStreamToPromise(stream) {
85-
const reader = stream.getReader()
86-
const decoder = new TextDecoder('utf-8')
87-
88-
const deferred = {
89-
resolve: undefined,
90-
reject: undefined
91-
}
92-
93-
const result = new Promise((resolve, reject) => {
94-
deferred.resolve = resolve
95-
deferred.reject = reject
96-
})
97-
98-
const acc = []
99-
const start = async () => {
100-
reader
101-
.read()
102-
.then(({ done, value }) => {
103-
if (done) return deferred.resolve(acc)
104-
105-
// Each `read` can produce one or more lines...
106-
const lines = decoder.decode(value).split(/\n/)
107-
const objects = lines
108-
.filter(line => line.trim() !== '')
109-
.map(line => JSON.parse(line))
110-
acc.push(...objects)
111-
112-
return start()
113-
})
114-
.catch(err => deferred.reject(err))
115-
}
116-
117-
start()
118-
11934
return result
12035
}

src/utils/upload-form-data-to-ipfs.ts

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
import { fetch } from 'cross-fetch'
22

3-
export function uploadFormDataToIPFS(
3+
export async function uploadFormDataToIPFS(
44
formData: FormData,
5-
operation: string = 'evidence'
5+
operation: string = 'evidence',
6+
pinToGraph = false
67
): Promise<Response> {
7-
const url = `/.netlify/functions/uploadToIPFS?dapp=curate&key=curate-v1&operation=${operation}`
8+
const url = `${process.env.REACT_APP_COURT_FUNCTIONS_URL}/.netlify/functions/upload-to-ipfs?operation=${operation}&pinToGraph=${pinToGraph}`
89

9-
return fetch(url, {
10+
const response = await fetch(url, {
1011
method: 'POST',
1112
body: formData
12-
}).then(async response => {
13-
if (response.status !== 200) {
14-
const error = await response
15-
.json()
16-
.catch(() => ({ message: 'Error uploading to IPFS' }))
17-
throw new Error(error.message)
18-
}
19-
return response
2013
})
14+
15+
if (response.status !== 200) {
16+
const error = await response
17+
.json()
18+
.catch(() => ({ message: 'Error uploading to IPFS' }))
19+
throw new Error(error.message)
20+
}
21+
const data = await response.json()
22+
return data
2123
}

0 commit comments

Comments
 (0)