diff --git a/components/Navbar.vue b/components/Navbar.vue index cf4ea57c3a..ba76963e19 100644 --- a/components/Navbar.vue +++ b/components/Navbar.vue @@ -56,7 +56,11 @@ - + @@ -134,6 +138,7 @@ import PrefixMixin from '~/utils/mixins/prefixMixin' import Identity from '@/components/shared/format/Identity.vue' import Search from '@/components/rmrk/Gallery/Search/SearchBar.vue' import BasicImage from '@/components/shared/view/BasicImage.vue' +import { createVisible } from '@/utils/config/permision.config' import { identityStore } from '@/utils/idbStore' import { get } from 'idb-keyval' @@ -173,6 +178,10 @@ export default class NavbarMenu extends mixins(PrefixMixin) { return this.$route.name === 'rmrk-u-id' } + get isCreateVisible(): boolean { + return createVisible(this.urlPrefix) + } + get isTargetPage(): boolean { return ( this.inCollectionPage || diff --git a/components/bsx/Create/CreateCollection.vue b/components/bsx/Create/CreateCollection.vue index 49d0917cca..e84087e6d7 100644 --- a/components/bsx/Create/CreateCollection.vue +++ b/components/bsx/Create/CreateCollection.vue @@ -44,7 +44,7 @@ import ChainMixin from '@/utils/mixins/chainMixin' import MetaTransactionMixin from '@/utils/mixins/metaMixin' import PrefixMixin from '@/utils/mixins/prefixMixin' import { notificationTypes, showNotification } from '@/utils/notification' -import { pinJson, PinningKey } from '@/utils/pinning' +import { pinJson, PinningKey } from '@/utils/nftStorage' import resolveQueryPath from '@/utils/queryPathResolver' import { getImageTypeSafe, pinImageSafe } from '@/utils/safePin' import { estimate } from '@/utils/transactionExecutor' diff --git a/components/bsx/Create/CreateToken.vue b/components/bsx/Create/CreateToken.vue index 9d8b557591..e220bc8c3f 100644 --- a/components/bsx/Create/CreateToken.vue +++ b/components/bsx/Create/CreateToken.vue @@ -63,7 +63,7 @@ import { } from '@/components/rmrk/Create/mintUtils' import ChainMixin from '@/utils/mixins/chainMixin' import { notificationTypes, showNotification } from '@/utils/notification' -import { pinFileToIPFS, pinJson, PinningKey } from '@/utils/pinning' +import { pinFileToIPFS, pinJson, PinningKey } from '@/utils/nftStorage' import shouldUpdate from '@/utils/shouldUpdate' import { Attribute, @@ -80,14 +80,20 @@ import { } from '@/components/unique/apiConstants' import { createTokenId } from '@/components/unique/utils' import onApiConnect from '@/utils/api/general' -import { IPFS_KODADOT_IMAGE_PLACEHOLDER } from '@/utils/constants' +import { + DETAIL_TIMEOUT, + IPFS_KODADOT_IMAGE_PLACEHOLDER, +} from '@/utils/constants' import AuthMixin from '@/utils/mixins/authMixin' import MetaTransactionMixin from '@/utils/mixins/metaMixin' import PrefixMixin from '@/utils/mixins/prefixMixin' import resolveQueryPath from '@/utils/queryPathResolver' import { unwrapSafe } from '@/utils/uniquery' import { isRoyaltyValid, Royalty } from '@/utils/royalty' -import { fetchCollectionMetadata } from '~/components/rmrk/utils' +import { + fetchCollectionMetadata, + preheatFileFromIPFS, +} from '~/components/rmrk/utils' import { getMany, update } from 'idb-keyval' type MintedCollection = BaseMintedCollection & { @@ -337,18 +343,22 @@ export default class CreateToken extends mixins( file.type ) + preheatFileFromIPFS(fileHash) + // uploadDirect(file, this.accountId).catch(this.$consola.warn) const metaHash = await pinJson(meta, imageHash) return unSanitizeIpfsUrl(metaHash) } protected navigateToDetail(collection: string, id: string): void { - showNotification('You will go to the detail in 2 seconds') + showNotification( + `You will go to the detail in ${DETAIL_TIMEOUT / 1000} seconds` + ) const go = () => this.$router.push({ path: `/${this.urlPrefix}/gallery/${createTokenId(collection, id)}`, query: { message: 'congrats' }, }) - setTimeout(go, 2000) + setTimeout(go, DETAIL_TIMEOUT) } } diff --git a/components/bsx/Offer/OfferTable.vue b/components/bsx/Offer/OfferTable.vue index 099f011dfc..18c376b31a 100644 --- a/components/bsx/Offer/OfferTable.vue +++ b/components/bsx/Offer/OfferTable.vue @@ -17,7 +17,7 @@ :label="$t('offer.price')" v-slot="props" sortable> - + + + + + + + + diff --git a/components/moonsama/Gallery/Item/utils.ts b/components/moonsama/Gallery/Item/utils.ts new file mode 100644 index 0000000000..2e6fea59dc --- /dev/null +++ b/components/moonsama/Gallery/Item/utils.ts @@ -0,0 +1,27 @@ +import type { ApiPromise } from '@polkadot/api' + +export function getMetadata(api: ApiPromise) { + return api.query.nft.instances +} + +export function getMarketplaceData(api: ApiPromise) { + return api.query.nft.instances +} + +export function getPrice(api: ApiPromise) { + return api.query.marketplace.prices +} + +export function getOffers(api: ApiPromise) { + return api.query.marketplace.offers.keys +} + +export function getOwner(api: ApiPromise) { + return api.query.uniques.asset +} + +export function hasAllPallets(api: ApiPromise): boolean { + return [api.query.uniques, api.query.nft, api.query.marketplace].every( + (pallet) => pallet + ) +} diff --git a/components/rmrk/Create/CreateCollection.vue b/components/rmrk/Create/CreateCollection.vue index a95dd6b2c1..19ca295438 100644 --- a/components/rmrk/Create/CreateCollection.vue +++ b/components/rmrk/Create/CreateCollection.vue @@ -53,7 +53,7 @@ import { unSanitizeIpfsUrl } from '@kodadot1/minimark' import { generateId } from '@/components/rmrk/service/Consolidator' import { canSupport } from '@/utils/support' import MetaTransactionMixin from '@/utils/mixins/metaMixin' -import { pinFileToIPFS, pinJson, PinningKey } from '@/utils/pinning' +import { pinFileToIPFS, pinJson, PinningKey } from '@/utils/nftStorage' import { uploadDirect } from '@/utils/directUpload' import AuthMixin from '@/utils/mixins/authMixin' import { diff --git a/components/rmrk/Create/CreateToken.vue b/components/rmrk/Create/CreateToken.vue index e56bc56bc1..7163c81ce0 100644 --- a/components/rmrk/Create/CreateToken.vue +++ b/components/rmrk/Create/CreateToken.vue @@ -54,7 +54,7 @@ import ChainMixin from '@/utils/mixins/chainMixin' import MetaTransactionMixin from '@/utils/mixins/metaMixin' import RmrkVersionMixin from '@/utils/mixins/rmrkVersionMixin' import { notificationTypes, showNotification } from '@/utils/notification' -import { pinFileToIPFS, PinningKey, pinJson } from '@/utils/pinning' +import { pinFileToIPFS, PinningKey, pinJson } from '@/utils/nftStorage' import shouldUpdate from '@/utils/shouldUpdate' import { canSupport } from '@/utils/support' import { @@ -71,7 +71,10 @@ import { formatBalance } from '@polkadot/util' import Connector from '@kodadot1/sub-api' import { Component, mixins, Watch } from 'nuxt-property-decorator' import { BaseMintedCollection, BaseTokenType } from '~/components/base/types' -import { IPFS_KODADOT_IMAGE_PLACEHOLDER } from '~/utils/constants' +import { + DETAIL_TIMEOUT, + IPFS_KODADOT_IMAGE_PLACEHOLDER, +} from '~/utils/constants' import AuthMixin from '~/utils/mixins/authMixin' import PrefixMixin from '~/utils/mixins/prefixMixin' import { basicUpdateFunction } from '../service/NftUtils' @@ -82,6 +85,7 @@ import { secondaryFileVisible, } from './mintUtils' import { uploadDirect } from '~/utils/directUpload' +import { preheatFileFromIPFS } from '../utils' type MintedCollection = BaseMintedCollection & { name: string @@ -288,6 +292,7 @@ export default class CreateToken extends mixins( ) const metaHash = await pinJson(meta, imageHash) + preheatFileFromIPFS(fileHash) uploadDirect(file, metaHash).catch(this.$consola.warn) return unSanitizeIpfsUrl(metaHash) } @@ -340,13 +345,15 @@ export default class CreateToken extends mixins( } protected navigateToDetail(nft: CreatedNFT, blockNumber: string) { - showNotification('You will go to the detail in 2 seconds') + showNotification( + `You will go to the detail in ${DETAIL_TIMEOUT / 1000} seconds` + ) const go = () => this.$router.push({ path: `/rmrk/detail/${toNFTId(nft, blockNumber)}`, query: { message: 'congrats' }, }) - setTimeout(go, 2000) + setTimeout(go, DETAIL_TIMEOUT) } } diff --git a/components/rmrk/Create/CreativeMint.vue b/components/rmrk/Create/CreativeMint.vue index 6f402e99b3..c52a2b57ce 100644 --- a/components/rmrk/Create/CreativeMint.vue +++ b/components/rmrk/Create/CreativeMint.vue @@ -63,7 +63,7 @@ import { emptyObject } from '@/utils/empty' import ChainMixin from '@/utils/mixins/chainMixin' import RmrkVersionMixin from '@/utils/mixins/rmrkVersionMixin' import { notificationTypes, showNotification } from '@/utils/notification' -import { pinFileToIPFS, pinJson, PinningKey } from '@/utils/pinning' +import { pinFileToIPFS, pinJson, PinningKey } from '@/utils/nftStorage' import { basicUpdateNameFunction, createCollection, @@ -85,6 +85,7 @@ import { getNftId, NFT, NFTMetadata, SimpleNFT } from '../service/scheme' import { MediaType } from '../types' import { resolveMedia, sanitizeIpfsUrl } from '../utils' import { askGpt } from '@/utils/gpt' +import { DETAIL_TIMEOUT } from '~/utils/constants' const components = { AuthField: () => import('@/components/shared/form/AuthField.vue'), @@ -242,13 +243,15 @@ export default class CreativeMint extends mixins( } protected navigateToDetail(nft: NFT, blockNumber: string) { - showNotification('You will go to the detail in 2 seconds') + showNotification( + `You will go to the detail in ${DETAIL_TIMEOUT / 1000} seconds` + ) const go = () => this.$router.push({ path: `/rmrk/detail/${getNftId(nft, blockNumber)}`, query: { message: 'congrats' }, }) - setTimeout(go, 2000) + setTimeout(go, DETAIL_TIMEOUT) } @Watch('file') diff --git a/components/rmrk/Create/SimpleMint.vue b/components/rmrk/Create/SimpleMint.vue index d3586c4c3f..85a3f27c3d 100644 --- a/components/rmrk/Create/SimpleMint.vue +++ b/components/rmrk/Create/SimpleMint.vue @@ -193,9 +193,12 @@ import { shuffleFunction, toDistribute, } from '@/components/accounts/utils' -import { PinningKey, pinFileToIPFS, pinJson } from '@/utils/pinning' +import { PinningKey, pinFileToIPFS, pinJson } from '@/utils/nftStorage' import { uploadDirect } from '@/utils/directUpload' -import { IPFS_KODADOT_IMAGE_PLACEHOLDER } from '~/utils/constants' +import { + DETAIL_TIMEOUT, + IPFS_KODADOT_IMAGE_PLACEHOLDER, +} from '~/utils/constants' import { createMetadata, findUniqueSymbol } from '@kodadot1/minimark' import Vue from 'vue' import PrefixMixin from '~/utils/mixins/prefixMixin' @@ -783,13 +786,15 @@ export default class SimpleMint extends mixins( } protected navigateToDetail(nft: NFT, blockNumber: string) { - showNotification('You will go to the detail in 2 seconds') + showNotification( + `You will go to the detail in ${DETAIL_TIMEOUT / 1000} seconds` + ) const go = () => this.$router.push({ path: `/rmrk/detail/${getNftId(nft, blockNumber)}`, query: { message: 'congrats' }, }) - setTimeout(go, 2000) + setTimeout(go, DETAIL_TIMEOUT) } protected getUsdFromKsm() { diff --git a/components/rmrk/Gallery/Gallery.vue b/components/rmrk/Gallery/Gallery.vue index 0960237107..10ba7ad65b 100644 --- a/components/rmrk/Gallery/Gallery.vue +++ b/components/rmrk/Gallery/Gallery.vue @@ -308,6 +308,7 @@ export default class Gallery extends mixins( Vue.set(this.nfts, i, { ...this.nfts[i], ...meta, + id: this.nfts[i].id, image: imageLinks[ fastExtract( diff --git a/components/rmrk/utils.ts b/components/rmrk/utils.ts index f7822f4e6b..ed5369eb87 100644 --- a/components/rmrk/utils.ts +++ b/components/rmrk/utils.ts @@ -9,6 +9,8 @@ import { NFTMetadata, Collection, NFT, NFTWithMeta } from './service/scheme' import { before } from '@/utils/math' import { justHash, Interaction } from '@kodadot1/minimark' import { logError } from '@/utils/mappers' +import consola from 'consola' +import { fastExtract } from '~/utils/ipfs' export const SQUARE = '::' export const DEFAULT_IPFS_PROVIDER = 'https://ipfs.io/' @@ -101,6 +103,15 @@ export const fetchMetadata = async ( return emptyObject() } +export const preheatFileFromIPFS = async (ipfsUrl: string) => { + const url = sanitizeIpfsUrl(ipfsUrl, 'pinata') + const hash = fastExtract(url) + api + .get(url) + .then(() => consola.log(`[PREHEAT] ${hash}`)) + .catch((err) => consola.warn(`[PREHEAT] ${hash} ${err.message}`)) +} + export const unSanitizeArweaveId = (url: string): string => { return unSanitizeUrl(url, 'ar://') } diff --git a/components/shared/ChainSelect.vue b/components/shared/ChainSelect.vue index 8074d3f379..436bede010 100644 --- a/components/shared/ChainSelect.vue +++ b/components/shared/ChainSelect.vue @@ -11,6 +11,7 @@ v-for="option in options" :key="option.value" :value="option.value" + :disabled="option.value === 'moonriver'" :class="{ 'is-active': selected === option.value }"> {{ option.text }} diff --git a/components/shared/form/BasicDatePicker.vue b/components/shared/form/BasicDatePicker.vue index 5ffd351dc1..87dd449ce2 100644 --- a/components/shared/form/BasicDatePicker.vue +++ b/components/shared/form/BasicDatePicker.vue @@ -17,7 +17,7 @@ import { Component, Prop, VModel, Vue } from 'nuxt-property-decorator' @Component({}) -export default class extends Vue { +export default class BasicDatePicker extends Vue { @VModel({ type: Date }) vValue!: Date @Prop({ type: String, required: true }) label!: string @Prop({ type: String, required: true }) placeholder!: string diff --git a/components/shared/format/Identity.vue b/components/shared/format/Identity.vue index 2ab0366228..3dbc674210 100644 --- a/components/shared/format/Identity.vue +++ b/components/shared/format/Identity.vue @@ -43,14 +43,14 @@ > - diff --git a/components/shared/format/Money.vue b/components/shared/format/Money.vue index 9d32e238e8..e8db7c11c0 100644 --- a/components/shared/format/Money.vue +++ b/components/shared/format/Money.vue @@ -1,7 +1,13 @@ diff --git a/langDir/en.json b/langDir/en.json index bf5dc7245f..dd0bc666b4 100644 --- a/langDir/en.json +++ b/langDir/en.json @@ -502,7 +502,7 @@ "submit": "Submit {0}" }, "properties": { - "label": "Properties" + "label": "Traits" }, "offer": { "label": "Offers ({0})", diff --git a/nuxt.config.js b/nuxt.config.js index 551fa3c42a..133c93eb8a 100644 --- a/nuxt.config.js +++ b/nuxt.config.js @@ -263,6 +263,7 @@ export default defineNuxtConfig({ process.env.SUBSQUID_ENDPOINT || URLS.koda.subsquidv6 ), bsx: toApolloEndpoint(URLS.koda.snekk), + moonsama: toApolloEndpoint(URLS.koda.click), }, // https://github.com/nuxt-community/apollo-module#options }, diff --git a/package.json b/package.json index a6a595d8c0..da39960ac3 100644 --- a/package.json +++ b/package.json @@ -62,8 +62,8 @@ "@google/model-viewer": "^1.12.0", "@keeex/qrcodejs-kx": "^1.0.2", "@kodadot1/minimark": "^0.0.1-rc.7", - "@kodadot1/sub-api": "0.0.1-rc.3", - "@kodadot1/vuex-options": "0.0.1-rc.8", + "@kodadot1/sub-api": "^0.0.1-rc.3", + "@kodadot1/vuex-options": "0.0.1-rc.10", "@nuxtjs/apollo": "^4.0.1-rc.5", "@nuxtjs/i18n": "^7.2.2", "@polkadot/extension-dapp": "^0.42.6", diff --git a/pages/moonsama/collection/_id.vue b/pages/moonsama/collection/_id.vue new file mode 100644 index 0000000000..15d6634d66 --- /dev/null +++ b/pages/moonsama/collection/_id.vue @@ -0,0 +1,50 @@ + + + diff --git a/pages/moonsama/create.vue b/pages/moonsama/create.vue new file mode 100644 index 0000000000..e4bb43508f --- /dev/null +++ b/pages/moonsama/create.vue @@ -0,0 +1,45 @@ + + + diff --git a/pages/moonsama/explore.vue b/pages/moonsama/explore.vue new file mode 100644 index 0000000000..4fab22b612 --- /dev/null +++ b/pages/moonsama/explore.vue @@ -0,0 +1,31 @@ + + + diff --git a/pages/moonsama/gallery/_id.vue b/pages/moonsama/gallery/_id.vue new file mode 100644 index 0000000000..28093b5ff0 --- /dev/null +++ b/pages/moonsama/gallery/_id.vue @@ -0,0 +1,53 @@ + + + diff --git a/pages/moonsama/index.vue b/pages/moonsama/index.vue new file mode 100644 index 0000000000..1515a0ed9f --- /dev/null +++ b/pages/moonsama/index.vue @@ -0,0 +1,23 @@ + diff --git a/pages/moonsama/u/_id.vue b/pages/moonsama/u/_id.vue new file mode 100644 index 0000000000..b371e5ea1a --- /dev/null +++ b/pages/moonsama/u/_id.vue @@ -0,0 +1,18 @@ + + + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index de69a23766..48f0a71db8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,8 +16,8 @@ specifiers: '@google/model-viewer': ^1.12.0 '@keeex/qrcodejs-kx': ^1.0.2 '@kodadot1/minimark': ^0.0.1-rc.7 - '@kodadot1/sub-api': 0.0.1-rc.3 - '@kodadot1/vuex-options': 0.0.1-rc.8 + '@kodadot1/sub-api': ^0.0.1-rc.3 + '@kodadot1/vuex-options': 0.0.1-rc.10 '@nuxt/bridge': npm:@nuxt/bridge-edge@3.0.0-27470397.9ebea90 '@nuxt/test-utils': ^0.2.2 '@nuxt/types': ^2.15.8 @@ -97,7 +97,7 @@ dependencies: '@keeex/qrcodejs-kx': 1.0.2 '@kodadot1/minimark': 0.0.1-rc.7 '@kodadot1/sub-api': 0.0.1-rc.3 - '@kodadot1/vuex-options': 0.0.1-rc.8 + '@kodadot1/vuex-options': 0.0.1-rc.10 '@nuxtjs/apollo': 4.0.1-rc.5_bxdthn3ysjabr5yy33n467wu6m '@nuxtjs/i18n': 7.2.2 '@polkadot/extension-dapp': 0.42.10 @@ -2344,8 +2344,8 @@ packages: - supports-color dev: false - /@kodadot1/vuex-options/0.0.1-rc.8: - resolution: {integrity: sha512-i1jTECVU5/t84qBE88XAXJGUH5/aZDN0xunqBsiVxb7pX/jmMRy87mB2LTxJMbjZ07vS7DhNh3XD+YE349Zgiw==} + /@kodadot1/vuex-options/0.0.1-rc.10: + resolution: {integrity: sha512-FxXyLrYJAKu9DtQYLSK5pveH2nlH+n+ANU9ablNM+GCvL/y42Y/nImNGg1bQZ2+e1NUz9nRfp7bwcwOG5/OrlQ==} dependencies: '@polkadot/networks': 7.9.2 dev: false @@ -10369,7 +10369,6 @@ packages: /graphql/16.5.0: resolution: {integrity: sha512-qbHgh8Ix+j/qY+a/ZcJnFQ+j8ezakqPiHwPiZhV/3PgGlgf96QMBB5/f2rkiC9sgLoy/xvT6TSiaf2nTHJh5iA==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} - dev: false /gzip-size/6.0.0: resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==} @@ -16612,7 +16611,6 @@ packages: resolution: {integrity: sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==} engines: {node: '>=4.2.0'} hasBin: true - dev: true /ua-parser-js/0.7.31: resolution: {integrity: sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==} @@ -17654,7 +17652,6 @@ packages: /vue/2.6.14: resolution: {integrity: sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ==} - dev: false /vuex-class/0.3.2_ot447vtrjddcfneoczzpyjkfhe: resolution: {integrity: sha512-m0w7/FMsNcwJgunJeM+wcNaHzK2KX1K1rw2WUQf7Q16ndXHo7pflRyOV/E8795JO/7fstyjH3EgqBI4h4n4qXQ==} diff --git a/store/pinning.ts b/store/pinning.ts index adbf267a58..4e6837d2ed 100644 --- a/store/pinning.ts +++ b/store/pinning.ts @@ -1,19 +1,20 @@ import { GetterTree, ActionTree, MutationTree, Commit } from 'vuex' -import { PinningKey, getKey as getPinningKey } from '@/utils/pinning' +import { PinningKey, getKey as getPinningKey } from '@/utils/nftStorage' import { emptyObject, isEmpty } from '@/utils/empty' type PinningState = { - pinningKey: PinningKey, + pinningKey: PinningKey } export const state = (): PinningState => ({ pinningKey: emptyObject(), }) - export const getters: GetterTree = { getPinningKey: (state) => state.pinningKey?.token, - isKeyValid: (state) => !!state.pinningKey?.expiry && new Date(state.pinningKey.expiry).getTime() < Date.now(), + isKeyValid: (state) => + !!state.pinningKey?.expiry && + new Date(state.pinningKey.expiry).getTime() < Date.now(), } export const mutations: MutationTree = { @@ -23,8 +24,15 @@ export const mutations: MutationTree = { } export const actions: ActionTree = { - async fetchPinningKey({ commit, state }: { commit: Commit, state: PinningState }, address: string): Promise { - if (isEmpty(state.pinningKey) || isExpired(state.pinningKey)) { + async fetchPinningKey( + { commit, state }: { commit: Commit; state: PinningState }, + address: string + ): Promise { + if ( + isEmpty(state.pinningKey) || + isExpired(state.pinningKey) || + isFromEstuary(state.pinningKey) + ) { const pinningKey = await getPinningKey(address) commit('SET_PINNING_KEY', pinningKey) return pinningKey @@ -42,3 +50,7 @@ const isExpired = (pinningKey: PinningKey) => { return false } + +const isFromEstuary = (pinningKey: PinningKey) => { + return pinningKey.token.startsWith('EST') +} diff --git a/utils/account.ts b/utils/account.ts index 30d313cb3c..d49ec31b89 100644 --- a/utils/account.ts +++ b/utils/account.ts @@ -1,7 +1,12 @@ import { KeyringAccount } from '@/utils/types/types' import keyring from '@polkadot/ui-keyring' import { getAddress } from '@/utils/extension' -import { decodeAddress, encodeAddress, addressEq } from '@polkadot/util-crypto' +import { + decodeAddress, + encodeAddress, + addressEq, + addressToEvm, +} from '@polkadot/util-crypto' import * as store from '~/store' import { Prefix } from '@polkadot/util-crypto/address/types' @@ -68,4 +73,9 @@ export const isSameAccount = ( return addressEq(address1, address2) } +export const accountToEvm = (account: KeyringAccount | string): string => { + const address = accountToAddress(account) + return addressToEvm(address)?.toString() +} + export default passwordRequired diff --git a/utils/config/indexer.config.ts b/utils/config/indexer.config.ts index ca3785d2ac..20bee40eab 100644 --- a/utils/config/indexer.config.ts +++ b/utils/config/indexer.config.ts @@ -1,28 +1,28 @@ type AvailableClient = 'subquery' | 'subsquid' -type Prefix = 'rmrk' | 'bsx' | 'statemine' | 'westmint' +export type Prefix = 'rmrk' | 'bsx' | 'statemine' | 'westmint' | 'moonsama' type DefaultIndexer = Record type ImplementationAvailable = Record // [subquery, subsquid] -const defaultIndexer: DefaultIndexer = { - rmrk: 'subquery', - bsx: 'subsquid', - statemine: 'subquery', - westmint: 'subquery', -} +// const defaultIndexer: DefaultIndexer = { +// rmrk: 'subquery', +// bsx: 'subsquid', +// statemine: 'subquery', +// westmint: 'subquery', +// } -const implementationAvailable: ImplementationAvailable = { - rmrk: [true, true], - bsx: [false, true], - statemine: [true, false], - westmint: [true, false], -} +// const implementationAvailable: ImplementationAvailable = { +// rmrk: [true, true], +// bsx: [false, true], +// statemine: [true, false], +// westmint: [true, false], +// } -function getDefaultIndexer(prefix: Prefix) { - return defaultIndexer[prefix] -} +// function getDefaultIndexer(prefix: Prefix) { +// return defaultIndexer[prefix] +// } -function indexOf(client: AvailableClient): 0 | 1 { - return client === 'subsquid' ? 1 : 0 -} +// function indexOf(client: AvailableClient): 0 | 1 { +// return client === 'subsquid' ? 1 : 0 +// } diff --git a/utils/config/permision.config.ts b/utils/config/permision.config.ts new file mode 100644 index 0000000000..18fe2b3440 --- /dev/null +++ b/utils/config/permision.config.ts @@ -0,0 +1,15 @@ +import { Prefix } from './indexer.config' + +type Config = Record + +const hasCreate: Config = { + rmrk: true, + bsx: true, + statemine: true, + westmint: true, + moonsama: false, +} + +export const createVisible = (prefix: Prefix | string): boolean => { + return hasCreate[prefix] +} diff --git a/utils/constants.ts b/utils/constants.ts index 521330a78e..f8176e605d 100644 --- a/utils/constants.ts +++ b/utils/constants.ts @@ -19,18 +19,22 @@ export const PER_PAGE = 20 export const SHOW_SCROLL_TOP_BUTTON_HEIGHT = 350 +export const DETAIL_TIMEOUT = 3000 + export const URLS = { koda: { cloudflare: 'https://durable-jpeg.kodadot.workers.dev/', pinata: 'https://kodadot.mypinata.cloud/ipfs/', directUpload: 'https://direct-upload.kodadot.workers.dev/', estuary: 'https://pinning.kodadot.workers.dev/', + nftStorage: 'https://nft-storage.kodadot.workers.dev/', netlify: 'https://beta.kodadot.xyz/.netlify/functions/', seoCard: 'https://og-image-green-seven.vercel.app/', magick: 'https://api.subquery.network/sq/vikiival/magick', subsquidv5: 'https://app.gc.subsquid.io/beta/rubick/005/graphql', subsquidv6: 'https://app.gc.subsquid.io/beta/rubick/006/graphql', snekk: 'https://app.gc.subsquid.io/beta/snekk/003/graphql', + click: 'https://app.gc.subsquid.io/beta/click/001-rc0/graphql', }, providers: { coingecko: 'https://api.coingecko.com/api/v3', diff --git a/utils/nftStorage.ts b/utils/nftStorage.ts new file mode 100644 index 0000000000..eb9f931a47 --- /dev/null +++ b/utils/nftStorage.ts @@ -0,0 +1,83 @@ +import Axios from 'axios' +import { URLS } from './constants' +import consola from 'consola' + +export const BASE_URL = URLS.koda.nftStorage + +const api = Axios.create({ + baseURL: BASE_URL, +}) + +export type PinningKey = { + expiry: string + token: string +} + +type StorageApiResponse = { + ok: boolean + value: { + cid: string + size: number + type: string + created: Date + } +} + +export const pinJson = async (object: Record, name: string) => { + try { + const { status, data } = await api.post( + `pinJson/${name}`, + object + ) + consola.log('[NFT::STORAGE] Pin JSON', status) + if (status < 400) { + return data.value.cid + } else { + throw new Error( + `[NFT::STORAGE] Unable to PIN JSON for reasons ${status} ${data}` + ) + } + } catch (e) { + consola.warn(e) + throw e + } +} + +export const getKey = async (address: string): Promise => { + try { + const { status, data } = await api.get(`getKey/${address}`) + consola.log('[NFT::STORAGE] Obtain', status) + return data + } catch (e) { + consola.warn(e) + throw e + } +} + +export const pinFileToIPFS = async (file: Blob, _: string): Promise => { + try { + const { status, data } = await api.post( + '/pinFile', + file, + { + headers: { + 'Content-Type': file.type ? `${file.type}` : '*/*', + }, + } + ) + consola.log('[NFT::STORAGE] Pin File', status) + if (status < 400) { + return data.value.cid + } else { + throw new Error( + `[NFT::STORAGE] Unable to PIN File for reasons ${status} ${data}` + ) + } + } catch (e) { + consola.warn(e) + throw e + } +} + +export default api +// QmYt2FydonvVMsEqe2q3hvm38WDq21xM8Z5ZSHZw19PwjF; diff --git a/utils/prefix.ts b/utils/prefix.ts index cf1cdcadd8..457c0a655e 100644 --- a/utils/prefix.ts +++ b/utils/prefix.ts @@ -34,9 +34,10 @@ export function prefixBuildOnText(prefix: string): string { case 'bsx': return 'Basilisk NFT Pallet' case 'statemine': - return 'Statemine Unique Pallet' case 'westmint': return 'Statemine Unique Pallet' + case 'moonsama': + return 'EVM Smart Contracts' default: return 'RMRK Protocol' } diff --git a/utils/queryPathResolver.ts b/utils/queryPathResolver.ts index d3cc4df6fd..e459e6e13b 100644 --- a/utils/queryPathResolver.ts +++ b/utils/queryPathResolver.ts @@ -27,6 +27,7 @@ function getPath(prefix: string) { case 'rmrk': return '' case 'bsx': + case 'moonsama': return 'subsquid/general/' case 'statemine': case 'westmint': diff --git a/utils/safePin.ts b/utils/safePin.ts index 8795148237..e4a77e66d8 100644 --- a/utils/safePin.ts +++ b/utils/safePin.ts @@ -1,5 +1,5 @@ import { IPFS_KODADOT_IMAGE_PLACEHOLDER } from './constants' -import { pinFileToIPFS } from './pinning' +import { pinFileToIPFS } from './nftStorage' type MaybeFile = File | null | undefined