@@ -41,7 +41,7 @@ const GRID_DEFAULT_WIDTH = {
large: 0,
}
-defineProps<{
+const props = defineProps<{
drops: Drop[] | InternalDropCalendar[]
loaded: boolean
defaultSkeletonCount: number
@@ -50,6 +50,8 @@ defineProps<{
clickable?: boolean
}>()
+const isAsync = computed(() => typeof props.asyncSkeletonCount === 'number')
+
const isDrop = (item: Drop | InternalDropCalendar): item is Drop =>
(item as Drop).collection !== undefined
diff --git a/components/drops/useDrops.ts b/components/drops/useDrops.ts
index 62da82a393..6cfe87e4ab 100644
--- a/components/drops/useDrops.ts
+++ b/components/drops/useDrops.ts
@@ -49,7 +49,7 @@ const DROP_LIST_ORDER = [
const ONE_DAYH_IN_MS = 24 * 60 * 60 * 1000
-export function useDrops(query?: GetDropsQuery, { async = false }: { async?: boolean } = { }) {
+export function useDrops(query?: GetDropsQuery, { async = false, filterOutMinted = false }: { async?: boolean, filterOutMinted?: boolean } = { }) {
const drops = ref
([])
const dropsList = ref([])
const count = computed(() => dropsList.value.length)
@@ -79,7 +79,7 @@ export function useDrops(query?: GetDropsQuery, { async = false }: { async?: boo
else {
drops.value = await Promise.all(
dropsList.value.map(async drop => getFormattedDropItem(drop, drop)),
- )
+ ).then(dropsList => filterOutMinted ? dropsList.filter(drop => !drop.isMintedOut) : dropsList)
loaded.value = true
}
diff --git a/composables/drop/massmint/useDropMassMint.ts b/composables/drop/massmint/useDropMassMint.ts
index 1524c0c1e0..5e37e0bbb5 100644
--- a/composables/drop/massmint/useDropMassMint.ts
+++ b/composables/drop/massmint/useDropMassMint.ts
@@ -1,10 +1,10 @@
import { useCollectionEntity } from '../useGenerativeDropMint'
import type { ToMintNft } from '@/components/collection/drop/types'
-import type { DoResult } from '@/services/fxart'
-import { updateMetadata } from '@/services/fxart'
+import { generateId, setDyndataUrl } from '@/services/dyndata'
export type MassMintNFT = Omit & {
- metadata?: string
+ image: string
+ metadata: string
nft: number // nft id
sn?: number // serial numbers
}
@@ -12,25 +12,54 @@ export type MassMintNFT = Omit & {
export default () => {
const dropStore = useDropStore()
const { collectionName } = useCollectionEntity()
-
const { drop, amountToMint, toMintNFTs, loading } = storeToRefs(dropStore)
+ const { isSub } = useIsChain(usePrefix().urlPrefix)
+
+ // ensure tokenIds are unique on single user session
+ const tokenIds = ref([])
+ const populateTokenIds = async () => {
+ for (const _ of Array.from({ length: amountToMint.value })) {
+ const tokenId = Number.parseInt(await generateId())
+ if (!tokenIds.value.includes(tokenId)) {
+ tokenIds.value.push(tokenId)
+ }
+ }
+
+ if (tokenIds.value.length < amountToMint.value) {
+ await populateTokenIds()
+ }
+ }
- const clearMassmint = () => {
+ const clearMassMint = () => {
dropStore.resetMassmint()
+ tokenIds.value = []
}
const massGenerate = async () => {
try {
- clearMassmint()
+ clearMassMint()
+ if (isSub.value) {
+ await populateTokenIds()
+ }
+
+ toMintNFTs.value = Array.from({ length: amountToMint.value }).map(
+ (_, index) => {
+ const { image, metadata } = setDyndataUrl({
+ chain: drop.value.chain,
+ collection: drop.value.collection,
+ nft: tokenIds.value[index],
+ })
- toMintNFTs.value = Array.from({ length: amountToMint.value }).map(() => {
- return {
- name: drop.value.name,
- collectionName: collectionName.value,
- price: drop.value.price?.toString() || '',
- nft: parseInt(uidMathDate()),
- }
- })
+ return {
+ name: drop.value.name,
+ collectionName: collectionName.value,
+ price: drop.value.price?.toString() || '',
+ nft: tokenIds.value[index],
+ metadata,
+ image,
+ }
+ },
+ )
console.log('[MASSMINT::GENERATE] Generated', toRaw(toMintNFTs.value))
}
@@ -40,27 +69,10 @@ export default () => {
}
}
- const submitMint = async (nft: MassMintNFT): Promise => {
- return new Promise((resolve, reject) => {
- try {
- updateMetadata({
- chain: drop.value.chain,
- collection: drop.value.collection,
- nft: nft.nft,
- sn: nft.sn,
- }).then(result => resolve(result))
- }
- catch (e) {
- reject(e)
- }
- })
- }
-
- onBeforeUnmount(clearMassmint)
+ onBeforeUnmount(clearMassMint)
return {
massGenerate,
- submitMint,
- clearMassMint: clearMassmint,
+ clearMassMint,
}
}
diff --git a/composables/drop/massmint/useDropMassMintListing.ts b/composables/drop/massmint/useDropMassMintListing.ts
index b1c39614dd..a5f4359914 100644
--- a/composables/drop/massmint/useDropMassMintListing.ts
+++ b/composables/drop/massmint/useDropMassMintListing.ts
@@ -5,7 +5,7 @@ export default () => {
const { client } = usePrefix()
const { listNftByNftWithMetadata } = useListingCartModal()
- const { mintedNFTs, mintingSession } = storeToRefs(useDropStore())
+ const { mintedNFTs, toMintNFTs } = storeToRefs(useDropStore())
const subscribeForNftsWithMetadata = (nftIds: string[]) => {
subscribeToNfts(nftIds, async (data) => {
@@ -29,10 +29,11 @@ export default () => {
}
const listMintedNFTs = () => {
- mintedNFTs.value.forEach((withMetadataNFT: NFTWithMetadata) => {
- const mintingSessionNFT = mintingSession.value.items.find(
- nft => nft.id === withMetadataNFT.id,
+ mintedNFTs.value.forEach(async (withMetadataNFT: NFTWithMetadata) => {
+ const mintingSessionNFT = toMintNFTs.value.find(
+ nft => nft.nft.toString() === withMetadataNFT.sn,
)
+
listNftByNftWithMetadata(
{
...withMetadataNFT,
diff --git a/composables/drop/useGenerativeDropMint.ts b/composables/drop/useGenerativeDropMint.ts
index 8ed1aedf62..d3fdfce491 100644
--- a/composables/drop/useGenerativeDropMint.ts
+++ b/composables/drop/useGenerativeDropMint.ts
@@ -1,15 +1,10 @@
import { useQuery } from '@tanstack/vue-query'
-import { type MintedNFT } from '@/components/collection/drop/types'
-import type { DoResult } from '@/services/fxart'
-import { setMetadataUrl } from '@/services/fxart'
+import { type DoResult, updateMetadata } from '@/services/fxart'
import { useDrop } from '@/components/drops/useDrops'
import unlockableCollectionById from '@/queries/subsquid/general/unlockableCollectionById.graphql'
import { FALLBACK_DROP_COLLECTION_MAX } from '@/utils/drop'
-import type {
- MassMintNFT,
-} from '@/composables/drop/massmint/useDropMassMint'
-import useDropMassMint from '@/composables/drop/massmint/useDropMassMint'
import useDropMassMintListing from '@/composables/drop/massmint/useDropMassMintListing'
+import type { MintedNFT } from '@/components/collection/drop/types'
export type DropMintedNft = DoResult & {
id: string
@@ -81,9 +76,7 @@ export const useUpdateMetadata = async ({
blockNumber: Ref
}) => {
const { drop } = useDrop()
- const { toMintNFTs, amountToMint, mintingSession }
- = storeToRefs(useDropStore())
- const { submitMint } = useDropMassMint()
+ const { toMintNFTs, mintingSession } = storeToRefs(useDropStore())
const { subscribeForNftsWithMetadata } = useDropMassMintListing()
const { collectionName, maxCount } = useCollectionEntity()
const { $consola } = useNuxtApp()
@@ -94,89 +87,32 @@ export const useUpdateMetadata = async ({
?? FALLBACK_DROP_COLLECTION_MAX)
const updateSubstrateMetdata = () => {
- const status = ref<'index' | 'update'>('index')
-
- // 1. get nft index
- const mintNFTs: Ref = ref([])
- useSubscriptionGraphql({
- query: `
- nfts: nftEntities(
- where: {collection: {id_eq: "${drop.value.collection}"}},
- orderBy: [createdAt_ASC, sn_ASC]
- ) {
- id
+ mintingSession.value.items = toMintNFTs.value.map((item) => {
+ // trigger update metadata
+ updateMetadata({
+ chain: drop.value.chain,
+ collection: drop.value.collection,
+ nft: item.nft,
+ })
+
+ return {
+ id: item.nft.toString(),
+ chain: drop.value.chain,
+ name: item.name,
+ image: item.image,
+ metadata: item.metadata,
+ collection: {
+ id: drop.value.collection,
+ name: item.collectionName,
+ max: drop.value.max,
+ },
}
- `,
- onChange: async ({ data: { nfts } }) => {
- mintNFTs.value = []
-
- if (status.value === 'update') {
- return
- }
-
- const checkIndex = new Set() // check duplicate index
- for (const mintNFT of toMintNFTs.value) {
- const index
- = nfts.findIndex(
- nft => nft.id === `${drop.value.collection}-${mintNFT.nft}`,
- ) + 1
-
- if (index > 0) {
- checkIndex.add(index)
- const metadata = setMetadataUrl({
- chain: drop.value.chain,
- collection: drop.value.collection,
- sn: index.toString(),
- })
-
- mintNFTs.value.push({
- ...mintNFT,
- name: `${mintNFT.name} #${index}`,
- metadata: metadata.toString(),
- sn: index,
- })
- }
- }
-
- if (checkIndex.size === amountToMint.value) {
- status.value = 'update'
- await submitMetadata()
- }
- },
})
-
- // 2. update metadata
- const mintedNfts: Ref = ref([])
- const submitMetadata = async () => {
- const response = await Promise.all(mintNFTs.value.map(submitMint))
-
- for (const [index, res] of response.entries()) {
- let metadata = { name: '', image: '' }
-
- try {
- metadata = await $fetch(res.metadata || '')
- }
- catch (error) {
- $consola.warn(error)
- }
-
- mintedNfts.value.push({
- id: `${drop.value.collection}-${res.nft}`,
- index: mintNFTs.value[index].sn as number,
- chain: res.chain,
- name: metadata.name,
- image: metadata.image,
- collection: {
- id: res.collection,
- name: collectionName.value,
- max: collectionMax.value,
- },
- })
- }
-
- mintingSession.value.items = mintedNfts.value
- subscribeForNftsWithMetadata(mintedNfts.value.map(item => item.id))
- }
+ subscribeForNftsWithMetadata(
+ toMintNFTs.value.map(
+ item => `${drop.value.collection}-${item.nft.toString()}`,
+ ),
+ )
}
const updateEvmMetdata = () => {
diff --git a/composables/transaction/transactionBurn.ts b/composables/transaction/transactionBurn.ts
index 8a020288f6..d0af3ac16a 100644
--- a/composables/transaction/transactionBurn.ts
+++ b/composables/transaction/transactionBurn.ts
@@ -5,6 +5,7 @@ import {
} from '@kodadot1/minimark/v2'
import type { ApiPromise } from '@polkadot/api'
import type { PalletNftsDestroyWitness } from '@polkadot/types/lookup'
+import type { Prefix } from '@kodadot1/static'
import { GENSOL_ABI } from './evm/utils'
import type {
ActionDeleteCollection,
@@ -31,7 +32,7 @@ function execBurnEvm(item: ActionConsume, executeTransaction: ExecuteTransaction
}
export function execBurnTx(item: ActionConsume, api, executeTransaction) {
- if (item.urlPrefix === 'base' || item.urlPrefix === 'imx') {
+ if (isEvm(item.urlPrefix as Prefix)) {
return execBurnEvm(item, executeTransaction)
}
diff --git a/composables/transaction/transactionMintDrop.ts b/composables/transaction/transactionMintDrop.ts
index 3ec5d75b31..1c7d97f4f7 100644
--- a/composables/transaction/transactionMintDrop.ts
+++ b/composables/transaction/transactionMintDrop.ts
@@ -61,7 +61,7 @@ export function execMintDrop({ item, ...params }: MintDropParams) {
} as SubstrateMintDropParams)
}
- if (item.prefix === 'base') {
+ if (isEvm(item.prefix)) {
return execEvmMintDrop({
item,
...params,
diff --git a/composables/transaction/transactionSend.ts b/composables/transaction/transactionSend.ts
index d2855a0f10..1709313917 100644
--- a/composables/transaction/transactionSend.ts
+++ b/composables/transaction/transactionSend.ts
@@ -4,6 +4,7 @@ import {
createInteraction as createNewInteraction,
} from '@kodadot1/minimark/v2'
import { checkAddress, isAddress } from '@polkadot/util-crypto'
+import type { Prefix } from '@kodadot1/static'
import type { ActionSend, ExecuteTransaction } from './types'
import { GENSOL_ABI } from './evm/utils'
import {
@@ -82,7 +83,7 @@ export function execSendTx(
api,
executeTransaction: ExecuteTransaction,
) {
- if (item.urlPrefix === 'base') {
+ if (isEvm(item.urlPrefix as Prefix)) {
return execSendEvm(item, executeTransaction)
}
diff --git a/composables/useChain.ts b/composables/useChain.ts
index 1e5b0b74c1..8c27b771bb 100644
--- a/composables/useChain.ts
+++ b/composables/useChain.ts
@@ -55,8 +55,6 @@ export default function () {
)
}
- const vmOf = (prefix: Prefix): ChainVM => chainPropListOf(prefix).vm
-
const existentialDeposit = computed(
() => chainsExistentialDeposit[urlPrefix.value],
)
@@ -86,7 +84,6 @@ export default function () {
withoutDecimals,
unit,
vm,
- vmOf,
offersDisabled,
chainProperties,
availableChains,
diff --git a/composables/useIsChain.ts b/composables/useIsChain.ts
index 216323fe66..46ede1c0a9 100644
--- a/composables/useIsChain.ts
+++ b/composables/useIsChain.ts
@@ -1,6 +1,9 @@
import type { Prefix } from '@kodadot1/static'
import type { ComputedRef } from 'vue'
-import { chainPropListOf } from '@/utils/config/chain.config'
+import { vmOf } from '@/utils/config/chain.config'
+
+export const isEvm = (prefix: Prefix) => vmOf(prefix) === 'EVM'
+export const isSub = (prefix: Prefix) => vmOf(prefix) === 'SUB'
export default function (prefix: ComputedRef) {
const isRemark = computed(
@@ -15,15 +18,12 @@ export default function (prefix: ComputedRef) {
const isBase = computed(() => 'base' === prefix.value)
- const isEvm = computed(() => chainPropListOf(prefix.value).vm === 'EVM')
- const isSub = computed(() => chainPropListOf(prefix.value).vm === 'SUB')
-
return {
isRemark,
isAssetHub,
- isEvm,
- isSub,
isRmrk,
isBase,
+ isEvm: computed(() => isEvm(prefix.value)),
+ isSub: computed(() => isSub(prefix.value)),
}
}
diff --git a/composables/useMultipleBalance.ts b/composables/useMultipleBalance.ts
index 7dbeac112d..60f09110d8 100644
--- a/composables/useMultipleBalance.ts
+++ b/composables/useMultipleBalance.ts
@@ -23,6 +23,7 @@ export const networkToPrefix: Partial> = {
polkadotHub: 'ahp',
base: 'base',
immutablex: 'imx',
+ mantle: 'mnt',
// rococoHub: 'ahr',
}
@@ -34,6 +35,7 @@ export const prefixToNetwork: Partial> = {
ahp: 'polkadotHub',
base: 'base',
imx: 'immutablex',
+ mnt: 'mantle',
// ahr: 'rococoHub',
}
@@ -87,6 +89,8 @@ export default function (refetchPeriodically: boolean = false) {
multiBalances.value.chains.base?.eth?.nativeBalance,
[Chain.IMMUTABLEX]:
multiBalances.value.chains.immutablex?.eth?.nativeBalance,
+ [Chain.MANTLE]:
+ multiBalances.value.chains.mantle?.mnt?.nativeBalance,
}))
const currentChain = computed(() => prefixToChainMap[urlPrefix.value])
diff --git a/composables/useNft.ts b/composables/useNft.ts
index fe870383c0..6ec3a0d0d5 100644
--- a/composables/useNft.ts
+++ b/composables/useNft.ts
@@ -198,8 +198,9 @@ export async function getNftMetadata(
prefix: string,
unify = false,
) {
- const checkMetadata = (nft.metadata || nft.meta?.id)?.includes(
- DYNAMIC_METADATA,
+ const ignoreMetadata = [DYNAMIC_METADATA, 'dyndata']
+ const checkMetadata = ignoreMetadata.some(item =>
+ (nft.metadata || nft.meta?.id)?.includes(item),
)
if (unify && !checkMetadata) {
return await getMetadata(sanitizeIpfsUrl(nft.metadata || nft.meta.id))
diff --git a/composables/useViem.ts b/composables/useViem.ts
index b334ef3f07..24c9d7d46f 100644
--- a/composables/useViem.ts
+++ b/composables/useViem.ts
@@ -1,21 +1,43 @@
import { createPublicClient, createWalletClient, custom, http } from 'viem'
import type { Prefix } from '@kodadot1/static'
+const provider = reactive<{ value: any, fetching: boolean }>({ value: undefined, fetching: false })
+
export default function (prefix: Prefix) {
+ const walletStore = useWalletStore()
+ const { connector } = useWagmi()
+
const publicClient = createPublicClient({
chain: PREFIX_TO_CHAIN[prefix],
transport: http(),
})
const getWalletClient = () => {
- if (window.ethereum) {
+ if (provider.value) {
return createWalletClient({
chain: PREFIX_TO_CHAIN[prefix],
- transport: custom(window.ethereum),
+ transport: custom(provider.value),
})
}
}
+ watch(connector, async (connector) => {
+ if (provider.fetching) {
+ return
+ }
+
+ if (connector?.getProvider && !provider.value) {
+ provider.fetching = true
+ provider.value = await connector.getProvider()
+ provider.fetching = false
+ console.log('[VIEM::PROVIDER] Using', provider.value)
+ }
+ else if (!connector && provider.value) {
+ provider.value = undefined
+ console.log('[VIEM::PROVIDER] Cleared')
+ }
+ }, { immediate: Boolean(walletStore.selected && walletStore.getIsEvm) })
+
return {
publicClient,
getWalletClient,
diff --git a/composables/useWagmi.ts b/composables/useWagmi.ts
index 42e045fe20..1669c4cc64 100644
--- a/composables/useWagmi.ts
+++ b/composables/useWagmi.ts
@@ -1,10 +1,9 @@
import { defaultWagmiConfig } from '@web3modal/wagmi/vue'
-import { base, immutableZkEvm } from 'viem/chains'
-import { reconnect as reconnectWagmi } from '@wagmi/core'
+import { base, immutableZkEvm, mantle } from 'viem/chains'
import { useAccount, useDisconnect } from 'use-wagmi'
import type { DisconnectMutateAsync } from 'use-wagmi/query'
-const buildWagmiConfig = () => {
+export const buildWagmiConfig = () => {
const metadata = {
name: 'KodaDot',
description: 'KodaDot - Generative Art Marketplace',
@@ -12,7 +11,7 @@ const buildWagmiConfig = () => {
icons: ['https://avatars.githubusercontent.com/u/37784886'],
}
- const chains = [base, immutableZkEvm]
+ const chains = [base, immutableZkEvm, mantle]
return defaultWagmiConfig({
chains,
@@ -21,29 +20,20 @@ const buildWagmiConfig = () => {
})
}
-const config = buildWagmiConfig() as any
-
export default (
- { reconnect }: { reconnect: boolean } = { reconnect: false },
) => {
- if (reconnect) {
- reconnectWagmi(config)
- }
+ const { $wagmiConfig: config } = useNuxtApp()
- const { isConnected, address, isConnecting, chainId } = useAccount({
- config,
+ const account = useAccount({
+ config: config as any,
})
const disconnect = useNuxtApp().runWithContext(
- () => useDisconnect({ config }).disconnectAsync,
+ () => useDisconnect({ config: config as any }).disconnectAsync,
) as Promise
return {
- config,
- isConnected,
- isConnecting,
- address,
+ ...account,
disconnect,
- chainId,
}
}
diff --git a/composables/useWallet.ts b/composables/useWallet.ts
index b0ceaf4fa4..965d677dba 100644
--- a/composables/useWallet.ts
+++ b/composables/useWallet.ts
@@ -1,3 +1,5 @@
+const PERSISTED_STORES = ['preferences', 'wallet']
+
export default function () {
const { disconnect: disconnectWeb3Modal } = useWagmi()
const shoppingCartStore = useShoppingCartStore()
@@ -5,14 +7,19 @@ export default function () {
const identityStore = useIdentityStore()
const logout = async () => {
+ const isEvm = walletStore.getIsEvm
+
identityStore.resetAuth()
sessionStorage.clear()
- localStorage.clear()
+ // don't use localStorage.clear(), web3modal uses localstorage to save data
+ // there's no way to regerate those values unless hard reload is made
+ PERSISTED_STORES.forEach(store => localStorage.removeItem(store))
shoppingCartStore.clear()
walletStore.setDisconnecting(true)
walletStore.clear()
- if (walletStore.getIsEvm) {
+
+ if (isEvm) {
await disconnectWeb3Modal().catch((error) => {
console.warn('[WEB3MODAL::CONNECTION] Failed disconnecting', error)
})
diff --git a/composables/useWeb3Modal.ts b/composables/useWeb3Modal.ts
index aed6c85335..f6ca69595d 100644
--- a/composables/useWeb3Modal.ts
+++ b/composables/useWeb3Modal.ts
@@ -1,19 +1,18 @@
-import { createWeb3Modal, useWeb3Modal } from '@web3modal/wagmi/vue'
+import { createWeb3Modal } from '@web3modal/wagmi/vue'
+import type { Web3Modal } from '@web3modal/wagmi'
-const modal = ref()
+const modal = ref()
export default () => {
- const { config } = useWagmi()
const { urlPrefix } = usePrefix()
-
- createWeb3Modal({
- wagmiConfig: config,
- projectId: useRuntimeConfig().public.walletConnectProjectId,
- defaultChain: PREFIX_TO_CHAIN[urlPrefix.value],
- })
+ const { $wagmiConfig } = useNuxtApp()
if (!modal.value) {
- modal.value = useWeb3Modal()
+ modal.value = createWeb3Modal({
+ wagmiConfig: $wagmiConfig as any,
+ projectId: useRuntimeConfig().public.walletConnectProjectId,
+ defaultChain: PREFIX_TO_CHAIN[urlPrefix.value],
+ })
}
return {
diff --git a/libs/static/src/chains.ts b/libs/static/src/chains.ts
index 13a87aee69..1671c6729e 100644
--- a/libs/static/src/chains.ts
+++ b/libs/static/src/chains.ts
@@ -32,7 +32,8 @@ export const CHAINS: Config = {
dot: toChainProperty(0, 10, 'DOT', 'https://polkadot.subscan.io/', 'SUB'),
ahp: toChainProperty(0, 10, 'DOT', 'https://statemint.subscan.io/', 'SUB'),
imx: toChainProperty(42, 18, 'IMX', 'https://explorer.immutable.com/', 'EVM'), // ss58Format is not available
- base: toChainProperty(42, 18, 'ETH', 'https://basescan.org', 'EVM'), // ss58Format is not available
+ base: toChainProperty(42, 18, 'ETH', 'https://basescan.org', 'EVM'),
+ mnt: toChainProperty(42, 18, 'MNT', 'https://mantlescan.xyz', 'EVM'), // ss58Format is not available
// ahr: toChainProperty(42, 12, 'ROC', 'https://rockmine.subscan.io/'),
// movr: toChainProperty(1285, 18, 'MOVR', 'https://moonriver.subscan.io/'),
// glmr: toChainProperty(1284, 18, 'GLMR', 'https://moonbeam.subscan.io/'),
@@ -53,6 +54,7 @@ export const chainPrefixes: Prefix[] = [
'dot',
'imx',
'base',
+ 'mnt',
// 'ahr',
// 'movr',
// 'glmr',
@@ -73,6 +75,7 @@ export const chainInfo: Record = {
ahp: 'statemint',
imx: 'immutable',
base: 'base',
+ mnt: 'mantle',
// ahr: 'rockmine',
// movr: 'moonriver',
// glmr: 'moonbeam',
@@ -86,6 +89,7 @@ export const chainNames: Record = {
ahp: 'Polkadot AssetHub',
imx: 'Immutable zkEVM',
base: 'Base',
+ mnt: 'Mantle',
// ahr: 'Rococo AssetHub',
// movr: 'Moonriver',
// glmr: 'Moonbeam',
@@ -113,6 +117,7 @@ export const teleportExistentialDeposit: Record = {
ahp: 5000000000,
imx: 0,
base: 0,
+ mnt: 0,
}
export const existentialDeposit: Record = {
@@ -123,4 +128,5 @@ export const existentialDeposit: Record = {
ahp: 1e8,
imx: 1e15, // nothing like ED in EVM :)
base: 1e15,
+ mnt: 1e15,
}
diff --git a/libs/static/src/endpoints.ts b/libs/static/src/endpoints.ts
index e66b5a28ac..6db8dc38a5 100644
--- a/libs/static/src/endpoints.ts
+++ b/libs/static/src/endpoints.ts
@@ -43,6 +43,7 @@ export const ALTERNATIVE_ENDPOINT_MAP: Config = {
ahp: AHP_ENDPOINTS,
imx: ['https://rpc.immutable.com'],
base: ['https://mainnet.base.org'],
+ mnt: ['https://rpc.mantle.xyz'],
// ahr: ['wss://rococo-asset-hub-rpc.polkadot.io'],
// glmr: ['wss://public-rpc.pinknode.io/moonbeam'],
// movr: ['wss://wss.api.moonriver.moonbeam.network'],
@@ -56,6 +57,7 @@ export const ENDPOINT_MAP: Config = {
ahp: AHP_ENDPOINTS[0],
imx: 'https://rpc.immutable.com',
base: 'https://mainnet.base.org',
+ mnt: 'https://rpc.mantle.xyz',
// ahr: 'wss://rococo-asset-hub-rpc.polkadot.io',
// glmr: 'wss://public-rpc.pinknode.io/moonbeam',
// movr: 'wss://wss.api.moonriver.moonbeam.network',
diff --git a/libs/static/src/indexers.ts b/libs/static/src/indexers.ts
index dec3e57b67..954a68d3aa 100644
--- a/libs/static/src/indexers.ts
+++ b/libs/static/src/indexers.ts
@@ -15,6 +15,7 @@ export const INDEXERS: Config = {
dot: 'https://squid.subsquid.io/rubick/graphql', // TODO: change to dot indexer when available
imx: 'https://squid.subsquid.io/flick/graphql',
base: 'https://kodadot.squids.live/basick/graphql',
+ mnt: 'https://squid.subsquid.io/flock/graphql',
// ahr: 'https://squid.subsquid.io/snack/graphql',
// movr: 'https://squid.subsquid.io/antick/v/001-rc0/graphql',
// glmr: 'https://squid.subsquid.io/click/v/002/graphql',
diff --git a/libs/static/src/names.ts b/libs/static/src/names.ts
index ad03bcd7f1..07da60ca8a 100644
--- a/libs/static/src/names.ts
+++ b/libs/static/src/names.ts
@@ -8,6 +8,7 @@ export const NAMES: Record = {
ahp: 'PolkadotHub',
imx: 'Immutable zkEVM',
base: 'Base',
+ mnt: 'Mantle',
// ahr: 'RococoHub',
// glmr: 'Moonbeam [Beta]',
// movr: 'Moonriver [Beta]',
diff --git a/libs/static/src/services.ts b/libs/static/src/services.ts
index 624f3eb220..36eaadfb72 100644
--- a/libs/static/src/services.ts
+++ b/libs/static/src/services.ts
@@ -17,6 +17,7 @@ export const EXPLORERS: Record = {
ahp: 'https://assethub-polkadot.subscan.io/account/',
imx: 'https://explorer.immutable.com/address/',
base: 'https://basescan.org/address/',
+ mnt: 'https://mantlescan.xyz/address/',
// ahr: 'https://assethub-rococo.subscan.io/account/',
// movr: 'https://moonriver.subscan.io/account/',
// glmr: 'https://moonbeam.subscan.io/account/',
diff --git a/libs/static/src/types.ts b/libs/static/src/types.ts
index 7ef81fb0f9..ec1f4f65c3 100644
--- a/libs/static/src/types.ts
+++ b/libs/static/src/types.ts
@@ -1,9 +1,9 @@
-export type Prefix = 'rmrk' | 'ksm' | 'ahk' | 'dot' | 'ahp' | 'imx' | 'base'
+export type Prefix = 'rmrk' | 'ksm' | 'ahk' | 'dot' | 'ahp' | 'imx' | 'base' | 'mnt'
// | 'ahr'
// | 'glmr'
// | 'movr'
-export type Squid = 'rubick' | 'marck' | 'stick' | 'speck' | 'flick' | 'basick'
+export type Squid = 'rubick' | 'marck' | 'stick' | 'speck' | 'flick' | 'basick' | 'flock'
// | 'snack'
// | 'click'
// | 'antick'
diff --git a/plugins/wagmi.client.ts b/plugins/wagmi.client.ts
new file mode 100644
index 0000000000..774226d07c
--- /dev/null
+++ b/plugins/wagmi.client.ts
@@ -0,0 +1,14 @@
+import { reconnect } from '@wagmi/core'
+
+export default defineNuxtPlugin(() => {
+ const config = buildWagmiConfig()
+
+ reconnect(config)
+
+ return {
+ provide: {
+ // important use same config across the app
+ wagmiConfig: config,
+ },
+ }
+})
diff --git a/services/dyndata.ts b/services/dyndata.ts
new file mode 100644
index 0000000000..98c2f4b17a
--- /dev/null
+++ b/services/dyndata.ts
@@ -0,0 +1,21 @@
+const BASE_URL = isProduction
+ ? 'https://dyndata.koda.art'
+ : 'https://dyndata-beta.koda.art'
+
+const api = $fetch.create({
+ baseURL: BASE_URL,
+})
+
+export const generateId = async () => {
+ return (await api('/generate-id')) as string
+}
+
+export const setDyndataUrl = ({ chain, collection, nft }) => {
+ const metadata = `https://dyndata.koda.art/v1/metadata/${chain}/${collection}/${nft}`
+ const image = `https://dyndata.koda.art/v1/image/${chain}/${collection}/${nft}`
+
+ return {
+ metadata,
+ image,
+ }
+}
diff --git a/services/fxart.ts b/services/fxart.ts
index 3af2862e61..8ee3e1d896 100644
--- a/services/fxart.ts
+++ b/services/fxart.ts
@@ -1,5 +1,4 @@
-import type { FetchError } from 'ofetch'
-import { $fetch } from 'ofetch'
+import { $fetch, type FetchError } from 'ofetch'
import type { Prefix } from '@kodadot1/static'
import type { DropItem } from '@/params/types'
import { isProduction } from '@/utils/env'
@@ -62,26 +61,14 @@ export const getDropMintedStatus = async (alias: string, accountId: string) => {
})
}
-export const setMetadataUrl = ({ chain, collection, sn }) => {
- const metadataUrl = new URL(
- 'https://fxart-beta.kodadot.workers.dev/metadata/v2/json',
- )
- metadataUrl.searchParams.set('chain', chain)
- metadataUrl.searchParams.set('collection', collection)
- metadataUrl.searchParams.set('sn', sn.toString())
-
- return metadataUrl.toString()
-}
-
-export const updateMetadata = async ({ chain, collection, nft, sn }) => {
+export const updateMetadata = async ({ chain, collection, nft }) => {
try {
- const response = await api('/metadata/v2/update', {
+ const response = await api('/metadata/v1/dyndata/update', {
method: 'post',
body: {
chain,
collection,
nft,
- sn,
},
})
diff --git a/stores/fiat.ts b/stores/fiat.ts
index b6405ce510..3d058416f7 100644
--- a/stores/fiat.ts
+++ b/stores/fiat.ts
@@ -4,17 +4,9 @@ import type { TokenName } from '~/utils/coinprice'
type FiatPrice = string | number | null
interface State {
- fiatPrice: {
- kusama: {
- usd: FiatPrice
- }
- polkadot: {
- usd: FiatPrice
- }
- ethereum: {
- usd: FiatPrice
- }
- }
+ fiatPrice: Record
}
export const useFiatStore = defineStore('fiat', {
@@ -29,6 +21,9 @@ export const useFiatStore = defineStore('fiat', {
ethereum: {
usd: null,
},
+ mantle: {
+ usd: null,
+ },
},
}),
getters: {
@@ -42,7 +37,7 @@ export const useFiatStore = defineStore('fiat', {
getCurrentROCValue: (_state): FiatPrice => 0,
getCurrentTokenValue:
state =>
- (token: string): FiatPrice => {
+ (token: Token): FiatPrice => {
switch (token) {
case 'KSM':
return state.fiatPrice.kusama.usd
@@ -50,6 +45,8 @@ export const useFiatStore = defineStore('fiat', {
return state.fiatPrice.polkadot.usd
case 'ETH':
return state.fiatPrice.ethereum.usd
+ case 'MNT':
+ return state.fiatPrice.mantle.usd
default:
return 0
}
@@ -58,7 +55,7 @@ export const useFiatStore = defineStore('fiat', {
actions: {
async fetchFiatPrice() {
const prices = await Promise.all(
- (['kusama', 'polkadot', 'ethereum'] as TokenName[]).map(getPrice),
+ (['kusama', 'polkadot', 'ethereum', 'mantle'] as TokenName[]).map(getPrice),
)
prices.forEach((price) => {
this.fiatPrice = Object.assign({}, this.fiatPrice, price)
diff --git a/stores/identity.ts b/stores/identity.ts
index 25c3076ca8..9bc898944c 100644
--- a/stores/identity.ts
+++ b/stores/identity.ts
@@ -11,6 +11,7 @@ const DEFAULT_BALANCE_STATE = {
dot: '0',
ahp: '0',
eth: '0',
+ mnt: '0',
// ahr: '0',
// glmr: '0',
// movr: '0',
@@ -34,6 +35,7 @@ export type ChainType =
| 'polkadotHub'
| 'base'
| 'immutablex'
+ | 'mantle'
// | 'rococoHub'
type ChainDetail = {
@@ -43,7 +45,7 @@ type ChainDetail = {
selected: boolean
address: string
}
-export type ChainToken = Partial>
+export type ChainToken = Partial>
interface MultiBalances {
address: string
@@ -105,6 +107,7 @@ export const useIdentityStore = defineStore('identity', {
{ chain: 'polkadotHub', token: 'DOT' },
{ chain: 'base', token: 'ETH' },
{ chain: 'immutablex', token: 'ETH' },
+ { chain: 'mantle', token: 'MNT' },
],
multiBalanceAssetsTestnet: [
// { chain: 'rococoHub', token: 'ROC' },
diff --git a/types/nuxt.d.ts b/types/nuxt.d.ts
new file mode 100644
index 0000000000..9a5a9a4b98
--- /dev/null
+++ b/types/nuxt.d.ts
@@ -0,0 +1,7 @@
+import type { Config } from '@wagmi/core'
+
+declare module '#app' {
+ interface NuxtApp {
+ $wagmiConfig: Config
+ }
+}
diff --git a/utils/coinprice.ts b/utils/coinprice.ts
index 6906cb24ee..8b4440aadd 100644
--- a/utils/coinprice.ts
+++ b/utils/coinprice.ts
@@ -60,12 +60,14 @@ export const getPrice = async (id: string): Promise => {
return emptyPrice
}
-export type TokenName = 'kusama' | 'polkadot' | 'ethereum'
+export type Token = 'KSM' | 'DOT' | 'ETH' | 'MNT'
+export type TokenName = 'kusama' | 'polkadot' | 'ethereum' | 'mantle'
// tokenMap but reversed
-const tokenMap: Record = {
+const tokenMap: Record = {
KSM: 'kusama',
DOT: 'polkadot',
ETH: 'ethereum',
+ MNT: 'mantle',
}
export const getApproximatePriceOf = async (id: string): Promise => {
diff --git a/utils/config/chain.config.ts b/utils/config/chain.config.ts
index 424cd5fa07..41e846611d 100644
--- a/utils/config/chain.config.ts
+++ b/utils/config/chain.config.ts
@@ -1,11 +1,15 @@
import { CHAINS } from '@kodadot1/static'
-import type { Prefix, ChainProperties } from '@kodadot1/static'
+import type { Prefix, ChainProperties, ChainVM } from '@kodadot1/static'
export const chainPropListOf = (prefix: Prefix): ChainProperties => {
return CHAINS[prefix]
}
+export const vmOf = (prefix: Prefix): ChainVM => {
+ return chainPropListOf(prefix).vm
+}
+
export const ss58Of = (prefix: Prefix): number => {
return chainPropListOf(prefix).ss58Format
}
diff --git a/utils/config/permission.config.ts b/utils/config/permission.config.ts
index da8efef4b5..9f2bf07ec9 100644
--- a/utils/config/permission.config.ts
+++ b/utils/config/permission.config.ts
@@ -1,16 +1,10 @@
+import { chainPropListOf } from './chain.config'
import type { PartialConfig, Prefix } from './types'
const hasCreate: PartialConfig = {
dot: false,
ksm: false,
rmrk: false,
- base: false,
- imx: false,
-}
-
-const hasList: PartialConfig = {
- base: false,
- imx: false,
}
const hasInsight: PartialConfig = {
@@ -34,11 +28,11 @@ const hasExplorer: PartialConfig = {
}
export const createVisible = (prefix: Prefix | string): boolean => {
- return hasCreate[prefix] ?? true
+ return isEvm(prefix as Prefix) ? false : hasCreate[prefix] ?? true
}
export const listVisible = (prefix: Prefix | string): boolean => {
- return hasList[prefix] ?? true
+ return !isEvm(prefix as Prefix)
}
export const seriesInsightVisible = (prefix: Prefix | string) => {
@@ -54,7 +48,7 @@ export const salesVisible = (prefix: Prefix | string) => {
}
export const dropsVisible = (prefix: Prefix | string) => {
- return prefix === 'ahk' || prefix === 'ahp' || prefix === 'base'
+ return prefix === 'ahk' || prefix === 'ahp' || chainPropListOf(prefix as Prefix).vm === 'EVM'
}
export const explorerVisible = (prefix: Prefix | string): boolean => {
diff --git a/utils/teleport.ts b/utils/teleport.ts
index 608d2babd9..f56982845d 100644
--- a/utils/teleport.ts
+++ b/utils/teleport.ts
@@ -16,6 +16,7 @@ export enum Chain {
POLKADOT = 'Polkadot',
BASE = 'Base',
IMMUTABLEX = 'Immutable',
+ MANTLE = 'Mantle',
}
export type TeleportChain = {
@@ -48,6 +49,7 @@ export const chainToPrefixMap: Record = {
[Chain.POLKADOT]: 'dot',
[Chain.BASE]: 'base',
[Chain.IMMUTABLEX]: 'imx',
+ [Chain.MANTLE]: 'mnt',
}
export const prefixToChainMap: Partial> = {
@@ -58,6 +60,7 @@ export const prefixToChainMap: Partial> = {
dot: Chain.POLKADOT,
imx: Chain.IMMUTABLEX,
base: Chain.BASE,
+ mnt: Chain.MANTLE,
}
export enum TeleprtType {
@@ -174,7 +177,7 @@ export const getTransactionFee = async ({
return info.partialFee.toString()
}
-export type Currency = 'KSM' | 'DOT' | 'ETH'
+export type Currency = 'KSM' | 'DOT' | 'ETH' | 'MNT'
export const getChainCurrency = (chain: Chain): Currency => {
switch (chain) {
@@ -187,6 +190,8 @@ export const getChainCurrency = (chain: Chain): Currency => {
case Chain.BASE:
case Chain.IMMUTABLEX:
return 'ETH'
+ case Chain.MANTLE:
+ return 'MNT'
}
}
@@ -195,6 +200,7 @@ export const chainToPrecisionMap: Record = {
[Chain.ASSETHUBKUSAMA]: 6,
[Chain.ASSETHUBPOLKADOT]: 5,
[Chain.BASE]: 5,
+ [Chain.MANTLE]: 5,
[Chain.IMMUTABLEX]: 5,
[Chain.POLKADOT]: 4,
}
diff --git a/utils/wagmi.ts b/utils/wagmi.ts
index ebedc07bbc..ac3949f1b2 100644
--- a/utils/wagmi.ts
+++ b/utils/wagmi.ts
@@ -1,15 +1,17 @@
import type { Prefix } from '@kodadot1/static'
-import { base, immutableZkEvm } from 'viem/chains'
+import { base, immutableZkEvm, mantle } from 'viem/chains'
import { type Chain, createPublicClient, http } from 'viem'
export const CHAIN_ID_TO_PREFIX: Record = {
8453: 'base',
13371: 'imx',
+ 5000: 'mnt',
}
export const PREFIX_TO_CHAIN: Partial> = {
base: base,
imx: immutableZkEvm,
+ mnt: mantle,
}
export const viemClient = (prefix: Prefix) =>