feat: Add utility code for NFT Features (#4256)
* import nft utilities * re-add featureflag provider * add back in useCurrencyBalanceString fn * remove static assets for separate pr * remove resolutions, swap dev and regular dependencies, respond to comments * remove currently unused dependencies and resynth .lock * build: update lockfile * build: update lockfile * remove env check * useCurrencyBalanceString as fn * remove supported_Wallets until wallet component merged in * make Atoms an interface * update abis * remove outdated comment * update usedebounce hook * remove useDarkMode * remove useLazyEffect * remove getEtherscan helper fn * remove useLastWallet * remove useWindowDimensions * refactor hooks * move hooks from nft to general folder * add walletBalanceInterface and remove wrongNetwork hook * remove empty obj * remove ethers imports * fixed comparison * same line eslint ignore * gtag removed * revert * revert * build: update lockfile * remove walletinfo interface * remove newline * remove tslinst exception from isMobile * remove hiding linter warnings * remove unused util * fix linter warnings Co-authored-by: Charles Bachmeier <charlie@genie.xyz> Co-authored-by: Zach Pomerantz <zzmp@uniswap.org>
This commit is contained in:
parent
783f197463
commit
8dbc91ee6b
19
craco.config.cjs
Normal file
19
craco.config.cjs
Normal file
@ -0,0 +1,19 @@
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const { VanillaExtractPlugin } = require('@vanilla-extract/webpack-plugin')
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||
|
||||
module.exports = {
|
||||
babel: {
|
||||
plugins: ['@vanilla-extract/babel-plugin'],
|
||||
},
|
||||
webpack: {
|
||||
plugins: [new VanillaExtractPlugin()],
|
||||
configure: (webpackConfig) => {
|
||||
const instanceOfMiniCssExtractPlugin = webpackConfig.plugins.find(
|
||||
(plugin) => plugin instanceof MiniCssExtractPlugin
|
||||
)
|
||||
if (instanceOfMiniCssExtractPlugin !== undefined) instanceOfMiniCssExtractPlugin.options.ignoreOrder = true
|
||||
return webpackConfig
|
||||
},
|
||||
},
|
||||
}
|
27
package.json
27
package.json
@ -14,11 +14,11 @@
|
||||
"i18n:compile": "yarn i18n:extract && lingui compile",
|
||||
"i18n:pseudo": "lingui extract --locale pseudo && lingui compile",
|
||||
"prepare": "yarn contracts:compile && yarn graphql:generate && yarn i18n:compile",
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"start": "craco start",
|
||||
"build": "craco build",
|
||||
"serve": "serve build -l 3000",
|
||||
"lint": "yarn eslint .",
|
||||
"test": "react-scripts test --coverage",
|
||||
"test": "craco test --coverage",
|
||||
"cypress:open": "cypress open --browser chrome --e2e",
|
||||
"cypress:run": "cypress run --browser chrome --e2e"
|
||||
},
|
||||
@ -55,6 +55,7 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@craco/craco": "6.4.3",
|
||||
"@ethersproject/experimental": "^5.4.0",
|
||||
"@graphql-codegen/cli": "1.21.5",
|
||||
"@graphql-codegen/typescript": "1.22.3",
|
||||
@ -85,6 +86,7 @@
|
||||
"@types/styled-components": "^5.1.25",
|
||||
"@types/testing-library__cypress": "^5.0.5",
|
||||
"@types/ua-parser-js": "^0.7.35",
|
||||
"@types/uuid": "^8.3.4",
|
||||
"@types/wcag-contrast": "^3.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4",
|
||||
"@typescript-eslint/parser": "^4",
|
||||
@ -104,7 +106,9 @@
|
||||
"react-scripts": "^4.0.3",
|
||||
"serve": "^11.3.2",
|
||||
"typechain": "^5.0.0",
|
||||
"typescript": "^4.4.3"
|
||||
"typescript": "^4.4.3",
|
||||
"@vanilla-extract/babel-plugin": "^1.1.7",
|
||||
"@vanilla-extract/webpack-plugin": "^2.1.11"
|
||||
},
|
||||
"dependencies": {
|
||||
"@amplitude/analytics-browser": "^0.5.1",
|
||||
@ -115,7 +119,9 @@
|
||||
"@lingui/core": "^3.14.0",
|
||||
"@lingui/macro": "^3.14.0",
|
||||
"@lingui/react": "^3.14.0",
|
||||
"@looksrare/sdk": "^0.7.1",
|
||||
"@metamask/jazzicon": "^2.0.0",
|
||||
"@opensea/seaport-js": "^1.0.2",
|
||||
"@popperjs/core": "^2.4.4",
|
||||
"@reach/dialog": "^0.10.3",
|
||||
"@reach/portal": "^0.10.3",
|
||||
@ -135,6 +141,10 @@
|
||||
"@uniswap/v3-core": "1.0.0",
|
||||
"@uniswap/v3-periphery": "^1.1.1",
|
||||
"@uniswap/v3-sdk": "^3.9.0",
|
||||
"@vanilla-extract/css": "^1.7.2",
|
||||
"@vanilla-extract/css-utils": "^0.1.2",
|
||||
"@vanilla-extract/dynamic": "^2.0.2",
|
||||
"@vanilla-extract/sprinkles": "^1.4.1",
|
||||
"@visx/axis": "^2.12.2",
|
||||
"@visx/event": "^2.6.0",
|
||||
"@visx/glyph": "^2.10.0",
|
||||
@ -156,11 +166,13 @@
|
||||
"array.prototype.flat": "^1.2.4",
|
||||
"array.prototype.flatmap": "^1.2.4",
|
||||
"cids": "^1.0.0",
|
||||
"clsx": "^1.1.1",
|
||||
"copy-to-clipboard": "^3.2.0",
|
||||
"d3": "^7.6.1",
|
||||
"d3-curve-circlecorners": "^0.1.6",
|
||||
"ethers": "^5.1.4",
|
||||
"firebase": "^9.1.3",
|
||||
"focus-visible": "^5.2.0",
|
||||
"fortmatic": "^2.4.0",
|
||||
"graphql": "^15.5.0",
|
||||
"graphql-request": "^3.4.0",
|
||||
@ -185,9 +197,11 @@
|
||||
"react-is": "^17.0.2",
|
||||
"react-markdown": "^4.3.1",
|
||||
"react-popper": "^2.2.3",
|
||||
"react-query": "^3.39.1",
|
||||
"react-redux": "^8.0.2",
|
||||
"react-router-dom": "^6.3.0",
|
||||
"react-spring": "^8.0.27",
|
||||
"react-table": "^7.8.0",
|
||||
"react-use-gesture": "^6.0.14",
|
||||
"react-virtualized-auto-sizer": "^1.0.2",
|
||||
"react-window": "^1.8.5",
|
||||
@ -200,11 +214,14 @@
|
||||
"ua-parser-js": "^0.7.28",
|
||||
"use-count-up": "^2.2.5",
|
||||
"use-resize-observer": "^9.0.2",
|
||||
"uuid": "^8.3.2",
|
||||
"video-extensions": "^1.2.0",
|
||||
"wcag-contrast": "^3.0.0",
|
||||
"web-vitals": "^2.1.0",
|
||||
"workbox-core": "^6.1.0",
|
||||
"workbox-navigation-preload": "^6.1.0",
|
||||
"workbox-precaching": "^6.1.0",
|
||||
"workbox-routing": "^6.1.0"
|
||||
"workbox-routing": "^6.1.0",
|
||||
"zustand": "^4.0.0-rc.1"
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,143 @@
|
||||
[
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "string",
|
||||
"name": "uri_",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "constructor"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "account",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "operator",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "bool",
|
||||
"name": "approved",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"name": "ApprovalForAll",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "operator",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "from",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256[]",
|
||||
"name": "ids",
|
||||
"type": "uint256[]"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256[]",
|
||||
"name": "values",
|
||||
"type": "uint256[]"
|
||||
}
|
||||
],
|
||||
"name": "TransferBatch",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "operator",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "from",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "id",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "TransferSingle",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "string",
|
||||
"name": "value",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "uint256",
|
||||
"name": "id",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "URI",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_owner",
|
||||
"name": "account",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_id",
|
||||
"name": "id",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
@ -21,16 +149,165 @@
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address[]",
|
||||
"name": "accounts",
|
||||
"type": "address[]"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256[]",
|
||||
"name": "ids",
|
||||
"type": "uint256[]"
|
||||
}
|
||||
],
|
||||
"name": "balanceOfBatch",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256[]",
|
||||
"name": "",
|
||||
"type": "uint256[]"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "account",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "operator",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "isApprovedForAll",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "from",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256[]",
|
||||
"name": "ids",
|
||||
"type": "uint256[]"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256[]",
|
||||
"name": "amounts",
|
||||
"type": "uint256[]"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "data",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"name": "safeBatchTransferFrom",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "from",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "id",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "data",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"name": "safeTransferFrom",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "operator",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "approved",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"name": "setApprovalForAll",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "bytes4",
|
||||
"name": "interfaceId",
|
||||
"type": "bytes4"
|
||||
}
|
||||
],
|
||||
"name": "supportsInterface",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_id",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
@ -42,7 +319,6 @@
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
}
|
||||
|
@ -1,5 +1,320 @@
|
||||
[
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "punkContract",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "constructor"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "owner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "approved",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "uint256",
|
||||
"name": "tokenId",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "Approval",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "owner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "operator",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "bool",
|
||||
"name": "approved",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"name": "ApprovalForAll",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "previousOwner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "newOwner",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "OwnershipTransferred",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "address",
|
||||
"name": "account",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "Paused",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "address",
|
||||
"name": "user",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "address",
|
||||
"name": "proxy",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "ProxyRegistered",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "from",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "uint256",
|
||||
"name": "tokenId",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "Transfer",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "address",
|
||||
"name": "account",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "Unpaused",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "tokenId",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "approve",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "owner",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "balanceOf",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "baseURI",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "string",
|
||||
"name": "",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "punkIndex",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "burn",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "tokenId",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "getApproved",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "owner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "operator",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "isApprovedForAll",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "punkIndex",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "mint",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "name",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "string",
|
||||
"name": "",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "owner",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
@ -15,10 +330,263 @@
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [],
|
||||
"name": "pause",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "paused",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "user",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "proxyInfo",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "punkContract",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [],
|
||||
"name": "registerProxy",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [],
|
||||
"name": "renounceOwnership",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "from",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "tokenId",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "safeTransferFrom",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "from",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "tokenId",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "_data",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"name": "safeTransferFrom",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "approved",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"name": "setApprovalForAll",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "string",
|
||||
"name": "baseUri",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"name": "setBaseURI",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "bytes4",
|
||||
"name": "interfaceId",
|
||||
"type": "bytes4"
|
||||
}
|
||||
],
|
||||
"name": "supportsInterface",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "symbol",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "string",
|
||||
"name": "",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "index",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "tokenByIndex",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "owner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "index",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "tokenOfOwnerByIndex",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
@ -34,7 +602,72 @@
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "totalSupply",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "from",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "tokenId",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "transferFrom",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "newOwner",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "transferOwnership",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [],
|
||||
"name": "unpause",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
}
|
||||
]
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
|
||||
/**
|
||||
* Debounces updates to a value.
|
||||
@ -24,3 +24,34 @@ export default function useDebounce<T>(value: T, delay: number): T {
|
||||
|
||||
return debouncedValue
|
||||
}
|
||||
|
||||
export function useDebouncedCallback<A extends unknown[]>(callback: (...args: A) => void, wait: number) {
|
||||
// track args & timeout handle between calls
|
||||
const argsRef = useRef<A>()
|
||||
const timeout = useRef<ReturnType<typeof setTimeout>>()
|
||||
|
||||
function cleanup() {
|
||||
if (timeout.current) {
|
||||
clearTimeout(timeout.current)
|
||||
}
|
||||
}
|
||||
|
||||
// make sure our timeout gets cleared if
|
||||
// our consuming component gets unmounted
|
||||
useEffect(() => cleanup, [])
|
||||
|
||||
return function debouncedCallback(...args: A) {
|
||||
// capture latest args
|
||||
argsRef.current = args
|
||||
|
||||
// clear debounce timer
|
||||
cleanup()
|
||||
|
||||
// start waiting again
|
||||
timeout.current = setTimeout(() => {
|
||||
if (argsRef.current) {
|
||||
callback(...argsRef.current)
|
||||
}
|
||||
}, wait)
|
||||
}
|
||||
}
|
||||
|
17
src/hooks/useImperativeDisableScroll.ts
Normal file
17
src/hooks/useImperativeDisableScroll.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { useEffect } from 'react'
|
||||
|
||||
/**
|
||||
* Disable scroll of an element based on condition
|
||||
*/
|
||||
export function useImperativeDisableScroll({ element, disabled }: { element?: HTMLElement; disabled?: boolean }) {
|
||||
useEffect(() => {
|
||||
if (!element) return
|
||||
|
||||
element.style.overflowY = disabled ? 'hidden' : 'auto'
|
||||
|
||||
return () => {
|
||||
element.style.overflowY = 'auto'
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [disabled])
|
||||
}
|
26
src/hooks/useOnClickOutside.ts
Normal file
26
src/hooks/useOnClickOutside.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { RefObject, useEffect, useRef } from 'react'
|
||||
|
||||
export function useOnClickOutside<T extends HTMLElement>(
|
||||
node: RefObject<T | undefined>,
|
||||
handler: undefined | (() => void)
|
||||
) {
|
||||
const handlerRef = useRef<undefined | (() => void)>(handler)
|
||||
useEffect(() => {
|
||||
handlerRef.current = handler
|
||||
}, [handler])
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (e: MouseEvent) => {
|
||||
if (node.current?.contains(e.target as Node) ?? false) {
|
||||
return
|
||||
}
|
||||
if (handlerRef.current) handlerRef.current()
|
||||
}
|
||||
|
||||
document.addEventListener('mousedown', handleClickOutside)
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', handleClickOutside)
|
||||
}
|
||||
}, [node])
|
||||
}
|
27
src/hooks/useTimeout.ts
Normal file
27
src/hooks/useTimeout.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
const getReturnValues = (countDown: number): [number, number, number, number] => {
|
||||
// calculate time left
|
||||
const days = Math.floor(countDown / (1000 * 60 * 60 * 24))
|
||||
const hours = Math.floor((countDown % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))
|
||||
const minutes = Math.floor((countDown % (1000 * 60 * 60)) / (1000 * 60))
|
||||
const seconds = Math.floor((countDown % (1000 * 60)) / 1000)
|
||||
|
||||
return [days, hours, minutes, seconds]
|
||||
}
|
||||
|
||||
export const useTimeout = (targetDate: Date) => {
|
||||
const countDownDate = new Date(targetDate).getTime()
|
||||
|
||||
const [countDown, setCountDown] = useState<number>(countDownDate - new Date().getTime())
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
setCountDown(countDownDate - new Date().getTime())
|
||||
}, 1000)
|
||||
|
||||
return () => clearInterval(interval)
|
||||
}, [countDownDate])
|
||||
|
||||
return getReturnValues(countDown)
|
||||
}
|
@ -8,6 +8,7 @@ import { BlockNumberProvider } from 'lib/hooks/useBlockNumber'
|
||||
import { MulticallUpdater } from 'lib/state/multicall'
|
||||
import { StrictMode } from 'react'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import { QueryClient, QueryClientProvider } from 'react-query'
|
||||
import { Provider } from 'react-redux'
|
||||
import { HashRouter } from 'react-router-dom'
|
||||
|
||||
@ -25,6 +26,8 @@ import UserUpdater from './state/user/updater'
|
||||
import ThemeProvider, { ThemedGlobalStyle } from './theme'
|
||||
import RadialGradientByChainUpdater from './theme/RadialGradientByChainUpdater'
|
||||
|
||||
const queryClient = new QueryClient()
|
||||
|
||||
if (!!window.ethereum) {
|
||||
window.ethereum.autoRefreshOnNetworkChange = false
|
||||
}
|
||||
@ -49,21 +52,23 @@ createRoot(container).render(
|
||||
<StrictMode>
|
||||
<Provider store={store}>
|
||||
<FeatureFlagsProvider>
|
||||
<HashRouter>
|
||||
<LanguageProvider>
|
||||
<Web3Provider>
|
||||
<Blocklist>
|
||||
<BlockNumberProvider>
|
||||
<Updaters />
|
||||
<ThemeProvider>
|
||||
<ThemedGlobalStyle />
|
||||
<App />
|
||||
</ThemeProvider>
|
||||
</BlockNumberProvider>
|
||||
</Blocklist>
|
||||
</Web3Provider>
|
||||
</LanguageProvider>
|
||||
</HashRouter>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<HashRouter>
|
||||
<LanguageProvider>
|
||||
<Web3Provider>
|
||||
<Blocklist>
|
||||
<BlockNumberProvider>
|
||||
<Updaters />
|
||||
<ThemeProvider>
|
||||
<ThemedGlobalStyle />
|
||||
<App />
|
||||
</ThemeProvider>
|
||||
</BlockNumberProvider>
|
||||
</Blocklist>
|
||||
</Web3Provider>
|
||||
</LanguageProvider>
|
||||
</HashRouter>
|
||||
</QueryClientProvider>
|
||||
</FeatureFlagsProvider>
|
||||
</Provider>
|
||||
</StrictMode>
|
||||
|
@ -141,3 +141,7 @@ export default function useCurrencyBalance(
|
||||
useMemo(() => [currency], [currency])
|
||||
)[0]
|
||||
}
|
||||
|
||||
export function useCurrencyBalanceString(account: string): string {
|
||||
return useNativeCurrencyBalances(account ? [account] : [])?.[account ?? '']?.toSignificant(3) ?? ''
|
||||
}
|
||||
|
886
src/nft/abis/CrossAssetSwap.json
Normal file
886
src/nft/abis/CrossAssetSwap.json
Normal file
@ -0,0 +1,886 @@
|
||||
[
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_marketRegistry",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_converter",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_guardian",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "constructor"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "previousOwner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "newOwner",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "OwnershipTransferred",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "GOV",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_affiliate",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "addAffiliate",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_marketId",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "addSponsoredMarket",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "affiliates",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "affiliate",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "isActive",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "baseFees",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "closeAllTrades",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "converter",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "guardian",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "marketRegistry",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "contract MarketRegistry",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "address[]",
|
||||
"name": "tokenAddrs",
|
||||
"type": "address[]"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256[]",
|
||||
"name": "amounts",
|
||||
"type": "uint256[]"
|
||||
}
|
||||
],
|
||||
"internalType": "struct GenieSwap.ERC20Details",
|
||||
"name": "erc20Details",
|
||||
"type": "tuple"
|
||||
},
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "tokenAddr",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address[]",
|
||||
"name": "to",
|
||||
"type": "address[]"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256[]",
|
||||
"name": "ids",
|
||||
"type": "uint256[]"
|
||||
}
|
||||
],
|
||||
"internalType": "struct SpecialTransferHelper.ERC721Details[]",
|
||||
"name": "erc721Details",
|
||||
"type": "tuple[]"
|
||||
},
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "tokenAddr",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256[]",
|
||||
"name": "ids",
|
||||
"type": "uint256[]"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256[]",
|
||||
"name": "amounts",
|
||||
"type": "uint256[]"
|
||||
}
|
||||
],
|
||||
"internalType": "struct GenieSwap.ERC1155Details[]",
|
||||
"name": "erc1155Details",
|
||||
"type": "tuple[]"
|
||||
},
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "conversionData",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"internalType": "struct GenieSwap.ConverstionDetails[]",
|
||||
"name": "converstionDetails",
|
||||
"type": "tuple[]"
|
||||
},
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "marketId",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "value",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "tradeData",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"internalType": "struct MarketRegistry.TradeDetails[]",
|
||||
"name": "tradeDetails",
|
||||
"type": "tuple[]"
|
||||
},
|
||||
{
|
||||
"internalType": "address[]",
|
||||
"name": "dustTokens",
|
||||
"type": "address[]"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256[2]",
|
||||
"name": "feeDetails",
|
||||
"type": "uint256[2]"
|
||||
}
|
||||
],
|
||||
"name": "multiAssetSwap",
|
||||
"outputs": [],
|
||||
"stateMutability": "payable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "address[]",
|
||||
"name": "tokenAddrs",
|
||||
"type": "address[]"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256[]",
|
||||
"name": "amounts",
|
||||
"type": "uint256[]"
|
||||
}
|
||||
],
|
||||
"internalType": "struct GenieSwap.ERC20Details",
|
||||
"name": "erc20Details",
|
||||
"type": "tuple"
|
||||
},
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "tokenAddr",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address[]",
|
||||
"name": "to",
|
||||
"type": "address[]"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256[]",
|
||||
"name": "ids",
|
||||
"type": "uint256[]"
|
||||
}
|
||||
],
|
||||
"internalType": "struct SpecialTransferHelper.ERC721Details[]",
|
||||
"name": "erc721Details",
|
||||
"type": "tuple[]"
|
||||
},
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "tokenAddr",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256[]",
|
||||
"name": "ids",
|
||||
"type": "uint256[]"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256[]",
|
||||
"name": "amounts",
|
||||
"type": "uint256[]"
|
||||
}
|
||||
],
|
||||
"internalType": "struct GenieSwap.ERC1155Details[]",
|
||||
"name": "erc1155Details",
|
||||
"type": "tuple[]"
|
||||
},
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "conversionData",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"internalType": "struct GenieSwap.ConverstionDetails[]",
|
||||
"name": "converstionDetails",
|
||||
"type": "tuple[]"
|
||||
},
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "marketId",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "value",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "tradeData",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"internalType": "struct MarketRegistry.TradeDetails[]",
|
||||
"name": "tradeDetails",
|
||||
"type": "tuple[]"
|
||||
},
|
||||
{
|
||||
"internalType": "address[]",
|
||||
"name": "dustTokens",
|
||||
"type": "address[]"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "sponsoredMarketIndex",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "multiAssetSwapWithoutFee",
|
||||
"outputs": [],
|
||||
"stateMutability": "payable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256[]",
|
||||
"name": "",
|
||||
"type": "uint256[]"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256[]",
|
||||
"name": "",
|
||||
"type": "uint256[]"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"name": "onERC1155BatchReceived",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bytes4",
|
||||
"name": "",
|
||||
"type": "bytes4"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"name": "onERC1155Received",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bytes4",
|
||||
"name": "",
|
||||
"type": "bytes4"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"name": "onERC721Received",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bytes4",
|
||||
"name": "",
|
||||
"type": "bytes4"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"name": "onERC721Received",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bytes4",
|
||||
"name": "",
|
||||
"type": "bytes4"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "openForFreeTrades",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "openForTrades",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "owner",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "punkProxy",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "renounceOwnership",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "asset",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256[]",
|
||||
"name": "ids",
|
||||
"type": "uint256[]"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256[]",
|
||||
"name": "amounts",
|
||||
"type": "uint256[]"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "rescueERC1155",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "asset",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "rescueERC20",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "asset",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256[]",
|
||||
"name": "ids",
|
||||
"type": "uint256[]"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "rescueERC721",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "rescueETH",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_baseFees",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "setBaseFees",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_converter",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "setConverter",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "contract MarketRegistry",
|
||||
"name": "_marketRegistry",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "setMarketRegistry",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "contract IERC20",
|
||||
"name": "token",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "operator",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "setOneTimeApproval",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "_openForFreeTrades",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"name": "setOpenForFreeTrades",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "_openForTrades",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"name": "setOpenForTrades",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "setUp",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "sponsoredMarkets",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "marketId",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "isActive",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "bytes4",
|
||||
"name": "interfaceId",
|
||||
"type": "bytes4"
|
||||
}
|
||||
],
|
||||
"name": "supportsInterface",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "newOwner",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "transferOwnership",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_affiliateIndex",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_affiliate",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "_IsActive",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"name": "updateAffiliate",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_guardian",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "updateGuardian",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_marketIndex",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_marketId",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "_isActive",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"name": "updateSponsoredMarket",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"stateMutability": "payable",
|
||||
"type": "receive"
|
||||
}
|
||||
]
|
595
src/nft/abis/CryptoPunksMarket.json
Normal file
595
src/nft/abis/CryptoPunksMarket.json
Normal file
@ -0,0 +1,595 @@
|
||||
[
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "name",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "punksOfferedForSale",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "isForSale",
|
||||
"type": "bool"
|
||||
},
|
||||
{
|
||||
"name": "punkIndex",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "seller",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "minValue",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "onlySellTo",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "punkIndex",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "enterBidForPunk",
|
||||
"outputs": [],
|
||||
"payable": true,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "totalSupply",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "punkIndex",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "minPrice",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "acceptBidForPunk",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "decimals",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint8"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "addresses",
|
||||
"type": "address[]"
|
||||
},
|
||||
{
|
||||
"name": "indices",
|
||||
"type": "uint256[]"
|
||||
}
|
||||
],
|
||||
"name": "setInitialOwners",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [],
|
||||
"name": "withdraw",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "imageHash",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "nextPunkIndexToAssign",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "punkIndexToAddress",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "standard",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "punkBids",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "hasBid",
|
||||
"type": "bool"
|
||||
},
|
||||
{
|
||||
"name": "punkIndex",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "bidder",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "balanceOf",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [],
|
||||
"name": "allInitialOwnersAssigned",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "allPunksAssigned",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "punkIndex",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "buyPunk",
|
||||
"outputs": [],
|
||||
"payable": true,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "punkIndex",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "transferPunk",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "symbol",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "punkIndex",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "withdrawBidForPunk",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"name": "punkIndex",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "setInitialOwner",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "punkIndex",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "minSalePriceInWei",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "toAddress",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "offerPunkForSaleToAddress",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "punksRemainingToAssign",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "punkIndex",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"name": "minSalePriceInWei",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "offerPunkForSale",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "punkIndex",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "getPunk",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "pendingWithdrawals",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "punkIndex",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "punkNoLongerForSale",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"payable": true,
|
||||
"type": "constructor"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "punkIndex",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "Assign",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"name": "from",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "Transfer",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"name": "from",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "punkIndex",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "PunkTransfer",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"name": "punkIndex",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "minValue",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"name": "toAddress",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "PunkOffered",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"name": "punkIndex",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "value",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"name": "fromAddress",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "PunkBidEntered",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"name": "punkIndex",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "value",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"name": "fromAddress",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "PunkBidWithdrawn",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"name": "punkIndex",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"name": "value",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"name": "fromAddress",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"name": "toAddress",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "PunkBought",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"name": "punkIndex",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "PunkNoLongerForSale",
|
||||
"type": "event"
|
||||
}
|
||||
]
|
153
src/nft/abis/WyvernProxyRegistry.json
Normal file
153
src/nft/abis/WyvernProxyRegistry.json
Normal file
@ -0,0 +1,153 @@
|
||||
[
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "name",
|
||||
"outputs": [{ "name": "", "type": "string" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "initialAddressSet",
|
||||
"outputs": [{ "name": "", "type": "bool" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [{ "name": "addr", "type": "address" }],
|
||||
"name": "endGrantAuthentication",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [{ "name": "addr", "type": "address" }],
|
||||
"name": "revokeAuthentication",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [{ "name": "", "type": "address" }],
|
||||
"name": "pending",
|
||||
"outputs": [{ "name": "", "type": "uint256" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [{ "name": "", "type": "address" }],
|
||||
"name": "contracts",
|
||||
"outputs": [{ "name": "", "type": "bool" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [],
|
||||
"name": "renounceOwnership",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "owner",
|
||||
"outputs": [{ "name": "", "type": "address" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "delegateProxyImplementation",
|
||||
"outputs": [{ "name": "", "type": "address" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [{ "name": "", "type": "address" }],
|
||||
"name": "proxies",
|
||||
"outputs": [{ "name": "", "type": "address" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [{ "name": "addr", "type": "address" }],
|
||||
"name": "startGrantAuthentication",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [],
|
||||
"name": "registerProxy",
|
||||
"outputs": [{ "name": "proxy", "type": "address" }],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "DELAY_PERIOD",
|
||||
"outputs": [{ "name": "", "type": "uint256" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [{ "name": "authAddress", "type": "address" }],
|
||||
"name": "grantInitialAuthentication",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [{ "name": "newOwner", "type": "address" }],
|
||||
"name": "transferOwnership",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{ "inputs": [], "payable": false, "stateMutability": "nonpayable", "type": "constructor" },
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [{ "indexed": true, "name": "previousOwner", "type": "address" }],
|
||||
"name": "OwnershipRenounced",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{ "indexed": true, "name": "previousOwner", "type": "address" },
|
||||
{ "indexed": true, "name": "newOwner", "type": "address" }
|
||||
],
|
||||
"name": "OwnershipTransferred",
|
||||
"type": "event"
|
||||
}
|
||||
]
|
19
src/nft/css/atoms.ts
Normal file
19
src/nft/css/atoms.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import clsx from 'clsx'
|
||||
|
||||
import * as resetStyles from './reset.css'
|
||||
import { Sprinkles, sprinkles } from './sprinkles.css'
|
||||
|
||||
export interface Atoms extends Sprinkles {
|
||||
// reset is used by the Box component when its expected to behave as something other than a div, ie button, a, or span
|
||||
reset?: keyof JSX.IntrinsicElements
|
||||
}
|
||||
|
||||
export const atoms = ({ reset, ...rest }: Atoms) => {
|
||||
if (!reset) return sprinkles(rest)
|
||||
|
||||
const elementReset = resetStyles.element[reset as keyof typeof resetStyles.element]
|
||||
|
||||
const sprinklesClasses = sprinkles(rest)
|
||||
|
||||
return clsx(resetStyles.base, elementReset, sprinklesClasses)
|
||||
}
|
119
src/nft/css/common.css.ts
Normal file
119
src/nft/css/common.css.ts
Normal file
@ -0,0 +1,119 @@
|
||||
import { style } from '@vanilla-extract/css'
|
||||
|
||||
import { sprinkles, themeVars } from './sprinkles.css'
|
||||
|
||||
export const center = sprinkles({
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
})
|
||||
|
||||
export const row = sprinkles({
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
})
|
||||
|
||||
export const column = sprinkles({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
})
|
||||
|
||||
export const section = style([
|
||||
sprinkles({
|
||||
paddingLeft: { mobile: '16', desktopL: '0' },
|
||||
paddingRight: { mobile: '16', desktopL: '0' },
|
||||
}),
|
||||
{ maxWidth: '1000px', margin: '0 auto' },
|
||||
])
|
||||
|
||||
// TYPOGRAPHY
|
||||
export const header1 = sprinkles({ fontWeight: 'normal', fontSize: '36' })
|
||||
export const header2 = sprinkles({ fontWeight: 'normal', fontSize: '28' })
|
||||
export const headlineSmall = sprinkles({ fontWeight: 'normal', fontSize: '20' })
|
||||
export const subhead = sprinkles({ fontWeight: 'medium', fontSize: '16' })
|
||||
export const subheadSmall = sprinkles({ fontWeight: 'medium', fontSize: '14' })
|
||||
export const body = sprinkles({ fontSize: '16' })
|
||||
export const bodySmall = sprinkles({
|
||||
fontSize: '14',
|
||||
})
|
||||
export const caption = sprinkles({ fontWeight: 'bold', fontSize: '12' })
|
||||
export const badge = style([sprinkles({ fontWeight: 'semibold', fontSize: '10' }), { letterSpacing: '0.5px' }])
|
||||
export const buttonTextLarge = sprinkles({ fontWeight: 'medium', fontSize: '28' })
|
||||
|
||||
export const buttonTextMedium = sprinkles({ fontWeight: 'medium', fontSize: '16' })
|
||||
export const buttonMedium = style([
|
||||
buttonTextMedium,
|
||||
sprinkles({
|
||||
backgroundColor: 'blue',
|
||||
borderRadius: '12',
|
||||
color: 'explicitWhite',
|
||||
transition: '250',
|
||||
boxShadow: { hover: 'elevation' },
|
||||
}),
|
||||
{
|
||||
cursor: 'pointer',
|
||||
padding: '14px 18px',
|
||||
border: 'none',
|
||||
':hover': {
|
||||
cursor: 'pointer',
|
||||
},
|
||||
':disabled': {
|
||||
cursor: 'auto',
|
||||
opacity: '0.3',
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
export const buttonReset = sprinkles({
|
||||
border: 'none',
|
||||
background: 'none',
|
||||
cursor: 'pointer',
|
||||
})
|
||||
|
||||
export const disabled = style([
|
||||
{
|
||||
padding: '19px 17px',
|
||||
boxSizing: 'border-box',
|
||||
textAlign: 'left',
|
||||
},
|
||||
sprinkles({
|
||||
color: 'placeholder',
|
||||
fontWeight: 'medium',
|
||||
background: 'whitesmoke',
|
||||
borderRadius: '14',
|
||||
borderStyle: 'none',
|
||||
width: 'full',
|
||||
fontSize: '16',
|
||||
}),
|
||||
])
|
||||
|
||||
export const buttonTextSmall = sprinkles({ fontWeight: 'normal', fontSize: '14' })
|
||||
export const buttonSmall = style([
|
||||
buttonTextSmall,
|
||||
sprinkles({
|
||||
background: 'lightGray',
|
||||
borderRadius: '12',
|
||||
fontSize: '12',
|
||||
color: 'genieBlue',
|
||||
transition: '250',
|
||||
boxShadow: { hover: 'elevation' },
|
||||
}),
|
||||
{
|
||||
padding: '2px 8px',
|
||||
border: 'none',
|
||||
':hover': {
|
||||
cursor: 'pointer',
|
||||
},
|
||||
':disabled': {
|
||||
cursor: 'auto',
|
||||
color: themeVars.colors.white,
|
||||
backgroundColor: themeVars.colors.medGray,
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
export const imageHover = style({
|
||||
transform: 'scale(1.25)',
|
||||
})
|
26
src/nft/css/cssObjectFromTheme.ts
Normal file
26
src/nft/css/cssObjectFromTheme.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { assignInlineVars } from '@vanilla-extract/dynamic'
|
||||
|
||||
import { Theme, themeVars } from './sprinkles.css'
|
||||
|
||||
const resolveTheme = (theme: Theme | (() => Theme)) => (typeof theme === 'function' ? theme() : theme)
|
||||
|
||||
export function cssObjectFromTheme(
|
||||
theme: Theme | (() => Theme),
|
||||
{ extends: baseTheme }: { extends?: Theme | (() => Theme) } = {}
|
||||
) {
|
||||
const resolvedThemeVars = {
|
||||
...assignInlineVars(themeVars, resolveTheme(theme)),
|
||||
}
|
||||
|
||||
if (!baseTheme) {
|
||||
return resolvedThemeVars
|
||||
}
|
||||
|
||||
const resolvedBaseThemeVars = assignInlineVars(themeVars, resolveTheme(baseTheme))
|
||||
|
||||
const filteredVars = Object.fromEntries(
|
||||
Object.entries(resolvedThemeVars).filter(([varName, value]) => value !== resolvedBaseThemeVars[varName])
|
||||
)
|
||||
|
||||
return filteredVars
|
||||
}
|
8
src/nft/css/cssStringFromTheme.ts
Normal file
8
src/nft/css/cssStringFromTheme.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { cssObjectFromTheme } from './cssObjectFromTheme'
|
||||
import { Theme } from './sprinkles.css'
|
||||
|
||||
export function cssStringFromTheme(theme: Theme | (() => Theme), options: { extends?: Theme | (() => Theme) } = {}) {
|
||||
return Object.entries(cssObjectFromTheme(theme, options))
|
||||
.map(([key, value]) => `${key}:${value};`)
|
||||
.join('')
|
||||
}
|
21
src/nft/css/loading.css.ts
Normal file
21
src/nft/css/loading.css.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { keyframes, style } from '@vanilla-extract/css'
|
||||
import { darken } from 'polished'
|
||||
|
||||
export const loadingAnimation = keyframes({
|
||||
'0%': {
|
||||
backgroundPosition: '100% 50%',
|
||||
},
|
||||
'100%': {
|
||||
backgroundPosition: '0% 50%',
|
||||
},
|
||||
})
|
||||
|
||||
export const loadingBlock = style([
|
||||
{
|
||||
animation: `${loadingAnimation} 1.5s infinite`,
|
||||
animationFillMode: 'both',
|
||||
background: `linear-gradient(to left, #7C85A24D 25%, ${darken(0.8, '#7C85A24D')} 50%, #7C85A24D 75%)`,
|
||||
backgroundSize: '400%',
|
||||
willChange: 'background-position',
|
||||
},
|
||||
])
|
106
src/nft/css/reset.css.ts
Normal file
106
src/nft/css/reset.css.ts
Normal file
@ -0,0 +1,106 @@
|
||||
import 'focus-visible'
|
||||
|
||||
import { style } from '@vanilla-extract/css'
|
||||
|
||||
const hideFocusRingsDataAttribute = '[data-js-focus-visible] &:focus:not([data-focus-visible-added])'
|
||||
|
||||
export const base = style({
|
||||
boxSizing: 'border-box',
|
||||
selectors: {
|
||||
[`${hideFocusRingsDataAttribute}`]: {
|
||||
outline: 'none',
|
||||
},
|
||||
},
|
||||
verticalAlign: 'baseline',
|
||||
WebkitTapHighlightColor: 'transparent',
|
||||
})
|
||||
|
||||
const list = style({
|
||||
listStyle: 'none',
|
||||
})
|
||||
|
||||
const quote = style({
|
||||
quotes: 'none',
|
||||
selectors: {
|
||||
'&:before, &:after': {
|
||||
content: "''",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const table = style({
|
||||
borderCollapse: 'collapse',
|
||||
borderSpacing: 0,
|
||||
})
|
||||
|
||||
const appearance = style({
|
||||
appearance: 'none',
|
||||
})
|
||||
|
||||
const field = style([
|
||||
appearance,
|
||||
{
|
||||
'::placeholder': {
|
||||
opacity: 1,
|
||||
},
|
||||
outline: 'none',
|
||||
},
|
||||
])
|
||||
|
||||
const mark = style({
|
||||
backgroundColor: 'transparent',
|
||||
color: 'inherit',
|
||||
})
|
||||
|
||||
const select = style([
|
||||
field,
|
||||
{
|
||||
':disabled': {
|
||||
opacity: 1,
|
||||
},
|
||||
selectors: {
|
||||
'&::-ms-expand': {
|
||||
display: 'none',
|
||||
},
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const input = style([
|
||||
field,
|
||||
{
|
||||
selectors: {
|
||||
'&::-ms-clear': {
|
||||
display: 'none',
|
||||
},
|
||||
'&::-webkit-search-cancel-button': {
|
||||
WebkitAppearance: 'none',
|
||||
},
|
||||
'&::-webkit-inner-spin-button, &::-webkit-inner-spin-button ': {
|
||||
WebkitAppearance: 'none',
|
||||
},
|
||||
},
|
||||
WebkitAppearance: 'none',
|
||||
MozAppearance: 'textfield',
|
||||
':focus': {
|
||||
outline: 'none',
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
const a = style({
|
||||
textDecoration: 'none',
|
||||
})
|
||||
|
||||
export const element = {
|
||||
a,
|
||||
blockquote: quote,
|
||||
input,
|
||||
mark,
|
||||
ol: list,
|
||||
q: quote,
|
||||
select,
|
||||
table,
|
||||
textarea: field,
|
||||
ul: list,
|
||||
}
|
366
src/nft/css/sprinkles.css.ts
Normal file
366
src/nft/css/sprinkles.css.ts
Normal file
@ -0,0 +1,366 @@
|
||||
import { createGlobalTheme } from '@vanilla-extract/css'
|
||||
import { createGlobalThemeContract } from '@vanilla-extract/css'
|
||||
import { createSprinkles, defineProperties } from '@vanilla-extract/sprinkles'
|
||||
|
||||
const themeContractValues = {
|
||||
colors: {
|
||||
// Pavel's colors, mostly used for the wallet connection. TODO Some may need to be changed / removed
|
||||
error: '',
|
||||
textDisconnect: '',
|
||||
modalBackdrop: '',
|
||||
backgroundSecondary: '',
|
||||
modalClose: '',
|
||||
text: '',
|
||||
modalTextSecondary: '',
|
||||
|
||||
// Bryan's colors from Figma that vary dark vs light
|
||||
blackBlue: '',
|
||||
darkGray: '',
|
||||
medGray: '',
|
||||
lightGray: '',
|
||||
white: '',
|
||||
darkGray10: '',
|
||||
blackBlue20: '',
|
||||
explicitWhite: '',
|
||||
magicGradient: '',
|
||||
placeholder: '',
|
||||
lightGrayButton: '',
|
||||
lightGrayContainer: ',',
|
||||
lightGrayOverlay: '',
|
||||
|
||||
// Opacities of black and whit
|
||||
white95: '',
|
||||
white90: '',
|
||||
white80: '',
|
||||
},
|
||||
|
||||
shadows: {
|
||||
menu: '',
|
||||
genieBlue: '',
|
||||
elevation: '',
|
||||
tooltip: '',
|
||||
},
|
||||
}
|
||||
|
||||
export type Theme = typeof themeContractValues
|
||||
|
||||
type DeepPartial<T> = {
|
||||
[P in keyof T]?: DeepPartial<T[P]>
|
||||
}
|
||||
export type ThemePartial = DeepPartial<Theme>
|
||||
|
||||
export const themeVars = createGlobalThemeContract(themeContractValues, (_, path) => `genie-${path.join('-')}`)
|
||||
|
||||
const dimensions = {
|
||||
'0': '0',
|
||||
'2': '2',
|
||||
'4': '4px',
|
||||
'8': '8px',
|
||||
'16': '16px',
|
||||
'18': '18px',
|
||||
'20': '20px',
|
||||
'24': '24px',
|
||||
'26': '26px',
|
||||
'28': '28px',
|
||||
'32': '32px',
|
||||
'36': '36px',
|
||||
'40': '40px',
|
||||
'42': '42px',
|
||||
'44': '44px',
|
||||
'48': '48px',
|
||||
'52': '52px',
|
||||
'54': '54px',
|
||||
'56': '56px',
|
||||
'60': '60px',
|
||||
'64': '64px',
|
||||
'72': '72px',
|
||||
'100': '100px',
|
||||
'120': '120px',
|
||||
'160': '160px',
|
||||
'276': '276px',
|
||||
'288': '288px',
|
||||
'292': '292px',
|
||||
'386': '386px',
|
||||
half: '50%',
|
||||
full: '100%',
|
||||
min: 'min-content',
|
||||
max: 'max-content',
|
||||
viewHeight: '100vh',
|
||||
viewWidth: '100vw',
|
||||
auto: 'auto',
|
||||
inherit: 'inherit',
|
||||
}
|
||||
|
||||
const spacing = {
|
||||
'0': '0',
|
||||
'1': '1px',
|
||||
'2': '2px',
|
||||
'4': '4px',
|
||||
'6': '6px',
|
||||
'8': '8px',
|
||||
'10': '10px',
|
||||
'12': '12px',
|
||||
'14': '14px',
|
||||
'16': '16px',
|
||||
'18': '18px',
|
||||
'20': '20px',
|
||||
'24': '24px',
|
||||
'28': '28px',
|
||||
'32': '32px',
|
||||
'36': '36px',
|
||||
'40': '40px',
|
||||
'48': '48px',
|
||||
'50': '50px',
|
||||
'52': '52px',
|
||||
'60': '60px',
|
||||
'64': '64px',
|
||||
'82': '82px',
|
||||
'72': '72px',
|
||||
'88': '88px',
|
||||
'100': '100px',
|
||||
'104': '104px',
|
||||
'136': '136px',
|
||||
'150': '150px',
|
||||
'1/2': '50%',
|
||||
auto: 'auto',
|
||||
unset: 'unset',
|
||||
}
|
||||
|
||||
export const vars = createGlobalTheme(':root', {
|
||||
color: {
|
||||
...themeVars.colors,
|
||||
genieBlue: '#4C82FB',
|
||||
fallbackGradient: 'linear-gradient(270deg, #D1D5DB 0%, #F6F6F6 100%)',
|
||||
dropShadow: '0px 4px 16px rgba(70, 115, 250, 0.4)',
|
||||
green: '#209853',
|
||||
orange: '#FA2C38',
|
||||
// Pavel's colors, TODO probably remove them after Pavel continues Genie List
|
||||
black: 'black',
|
||||
whitesmoke: '#F5F5F5',
|
||||
blue: '#4C82FB',
|
||||
explicitBlackBlue: '#0E111A',
|
||||
gray: '#CBCEDC',
|
||||
transculent: '#7F7F7F',
|
||||
transparent: 'transparent',
|
||||
none: 'none',
|
||||
|
||||
// new uniswap colors:
|
||||
blue400: '#4C82FB',
|
||||
pink400: '#FB118E',
|
||||
red700: '#530f10',
|
||||
red400: '#FA2C38',
|
||||
green200: '#5CFE9D',
|
||||
green400: '#1A9550',
|
||||
grey900: '#0E111A',
|
||||
grey700: '#293249',
|
||||
grey500: '#5E6887',
|
||||
grey400: '#7C85A2',
|
||||
grey300: '#99A1BD',
|
||||
grey200: '#B7BED4',
|
||||
grey100: '#DDE3F7',
|
||||
grey50: '#EDEFF7',
|
||||
},
|
||||
border: {
|
||||
transculent: '1.5px solid rgba(0, 0, 0, 0.1)',
|
||||
none: 'none',
|
||||
},
|
||||
radii: {
|
||||
menu: '16px',
|
||||
modal: '24px',
|
||||
'0': '0px',
|
||||
'4': '4px',
|
||||
'8': '8px',
|
||||
'10': '10px',
|
||||
'12': '12px',
|
||||
'14': '14px',
|
||||
'16': '16px',
|
||||
'20': '20px',
|
||||
'30': '30px',
|
||||
'40': '40px',
|
||||
'100': '100px',
|
||||
round: '9999px',
|
||||
},
|
||||
fontSize: {
|
||||
'0': '0',
|
||||
'10': '10px',
|
||||
'12': '12px',
|
||||
'14': '14px',
|
||||
'16': '16px',
|
||||
'20': '20px',
|
||||
'24': '24px',
|
||||
'28': '28px',
|
||||
'34': '34px',
|
||||
'36': '36px',
|
||||
'40': '40px',
|
||||
'48': '48px',
|
||||
'60': '60px',
|
||||
'96': '96px',
|
||||
},
|
||||
fontWeight: {
|
||||
normal: '400',
|
||||
medium: '500',
|
||||
semibold: '600',
|
||||
bold: '700',
|
||||
black: '900',
|
||||
},
|
||||
time: {
|
||||
'250': '250ms',
|
||||
'500': '500ms',
|
||||
},
|
||||
fonts: {
|
||||
body: 'Inter, sans-serif',
|
||||
heading: 'Adieu, sans-serif',
|
||||
},
|
||||
})
|
||||
|
||||
const flexAlignment = [
|
||||
'flex-start',
|
||||
'center',
|
||||
'flex-end',
|
||||
'stretch',
|
||||
'baseline',
|
||||
'space-around',
|
||||
'space-between',
|
||||
] as const
|
||||
|
||||
const overflow = ['hidden', 'inherit', 'scroll', 'visible', 'auto'] as const
|
||||
|
||||
const borderWidth = ['1px', '1.5px', '2px', '4px']
|
||||
|
||||
const borderStyle = ['none', 'solid'] as const
|
||||
|
||||
export const breakpoints = {
|
||||
tabletSm: 656,
|
||||
tablet: 708,
|
||||
tabletL: 784,
|
||||
tabletXl: 830,
|
||||
desktop: 948,
|
||||
desktopL: 1030,
|
||||
desktopXl: 1260,
|
||||
}
|
||||
|
||||
const layoutStyles = defineProperties({
|
||||
conditions: {
|
||||
mobile: {},
|
||||
tabletSm: { '@media': `screen and (min-width: ${breakpoints.tabletSm}px)` },
|
||||
tablet: { '@media': `screen and (min-width: ${breakpoints.tablet})` },
|
||||
tabletL: { '@media': `screen and (min-width: ${breakpoints.tabletL}px)` },
|
||||
tabletXl: { '@media': `screen and (min-width: ${breakpoints.tabletXl}px)` },
|
||||
desktop: { '@media': `screen and (min-width: ${breakpoints.desktop}px)` },
|
||||
desktopL: { '@media': `screen and (min-width: ${breakpoints.desktopL}px)` },
|
||||
desktopXl: { '@media': `screen and (min-width: ${breakpoints.desktopXl}px)` },
|
||||
},
|
||||
defaultCondition: 'mobile',
|
||||
properties: {
|
||||
alignItems: flexAlignment,
|
||||
alignSelf: flexAlignment,
|
||||
justifyItems: flexAlignment,
|
||||
justifySelf: flexAlignment,
|
||||
placeItems: flexAlignment,
|
||||
placeContent: flexAlignment,
|
||||
fontSize: vars.fontSize,
|
||||
fontWeight: vars.fontWeight,
|
||||
marginBottom: spacing,
|
||||
marginLeft: spacing,
|
||||
marginRight: spacing,
|
||||
marginTop: spacing,
|
||||
width: dimensions,
|
||||
height: dimensions,
|
||||
maxWidth: dimensions,
|
||||
minWidth: dimensions,
|
||||
maxHeight: dimensions,
|
||||
minHeight: dimensions,
|
||||
paddingBottom: spacing,
|
||||
paddingLeft: spacing,
|
||||
paddingRight: spacing,
|
||||
paddingTop: spacing,
|
||||
padding: spacing,
|
||||
bottom: spacing,
|
||||
left: spacing,
|
||||
right: spacing,
|
||||
top: spacing,
|
||||
margin: spacing,
|
||||
zIndex: ['auto', '0', '1', '2', '3'],
|
||||
gap: spacing,
|
||||
flexShrink: spacing,
|
||||
flex: ['1', '2', '3'],
|
||||
flexWrap: ['nowrap', 'wrap', 'wrap-reverse'],
|
||||
display: ['none', 'block', 'flex', 'inline-flex', 'inline-block', 'grid', 'inline'],
|
||||
whiteSpace: ['nowrap'],
|
||||
textOverflow: ['ellipsis'],
|
||||
textAlign: ['left', 'right', 'center', 'justify'],
|
||||
visibility: ['visible', 'hidden'],
|
||||
flexDirection: ['row', 'column', 'column-reverse'],
|
||||
justifyContent: flexAlignment,
|
||||
position: ['absolute', 'fixed', 'relative', 'sticky', 'static'],
|
||||
objectFit: ['contain', 'cover'],
|
||||
order: [0, 1],
|
||||
} as const,
|
||||
shorthands: {
|
||||
paddingX: ['paddingLeft', 'paddingRight'],
|
||||
paddingY: ['paddingTop', 'paddingBottom'],
|
||||
marginX: ['marginLeft', 'marginRight'],
|
||||
marginY: ['marginTop', 'marginBottom'],
|
||||
},
|
||||
})
|
||||
|
||||
const colorStyles = defineProperties({
|
||||
conditions: {
|
||||
default: {},
|
||||
hover: { selector: '&:hover' },
|
||||
active: { selector: '&:active' },
|
||||
focus: { selector: '&:focus' },
|
||||
before: { selector: '&:before' },
|
||||
placeholder: { selector: '&::placeholder' },
|
||||
},
|
||||
defaultCondition: 'default',
|
||||
properties: {
|
||||
color: vars.color,
|
||||
background: vars.color,
|
||||
borderColor: vars.color,
|
||||
borderBottomColor: vars.color,
|
||||
borderTopColor: vars.color,
|
||||
backgroundColor: vars.color,
|
||||
outlineColor: vars.color,
|
||||
fill: vars.color,
|
||||
},
|
||||
})
|
||||
|
||||
const unresponsiveProperties = defineProperties({
|
||||
conditions: {
|
||||
default: {},
|
||||
hover: { selector: '&:hover' },
|
||||
active: { selector: '&:active' },
|
||||
before: { selector: '&:before' },
|
||||
},
|
||||
defaultCondition: 'default',
|
||||
properties: {
|
||||
cursor: ['default', 'pointer', 'auto'],
|
||||
borderStyle,
|
||||
borderBottomStyle: borderStyle,
|
||||
borderRadius: vars.radii,
|
||||
borderTopLeftRadius: vars.radii,
|
||||
borderTopRightRadius: vars.radii,
|
||||
borderBottomLeftRadius: vars.radii,
|
||||
borderBottomRightRadius: vars.radii,
|
||||
border: vars.border,
|
||||
borderBottom: vars.border,
|
||||
borderTop: vars.border,
|
||||
borderWidth,
|
||||
borderBottomWidth: borderWidth,
|
||||
fontFamily: vars.fonts,
|
||||
overflow,
|
||||
overflowX: overflow,
|
||||
overflowY: overflow,
|
||||
boxShadow: { ...themeVars.shadows, none: 'none', dropShadow: vars.color.dropShadow },
|
||||
lineHeight: ['1', 'auto'],
|
||||
transition: vars.time,
|
||||
transitionDuration: vars.time,
|
||||
animationDuration: vars.time,
|
||||
},
|
||||
})
|
||||
|
||||
export type UnresponsiveProperties = keyof typeof unresponsiveProperties
|
||||
|
||||
export const sprinkles = createSprinkles(layoutStyles, colorStyles, unresponsiveProperties)
|
||||
export type Sprinkles = Parameters<typeof sprinkles>[0]
|
14
src/nft/hooks/index.ts
Normal file
14
src/nft/hooks/index.ts
Normal file
@ -0,0 +1,14 @@
|
||||
export * from './useCart'
|
||||
export * from './useCollectionFilters'
|
||||
export * from './useFiltersExpanded'
|
||||
export * from './useGenieList'
|
||||
export * from './useIsMobile'
|
||||
export * from './useMarketplaceSelect'
|
||||
export * from './useNFTSelect'
|
||||
export * from './useSearchHistory'
|
||||
export * from './useSelectAsset'
|
||||
export * from './useSellAsset'
|
||||
export * from './useSellPageState'
|
||||
export * from './useSweep'
|
||||
export * from './useWalletBalance'
|
||||
export * from './useWalletCollections'
|
20
src/nft/hooks/useCart.ts
Normal file
20
src/nft/hooks/useCart.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import create from 'zustand'
|
||||
import { devtools } from 'zustand/middleware'
|
||||
|
||||
interface CartState {
|
||||
cartExpanded: boolean
|
||||
toggleCart: () => void
|
||||
}
|
||||
|
||||
export const useCart = create<CartState>()(
|
||||
devtools(
|
||||
(set) => ({
|
||||
cartExpanded: false,
|
||||
toggleCart: () =>
|
||||
set(({ cartExpanded }) => ({
|
||||
cartExpanded: !cartExpanded,
|
||||
})),
|
||||
}),
|
||||
{ name: 'useCart' }
|
||||
)
|
||||
)
|
97
src/nft/hooks/useCollectionFilters.ts
Normal file
97
src/nft/hooks/useCollectionFilters.ts
Normal file
@ -0,0 +1,97 @@
|
||||
import create from 'zustand'
|
||||
import { devtools } from 'zustand/middleware'
|
||||
|
||||
export enum SortBy {
|
||||
LowToHigh,
|
||||
HighToLow,
|
||||
RareToCommon,
|
||||
CommonToRare,
|
||||
}
|
||||
|
||||
export const SortByPointers = {
|
||||
[SortBy.HighToLow]: 'highest',
|
||||
[SortBy.LowToHigh]: 'lowest',
|
||||
[SortBy.RareToCommon]: 'rare',
|
||||
[SortBy.CommonToRare]: 'common',
|
||||
}
|
||||
|
||||
export type Trait = {
|
||||
trait_type: string
|
||||
trait_value: string
|
||||
trait_count: number
|
||||
floorPrice?: number
|
||||
}
|
||||
|
||||
interface State {
|
||||
traits: Trait[]
|
||||
markets: string[]
|
||||
minPrice: number | ''
|
||||
maxPrice: number | ''
|
||||
minRarity: number | ''
|
||||
maxRarity: number | ''
|
||||
marketCount: Record<string, number>
|
||||
buyNow: boolean
|
||||
search: string
|
||||
sortBy: SortBy
|
||||
showFullTraitName: { shouldShow: boolean; trait_value?: string; trait_type: string }
|
||||
}
|
||||
|
||||
type Actions = {
|
||||
setMarketCount: (_: Record<string, number>) => void
|
||||
addMarket: (market: string) => void
|
||||
removeMarket: (market: string) => void
|
||||
addTrait: (trait: Trait) => void
|
||||
removeTrait: (trait: Trait) => void
|
||||
reset: () => void
|
||||
setMinPrice: (price: number | '') => void
|
||||
setMaxPrice: (price: number | '') => void
|
||||
setMinRarity: (range: number | '') => void
|
||||
setMaxRarity: (range: number | '') => void
|
||||
setBuyNow: (bool: boolean) => void
|
||||
setSearch: (term: string) => void
|
||||
setSortBy: (sortBy: SortBy) => void
|
||||
toggleShowFullTraitName: (show: { shouldShow: boolean; trait_value: string; trait_type: string }) => void
|
||||
}
|
||||
|
||||
export type CollectionFilters = State & Actions
|
||||
|
||||
export const initialCollectionFilterState: State = {
|
||||
minPrice: '',
|
||||
maxPrice: '',
|
||||
minRarity: '',
|
||||
maxRarity: '',
|
||||
traits: [],
|
||||
markets: [],
|
||||
marketCount: {},
|
||||
buyNow: true,
|
||||
search: '',
|
||||
sortBy: SortBy.LowToHigh,
|
||||
showFullTraitName: { shouldShow: false, trait_value: '', trait_type: '' },
|
||||
}
|
||||
|
||||
export const useCollectionFilters = create<CollectionFilters>()(
|
||||
devtools(
|
||||
(set) => ({
|
||||
...initialCollectionFilterState,
|
||||
setSortBy: (sortBy) => set({ sortBy }),
|
||||
setSearch: (search) => set({ search }),
|
||||
setBuyNow: (buyNow) => set({ buyNow }),
|
||||
setMarketCount: (marketCount) => set({ marketCount }),
|
||||
addMarket: (market) => set(({ markets }) => ({ markets: [...markets, market] })),
|
||||
removeMarket: (market) => set(({ markets }) => ({ markets: markets.filter((_market) => market !== _market) })),
|
||||
addTrait: (trait) => set(({ traits }) => ({ traits: [...traits, trait] })),
|
||||
removeTrait: (trait) =>
|
||||
set(({ traits }) => ({
|
||||
traits: traits.filter((x) => JSON.stringify(x) !== JSON.stringify(trait)),
|
||||
})),
|
||||
reset: () => set(() => ({ traits: [], minRarity: '', maxRarity: '', markets: [] })),
|
||||
setMinPrice: (price) => set(() => ({ minPrice: price })),
|
||||
setMaxPrice: (price) => set(() => ({ maxPrice: price })),
|
||||
setMinRarity: (range) => set(() => ({ minRarity: range })),
|
||||
setMaxRarity: (range) => set(() => ({ maxRarity: range })),
|
||||
toggleShowFullTraitName: ({ shouldShow, trait_value, trait_type }) =>
|
||||
set(() => ({ showFullTraitName: { shouldShow, trait_value, trait_type } })),
|
||||
}),
|
||||
{ name: 'useCollectionTraits' }
|
||||
)
|
||||
)
|
30
src/nft/hooks/useFiltersExpanded.ts
Normal file
30
src/nft/hooks/useFiltersExpanded.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import create from 'zustand'
|
||||
import { devtools, persist } from 'zustand/middleware'
|
||||
|
||||
interface State {
|
||||
isExpanded: boolean
|
||||
setExpanded: (expanded: boolean) => void
|
||||
}
|
||||
|
||||
const useFiltersExpandedStore = create<State>()(
|
||||
persist(
|
||||
devtools(
|
||||
(set) => ({
|
||||
isExpanded: false,
|
||||
setExpanded: (expanded) =>
|
||||
set(() => ({
|
||||
isExpanded: expanded,
|
||||
})),
|
||||
}),
|
||||
{ name: 'useFiltersExpanded' }
|
||||
),
|
||||
{ name: 'useFiltersExpanded' }
|
||||
)
|
||||
)
|
||||
|
||||
export const useFiltersExpanded = (): [boolean, (expanded: boolean) => void] => {
|
||||
const isExpanded = useFiltersExpandedStore((s) => s.isExpanded)
|
||||
const setExpanded = useFiltersExpandedStore((s) => s.setExpanded)
|
||||
|
||||
return [isExpanded, setExpanded]
|
||||
}
|
21
src/nft/hooks/useGenieList.ts
Normal file
21
src/nft/hooks/useGenieList.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import create from 'zustand'
|
||||
import { devtools } from 'zustand/middleware'
|
||||
|
||||
interface GenieListState {
|
||||
looksRareNonce: number
|
||||
setLooksRareNonce: (nonce: number) => void
|
||||
getLooksRareNonce: () => number
|
||||
}
|
||||
|
||||
export const useGenieList = create<GenieListState>()(
|
||||
devtools((set, get) => ({
|
||||
looksRareNonce: 0,
|
||||
setLooksRareNonce: (nonce) =>
|
||||
set(() => {
|
||||
return { looksRareNonce: nonce }
|
||||
}),
|
||||
getLooksRareNonce: () => {
|
||||
return get().looksRareNonce
|
||||
},
|
||||
}))
|
||||
)
|
25
src/nft/hooks/useIsMobile.ts
Normal file
25
src/nft/hooks/useIsMobile.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import create from 'zustand'
|
||||
import { devtools } from 'zustand/middleware'
|
||||
|
||||
import { breakpoints } from '../css/sprinkles.css'
|
||||
|
||||
interface IsMobileState {
|
||||
isMobile: boolean
|
||||
width: number
|
||||
setMobileWidth: (width: number) => void
|
||||
}
|
||||
|
||||
export const useIsMobile = create<IsMobileState>()(
|
||||
devtools(
|
||||
(set) => ({
|
||||
isMobile: true,
|
||||
width: 800,
|
||||
setMobileWidth: (width: number) =>
|
||||
set(() => ({
|
||||
width,
|
||||
isMobile: width < breakpoints.tabletSm,
|
||||
})),
|
||||
}),
|
||||
{ name: 'isMobile' }
|
||||
)
|
||||
)
|
24
src/nft/hooks/useMarketplaceSelect.ts
Normal file
24
src/nft/hooks/useMarketplaceSelect.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import create from 'zustand'
|
||||
import { devtools } from 'zustand/middleware'
|
||||
|
||||
export type MarketplaceOption = { name: string; icon: string }
|
||||
|
||||
interface State {
|
||||
options: MarketplaceOption[]
|
||||
select: (o: MarketplaceOption) => void
|
||||
}
|
||||
|
||||
export const useMarketplaceSelect = create<State>()(
|
||||
devtools(
|
||||
(set) => ({
|
||||
options: [],
|
||||
select: (option) =>
|
||||
set(({ options }) => {
|
||||
if (options.find((o) => option.name === o.name))
|
||||
return { options: options.filter((x) => x.name !== option.name) }
|
||||
else return { options: [...options, option] }
|
||||
}),
|
||||
}),
|
||||
{ name: 'useMarketplaceSelect' }
|
||||
)
|
||||
)
|
52
src/nft/hooks/useNFTSelect.ts
Normal file
52
src/nft/hooks/useNFTSelect.ts
Normal file
@ -0,0 +1,52 @@
|
||||
import create from 'zustand'
|
||||
import { devtools } from 'zustand/middleware'
|
||||
|
||||
import { OpenSeaAsset } from '../types'
|
||||
|
||||
interface SelectNFTState {
|
||||
/**
|
||||
* NFTs selected by a user
|
||||
*/
|
||||
selectedNFTs: (OpenSeaAsset & { price?: number })[]
|
||||
|
||||
selectNFT: (nft: OpenSeaAsset & { price?: number }) => void
|
||||
reset: () => void
|
||||
setUniversalPrice: (price: number) => void
|
||||
toggleUniversalPrice: (v: boolean) => void
|
||||
setSingleNFTPrice: (id: number, price: number) => void
|
||||
isUniversalPrice: boolean
|
||||
}
|
||||
|
||||
export const useNFTSelect = create<SelectNFTState>()(
|
||||
devtools(
|
||||
(set) => ({
|
||||
selectedNFTs: [],
|
||||
isUniversalPrice: false,
|
||||
selectNFT: (nft) =>
|
||||
set(({ selectedNFTs }) => {
|
||||
if (selectedNFTs.length === 0) return { selectedNFTs: [nft] }
|
||||
else if (!!selectedNFTs.find((x) => x.id === nft.id))
|
||||
return { selectedNFTs: selectedNFTs.filter((n) => n.id !== nft.id) }
|
||||
else return { selectedNFTs: [...selectedNFTs, nft] }
|
||||
}),
|
||||
reset: () => set(() => ({ selectedNFTs: [] })),
|
||||
toggleUniversalPrice: (v) => set(() => ({ isUniversalPrice: v })),
|
||||
setUniversalPrice: (price) =>
|
||||
set(({ selectedNFTs }) => {
|
||||
return {
|
||||
selectedNFTs: selectedNFTs.map((n) => ({ ...n, price })),
|
||||
isUniversalPrice: true,
|
||||
}
|
||||
}),
|
||||
setSingleNFTPrice: (id, price) =>
|
||||
set(({ selectedNFTs }) => {
|
||||
const found = selectedNFTs.find((i) => i.id === id)
|
||||
|
||||
return {
|
||||
selectedNFTs: [...selectedNFTs.filter((n) => n.id !== id), { ...found, price }],
|
||||
}
|
||||
}),
|
||||
}),
|
||||
{ name: 'useNFTSelect' }
|
||||
)
|
||||
)
|
24
src/nft/hooks/useSearchHistory.ts
Normal file
24
src/nft/hooks/useSearchHistory.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { FungibleToken, GenieCollection } from 'nft/types'
|
||||
import create from 'zustand'
|
||||
import { devtools, persist } from 'zustand/middleware'
|
||||
|
||||
interface SearchHistoryProps {
|
||||
history: (FungibleToken | GenieCollection)[]
|
||||
addItem: (item: FungibleToken | GenieCollection) => void
|
||||
}
|
||||
|
||||
export const useSearchHistory = create<SearchHistoryProps>()(
|
||||
persist(
|
||||
devtools((set) => ({
|
||||
history: [],
|
||||
addItem: (item: FungibleToken | GenieCollection) => {
|
||||
set(({ history }) => {
|
||||
const historyCopy = [...history]
|
||||
if (historyCopy.length === 0 || historyCopy[0].address !== item.address) historyCopy.unshift(item)
|
||||
return { history: historyCopy }
|
||||
})
|
||||
},
|
||||
})),
|
||||
{ name: 'useSearchHistory' }
|
||||
)
|
||||
)
|
37
src/nft/hooks/useSelectAsset.ts
Normal file
37
src/nft/hooks/useSelectAsset.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import create from 'zustand'
|
||||
import { devtools } from 'zustand/middleware'
|
||||
|
||||
import { GenieAsset } from '../types'
|
||||
|
||||
interface SelectAssetState {
|
||||
selectedAssets: GenieAsset[]
|
||||
selectAsset: (asset: GenieAsset) => void
|
||||
removeAsset: (asset: GenieAsset) => void
|
||||
reset: () => void
|
||||
}
|
||||
|
||||
export const useSelectAsset = create<SelectAssetState>()(
|
||||
devtools((set) => ({
|
||||
selectedAssets: [],
|
||||
selectAsset: (asset) =>
|
||||
set(({ selectedAssets }) => {
|
||||
const assetWithId = { id: uuidv4(), ...asset }
|
||||
if (selectedAssets.length === 0) return { selectedAssets: [assetWithId] }
|
||||
else return { selectedAssets: [...selectedAssets, assetWithId] }
|
||||
}),
|
||||
removeAsset: (asset) => {
|
||||
set(({ selectedAssets }) => {
|
||||
if (selectedAssets.length === 0) return { selectedAssets: [] }
|
||||
else selectedAssets.find((x) => x.tokenId === asset.tokenId && x.address === asset.address)
|
||||
const assetsCopy = [...selectedAssets]
|
||||
assetsCopy.splice(
|
||||
selectedAssets.findIndex((n) => n.tokenId === asset.tokenId && n.address === asset.address),
|
||||
1
|
||||
)
|
||||
return { selectedAssets: assetsCopy }
|
||||
})
|
||||
},
|
||||
reset: () => set(() => ({ selectedAssets: [] })),
|
||||
}))
|
||||
)
|
149
src/nft/hooks/useSellAsset.ts
Normal file
149
src/nft/hooks/useSellAsset.ts
Normal file
@ -0,0 +1,149 @@
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import create from 'zustand'
|
||||
import { devtools } from 'zustand/middleware'
|
||||
|
||||
import { ListingMarket, ListingWarning, WalletAsset } from '../types'
|
||||
|
||||
interface SellAssetState {
|
||||
sellAssets: WalletAsset[]
|
||||
selectSellAsset: (asset: WalletAsset) => void
|
||||
removeSellAsset: (asset: WalletAsset) => void
|
||||
reset: () => void
|
||||
setGlobalExpiration: (expirationTime: number) => void
|
||||
setAssetListPrice: (asset: WalletAsset, price: string, marketplace?: ListingMarket) => void
|
||||
setGlobalMarketplaces: (marketplaces: ListingMarket[]) => void
|
||||
removeAssetMarketplace: (asset: WalletAsset, marketplace: ListingMarket) => void
|
||||
addMarketplaceWarning: (asset: WalletAsset, warning: ListingWarning) => void
|
||||
removeMarketplaceWarning: (asset: WalletAsset, warning: ListingWarning, setGlobalOverride?: boolean) => void
|
||||
removeAllMarketplaceWarnings: () => void
|
||||
}
|
||||
|
||||
export const useSellAsset = create<SellAssetState>()(
|
||||
devtools(
|
||||
(set) => ({
|
||||
sellAssets: [],
|
||||
selectSellAsset: (asset) =>
|
||||
set(({ sellAssets }) => {
|
||||
const assetWithId = { id: uuidv4(), ...asset }
|
||||
if (sellAssets.length === 0) return { sellAssets: [assetWithId] }
|
||||
else return { sellAssets: [...sellAssets, assetWithId] }
|
||||
}),
|
||||
removeSellAsset: (asset) => {
|
||||
set(({ sellAssets }) => {
|
||||
if (sellAssets.length === 0) return { sellAssets: [] }
|
||||
else sellAssets.find((x) => x.id === asset.id)
|
||||
const assetsCopy = [...sellAssets]
|
||||
assetsCopy.splice(
|
||||
sellAssets.findIndex((n) => n.id === asset.id),
|
||||
1
|
||||
)
|
||||
return { sellAssets: assetsCopy }
|
||||
})
|
||||
},
|
||||
reset: () => set(() => ({ sellAssets: [] })),
|
||||
setGlobalExpiration: (expirationTime) => {
|
||||
set(({ sellAssets }) => {
|
||||
const assetsCopy = [...sellAssets]
|
||||
assetsCopy.map((asset) => {
|
||||
asset.expirationTime = expirationTime
|
||||
return asset
|
||||
})
|
||||
return { sellAssets: assetsCopy }
|
||||
})
|
||||
},
|
||||
setAssetListPrice: (asset, price, marketplace?) => {
|
||||
set(({ sellAssets }) => {
|
||||
const assetsCopy = [...sellAssets]
|
||||
if (marketplace) {
|
||||
const listingIndex = asset.newListings?.findIndex(
|
||||
(listing) => listing.marketplace.name === marketplace.name
|
||||
)
|
||||
if (asset.newListings && listingIndex != null && listingIndex > -1) {
|
||||
asset.newListings[listingIndex] = { price, marketplace, overrideFloorPrice: false }
|
||||
if (listingIndex === 0) asset.marketAgnosticPrice = price
|
||||
} else asset.newListings?.push({ price, marketplace, overrideFloorPrice: false })
|
||||
} else asset.marketAgnosticPrice = price
|
||||
const index = sellAssets.findIndex((n) => n.id === asset.id)
|
||||
assetsCopy[index] = asset
|
||||
return { sellAssets: assetsCopy }
|
||||
})
|
||||
},
|
||||
setGlobalMarketplaces: (marketplaces) => {
|
||||
set(({ sellAssets }) => {
|
||||
const assetsCopy = [...sellAssets]
|
||||
assetsCopy.map((asset) => {
|
||||
asset.marketplaces = marketplaces
|
||||
asset.newListings = []
|
||||
for (const marketplace of marketplaces) {
|
||||
const listingIndex = asset.newListings.findIndex(
|
||||
(listing) => listing.marketplace.name === marketplace.name
|
||||
)
|
||||
const newListing = {
|
||||
price: asset.marketAgnosticPrice,
|
||||
marketplace,
|
||||
overrideFloorPrice: false,
|
||||
}
|
||||
listingIndex > -1 ? (asset.newListings[listingIndex] = newListing) : asset.newListings.push(newListing)
|
||||
}
|
||||
return asset
|
||||
})
|
||||
return { sellAssets: assetsCopy }
|
||||
})
|
||||
},
|
||||
removeAssetMarketplace: (asset, marketplace) => {
|
||||
set(({ sellAssets }) => {
|
||||
const assetsCopy = [...sellAssets]
|
||||
const assetIndex = sellAssets.indexOf(asset)
|
||||
const marketplaceIndex =
|
||||
asset.marketplaces?.findIndex((oldMarket) => oldMarket.name === marketplace.name) ?? -1
|
||||
const listingIndex = asset.newListings?.findIndex((listing) => listing.marketplace.name === marketplace.name)
|
||||
const assetCopy = JSON.parse(JSON.stringify(asset))
|
||||
if (marketplaceIndex > -1) {
|
||||
assetCopy.marketplaces.splice(marketplaceIndex, 1)
|
||||
assetCopy.newListings.splice(listingIndex, 1)
|
||||
}
|
||||
assetsCopy.splice(assetIndex, 1, assetCopy)
|
||||
return { sellAssets: assetsCopy }
|
||||
})
|
||||
},
|
||||
addMarketplaceWarning: (asset, warning) => {
|
||||
set(({ sellAssets }) => {
|
||||
const assetsCopy = [...sellAssets]
|
||||
asset.listingWarnings?.push(warning)
|
||||
const index = sellAssets.findIndex((n) => n.id === asset.id)
|
||||
assetsCopy[index] = asset
|
||||
return { sellAssets: assetsCopy }
|
||||
})
|
||||
},
|
||||
removeMarketplaceWarning: (asset, warning, setGlobalOverride?) => {
|
||||
set(({ sellAssets }) => {
|
||||
const assetsCopy = [...sellAssets]
|
||||
if (asset.listingWarnings === undefined || asset.newListings === undefined) return { sellAssets: assetsCopy }
|
||||
const warningIndex =
|
||||
asset.listingWarnings?.findIndex((n) => n.marketplace.name === warning.marketplace.name) ?? -1
|
||||
asset.listingWarnings?.splice(warningIndex, 1)
|
||||
if (warning?.message?.includes('LISTING BELOW FLOOR')) {
|
||||
if (setGlobalOverride) {
|
||||
asset.newListings?.forEach((listing) => (listing.overrideFloorPrice = true))
|
||||
} else {
|
||||
const listingIndex =
|
||||
asset.newListings?.findIndex((n) => n.marketplace.name === warning.marketplace.name) ?? -1
|
||||
asset.newListings[listingIndex].overrideFloorPrice = true
|
||||
}
|
||||
}
|
||||
const index = sellAssets.findIndex((n) => n.id === asset.id)
|
||||
assetsCopy[index] = asset
|
||||
return { sellAssets: assetsCopy }
|
||||
})
|
||||
},
|
||||
removeAllMarketplaceWarnings: () => {
|
||||
set(({ sellAssets }) => {
|
||||
const assetsCopy = [...sellAssets]
|
||||
assetsCopy.map((asset) => (asset.listingWarnings = []))
|
||||
return { sellAssets: assetsCopy }
|
||||
})
|
||||
},
|
||||
}),
|
||||
{ name: 'useSelectAsset' }
|
||||
)
|
||||
)
|
25
src/nft/hooks/useSellPageState.ts
Normal file
25
src/nft/hooks/useSellPageState.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import create from 'zustand'
|
||||
import { devtools } from 'zustand/middleware'
|
||||
|
||||
import { SellPageStateType } from '../types'
|
||||
|
||||
interface sellPageState {
|
||||
/**
|
||||
* State of user settings
|
||||
*/
|
||||
state: SellPageStateType
|
||||
setSellPageState: (state: SellPageStateType) => void
|
||||
}
|
||||
|
||||
export const useSellPageState = create<sellPageState>()(
|
||||
devtools(
|
||||
(set) => ({
|
||||
state: SellPageStateType.SELECTING,
|
||||
setSellPageState: (newState) =>
|
||||
set(() => ({
|
||||
state: newState,
|
||||
})),
|
||||
}),
|
||||
{ name: 'useSellPageState' }
|
||||
)
|
||||
)
|
165
src/nft/hooks/useSendTransaction.ts
Normal file
165
src/nft/hooks/useSendTransaction.ts
Normal file
@ -0,0 +1,165 @@
|
||||
import { Interface } from '@ethersproject/abi'
|
||||
import { BigNumber } from '@ethersproject/bignumber'
|
||||
import { hexStripZeros } from '@ethersproject/bytes'
|
||||
import { ContractReceipt } from '@ethersproject/contracts'
|
||||
import { JsonRpcSigner } from '@ethersproject/providers'
|
||||
import create from 'zustand'
|
||||
import { devtools } from 'zustand/middleware'
|
||||
|
||||
import ERC721 from '../../abis/erc721.json'
|
||||
import ERC1155 from '../../abis/erc1155.json'
|
||||
import CryptoPunksMarket from '../abis/CryptoPunksMarket.json'
|
||||
import { GenieAsset, RouteResponse, RoutingItem, TxResponse, TxStateType, UpdatedGenieAsset } from '../types'
|
||||
import { combineBuyItemsWithTxRoute } from '../utils/txRoute/combineItemsWithTxRoute'
|
||||
|
||||
// Shortens a given txHash. With standard charsToShorten var of 4, a hash will become 0x1234...1234
|
||||
export const shortenTxHash = (txHash: string, charsToShorten = 4, addCharsToBack = 0): string => {
|
||||
return `${txHash.substring(0, charsToShorten + 2)}...${txHash.substring(
|
||||
txHash.length - charsToShorten,
|
||||
txHash.length - (charsToShorten + addCharsToBack)
|
||||
)}`
|
||||
}
|
||||
|
||||
interface TxState {
|
||||
state: TxStateType
|
||||
setState: (state: TxStateType) => void
|
||||
txHash: string
|
||||
clearTxHash: () => void
|
||||
sendTransaction: (
|
||||
signer: JsonRpcSigner,
|
||||
selectedAssets: UpdatedGenieAsset[],
|
||||
transactionData: RouteResponse
|
||||
) => Promise<TxResponse | undefined>
|
||||
}
|
||||
|
||||
export const useSendTransaction = create<TxState>()(
|
||||
devtools(
|
||||
(set) => ({
|
||||
state: TxStateType.New,
|
||||
txHash: '',
|
||||
clearTxHash: () => set({ txHash: '' }),
|
||||
setState: (newState) => set(() => ({ state: newState })),
|
||||
sendTransaction: async (signer, selectedAssets, transactionData) => {
|
||||
const address = await signer.getAddress()
|
||||
try {
|
||||
const txNoGasLimit = {
|
||||
to: transactionData.to,
|
||||
value: BigNumber.from(transactionData.valueToSend),
|
||||
data: transactionData.data,
|
||||
}
|
||||
|
||||
const gasLimit = (await signer.estimateGas(txNoGasLimit)).mul(105).div(100)
|
||||
// tx['gasLimit'] = gasLimit
|
||||
const tx = { ...txNoGasLimit, gasLimit } // TODO test this works when firing off tx
|
||||
|
||||
set({ state: TxStateType.Signing })
|
||||
const res = await signer.sendTransaction(tx)
|
||||
set({ state: TxStateType.Confirming })
|
||||
set({ txHash: res.hash })
|
||||
|
||||
const txReceipt = await res.wait()
|
||||
|
||||
//tx was mined successfully
|
||||
if (txReceipt.status === 1) {
|
||||
const nftsPurchased = findNFTsPurchased(txReceipt, address, selectedAssets, transactionData.route)
|
||||
const nftsNotPurchased = findNFTsNotPurchased(selectedAssets, nftsPurchased)
|
||||
set({ state: TxStateType.Success })
|
||||
return {
|
||||
nftsPurchased,
|
||||
nftsNotPurchased,
|
||||
txReceipt,
|
||||
}
|
||||
} else {
|
||||
set({ state: TxStateType.Failed })
|
||||
return {
|
||||
nftsPurchased: [],
|
||||
nftsNotPurchased: selectedAssets,
|
||||
txReceipt,
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Error creating multiAssetSwap Transaction', e)
|
||||
if (e.code === 4001) {
|
||||
set({ state: TxStateType.Denied })
|
||||
} else {
|
||||
set({ state: TxStateType.Invalid })
|
||||
}
|
||||
return
|
||||
}
|
||||
},
|
||||
}),
|
||||
{ name: 'useSendTransactionState' }
|
||||
)
|
||||
)
|
||||
|
||||
const findNFTsPurchased = (
|
||||
txReceipt: ContractReceipt,
|
||||
signerAddress: string,
|
||||
toBuy: GenieAsset[],
|
||||
txRoute: RoutingItem[]
|
||||
): UpdatedGenieAsset[] => {
|
||||
if (!txReceipt.logs) {
|
||||
return []
|
||||
}
|
||||
const erc721Interface = new Interface(ERC721)
|
||||
const erc1155Interface = new Interface(ERC1155)
|
||||
const cryptopunksMarketInterface = new Interface(CryptoPunksMarket)
|
||||
|
||||
// Find successfully purchased NFTs (and assign to state nftsPurchased) by parsing events
|
||||
const transferErc721BuyEvents = txReceipt.logs.filter(
|
||||
(x) =>
|
||||
x.topics[0] === erc721Interface.getEventTopic('Transfer') &&
|
||||
hexStripZeros(x.topics[2]).toLowerCase() === signerAddress.toLowerCase()
|
||||
)
|
||||
|
||||
const transferredErc721 = transferErc721BuyEvents.map((x) => ({
|
||||
address: x.address,
|
||||
tokenId: parseInt(x.topics[3]).toString(),
|
||||
}))
|
||||
const transferErc1155BuyEvents = txReceipt.logs.filter(
|
||||
(x) =>
|
||||
x.topics[0] === erc1155Interface.getEventTopic('TransferSingle') &&
|
||||
hexStripZeros(x.topics[3]).toLowerCase() === signerAddress.toLowerCase()
|
||||
)
|
||||
|
||||
const transferredErc1155 = transferErc1155BuyEvents.map((x) => ({
|
||||
address: x.address,
|
||||
tokenId: erc1155Interface.parseLog(x).args[3].toString(),
|
||||
}))
|
||||
|
||||
// Find transferred CryptoPunks
|
||||
const transferCryptopunkEvents = txReceipt.logs.filter(
|
||||
(x) =>
|
||||
x.topics[0] === cryptopunksMarketInterface.getEventTopic('PunkTransfer') &&
|
||||
hexStripZeros(x.topics[2]).toLowerCase() === signerAddress.toLowerCase()
|
||||
)
|
||||
const transferredCryptopunks = transferCryptopunkEvents.map((x) => ({
|
||||
address: x.address,
|
||||
tokenId: cryptopunksMarketInterface.parseLog(x).args[2].toString(),
|
||||
}))
|
||||
|
||||
const allTransferred = [...transferredErc721, ...transferredErc1155, ...transferredCryptopunks]
|
||||
|
||||
const transferredItems = toBuy.filter((assetToBuy) => {
|
||||
return allTransferred.some(
|
||||
(purchasedNft) =>
|
||||
assetToBuy.address.toLowerCase() === purchasedNft.address.toLowerCase() &&
|
||||
parseInt(assetToBuy.tokenId).toString() === purchasedNft.tokenId
|
||||
)
|
||||
})
|
||||
|
||||
return combineBuyItemsWithTxRoute(transferredItems, txRoute)
|
||||
}
|
||||
|
||||
const findNFTsNotPurchased = (toBuy: GenieAsset[], nftsPurchased: UpdatedGenieAsset[]) => {
|
||||
const nftsNotPurchased: Array<UpdatedGenieAsset> = []
|
||||
toBuy.forEach((selectedAsset) => {
|
||||
const purchasedNft = nftsPurchased.find(
|
||||
(x) => x.address.toLowerCase() === selectedAsset.address.toLowerCase() && x.tokenId === selectedAsset.tokenId
|
||||
)
|
||||
if (!purchasedNft) {
|
||||
nftsNotPurchased.push(selectedAsset)
|
||||
}
|
||||
})
|
||||
return nftsNotPurchased
|
||||
}
|
37
src/nft/hooks/useSweep.ts
Normal file
37
src/nft/hooks/useSweep.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import create from 'zustand'
|
||||
import { devtools, persist } from 'zustand/middleware'
|
||||
|
||||
import { GenieAsset } from '../types'
|
||||
|
||||
interface SweepState {
|
||||
sweepAssets: GenieAsset[]
|
||||
setSweepAssets: (assets: GenieAsset[]) => void
|
||||
removeSweepAsset: (asset: GenieAsset) => void
|
||||
reset: () => void
|
||||
}
|
||||
|
||||
export const useSweep = create<SweepState>()(
|
||||
persist(
|
||||
devtools((set) => ({
|
||||
sweepAssets: [],
|
||||
setSweepAssets: (assets) =>
|
||||
set(() => {
|
||||
return { sweepAssets: assets }
|
||||
}),
|
||||
removeSweepAsset: (asset) => {
|
||||
set(({ sweepAssets }) => {
|
||||
if (sweepAssets.length === 0) return { sweepAssets: [] }
|
||||
else sweepAssets.find((x) => x.tokenId === asset.tokenId && x.address === asset.address)
|
||||
const assetsCopy = [...sweepAssets]
|
||||
assetsCopy.splice(
|
||||
sweepAssets.findIndex((n) => n.tokenId === asset.tokenId && n.address === asset.address),
|
||||
1
|
||||
)
|
||||
return { sweepAssets: assetsCopy }
|
||||
})
|
||||
},
|
||||
reset: () => set(() => ({ sweepAssets: [] })),
|
||||
})),
|
||||
{ name: 'useSweep' }
|
||||
)
|
||||
)
|
31
src/nft/hooks/useWalletBalance.ts
Normal file
31
src/nft/hooks/useWalletBalance.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { BigNumber } from '@ethersproject/bignumber'
|
||||
import { Web3Provider } from '@ethersproject/providers'
|
||||
import { parseEther } from '@ethersproject/units'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { useNativeCurrencyBalances } from 'state/connection/hooks'
|
||||
|
||||
interface WalletBalanceProps {
|
||||
address: string
|
||||
balance: string
|
||||
weiBalance: BigNumber
|
||||
provider: Web3Provider | undefined
|
||||
}
|
||||
|
||||
export function useWalletBalance(): WalletBalanceProps {
|
||||
const { account: address, provider } = useWeb3React()
|
||||
const balanceString = useNativeCurrencyBalances(address ? [address] : [])?.[address ?? '']?.toSignificant(3) || '0'
|
||||
|
||||
return address == null
|
||||
? {
|
||||
address: '',
|
||||
balance: '0',
|
||||
weiBalance: parseEther('0'),
|
||||
provider: undefined,
|
||||
}
|
||||
: {
|
||||
address,
|
||||
balance: balanceString,
|
||||
weiBalance: parseEther(balanceString),
|
||||
provider,
|
||||
}
|
||||
}
|
73
src/nft/hooks/useWalletCollections.ts
Normal file
73
src/nft/hooks/useWalletCollections.ts
Normal file
@ -0,0 +1,73 @@
|
||||
import create from 'zustand'
|
||||
import { devtools } from 'zustand/middleware'
|
||||
|
||||
import { WalletAsset, WalletCollection } from '../types'
|
||||
|
||||
interface WalletCollectionState {
|
||||
walletAssets: WalletAsset[]
|
||||
walletCollections: WalletCollection[]
|
||||
displayAssets: WalletAsset[]
|
||||
collectionFilters: string[]
|
||||
listFilter: string
|
||||
setWalletAssets: (assets: WalletAsset[]) => void
|
||||
setWalletCollections: (collections: WalletCollection[]) => void
|
||||
setCollectionFilters: (address: string) => void
|
||||
clearCollectionFilters: () => void
|
||||
setListFilter: (value: string) => void
|
||||
setDisplayAssets: (walletAssets: WalletAsset[], listFilter: string) => void
|
||||
}
|
||||
|
||||
export const useWalletCollections = create<WalletCollectionState>()(
|
||||
devtools(
|
||||
(set) => ({
|
||||
walletAssets: [],
|
||||
walletCollections: [],
|
||||
displayAssets: [],
|
||||
collectionFilters: [],
|
||||
listFilter: 'All',
|
||||
setWalletAssets: (assets) =>
|
||||
set(() => {
|
||||
return {
|
||||
walletAssets: assets?.filter((asset) => asset.asset_contract?.schema_name === 'ERC721'),
|
||||
}
|
||||
}),
|
||||
setWalletCollections: (collections) =>
|
||||
set(() => {
|
||||
return { walletCollections: collections }
|
||||
}),
|
||||
setCollectionFilters: (address) =>
|
||||
set(({ collectionFilters }) => {
|
||||
if (collectionFilters.length === 0) return { collectionFilters: [address] }
|
||||
else if (!!collectionFilters.find((x) => x === address))
|
||||
return { collectionFilters: collectionFilters.filter((n) => n !== address) }
|
||||
else return { collectionFilters: [...collectionFilters, address] }
|
||||
}),
|
||||
clearCollectionFilters: () =>
|
||||
set(() => {
|
||||
return { collectionFilters: [] }
|
||||
}),
|
||||
setListFilter: (value) =>
|
||||
set(() => {
|
||||
return { listFilter: value }
|
||||
}),
|
||||
setDisplayAssets: (walletAssets, listFilter) =>
|
||||
set(() => {
|
||||
return { displayAssets: filterWalletAssets(walletAssets, listFilter) }
|
||||
}),
|
||||
}),
|
||||
{ name: 'useWalletCollections' }
|
||||
)
|
||||
)
|
||||
|
||||
const filterWalletAssets = (walletAssets: WalletAsset[], listFilter: string) => {
|
||||
let displayAssets = walletAssets
|
||||
if (listFilter === 'Listed')
|
||||
displayAssets = displayAssets?.filter((x) => {
|
||||
return x.listing_date !== null
|
||||
})
|
||||
if (listFilter === 'Unlisted')
|
||||
displayAssets = displayAssets?.filter((x) => {
|
||||
return x.listing_date === null
|
||||
})
|
||||
return displayAssets
|
||||
}
|
24
src/nft/queries/genie/ActivityFetcher.ts
Normal file
24
src/nft/queries/genie/ActivityFetcher.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { ActivityEventResponse, ActivityFilter } from '../../types'
|
||||
|
||||
export const ActivityFetcher = async (
|
||||
contractAddress: string,
|
||||
filters?: ActivityFilter,
|
||||
cursor?: string
|
||||
): Promise<ActivityEventResponse> => {
|
||||
const filterParam =
|
||||
filters && filters.eventTypes
|
||||
? `&${filters.eventTypes?.map((eventType) => `event_types[]=${eventType}`).join('&')}`
|
||||
: ''
|
||||
const url = `${
|
||||
process.env.REACT_APP_GENIE_V3_API_URL
|
||||
}/collections/${contractAddress}/activity?limit=25${filterParam}${cursor ? `&cursor=${cursor}` : ''}`
|
||||
|
||||
const r = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
const data = await r.json()
|
||||
return data.data
|
||||
}
|
126
src/nft/queries/genie/AssetsFetcher.ts
Normal file
126
src/nft/queries/genie/AssetsFetcher.ts
Normal file
@ -0,0 +1,126 @@
|
||||
import { parseEther } from '@ethersproject/units'
|
||||
|
||||
import { Trait } from '../../hooks/useCollectionFilters'
|
||||
import { AssetPayload, CollectionSort, GenieAsset } from '../../types'
|
||||
|
||||
export const formatTraits = (traits: Trait[]) => {
|
||||
const traitObj: Record<string, string[]> = {}
|
||||
const nonMetaTraits = traits.filter((el) => el.trait_type !== 'Number of traits')
|
||||
for (const trait of nonMetaTraits) {
|
||||
if (!traitObj[trait.trait_type]) traitObj[trait.trait_type] = [trait.trait_value]
|
||||
else traitObj[trait.trait_type].push(trait.trait_value)
|
||||
}
|
||||
|
||||
return traitObj
|
||||
}
|
||||
|
||||
const formatPrice = (x: number | string) => parseEther(x.toString()).toString()
|
||||
|
||||
export const AssetsFetcher = async ({
|
||||
contractAddress,
|
||||
tokenId,
|
||||
sort,
|
||||
markets,
|
||||
price,
|
||||
rarityRange,
|
||||
traits,
|
||||
searchText,
|
||||
notForSale,
|
||||
pageParam,
|
||||
}: {
|
||||
contractAddress: string
|
||||
tokenId?: string
|
||||
offset?: number
|
||||
sort?: CollectionSort
|
||||
markets?: string[]
|
||||
price?: { high?: number | string; low?: number | string; symbol: string }
|
||||
rarityRange?: Record<string, unknown>
|
||||
traits?: Trait[]
|
||||
searchText?: string
|
||||
notForSale?: boolean
|
||||
pageParam: number
|
||||
}): Promise<GenieAsset[] | undefined> => {
|
||||
const url = `${process.env.REACT_APP_GENIE_API_URL}/assets`
|
||||
const payload: AssetPayload = {
|
||||
filters: {
|
||||
address: contractAddress.toLowerCase(),
|
||||
traits: {},
|
||||
searchText,
|
||||
notForSale,
|
||||
tokenId,
|
||||
...rarityRange,
|
||||
},
|
||||
fields: {
|
||||
address: 1,
|
||||
name: 1,
|
||||
id: 1,
|
||||
imageUrl: 1,
|
||||
currentPrice: 1,
|
||||
currentUsdPrice: 1,
|
||||
paymentToken: 1,
|
||||
animationUrl: 1,
|
||||
notForSale: 1,
|
||||
rarity: 1,
|
||||
tokenId: 1,
|
||||
},
|
||||
limit: 25,
|
||||
offset: pageParam * 25,
|
||||
}
|
||||
if (sort) {
|
||||
payload.sort = sort
|
||||
}
|
||||
if (markets) {
|
||||
payload.markets = markets
|
||||
}
|
||||
const numberOfTraits = traits?.filter((trait) => trait.trait_type === 'Number of traits')
|
||||
if (numberOfTraits) {
|
||||
payload.filters.numTraits = numberOfTraits.map((el) => ({ traitCount: el.trait_value }))
|
||||
}
|
||||
if (traits) {
|
||||
payload.filters.traits = formatTraits(traits)
|
||||
}
|
||||
|
||||
const low = price?.low ? parseFloat(formatPrice(price.low)) : undefined
|
||||
const high = price?.high ? parseFloat(formatPrice(price.high)) : undefined
|
||||
|
||||
// Only consider sending eth price filters when searching
|
||||
// across listed assets
|
||||
if (!notForSale) {
|
||||
if (low || high) {
|
||||
payload.filters.currentEthPrice = {}
|
||||
}
|
||||
|
||||
if (low && payload.filters.currentEthPrice) {
|
||||
payload.filters.currentEthPrice.$gte = low
|
||||
}
|
||||
|
||||
if (high && payload.filters.currentEthPrice) {
|
||||
payload.filters.currentEthPrice.$lte = high
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const r = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
})
|
||||
const data = await r.json()
|
||||
// Unfortunately have to include totalCount into each element. The fetcher
|
||||
// for swr infinite must return an array.
|
||||
for (const x of data.data) {
|
||||
x.totalCount = data.totalCount
|
||||
x.numTraitsByAmount = data.numTraitsByAmount
|
||||
}
|
||||
|
||||
// Uncomment the lines belo if you want to simulate a delay
|
||||
// await (async () => await new Promise((resolve) => setTimeout(resolve, 50000)))();
|
||||
|
||||
return data.data
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
return
|
||||
}
|
||||
}
|
32
src/nft/queries/genie/CollectionPreviewFetcher.ts
Normal file
32
src/nft/queries/genie/CollectionPreviewFetcher.ts
Normal file
@ -0,0 +1,32 @@
|
||||
export const CollectionPreviewFetcher = async (
|
||||
address: string
|
||||
): Promise<
|
||||
[
|
||||
{
|
||||
name: string
|
||||
bannerImageUrl?: string
|
||||
}
|
||||
]
|
||||
> => {
|
||||
const url = `${process.env.REACT_APP_GENIE_API_URL}/collectionPreview?address=${address}`
|
||||
|
||||
const controller = new AbortController()
|
||||
|
||||
const timeoutId = setTimeout(() => controller.abort(), 3000)
|
||||
|
||||
const r = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
clearInterval(timeoutId)
|
||||
const data = await r.json()
|
||||
|
||||
return [
|
||||
{
|
||||
name: data.data.collectionName,
|
||||
bannerImageUrl: data.data.bannerImageUrl,
|
||||
},
|
||||
]
|
||||
}
|
59
src/nft/queries/genie/CollectionStatsFetcher.ts
Normal file
59
src/nft/queries/genie/CollectionStatsFetcher.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import { isAddress } from '@ethersproject/address'
|
||||
|
||||
import { GenieCollection } from '../../types'
|
||||
|
||||
export const CollectionStatsFetcher = async (addressOrName: string, recursive = false): Promise<GenieCollection> => {
|
||||
const isName = !isAddress(addressOrName.toLowerCase())
|
||||
const url = `${process.env.REACT_APP_GENIE_API_URL}/collections`
|
||||
|
||||
if (!isName && !recursive) {
|
||||
try {
|
||||
return await CollectionStatsFetcher(addressOrName.toLowerCase(), true)
|
||||
} catch {
|
||||
// Handle Error
|
||||
}
|
||||
}
|
||||
|
||||
const filters = isName
|
||||
? {
|
||||
$or: [{ name: { $regex: addressOrName, $options: 'i' } }],
|
||||
}
|
||||
: { address: addressOrName }
|
||||
|
||||
const payload = {
|
||||
filters,
|
||||
limit: isName ? 6 : 1,
|
||||
fields: isName
|
||||
? {
|
||||
name: 1,
|
||||
imageUrl: 1,
|
||||
address: 1,
|
||||
stats: 1,
|
||||
floorPrice: 1,
|
||||
}
|
||||
: {
|
||||
traits: 1,
|
||||
stats: 1,
|
||||
'indexingStats.openSea': 1,
|
||||
imageUrl: 1,
|
||||
bannerImageUrl: 1,
|
||||
twitter: 1,
|
||||
externalUrl: 1,
|
||||
instagram: 1,
|
||||
discordUrl: 1,
|
||||
marketplaceCount: 1,
|
||||
floorPrice: 1,
|
||||
},
|
||||
offset: 0,
|
||||
}
|
||||
const r = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
})
|
||||
|
||||
const data = await r.json()
|
||||
return data?.data ? data.data[0] : {}
|
||||
}
|
13
src/nft/queries/genie/LooksRareRewardsFetcher.ts
Normal file
13
src/nft/queries/genie/LooksRareRewardsFetcher.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { LooksRareRewardsData } from '../../types'
|
||||
|
||||
const looksRareApiAddress = 'https://api.looksrare.org/api/v1'
|
||||
|
||||
export const fetchLooksRareRewards = async (address: string): Promise<LooksRareRewardsData> => {
|
||||
const res = await fetch(`${looksRareApiAddress}/rewards?address=${address}`)
|
||||
|
||||
if (res.status !== 200) throw new Error(`LooksRare rewards API errored with status ${res.statusText}`)
|
||||
|
||||
const json = await res.json()
|
||||
|
||||
return json.data
|
||||
}
|
31
src/nft/queries/genie/MultipleCollectionStatsFetcher.ts
Normal file
31
src/nft/queries/genie/MultipleCollectionStatsFetcher.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { GenieCollection } from '../../types'
|
||||
|
||||
export const fetchMultipleCollectionStats = async ({
|
||||
addresses,
|
||||
}: {
|
||||
addresses: string[]
|
||||
}): Promise<GenieCollection[]> => {
|
||||
const url = `${process.env.REACT_APP_GENIE_API_URL}/searchCollections`
|
||||
const filters = {
|
||||
address: { $in: addresses },
|
||||
}
|
||||
const payload = {
|
||||
filters,
|
||||
fields: {
|
||||
stats: 1,
|
||||
imageUrl: 1,
|
||||
address: 1,
|
||||
name: 1,
|
||||
},
|
||||
}
|
||||
|
||||
const r = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
})
|
||||
const data = await r.json()
|
||||
return data.data
|
||||
}
|
69
src/nft/queries/genie/RouteFetcher.ts
Normal file
69
src/nft/queries/genie/RouteFetcher.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import { GenieAsset, RouteResponse, TokenType } from '../../types'
|
||||
|
||||
export const fetchRoute = async ({
|
||||
toSell,
|
||||
toBuy,
|
||||
senderAddress,
|
||||
}: {
|
||||
toSell: any
|
||||
toBuy: any
|
||||
senderAddress: string
|
||||
}): Promise<RouteResponse> => {
|
||||
const url = `${process.env.REACT_APP_GENIE_API_URL}/route`
|
||||
const payload = {
|
||||
sell: [...toSell].map((x) => buildRouteItem(x)),
|
||||
buy: [...toBuy].filter((x) => x.tokenType !== 'Dust').map((x) => buildRouteItem(x)),
|
||||
sender: senderAddress,
|
||||
}
|
||||
|
||||
const r = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
})
|
||||
const data = await r.json()
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
type ApiPriceInfo = {
|
||||
basePrice: string
|
||||
baseAsset: string
|
||||
ETHPrice: string
|
||||
}
|
||||
|
||||
type RouteItem = {
|
||||
id?: string
|
||||
symbol?: string
|
||||
name: string
|
||||
decimals: number
|
||||
address: string
|
||||
priceInfo: ApiPriceInfo
|
||||
tokenType: TokenType
|
||||
tokenId: string
|
||||
amount: number
|
||||
marketplace?: string
|
||||
collectionName?: string
|
||||
}
|
||||
|
||||
const buildRouteItem = (item: GenieAsset): RouteItem => {
|
||||
return {
|
||||
id: item.id,
|
||||
symbol: item.priceInfo.baseAsset,
|
||||
name: item.name,
|
||||
decimals: item.decimals || 0, // 0 for fungible items
|
||||
address: item.address,
|
||||
tokenType: item.tokenType,
|
||||
tokenId: item.tokenId,
|
||||
marketplace: item.marketplace,
|
||||
collectionName: item.collectionName,
|
||||
amount: item.amount || 1, // default 1 for a single asset
|
||||
priceInfo: {
|
||||
basePrice: item.priceInfo.basePrice,
|
||||
baseAsset: item.priceInfo.baseAsset,
|
||||
ETHPrice: item.priceInfo.ETHPrice,
|
||||
},
|
||||
}
|
||||
}
|
48
src/nft/queries/genie/SearchCollectionsFetcher.ts
Normal file
48
src/nft/queries/genie/SearchCollectionsFetcher.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import { isAddress } from '@ethersproject/address'
|
||||
|
||||
import { GenieCollection } from '../../types'
|
||||
|
||||
export const fetchSearchCollections = async (addressOrName: string, recursive = false): Promise<GenieCollection[]> => {
|
||||
const url = `${process.env.REACT_APP_GENIE_V3_API_URL}/searchCollections`
|
||||
const isName = !isAddress(addressOrName.toLowerCase())
|
||||
|
||||
if (!isName && !recursive) {
|
||||
try {
|
||||
return await fetchSearchCollections(addressOrName.toLowerCase(), true)
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
const filters = isName
|
||||
? {
|
||||
$or: [{ name: { $regex: addressOrName, $options: 'i' } }],
|
||||
}
|
||||
: { address: addressOrName }
|
||||
|
||||
const payload = {
|
||||
filters,
|
||||
limit: 6,
|
||||
fields: {
|
||||
name: 1,
|
||||
imageUrl: 1,
|
||||
address: 1,
|
||||
floorPrice: 1,
|
||||
},
|
||||
offset: 0,
|
||||
}
|
||||
const r = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
})
|
||||
if (isName) {
|
||||
const data = (await r.json()) as { data: GenieCollection[] }
|
||||
return data?.data ? data.data.slice(0, 6) : []
|
||||
}
|
||||
const data = await r.json()
|
||||
|
||||
return data.data ? [data.data[0]] : []
|
||||
}
|
20
src/nft/queries/genie/SearchTokensFetcher.ts
Normal file
20
src/nft/queries/genie/SearchTokensFetcher.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { FungibleToken } from '../../types'
|
||||
|
||||
export const fetchSearchTokens = async (tokenQuery: string): Promise<FungibleToken[]> => {
|
||||
const url = `${process.env.REACT_APP_GENIE_V3_API_URL}/searchTokens?tokenQuery=${tokenQuery}`
|
||||
|
||||
const r = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
|
||||
const data = await r.json()
|
||||
|
||||
// TODO Undo favoritism
|
||||
return (
|
||||
data.data &&
|
||||
data.data.sort((a: FungibleToken, b: FungibleToken) => (b.name === 'Uniswap' ? 1 : b.volume24h - a.volume24h))
|
||||
)
|
||||
}
|
14
src/nft/queries/genie/SingleAssetFetcher.ts
Normal file
14
src/nft/queries/genie/SingleAssetFetcher.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { CollectionInfoForAsset, GenieAsset } from '../../types'
|
||||
|
||||
export const fetchSingleAsset = async ({
|
||||
contractAddress,
|
||||
tokenId,
|
||||
}: {
|
||||
contractAddress: string
|
||||
tokenId?: string
|
||||
}): Promise<[GenieAsset, CollectionInfoForAsset]> => {
|
||||
const url = `${process.env.REACT_APP_GENIE_API_URL}/assetDetails?address=${contractAddress}&tokenId=${tokenId}`
|
||||
const r = await fetch(url)
|
||||
const data = await r.json()
|
||||
return [data.asset[0], data.collection]
|
||||
}
|
55
src/nft/queries/genie/SweepFetcher.ts
Normal file
55
src/nft/queries/genie/SweepFetcher.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import { Trait } from '../../hooks/useCollectionFilters'
|
||||
import { AssetPayload, GenieAsset } from '../../types'
|
||||
import { formatTraits } from './AssetsFetcher'
|
||||
|
||||
export const fetchSweep = async ({
|
||||
contractAddress,
|
||||
markets,
|
||||
traits = [],
|
||||
}: {
|
||||
contractAddress: string
|
||||
markets?: string[]
|
||||
traits?: Trait[]
|
||||
}): Promise<GenieAsset[]> => {
|
||||
const url = `${process.env.REACT_APP_GENIE_API_URL}/assets`
|
||||
const payload: AssetPayload = {
|
||||
filters: { address: contractAddress.toLowerCase(), traits: {}, notForSale: false },
|
||||
fields: {
|
||||
address: 1,
|
||||
name: 1,
|
||||
id: 1,
|
||||
imageUrl: 1,
|
||||
currentPrice: 1,
|
||||
currentUsdPrice: 1,
|
||||
paymentToken: 1,
|
||||
animationUrl: 1,
|
||||
notForSale: 1,
|
||||
},
|
||||
limit: 99,
|
||||
offset: 0,
|
||||
}
|
||||
|
||||
if (markets) {
|
||||
payload.markets = markets
|
||||
}
|
||||
|
||||
if (traits) {
|
||||
payload.filters.traits = formatTraits(traits)
|
||||
}
|
||||
|
||||
const numberOfTraits = traits.filter((trait) => trait.trait_type === 'Number of traits')
|
||||
if (numberOfTraits) {
|
||||
payload.filters.numTraits = numberOfTraits.map((el) => ({ traitCount: el.trait_value }))
|
||||
}
|
||||
|
||||
const r = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
})
|
||||
|
||||
const data = await r.json()
|
||||
return data.data
|
||||
}
|
19
src/nft/queries/genie/TransactionsFetcher.ts
Normal file
19
src/nft/queries/genie/TransactionsFetcher.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { TransactionsResponse } from '../../types'
|
||||
|
||||
export const fetchTransactions = async (payload: { sweep?: boolean }): Promise<TransactionsResponse[]> => {
|
||||
const url = `${process.env.REACT_APP_GENIE_API_URL}/transactions`
|
||||
|
||||
const r = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
})
|
||||
|
||||
const data = (await r.json()) as TransactionsResponse[]
|
||||
|
||||
return data.filter(
|
||||
(x) => x.bannerImage && (payload.sweep ? x.nftCount >= 3 && Math.floor(x.ethValue / 10 ** 18) >= 1 : true)
|
||||
)
|
||||
}
|
20
src/nft/queries/genie/TrendingCollectionsFetcher.ts
Normal file
20
src/nft/queries/genie/TrendingCollectionsFetcher.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { TimePeriod, TrendingCollection } from '../../types'
|
||||
|
||||
export const fetchTrendingCollections = async (payload: {
|
||||
volumeType: 'eth' | 'nft'
|
||||
timePeriod: TimePeriod
|
||||
size: number
|
||||
}): Promise<TrendingCollection[]> => {
|
||||
const url = `${process.env.REACT_APP_GENIE_V3_API_URL}/collections/trending`
|
||||
const r = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
})
|
||||
|
||||
const data = await r.json()
|
||||
|
||||
return data
|
||||
}
|
16
src/nft/queries/genie/TrendingTokensFetcher.ts
Normal file
16
src/nft/queries/genie/TrendingTokensFetcher.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { FungibleToken } from '../../types'
|
||||
|
||||
export const fetchTrendingTokens = async (numTokens?: number): Promise<FungibleToken[]> => {
|
||||
const url = `${process.env.REACT_APP_GENIE_V3_API_URL}/tokens/trending${numTokens ? `?numTokens=${numTokens}` : ''}`
|
||||
|
||||
const r = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
|
||||
const data = await r.json()
|
||||
|
||||
return data.data
|
||||
}
|
64
src/nft/queries/genie/WalletAssetsFetcher.ts
Normal file
64
src/nft/queries/genie/WalletAssetsFetcher.ts
Normal file
@ -0,0 +1,64 @@
|
||||
import { BigNumber } from '@ethersproject/bignumber'
|
||||
import { formatEther } from '@ethersproject/units'
|
||||
|
||||
import { WalletAsset } from '../../types'
|
||||
|
||||
const getEthPrice = (price: any) => {
|
||||
if (price.toString().includes('e')) {
|
||||
return BigNumber.from(10).pow(price.toString().split('e+')[1]).toString()
|
||||
}
|
||||
|
||||
return Math.round(price).toString()
|
||||
}
|
||||
|
||||
export const fetchWalletAssets = async ({
|
||||
ownerAddress,
|
||||
collectionAddresses,
|
||||
pageParam,
|
||||
}: {
|
||||
ownerAddress: string
|
||||
collectionAddresses?: string[]
|
||||
pageParam: number
|
||||
}): Promise<WalletAsset[]> => {
|
||||
const collectionAddressesString = collectionAddresses
|
||||
? collectionAddresses.reduce((str, collectionAddress) => str + `&assetContractAddresses=${collectionAddress}`, '')
|
||||
: ''
|
||||
const url = `${
|
||||
process.env.REACT_APP_GENIE_API_URL
|
||||
}/walletAssets?address=${ownerAddress}${collectionAddressesString}&limit=25&offset=${pageParam * 25}`
|
||||
|
||||
const r = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
const data = await r.json()
|
||||
return data.data.assets.map((asset: any) => {
|
||||
return {
|
||||
...asset,
|
||||
collectionIsVerified: asset.asset_contract.isVerified,
|
||||
lastPrice: asset.last_sale && formatEther(asset.last_sale.total_price),
|
||||
floorPrice: asset.collection?.floorPrice,
|
||||
creatorPercentage: parseFloat(asset.asset_contract.dev_seller_fee_basis_points) / 10000,
|
||||
date_acquired: asset.last_sale ? asset.last_sale.event_timestamp : asset.asset_contract.created_date,
|
||||
listing_date: asset.sellOrders.length
|
||||
? Math.max
|
||||
.apply(
|
||||
null,
|
||||
asset.sellOrders.map(function (order: any) {
|
||||
return new Date(order.orderCreatedDate)
|
||||
})
|
||||
)
|
||||
.toString()
|
||||
: null,
|
||||
floor_sell_order_price: asset?.sellOrders?.length
|
||||
? Math.min(
|
||||
...asset.sellOrders.map((order: any) => {
|
||||
return parseFloat(formatEther(getEthPrice(order.ethPrice)))
|
||||
})
|
||||
)
|
||||
: null,
|
||||
}
|
||||
})
|
||||
}
|
14
src/nft/queries/genie/index.ts
Normal file
14
src/nft/queries/genie/index.ts
Normal file
@ -0,0 +1,14 @@
|
||||
export * from './AssetsFetcher'
|
||||
export * from './CollectionPreviewFetcher'
|
||||
export * from './CollectionStatsFetcher'
|
||||
export * from './logListing'
|
||||
export * from './LooksRareRewardsFetcher'
|
||||
export * from './MultipleCollectionStatsFetcher'
|
||||
export * from './RouteFetcher'
|
||||
export * from './SearchCollectionsFetcher'
|
||||
export * from './SingleAssetFetcher'
|
||||
export * from './SweepFetcher'
|
||||
export * from './TransactionsFetcher'
|
||||
export * from './TrendingCollectionsFetcher'
|
||||
export * from './triggerPriceUpdatesForCollection'
|
||||
export * from './WalletAssetsFetcher'
|
36
src/nft/queries/genie/logListing.ts
Normal file
36
src/nft/queries/genie/logListing.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { AssetRow, ListingMarket } from '../../types'
|
||||
|
||||
interface Listing extends AssetRow {
|
||||
marketplaces: ListingMarket[]
|
||||
}
|
||||
|
||||
export const logListing = async (listings: AssetRow[], userAddress: string): Promise<boolean> => {
|
||||
const url = `${process.env.REACT_APP_GENIE_API_URL}/logGenieList`
|
||||
const listingsConsolidated: Listing[] = listings.map((el) => ({ ...el, marketplaces: [] }))
|
||||
const marketplacesById: Record<string, ListingMarket[]> = {}
|
||||
const listingsWithMarketsConsolidated = listingsConsolidated.reduce((uniqueListings, curr) => {
|
||||
const key = `${curr.asset.asset_contract.address}-${curr.asset.tokenId}`
|
||||
if (marketplacesById[key]) {
|
||||
marketplacesById[key].push(curr.marketplace)
|
||||
} else {
|
||||
marketplacesById[key] = [curr.marketplace]
|
||||
}
|
||||
if (!uniqueListings.some((listing) => `${listing.asset.asset_contract.address}-${listing.asset.tokenId}` === key)) {
|
||||
curr.marketplaces = marketplacesById[key]
|
||||
uniqueListings.push(curr)
|
||||
}
|
||||
return uniqueListings
|
||||
}, [] as Listing[])
|
||||
const payload = {
|
||||
listings: listingsWithMarketsConsolidated,
|
||||
userAddress,
|
||||
}
|
||||
const r = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
})
|
||||
return r.status === 200
|
||||
}
|
13
src/nft/queries/genie/triggerPriceUpdatesForCollection.ts
Normal file
13
src/nft/queries/genie/triggerPriceUpdatesForCollection.ts
Normal file
@ -0,0 +1,13 @@
|
||||
export const triggerPriceUpdatesForCollection = async (address: string) => {
|
||||
const url = `${process.env.REACT_APP_GENIE_API_URL}/collections/refresh`
|
||||
const r = await fetch(url, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
address,
|
||||
}),
|
||||
})
|
||||
return r.json()
|
||||
}
|
4
src/nft/queries/index.ts
Normal file
4
src/nft/queries/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export * from './genie'
|
||||
export * from './looksRare'
|
||||
export * from './openSea'
|
||||
export * from './x2y2'
|
16
src/nft/queries/looksRare/createLooksRareOrder.ts
Normal file
16
src/nft/queries/looksRare/createLooksRareOrder.ts
Normal file
@ -0,0 +1,16 @@
|
||||
export const createLooksRareOrder = async (payload: any): Promise<boolean> => {
|
||||
const url = `${process.env.REACT_APP_GENIE_API_URL}/createLooksRareOrder`
|
||||
const res = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
})
|
||||
try {
|
||||
const data = await res.json()
|
||||
return data.code === 200
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
3
src/nft/queries/looksRare/index.ts
Normal file
3
src/nft/queries/looksRare/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from './createLooksRareOrder'
|
||||
export * from './looksRareNonceFetcher'
|
||||
export * from './looksRareRewardsFetcher'
|
14
src/nft/queries/looksRare/looksRareNonceFetcher.ts
Normal file
14
src/nft/queries/looksRare/looksRareNonceFetcher.ts
Normal file
@ -0,0 +1,14 @@
|
||||
const looksRareApiAddress = 'https://api.looksrare.org/api/v1'
|
||||
|
||||
export const looksRareNonceFetcher = async (address: any): Promise<number | undefined> => {
|
||||
const res = await fetch(`${looksRareApiAddress}/orders/nonce?address=${address}`)
|
||||
|
||||
if (res.status !== 200) {
|
||||
console.log(`LooksRare nonce API errored with status ${res.statusText}`)
|
||||
return
|
||||
}
|
||||
|
||||
const json = await res.json()
|
||||
|
||||
return parseFloat(json.data)
|
||||
}
|
13
src/nft/queries/looksRare/looksRareRewardsFetcher.ts
Normal file
13
src/nft/queries/looksRare/looksRareRewardsFetcher.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { LooksRareRewardsData } from '../../types'
|
||||
|
||||
const looksRareApiAddress = 'https://api.looksrare.org/api/v1'
|
||||
|
||||
export const looksRareRewardsFetcher = async (address: any): Promise<LooksRareRewardsData | string> => {
|
||||
const res = await fetch(`${looksRareApiAddress}/rewards?address=${address}`)
|
||||
|
||||
if (res.status !== 200) throw new Error(`LooksRare rewards API errored with status ${res.statusText}`)
|
||||
|
||||
const json = await res.json()
|
||||
|
||||
return json.data
|
||||
}
|
30
src/nft/queries/openSea/OSCollectionsFetcher.ts
Normal file
30
src/nft/queries/openSea/OSCollectionsFetcher.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { WalletCollection } from '../../types'
|
||||
|
||||
export const OSCollectionsFetcher = async ({ params }: any): Promise<WalletCollection[]> => {
|
||||
let hasEmptyFields = false
|
||||
|
||||
for (const v of Object.values(params)) {
|
||||
if (v === undefined) {
|
||||
hasEmptyFields = true
|
||||
}
|
||||
}
|
||||
if (hasEmptyFields) return []
|
||||
|
||||
const r = await fetch(`https://api.opensea.io/api/v1/collections?${new URLSearchParams(params).toString()}`)
|
||||
const walletCollections = await r.json()
|
||||
if (walletCollections) {
|
||||
return walletCollections
|
||||
.filter(
|
||||
(collection: any) =>
|
||||
collection.primary_asset_contracts.length && collection.primary_asset_contracts[0].schema_name === 'ERC721'
|
||||
)
|
||||
.map((collection: any) => ({
|
||||
address: collection.primary_asset_contracts[0].address,
|
||||
name: collection.name,
|
||||
image: collection.image_url,
|
||||
count: collection.owned_asset_count,
|
||||
}))
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
}
|
76
src/nft/queries/openSea/PostOpenSeaSellOrder.ts
Normal file
76
src/nft/queries/openSea/PostOpenSeaSellOrder.ts
Normal file
@ -0,0 +1,76 @@
|
||||
import { OPENSEA_BASE_API_PATH } from 'nft/queries/openSea'
|
||||
|
||||
export async function PostOpenSeaSellOrder<T>(
|
||||
apiPath: string,
|
||||
body?: Record<string, unknown>,
|
||||
opts: RequestInit = {}
|
||||
): Promise<T> {
|
||||
const fetchOpts = {
|
||||
method: 'POST',
|
||||
body: body ? JSON.stringify(body) : undefined,
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
...opts,
|
||||
}
|
||||
|
||||
const response = await _fetch(apiPath, fetchOpts)
|
||||
return response.json()
|
||||
}
|
||||
|
||||
async function _fetch(apiPath: string, opts: RequestInit = {}) {
|
||||
const apiBase = OPENSEA_BASE_API_PATH
|
||||
const finalUrl = apiBase + apiPath
|
||||
const finalOpts = {
|
||||
...opts,
|
||||
headers: {
|
||||
...(opts.headers || {}),
|
||||
},
|
||||
}
|
||||
|
||||
return fetch(finalUrl, finalOpts).then(async (res) => _handleApiResponse(res))
|
||||
}
|
||||
|
||||
async function _handleApiResponse(response: Response) {
|
||||
if (response.ok) {
|
||||
return response
|
||||
}
|
||||
|
||||
let result
|
||||
let errorMessage
|
||||
try {
|
||||
result = await response.text()
|
||||
result = JSON.parse(result)
|
||||
} catch {
|
||||
// Result will be undefined or text
|
||||
}
|
||||
|
||||
switch (response.status) {
|
||||
case 400:
|
||||
errorMessage = result && result.errors ? result.errors.join(', ') : `Invalid request: ${JSON.stringify(result)}`
|
||||
break
|
||||
case 401:
|
||||
case 403:
|
||||
errorMessage = `Unauthorized. Full message was '${JSON.stringify(result)}'`
|
||||
break
|
||||
case 404:
|
||||
errorMessage = `Not found. Full message was '${JSON.stringify(result)}'`
|
||||
break
|
||||
case 500:
|
||||
errorMessage = `Internal server error. OpenSea has been alerted, but if the problem persists please contact us via Discord: https://discord.gg/ga8EJbv - full message was ${JSON.stringify(
|
||||
result
|
||||
)}`
|
||||
break
|
||||
case 503:
|
||||
errorMessage = `Service unavailable. Please try again in a few minutes. If the problem persists please contact us via Discord: https://discord.gg/ga8EJbv - full message was ${JSON.stringify(
|
||||
result
|
||||
)}`
|
||||
break
|
||||
default:
|
||||
errorMessage = `Message: ${JSON.stringify(result)}`
|
||||
break
|
||||
}
|
||||
|
||||
throw new Error(`API Error ${response.status}: ${errorMessage}`)
|
||||
}
|
10
src/nft/queries/openSea/constants.ts
Normal file
10
src/nft/queries/openSea/constants.ts
Normal file
@ -0,0 +1,10 @@
|
||||
export const OPENSEA_BASE_API_PATH = 'https://api.opensea.io'
|
||||
export const OPENSEA_FEE_ADDRESS = '0x8de9c5a032463c561423387a9648c5c7bcc5bc90'
|
||||
export const OPENSEA_DEFAULT_ZONE = '0x004c00500000ad104d7dbd00e3ae0a5c00560c00'
|
||||
export const OPENSEA_LISTINGS_API_PATH = '/v2/orders/ethereum/seaport/listings'
|
||||
export const OPENSEA_DEFAULT_CROSS_CHAIN_CONDUIT_KEY =
|
||||
'0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000'
|
||||
export const OPENSEA_CROSS_CHAIN_CONDUIT = '0x1e0049783f008a0085193e00003d00cd54003c71'
|
||||
export const OPENSEA_KEY_TO_CONDUIT = { [OPENSEA_DEFAULT_CROSS_CHAIN_CONDUIT_KEY]: OPENSEA_CROSS_CHAIN_CONDUIT }
|
||||
export const OPENSEA_DEFAULT_FEE = 0.025
|
||||
export const INVERSE_BASIS_POINTS = 10000
|
3
src/nft/queries/openSea/index.ts
Normal file
3
src/nft/queries/openSea/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from './constants'
|
||||
export * from './OSCollectionsFetcher'
|
||||
export * from './PostOpenSeaSellOrder'
|
25
src/nft/queries/x2y2/index.ts
Normal file
25
src/nft/queries/x2y2/index.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { OrderPayload } from '../../utils/x2y2'
|
||||
|
||||
export const newX2Y2Order = async (payload: OrderPayload): Promise<boolean> => {
|
||||
const body = JSON.stringify(payload)
|
||||
const url = `${process.env.REACT_APP_GENIE_API_URL}/postX2Y2SellOrderWithApiKey`
|
||||
const ac = new AbortController()
|
||||
const req = new Request(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
},
|
||||
body,
|
||||
signal: ac.signal,
|
||||
})
|
||||
const timeout = setTimeout(() => ac.abort(), 60 * 1000)
|
||||
try {
|
||||
const res = await fetch(req)
|
||||
const data = await res.json()
|
||||
return data.code === 200
|
||||
} catch (e) {
|
||||
return false
|
||||
} finally {
|
||||
clearTimeout(timeout)
|
||||
}
|
||||
}
|
39
src/nft/themes/darkTheme.ts
Normal file
39
src/nft/themes/darkTheme.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { Theme, vars } from '../css/sprinkles.css'
|
||||
|
||||
export const darkTheme: Theme = {
|
||||
colors: {
|
||||
error: '#FF494A',
|
||||
textDisconnect: '#FF494A',
|
||||
modalBackdrop: 'linear-gradient(0deg, rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7))',
|
||||
backgroundSecondary: '#23262F',
|
||||
modalClose: 'rgba(255, 255, 255, 0.08)',
|
||||
text: '#fff',
|
||||
modalTextSecondary: 'rgba(255, 255, 255, 0.6)',
|
||||
|
||||
// Bryan's colors from Figma that vary dark vs light
|
||||
blackBlue: '#FFFFFF',
|
||||
blackBlue20: '#FFFFFF20',
|
||||
darkGray: vars.color.grey300,
|
||||
medGray: `#99A1BD3D`,
|
||||
lightGray: vars.color.grey900,
|
||||
white: '#000000',
|
||||
darkGray10: `#99A1BD1A`,
|
||||
explicitWhite: '#FFFFFF',
|
||||
magicGradient: vars.color.blue400,
|
||||
placeholder: vars.color.grey400,
|
||||
lightGrayButton: vars.color.grey700,
|
||||
lightGrayContainer: `#99A1BD14`,
|
||||
lightGrayOverlay: '#35373F',
|
||||
|
||||
// Opacities of black and white
|
||||
white95: '#0E111AF2',
|
||||
white90: '#000000E5',
|
||||
white80: '#000000CC',
|
||||
},
|
||||
shadows: {
|
||||
menu: '0px 10px 30px rgba(0, 0, 0, 0.1)',
|
||||
genieBlue: '0 4px 16px 0 rgba(70, 115, 250, 0.4)',
|
||||
elevation: '0px 4px 16px rgba(70, 115, 250, 0.4)',
|
||||
tooltip: '0px 4px 16px rgba(255, 255, 255, 0.2)',
|
||||
},
|
||||
}
|
39
src/nft/themes/lightTheme.ts
Normal file
39
src/nft/themes/lightTheme.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { Theme, vars } from '../css/sprinkles.css'
|
||||
|
||||
export const lightTheme: Theme = {
|
||||
colors: {
|
||||
error: '#FF494A',
|
||||
textDisconnect: '#FF494A',
|
||||
modalBackdrop: 'rgba(0, 0, 0, 0.3)',
|
||||
backgroundSecondary: '#FCFCFD',
|
||||
modalClose: 'rgba(60, 66, 82, 0.06)',
|
||||
text: '#25292E',
|
||||
modalTextSecondary: 'rgba(60, 66, 82, 0.6)',
|
||||
|
||||
// Bryan's colors from Figma that vary dark vs light
|
||||
blackBlue: vars.color.grey900,
|
||||
blackBlue20: `#0E111A33`,
|
||||
darkGray: vars.color.grey500,
|
||||
medGray: `#5E68873D`,
|
||||
lightGray: vars.color.grey50,
|
||||
white: '#FFFFFF',
|
||||
darkGray10: `#5E68871A`,
|
||||
explicitWhite: '#FFFFFF',
|
||||
magicGradient: vars.color.pink400,
|
||||
placeholder: vars.color.grey300,
|
||||
lightGrayButton: vars.color.grey100,
|
||||
lightGrayContainer: vars.color.grey100,
|
||||
lightGrayOverlay: '#E6E8F0',
|
||||
|
||||
// Opacities of black and white
|
||||
white95: '#EDEFF7F2',
|
||||
white90: '#FFFFFFE5',
|
||||
white80: '#FFFFFFCC',
|
||||
},
|
||||
shadows: {
|
||||
menu: '0px 10px 30px rgba(0, 0, 0, 0.1)',
|
||||
genieBlue: '0 4px 16px 0 rgba(251, 17, 142)',
|
||||
elevation: '0px 4px 16px rgba(70, 115, 250, 0.4)',
|
||||
tooltip: '0px 4px 16px rgba(10, 10, 59, 0.2)',
|
||||
},
|
||||
}
|
75
src/nft/types/checkout/checkout.ts
Normal file
75
src/nft/types/checkout/checkout.ts
Normal file
@ -0,0 +1,75 @@
|
||||
import { ContractReceipt } from '@ethersproject/contracts'
|
||||
|
||||
import { GenieAsset, Markets, PriceInfo, TokenType } from '../common'
|
||||
|
||||
export interface UpdatedGenieAsset extends GenieAsset {
|
||||
updatedPriceInfo?: PriceInfo
|
||||
isUnavailable?: boolean
|
||||
orderSource?: 'api' | 'stored' | string
|
||||
}
|
||||
|
||||
export enum RoutingActions {
|
||||
Buy = 'Buy',
|
||||
Sell = 'Sell',
|
||||
Swap = 'Swap',
|
||||
}
|
||||
|
||||
export type SellItem = {
|
||||
id?: string
|
||||
symbol?: string
|
||||
name: string
|
||||
decimals: number
|
||||
address: string
|
||||
priceInfo: PriceInfo
|
||||
tokenType: TokenType
|
||||
tokenId: string
|
||||
amount: string // convert to BigNumber
|
||||
marketplace?: Markets
|
||||
}
|
||||
|
||||
export type BuyItem = {
|
||||
id?: string
|
||||
symbol?: string
|
||||
name: string
|
||||
decimals: number
|
||||
address: string
|
||||
priceInfo: PriceInfo
|
||||
tokenType: TokenType
|
||||
tokenId: string
|
||||
amount: string // convert to BigNumber
|
||||
marketplace: Markets
|
||||
collectionName?: string
|
||||
orderSource?: 'api' | 'stored' | string
|
||||
}
|
||||
|
||||
export type RoutingItem = {
|
||||
action: RoutingActions
|
||||
marketplace: string
|
||||
amountIn: string
|
||||
assetIn: SellItem | PriceInfo
|
||||
amountOut: string
|
||||
assetOut: BuyItem | PriceInfo
|
||||
}
|
||||
|
||||
export interface RouteResponse {
|
||||
valueToSend: string
|
||||
route: RoutingItem[]
|
||||
data: any
|
||||
to: any
|
||||
}
|
||||
|
||||
export interface TxResponse {
|
||||
nftsPurchased: UpdatedGenieAsset[]
|
||||
nftsNotPurchased: UpdatedGenieAsset[]
|
||||
txReceipt: ContractReceipt
|
||||
}
|
||||
|
||||
export enum TxStateType {
|
||||
Success = 'Success',
|
||||
Denied = 'Denied',
|
||||
Invalid = 'Invalid',
|
||||
Failed = 'Failed',
|
||||
New = 'New',
|
||||
Signing = 'Signing',
|
||||
Confirming = 'Confirming',
|
||||
}
|
1
src/nft/types/checkout/index.ts
Normal file
1
src/nft/types/checkout/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './checkout'
|
101
src/nft/types/collection/collection.ts
Normal file
101
src/nft/types/collection/collection.ts
Normal file
@ -0,0 +1,101 @@
|
||||
import { Markets, TokenType } from '../common'
|
||||
export interface AssetPayload {
|
||||
filters: {
|
||||
traits?: Record<string, string[]>
|
||||
address: string
|
||||
currentEthPrice?: {
|
||||
$gte?: number
|
||||
$lte?: number
|
||||
}
|
||||
numTraits?: { traitCount: string }[]
|
||||
name?: string
|
||||
searchText?: string
|
||||
notForSale?: boolean
|
||||
tokenId?: string
|
||||
}
|
||||
fields?: Record<string, number>
|
||||
limit: number
|
||||
offset?: number
|
||||
sort?: CollectionSort
|
||||
markets?: string[]
|
||||
}
|
||||
|
||||
export interface CollectionInfoForAsset {
|
||||
collectionSymbol: string
|
||||
collectionDescription: string | null
|
||||
collectionImageUrl: string
|
||||
collectionName: string
|
||||
isVerified: boolean
|
||||
totalSupply: number
|
||||
}
|
||||
|
||||
export type CollectionSort = Record<
|
||||
string,
|
||||
'asc' | 'desc' | 1 | -1 | { $gte?: string | number; $lte?: string | number } | string | number
|
||||
>
|
||||
|
||||
export enum UniformHeight {
|
||||
unset,
|
||||
notUniform,
|
||||
}
|
||||
|
||||
export enum ActivityEventType {
|
||||
Listing = 'LISTING',
|
||||
Sale = 'SALE',
|
||||
CancelListing = 'CANCEL_LISTING',
|
||||
Transfer = 'TRANSFER',
|
||||
}
|
||||
|
||||
export enum OrderStatus {
|
||||
VALID = 'VALID',
|
||||
EXECUTED = 'EXECUTED',
|
||||
CANCELLED = 'CANCELLED',
|
||||
EXPIRED = 'EXPIRED',
|
||||
}
|
||||
|
||||
export interface ActivityFilter {
|
||||
collectionAddress?: string
|
||||
eventTypes?: ActivityEventType[]
|
||||
marketplaces?: Markets[]
|
||||
}
|
||||
|
||||
export interface ActivityEventResponse {
|
||||
events: ActivityEvent[]
|
||||
cursor?: string
|
||||
}
|
||||
|
||||
export interface TokenRarity {
|
||||
rank: number
|
||||
score: number
|
||||
source: string
|
||||
}
|
||||
|
||||
export interface TokenMetadata {
|
||||
name: string
|
||||
imageUrl: string
|
||||
smallImageUrl: string
|
||||
metadataUrl: string
|
||||
rarity: TokenRarity
|
||||
suspiciousFlag: boolean
|
||||
suspiciousFlaggedBy: string
|
||||
standard: TokenType
|
||||
}
|
||||
|
||||
export interface ActivityEvent {
|
||||
collectionAddress: string
|
||||
tokenId?: string
|
||||
tokenMetadata?: TokenMetadata
|
||||
eventType: ActivityEventType
|
||||
marketplace?: Markets
|
||||
fromAddress: string
|
||||
toAddress?: string
|
||||
transactionHash?: string
|
||||
orderHash?: string
|
||||
orderStatus?: OrderStatus
|
||||
price?: string
|
||||
symbol?: string
|
||||
quantity?: number
|
||||
auctionType?: string
|
||||
url?: string
|
||||
eventTimestamp?: number
|
||||
}
|
1
src/nft/types/collection/index.ts
Normal file
1
src/nft/types/collection/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './collection'
|
183
src/nft/types/common/common.ts
Normal file
183
src/nft/types/common/common.ts
Normal file
@ -0,0 +1,183 @@
|
||||
import { SellOrder } from '../sell'
|
||||
|
||||
export interface OpenSeaCollection {
|
||||
name: string
|
||||
slug: string
|
||||
image_url: string
|
||||
description: string
|
||||
external_url: string
|
||||
featured: boolean
|
||||
hidden: boolean
|
||||
safelist_request_status: string
|
||||
is_subject_to_whitelist: boolean
|
||||
large_image_url: string
|
||||
only_proxied_transfers: boolean
|
||||
payout_address: string
|
||||
}
|
||||
|
||||
export interface OpenSeaAsset {
|
||||
id?: number
|
||||
image_url?: string
|
||||
image_preview_url?: string
|
||||
name?: string
|
||||
token_id?: string
|
||||
last_sale?: {
|
||||
total_price: string
|
||||
}
|
||||
asset_contract?: {
|
||||
address: string
|
||||
schema_name: 'ERC1155' | 'ERC721' | string
|
||||
asset_contract_type: string
|
||||
created_date: string
|
||||
name: string
|
||||
symbol: string
|
||||
description: string
|
||||
external_link: string
|
||||
image_url: string
|
||||
default_to_fiat: boolean
|
||||
only_proxied_transfers: boolean
|
||||
payout_address: string
|
||||
}
|
||||
collection?: OpenSeaCollection
|
||||
}
|
||||
|
||||
interface OpenSeaUser {
|
||||
user?: null
|
||||
profile_img_url: string
|
||||
address: string
|
||||
config: string
|
||||
}
|
||||
|
||||
export enum TokenType {
|
||||
ERC20 = 'ERC20',
|
||||
ERC721 = 'ERC721',
|
||||
ERC1155 = 'ERC1155',
|
||||
Dust = 'Dust',
|
||||
Cryptopunk = 'Cryptopunk',
|
||||
}
|
||||
|
||||
export interface PriceInfo {
|
||||
ETHPrice: string
|
||||
USDPrice: string
|
||||
baseAsset: string
|
||||
baseDecimals: string
|
||||
basePrice: string
|
||||
}
|
||||
|
||||
export interface AssetSellOrder {
|
||||
ammFeePercent: number
|
||||
ethReserves: number
|
||||
tokenReserves: number
|
||||
}
|
||||
|
||||
export interface Rarity {
|
||||
primaryProvider: string
|
||||
providers: { provider: string; rank: number; url: string; score: number }[]
|
||||
}
|
||||
|
||||
export interface GenieAsset {
|
||||
id?: string // This would be a random id created and assigned by front end
|
||||
address: string
|
||||
notForSale: boolean
|
||||
collectionName: string
|
||||
collectionSymbol: string
|
||||
currentEthPrice: string
|
||||
currentUsdPrice: string
|
||||
imageUrl: string
|
||||
animationUrl: string
|
||||
marketplace: string
|
||||
name: string
|
||||
priceInfo: PriceInfo
|
||||
openseaSusFlag: boolean
|
||||
sellorders: SellOrder[]
|
||||
smallImageUrl: string
|
||||
tokenId: string
|
||||
tokenType: TokenType
|
||||
url: string
|
||||
totalCount?: number // The totalCount from the query to /assets
|
||||
amount?: number
|
||||
decimals?: number
|
||||
collectionIsVerified?: boolean
|
||||
rarity?: Rarity
|
||||
owner: OpenSeaUser
|
||||
creator: OpenSeaUser
|
||||
externalLink: string
|
||||
traits?: {
|
||||
trait_type: string
|
||||
value: string
|
||||
display_type?: any
|
||||
max_value?: any
|
||||
trait_count: number
|
||||
order?: any
|
||||
}[]
|
||||
}
|
||||
|
||||
export interface GenieCollection {
|
||||
collectionAddress: string
|
||||
address: string
|
||||
indexingStatus: string
|
||||
isVerified: boolean
|
||||
name: string
|
||||
description: string
|
||||
standard: string
|
||||
bannerImageUrl?: string
|
||||
floorPrice: number
|
||||
stats: {
|
||||
num_owners: number
|
||||
floor_price: number
|
||||
one_day_volume: number
|
||||
one_day_change: number
|
||||
one_day_floor_change: number
|
||||
banner_image_url: string
|
||||
total_supply: number
|
||||
total_listings: number
|
||||
total_volume: number
|
||||
}
|
||||
symbol: string
|
||||
traits: {
|
||||
trait_type: string
|
||||
trait_value: string
|
||||
trait_count: number
|
||||
floorSellOrder: PriceInfo
|
||||
floorPrice: number
|
||||
}[]
|
||||
numTraitsByAmount: { traitCount: number; numWithTrait: number }[]
|
||||
indexingStats: { openSea: { successfulExecutionDate: string; lastRequestedAt: string } }
|
||||
marketplaceCount?: { marketplace: string; count: number }[]
|
||||
imageUrl: string
|
||||
twitter?: string
|
||||
instagram?: string
|
||||
discordUrl?: string
|
||||
externalUrl?: string
|
||||
rarityVerified?: boolean
|
||||
isFoundation?: boolean
|
||||
}
|
||||
|
||||
export enum Markets {
|
||||
NFT20 = 'nft20',
|
||||
NFTX = 'nftx',
|
||||
Opensea = 'opensea',
|
||||
Rarible = 'rarible',
|
||||
Uniswap = 'Uniswap',
|
||||
Uniswap_V2 = 'Uniswap_V2',
|
||||
SushiSwap = 'SushiSwap',
|
||||
SuperRare = 'superrare',
|
||||
KnownOrigin = 'knownorigin',
|
||||
WETH = 'weth',
|
||||
Cryptopunks = 'cryptopunks',
|
||||
CryptoPhunks = 'cryptophunks',
|
||||
}
|
||||
|
||||
export enum ToolTipType {
|
||||
pool,
|
||||
sus,
|
||||
}
|
||||
|
||||
// index starts at 1 for boolean reasons
|
||||
export interface DropDownOption {
|
||||
displayText: string
|
||||
icon?: JSX.Element
|
||||
onClick: () => void
|
||||
reverseIndex?: number
|
||||
reverseOnClick?: () => void
|
||||
}
|
1
src/nft/types/common/index.ts
Normal file
1
src/nft/types/common/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './common'
|
77
src/nft/types/discover/discover.ts
Normal file
77
src/nft/types/discover/discover.ts
Normal file
@ -0,0 +1,77 @@
|
||||
export enum TimePeriod {
|
||||
OneDay = 'ONE_DAY',
|
||||
SevenDays = 'SEVEN_DAYS',
|
||||
ThirtyDays = 'THIRTY_DAYS',
|
||||
AllTime = 'ALL_TIME',
|
||||
}
|
||||
|
||||
export type VolumeType = 'nft' | 'eth'
|
||||
export interface TransactionsResponse {
|
||||
__v: number
|
||||
_id: string
|
||||
bannerImage: string
|
||||
blockNumber: string
|
||||
blockTimestamp: string
|
||||
collections: [string]
|
||||
createdAt: string
|
||||
ethValue: number
|
||||
from_address: string
|
||||
gas: string
|
||||
gasPrice: string
|
||||
hash: string
|
||||
isVerified: boolean
|
||||
nftCount: number
|
||||
profileImage: string
|
||||
receiptContractAddress: string | null
|
||||
receiptCumulatioveGasUsed: string
|
||||
receiptGasUsed: string
|
||||
receiptStatus: string
|
||||
sweep: boolean
|
||||
timestamp: string
|
||||
to_address: string
|
||||
updatedAt: string
|
||||
usdValue: number
|
||||
title: string
|
||||
}
|
||||
|
||||
export interface TrendingCollection {
|
||||
name: string
|
||||
address: string
|
||||
imageUrl: string
|
||||
bannerImageUrl: string
|
||||
isVerified: boolean
|
||||
volume: number
|
||||
volumeChange: number
|
||||
floor: number
|
||||
floorChange: number
|
||||
marketCap: number
|
||||
percentListed: number
|
||||
owners: number
|
||||
ownersChange: number
|
||||
totalSupply: number
|
||||
sales: number
|
||||
}
|
||||
|
||||
export interface CollectionTableColumn {
|
||||
collection: {
|
||||
name: string
|
||||
address: string
|
||||
logo: string
|
||||
isVerified: boolean
|
||||
}
|
||||
volume: {
|
||||
value: number
|
||||
change: number
|
||||
type: VolumeType
|
||||
}
|
||||
floor: {
|
||||
value: number
|
||||
change: number
|
||||
}
|
||||
owners: {
|
||||
value: number
|
||||
change: number
|
||||
}
|
||||
sales: number
|
||||
totalSupply: number
|
||||
}
|
1
src/nft/types/discover/index.ts
Normal file
1
src/nft/types/discover/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './discover'
|
21
src/nft/types/discover/react-table-config.d.ts
vendored
Normal file
21
src/nft/types/discover/react-table-config.d.ts
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
import { UseSortByColumnOptions, UseSortByColumnProps, UseSortByOptions, UseSortByState } from 'react-table'
|
||||
|
||||
/* https://github.com/TanStack/table/issues/2970 */
|
||||
declare module 'react-table' {
|
||||
export interface TableOptions<D extends Record<string, unknown>>
|
||||
extends UseExpandedOptions<D>,
|
||||
UseSortByOptions<D>,
|
||||
Record<string, any> {}
|
||||
|
||||
export interface TableState<D extends Record<string, unknown> = Record<string, unknown>>
|
||||
extends UseColumnOrderState<D>,
|
||||
UseSortByState<D> {}
|
||||
|
||||
export interface ColumnInterface<D extends Record<string, unknown> = Record<string, unknown>>
|
||||
extends UseFiltersColumnOptions<D>,
|
||||
UseSortByColumnOptions<D> {}
|
||||
|
||||
export interface ColumnInstance<D extends Record<string, unknown> = Record<string, unknown>>
|
||||
extends UseFiltersColumnProps<D>,
|
||||
UseSortByColumnProps<D> {}
|
||||
}
|
6
src/nft/types/index.ts
Normal file
6
src/nft/types/index.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export * from './checkout'
|
||||
export * from './collection'
|
||||
export * from './common'
|
||||
export * from './discover'
|
||||
export * from './navbar'
|
||||
export * from './sell'
|
1
src/nft/types/navbar/index.ts
Normal file
1
src/nft/types/navbar/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './navbar'
|
20
src/nft/types/navbar/navbar.ts
Normal file
20
src/nft/types/navbar/navbar.ts
Normal file
@ -0,0 +1,20 @@
|
||||
export interface LooksRareRewardsData {
|
||||
address: string
|
||||
cumulativeLooksAmount: string
|
||||
cumulativeLooksProof: string[]
|
||||
}
|
||||
|
||||
export interface FungibleToken {
|
||||
name: string
|
||||
address: string
|
||||
symbol: string
|
||||
decimals: number
|
||||
chainId: number
|
||||
logoURI: string
|
||||
coinGeckoId: string
|
||||
priceUsd: number
|
||||
price24hChange: number
|
||||
volume24h: number
|
||||
onDefaultList?: boolean
|
||||
marketCap: number
|
||||
}
|
1
src/nft/types/sell/index.ts
Normal file
1
src/nft/types/sell/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './sell'
|
117
src/nft/types/sell/sell.ts
Normal file
117
src/nft/types/sell/sell.ts
Normal file
@ -0,0 +1,117 @@
|
||||
import { GenieCollection } from '../common'
|
||||
|
||||
export interface ListingMarket {
|
||||
name: string
|
||||
fee: number
|
||||
icon: string
|
||||
}
|
||||
export interface ListingWarning {
|
||||
marketplace: ListingMarket
|
||||
message: string
|
||||
}
|
||||
|
||||
export interface SellOrder {
|
||||
assetId: string
|
||||
ethPrice: number
|
||||
basePrice: number
|
||||
baseCurrency: string
|
||||
baseCurrencyDecimal: number
|
||||
orderCreatedDate: string
|
||||
orderClosingDate: string
|
||||
quantity: number
|
||||
timestamp: string
|
||||
marketplace: string
|
||||
marketplaceUrl: string
|
||||
orderHash: string
|
||||
ammFeePercent?: number
|
||||
ethReserves?: number
|
||||
tokenReserves?: number
|
||||
}
|
||||
|
||||
export interface WalletAsset {
|
||||
id?: string
|
||||
image_url: string
|
||||
image_preview_url: string
|
||||
name: string
|
||||
tokenId: string
|
||||
asset_contract: {
|
||||
address: string
|
||||
schema_name: 'ERC1155' | 'ERC721' | string
|
||||
asset_contract_type: string
|
||||
created_date: string
|
||||
name: string
|
||||
symbol: string
|
||||
description: string
|
||||
external_link: string
|
||||
image_url: string
|
||||
default_to_fiat: boolean
|
||||
only_proxied_transfers: boolean
|
||||
payout_address: string
|
||||
}
|
||||
collection: GenieCollection
|
||||
collectionIsVerified: boolean
|
||||
lastPrice: number
|
||||
floorPrice: number
|
||||
creatorPercentage: number
|
||||
listing_date: string
|
||||
date_acquired: string
|
||||
sellOrders: SellOrder[]
|
||||
floor_sell_order_price: number
|
||||
// Used for creating new listings
|
||||
expirationTime?: number
|
||||
marketAgnosticPrice?: string
|
||||
newListings?: {
|
||||
price?: string
|
||||
marketplace: ListingMarket
|
||||
overrideFloorPrice?: boolean
|
||||
}[]
|
||||
marketplaces?: ListingMarket[]
|
||||
listingWarnings?: ListingWarning[]
|
||||
}
|
||||
|
||||
export interface WalletCollection {
|
||||
address: string
|
||||
name: string
|
||||
image: string
|
||||
floorPrice: number
|
||||
count: number
|
||||
}
|
||||
|
||||
export enum ListingStatus {
|
||||
APPROVED = 'Approved',
|
||||
CONTINUE = 'Continue',
|
||||
DEFINED = 'Defined',
|
||||
FAILED = 'Failed',
|
||||
PAUSED = 'Paused',
|
||||
PENDING = 'Pending',
|
||||
REJECTED = 'Rejected',
|
||||
SIGNING = 'Signing',
|
||||
}
|
||||
|
||||
export interface ListingRow {
|
||||
images: string[]
|
||||
name: string
|
||||
status: ListingStatus
|
||||
callback?: () => Promise<void>
|
||||
}
|
||||
|
||||
export interface AssetRow extends ListingRow {
|
||||
asset: WalletAsset
|
||||
marketplace: ListingMarket
|
||||
}
|
||||
|
||||
export interface CollectionRow extends ListingRow {
|
||||
collectionAddress: string
|
||||
marketplace: ListingMarket
|
||||
}
|
||||
|
||||
// Creating this as an enum and not boolean as we will likely have a success screen state to show
|
||||
export enum SellPageStateType {
|
||||
SELECTING,
|
||||
LISTING,
|
||||
}
|
||||
|
||||
export enum ListingResponse {
|
||||
TRY_AGAIN,
|
||||
SUCCESS,
|
||||
}
|
19
src/nft/utils/address.ts
Normal file
19
src/nft/utils/address.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { isAddress } from '@ethersproject/address'
|
||||
|
||||
/**
|
||||
* Shortens an Ethereum address by N characters
|
||||
* @param address blockchain address
|
||||
* @param charsStart amount of character to shorten (from both ends / in the beginning)
|
||||
* @param charsEnd amount of characters to shorten in the end
|
||||
* @returns formatted string
|
||||
*/
|
||||
export function shortenAddress(address: string, charsStart = 4, charsEnd?: number): string {
|
||||
const parsed = isAddress(address)
|
||||
if (!parsed) throw Error(`Invalid 'address' parameter '${address}'.`)
|
||||
|
||||
return `${address.substring(0, charsStart + 2)}...${address.substring(42 - (charsEnd || charsStart))}`
|
||||
}
|
||||
|
||||
export function shortenEnsName(name?: string): string | undefined {
|
||||
return !name || name.length <= 12 ? name : `${name.substring(0, 6)}...eth`
|
||||
}
|
34
src/nft/utils/buildActivityAsset.ts
Normal file
34
src/nft/utils/buildActivityAsset.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { BigNumber } from '@ethersproject/bignumber'
|
||||
import { formatEther } from '@ethersproject/units'
|
||||
import { ActivityEvent, GenieAsset } from 'nft/types'
|
||||
|
||||
export const buildActivityAsset = (event: ActivityEvent, collectionName: string, ethPriceInUSD: number): GenieAsset => {
|
||||
const assetUsdPrice = event.price
|
||||
? formatEther(
|
||||
BigNumber.from(event.price)
|
||||
.mul(BigNumber.from(Math.trunc(ethPriceInUSD * 100)))
|
||||
.div(100)
|
||||
)
|
||||
: '0'
|
||||
|
||||
return {
|
||||
address: event.collectionAddress,
|
||||
collectionName,
|
||||
currentEthPrice: event.price,
|
||||
imageUrl: event.tokenMetadata?.imageUrl,
|
||||
marketplace: event.marketplace,
|
||||
name: event.tokenMetadata?.name,
|
||||
tokenId: event.tokenId,
|
||||
openseaSusFlag: event.tokenMetadata?.suspiciousFlag,
|
||||
smallImageUrl: event.tokenMetadata?.smallImageUrl,
|
||||
collectionSymbol: event.symbol,
|
||||
currentUsdPrice: assetUsdPrice,
|
||||
priceInfo: {
|
||||
USDPrice: assetUsdPrice,
|
||||
ETHPrice: event.price,
|
||||
basePrice: event.price,
|
||||
baseAsset: 'ETH',
|
||||
},
|
||||
tokenType: event.tokenMetadata?.standard,
|
||||
} as GenieAsset
|
||||
}
|
16
src/nft/utils/buildSellObject.ts
Normal file
16
src/nft/utils/buildSellObject.ts
Normal file
@ -0,0 +1,16 @@
|
||||
export const buildSellObject = (amount: string) => {
|
||||
return {
|
||||
address: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
|
||||
amount,
|
||||
decimals: 18,
|
||||
name: 'Ethereum',
|
||||
priceInfo: {
|
||||
baseAsset: 'ETH',
|
||||
basePrice: amount,
|
||||
ETHPrice: amount,
|
||||
},
|
||||
symbol: 'ETH',
|
||||
tokenId: 'ETH',
|
||||
tokenType: 'ERC20',
|
||||
}
|
||||
}
|
45
src/nft/utils/calcPoolPrice.ts
Normal file
45
src/nft/utils/calcPoolPrice.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import { BigNumber } from '@ethersproject/bignumber'
|
||||
|
||||
import { GenieAsset, Markets } from '../types'
|
||||
|
||||
export const calcPoolPrice = (asset: GenieAsset, position = 0) => {
|
||||
let amountToBuy: BigNumber = BigNumber.from(0)
|
||||
let marginalBuy: BigNumber = BigNumber.from(0)
|
||||
const nft = asset.sellorders[0]
|
||||
const decimals = BigNumber.from(1).mul(10).pow(18)
|
||||
const ammFee = nft.ammFeePercent ? (100 + nft.ammFeePercent) * 100 : 110 * 100
|
||||
|
||||
if (asset.marketplace === Markets.NFTX) {
|
||||
const sixteenmul = BigNumber.from(1).mul(10).pow(16)
|
||||
amountToBuy = BigNumber.from(ammFee)
|
||||
.div(100)
|
||||
.mul(position + 1)
|
||||
amountToBuy = amountToBuy.mul(sixteenmul)
|
||||
|
||||
marginalBuy = BigNumber.from(ammFee).div(100).mul(position)
|
||||
marginalBuy = marginalBuy.mul(sixteenmul)
|
||||
}
|
||||
if (asset.marketplace === Markets.NFT20) {
|
||||
amountToBuy = BigNumber.from(100).mul(position + 1)
|
||||
amountToBuy = amountToBuy.mul(decimals)
|
||||
|
||||
marginalBuy = BigNumber.from(100).mul(position)
|
||||
marginalBuy = marginalBuy.mul(decimals)
|
||||
}
|
||||
|
||||
const ethReserves = BigNumber.from(nft.ethReserves?.toLocaleString('fullwide', { useGrouping: false }))
|
||||
const tokenReserves = BigNumber.from(nft.tokenReserves?.toLocaleString('fullwide', { useGrouping: false }))
|
||||
const numerator = ethReserves.mul(amountToBuy).mul(1000)
|
||||
const denominator = tokenReserves.sub(amountToBuy).mul(997)
|
||||
|
||||
const marginalnumerator = ethReserves.mul(marginalBuy).mul(1000)
|
||||
const marginaldenominator = tokenReserves.sub(marginalBuy).mul(997)
|
||||
|
||||
let price = numerator.div(denominator)
|
||||
const marginalprice = marginalnumerator.div(marginaldenominator)
|
||||
|
||||
price = price.sub(marginalprice)
|
||||
price = price.mul(101).div(100)
|
||||
|
||||
return price.toString()
|
||||
}
|
48
src/nft/utils/claimLooks.ts
Normal file
48
src/nft/utils/claimLooks.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import { Signer } from '@ethersproject/abstract-signer'
|
||||
import { Contract } from '@ethersproject/contracts'
|
||||
import { BaseProvider } from '@ethersproject/providers'
|
||||
|
||||
const looksRareContract = new Contract('0xea37093ce161f090e443f304e1bf3a8f14d7bb40', [
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{ indexed: true, internalType: 'address', name: 'user', type: 'address' },
|
||||
{ indexed: true, internalType: 'uint256', name: 'rewardRound', type: 'uint256' },
|
||||
{ indexed: false, internalType: 'uint256', name: 'amount', type: 'uint256' },
|
||||
],
|
||||
name: 'RewardsClaim',
|
||||
type: 'event',
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{ internalType: 'uint256', name: 'amount', type: 'uint256' },
|
||||
{ internalType: 'bytes32[]', name: 'merkleProof', type: 'bytes32[]' },
|
||||
],
|
||||
name: 'claim',
|
||||
outputs: [],
|
||||
stateMutability: 'nonpayable',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [{ internalType: 'address', name: '', type: 'address' }],
|
||||
name: 'amountClaimedByUser',
|
||||
outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
|
||||
stateMutability: 'view',
|
||||
type: 'function',
|
||||
},
|
||||
])
|
||||
|
||||
export const getClaimedAmount = async ({ address, provider }: { address: string; provider: BaseProvider }) =>
|
||||
provider && (await looksRareContract.connect(provider).amountClaimedByUser(address))
|
||||
|
||||
export const claimLooks = async ({
|
||||
signer,
|
||||
looksTotal,
|
||||
proof,
|
||||
}: {
|
||||
signer: Signer
|
||||
looksTotal: string
|
||||
proof: string[]
|
||||
}) => {
|
||||
await looksRareContract.connect(signer).functions.claim(looksTotal, proof)
|
||||
}
|
20
src/nft/utils/colors.ts
Normal file
20
src/nft/utils/colors.ts
Normal file
@ -0,0 +1,20 @@
|
||||
export const foregrounds = ['#001FAA', '#5D31FF', '#8EC3E4', '#F10B00', '#E843D3', '#C4B5FC', '#F88DD5']
|
||||
|
||||
export const backgrounds = ['#5DCCB9', '#9AFBCF', '#D1F8E7', '#73F54B', '#D3FB51', '#FCF958']
|
||||
|
||||
export function hashCode(text: string) {
|
||||
let hash = 0
|
||||
if (text.length === 0) return hash
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
const chr = text.charCodeAt(i)
|
||||
hash = (hash << 3) - hash + chr
|
||||
hash |= 0
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
export function addressToHashedColor(colors: string[], address: string | null): string | undefined {
|
||||
if (address == null) return undefined
|
||||
|
||||
return colors[Math.abs(hashCode(address.toLowerCase()) % colors.length)]
|
||||
}
|
54
src/nft/utils/currency.ts
Normal file
54
src/nft/utils/currency.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import { formatEther, parseEther } from '@ethersproject/units'
|
||||
|
||||
export const formatUsdPrice = (price: number) => {
|
||||
if (price > 1000000) {
|
||||
return `$${(price / 1000000).toFixed(1)}M`
|
||||
} else if (price > 1000) {
|
||||
return `$${(price / 1000).toFixed(1)}K`
|
||||
} else {
|
||||
return `$${price.toFixed(2)}`
|
||||
}
|
||||
}
|
||||
|
||||
export const formatUSDPriceWithCommas = (price: number) => {
|
||||
return `$${Math.round(price)
|
||||
.toString()
|
||||
.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}`
|
||||
}
|
||||
|
||||
export const formatEthPrice = (price: string) => {
|
||||
if (!price) return 0
|
||||
|
||||
const formattedPrice = parseFloat(formatEther(String(price)))
|
||||
return (
|
||||
Math.round(formattedPrice * (formattedPrice >= 1 ? 100 : 1000) + Number.EPSILON) /
|
||||
(formattedPrice >= 1 ? 100 : 1000)
|
||||
)
|
||||
}
|
||||
|
||||
// Stringify the `price` anyway because the `price` is being passed as any in some places
|
||||
export const numberToWei = (amount: number) => {
|
||||
return parseEther(amount.toString())
|
||||
}
|
||||
|
||||
export const ethNumberStandardFormatter = (amount: string | number | undefined, includeDollarSign = false): string => {
|
||||
if (!amount) return '-'
|
||||
|
||||
const amountInDecimals = parseFloat(amount.toString())
|
||||
const conditionalDollarSign = includeDollarSign ? '$' : ''
|
||||
|
||||
if (amountInDecimals < 0.0001) return `< ${conditionalDollarSign}0.00001`
|
||||
if (amountInDecimals < 1) return `${conditionalDollarSign}${amountInDecimals.toFixed(3)}`
|
||||
return (
|
||||
conditionalDollarSign +
|
||||
amountInDecimals
|
||||
.toFixed(2)
|
||||
.toString()
|
||||
.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
||||
)
|
||||
}
|
||||
|
||||
export const formatWeiToDecimal = (amount: string) => {
|
||||
if (!amount) return '-'
|
||||
return ethNumberStandardFormatter(formatEther(amount))
|
||||
}
|
18
src/nft/utils/date.ts
Normal file
18
src/nft/utils/date.ts
Normal file
@ -0,0 +1,18 @@
|
||||
export const isValidDate = (date: number): boolean => {
|
||||
const d = Date.parse(date.toString())
|
||||
return isNaN(d) ? false : true
|
||||
}
|
||||
|
||||
export const getTimeDifference = (eventTimestamp: string) => {
|
||||
const date = new Date(eventTimestamp).getTime()
|
||||
const diff = new Date().getTime() - date
|
||||
|
||||
const days = Math.floor(diff / (1000 * 60 * 60 * 24))
|
||||
const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))
|
||||
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60))
|
||||
|
||||
if (days > 0) return `${days} day${days > 1 ? 's' : ''} ago`
|
||||
if (hours > 0) return `${hours} hour${hours > 1 ? 's' : ''} ago`
|
||||
if (minutes > 1) return `${minutes} minutes ago`
|
||||
return 'Just now'
|
||||
}
|
72
src/nft/utils/eu-timezones.ts
Normal file
72
src/nft/utils/eu-timezones.ts
Normal file
@ -0,0 +1,72 @@
|
||||
export function consentRequired(tz: string): boolean {
|
||||
switch (tz) {
|
||||
case 'Europe/Vienna':
|
||||
return true
|
||||
case 'Europe/Brussels':
|
||||
return true
|
||||
case 'Europe/Sofia':
|
||||
return true
|
||||
case 'Europe/Zagreb':
|
||||
return true
|
||||
case 'Asia/Famagusta':
|
||||
return true
|
||||
case 'Asia/Nicosia':
|
||||
return true
|
||||
case 'Europe/Prague':
|
||||
return true
|
||||
case 'Europe/Copenhagen':
|
||||
return true
|
||||
case 'Europe/Tallinn':
|
||||
return true
|
||||
case 'Europe/Helsinki':
|
||||
return true
|
||||
case 'Europe/Paris':
|
||||
return true
|
||||
case 'Europe/Berlin':
|
||||
return true
|
||||
case 'Europe/Busingen':
|
||||
return true
|
||||
case 'Europe/Athens':
|
||||
return true
|
||||
case 'Europe/Budapest':
|
||||
return true
|
||||
case 'Europe/Dublin':
|
||||
return true
|
||||
case 'Europe/Rome':
|
||||
return true
|
||||
case 'Europe/Riga':
|
||||
return true
|
||||
case 'Europe/Vilnius':
|
||||
return true
|
||||
case 'Europe/Luxembourg':
|
||||
return true
|
||||
case 'Europe/Malta':
|
||||
return true
|
||||
case 'Europe/Amsterdam':
|
||||
return true
|
||||
case 'Europe/Warsaw':
|
||||
return true
|
||||
case 'Atlantic/Azores':
|
||||
return true
|
||||
case 'Atlantic/Madeira':
|
||||
return true
|
||||
case 'Europe/Lisbon':
|
||||
return true
|
||||
case 'Europe/Bucharest':
|
||||
return true
|
||||
case 'Europe/Bratislava':
|
||||
return true
|
||||
case 'Europe/Ljubljana':
|
||||
return true
|
||||
case 'Africa/Ceuta':
|
||||
return true
|
||||
case 'Atlantic/Canary':
|
||||
return true
|
||||
case 'Europe/Madrid':
|
||||
return true
|
||||
case 'Europe/Stockholm':
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
15
src/nft/utils/fetchPrice.ts
Normal file
15
src/nft/utils/fetchPrice.ts
Normal file
@ -0,0 +1,15 @@
|
||||
export enum Currency {
|
||||
ETH = 'ETH',
|
||||
LOOKS = 'LOOKS',
|
||||
MATIC = 'MATIC',
|
||||
}
|
||||
|
||||
export const fetchPrice = async (currency: Currency = Currency.ETH): Promise<number | undefined> => {
|
||||
try {
|
||||
const response = await fetch(`https://api.coinbase.com/v2/exchange-rates?currency=${currency}`)
|
||||
return response.json().then((j) => j.data.rates.USD)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
return
|
||||
}
|
||||
}
|
6
src/nft/utils/groupBy.ts
Normal file
6
src/nft/utils/groupBy.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export const groupBy = <T>(xs: T[], key: string) => {
|
||||
return xs.reduce((rv: any, x: any) => {
|
||||
;(rv[x[key]] = rv[x[key]] || []).push(x)
|
||||
return rv
|
||||
}, {})
|
||||
}
|
25
src/nft/utils/isAssetOwnedByUser.ts
Normal file
25
src/nft/utils/isAssetOwnedByUser.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { Provider } from '@ethersproject/abstract-provider'
|
||||
import { Contract } from '@ethersproject/contracts'
|
||||
|
||||
import ERC721 from '../../abis/erc721.json'
|
||||
import { TokenType } from '../types'
|
||||
|
||||
export const isAssetOwnedByUser = async ({
|
||||
tokenId,
|
||||
assetAddress,
|
||||
userAddress,
|
||||
tokenType,
|
||||
provider,
|
||||
}: {
|
||||
tokenId: string
|
||||
assetAddress: string
|
||||
userAddress: string
|
||||
tokenType: TokenType
|
||||
provider: Provider
|
||||
}) => {
|
||||
if (tokenType === TokenType.ERC721) {
|
||||
const c = new Contract(assetAddress, ERC721, provider)
|
||||
|
||||
return (await c.functions.ownerOf(tokenId)) === userAddress
|
||||
} else return false
|
||||
}
|
9
src/nft/utils/isAudio.ts
Normal file
9
src/nft/utils/isAudio.ts
Normal file
@ -0,0 +1,9 @@
|
||||
const set = new Set<string>(['mp3', 'wav'])
|
||||
|
||||
export const isAudio = (file: string) => {
|
||||
if (!file) return false
|
||||
|
||||
const fileType = file.substring(file.lastIndexOf('.') + 1)
|
||||
|
||||
return set.has(fileType)
|
||||
}
|
11
src/nft/utils/isIPhoneOrSafari.ts
Normal file
11
src/nft/utils/isIPhoneOrSafari.ts
Normal file
@ -0,0 +1,11 @@
|
||||
const iOSDevices = ['iPhone', 'iPad', 'iPod', 'iPhone Simulator', 'iPod Simulator', 'iPad Simulator']
|
||||
|
||||
export const isIPhoneOrSafari = () => {
|
||||
const uA = navigator.userAgent
|
||||
const vendor = navigator.vendor
|
||||
const platform = navigator.platform
|
||||
|
||||
return (
|
||||
iOSDevices.includes(platform) || (/Safari/i.test(uA) && /Apple Computer/.test(vendor) && !/Mobi|Android/i.test(uA))
|
||||
)
|
||||
}
|
3
src/nft/utils/isVideo.ts
Normal file
3
src/nft/utils/isVideo.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import extensions from 'video-extensions'
|
||||
|
||||
export const isVideo = (path: string | null) => extensions.find((ext) => path?.endsWith(`.${ext}`)) !== undefined
|
268
src/nft/utils/listNfts.ts
Normal file
268
src/nft/utils/listNfts.ts
Normal file
@ -0,0 +1,268 @@
|
||||
import { Signer } from '@ethersproject/abstract-signer'
|
||||
import { BigNumber } from '@ethersproject/bignumber'
|
||||
import { Contract } from '@ethersproject/contracts'
|
||||
import { JsonRpcSigner, Web3Provider } from '@ethersproject/providers'
|
||||
import { parseEther } from '@ethersproject/units'
|
||||
import { addressesByNetwork, MakerOrder, signMakerOrder, SupportedChainId } from '@looksrare/sdk'
|
||||
import { Seaport } from '@opensea/seaport-js'
|
||||
import { ItemType } from '@opensea/seaport-js/lib/constants'
|
||||
import { ConsiderationInputItem } from '@opensea/seaport-js/lib/types'
|
||||
import {
|
||||
OPENSEA_DEFAULT_CROSS_CHAIN_CONDUIT_KEY,
|
||||
OPENSEA_DEFAULT_ZONE,
|
||||
OPENSEA_KEY_TO_CONDUIT,
|
||||
OPENSEA_LISTINGS_API_PATH,
|
||||
} from 'nft/queries/openSea'
|
||||
|
||||
import ERC721 from '../../abis/erc721.json'
|
||||
import { PostOpenSeaSellOrder } from '../queries'
|
||||
import { createLooksRareOrder } from '../queries'
|
||||
import { newX2Y2Order } from '../queries'
|
||||
import { INVERSE_BASIS_POINTS, OPENSEA_DEFAULT_FEE, OPENSEA_FEE_ADDRESS } from '../queries/openSea'
|
||||
import { ListingMarket, WalletAsset } from '../types'
|
||||
import { ListingStatus } from '../types'
|
||||
import { createSellOrder, encodeOrder, OfferItem, OrderPayload, signOrderData } from './x2y2'
|
||||
|
||||
export const ListingMarkets: ListingMarket[] = [
|
||||
{
|
||||
name: 'LooksRare',
|
||||
fee: 2.0,
|
||||
icon: '/nft/svgs/marketplaces/looksrare.svg',
|
||||
},
|
||||
{
|
||||
name: 'OpenSea',
|
||||
fee: 2.5,
|
||||
icon: '/nft/svgs/marketplaces/opensea.svg',
|
||||
},
|
||||
{
|
||||
name: 'X2Y2',
|
||||
fee: 0.5,
|
||||
icon: '/nft/svgs/marketplaces/x2y2.svg',
|
||||
},
|
||||
]
|
||||
|
||||
const createConsiderationItem = (basisPoints: string, recipient: string): ConsiderationInputItem => {
|
||||
return {
|
||||
amount: basisPoints,
|
||||
recipient,
|
||||
}
|
||||
}
|
||||
|
||||
const getConsiderationItems = (
|
||||
asset: WalletAsset,
|
||||
price: BigNumber,
|
||||
signerAddress: string
|
||||
): {
|
||||
sellerFee: ConsiderationInputItem
|
||||
openseaFee: ConsiderationInputItem
|
||||
creatorFee?: ConsiderationInputItem
|
||||
} => {
|
||||
const openSeaBasisPoints = OPENSEA_DEFAULT_FEE * INVERSE_BASIS_POINTS
|
||||
const creatorFeeBasisPoints = asset.creatorPercentage * INVERSE_BASIS_POINTS
|
||||
const sellerBasisPoints = INVERSE_BASIS_POINTS - openSeaBasisPoints - creatorFeeBasisPoints
|
||||
|
||||
const openseaFee = price.mul(BigNumber.from(openSeaBasisPoints)).div(BigNumber.from(INVERSE_BASIS_POINTS)).toString()
|
||||
const creatorFee = price
|
||||
.mul(BigNumber.from(creatorFeeBasisPoints))
|
||||
.div(BigNumber.from(INVERSE_BASIS_POINTS))
|
||||
.toString()
|
||||
const sellerFee = price.mul(BigNumber.from(sellerBasisPoints)).div(BigNumber.from(INVERSE_BASIS_POINTS)).toString()
|
||||
|
||||
return {
|
||||
sellerFee: createConsiderationItem(sellerFee, signerAddress),
|
||||
openseaFee: createConsiderationItem(openseaFee, OPENSEA_FEE_ADDRESS),
|
||||
creatorFee:
|
||||
creatorFeeBasisPoints > 0 ? createConsiderationItem(creatorFee, asset.asset_contract.payout_address) : undefined,
|
||||
}
|
||||
}
|
||||
|
||||
export async function approveCollection(
|
||||
operator: string,
|
||||
collectionAddress: string,
|
||||
signer: Signer,
|
||||
setStatus: (newStatus: ListingStatus) => void
|
||||
): Promise<void> {
|
||||
// This will work for both 721s & 1155s because they both have the
|
||||
// setApprovalForAll() method
|
||||
const ERC721Contract = new Contract(collectionAddress, ERC721, signer)
|
||||
const signerAddress = await signer.getAddress()
|
||||
setStatus(ListingStatus.PENDING)
|
||||
try {
|
||||
const approved = await ERC721Contract.isApprovedForAll(signerAddress, operator)
|
||||
if (approved) {
|
||||
setStatus(ListingStatus.APPROVED)
|
||||
return
|
||||
}
|
||||
|
||||
setStatus(ListingStatus.SIGNING)
|
||||
const approvalTransaction = await ERC721Contract.setApprovalForAll(operator, true)
|
||||
|
||||
setStatus(ListingStatus.PENDING)
|
||||
const tx = await approvalTransaction.wait()
|
||||
|
||||
tx.status === 1 ? setStatus(ListingStatus.APPROVED) : setStatus(ListingStatus.FAILED)
|
||||
} catch (error) {
|
||||
if (error.code === 4001) setStatus(ListingStatus.REJECTED)
|
||||
else setStatus(ListingStatus.FAILED)
|
||||
}
|
||||
}
|
||||
|
||||
export async function signListing(
|
||||
marketplace: ListingMarket,
|
||||
asset: WalletAsset,
|
||||
signer: JsonRpcSigner,
|
||||
provider: Web3Provider,
|
||||
looksRareNonce = 0,
|
||||
setStatus: (newStatus: ListingStatus) => void
|
||||
): Promise<boolean> {
|
||||
const seaport = new Seaport(provider, {
|
||||
conduitKeyToConduit: OPENSEA_KEY_TO_CONDUIT,
|
||||
overrides: {
|
||||
defaultConduitKey: OPENSEA_DEFAULT_CROSS_CHAIN_CONDUIT_KEY,
|
||||
},
|
||||
})
|
||||
|
||||
const signerAddress = await signer.getAddress()
|
||||
const listingPrice = asset.newListings?.find((listing) => listing.marketplace.name === marketplace.name)?.price
|
||||
if (!listingPrice || !asset.expirationTime) return false
|
||||
switch (marketplace.name) {
|
||||
case 'OpenSea':
|
||||
try {
|
||||
const listingInWei = parseEther(listingPrice)
|
||||
const { sellerFee, openseaFee, creatorFee } = getConsiderationItems(asset, listingInWei, signerAddress)
|
||||
const considerationItems = [sellerFee, openseaFee, creatorFee].filter(
|
||||
(item): item is ConsiderationInputItem => item !== undefined
|
||||
)
|
||||
|
||||
const { executeAllActions } = await seaport.createOrder(
|
||||
{
|
||||
offer: [
|
||||
{
|
||||
itemType: ItemType.ERC721,
|
||||
token: asset.asset_contract.address,
|
||||
identifier: asset.tokenId,
|
||||
amount: '1',
|
||||
},
|
||||
],
|
||||
consideration: considerationItems,
|
||||
endTime: asset.expirationTime.toString(),
|
||||
zone: OPENSEA_DEFAULT_ZONE,
|
||||
restrictedByZone: true,
|
||||
allowPartialFills: true,
|
||||
},
|
||||
signerAddress
|
||||
)
|
||||
|
||||
const order = await executeAllActions()
|
||||
const res = await PostOpenSeaSellOrder(OPENSEA_LISTINGS_API_PATH, order)
|
||||
if (res) setStatus(ListingStatus.APPROVED)
|
||||
return true
|
||||
} catch (error) {
|
||||
if (error.code === 4001) setStatus(ListingStatus.REJECTED)
|
||||
else setStatus(ListingStatus.FAILED)
|
||||
return false
|
||||
}
|
||||
case 'LooksRare':
|
||||
const addresses = addressesByNetwork[SupportedChainId.MAINNET]
|
||||
const currentTime = Math.round(Date.now() / 1000)
|
||||
const makerOrder: MakerOrder = {
|
||||
// true --> ask / false --> bid
|
||||
isOrderAsk: true,
|
||||
// signer address of the maker order
|
||||
signer: signerAddress,
|
||||
// collection address
|
||||
collection: asset.asset_contract.address,
|
||||
// Price in WEI
|
||||
price: parseEther(listingPrice.toString()),
|
||||
// Token ID
|
||||
tokenId: BigNumber.from(asset.tokenId),
|
||||
// amount of tokens to sell/purchase (must be 1 for ERC721, 1+ for ERC1155)
|
||||
amount: BigNumber.from(1),
|
||||
// strategy for trade execution (e.g., DutchAuction, StandardSaleForFixedPrice), see addresses in the SDK
|
||||
strategy: addresses.STRATEGY_STANDARD_SALE,
|
||||
// currency address
|
||||
currency: addresses.WETH,
|
||||
// order nonce (must be unique unless new maker order is meant to override existing one e.g., lower ask price)
|
||||
nonce: BigNumber.from(looksRareNonce),
|
||||
// startTime timestamp in seconds
|
||||
startTime: BigNumber.from(currentTime),
|
||||
// endTime timestamp in seconds
|
||||
endTime: BigNumber.from(asset.expirationTime),
|
||||
// minimum ratio to be received by the user (per 10000)
|
||||
minPercentageToAsk: BigNumber.from(10000)
|
||||
.sub(BigNumber.from(200).add(BigNumber.from(asset.creatorPercentage * 10000)))
|
||||
.toNumber(),
|
||||
// params (e.g., price, target account for private sale)
|
||||
params: [],
|
||||
}
|
||||
|
||||
try {
|
||||
const signatureHash = await signMakerOrder(
|
||||
signer,
|
||||
SupportedChainId.MAINNET,
|
||||
makerOrder,
|
||||
process.env.REACT_APP_LOOKSRARE_MARKETPLACE_CONTRACT || ''
|
||||
)
|
||||
setStatus(ListingStatus.PENDING)
|
||||
const payload = {
|
||||
signature: signatureHash,
|
||||
tokenId: asset.tokenId,
|
||||
collection: asset.asset_contract.address,
|
||||
strategy: addresses.STRATEGY_STANDARD_SALE,
|
||||
currency: addresses.WETH,
|
||||
signer: signerAddress,
|
||||
isOrderAsk: true,
|
||||
nonce: looksRareNonce,
|
||||
amount: 1,
|
||||
price: parseEther(listingPrice.toString()).toString(),
|
||||
startTime: currentTime,
|
||||
endTime: asset.expirationTime,
|
||||
minPercentageToAsk: 10000 - (200 + asset.creatorPercentage * 10000),
|
||||
params: [],
|
||||
}
|
||||
const res = await createLooksRareOrder(payload)
|
||||
if (res) setStatus(ListingStatus.APPROVED)
|
||||
return res
|
||||
} catch (error) {
|
||||
if (error.code === 4001) setStatus(ListingStatus.REJECTED)
|
||||
else setStatus(ListingStatus.FAILED)
|
||||
return false
|
||||
}
|
||||
|
||||
case 'X2Y2':
|
||||
const orderItem: OfferItem = {
|
||||
price: parseEther(listingPrice.toString()),
|
||||
tokens: [
|
||||
{
|
||||
token: asset.asset_contract.address,
|
||||
tokenId: BigNumber.from(parseFloat(asset.tokenId)),
|
||||
},
|
||||
],
|
||||
}
|
||||
const order = createSellOrder(signerAddress, asset.expirationTime, [orderItem])
|
||||
try {
|
||||
await signOrderData(provider, order)
|
||||
const payload: OrderPayload = {
|
||||
order: encodeOrder(order),
|
||||
isBundle: false,
|
||||
bundleName: '',
|
||||
bundleDesc: '',
|
||||
orderIds: [],
|
||||
changePrice: false,
|
||||
isCollection: false,
|
||||
}
|
||||
setStatus(ListingStatus.PENDING)
|
||||
// call server api
|
||||
const resp = await newX2Y2Order(payload)
|
||||
if (resp) setStatus(ListingStatus.APPROVED)
|
||||
return resp
|
||||
} catch (error) {
|
||||
if (error.code === 4001) setStatus(ListingStatus.REJECTED)
|
||||
else setStatus(ListingStatus.FAILED)
|
||||
return false
|
||||
}
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
11
src/nft/utils/numbers.ts
Normal file
11
src/nft/utils/numbers.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export const isNumber = (s: string): boolean => {
|
||||
const reg = /^-?\d+\.?\d*$/
|
||||
return reg.test(s) && !isNaN(parseFloat(s)) && isFinite(parseFloat(s))
|
||||
}
|
||||
|
||||
export const formatPercentage = (percentage: string): string => {
|
||||
if (!percentage) return '-'
|
||||
return `${parseFloat(percentage)
|
||||
.toFixed(2)
|
||||
.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}%`
|
||||
}
|
8
src/nft/utils/putCommas.ts
Normal file
8
src/nft/utils/putCommas.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export const putCommas = (value: number) => {
|
||||
try {
|
||||
if (!value) return value
|
||||
return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
||||
} catch (err) {
|
||||
return value
|
||||
}
|
||||
}
|
17
src/nft/utils/rarity.ts
Normal file
17
src/nft/utils/rarity.ts
Normal file
@ -0,0 +1,17 @@
|
||||
// change this if we change the fallback provider
|
||||
export const fallbackProvider = 'PopRank'
|
||||
export const shouldLinkToFallbackProvider = false
|
||||
export const fallbackProviderLogo = '/nft/logos/poprank.png'
|
||||
|
||||
/**
|
||||
* Add provider mappings based on provider name returned from the backend here
|
||||
*/
|
||||
export const rarityProviderLogo: { [key: string]: string } = {
|
||||
'Rarity Sniper': '/nft/svgs/gem.svg',
|
||||
Genie: fallbackProviderLogo,
|
||||
}
|
||||
|
||||
export const getRarityProviderLogo = (source?: string): string | null => {
|
||||
if (!source) return null
|
||||
return rarityProviderLogo[source] || fallbackProviderLogo
|
||||
}
|
5
src/nft/utils/roundAndPluralize.ts
Normal file
5
src/nft/utils/roundAndPluralize.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export const roundAndPluralize = (i: number, word: string) => {
|
||||
const rounded = Math.floor(i)
|
||||
|
||||
return `${rounded} ${word}${rounded === 1 ? '' : 's'}`
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user