Skip to content
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
1 change: 1 addition & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@
"xlarge",
"xlink",
"zerion",
"zora",
"zubin"
],
"ignoreWords": [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { makeStyles } from '@masknet/theme'
import { OpenSeaIcon } from '../../../resources/OpenSeaIcon'
import { RaribleIcon } from '../../../resources/RaribleIcon'
import { ZoraIcon } from '../../../resources/ZoraIcon'
import { unreachable } from '@dimensiondev/kit'
import { NonFungibleAssetProvider } from '@masknet/web3-shared-evm'

Expand Down Expand Up @@ -37,6 +38,8 @@ export function CollectibleProviderIcon(props: CollectibleProviderIconProps) {
return <OpenSeaIcon classes={{ root: classes.opensea }} viewBox="0 0 16 16" />
case NonFungibleAssetProvider.RARIBLE:
return <RaribleIcon classes={{ root: classes.rarible }} viewBox="0 0 16 16" />
case NonFungibleAssetProvider.ZORA:
return <ZoraIcon classes={{ root: classes.rarible }} viewBox="0 0 16 16" />
default:
unreachable(props.provider)
}
Expand Down
1 change: 1 addition & 0 deletions packages/mask/src/plugins/Collectible/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const base: Plugin.Shared.Definition = {
postContent: new Set([
/opensea.io\/assets\/(0x[\dA-Fa-f]{40})\/(\d+)/,
/rarible.com\/token\/(0x[\dA-Fa-f]{40}):(\d+)/,
/zora.co\/collections\/(0x[\dA-Fa-f]{40})\/\d+$/,
]),
},
}
3 changes: 3 additions & 0 deletions packages/mask/src/plugins/Collectible/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ export const openseaPathnameRegexMatcher = /^\/assets\/(0x[\dA-Fa-f]{40})\/(\d+)
export const raribleHostnames = ['rarible.com', 'app.rarible.com', 'ropsten.rarible.com']
export const rariblePathnameRegexMatcher = /^\/token\/(0x[\dA-Fa-f]{40}):(\d+)/

export const zoraHostnames = ['zora.co']
export const zoraPathnameRegexMatcher = /^\/collections\/(0x[\dA-Fa-f]{40})\/(\d+)$/

export const OpenSeaAPI_Key = 'c38fe2446ee34f919436c32db480a2e3'
export const OpenSeaBaseURL = 'https://api.opensea.io/api/v1/'
export const OpenSeaRinkebyBaseURL = 'https://rinkeby-api.opensea.io/api/v1/'
Expand Down
2 changes: 2 additions & 0 deletions packages/mask/src/plugins/Collectible/hooks/useAssetOrder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ export function useAssetOrder(provider: NonFungibleAssetProvider, token?: Collec
return
case NonFungibleAssetProvider.NFTSCAN:
return
case NonFungibleAssetProvider.ZORA:
return
default:
unreachable(provider)
}
Expand Down
14 changes: 14 additions & 0 deletions packages/mask/src/plugins/Collectible/pipes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export const resolveCollectibleProviderName = createLookupTableResolver<NonFungi
[NonFungibleAssetProvider.OPENSEA]: 'OpenSea',
[NonFungibleAssetProvider.RARIBLE]: 'Rarible',
[NonFungibleAssetProvider.NFTSCAN]: 'NFTScan',
[NonFungibleAssetProvider.ZORA]: 'Zora',
},
(providerType) => {
throw new Error(`Unknown provider type: ${providerType}.`)
Expand Down Expand Up @@ -88,6 +89,13 @@ export const resolveLinkOnRarible = createLookupTableResolver<ChainId, string>(
'https://rarible.com',
)

export const resolveLinkOnZora = createLookupTableResolver<ChainId, string>(
{
[ChainId.Mainnet]: 'https://zora.co',
},
'https://zora.co',
)

export function resolveTraitLinkOnOpenSea(chainId: ChainId, slug: string, search: string, value: string) {
if (chainId === ChainId.Rinkeby) {
return `https://testnets.opensea.io/assets/${slug}?search[stringTraits][0][name]=${search}&search[stringTraits][0][values][0]=${value}`
Expand All @@ -109,6 +117,8 @@ export function resolveAssetLinkOnCurrentProvider(
return urlcat(resolveLinkOnRarible(chainId), '/token/:address/:id', { address, id })
case NonFungibleAssetProvider.NFTSCAN:
return ''
case NonFungibleAssetProvider.ZORA:
return urlcat(resolveLinkOnZora(chainId), '/collections/:address/:id', { address, id })
default:
return ''
}
Expand All @@ -127,6 +137,8 @@ export function resolveUserUrlOnCurrentProvider(
return urlcat(resolveLinkOnOpenSea(chainId), `/${username ?? ''}`)
case NonFungibleAssetProvider.NFTSCAN:
return ''
case NonFungibleAssetProvider.ZORA:
return urlcat(resolveLinkOnZora(chainId), `/${address}`)
default:
return ''
}
Expand All @@ -140,6 +152,8 @@ export function resolveAvatarLinkOnCurrentProvider(chainId: ChainId, asset: any,
return urlcat(resolveLinkOnRarible(chainId), `/collection/${asset.token_address ?? ''}`)
case NonFungibleAssetProvider.NFTSCAN:
return ''
case NonFungibleAssetProvider.ZORA:
return ''
default:
return ''
}
Expand Down
16 changes: 15 additions & 1 deletion packages/mask/src/plugins/Collectible/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
openseaPathnameRegexMatcher,
raribleHostnames,
rariblePathnameRegexMatcher,
zoraHostnames,
zoraPathnameRegexMatcher,
} from './constants'
import { ChainId } from '@masknet/web3-shared-evm'
import { WyvernSchemaName } from 'opensea-js/lib/types'
Expand All @@ -14,7 +16,8 @@ export function checkUrl(url: string): boolean {

return (
(openseaHostnames.includes(_url.hostname) && openseaPathnameRegexMatcher.test(_url.pathname)) ||
(raribleHostnames.includes(_url.hostname) && rariblePathnameRegexMatcher.test(_url.pathname))
(raribleHostnames.includes(_url.hostname) && rariblePathnameRegexMatcher.test(_url.pathname)) ||
(zoraHostnames.includes(_url.hostname) && zoraPathnameRegexMatcher.test(_url.pathname))
)
}

Expand Down Expand Up @@ -53,6 +56,17 @@ export function getAssetInfoFromURL(url?: string) {
}
// #endregion

// #region zora
const zoraMatched = _url.pathname.match(zoraPathnameRegexMatcher)
if (zoraMatched) {
return {
chain_id: _url.host.includes('rinkeby') ? ChainId.Rinkeby : ChainId.Mainnet,
address: zoraMatched[1],
token_id: zoraMatched[2],
}
}
// #endregion

// nothing matched
return
}
Expand Down
12 changes: 11 additions & 1 deletion packages/mask/src/plugins/EVM/services/Asset/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { unreachable } from '@dimensiondev/kit'
import { ChainId, NonFungibleAssetProvider } from '@masknet/web3-shared-evm'
import { NonFungibleTokenAPI, OpenSea, Rarible } from '@masknet/web3-providers'
import { NonFungibleTokenAPI, OpenSea, Rarible, Zora } from '@masknet/web3-providers'

export interface AssetOption {
address: string
Expand Down Expand Up @@ -56,6 +56,8 @@ export async function getAsset(options: AssetOption) {
return
case NonFungibleAssetProvider.RARIBLE:
return Rarible.getAsset(options.address, options.tokenId, { chainId: options.chainId })
case NonFungibleAssetProvider.ZORA:
return Zora.getAsset(options.address, options.tokenId)
default:
unreachable(options.provider)
}
Expand All @@ -74,6 +76,8 @@ export async function getOrders(options: OrderOption) {
return []
case NonFungibleAssetProvider.RARIBLE:
return Rarible.getOrders(address, tokenId, side, { chainId })
case NonFungibleAssetProvider.ZORA:
return Zora.getOrders(address, tokenId, side)
default:
unreachable(provider)
}
Expand All @@ -88,6 +92,8 @@ export async function getListings(options: ListOption) {
return []
case NonFungibleAssetProvider.RARIBLE:
return Rarible.getListings(address, tokenId, { chainId })
case NonFungibleAssetProvider.ZORA:
return Zora.getListings(address, tokenId)
default:
unreachable(provider)
}
Expand All @@ -102,6 +108,8 @@ export async function getHistory(options: HistoryOption) {
return []
case NonFungibleAssetProvider.RARIBLE:
return Rarible.getHistory(address, tokenId)
case NonFungibleAssetProvider.ZORA:
return Zora.getHistory(address, tokenId)
default:
unreachable(provider)
}
Expand All @@ -116,6 +124,8 @@ export async function getCollections(options: CollectionOption) {
return defaultPageableData
case NonFungibleAssetProvider.NFTSCAN:
return defaultPageableData
case NonFungibleAssetProvider.ZORA:
return defaultPageableData
default:
unreachable(provider)
}
Expand Down
9 changes: 8 additions & 1 deletion packages/mask/src/plugins/EVM/services/NFT/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { OpenSea, Rarible, NFTScan } from '@masknet/web3-providers'
import { OpenSea, Rarible, NFTScan, Zora } from '@masknet/web3-providers'
import { unreachable } from '@dimensiondev/kit'
import { ChainId, NonFungibleAssetProvider } from '@masknet/web3-shared-evm'

Expand Down Expand Up @@ -39,6 +39,8 @@ export async function getNFT(options: NFTOption) {
return NFTScan.getToken(address, tokenId)
case NonFungibleAssetProvider.RARIBLE:
return Rarible.getToken(address, tokenId)
case NonFungibleAssetProvider.ZORA:
return Zora.getToken(address, tokenId)
default:
unreachable(provider)
}
Expand All @@ -50,6 +52,7 @@ export async function getNFTBalance(options: BalanceOption) {
case NonFungibleAssetProvider.RARIBLE:
case NonFungibleAssetProvider.OPENSEA:
case NonFungibleAssetProvider.NFTSCAN:
case NonFungibleAssetProvider.ZORA:
return NFTScan.getContractBalance(address)

default:
Expand All @@ -65,6 +68,8 @@ export async function getNFTContract(options: ContractOption) {
return OpenSea.getContract(contractAddress, chainId)
case NonFungibleAssetProvider.RARIBLE:
return
case NonFungibleAssetProvider.ZORA:
return
default:
unreachable(provider)
}
Expand All @@ -79,6 +84,8 @@ export async function getNFTsByPagination(options: NFTsByPaginationOption) {
return NFTScan.getTokens(from, options)
case NonFungibleAssetProvider.RARIBLE:
return Rarible.getTokens(from, options)
case NonFungibleAssetProvider.ZORA:
return Rarible.getTokens(from, options)
default:
unreachable(provider)
}
Expand Down
63 changes: 63 additions & 0 deletions packages/mask/src/resources/ZoraIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { SvgIconProps, SvgIcon } from '@mui/material'

const svg = (
<svg width="30" height="30" viewBox="0 0 55 55" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M0.943359 13.2631C0.943359 20.5774 6.88707 26.5261 14.1951 26.5261C21.5032 26.5261 27.4469 20.5774 27.4469 13.2631C27.4402 5.94887 21.4964 0.00012207 14.1951 0.00012207C6.88707 0.00012207 0.943359 5.94887 0.943359 13.2631Z"
fill="url(#paint0_radial)"
/>
<path
d="M0.943359 13.2631C0.943359 20.5774 6.88707 26.5261 14.1951 26.5261C21.5032 26.5261 27.4469 20.5774 27.4469 13.2631C27.4402 5.94887 21.4964 0.00012207 14.1951 0.00012207C6.88707 0.00012207 0.943359 5.94887 0.943359 13.2631Z"
fill="url(#paint1_radial)"
/>
<path
d="M0.943359 13.2631C0.943359 20.5774 6.88707 26.5261 14.1951 26.5261C21.5032 26.5261 27.4469 20.5774 27.4469 13.2631C27.4402 5.94887 21.4964 0.00012207 14.1951 0.00012207C6.88707 0.00012207 0.943359 5.94887 0.943359 13.2631Z"
fill="url(#paint2_radial)"
/>
<defs>
<radialGradient
id="paint0_radial"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(18.1597 6.46118) scale(19.9547 19.9716)">
<stop offset="0.00520833" stopColor="white" />
<stop offset="0.458333" stopColor="#B7D8C8" />
<stop offset="0.65625" stopColor="#6D9487" />
<stop offset="1" stopColor="#4B4C3C" />
</radialGradient>
<radialGradient
id="paint1_radial"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(18.1597 6.46118) scale(19.9547 19.9716)">
<stop offset="0.00520833" stopColor="white" />
<stop offset="0.458333" stopColor="#B5B4C6" />
<stop offset="0.65625" stopColor="#9B8F8F" />
<stop offset="1" stopColor="#4B4C3C" />
</radialGradient>
<radialGradient
id="paint2_radial"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(18.1597 6.46118) scale(19.9547 19.9716)">
<stop offset="0.15625" stopColor="#DCC8D0" />
<stop offset="0.302083" stopColor="#78C8CF" />
<stop offset="0.427083" stopColor="#4D959E" />
<stop offset="0.557292" stopColor="#305EB9" />
<stop offset="0.796875" stopColor="#311F12" />
<stop offset="0.90625" stopColor="#684232" />
<stop offset="1" stopColor="#2D1C13" />
</radialGradient>
</defs>
</svg>
)

export function ZoraIcon(props: SvgIconProps) {
return <SvgIcon {...props}>{svg}</SvgIcon>
}
1 change: 1 addition & 0 deletions packages/web3-providers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"@masknet/web3-contracts": "workspace:*",
"react-use": "^17.3.2",
"wallet.ts": "^1.0.1",
"graphql-request": "^3.4.0",
"bignumber.js": "9.0.2",
"date-fns": "^2.28.0",
"json-stable-stringify": "^1.0.1",
Expand Down
2 changes: 2 additions & 0 deletions packages/web3-providers/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { CoinGeckoAPI } from './coingecko'
import { OpenSeaAPI } from './opensea'
import { RaribleAPI } from './rarible'
import { NFTScanAPI } from './NFTScan'
import { ZoraAPI } from './zora'
import { NativeExplorerAPI } from './explorer'
import { RSS3API } from './rss3'
import { KeyValueAPI } from './kv'
Expand All @@ -17,6 +18,7 @@ export * from './NextID'
export const OpenSea = new OpenSeaAPI()
export const Rarible = new RaribleAPI()
export const NFTScan = new NFTScanAPI()
export const Zora = new ZoraAPI()
export const CoinGecko = new CoinGeckoAPI()
export const Explorer = new NativeExplorerAPI()
export const RSS3 = new RSS3API()
Expand Down
1 change: 1 addition & 0 deletions packages/web3-providers/src/zora/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const ZORA_MAINNET_GRAPHQL_URL = 'https://cors.r2d2.to/?https://indexer-prod-mainnet.zora.co/v1/graphql'
Loading