Skip to content
This repository was archived by the owner on Dec 5, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions dashboard/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@ yarn-error.log*

.vercel
/test

# Local Netlify folder
.netlify
1 change: 1 addition & 0 deletions dashboard/functions/pinHash.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dashboard/functions/pinJson.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dashboard/functions/test.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dashboard/functions/unpin.js

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions dashboard/netlify.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
[build]
# This will be your default build command.
command = "npm run build"
# This is where Netlify will look for your lambda functions.
functions = "functions"
# This is the directory that you are publishing from.
publish = "dist"
[[redirects]]
from = "/*"
to = "/index.html"
Expand Down
6 changes: 4 additions & 2 deletions dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"build": "netlify-lambda build src-functions && vue-cli-service build",
"lint": "vue-cli-service lint",
"i18n:report": "vue-cli-service i18n:report --src './src/**/*.?(js|vue)' --locales './src/locales/**/*.json'",
"start": "vue-cli-service serve"
"start": "vue-cli-service serve",
"lambda": "netlify-lambda serve src-functions"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^1.2.34",
Expand All @@ -33,6 +34,7 @@
"lazysizes": "^5.3.0",
"markdown-it-vue": "^1.1.6",
"mingo": "^4.1.2",
"netlify-lambda": "^2.0.4",
"register-service-worker": "^1.7.1",
"setimmediate": "^1.0.5",
"slugify": "^1.4.6",
Expand Down
35 changes: 35 additions & 0 deletions dashboard/src-functions/pinHash.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import axios from "axios"

exports.handler = async (event, context) => {


// const location = event.queryStringParameters.location || "home";
const BASE_URL = 'https://api.pinata.cloud/pinning/pinByHash';
const object = event.body;

try {
const { status, data } = await axios.post(BASE_URL, object, {
headers: {
'Content-Type': 'application/json',
pinata_api_key: process.env.PINATA_API_KEY,
pinata_secret_api_key: process.env.PINATA_SECRET_API_KEY
},
});
console.log('[PINATA] Pin HASH', status, data);

return {
statusCode: status,
body: JSON.stringify(data),
};


} catch (e) {
console.log('Error', e.message)
return {
statusCode: 500,
body: e.message,
};
}

};

43 changes: 43 additions & 0 deletions dashboard/src-functions/pinJson.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import axios from "axios"

exports.handler = async (event, context) => {


// const location = event.queryStringParameters.location || "home";
const BASE_URL = 'https://api.pinata.cloud/pinning/pinJSONToIPFS';
const object = event.body;

try {
const { status, data } = await axios.post(BASE_URL, object, {
headers: {
'Content-Type': 'application/json',
pinata_api_key: process.env.PINATA_API_KEY,
pinata_secret_api_key: process.env.PINATA_SECRET_API_KEY
},
});
console.log('[PINATA] Pin JSON', status, data);

if (status < 400) {
return {
statusCode: status,
body: JSON.stringify(data),
};
}


} catch (e) {
console.log('Error', e.message)
return {
statusCode: 500,
body: e.message,
};
}

return {
statusCode: status,
body: JSON.stringify({}),
};


};

34 changes: 34 additions & 0 deletions dashboard/src-functions/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import axios from "axios"

exports.handler = async (event, context) => {

const BASE_URL = `https://api.pinata.cloud/data/testAuthentication`;
const { PINATA_API_KEY, PINATA_SECRET_API_KEY } = process.env;

console.log(PINATA_API_KEY, PINATA_SECRET_API_KEY)

try {
const { status, data } = await axios.get(BASE_URL, {
headers: {
pinata_api_key: PINATA_API_KEY || '1132c4704eda6c83a876',
pinata_secret_api_key: PINATA_SECRET_API_KEY || '684571ddca0c3e2ba69876a0d339c6d64bc88446a5eee5182ceccfaad8e12e7b'
},
});
console.log('[PINATA] TEST', status, data);

return {
statusCode: status,
body: JSON.stringify(data),
};


} catch (e) {
console.log('Error', e.message)
return {
statusCode: 500,
body: e.message,
};
}

};

42 changes: 42 additions & 0 deletions dashboard/src-functions/unpin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import axios from "axios"

exports.handler = async (event, context) => {


const hash = event.queryStringParameters.hash;

if (!hash) {
return {
statusCode: 403,
body: `Cannot unpin without hash`,
};
}

const BASE_URL = `https://api.pinata.cloud/pinning/unpin/${hash}`;

try {
const { status, data } = await axios.delete(BASE_URL, {
headers: {
'Content-Type': 'application/json',
pinata_api_key: process.env.PINATA_API_KEY,
pinata_secret_api_key: process.env.PINATA_SECRET_API_KEY
},
});
console.log('[PINATA] Pin HASH', status, data);

return {
statusCode: status,
body: JSON.stringify(data),
};


} catch (e) {
console.log('Error', e.message)
return {
statusCode: 500,
body: e.message,
};
}

};

3 changes: 2 additions & 1 deletion dashboard/src/components/rmrk/Create/CreateCollection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ import RmrkVersionMixin from '@/utils/mixins/rmrkVersionMixin';

import { getInstance, RmrkType } from '../service/RmrkService';
import { Collection, CollectionMetadata } from '../service/scheme';
import { pinFile, pinJson, unSanitizeIpfsUrl } from '@/pinata';
import { unSanitizeIpfsUrl } from '@/utils/ipfs';
import { pinFile, pinJson } from '@/proxy';
import { decodeAddress } from '@polkadot/keyring';
import { u8aToHex } from '@polkadot/util';
import { generateId } from '@/components/rmrk/service/Consolidator'
Expand Down
3 changes: 2 additions & 1 deletion dashboard/src/components/rmrk/Create/CreateToken.vue
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ import {
NFT,
NFTMetadata,
} from '../service/scheme';
import { pinFile, pinJson, unSanitizeIpfsUrl } from '@/pinata';
import { pinFile, pinJson } from '@/proxy';
import { unSanitizeIpfsUrl } from '@/utils/ipfs';
import PasswordInput from '@/components/shared/PasswordInput.vue';
import slugify from 'slugify'
import { fetchCollectionMetadata } from '../utils';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import Connector from '@vue-polkadot/vue-api';
import exec, { execResultValue } from '@/utils/transactionExecutor';
import { notificationTypes, showNotification } from '@/utils/notification';
import { getInstance, RmrkType } from '../service/RmrkService';
import { unpin } from '@/pinata';
import { unpin } from '@/proxy';
import Consolidator from '../service/Consolidator';
import RmrkVersionMixin from '@/utils/mixins/rmrkVersionMixin';
import { somePercentFromTX } from '@/utils/support';
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/components/rmrk/Gallery/Item/Facts.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@

<script lang="ts" >
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
import { extractCid } from '@/pinata';
import { extractCid } from '@/utils/ipfs';
import { NFTWithMeta } from '../../service/scheme';
import { emptyObject } from '@/utils/empty';
const components = {
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/components/rmrk/service/RmrkService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Consolidator, { generateId } from './Consolidator';
import { keyInfo as keysToTheKingdom } from '@/textile'
import slugify from 'slugify';
import { fetchCollectionMetadata, fetchNFTMetadata } from '../utils';
import { ipfsToArweave } from '@/pinata'
import { ipfsToArweave } from '@/utils/ipfs'
import { fetchMimeType } from '@/fetch';

export type RmrkType = RmrkWithMetaType | Emotion | Pack
Expand Down
2 changes: 2 additions & 0 deletions dashboard/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import i18n from './i18n'
import mingo from 'mingo'
import api from './fetch'
import { baseIpfsPrice, cost, getFileSize, supportTx } from './utils/support'
import axios from 'axios'


import { useOperators, OperatorType } from 'mingo/core'
Expand All @@ -52,6 +53,7 @@ Vue.filter('shortAddress', shortAddress);
(window as any).mingo = mingo;
(window as any).api = api;
(window as any).P = { baseIpfsPrice, cost, getFileSize, supportTx};
(window as any).axios = axios;
// (window as any).migrateCollection = migrateCollection;
// (window as any).migrateNFT = migrateNFT;

Expand Down
41 changes: 1 addition & 40 deletions dashboard/src/pinata.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Axios from 'axios';
import { extractCid, justHash } from './utils/ipfs';

export const BASE_URL = 'https://api.pinata.cloud/pinning/';

Expand Down Expand Up @@ -58,47 +59,7 @@ export const unpin = async (ipfsLink: string) => {
}
};

export const unSanitizeIpfsUrl = (url: string) => {
return `ipfs://ipfs/${url}`;
};

export const justHash = (ipfsLink?: string): boolean => {
return /^[a-zA-Z0-9]+$/.test(ipfsLink || '');
};

const cidRegex: RegExp = /ipfs\/([a-zA-Z0-9]+)\/?$/;
export const extractCid = (ipfsLink?: string): string => {
if (!ipfsLink) {
return '';
}

const match = ipfsLink.match(cidRegex);

return match ? match[1] : '';
};

type IpfsToArweaveType = {
arweaveId: string;
ipfsHash: string;
statusCode: number;
}

const IPFS2AR = 'https://ipfs2arweave.com/permapin/'
export const ipfsToArweave = async (ipfsLink: string): Promise<string> => {
const hash = justHash(ipfsLink) ? ipfsLink : extractCid(ipfsLink)
try {
const res = await fetch(IPFS2AR + hash, {method: 'POST'})
if (res.ok) {
return (await res.json()).arweaveId
}

return ''
} catch (e) {
console.error(`[IPFS2AR] Unable to Arweave ${e.message}`)
return ''
}

}

export default api;
// QmYt2FydonvVMsEqe2q3hvm38WDq21xM8Z5ZSHZw19PwjF;
62 changes: 62 additions & 0 deletions dashboard/src/proxy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import Axios from 'axios';
import { extractCid, justHash } from './utils/ipfs';

export const BASE_URL = `${window.location.origin}/.netlify/functions/`;

const api = Axios.create({
baseURL: BASE_URL
});

export const pinJson = async (object: any) => {
try {
const { status, data } = await api.post('pinJson', object);
console.log('[PROXY] Pin JSON', status, data);
if (status < 400) {
return data.IpfsHash;
}
} catch (e) {
throw e;
}
};

export const pinFile = async (file: Blob): Promise<string> => {
const formData = new FormData();
formData.append('file', file);

const SLATE_URL = 'https://uploads.slate.host/api/public'

try {
const { status, data } = await Axios.post(SLATE_URL, formData, {
headers: {
'Content-Type': `multipart/form-data`,
Authorization: `Basic ${process.env.VUE_APP_SLATE_KEY}`
}
});
console.log('[PROXY] SLATE Image', status, data);
if (status < 400) {
await api.post('pinHash', { hashToPin: data.data.cid })
return data.data.cid;
} else {
throw new Error('Unable to PIN for reasons');
}
} catch (e) {
throw e;
}
};

export const unpin = async (ipfsLink: string) => {
const hash = justHash(ipfsLink) ? ipfsLink : extractCid(ipfsLink)
try {
const { status, data } = await api.delete(`unpin/?hash=${hash}`);
console.log('[PROXY] Unpin whatever', status, data);
if (status < 400) {
return data;
}
} catch (e) {
throw e;
}
};


export default api;
// QmYt2FydonvVMsEqe2q3hvm38WDq21xM8Z5ZSHZw19PwjF;
Loading