├── .yarnrc
├── src
├── connectors
│ ├── fortmatic.d.ts
│ └── Fortmatic.ts
├── assets
│ ├── images
│ │ ├── noise.png
│ │ ├── xl_uni.png
│ │ ├── metamask.png
│ │ ├── big_unicorn.png
│ │ ├── no_service.png
│ │ ├── portisIcon.png
│ │ ├── token-logo.png
│ │ ├── trustWallet.png
│ │ ├── ethereum-logo.png
│ │ ├── fortmaticIcon.png
│ │ ├── arrow-right-white.png
│ │ ├── token-list-logo.png
│ │ ├── tokenlistsgrouped.png
│ │ ├── token-list
│ │ │ ├── lists-dark.png
│ │ │ └── lists-light.png
│ │ ├── dropdown.svg
│ │ ├── dropup-blue.svg
│ │ ├── dropdown-blue.svg
│ │ ├── plus-blue.svg
│ │ ├── plus-grey.svg
│ │ ├── arrow-right.svg
│ │ ├── x.svg
│ │ ├── blue-loader.svg
│ │ ├── link.svg
│ │ ├── circle.svg
│ │ ├── circle-grey.svg
│ │ ├── arrow-down-blue.svg
│ │ ├── arrow-down-grey.svg
│ │ ├── menu.svg
│ │ ├── spinner.svg
│ │ ├── question.svg
│ │ └── question-mark.svg
│ └── svg
│ │ ├── menu.svg
│ │ ├── down.svg
│ │ ├── arrow_up.svg
│ │ ├── gray_loader.svg
│ │ ├── put_icon.svg
│ │ ├── binance.svg
│ │ ├── bsc_logo_selected.svg
│ │ ├── cross.svg
│ │ ├── copy.svg
│ │ ├── QR.svg
│ │ ├── call_icon.svg
│ │ ├── avax_logo.svg
│ │ ├── eth_logo.svg
│ │ ├── circle_ETH.svg
│ │ ├── sell.svg
│ │ ├── buy.svg
│ │ ├── huobi.svg
│ │ ├── huobi_inverted.svg
│ │ ├── check_circle.svg
│ │ ├── lightcircle.svg
│ │ ├── cross_circle.svg
│ │ ├── plus.svg
│ │ ├── put_type.svg
│ │ ├── transaction_submitted.svg
│ │ ├── call_type.svg
│ │ ├── walletConnect_logo.svg
│ │ ├── circle_unknown.svg
│ │ ├── transaction_error.svg
│ │ ├── put_token.svg
│ │ ├── helper.svg
│ │ ├── search.svg
│ │ └── call_token.svg
├── constants
│ ├── proposals
│ │ └── index.ts
│ ├── abis
│ │ ├── migrator.ts
│ │ ├── argent-wallet-detector.ts
│ │ ├── erc20.ts
│ │ ├── staking-rewards.ts
│ │ ├── erc20_bytes32.json
│ │ └── migrator.json
│ ├── lists.ts
│ ├── multicall
│ │ └── index.ts
│ ├── tokenLists
│ │ └── uniswap-v2-unsupported.tokenlist.json
│ └── v1
│ │ └── index.ts
├── hooks
│ ├── useTheme.ts
│ ├── useToggle.ts
│ ├── useParsedQueryString.ts
│ ├── useCurrentBlockTimestamp.ts
│ ├── useToggledVersion.ts
│ ├── useIsArgentWallet.ts
│ ├── useMediaWidth.ts
│ ├── usePrevious.ts
│ ├── useTimestampFromBlock.ts
│ ├── useInterval.ts
│ ├── useCopyClipboard.ts
│ ├── useTransactionDeadline.ts
│ ├── useHttpLocations.ts
│ ├── useDebounce.ts
│ ├── useWindowSize.ts
│ ├── useOnClickOutside.tsx
│ ├── useSocksBalance.ts
│ ├── useENS.ts
│ ├── useIsWindowVisible.ts
│ ├── useLast.ts
│ ├── useENSContentHash.ts
│ ├── useENSAddress.ts
│ ├── useCreationCallback.ts
│ ├── useAddTokenToMetamask.ts
│ ├── useENSName.ts
│ ├── useOptionList.ts
│ └── useCalculatorCallback.ts
├── utils
│ ├── isZero.ts
│ ├── listVersionLabel.ts
│ ├── getLibrary.ts
│ ├── currencyId.ts
│ ├── option
│ │ ├── location.ts
│ │ ├── axios.tsx
│ │ └── wrapPromise.ts
│ ├── getCurrencySymbol.ts
│ ├── parseENSAddress.ts
│ ├── listSort.ts
│ ├── maxAmountSpend.ts
│ ├── showPassDateTime.ts
│ ├── uriToHttp.ts
│ ├── wrappedCurrency.ts
│ ├── contenthashToUri.test.skip.ts
│ ├── chunkArray.test.ts
│ ├── trades.ts
│ ├── uriToHttp.test.ts
│ ├── parseENSAddress.test.ts
│ ├── useDebouncedChangeHandler.tsx
│ ├── chunkArray.ts
│ ├── marketStrategyUtils.ts
│ ├── computeUniCirculation.test.ts
│ ├── contenthashToUri.ts
│ └── prices.test.ts
├── state
│ ├── global
│ │ └── actions.ts
│ ├── burn
│ │ ├── actions.ts
│ │ └── reducer.ts
│ ├── mint
│ │ ├── actions.ts
│ │ ├── reducer.test.ts
│ │ └── reducer.ts
│ ├── multicall
│ │ └── utils.ts
│ ├── swap
│ │ ├── actions.ts
│ │ └── reducer.test.ts
│ ├── application
│ │ ├── actions.ts
│ │ └── reducer.ts
│ ├── transactions
│ │ ├── actions.ts
│ │ └── updater.test.ts
│ ├── index.ts
│ ├── user
│ │ ├── updater.tsx
│ │ └── reducer.test.ts
│ └── lists
│ │ └── actions.ts
├── components
│ ├── swap
│ │ ├── AdvancedSwapDetailsDropdown.tsx
│ │ ├── FormattedPriceImpact.tsx
│ │ ├── SwapHeader.tsx
│ │ ├── TradePrice.tsx
│ │ ├── confirmPriceImpactWithoutFee.ts
│ │ └── SwapRoute.tsx
│ ├── analytics
│ │ └── GoogleAnalyticsReporter.tsx
│ ├── Blocklist
│ │ └── index.tsx
│ ├── TokenWarningModal
│ │ └── index.tsx
│ ├── PairChart
│ │ ├── constants.js
│ │ ├── apollo
│ │ │ └── client.js
│ │ └── utils
│ │ │ └── data.ts
│ ├── ListLogo
│ │ └── index.tsx
│ ├── FormattedCurrencyAmount
│ │ └── index.tsx
│ ├── Column
│ │ └── index.tsx
│ ├── SearchModal
│ │ ├── SortButton.tsx
│ │ └── sorting.ts
│ ├── Identicon
│ │ └── index.tsx
│ ├── Header
│ │ ├── ShortLogo.tsx
│ │ └── URLWarning.tsx
│ ├── MarketStrategy
│ │ ├── TypeRadioButton.tsx
│ │ └── RadioButton.tsx
│ ├── Image
│ │ └── index.tsx
│ ├── CurrencyLogo
│ │ └── CallPutToken.tsx
│ ├── Tooltip
│ │ └── index.tsx
│ ├── Confetti
│ │ └── index.tsx
│ ├── Logo
│ │ └── index.tsx
│ ├── DoubleLogo
│ │ ├── index.tsx
│ │ └── DoubleLogoReverse.tsx
│ ├── Row
│ │ └── index.tsx
│ ├── AccountDetails
│ │ └── Copy.tsx
│ ├── Pagination
│ │ └── index.tsx
│ ├── Popups
│ │ └── TransactionPopup.tsx
│ ├── SwitchTab
│ │ └── index.tsx
│ ├── Spinner
│ │ └── index.tsx
│ ├── Loader
│ │ └── index.tsx
│ └── Toggle
│ │ ├── ListToggle.tsx
│ │ └── index.tsx
├── pages
│ ├── MigrateV1
│ │ └── EmptyState.tsx
│ ├── RemoveLiquidity
│ │ └── redirects.tsx
│ ├── OptionCreation
│ │ └── Liquidity.tsx
│ ├── ComingSoon.tsx
│ ├── MatterToken
│ │ ├── index.tsx
│ │ └── ConfirmRedeemModalBottom.tsx
│ ├── Vote
│ │ └── styled.tsx
│ ├── AddLiquidity
│ │ ├── redirects.tsx
│ │ └── PoolPriceBar.tsx
│ ├── Pool
│ │ └── styleds.tsx
│ ├── Swap
│ │ └── redirects.tsx
│ ├── Info
│ │ └── PriceItem.tsx
│ ├── Redeem
│ │ └── ConfirmRedeemModalBottom.tsx
│ ├── Generate
│ │ └── ConfirmAddModalBottom.tsx
│ └── AppBody.tsx
├── i18n.ts
├── data
│ ├── TotalSupply.ts
│ └── Allowances.ts
├── react-app-env.d.ts
└── theme
│ ├── DarkModeQueryParamReader.tsx
│ └── styled.d.ts
├── icon_32.png
├── icon_6.png
├── icon_64.png
├── .prettierrc
├── antimatter_icon.png
├── public
├── favicon.png
├── fonts
│ ├── Roboto-Bold.ttf
│ ├── Roboto-Light.ttf
│ ├── FuturaPT-Demi.ttf
│ ├── Roboto-Italic.ttf
│ ├── Roboto-Medium.ttf
│ └── Roboto-Regular.ttf
├── images
│ ├── 192x192_App_Icon.png
│ └── 512x512_App_Icon.png
├── 451.html
├── manifest.json
└── css
│ └── font.css
├── .env
├── .github
├── ISSUE_TEMPLATE
│ ├── config.yml
│ ├── proposal.md
│ ├── ask-a-question.md
│ ├── enhancement.md
│ ├── bug-report.md
│ └── feature-request.md
└── workflows
│ └── lint.yml
├── cypress.json
├── cypress
├── tsconfig.json
├── integration
│ ├── migrate-v1.test.ts
│ ├── lists.test.ts
│ ├── send.test.ts
│ ├── pool.test.ts
│ └── landing.test.ts
└── support
│ ├── commands.d.ts
│ └── index.js
├── .env.production
├── .gitignore
├── .eslintrc.json
├── tsconfig.json
├── README.md
├── sitemap.xml
└── test
└── unit
└── functions
└── approveAmountCallData.test.ts
/.yarnrc:
--------------------------------------------------------------------------------
1 | ignore-scripts true
2 |
--------------------------------------------------------------------------------
/src/connectors/fortmatic.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'formatic'
2 |
--------------------------------------------------------------------------------
/icon_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/icon_32.png
--------------------------------------------------------------------------------
/icon_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/icon_6.png
--------------------------------------------------------------------------------
/icon_64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/icon_64.png
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": false,
3 | "singleQuote": true,
4 | "printWidth": 120
5 | }
6 |
--------------------------------------------------------------------------------
/antimatter_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/antimatter_icon.png
--------------------------------------------------------------------------------
/public/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/public/favicon.png
--------------------------------------------------------------------------------
/public/fonts/Roboto-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/public/fonts/Roboto-Bold.ttf
--------------------------------------------------------------------------------
/public/fonts/Roboto-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/public/fonts/Roboto-Light.ttf
--------------------------------------------------------------------------------
/src/assets/images/noise.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/src/assets/images/noise.png
--------------------------------------------------------------------------------
/src/assets/images/xl_uni.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/src/assets/images/xl_uni.png
--------------------------------------------------------------------------------
/public/fonts/FuturaPT-Demi.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/public/fonts/FuturaPT-Demi.ttf
--------------------------------------------------------------------------------
/public/fonts/Roboto-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/public/fonts/Roboto-Italic.ttf
--------------------------------------------------------------------------------
/public/fonts/Roboto-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/public/fonts/Roboto-Medium.ttf
--------------------------------------------------------------------------------
/public/fonts/Roboto-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/public/fonts/Roboto-Regular.ttf
--------------------------------------------------------------------------------
/src/assets/images/metamask.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/src/assets/images/metamask.png
--------------------------------------------------------------------------------
/public/images/192x192_App_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/public/images/192x192_App_Icon.png
--------------------------------------------------------------------------------
/public/images/512x512_App_Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/public/images/512x512_App_Icon.png
--------------------------------------------------------------------------------
/src/assets/images/big_unicorn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/src/assets/images/big_unicorn.png
--------------------------------------------------------------------------------
/src/assets/images/no_service.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/src/assets/images/no_service.png
--------------------------------------------------------------------------------
/src/assets/images/portisIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/src/assets/images/portisIcon.png
--------------------------------------------------------------------------------
/src/assets/images/token-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/src/assets/images/token-logo.png
--------------------------------------------------------------------------------
/src/assets/images/trustWallet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/src/assets/images/trustWallet.png
--------------------------------------------------------------------------------
/src/assets/images/ethereum-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/src/assets/images/ethereum-logo.png
--------------------------------------------------------------------------------
/src/assets/images/fortmaticIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/src/assets/images/fortmaticIcon.png
--------------------------------------------------------------------------------
/src/assets/images/arrow-right-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/src/assets/images/arrow-right-white.png
--------------------------------------------------------------------------------
/src/assets/images/token-list-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/src/assets/images/token-list-logo.png
--------------------------------------------------------------------------------
/src/assets/images/tokenlistsgrouped.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/src/assets/images/tokenlistsgrouped.png
--------------------------------------------------------------------------------
/src/assets/images/token-list/lists-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/src/assets/images/token-list/lists-dark.png
--------------------------------------------------------------------------------
/src/assets/images/token-list/lists-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/HEAD/src/assets/images/token-list/lists-light.png
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | REACT_APP_CHAIN_ID="1"
2 | REACT_APP_NETWORK_URL="https://mainnet.infura.io/v3/3f6f55ba1ee540328662f8496ddbc228"
3 |
--------------------------------------------------------------------------------
/src/constants/proposals/index.ts:
--------------------------------------------------------------------------------
1 | import { UNISWAP_GRANTS } from './uniswap_grants'
2 |
3 | // Proposals are 0-indexed
4 | export const PRELOADED_PROPOSALS = new Map([[2, UNISWAP_GRANTS]])
5 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: Document
4 | url: https://docs.antimatter.finance/
5 | about: About how antimatter work.
6 |
--------------------------------------------------------------------------------
/src/hooks/useTheme.ts:
--------------------------------------------------------------------------------
1 | import { ThemeContext } from 'styled-components'
2 | import { useContext } from 'react'
3 |
4 | export default function useTheme() {
5 | return useContext(ThemeContext)
6 | }
7 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/proposal.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Proposal
3 | about: Propose application ideas to Antimatter ecosystem.
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/assets/images/dropdown.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/assets/images/dropup-blue.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/constants/abis/migrator.ts:
--------------------------------------------------------------------------------
1 | import MIGRATOR_ABI from './migrator.json'
2 |
3 | const MIGRATOR_ADDRESS = '0x16D4F26C15f3658ec65B1126ff27DD3dF2a2996b'
4 |
5 | export { MIGRATOR_ADDRESS, MIGRATOR_ABI }
6 |
--------------------------------------------------------------------------------
/src/assets/images/dropdown-blue.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/assets/svg/menu.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/ask-a-question.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Ask a Question
3 | about: I want to ask a question about the product and technology.
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
--------------------------------------------------------------------------------
/cypress.json:
--------------------------------------------------------------------------------
1 | {
2 | "baseUrl": "http://localhost:3000",
3 | "pluginsFile": false,
4 | "fixturesFolder": false,
5 | "supportFile": "cypress/support/index.js",
6 | "video": false,
7 | "defaultCommandTimeout": 10000
8 | }
9 |
--------------------------------------------------------------------------------
/src/assets/images/plus-blue.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/assets/images/plus-grey.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/utils/isZero.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Returns true if the string value is zero in hex
3 | * @param hexNumberString
4 | */
5 | export default function isZero(hexNumberString: string) {
6 | return /^0x0*$/.test(hexNumberString)
7 | }
8 |
--------------------------------------------------------------------------------
/src/utils/listVersionLabel.ts:
--------------------------------------------------------------------------------
1 | import { Version } from '@uniswap/token-lists'
2 |
3 | export default function listVersionLabel(version: Version): string {
4 | return `v${version.major}.${version.minor}.${version.patch}`
5 | }
6 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/enhancement.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Enhancement
3 | about: As a BlockChain developer, I want to make an enhancement for Antimatter ecology.
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
--------------------------------------------------------------------------------
/cypress/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "baseUrl": "../node_modules",
5 | "target": "es5",
6 | "lib": ["es5", "dom"],
7 | "types": ["cypress"]
8 | },
9 | "include": ["**/*.ts"]
10 | }
11 |
--------------------------------------------------------------------------------
/src/assets/svg/down.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/public/451.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Unavailable For Legal Reasons
6 |
7 |
8 | Unavailable For Legal Reasons
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/assets/svg/arrow_up.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/utils/getLibrary.ts:
--------------------------------------------------------------------------------
1 | import { Web3Provider } from '@ethersproject/providers'
2 |
3 | export default function getLibrary(provider: any): Web3Provider {
4 | const library = new Web3Provider(provider, 'any')
5 | library.pollingInterval = 15000
6 | return library
7 | }
8 |
--------------------------------------------------------------------------------
/.env.production:
--------------------------------------------------------------------------------
1 | REACT_APP_CHAIN_ID="1"
2 | REACT_APP_NETWORK_URL="https://mainnet.infura.io/v3/3f6f55ba1ee540328662f8496ddbc228"
3 | REACT_APP_PORTIS_ID="c0e2bf01-4b08-4fd5-ac7b-8e26b58cd236"
4 | REACT_APP_FORTMATIC_KEY="pk_live_F937DF033A1666BF"
5 | REACT_APP_GOOGLE_ANALYTICS_ID="UA-128182339-4"
6 |
--------------------------------------------------------------------------------
/src/utils/currencyId.ts:
--------------------------------------------------------------------------------
1 | import { Currency, ETHER, Token } from '@uniswap/sdk'
2 |
3 | export function currencyId(currency: Currency): string {
4 | if (currency === ETHER) return 'ETH'
5 | if (currency instanceof Token) return currency.address
6 | throw new Error('invalid currency')
7 | }
8 |
--------------------------------------------------------------------------------
/src/assets/images/arrow-right.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/constants/abis/argent-wallet-detector.ts:
--------------------------------------------------------------------------------
1 | import ARGENT_WALLET_DETECTOR_ABI from './argent-wallet-detector.json'
2 |
3 | const ARGENT_WALLET_DETECTOR_MAINNET_ADDRESS = '0xeca4B0bDBf7c55E9b7925919d03CbF8Dc82537E8'
4 |
5 | export { ARGENT_WALLET_DETECTOR_ABI, ARGENT_WALLET_DETECTOR_MAINNET_ADDRESS }
6 |
--------------------------------------------------------------------------------
/src/state/global/actions.ts:
--------------------------------------------------------------------------------
1 | import { createAction } from '@reduxjs/toolkit'
2 |
3 | // fired once when the app reloads but before the app renders
4 | // allows any updates to be applied to store data loaded from localStorage
5 | export const updateVersion = createAction('global/updateVersion')
6 |
--------------------------------------------------------------------------------
/src/assets/images/x.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/hooks/useToggle.ts:
--------------------------------------------------------------------------------
1 | import { useCallback, useState } from 'react'
2 |
3 | export default function useToggle(initialState = false): [boolean, () => void] {
4 | const [state, setState] = useState(initialState)
5 | const toggle = useCallback(() => setState(state => !state), [])
6 | return [state, toggle]
7 | }
8 |
--------------------------------------------------------------------------------
/src/assets/images/blue-loader.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/assets/svg/gray_loader.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/src/assets/images/link.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/cypress/integration/migrate-v1.test.ts:
--------------------------------------------------------------------------------
1 | describe('Migrate V1 Liquidity', () => {
2 | describe('Remove V1 liquidity', () => {
3 | it('renders the correct page', () => {
4 | cy.visit('/remove/v1/0x93bB63aFe1E0180d0eF100D774B473034fd60C36')
5 | cy.get('#remove-v1-exchange').should('contain', 'MKR/ETH')
6 | })
7 | })
8 | })
9 |
--------------------------------------------------------------------------------
/cypress/support/commands.d.ts:
--------------------------------------------------------------------------------
1 | export const TEST_ADDRESS_NEVER_USE: string
2 |
3 | export const TEST_ADDRESS_NEVER_USE_SHORTENED: string
4 |
5 | // declare namespace Cypress {
6 | // // eslint-disable-next-line @typescript-eslint/class-name-casing
7 | // interface cy {
8 | // additionalCommands(): void
9 | // }
10 | // }
11 |
--------------------------------------------------------------------------------
/src/assets/images/circle.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/assets/images/circle-grey.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/state/burn/actions.ts:
--------------------------------------------------------------------------------
1 | import { createAction } from '@reduxjs/toolkit'
2 |
3 | export enum Field {
4 | LIQUIDITY_PERCENT = 'LIQUIDITY_PERCENT',
5 | LIQUIDITY = 'LIQUIDITY',
6 | CURRENCY_A = 'CURRENCY_A',
7 | CURRENCY_B = 'CURRENCY_B'
8 | }
9 |
10 | export const typeInput = createAction<{ field: Field; typedValue: string }>('burn/typeInputBurn')
11 |
--------------------------------------------------------------------------------
/src/utils/option/location.ts:
--------------------------------------------------------------------------------
1 | import wrapPromise from './wrapPromise'
2 |
3 | export const fetchLocation = () => {
4 | return wrapPromise(
5 | fetch('https://geolocation-db.com/json/')
6 | .then(r => r.clone().json())
7 | .then(json => json.country_code)
8 | .catch(e => {
9 | console.error(e)
10 | })
11 | )
12 | }
13 |
--------------------------------------------------------------------------------
/src/assets/images/arrow-down-blue.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/assets/images/arrow-down-grey.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/cypress/integration/lists.test.ts:
--------------------------------------------------------------------------------
1 | describe('Lists', () => {
2 | beforeEach(() => {
3 | cy.visit('/swap')
4 | })
5 |
6 | // @TODO check if default lists are active when we have them
7 | it('change list', () => {
8 | cy.get('#swap-currency-output .open-currency-select-button').click()
9 | cy.get('.list-token-manage-button').click()
10 | })
11 | })
12 |
--------------------------------------------------------------------------------
/src/components/swap/AdvancedSwapDetailsDropdown.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { AdvancedSwapDetails, AdvancedSwapDetailsProps } from './AdvancedSwapDetails'
3 |
4 | export default function AdvancedSwapDetailsDropdown({ undTrade, curTrade, ...rest }: AdvancedSwapDetailsProps) {
5 | return
6 | }
7 |
--------------------------------------------------------------------------------
/src/state/mint/actions.ts:
--------------------------------------------------------------------------------
1 | import { createAction } from '@reduxjs/toolkit'
2 |
3 | export enum Field {
4 | CURRENCY_A = 'CURRENCY_A',
5 | CURRENCY_B = 'CURRENCY_B'
6 | }
7 |
8 | export const typeInput = createAction<{ field: Field; typedValue: string; noLiquidity: boolean }>('mint/typeInputMint')
9 | export const resetMintState = createAction('mint/resetMintState')
10 |
--------------------------------------------------------------------------------
/src/utils/getCurrencySymbol.ts:
--------------------------------------------------------------------------------
1 | import { ChainId, Currency, ETHER, Token } from '@uniswap/sdk'
2 | import { Symbol } from 'constants/index'
3 |
4 | export function getCurrencySymbol(currency: Currency, chainId: ChainId | undefined): string {
5 | if (currency === ETHER) return Symbol[chainId ?? 1] ?? ''
6 | if (currency instanceof Token) return currency.symbol ?? ''
7 | return ''
8 | }
9 |
--------------------------------------------------------------------------------
/src/utils/parseENSAddress.ts:
--------------------------------------------------------------------------------
1 | const ENS_NAME_REGEX = /^(([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\.)+)eth(\/.*)?$/
2 |
3 | export function parseENSAddress(ensAddress: string): { ensName: string; ensPath: string | undefined } | undefined {
4 | const match = ensAddress.match(ENS_NAME_REGEX)
5 | if (!match) return undefined
6 | return { ensName: `${match[1].toLowerCase()}eth`, ensPath: match[4] }
7 | }
8 |
--------------------------------------------------------------------------------
/cypress/support/index.js:
--------------------------------------------------------------------------------
1 | // ***********************************************************
2 | // This file is processed and loaded automatically before your test files.
3 | //
4 | // You can read more here:
5 | // https://on.cypress.io/configuration
6 | // ***********************************************************
7 |
8 | // Import commands.ts using ES2015 syntax:
9 | import './commands'
10 |
--------------------------------------------------------------------------------
/cypress/integration/send.test.ts:
--------------------------------------------------------------------------------
1 | describe('Send', () => {
2 | it('should redirect', () => {
3 | cy.visit('/send')
4 | cy.url().should('include', '/swap')
5 | })
6 |
7 | it('should redirect with url params', () => {
8 | cy.visit('/send?outputCurrency=ETH&recipient=bob.argent.xyz')
9 | cy.url().should('contain', '/swap?outputCurrency=ETH&recipient=bob.argent.xyz')
10 | })
11 | })
12 |
--------------------------------------------------------------------------------
/cypress/integration/pool.test.ts:
--------------------------------------------------------------------------------
1 | describe('Pool', () => {
2 | beforeEach(() => cy.visit('/pool'))
3 | it('add liquidity links to /add/ETH', () => {
4 | cy.get('#join-pool-button').click()
5 | cy.url().should('contain', '/add/ETH')
6 | })
7 |
8 | it('import pool links to /import', () => {
9 | cy.get('#import-pool-link').click()
10 | cy.url().should('contain', '/find')
11 | })
12 | })
13 |
--------------------------------------------------------------------------------
/src/constants/abis/erc20.ts:
--------------------------------------------------------------------------------
1 | import { Interface } from '@ethersproject/abi'
2 | import ERC20_ABI from './erc20.json'
3 | import ERC20_BYTES32_ABI from './erc20_bytes32.json'
4 |
5 | const ERC20_INTERFACE = new Interface(ERC20_ABI)
6 |
7 | const ERC20_BYTES32_INTERFACE = new Interface(ERC20_BYTES32_ABI)
8 |
9 | export default ERC20_INTERFACE
10 | export { ERC20_ABI, ERC20_BYTES32_INTERFACE, ERC20_BYTES32_ABI }
11 |
--------------------------------------------------------------------------------
/src/pages/MigrateV1/EmptyState.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { AutoColumn } from '../../components/Column'
3 | import { TYPE } from '../../theme'
4 |
5 | export function EmptyState({ message }: { message: string }) {
6 | return (
7 |
8 | {message}
9 |
10 | )
11 | }
12 |
--------------------------------------------------------------------------------
/src/assets/svg/put_icon.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/hooks/useParsedQueryString.ts:
--------------------------------------------------------------------------------
1 | import { parse, ParsedQs } from 'qs'
2 | import { useMemo } from 'react'
3 | import { useLocation } from 'react-router-dom'
4 |
5 | export default function useParsedQueryString(): ParsedQs {
6 | const { search } = useLocation()
7 | return useMemo(
8 | () => (search && search.length > 1 ? parse(search, { parseArrays: false, ignoreQueryPrefix: true }) : {}),
9 | [search]
10 | )
11 | }
12 |
--------------------------------------------------------------------------------
/src/hooks/useCurrentBlockTimestamp.ts:
--------------------------------------------------------------------------------
1 | import { BigNumber } from 'ethers'
2 | import { useSingleCallResult } from '../state/multicall/hooks'
3 | import { useMulticallContract } from './useContract'
4 |
5 | // gets the current timestamp from the blockchain
6 | export default function useCurrentBlockTimestamp(): BigNumber | undefined {
7 | const multicall = useMulticallContract()
8 | return useSingleCallResult(multicall, 'getCurrentBlockTimestamp')?.result?.[0]
9 | }
10 |
--------------------------------------------------------------------------------
/src/components/analytics/GoogleAnalyticsReporter.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect } from 'react'
2 | import ReactGA from 'react-ga'
3 | import { RouteComponentProps } from 'react-router-dom'
4 |
5 | // fires a GA pageview every time the route changes
6 | export default function GoogleAnalyticsReporter({ location: { pathname, search } }: RouteComponentProps): null {
7 | useEffect(() => {
8 | ReactGA.pageview(`${pathname}${search}`)
9 | }, [pathname, search])
10 | return null
11 | }
12 |
--------------------------------------------------------------------------------
/src/hooks/useToggledVersion.ts:
--------------------------------------------------------------------------------
1 | import useParsedQueryString from './useParsedQueryString'
2 |
3 | export enum Version {
4 | v1 = 'v1',
5 | v2 = 'v2'
6 | }
7 |
8 | export const DEFAULT_VERSION: Version = Version.v2
9 |
10 | export default function useToggledVersion(): Version {
11 | const { use } = useParsedQueryString()
12 | if (!use || typeof use !== 'string') return Version.v2
13 | if (use.toLowerCase() === 'v1') return Version.v1
14 | return DEFAULT_VERSION
15 | }
16 |
--------------------------------------------------------------------------------
/src/assets/svg/binance.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/assets/svg/bsc_logo_selected.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/constants/abis/staking-rewards.ts:
--------------------------------------------------------------------------------
1 | import { Interface } from '@ethersproject/abi'
2 | import { abi as STAKING_REWARDS_ABI } from '../abis/StakingRewards.json'
3 | import { abi as STAKING_REWARDS_FACTORY_ABI } from '@uniswap/liquidity-staker/build/StakingRewardsFactory.json'
4 |
5 | const STAKING_REWARDS_INTERFACE = new Interface(STAKING_REWARDS_ABI)
6 |
7 | const STAKING_REWARDS_FACTORY_INTERFACE = new Interface(STAKING_REWARDS_FACTORY_ABI)
8 |
9 | export { STAKING_REWARDS_FACTORY_INTERFACE, STAKING_REWARDS_INTERFACE }
10 |
--------------------------------------------------------------------------------
/src/components/Blocklist/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { ReactNode, useMemo } from 'react'
2 | import { BLOCKED_ADDRESSES } from '../../constants'
3 | import { useActiveWeb3React } from '../../hooks'
4 |
5 | export default function Blocklist({ children }: { children: ReactNode }) {
6 | const { account } = useActiveWeb3React()
7 | const blocked: boolean = useMemo(() => Boolean(account && BLOCKED_ADDRESSES.indexOf(account) !== -1), [account])
8 | if (blocked) {
9 | return Blocked address
10 | }
11 | return <>{children}>
12 | }
13 |
--------------------------------------------------------------------------------
/src/constants/lists.ts:
--------------------------------------------------------------------------------
1 | // used to mark unsupported tokens, these are hosted lists of unsupported tokens
2 |
3 | const GEMINI_LIST = 'https://www.gemini.com/uniswap/manifest.json'
4 |
5 | export const UNSUPPORTED_LIST_URLS: string[] = []
6 |
7 | // lower index == higher priority for token import
8 | export const DEFAULT_LIST_OF_LISTS: string[] = [
9 | ...UNSUPPORTED_LIST_URLS // need to load unsupported tokens as well
10 | ]
11 |
12 | // default lists to be 'active' aka searched across
13 | export const DEFAULT_ACTIVE_LIST_URLS: string[] = [GEMINI_LIST]
14 |
--------------------------------------------------------------------------------
/src/utils/option/axios.tsx:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 |
3 | const axiosInstance = axios.create({
4 | baseURL: 'https://testapi.antimatter.finance/app/',
5 | timeout: 5000,
6 | headers: { 'content-type': 'application/json', accept: 'application/json' }
7 | })
8 |
9 | export const Axios = {
10 | get(url: string, params: { [key: string]: any }) {
11 | return axiosInstance.get(url, { params })
12 | },
13 | post(url: string, data: { [key: string]: any }, params = {}) {
14 | return axiosInstance.post(url, data, { params })
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/hooks/useIsArgentWallet.ts:
--------------------------------------------------------------------------------
1 | import { NEVER_RELOAD, useSingleCallResult } from '../state/multicall/hooks'
2 | import { useActiveWeb3React } from './index'
3 | import { useArgentWalletDetectorContract } from './useContract'
4 |
5 | export default function useIsArgentWallet(): boolean {
6 | const { account } = useActiveWeb3React()
7 | const argentWalletDetector = useArgentWalletDetectorContract()
8 | const call = useSingleCallResult(argentWalletDetector, 'isArgentWallet', [account ?? undefined], NEVER_RELOAD)
9 | return call?.result?.[0] ?? false
10 | }
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | /.netlify
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
25 | notes.txt
26 | .idea/
27 |
28 | .vscode/
29 |
30 | package-lock.json
31 |
32 | cypress/videos
33 | cypress/screenshots
34 | cypress/fixtures/example.json
--------------------------------------------------------------------------------
/src/assets/svg/cross.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/hooks/useMediaWidth.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 | import { MEDIA_WIDTHS } from '../theme'
3 | import { useWindowSize } from './useWindowSize'
4 |
5 | export default function useMediaWidth(width: keyof typeof MEDIA_WIDTHS) {
6 | const [isUpTo, setIsUpTo] = useState(false)
7 | const windowSize = useWindowSize()
8 |
9 | useEffect(() => {
10 | if (windowSize.width && windowSize.width >= MEDIA_WIDTHS[width]) {
11 | setIsUpTo(false)
12 | } else {
13 | setIsUpTo(true)
14 | }
15 | }, [windowSize, width])
16 |
17 | return isUpTo
18 | }
19 |
--------------------------------------------------------------------------------
/src/constants/multicall/index.ts:
--------------------------------------------------------------------------------
1 | import { ChainId } from '@uniswap/sdk'
2 | import MULTICALL_ABI from './abi.json'
3 |
4 | const MULTICALL_NETWORKS: { [chainId in ChainId]: string } = {
5 | [ChainId.MAINNET]: '0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696',
6 | [ChainId.ROPSTEN]: '0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696',
7 | [ChainId.BSC]: '0xa9193376D09C7f31283C54e56D013fCF370Cd9D9',
8 | [ChainId.Arbitrum]: '0x80C7DD17B01855a6D2347444a0FCC36136a314de',
9 | [ChainId.Avalanche]: '0xdDCbf776dF3dE60163066A5ddDF2277cB445E0F3'
10 | }
11 |
12 | export { MULTICALL_ABI, MULTICALL_NETWORKS }
13 |
--------------------------------------------------------------------------------
/src/assets/svg/copy.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/i18n.ts:
--------------------------------------------------------------------------------
1 | import i18next from 'i18next'
2 | import { initReactI18next } from 'react-i18next'
3 | import XHR from 'i18next-xhr-backend'
4 | import LanguageDetector from 'i18next-browser-languagedetector'
5 |
6 | i18next
7 | .use(XHR)
8 | .use(LanguageDetector)
9 | .use(initReactI18next)
10 | .init({
11 | backend: {
12 | loadPath: `./locales/{{lng}}.json`
13 | },
14 | react: {
15 | useSuspense: true
16 | },
17 | fallbackLng: 'en',
18 | preload: ['en'],
19 | keySeparator: false,
20 | interpolation: { escapeValue: false }
21 | })
22 |
23 | export default i18next
24 |
--------------------------------------------------------------------------------
/src/pages/RemoveLiquidity/redirects.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { RouteComponentProps, Redirect } from 'react-router-dom'
3 |
4 | const OLD_PATH_STRUCTURE = /^(0x[a-fA-F0-9]{40})-(0x[a-fA-F0-9]{40})$/
5 |
6 | export function RedirectOldRemoveLiquidityPathStructure({
7 | match: {
8 | params: { tokens }
9 | }
10 | }: RouteComponentProps<{ tokens: string }>) {
11 | if (!OLD_PATH_STRUCTURE.test(tokens)) {
12 | return
13 | }
14 | const [currency0, currency1] = tokens.split('-')
15 |
16 | return
17 | }
18 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug Report
3 | about: Describe an issue in the Antimatter Interface
4 | title: ''
5 | labels: bug
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Bug Description**
11 | A clear and concise description of the bug.
12 |
13 | **Steps to Reproduce**
14 | 1. Go to ...
15 | 2. Click on ...
16 | ...
17 |
18 | **Expected Behavior**
19 | A clear and concise description of what you expected to happen.
20 |
21 | **Additional Context**
22 | Add any other context about the problem here (screenshots, whether the bug only occurs only in certain mobile/desktop/browser environments, etc.)
23 |
--------------------------------------------------------------------------------
/src/assets/svg/QR.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/hooks/usePrevious.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useRef } from 'react'
2 |
3 | // modified from https://usehooks.com/usePrevious/
4 | export default function usePrevious(value: T) {
5 | // The ref object is a generic container whose current property is mutable ...
6 | // ... and can hold any value, similar to an instance property on a class
7 | const ref = useRef()
8 |
9 | // Store current value in ref
10 | useEffect(() => {
11 | ref.current = value
12 | }, [value]) // Only re-run if value changes
13 |
14 | // Return previous value (happens before update in useEffect above)
15 | return ref.current
16 | }
17 |
--------------------------------------------------------------------------------
/src/assets/svg/call_icon.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/constants/abis/erc20_bytes32.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "constant": true,
4 | "inputs": [],
5 | "name": "name",
6 | "outputs": [
7 | {
8 | "name": "",
9 | "type": "bytes32"
10 | }
11 | ],
12 | "payable": false,
13 | "stateMutability": "view",
14 | "type": "function"
15 | },
16 | {
17 | "constant": true,
18 | "inputs": [],
19 | "name": "symbol",
20 | "outputs": [
21 | {
22 | "name": "",
23 | "type": "bytes32"
24 | }
25 | ],
26 | "payable": false,
27 | "stateMutability": "view",
28 | "type": "function"
29 | }
30 | ]
31 |
--------------------------------------------------------------------------------
/src/components/TokenWarningModal/index.tsx:
--------------------------------------------------------------------------------
1 | import { Token } from '@uniswap/sdk'
2 | import React from 'react'
3 | import Modal from '../Modal'
4 | import { ImportToken } from 'components/SearchModal/ImportToken'
5 |
6 | export default function TokenWarningModal({
7 | isOpen,
8 | tokens,
9 | onConfirm,
10 | onDismiss
11 | }: {
12 | isOpen: boolean
13 | tokens: Token[]
14 | onConfirm: () => void
15 | onDismiss: () => void
16 | }) {
17 | return (
18 |
19 |
20 |
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/src/state/burn/reducer.ts:
--------------------------------------------------------------------------------
1 | import { createReducer } from '@reduxjs/toolkit'
2 | import { Field, typeInput } from './actions'
3 |
4 | export interface BurnState {
5 | readonly independentField: Field
6 | readonly typedValue: string
7 | }
8 |
9 | const initialState: BurnState = {
10 | independentField: Field.LIQUIDITY_PERCENT,
11 | typedValue: '0'
12 | }
13 |
14 | export default createReducer(initialState, builder =>
15 | builder.addCase(typeInput, (state, { payload: { field, typedValue } }) => {
16 | return {
17 | ...state,
18 | independentField: field,
19 | typedValue
20 | }
21 | })
22 | )
23 |
--------------------------------------------------------------------------------
/src/utils/listSort.ts:
--------------------------------------------------------------------------------
1 | import { DEFAULT_LIST_OF_LISTS } from './../constants/lists'
2 |
3 | // use ordering of default list of lists to assign priority
4 | export default function sortByListPriority(urlA: string, urlB: string) {
5 | const first = DEFAULT_LIST_OF_LISTS.includes(urlA) ? DEFAULT_LIST_OF_LISTS.indexOf(urlA) : Number.MAX_SAFE_INTEGER
6 | const second = DEFAULT_LIST_OF_LISTS.includes(urlB) ? DEFAULT_LIST_OF_LISTS.indexOf(urlB) : Number.MAX_SAFE_INTEGER
7 |
8 | // need reverse order to make sure mapping includes top priority last
9 | if (first < second) return 1
10 | else if (first > second) return -1
11 | return 0
12 | }
13 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "background_color": "#000",
3 | "display": "standalone",
4 | "homepage_url": "https://antimatter.finance/",
5 | "icons": [
6 | {
7 | "src": "./images/192x192_App_Icon.png",
8 | "sizes": "192x192",
9 | "type": "image/png",
10 | "purpose": "any maskable"
11 | },
12 | {
13 | "src": "./images/512x512_App_Icon.png",
14 | "sizes": "512x512",
15 | "type": "image/png",
16 | "purpose": "any maskable"
17 | }
18 | ],
19 | "orientation": "portrait",
20 | "name": "Antimatter",
21 | "short_name": "Antimatter",
22 | "start_url": ".",
23 | "theme_color": "#B2F355"
24 | }
--------------------------------------------------------------------------------
/src/hooks/useTimestampFromBlock.ts:
--------------------------------------------------------------------------------
1 | import { useActiveWeb3React } from '.'
2 | import { useState, useEffect } from 'react'
3 |
4 | export function useTimestampFromBlock(block: number | undefined): number | undefined {
5 | const { library } = useActiveWeb3React()
6 | const [timestamp, setTimestamp] = useState()
7 | useEffect(() => {
8 | async function fetchTimestamp() {
9 | if (block) {
10 | const blockData = await library?.getBlock(block)
11 | blockData && setTimestamp(blockData.timestamp)
12 | }
13 | }
14 | if (!timestamp) {
15 | fetchTimestamp()
16 | }
17 | }, [block, library, timestamp])
18 | return timestamp
19 | }
20 |
--------------------------------------------------------------------------------
/src/assets/svg/avax_logo.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/assets/svg/eth_logo.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/src/components/swap/FormattedPriceImpact.tsx:
--------------------------------------------------------------------------------
1 | import { Percent } from '@uniswap/sdk'
2 | import React from 'react'
3 | import { ONE_BIPS } from '../../constants'
4 | import { warningSeverity } from '../../utils/prices'
5 | import { ErrorText } from './styleds'
6 |
7 | /**
8 | * Formatted version of price impact text with warning colors
9 | */
10 | export default function FormattedPriceImpact({ priceImpact }: { priceImpact?: Percent }) {
11 | return (
12 |
13 | {priceImpact ? (priceImpact.lessThan(ONE_BIPS) ? '<0.01%' : `${priceImpact.toFixed(2)}%`) : '-'}
14 |
15 | )
16 | }
17 |
--------------------------------------------------------------------------------
/src/components/PairChart/constants.js:
--------------------------------------------------------------------------------
1 | export const timeframeOptions = {
2 | WEEK: '1 week',
3 | MONTH: '1 month',
4 | // THREE_MONTHS: '3 months',
5 | // YEAR: '1 year',
6 | HALF_YEAR: '6 months',
7 | ALL_TIME: 'All time'
8 | }
9 |
10 | export const BUNDLE_ID = '1'
11 |
12 | export const FACTORY_ADDRESS = '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f'
13 |
14 | // tokens that should be tracked but arent due to lag in subgraph
15 | export const TRACKED_OVERRIDES = [
16 | '0x9928e4046d7c6513326ccea028cd3e7a91c7590a',
17 | '0x87da823b6fc8eb8575a235a824690fda94674c88',
18 | '0xcd7989894bc033581532d2cd88da5db0a4b12859',
19 | '0xe1573b9d29e2183b1af0e743dc2754979a40d237'
20 | ]
21 |
--------------------------------------------------------------------------------
/src/pages/OptionCreation/Liquidity.tsx:
--------------------------------------------------------------------------------
1 | import React, { useMemo } from 'react'
2 | import { useOptionTypeCount } from '../../state/market/hooks'
3 | import AppBody from '../AppBody'
4 | import FullPositionCard from '../../components/PositionCard'
5 |
6 | export function Liquidity() {
7 | const optionCount = useOptionTypeCount()
8 |
9 | const optionIndexes = useMemo(() => {
10 | return Array.from({ length: optionCount }, (v, i) => i.toString())
11 | }, [optionCount])
12 |
13 | return (
14 |
15 | {optionIndexes.map(item => {
16 | return
17 | })}
18 |
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/cypress/integration/landing.test.ts:
--------------------------------------------------------------------------------
1 | import { TEST_ADDRESS_NEVER_USE_SHORTENED } from '../support/commands'
2 |
3 | describe('Landing Page', () => {
4 | beforeEach(() => cy.visit('/'))
5 | it('loads swap page', () => {
6 | cy.get('#swap-page')
7 | })
8 |
9 | it('redirects to url /swap', () => {
10 | cy.url().should('include', '/swap')
11 | })
12 |
13 | it('allows navigation to pool', () => {
14 | cy.get('#pool-nav-link').click()
15 | cy.url().should('include', '/pool')
16 | })
17 |
18 | it('is connected', () => {
19 | cy.get('#web3-status-connected').click()
20 | cy.get('#web3-account-identifier-row').contains(TEST_ADDRESS_NEVER_USE_SHORTENED)
21 | })
22 | })
23 |
--------------------------------------------------------------------------------
/src/components/ListLogo/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components'
3 | import useHttpLocations from '../../hooks/useHttpLocations'
4 |
5 | import Logo from '../Logo'
6 |
7 | const StyledListLogo = styled(Logo)<{ size: string }>`
8 | width: ${({ size }) => size};
9 | height: ${({ size }) => size};
10 | `
11 |
12 | export default function ListLogo({
13 | logoURI,
14 | style,
15 | size = '24px',
16 | alt
17 | }: {
18 | logoURI: string
19 | size?: string
20 | style?: React.CSSProperties
21 | alt?: string
22 | }) {
23 | const srcs: string[] = useHttpLocations(logoURI)
24 |
25 | return
26 | }
27 |
--------------------------------------------------------------------------------
/src/components/swap/SwapHeader.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components'
3 | import Settings from '../Settings'
4 | import { RowBetween } from '../Row'
5 | import { TYPE } from '../../theme'
6 |
7 | const StyledSwapHeader = styled.div`
8 | margin-bottom: -4px;
9 | font-size: 22px;
10 | width: 100%;
11 | max-width: 480px;
12 | font-weight: 500;
13 | color: ${({ theme }) => theme.text1};
14 | `
15 |
16 | export default function SwapHeader() {
17 | return (
18 |
19 |
20 | Option Trading
21 |
22 |
23 |
24 | )
25 | }
26 |
--------------------------------------------------------------------------------
/src/utils/maxAmountSpend.ts:
--------------------------------------------------------------------------------
1 | import { CurrencyAmount, ETHER, JSBI } from '@uniswap/sdk'
2 | import { MIN_ETH } from '../constants'
3 |
4 | /**
5 | * Given some token amount, return the max that can be spent of it
6 | * @param currencyAmount to return max of
7 | */
8 | export function maxAmountSpend(currencyAmount?: CurrencyAmount): CurrencyAmount | undefined {
9 | if (!currencyAmount) return undefined
10 | if (currencyAmount.currency === ETHER) {
11 | if (JSBI.greaterThan(currencyAmount.raw, MIN_ETH)) {
12 | return CurrencyAmount.ether(JSBI.subtract(currencyAmount.raw, MIN_ETH))
13 | } else {
14 | return CurrencyAmount.ether(JSBI.BigInt(0))
15 | }
16 | }
17 | return currencyAmount
18 | }
19 |
--------------------------------------------------------------------------------
/src/components/FormattedCurrencyAmount/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { CurrencyAmount, Fraction, JSBI } from '@uniswap/sdk'
3 |
4 | const CURRENCY_AMOUNT_MIN = new Fraction(JSBI.BigInt(1), JSBI.BigInt(1000000))
5 |
6 | export default function FormattedCurrencyAmount({
7 | currencyAmount,
8 | significantDigits = 4
9 | }: {
10 | currencyAmount: CurrencyAmount
11 | significantDigits?: number
12 | }) {
13 | return (
14 | <>
15 | {currencyAmount.equalTo(JSBI.BigInt(0))
16 | ? '0'
17 | : currencyAmount.greaterThan(CURRENCY_AMOUNT_MIN)
18 | ? currencyAmount.toSignificant(significantDigits)
19 | : `<${CURRENCY_AMOUNT_MIN.toSignificant(1)}`}
20 | >
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/src/data/TotalSupply.ts:
--------------------------------------------------------------------------------
1 | import { BigNumber } from '@ethersproject/bignumber'
2 | import { Token, TokenAmount } from '@uniswap/sdk'
3 | import { useTokenContract } from '../hooks/useContract'
4 | import { useSingleCallResult } from '../state/multicall/hooks'
5 |
6 | // returns undefined if input token is undefined, or fails to get token contract,
7 | // or contract total supply cannot be fetched
8 | export function useTotalSupply(token?: Token): TokenAmount | undefined {
9 | const contract = useTokenContract(token?.address, false)
10 |
11 | const totalSupply: BigNumber = useSingleCallResult(contract, 'totalSupply')?.result?.[0]
12 |
13 | return token && totalSupply ? new TokenAmount(token, totalSupply.toString()) : undefined
14 | }
15 |
--------------------------------------------------------------------------------
/src/assets/svg/circle_ETH.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/src/data/Allowances.ts:
--------------------------------------------------------------------------------
1 | import { Token, TokenAmount } from '@uniswap/sdk'
2 | import { useMemo } from 'react'
3 |
4 | import { useTokenContract } from '../hooks/useContract'
5 | import { useSingleCallResult } from '../state/multicall/hooks'
6 |
7 | export function useTokenAllowance(token?: Token, owner?: string, spender?: string): TokenAmount | undefined {
8 | const contract = useTokenContract(token?.address, false)
9 |
10 | const inputs = useMemo(() => [owner, spender], [owner, spender])
11 | const allowance = useSingleCallResult(contract, 'allowance', inputs).result
12 |
13 | return useMemo(() => (token && allowance ? new TokenAmount(token, allowance.toString()) : undefined), [
14 | token,
15 | allowance
16 | ])
17 | }
18 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature Request
3 | about: Suggest an idea for improving the UX of the Antimatter Interface
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/src/assets/images/menu.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/src/hooks/useInterval.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useRef } from 'react'
2 |
3 | export default function useInterval(callback: () => void, delay: null | number, leading = true) {
4 | const savedCallback = useRef<() => void>()
5 |
6 | // Remember the latest callback.
7 | useEffect(() => {
8 | savedCallback.current = callback
9 | }, [callback])
10 |
11 | // Set up the interval.
12 | useEffect(() => {
13 | function tick() {
14 | const current = savedCallback.current
15 | current && current()
16 | }
17 |
18 | if (delay !== null) {
19 | if (leading) tick()
20 | const id = setInterval(tick, delay)
21 | return () => clearInterval(id)
22 | }
23 | return undefined
24 | }, [delay, leading])
25 | }
26 |
--------------------------------------------------------------------------------
/src/utils/showPassDateTime.ts:
--------------------------------------------------------------------------------
1 | export default function showPassDateTime(preTime: Date): string {
2 | const nowTime = new Date()
3 | const passTime = nowTime.getTime() - preTime.getTime()
4 | const base = 1000
5 | if (passTime < 0) return '-'
6 | if (passTime < base * 60) {
7 | return Math.floor(passTime / base) + ' seconds ago'
8 | }
9 | if (passTime < base * 60 * 60) {
10 | return Math.floor(passTime / (base * 60)) + ' minutes ago'
11 | }
12 | if (passTime < base * 60 * 60 * 24) {
13 | return Math.floor(passTime / (base * 60 * 60)) + ' hours ago'
14 | }
15 | if (passTime < base * 60 * 60 * 24 * 3) {
16 | return Math.floor(passTime / (base * 60 * 60 * 24)) + ' days ago'
17 | }
18 | return preTime.toLocaleString('en')
19 | }
20 |
--------------------------------------------------------------------------------
/src/hooks/useCopyClipboard.ts:
--------------------------------------------------------------------------------
1 | import copy from 'copy-to-clipboard'
2 | import { useCallback, useEffect, useState } from 'react'
3 |
4 | export default function useCopyClipboard(timeout = 500): [boolean, (toCopy: string) => void] {
5 | const [isCopied, setIsCopied] = useState(false)
6 |
7 | const staticCopy = useCallback(text => {
8 | const didCopy = copy(text)
9 | setIsCopied(didCopy)
10 | }, [])
11 |
12 | useEffect(() => {
13 | if (isCopied) {
14 | const hide = setTimeout(() => {
15 | setIsCopied(false)
16 | }, timeout)
17 |
18 | return () => {
19 | clearTimeout(hide)
20 | }
21 | }
22 | return undefined
23 | }, [isCopied, setIsCopied, timeout])
24 |
25 | return [isCopied, staticCopy]
26 | }
27 |
--------------------------------------------------------------------------------
/src/hooks/useTransactionDeadline.ts:
--------------------------------------------------------------------------------
1 | import { BigNumber } from 'ethers'
2 | import { useMemo } from 'react'
3 | import { useSelector } from 'react-redux'
4 | import { AppState } from '../state'
5 | import useCurrentBlockTimestamp from './useCurrentBlockTimestamp'
6 |
7 | // combines the block timestamp with the user setting to give the deadline that should be used for any submitted transaction
8 | export default function useTransactionDeadline(): BigNumber | undefined {
9 | const ttl = useSelector(state => state.user.userDeadline)
10 | const blockTimestamp = useCurrentBlockTimestamp()
11 | return useMemo(() => {
12 | if (blockTimestamp && ttl) return blockTimestamp.add(ttl)
13 | return undefined
14 | }, [blockTimestamp, ttl])
15 | }
16 |
--------------------------------------------------------------------------------
/src/assets/svg/sell.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/components/Column/index.tsx:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components'
2 |
3 | const Column = styled.div`
4 | display: flex;
5 | flex-direction: column;
6 | justify-content: flex-start;
7 | `
8 | export const ColumnCenter = styled(Column)`
9 | width: 100%;
10 | align-items: center;
11 | `
12 |
13 | export const AutoColumn = styled.div<{
14 | gap?: 'sm' | 'md' | 'lg' | string
15 | justify?: 'stretch' | 'center' | 'start' | 'end' | 'flex-start' | 'flex-end' | 'space-between'
16 | }>`
17 | display: grid;
18 | grid-auto-rows: auto;
19 | grid-row-gap: ${({ gap }) => (gap === 'sm' && '8px') || (gap === 'md' && '12px') || (gap === 'lg' && '24px') || gap};
20 | justify-items: ${({ justify }) => justify && justify};
21 | `
22 |
23 | export default Column
24 |
--------------------------------------------------------------------------------
/src/constants/tokenLists/uniswap-v2-unsupported.tokenlist.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Uniswap V2 Unsupported List",
3 | "timestamp": "2021-01-05T20:47:02.923Z",
4 | "version": {
5 | "major": 1,
6 | "minor": 0,
7 | "patch": 0
8 | },
9 | "tags": {},
10 | "logoURI": "ipfs://QmNa8mQkrNKp1WEEeGjFezDmDeodkWRevGFN8JCV7b4Xir",
11 | "keywords": ["uniswap", "unsupported"],
12 | "tokens": [
13 | {
14 | "name": "Gold Tether",
15 | "address": "0x4922a015c4407F87432B179bb209e125432E4a2A",
16 | "symbol": "XAUt",
17 | "decimals": 6,
18 | "chainId": 1,
19 | "logoURI": "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x4922a015c4407F87432B179bb209e125432E4a2A/logo.png"
20 | }
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/src/constants/v1/index.ts:
--------------------------------------------------------------------------------
1 | import { Interface } from '@ethersproject/abi'
2 | import { ChainId } from '@uniswap/sdk'
3 | import V1_EXCHANGE_ABI from './v1_exchange.json'
4 | import V1_FACTORY_ABI from './v1_factory.json'
5 |
6 | const V1_FACTORY_ADDRESSES: { [chainId in ChainId]: string } = {
7 | [ChainId.MAINNET]: '0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95',
8 | [ChainId.ROPSTEN]: '0x9c83dCE8CA20E9aAF9D3efc003b2ea62aBC08351',
9 | [ChainId.BSC]: '',
10 | [ChainId.Arbitrum]: '',
11 | [ChainId.Avalanche]: ''
12 | }
13 |
14 | const V1_FACTORY_INTERFACE = new Interface(V1_FACTORY_ABI)
15 | const V1_EXCHANGE_INTERFACE = new Interface(V1_EXCHANGE_ABI)
16 |
17 | export { V1_FACTORY_ADDRESSES, V1_FACTORY_INTERFACE, V1_FACTORY_ABI, V1_EXCHANGE_INTERFACE, V1_EXCHANGE_ABI }
18 |
--------------------------------------------------------------------------------
/src/assets/images/spinner.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/assets/images/question.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/utils/option/wrapPromise.ts:
--------------------------------------------------------------------------------
1 | export interface WrappedPromise {
2 | read: () => T | undefined | Error
3 | }
4 |
5 | export default function wrapPromise(promise: Promise): WrappedPromise {
6 | let status = 'pending'
7 | let result: T | Error | undefined
8 | const suspender = promise.then(
9 | (r: any) => {
10 | status = 'success'
11 | result = r
12 | },
13 | (e: Error) => {
14 | status = 'error'
15 | result = e
16 | }
17 | )
18 | return {
19 | read() {
20 | if (status === 'pending') {
21 | throw suspender
22 | } else if (status === 'error') {
23 | throw result
24 | } else if (status === 'success') {
25 | return result
26 | }
27 | return undefined
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/hooks/useHttpLocations.ts:
--------------------------------------------------------------------------------
1 | import { useMemo } from 'react'
2 | import contenthashToUri from '../utils/contenthashToUri'
3 | import { parseENSAddress } from '../utils/parseENSAddress'
4 | import uriToHttp from '../utils/uriToHttp'
5 | import useENSContentHash from './useENSContentHash'
6 |
7 | export default function useHttpLocations(uri: string | undefined): string[] {
8 | const ens = useMemo(() => (uri ? parseENSAddress(uri) : undefined), [uri])
9 | const resolvedContentHash = useENSContentHash(ens?.ensName)
10 | return useMemo(() => {
11 | if (ens) {
12 | return resolvedContentHash.contenthash ? uriToHttp(contenthashToUri(resolvedContentHash.contenthash)) : []
13 | } else {
14 | return uri ? uriToHttp(uri) : []
15 | }
16 | }, [ens, resolvedContentHash.contenthash, uri])
17 | }
18 |
--------------------------------------------------------------------------------
/src/hooks/useDebounce.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 |
3 | // modified from https://usehooks.com/useDebounce/
4 | export default function useDebounce(value: T, delay: number): T {
5 | const [debouncedValue, setDebouncedValue] = useState(value)
6 |
7 | useEffect(() => {
8 | // Update debounced value after delay
9 | const handler = setTimeout(() => {
10 | setDebouncedValue(value)
11 | }, delay)
12 |
13 | // Cancel the timeout if value changes (also on delay change or unmount)
14 | // This is how we prevent debounced value from updating if value is changed ...
15 | // .. within the delay period. Timeout gets cleared and restarted.
16 | return () => {
17 | clearTimeout(handler)
18 | }
19 | }, [value, delay])
20 |
21 | return debouncedValue
22 | }
23 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "@typescript-eslint/parser",
3 | "parserOptions": {
4 | "ecmaVersion": 2020,
5 | "sourceType": "module",
6 | "ecmaFeatures": {
7 | // Allows for the parsing of JSX
8 | "jsx": true
9 | }
10 | },
11 | "ignorePatterns": [
12 | "node_modules/**/*"
13 | ],
14 | "settings": {
15 | "react": {
16 | "version": "detect"
17 | }
18 | },
19 | "extends": [
20 | "plugin:react/recommended",
21 | "plugin:@typescript-eslint/recommended",
22 | "plugin:react-hooks/recommended",
23 | "prettier/@typescript-eslint",
24 | "plugin:prettier/recommended"
25 | ],
26 | "rules": {
27 | "@typescript-eslint/explicit-function-return-type": "off",
28 | "prettier/prettier": "error",
29 | "@typescript-eslint/no-explicit-any": "off"
30 | }
31 | }
--------------------------------------------------------------------------------
/src/hooks/useWindowSize.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 |
3 | const isClient = typeof window === 'object'
4 |
5 | function getSize() {
6 | return {
7 | width: isClient ? window.innerWidth : undefined,
8 | height: isClient ? window.innerHeight : undefined
9 | }
10 | }
11 |
12 | // https://usehooks.com/useWindowSize/
13 | export function useWindowSize() {
14 | const [windowSize, setWindowSize] = useState(getSize)
15 |
16 | useEffect(() => {
17 | function handleResize() {
18 | setWindowSize(getSize())
19 | }
20 |
21 | if (isClient) {
22 | window.addEventListener('resize', handleResize)
23 | return () => {
24 | window.removeEventListener('resize', handleResize)
25 | }
26 | }
27 | return undefined
28 | }, [])
29 |
30 | return windowSize
31 | }
32 |
--------------------------------------------------------------------------------
/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | declare module 'jazzicon' {
4 | export default function(diameter: number, seed: number): HTMLElement
5 | }
6 |
7 | declare module 'fortmatic'
8 |
9 | interface Window {
10 | ethereum?: {
11 | isMetaMask?: true
12 | on?: (...args: any[]) => void
13 | removeListener?: (...args: any[]) => void
14 | autoRefreshOnNetworkChange?: boolean
15 | }
16 | web3?: {}
17 | }
18 |
19 | declare module 'content-hash' {
20 | declare function decode(x: string): string
21 | declare function getCodec(x: string): string
22 | }
23 |
24 | declare module 'multihashes' {
25 | declare function decode(buff: Uint8Array): { code: number; name: string; length: number; digest: Uint8Array }
26 | declare function toB58String(hash: Uint8Array): string
27 | }
28 |
--------------------------------------------------------------------------------
/src/assets/svg/buy.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/assets/images/question-mark.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/assets/svg/huobi.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/src/hooks/useOnClickOutside.tsx:
--------------------------------------------------------------------------------
1 | import { RefObject, useEffect, useRef } from 'react'
2 |
3 | export function useOnClickOutside(
4 | node: RefObject,
5 | handler: undefined | (() => void)
6 | ) {
7 | const handlerRef = useRef void)>(handler)
8 | useEffect(() => {
9 | handlerRef.current = handler
10 | }, [handler])
11 |
12 | useEffect(() => {
13 | const handleClickOutside = (e: MouseEvent) => {
14 | if (node.current?.contains(e.target as Node) ?? false) {
15 | return
16 | }
17 | if (handlerRef.current) handlerRef.current()
18 | }
19 |
20 | document.addEventListener('mousedown', handleClickOutside)
21 |
22 | return () => {
23 | document.removeEventListener('mousedown', handleClickOutside)
24 | }
25 | }, [node])
26 | }
27 |
--------------------------------------------------------------------------------
/src/assets/svg/huobi_inverted.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/public/css/font.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'Roboto';
3 | font-style: normal;
4 | font-weight: 300;
5 | font-display: swap;
6 | src: url('../fonts/Roboto-Light.ttf');
7 | }
8 |
9 | @font-face {
10 | font-family: 'Roboto';
11 | font-style: normal;
12 | font-weight: 400;
13 | font-display: swap;
14 | src: url('../fonts/Roboto-Regular.ttf');
15 | }
16 | @font-face {
17 | font-family: 'Roboto';
18 | font-style: normal;
19 | font-weight: 500;
20 | font-display: swap;
21 | src: url('../fonts/Roboto-Medium.ttf');
22 | }
23 | @font-face {
24 | font-family: 'Roboto';
25 | font-style: normal;
26 | font-weight: bold;
27 | font-display: swap;
28 | src: url('../fonts/Roboto-Bold.ttf');
29 | }
30 |
31 | @font-face {
32 | font-family: 'Futura PT';
33 | font-display: block;
34 | src: url('../fonts/FuturaPT-Demi.ttf');
35 | }
--------------------------------------------------------------------------------
/src/hooks/useSocksBalance.ts:
--------------------------------------------------------------------------------
1 | import { JSBI } from '@uniswap/sdk'
2 | import { useMemo } from 'react'
3 | import { NEVER_RELOAD, useSingleCallResult } from '../state/multicall/hooks'
4 | import { useActiveWeb3React } from './index'
5 | import { useSocksController } from './useContract'
6 |
7 | export default function useSocksBalance(): JSBI | undefined {
8 | const { account } = useActiveWeb3React()
9 | const socksContract = useSocksController()
10 |
11 | const { result } = useSingleCallResult(socksContract, 'balanceOf', [account ?? undefined], NEVER_RELOAD)
12 | const data = result?.[0]
13 | return data ? JSBI.BigInt(data.toString()) : undefined
14 | }
15 |
16 | export function useHasSocks(): boolean | undefined {
17 | const balance = useSocksBalance()
18 | return useMemo(() => balance && JSBI.greaterThan(balance, JSBI.BigInt(0)), [balance])
19 | }
20 |
--------------------------------------------------------------------------------
/src/utils/uriToHttp.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Given a URI that may be ipfs, ipns, http, or https protocol, return the fetch-able http(s) URLs for the same content
3 | * @param uri to convert to fetch-able http url
4 | */
5 | export default function uriToHttp(uri: string): string[] {
6 | const protocol = uri.split(':')[0].toLowerCase()
7 | switch (protocol) {
8 | case 'https':
9 | return [uri]
10 | case 'http':
11 | return ['https' + uri.substr(4), uri]
12 | case 'ipfs':
13 | const hash = uri.match(/^ipfs:(\/\/)?(.*)$/i)?.[2]
14 | return [`https://cloudflare-ipfs.com/ipfs/${hash}/`, `https://ipfs.io/ipfs/${hash}/`]
15 | case 'ipns':
16 | const name = uri.match(/^ipns:(\/\/)?(.*)$/i)?.[2]
17 | return [`https://cloudflare-ipfs.com/ipns/${name}/`, `https://ipfs.io/ipns/${name}/`]
18 | default:
19 | return []
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/state/multicall/utils.ts:
--------------------------------------------------------------------------------
1 | export interface Call {
2 | address: string
3 | callData: string
4 | gasRequired?: number
5 | }
6 |
7 | export function toCallKey(call: Call): string {
8 | let key = `${call.address}-${call.callData}`
9 | if (call.gasRequired) {
10 | if (!Number.isSafeInteger(call.gasRequired)) {
11 | throw new Error(`Invalid number: ${call.gasRequired}`)
12 | }
13 | key += `-${call.gasRequired}`
14 | }
15 | return key
16 | }
17 |
18 | export function parseCallKey(callKey: string): Call {
19 | const pcs = callKey.split('-')
20 | if (![2, 3].includes(pcs.length)) {
21 | throw new Error(`Invalid call key: ${callKey}`)
22 | }
23 | return {
24 | address: pcs[0],
25 | callData: pcs[1],
26 | ...(pcs[2] ? { gasRequired: Number.parseInt(pcs[2]) } : {}),
27 | }
28 | }
--------------------------------------------------------------------------------
/src/hooks/useENS.ts:
--------------------------------------------------------------------------------
1 | import { isAddress } from '../utils'
2 | import useENSAddress from './useENSAddress'
3 | import useENSName from './useENSName'
4 |
5 | /**
6 | * Given a name or address, does a lookup to resolve to an address and name
7 | * @param nameOrAddress ENS name or address
8 | */
9 | export default function useENS(
10 | nameOrAddress?: string | null
11 | ): { loading: boolean; address: string | null; name: string | null } {
12 | const validated = isAddress(nameOrAddress)
13 | const reverseLookup = useENSName(validated ? validated : undefined)
14 | const lookup = useENSAddress(nameOrAddress)
15 |
16 | return {
17 | loading: reverseLookup.loading || lookup.loading,
18 | address: validated ? validated : lookup.address,
19 | name: reverseLookup.ENSName ? reverseLookup.ENSName : !validated && lookup.address ? nameOrAddress || null : null
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/components/SearchModal/SortButton.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Text } from 'rebass'
3 | import styled from 'styled-components'
4 | import { RowFixed } from '../Row'
5 |
6 | export const FilterWrapper = styled(RowFixed)`
7 | padding: 8px;
8 | background-color: ${({ theme }) => theme.bg2};
9 | color: ${({ theme }) => theme.text1};
10 | border-radius: 8px;
11 | user-select: none;
12 | & > * {
13 | user-select: none;
14 | }
15 | :hover {
16 | cursor: pointer;
17 | }
18 | `
19 |
20 | export default function SortButton({
21 | toggleSortOrder,
22 | ascending
23 | }: {
24 | toggleSortOrder: () => void
25 | ascending: boolean
26 | }) {
27 | return (
28 |
29 |
30 | {ascending ? '↑' : '↓'}
31 |
32 |
33 | )
34 | }
35 |
--------------------------------------------------------------------------------
/src/utils/wrappedCurrency.ts:
--------------------------------------------------------------------------------
1 | import { ChainId, Currency, CurrencyAmount, ETHER, Token, TokenAmount, WETH } from '@uniswap/sdk'
2 |
3 | export function wrappedCurrency(currency: Currency | undefined, chainId: ChainId | undefined): Token | undefined {
4 | return chainId && currency === ETHER ? WETH[chainId] : currency instanceof Token ? currency : undefined
5 | }
6 |
7 | export function wrappedCurrencyAmount(
8 | currencyAmount: CurrencyAmount | undefined,
9 | chainId: ChainId | undefined
10 | ): TokenAmount | undefined {
11 | const token = currencyAmount && chainId ? wrappedCurrency(currencyAmount.currency, chainId) : undefined
12 | return token && currencyAmount ? new TokenAmount(token, currencyAmount.raw) : undefined
13 | }
14 |
15 | export function unwrappedToken(token: Token): Currency {
16 | if (token.equals(WETH[token.chainId])) return ETHER
17 | return token
18 | }
19 |
--------------------------------------------------------------------------------
/src/utils/contenthashToUri.test.skip.ts:
--------------------------------------------------------------------------------
1 | import contenthashToUri, { hexToUint8Array } from './contenthashToUri'
2 |
3 | // this test is skipped for now because importing CID results in
4 | // TypeError: TextDecoder is not a constructor
5 |
6 | describe('#contenthashToUri', () => {
7 | it('1inch.tokens.eth contenthash', () => {
8 | expect(contenthashToUri('0xe3010170122013e051d1cfff20606de36845d4fe28deb9861a319a5bc8596fa4e610e8803918')).toEqual(
9 | 'ipfs://QmPgEqyV3m8SB52BS2j2mJpu9zGprhj2BGCHtRiiw2fdM1'
10 | )
11 | })
12 | it('uniswap.eth contenthash', () => {
13 | expect(contenthashToUri('0xe5010170000f6170702e756e69737761702e6f7267')).toEqual('ipns://app.uniswap.org')
14 | })
15 | })
16 |
17 | describe('#hexToUint8Array', () => {
18 | it('common case', () => {
19 | expect(hexToUint8Array('0x010203fdfeff')).toEqual(new Uint8Array([1, 2, 3, 253, 254, 255]))
20 | })
21 | })
22 |
--------------------------------------------------------------------------------
/src/components/Identicon/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useRef } from 'react'
2 |
3 | import styled from 'styled-components'
4 |
5 | import { useActiveWeb3React } from '../../hooks'
6 | import Jazzicon from 'jazzicon'
7 |
8 | const StyledIdenticonContainer = styled.div`
9 | height: 1rem;
10 | width: 1rem;
11 | border-radius: 1.125rem;
12 | background-color: ${({ theme }) => theme.bg4};
13 | `
14 |
15 | export default function Identicon() {
16 | const ref = useRef()
17 |
18 | const { account } = useActiveWeb3React()
19 |
20 | useEffect(() => {
21 | if (account && ref.current) {
22 | ref.current.innerHTML = ''
23 | ref.current.appendChild(Jazzicon(16, parseInt(account.slice(2, 10), 16)))
24 | }
25 | }, [account])
26 |
27 | // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/30451
28 | return
29 | }
30 |
--------------------------------------------------------------------------------
/src/state/swap/actions.ts:
--------------------------------------------------------------------------------
1 | import { createAction } from '@reduxjs/toolkit'
2 |
3 | export enum Field {
4 | INPUT = 'INPUT',
5 | OUTPUT = 'OUTPUT'
6 | }
7 |
8 | export enum OptionType {
9 | CALL = 'CALL',
10 | PUT = 'PUT'
11 | }
12 |
13 | export enum Auction {
14 | BUY = 'BUY',
15 | SELL = 'SELL'
16 | }
17 |
18 | export const selectCurrency = createAction<{ field: Field; currencyId: string }>('swap/selectCurrency')
19 | export const switchCurrencies = createAction('swap/switchCurrencies')
20 | export const typeInput = createAction<{ field: Field; typedValue: string }>('swap/typeInput')
21 | export const replaceSwapState = createAction<{
22 | field: Field
23 | typedValue: string
24 | inputCurrencyId?: string
25 | outputCurrencyId?: string
26 | recipient: string | null
27 | }>('swap/replaceSwapState')
28 | export const setRecipient = createAction<{ recipient: string | null }>('swap/setRecipient')
29 |
--------------------------------------------------------------------------------
/src/components/Header/ShortLogo.tsx:
--------------------------------------------------------------------------------
1 | import { SVGAttributes } from 'react'
2 |
3 | export const ShortLogo = (props: SVGAttributes) => {
4 | return (
5 |
13 | )
14 | }
15 |
--------------------------------------------------------------------------------
/src/hooks/useIsWindowVisible.ts:
--------------------------------------------------------------------------------
1 | import { useCallback, useEffect, useState } from 'react'
2 |
3 | const VISIBILITY_STATE_SUPPORTED = 'visibilityState' in document
4 |
5 | function isWindowVisible() {
6 | return !VISIBILITY_STATE_SUPPORTED || document.visibilityState !== 'hidden'
7 | }
8 |
9 | /**
10 | * Returns whether the window is currently visible to the user.
11 | */
12 | export default function useIsWindowVisible(): boolean {
13 | const [focused, setFocused] = useState(isWindowVisible())
14 | const listener = useCallback(() => {
15 | setFocused(isWindowVisible())
16 | }, [setFocused])
17 |
18 | useEffect(() => {
19 | if (!VISIBILITY_STATE_SUPPORTED) return undefined
20 |
21 | document.addEventListener('visibilitychange', listener)
22 | return () => {
23 | document.removeEventListener('visibilitychange', listener)
24 | }
25 | }, [listener])
26 |
27 | return focused
28 | }
29 |
--------------------------------------------------------------------------------
/src/assets/svg/check_circle.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/src/pages/ComingSoon.tsx:
--------------------------------------------------------------------------------
1 | import { Dots } from 'components/swap/styleds'
2 | import React from 'react'
3 | import styled from 'styled-components'
4 | const Frame = styled.div`
5 | width: 500px;
6 | height: 280px;
7 | border: 1px solid rgba(255, 255, 255, 0.2);
8 | box-sizing: border-box;
9 | border-radius: 32px;
10 | display: flex;
11 | flex-direction: column;
12 | align-items: center;
13 | justify-content: center;
14 | color: rgba(255, 255, 255, 0.6);
15 | `
16 |
17 | const Title = styled.p`
18 | font-weight: 500;
19 | font-size: 24px;
20 | line-height: 88.69%;
21 | color: #ffffff;
22 | `
23 |
24 | export default function ComingSoon() {
25 | return (
26 |
27 |
28 | Coming Soon
29 |
30 |
31 | This section is still implemeting.
32 | Please come back later
33 |
34 | )
35 | }
36 |
--------------------------------------------------------------------------------
/src/components/MarketStrategy/TypeRadioButton.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { RadioButton } from './RadioButton'
3 |
4 | interface RadioOption {
5 | label: string
6 | option: string
7 | }
8 |
9 | export function TypeRadioButton({
10 | name,
11 | options,
12 | selected,
13 | onCheck
14 | }: {
15 | name: string
16 | options: RadioOption[]
17 | selected: string
18 | onCheck: (tokenType: string) => void
19 | }) {
20 | return (
21 |
34 | )
35 | }
36 |
--------------------------------------------------------------------------------
/src/assets/svg/lightcircle.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/components/Image/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { ImgHTMLAttributes, useMemo, useState } from 'react'
2 |
3 | const BAD_SRCS: { [tokenAddress: string]: true } = {}
4 |
5 | export default function Image({
6 | src,
7 | alt = '',
8 | style,
9 | className,
10 | altSrc,
11 | ...rest
12 | }: {
13 | src: string
14 | alt?: string
15 | style?: React.CSSProperties
16 | className?: string
17 | altSrc?: string
18 | } & Omit, 'src' | 'alt' | 'style'>) {
19 | const [, refresh] = useState(0)
20 | const srcs = useMemo(() => [src, altSrc], [src, altSrc])
21 | const srcStr = srcs.find(item => !BAD_SRCS[item ?? ''])
22 | return (
23 |
{
30 | if (srcStr) BAD_SRCS[srcStr] = true
31 | refresh(i => i + 1)
32 | }}
33 | />
34 | )
35 | }
36 |
--------------------------------------------------------------------------------
/src/components/swap/TradePrice.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { CurrencyAmount, ETHER } from '@uniswap/sdk'
3 | import { Text } from 'rebass'
4 | import { Symbol } from '../../constants'
5 | import { useActiveWeb3React } from '../../hooks'
6 |
7 | interface TradePriceProps {
8 | currencyAmount?: CurrencyAmount
9 | }
10 |
11 | export default function TradePrice({ currencyAmount }: TradePriceProps) {
12 | const { chainId } = useActiveWeb3React()
13 | return (
14 |
20 | {currencyAmount ? (
21 | <>
22 | ~ {currencyAmount.toExact().toString() ?? '-'}{' '}
23 | {currencyAmount.currency === ETHER ? Symbol[chainId ?? 1] : currencyAmount.currency.symbol}
24 | >
25 | ) : (
26 | '-'
27 | )}
28 |
29 | )
30 | }
31 |
--------------------------------------------------------------------------------
/src/pages/MatterToken/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components'
3 | import { LPT_TYPE } from 'constants/matterToken/matterTokenTokens'
4 | import MatterTokenManageModal, { cardWidth } from './MatterTokenManageModal'
5 |
6 | const Wrapper = styled.div`
7 | width: 100%;
8 | padding: 50px;
9 | grid-template-rows: 340px;
10 | grid-template-columns: repeat(auto-fill, ${cardWidth});
11 | grid-gap: 20px;
12 | display: grid;
13 | ${({ theme }) => theme.mediaWidth.upToMedium`
14 | grid-template-columns: 100%;
15 | padding:0
16 | `}
17 | justify-content: center;
18 | margin-bottom: auto;
19 | ${({ theme }) => theme.mediaWidth.upToLarge`
20 | padding-bottom: 100px
21 | `}
22 | `
23 | export default function MatterToken() {
24 | return (
25 |
26 | {Object.keys(LPT_TYPE).map(lpt => (
27 |
28 | ))}
29 |
30 | )
31 | }
32 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "forceConsistentCasingInFileNames": true,
8 | "noEmit": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "strict": true,
12 | "alwaysStrict": true,
13 | "strictNullChecks": true,
14 | "noUnusedLocals": true,
15 | "noFallthroughCasesInSwitch": true,
16 | "noImplicitAny": true,
17 | "noImplicitThis": true,
18 | "noImplicitReturns": true,
19 | "moduleResolution": "node",
20 | "resolveJsonModule": true,
21 | "isolatedModules": true,
22 | "jsx": "preserve",
23 | "downlevelIteration": true,
24 | "allowSyntheticDefaultImports": true,
25 | "types": ["react-spring", "jest"],
26 | "baseUrl": "src"
27 | },
28 | "exclude": ["node_modules", "cypress"],
29 | "include": ["./src/**/*.ts", "./src/**/*.tsx", "src/components/Confetti/index.js"]
30 | }
31 |
--------------------------------------------------------------------------------
/src/components/CurrencyLogo/CallPutToken.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Currency } from '@uniswap/sdk'
3 | import styled from 'styled-components'
4 | import CurrencyLogo from './'
5 | import { ReactComponent as CallIcon } from '../../assets/svg/call_icon.svg'
6 | import { ReactComponent as PutIcon } from '../../assets/svg/put_icon.svg'
7 |
8 | const StyledCallIcon = styled(CallIcon)`
9 | position:absolute
10 | bottom:-2px;
11 | right:-2px
12 | `
13 |
14 | const StyledPutIcon = styled(PutIcon)`
15 | position:absolute
16 | bottom:-2px;
17 | right:-2px
18 | `
19 |
20 | export default function CallPutToken({
21 | currency,
22 | isCall,
23 | size = '24px'
24 | }: {
25 | currency: Currency
26 | isCall: boolean
27 | size?: string
28 | }) {
29 | return (
30 |
31 |
32 | {isCall ? : }
33 |
34 | )
35 | }
36 |
--------------------------------------------------------------------------------
/src/utils/chunkArray.test.ts:
--------------------------------------------------------------------------------
1 | import chunkArray from './chunkArray'
2 |
3 | describe('#chunkArray', () => {
4 | it('size 1', () => {
5 | expect(chunkArray([1, 2, 3], 1)).toEqual([[1], [2], [3]])
6 | })
7 | it('size 0 throws', () => {
8 | expect(() => chunkArray([1, 2, 3], 0)).toThrow('maxChunkSize must be gte 1')
9 | })
10 | it('size gte items', () => {
11 | expect(chunkArray([1, 2, 3], 3)).toEqual([[1, 2, 3]])
12 | expect(chunkArray([1, 2, 3], 4)).toEqual([[1, 2, 3]])
13 | })
14 | it('size exact half', () => {
15 | expect(chunkArray([1, 2, 3, 4], 2)).toEqual([
16 | [1, 2],
17 | [3, 4]
18 | ])
19 | })
20 | it('evenly distributes', () => {
21 | const chunked = chunkArray([...Array(100).keys()], 40)
22 |
23 | expect(chunked).toEqual([
24 | [...Array(34).keys()],
25 | [...Array(34).keys()].map(i => i + 34),
26 | [...Array(32).keys()].map(i => i + 68)
27 | ])
28 |
29 | expect(chunked[0][0]).toEqual(0)
30 | expect(chunked[2][31]).toEqual(99)
31 | })
32 | })
33 |
--------------------------------------------------------------------------------
/src/state/swap/reducer.test.ts:
--------------------------------------------------------------------------------
1 | import { createStore, Store } from 'redux'
2 | import { Field, selectCurrency } from './actions'
3 | import reducer, { SwapState } from './reducer'
4 |
5 | describe('swap reducer', () => {
6 | let store: Store
7 |
8 | beforeEach(() => {
9 | store = createStore(reducer, {
10 | [Field.OUTPUT]: { currencyId: '' },
11 | [Field.INPUT]: { currencyId: '' },
12 | typedValue: '',
13 | independentField: Field.INPUT,
14 | recipient: null
15 | })
16 | })
17 |
18 | describe('selectToken', () => {
19 | it('changes token', () => {
20 | store.dispatch(
21 | selectCurrency({
22 | field: Field.OUTPUT,
23 | currencyId: '0x0000'
24 | })
25 | )
26 |
27 | expect(store.getState()).toEqual({
28 | [Field.OUTPUT]: { currencyId: '0x0000' },
29 | [Field.INPUT]: { currencyId: '' },
30 | typedValue: '',
31 | independentField: Field.INPUT,
32 | recipient: null
33 | })
34 | })
35 | })
36 | })
37 |
--------------------------------------------------------------------------------
/src/pages/Vote/styled.tsx:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components'
2 |
3 | const handleColorType = (status?: any, theme?: any) => {
4 | switch (status) {
5 | case 'pending':
6 | return theme.blue1
7 | case 'active':
8 | return theme.blue1
9 | case 'succeeded':
10 | return theme.green1
11 | case 'defeated':
12 | return theme.red1
13 | case 'queued':
14 | return theme.text3
15 | case 'executed':
16 | return theme.green1
17 | case 'canceled':
18 | return theme.text3
19 | case 'expired':
20 | return theme.text3
21 | default:
22 | return theme.text3
23 | }
24 | }
25 |
26 | export const ProposalStatus = styled.span<{ status: string }>`
27 | font-size: 0.825rem;
28 | font-weight: 600;
29 | padding: 0.5rem;
30 | border-radius: 8px;
31 | color: ${({ status, theme }) => handleColorType(status, theme)};
32 | border: 1px solid ${({ status, theme }) => handleColorType(status, theme)};
33 | width: fit-content;
34 | justify-self: flex-end;
35 | text-transform: uppercase;
36 | `
37 |
--------------------------------------------------------------------------------
/src/assets/svg/cross_circle.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/src/components/MarketStrategy/RadioButton.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components'
3 |
4 | const Label = styled.label<{ checked: boolean }>`
5 | wrap: nowrap;
6 | display: flex;
7 | align-items:center;
8 |
9 | :before {
10 | content: '';
11 | display: block;
12 | width: 6px;
13 | height: 6px;
14 | background-color: ${({ theme, checked }) => (checked ? theme.primary1 : 'transparent')};
15 | border-radius: 50%;
16 | margin-right:8px
17 | border: 4px solid ${({ theme }) => theme.bg1};
18 | box-shadow: 0 0 0 1px ${({ theme, checked }) => (checked ? theme.primary1 : theme.text1)};
19 |
20 | }
21 | & input {
22 | display: none;
23 | }
24 | `
25 |
26 | export function RadioButton({
27 | label,
28 | name,
29 | checked,
30 | onCheck
31 | }: {
32 | label: string
33 | name: string
34 | checked: boolean
35 | onCheck: () => void
36 | }) {
37 | return (
38 |
42 | )
43 | }
44 |
--------------------------------------------------------------------------------
/src/components/Tooltip/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { useCallback, useState } from 'react'
2 | import styled from 'styled-components'
3 | import Popover, { PopoverProps } from '../Popover'
4 |
5 | const TooltipContainer = styled.div`
6 | width: 228px;
7 | padding: 0.6rem 1rem;
8 | line-height: 150%;
9 | font-weight: 400;
10 | white-space: pre-line;
11 | `
12 |
13 | interface TooltipProps extends Omit {
14 | text: string
15 | }
16 |
17 | export default function Tooltip({ text, ...rest }: TooltipProps) {
18 | return {text}} {...rest} />
19 | }
20 |
21 | export function MouseoverTooltip({ children, ...rest }: Omit) {
22 | const [show, setShow] = useState(false)
23 | const open = useCallback(() => setShow(true), [setShow])
24 | const close = useCallback(() => setShow(false), [setShow])
25 | return (
26 |
27 |
28 | {children}
29 |
30 |
31 | )
32 | }
33 |
--------------------------------------------------------------------------------
/src/components/Confetti/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactConfetti from 'react-confetti'
3 | import { useWindowSize } from '../../hooks/useWindowSize'
4 |
5 | // eslint-disable-next-line react/prop-types
6 | export default function Confetti({ start, variant }: { start: boolean; variant?: string }) {
7 | const { width, height } = useWindowSize()
8 |
9 | const _variant = variant ? variant : height && width && height > 1.5 * width ? 'bottom' : variant
10 |
11 | return start && width && height ? (
12 |
31 | ) : null
32 | }
33 |
--------------------------------------------------------------------------------
/src/assets/svg/plus.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/src/state/application/actions.ts:
--------------------------------------------------------------------------------
1 | import { createAction } from '@reduxjs/toolkit'
2 | import { TokenList } from '@uniswap/token-lists'
3 |
4 | export type PopupContent =
5 | | {
6 | txn: {
7 | hash: string
8 | success: boolean
9 | summary?: string
10 | }
11 | }
12 | | {
13 | listUpdate: {
14 | listUrl: string
15 | oldList: TokenList
16 | newList: TokenList
17 | auto: boolean
18 | }
19 | }
20 |
21 | export enum ApplicationModal {
22 | WALLET,
23 | SETTINGS,
24 | SELF_CLAIM,
25 | ADDRESS_CLAIM,
26 | CLAIM_POPUP,
27 | MENU,
28 | DELEGATE,
29 | VOTE
30 | }
31 |
32 | export const updateBlockNumber = createAction<{ chainId: number; blockNumber: number }>('application/updateBlockNumber')
33 | export const setOpenModal = createAction('application/setOpenModal')
34 | export const addPopup = createAction<{ key?: string; removeAfterMs?: number | null; content: PopupContent }>(
35 | 'application/addPopup'
36 | )
37 | export const removePopup = createAction<{ key: string }>('application/removePopup')
38 |
--------------------------------------------------------------------------------
/src/state/transactions/actions.ts:
--------------------------------------------------------------------------------
1 | import { createAction } from '@reduxjs/toolkit'
2 | import { ChainId } from '@uniswap/sdk'
3 |
4 | export interface SerializableTransactionReceipt {
5 | to: string
6 | from: string
7 | contractAddress: string
8 | transactionIndex: number
9 | blockHash: string
10 | transactionHash: string
11 | blockNumber: number
12 | status?: number
13 | }
14 |
15 | export const addTransaction = createAction<{
16 | chainId: ChainId
17 | hash: string
18 | from: string
19 | approval?: { tokenAddress: string; spender: string }
20 | claim?: { recipient: string }
21 | summary?: string
22 | }>('transactions/addTransaction')
23 | export const clearAllTransactions = createAction<{ chainId: ChainId }>('transactions/clearAllTransactions')
24 | export const finalizeTransaction = createAction<{
25 | chainId: ChainId
26 | hash: string
27 | receipt: SerializableTransactionReceipt
28 | }>('transactions/finalizeTransaction')
29 | export const checkedTransaction = createAction<{
30 | chainId: ChainId
31 | hash: string
32 | blockNumber: number
33 | }>('transactions/checkedTransaction')
34 |
--------------------------------------------------------------------------------
/src/components/swap/confirmPriceImpactWithoutFee.ts:
--------------------------------------------------------------------------------
1 | import { Percent } from '@uniswap/sdk'
2 | import { ALLOWED_PRICE_IMPACT_HIGH, PRICE_IMPACT_WITHOUT_FEE_CONFIRM_MIN } from '../../constants'
3 |
4 | /**
5 | * Given the price impact, get user confirmation.
6 | *
7 | * @param priceImpactWithoutFee price impact of the trade without the fee.
8 | */
9 | export default function confirmPriceImpactWithoutFee(priceImpactWithoutFee: Percent): boolean {
10 | if (!priceImpactWithoutFee.lessThan(PRICE_IMPACT_WITHOUT_FEE_CONFIRM_MIN)) {
11 | return (
12 | window.prompt(
13 | `This swap has a price impact of at least ${PRICE_IMPACT_WITHOUT_FEE_CONFIRM_MIN.toFixed(
14 | 0
15 | )}%. Please type the word "confirm" to continue with this swap.`
16 | ) === 'confirm'
17 | )
18 | } else if (!priceImpactWithoutFee.lessThan(ALLOWED_PRICE_IMPACT_HIGH)) {
19 | return window.confirm(
20 | `This swap has a price impact of at least ${ALLOWED_PRICE_IMPACT_HIGH.toFixed(
21 | 0
22 | )}%. Please confirm that you would like to continue with this swap.`
23 | )
24 | }
25 | return true
26 | }
27 |
--------------------------------------------------------------------------------
/src/assets/svg/put_type.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/src/utils/trades.ts:
--------------------------------------------------------------------------------
1 | import { ZERO_PERCENT, ONE_HUNDRED_PERCENT } from './../constants/index'
2 | import { Trade, Percent, currencyEquals } from '@uniswap/sdk'
3 |
4 | // returns whether tradeB is better than tradeA by at least a threshold percentage amount
5 | export function isTradeBetter(
6 | tradeA: Trade | undefined | null,
7 | tradeB: Trade | undefined | null,
8 | minimumDelta: Percent = ZERO_PERCENT
9 | ): boolean | undefined {
10 | if (tradeA && !tradeB) return false
11 | if (tradeB && !tradeA) return true
12 | if (!tradeA || !tradeB) return undefined
13 |
14 | if (
15 | tradeA.tradeType !== tradeB.tradeType ||
16 | !currencyEquals(tradeA.inputAmount.currency, tradeB.inputAmount.currency) ||
17 | !currencyEquals(tradeB.outputAmount.currency, tradeB.outputAmount.currency)
18 | ) {
19 | throw new Error('Trades are not comparable')
20 | }
21 |
22 | if (minimumDelta.equalTo(ZERO_PERCENT)) {
23 | return tradeA.executionPrice.lessThan(tradeB.executionPrice)
24 | } else {
25 | return tradeA.executionPrice.raw.multiply(minimumDelta.add(ONE_HUNDRED_PERCENT)).lessThan(tradeB.executionPrice)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/theme/DarkModeQueryParamReader.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect } from 'react'
2 | import { useDispatch } from 'react-redux'
3 | import { RouteComponentProps } from 'react-router-dom'
4 | import { parse } from 'qs'
5 | import { AppDispatch } from '../state'
6 | import { updateUserDarkMode } from '../state/user/actions'
7 |
8 | export default function DarkModeQueryParamReader({ location: { search } }: RouteComponentProps): null {
9 | const dispatch = useDispatch()
10 |
11 | useEffect(() => {
12 | if (!search) return
13 | if (search.length < 2) return
14 |
15 | const parsed = parse(search, {
16 | parseArrays: false,
17 | ignoreQueryPrefix: true
18 | })
19 |
20 | const theme = parsed.theme
21 |
22 | if (typeof theme !== 'string') return
23 |
24 | if (theme.toLowerCase() === 'light') {
25 | dispatch(updateUserDarkMode({ userDarkMode: true }))
26 | //dispatch(updateUserDarkMode({ userDarkMode: false }))
27 | } else if (theme.toLowerCase() === 'dark') {
28 | dispatch(updateUserDarkMode({ userDarkMode: true }))
29 | }
30 | }, [dispatch, search])
31 |
32 | return null
33 | }
34 |
--------------------------------------------------------------------------------
/src/state/mint/reducer.test.ts:
--------------------------------------------------------------------------------
1 | import { createStore, Store } from 'redux'
2 |
3 | import { Field, typeInput } from './actions'
4 | import reducer, { MintState } from './reducer'
5 |
6 | describe('mint reducer', () => {
7 | let store: Store
8 |
9 | beforeEach(() => {
10 | store = createStore(reducer, {
11 | independentField: Field.CURRENCY_A,
12 | typedValue: '',
13 | otherTypedValue: ''
14 | })
15 | })
16 |
17 | describe('typeInput', () => {
18 | it('sets typed value', () => {
19 | store.dispatch(typeInput({ field: Field.CURRENCY_A, typedValue: '1.0', noLiquidity: false }))
20 | expect(store.getState()).toEqual({ independentField: Field.CURRENCY_A, typedValue: '1.0', otherTypedValue: '' })
21 | })
22 | it('clears other value', () => {
23 | store.dispatch(typeInput({ field: Field.CURRENCY_A, typedValue: '1.0', noLiquidity: false }))
24 | store.dispatch(typeInput({ field: Field.CURRENCY_B, typedValue: '1.0', noLiquidity: false }))
25 | expect(store.getState()).toEqual({ independentField: Field.CURRENCY_B, typedValue: '1.0', otherTypedValue: '' })
26 | })
27 | })
28 | })
29 |
--------------------------------------------------------------------------------
/src/hooks/useLast.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 |
3 | /**
4 | * Returns the last value of type T that passes a filter function
5 | * @param value changing value
6 | * @param filterFn function that determines whether a given value should be considered for the last value
7 | */
8 | export default function useLast(
9 | value: T | undefined | null,
10 | filterFn?: (value: T | null | undefined) => boolean
11 | ): T | null | undefined {
12 | const [last, setLast] = useState(filterFn && filterFn(value) ? value : undefined)
13 | useEffect(() => {
14 | setLast(last => {
15 | const shouldUse: boolean = filterFn ? filterFn(value) : true
16 | if (shouldUse) return value
17 | return last
18 | })
19 | }, [filterFn, value])
20 | return last
21 | }
22 |
23 | function isDefined(x: T | null | undefined): x is T {
24 | return x !== null && x !== undefined
25 | }
26 |
27 | /**
28 | * Returns the last truthy value of type T
29 | * @param value changing value
30 | */
31 | export function useLastTruthy(value: T | undefined | null): T | null | undefined {
32 | return useLast(value, isDefined)
33 | }
34 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Antimatter Overview
2 | Antimatter = Dual Investment + Bull & Bear Tokens + Financial NFTs + Antimatter DAO + more
3 | Antimatter is positioned to be the gateway for DeFi derivatives, including four main products now, including Dual Investment, Bull & Bear Tokens, Financial NFTs, as well as Antimatter DAO.
4 | ## Product - Bull & Bear Tokens
5 | In its tokenized none-oracle perpetual options protocol, users can buy call and put options as an individual holder (buyer) or generate or redeem call and put options as one of the liquidity providers on (Currently on testnet). They can also trade on-chain options for trading profits or to hedge their positions.
6 | Understand Tokenized Perpetual Options in 1 minute
7 | What Antimatter creates is decentralized Bull and Bear Tokens, which are leverage embedded and non-expiry.
8 | When the Underlying Asset price increases, the Bull Token price will increase more.
9 | When the Underlying Asset price decreases, the Bear token price will decrease more.
10 | It is simple as it is, leveraged tokens.
11 | Bullish and want to have more price exposure? Buy Bull Token. Bearish and want to have some hedge? Buy Bear Token.
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/components/Logo/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | // import { HelpCircle } from 'react-feather'
3 | import { ImageProps } from 'rebass'
4 | import { ReactComponent as Unknown } from 'assets/svg/circle_unknown.svg'
5 | import unknownUrl from 'assets/svg/circle_unknown.svg'
6 |
7 | const BAD_SRCS: { [tokenAddress: string]: true } = {}
8 |
9 | export interface LogoProps extends Pick {
10 | srcs: string[]
11 | }
12 |
13 | /**
14 | * Renders an image by sequentially trying a list of URIs, and then eventually a fallback triangle alert
15 | */
16 | export default function Logo({ srcs, alt, ...rest }: LogoProps) {
17 | const [, refresh] = useState(0)
18 |
19 | const src: string | undefined = srcs.find(src => !BAD_SRCS[src])
20 |
21 | if (src) {
22 | return (
23 |
{
28 | if (src) BAD_SRCS[src] = true
29 | refresh(i => i + 1)
30 | }}
31 | />
32 | )
33 | }
34 | return
35 | // return
36 | }
37 |
--------------------------------------------------------------------------------
/src/state/index.ts:
--------------------------------------------------------------------------------
1 | import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit'
2 | import { save, load } from 'redux-localstorage-simple'
3 |
4 | import application from './application/reducer'
5 | import { updateVersion } from './global/actions'
6 | import user from './user/reducer'
7 | import transactions from './transactions/reducer'
8 | import swap from './swap/reducer'
9 | import mint from './mint/reducer'
10 | import lists from './lists/reducer'
11 | import burn from './burn/reducer'
12 | import multicall from './multicall/reducer'
13 |
14 | const PERSISTED_KEYS: string[] = ['user', 'transactions', 'lists']
15 |
16 | const store = configureStore({
17 | reducer: {
18 | application,
19 | user,
20 | transactions,
21 | swap,
22 | mint,
23 | burn,
24 | multicall,
25 | lists
26 | },
27 | middleware: [...getDefaultMiddleware({ thunk: false }), save({ states: PERSISTED_KEYS })],
28 | preloadedState: load({ states: PERSISTED_KEYS })
29 | })
30 |
31 | store.dispatch(updateVersion())
32 |
33 | export default store
34 |
35 | export type AppState = ReturnType
36 | export type AppDispatch = typeof store.dispatch
37 |
--------------------------------------------------------------------------------
/src/state/user/updater.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect } from 'react'
2 | import { useDispatch } from 'react-redux'
3 | import { AppDispatch } from '../index'
4 | import { updateMatchesDarkMode } from './actions'
5 |
6 | export default function Updater(): null {
7 | const dispatch = useDispatch()
8 |
9 | // keep dark mode in sync with the system
10 | useEffect(() => {
11 | const darkHandler = (match: MediaQueryListEvent) => {
12 | dispatch(updateMatchesDarkMode({ matchesDarkMode: match.matches }))
13 | }
14 |
15 | const match = window?.matchMedia('(prefers-color-scheme: dark)')
16 | dispatch(updateMatchesDarkMode({ matchesDarkMode: match.matches }))
17 |
18 | if (match?.addListener) {
19 | match?.addListener(darkHandler)
20 | } else if (match?.addEventListener) {
21 | match?.addEventListener('change', darkHandler)
22 | }
23 |
24 | return () => {
25 | if (match?.removeListener) {
26 | match?.removeListener(darkHandler)
27 | } else if (match?.removeEventListener) {
28 | match?.removeEventListener('change', darkHandler)
29 | }
30 | }
31 | }, [dispatch])
32 |
33 | return null
34 | }
35 |
--------------------------------------------------------------------------------
/src/components/swap/SwapRoute.tsx:
--------------------------------------------------------------------------------
1 | import { Trade } from '@uniswap/sdk'
2 | import React, { Fragment, memo, useContext } from 'react'
3 | import { ChevronRight } from 'react-feather'
4 | import { Flex } from 'rebass'
5 | import { ThemeContext } from 'styled-components'
6 | import { TYPE } from '../../theme'
7 | import { unwrappedToken } from 'utils/wrappedCurrency'
8 |
9 | export default memo(function SwapRoute({ trade }: { trade: Trade }) {
10 | const theme = useContext(ThemeContext)
11 | return (
12 |
13 | {trade.route.path.map((token, i, path) => {
14 | const isLastItem: boolean = i === path.length - 1
15 | const currency = unwrappedToken(token)
16 | return (
17 |
18 |
19 |
20 | {currency.symbol}
21 |
22 |
23 | {isLastItem ? null : }
24 |
25 | )
26 | })}
27 |
28 | )
29 | })
30 |
--------------------------------------------------------------------------------
/src/utils/uriToHttp.test.ts:
--------------------------------------------------------------------------------
1 | import uriToHttp from './uriToHttp'
2 |
3 | describe('uriToHttp', () => {
4 | it('returns .eth.link for ens names', () => {
5 | expect(uriToHttp('t2crtokens.eth')).toEqual([])
6 | })
7 | it('returns https first for http', () => {
8 | expect(uriToHttp('http://test.com')).toEqual(['https://test.com', 'http://test.com'])
9 | })
10 | it('returns https for https', () => {
11 | expect(uriToHttp('https://test.com')).toEqual(['https://test.com'])
12 | })
13 | it('returns ipfs gateways for ipfs:// urls', () => {
14 | expect(uriToHttp('ipfs://QmV8AfDE8GFSGQvt3vck8EwAzsPuNTmtP8VcQJE3qxRPaZ')).toEqual([
15 | 'https://cloudflare-ipfs.com/ipfs/QmV8AfDE8GFSGQvt3vck8EwAzsPuNTmtP8VcQJE3qxRPaZ/',
16 | 'https://ipfs.io/ipfs/QmV8AfDE8GFSGQvt3vck8EwAzsPuNTmtP8VcQJE3qxRPaZ/'
17 | ])
18 | })
19 | it('returns ipns gateways for ipns:// urls', () => {
20 | expect(uriToHttp('ipns://app.uniswap.org')).toEqual([
21 | 'https://cloudflare-ipfs.com/ipns/app.uniswap.org/',
22 | 'https://ipfs.io/ipns/app.uniswap.org/'
23 | ])
24 | })
25 | it('returns empty array for invalid scheme', () => {
26 | expect(uriToHttp('blah:test')).toEqual([])
27 | })
28 | })
29 |
--------------------------------------------------------------------------------
/src/pages/AddLiquidity/redirects.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Redirect, RouteComponentProps } from 'react-router-dom'
3 | import AddLiquidity from './index'
4 |
5 | export function RedirectToAddLiquidity() {
6 | return
7 | }
8 |
9 | const OLD_PATH_STRUCTURE = /^(0x[a-fA-F0-9]{40})-(0x[a-fA-F0-9]{40})$/
10 | export function RedirectOldAddLiquidityPathStructure(props: RouteComponentProps<{ currencyIdA: string }>) {
11 | const {
12 | match: {
13 | params: { currencyIdA }
14 | }
15 | } = props
16 | const match = currencyIdA.match(OLD_PATH_STRUCTURE)
17 | if (match?.length) {
18 | return
19 | }
20 |
21 | // return
22 | return
23 | }
24 |
25 | export function RedirectDuplicateTokenIds(props: RouteComponentProps<{ currencyIdA: string; currencyIdB: string }>) {
26 | const {
27 | match: {
28 | params: { currencyIdA, currencyIdB }
29 | }
30 | } = props
31 | if (currencyIdA.toLowerCase() === currencyIdB.toLowerCase()) {
32 | return
33 | }
34 | // return
35 | return
36 | }
37 |
--------------------------------------------------------------------------------
/src/state/lists/actions.ts:
--------------------------------------------------------------------------------
1 | import { ActionCreatorWithPayload, createAction } from '@reduxjs/toolkit'
2 | import { TokenList, Version } from '@uniswap/token-lists'
3 |
4 | export const fetchTokenList: Readonly<{
5 | pending: ActionCreatorWithPayload<{ url: string; requestId: string }>
6 | fulfilled: ActionCreatorWithPayload<{ url: string; tokenList: TokenList; requestId: string }>
7 | rejected: ActionCreatorWithPayload<{ url: string; errorMessage: string; requestId: string }>
8 | }> = {
9 | pending: createAction('lists/fetchTokenList/pending'),
10 | fulfilled: createAction('lists/fetchTokenList/fulfilled'),
11 | rejected: createAction('lists/fetchTokenList/rejected')
12 | }
13 | // add and remove from list options
14 | export const addList = createAction('lists/addList')
15 | export const removeList = createAction('lists/removeList')
16 |
17 | // select which lists to search across from loaded lists
18 | export const enableList = createAction('lists/enableList')
19 | export const disableList = createAction('lists/disableList')
20 |
21 | // versioning
22 | export const acceptListUpdate = createAction('lists/acceptListUpdate')
23 | export const rejectVersionUpdate = createAction('lists/rejectVersionUpdate')
24 |
--------------------------------------------------------------------------------
/src/constants/abis/migrator.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "inputs": [
4 | {
5 | "internalType": "address",
6 | "name": "_factoryV1",
7 | "type": "address"
8 | },
9 | {
10 | "internalType": "address",
11 | "name": "_router",
12 | "type": "address"
13 | }
14 | ],
15 | "stateMutability": "nonpayable",
16 | "type": "constructor"
17 | },
18 | {
19 | "inputs": [
20 | {
21 | "internalType": "address",
22 | "name": "token",
23 | "type": "address"
24 | },
25 | {
26 | "internalType": "uint256",
27 | "name": "amountTokenMin",
28 | "type": "uint256"
29 | },
30 | {
31 | "internalType": "uint256",
32 | "name": "amountETHMin",
33 | "type": "uint256"
34 | },
35 | {
36 | "internalType": "address",
37 | "name": "to",
38 | "type": "address"
39 | },
40 | {
41 | "internalType": "uint256",
42 | "name": "deadline",
43 | "type": "uint256"
44 | }
45 | ],
46 | "name": "migrate",
47 | "outputs": [],
48 | "stateMutability": "nonpayable",
49 | "type": "function"
50 | },
51 | {
52 | "stateMutability": "payable",
53 | "type": "receive"
54 | }
55 | ]
56 |
--------------------------------------------------------------------------------
/src/utils/parseENSAddress.test.ts:
--------------------------------------------------------------------------------
1 | import { parseENSAddress } from './parseENSAddress'
2 |
3 | describe('parseENSAddress', () => {
4 | it('test cases', () => {
5 | expect(parseENSAddress('hello.eth')).toEqual({ ensName: 'hello.eth', ensPath: undefined })
6 | expect(parseENSAddress('hello.eth/')).toEqual({ ensName: 'hello.eth', ensPath: '/' })
7 | expect(parseENSAddress('hello.world.eth/')).toEqual({ ensName: 'hello.world.eth', ensPath: '/' })
8 | expect(parseENSAddress('hello.world.eth/abcdef')).toEqual({ ensName: 'hello.world.eth', ensPath: '/abcdef' })
9 | expect(parseENSAddress('abso.lutely')).toEqual(undefined)
10 | expect(parseENSAddress('abso.lutely.eth')).toEqual({ ensName: 'abso.lutely.eth', ensPath: undefined })
11 | expect(parseENSAddress('eth')).toEqual(undefined)
12 | expect(parseENSAddress('eth/hello-world')).toEqual(undefined)
13 | expect(parseENSAddress('hello-world.eth')).toEqual({ ensName: 'hello-world.eth', ensPath: undefined })
14 | expect(parseENSAddress('-prefix-dash.eth')).toEqual(undefined)
15 | expect(parseENSAddress('suffix-dash-.eth')).toEqual(undefined)
16 | expect(parseENSAddress('it.eth')).toEqual({ ensName: 'it.eth', ensPath: undefined })
17 | expect(parseENSAddress('only-single--dash.eth')).toEqual(undefined)
18 | })
19 | })
20 |
--------------------------------------------------------------------------------
/src/components/PairChart/apollo/client.js:
--------------------------------------------------------------------------------
1 | import { ApolloClient } from 'apollo-client'
2 | import { InMemoryCache } from 'apollo-cache-inmemory'
3 | import { HttpLink } from 'apollo-link-http'
4 |
5 | export const client = new ApolloClient({
6 | link: new HttpLink({
7 | uri: 'https://api.thegraph.com/subgraphs/name/ianlapham/uniswapv2',
8 | }),
9 | cache: new InMemoryCache(),
10 | shouldBatch: true,
11 | })
12 |
13 | export const healthClient = new ApolloClient({
14 | link: new HttpLink({
15 | uri: 'https://api.thegraph.com/index-node/graphql',
16 | }),
17 | cache: new InMemoryCache(),
18 | shouldBatch: true,
19 | })
20 |
21 | export const v1Client = new ApolloClient({
22 | link: new HttpLink({
23 | uri: 'https://api.thegraph.com/subgraphs/name/ianlapham/uniswap',
24 | }),
25 | cache: new InMemoryCache(),
26 | shouldBatch: true,
27 | })
28 |
29 | export const stakingClient = new ApolloClient({
30 | link: new HttpLink({
31 | uri: 'https://api.thegraph.com/subgraphs/name/way2rach/talisman',
32 | }),
33 | cache: new InMemoryCache(),
34 | shouldBatch: true,
35 | })
36 |
37 | export const blockClient = new ApolloClient({
38 | link: new HttpLink({
39 | uri: 'https://api.thegraph.com/subgraphs/name/blocklytics/ethereum-blocks',
40 | }),
41 | cache: new InMemoryCache(),
42 | })
43 |
--------------------------------------------------------------------------------
/src/components/DoubleLogo/index.tsx:
--------------------------------------------------------------------------------
1 | import { Currency } from '@uniswap/sdk'
2 | import React from 'react'
3 | import styled from 'styled-components'
4 | import CurrencyLogo from '../CurrencyLogo'
5 |
6 | const Wrapper = styled.div<{ margin: boolean; sizeraw: number }>`
7 | position: relative;
8 | display: flex;
9 | flex-direction: row;
10 | margin-right: ${({ sizeraw, margin }) => margin && (sizeraw / 3 + 8).toString() + 'px'};
11 | `
12 |
13 | interface DoubleCurrencyLogoProps {
14 | margin?: boolean
15 | size?: number
16 | currency0?: Currency
17 | currency1?: Currency
18 | }
19 |
20 | const HigherLogo = styled(CurrencyLogo)`
21 | z-index: 2;
22 | `
23 | const CoveredLogo = styled(CurrencyLogo)<{ sizeraw: number }>`
24 | position: absolute;
25 | left: ${({ sizeraw }) => '-' + (sizeraw / 2).toString() + 'px'} !important;
26 | `
27 |
28 | export default function DoubleCurrencyLogo({
29 | currency0,
30 | currency1,
31 | size = 16,
32 | margin = false
33 | }: DoubleCurrencyLogoProps) {
34 | return (
35 |
36 | {currency0 && }
37 | {currency1 && }
38 |
39 | )
40 | }
41 |
--------------------------------------------------------------------------------
/src/utils/useDebouncedChangeHandler.tsx:
--------------------------------------------------------------------------------
1 | import { useCallback, useEffect, useRef, useState } from 'react'
2 |
3 | /**
4 | * Easy way to debounce the handling of a rapidly changing value, e.g. a changing slider input
5 | * @param value value that is rapidly changing
6 | * @param onChange change handler that should receive the debounced updates to the value
7 | * @param debouncedMs how long we should wait for changes to be applied
8 | */
9 | export default function useDebouncedChangeHandler(
10 | value: T,
11 | onChange: (newValue: T) => void,
12 | debouncedMs = 100
13 | ): [T, (value: T) => void] {
14 | const [inner, setInner] = useState(() => value)
15 | const timer = useRef>()
16 |
17 | const onChangeInner = useCallback(
18 | (newValue: T) => {
19 | setInner(newValue)
20 | if (timer.current) {
21 | clearTimeout(timer.current)
22 | }
23 | timer.current = setTimeout(() => {
24 | onChange(newValue)
25 | timer.current = undefined
26 | }, debouncedMs)
27 | },
28 | [debouncedMs, onChange]
29 | )
30 |
31 | useEffect(() => {
32 | if (timer.current) {
33 | clearTimeout(timer.current)
34 | timer.current = undefined
35 | }
36 | setInner(value)
37 | }, [value])
38 |
39 | return [inner, onChangeInner]
40 | }
41 |
--------------------------------------------------------------------------------
/src/state/user/reducer.test.ts:
--------------------------------------------------------------------------------
1 | import { createStore, Store } from 'redux'
2 | import { DEFAULT_DEADLINE_FROM_NOW, INITIAL_ALLOWED_SLIPPAGE } from '../../constants'
3 | import { updateVersion } from '../global/actions'
4 | import reducer, { initialState, UserState } from './reducer'
5 |
6 | describe('swap reducer', () => {
7 | let store: Store
8 |
9 | beforeEach(() => {
10 | store = createStore(reducer, initialState)
11 | })
12 |
13 | describe('updateVersion', () => {
14 | it('has no timestamp originally', () => {
15 | expect(store.getState().lastUpdateVersionTimestamp).toBeUndefined()
16 | })
17 | it('sets the lastUpdateVersionTimestamp', () => {
18 | const time = new Date().getTime()
19 | store.dispatch(updateVersion())
20 | expect(store.getState().lastUpdateVersionTimestamp).toBeGreaterThanOrEqual(time)
21 | })
22 | it('sets allowed slippage and deadline', () => {
23 | store = createStore(reducer, {
24 | ...initialState,
25 | userDeadline: undefined,
26 | userSlippageTolerance: undefined
27 | } as any)
28 | store.dispatch(updateVersion())
29 | expect(store.getState().userDeadline).toEqual(DEFAULT_DEADLINE_FROM_NOW)
30 | expect(store.getState().userSlippageTolerance).toEqual(INITIAL_ALLOWED_SLIPPAGE)
31 | })
32 | })
33 | })
34 |
--------------------------------------------------------------------------------
/src/components/Row/index.tsx:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components'
2 | import { Box } from 'rebass/styled-components'
3 |
4 | export const Row = styled(Box)<{
5 | width?: string
6 | align?: string
7 | justify?: string
8 | padding?: string
9 | border?: string
10 | borderRadius?: string
11 | }>`
12 | width: ${({ width }) => width ?? '100%'};
13 | display: flex;
14 | padding: 0;
15 | align-items: ${({ align }) => align ?? 'center'};
16 | justify-content: ${({ justify }) => justify ?? 'flex-start'};
17 | padding: ${({ padding }) => padding};
18 | border: ${({ border }) => border};
19 | border-radius: ${({ borderRadius }) => borderRadius};
20 | `
21 |
22 | export const RowBetween = styled(Row)`
23 | justify-content: space-between;
24 | `
25 |
26 | export const RowFlat = styled.div`
27 | display: flex;
28 | align-items: flex-end;
29 | `
30 |
31 | export const AutoRow = styled(Row)<{ gap?: string; justify?: string }>`
32 | flex-wrap: wrap;
33 | margin: ${({ gap }) => gap && `-${gap}`};
34 | justify-content: ${({ justify }) => justify && justify};
35 |
36 | & > * {
37 | margin: ${({ gap }) => gap} !important;
38 | }
39 | `
40 |
41 | export const RowFixed = styled(Row)<{ gap?: string; justify?: string }>`
42 | width: fit-content;
43 | margin: ${({ gap }) => gap && `-${gap}`};
44 | `
45 |
46 | export default Row
47 |
--------------------------------------------------------------------------------
/.github/workflows/lint.yml:
--------------------------------------------------------------------------------
1 | name: Lint
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request_target:
8 | branches:
9 | - main
10 |
11 | jobs:
12 | run-linters:
13 | name: Run linters
14 | runs-on: ubuntu-latest
15 |
16 | steps:
17 | - name: Check out Git repository
18 | uses: actions/checkout@v2
19 |
20 | - name: Set up node
21 | uses: actions/setup-node@v1
22 | with:
23 | node-version: 12
24 | always-auth: true
25 | registry-url: https://registry.npmjs.org
26 |
27 | - name: Set output of cache
28 | id: yarn-cache
29 | run: echo "::set-output name=dir::$(yarn cache dir)"
30 |
31 | - name: Node dependency cache
32 | uses: actions/cache@v1
33 | with:
34 | path: ${{ steps.yarn-cache.outputs.dir }}
35 | key: yarn-${{ hashFiles('**/yarn.lock') }}
36 | restore-keys: |
37 | yarn-
38 |
39 | - name: Install dependencies
40 | run: yarn install --frozen-lockfile
41 |
42 | - name: Run linters
43 | uses: wearerequired/lint-action@77d70b9a07ecb93bc98dc46dc27d96c4f004d035
44 | with:
45 | github_token: ${{ secrets.github_token }}
46 | eslint: true
47 | eslint_extensions: js,jsx,ts,tsx,json
48 | auto_fix: true
49 |
--------------------------------------------------------------------------------
/src/assets/svg/transaction_submitted.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/src/components/PairChart/utils/data.ts:
--------------------------------------------------------------------------------
1 | interface BasicData {
2 | token0?: {
3 | id: string
4 | name: string
5 | symbol: string
6 | }
7 | token1?: {
8 | id: string
9 | name: string
10 | symbol: string
11 | }
12 | }
13 |
14 | // Override data return from graph - usually because proxy token has changed
15 | // names since entitiy was created in subgraph
16 | // keys are lowercase token addresses <--------
17 | const TOKEN_OVERRIDES: { [address: string]: { name: string; symbol: string } } = {
18 | '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2': {
19 | name: 'Ether (Wrapped)',
20 | symbol: 'ETH',
21 | },
22 | '0x1416946162b1c2c871a73b07e932d2fb6c932069': {
23 | name: 'Energi',
24 | symbol: 'NRGE',
25 | },
26 | }
27 |
28 | // override tokens with incorrect symbol or names
29 | export function updateNameData(data: BasicData): BasicData | undefined {
30 | if (data?.token0?.id && Object.keys(TOKEN_OVERRIDES).includes(data.token0.id)) {
31 | data.token0.name = TOKEN_OVERRIDES[data.token0.id].name
32 | data.token0.symbol = TOKEN_OVERRIDES[data.token0.id].symbol
33 | }
34 |
35 | if (data?.token1?.id && Object.keys(TOKEN_OVERRIDES).includes(data.token1.id)) {
36 | data.token1.name = TOKEN_OVERRIDES[data.token1.id].name
37 | data.token1.symbol = TOKEN_OVERRIDES[data.token1.id].symbol
38 | }
39 |
40 | return data
41 | }
42 |
--------------------------------------------------------------------------------
/src/hooks/useENSContentHash.ts:
--------------------------------------------------------------------------------
1 | import { namehash } from 'ethers/lib/utils'
2 | import { useMemo } from 'react'
3 | import { useSingleCallResult } from '../state/multicall/hooks'
4 | import isZero from '../utils/isZero'
5 | import { useENSRegistrarContract, useENSResolverContract } from './useContract'
6 |
7 | /**
8 | * Does a lookup for an ENS name to find its contenthash.
9 | */
10 | export default function useENSContentHash(ensName?: string | null): { loading: boolean; contenthash: string | null } {
11 | const ensNodeArgument = useMemo(() => {
12 | if (!ensName) return [undefined]
13 | try {
14 | return ensName ? [namehash(ensName)] : [undefined]
15 | } catch (error) {
16 | return [undefined]
17 | }
18 | }, [ensName])
19 | const registrarContract = useENSRegistrarContract(false)
20 | const resolverAddressResult = useSingleCallResult(registrarContract, 'resolver', ensNodeArgument)
21 | const resolverAddress = resolverAddressResult.result?.[0]
22 | const resolverContract = useENSResolverContract(
23 | resolverAddress && isZero(resolverAddress) ? undefined : resolverAddress,
24 | false
25 | )
26 | const contenthash = useSingleCallResult(resolverContract, 'contenthash', ensNodeArgument)
27 |
28 | return {
29 | contenthash: contenthash.result?.[0] ?? null,
30 | loading: resolverAddressResult.loading || contenthash.loading
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/pages/AddLiquidity/PoolPriceBar.tsx:
--------------------------------------------------------------------------------
1 | import { Currency, Percent, Price } from '@uniswap/sdk'
2 | import React from 'react'
3 | import DataCard from 'components/Card/DataCard'
4 | import { ONE_BIPS } from '../../constants'
5 | import { Field } from '../../state/mint/actions'
6 |
7 | export function PoolPriceBar({
8 | cardTitle,
9 | currencies,
10 | noLiquidity,
11 | poolTokenPercentage,
12 | price
13 | }: {
14 | cardTitle?: string
15 | currencies: { [field in Field]?: Currency }
16 | noLiquidity?: boolean
17 | poolTokenPercentage?: Percent
18 | price?: Price
19 | }) {
20 | return (
21 |
43 | )
44 | }
45 |
--------------------------------------------------------------------------------
/src/pages/Pool/styleds.tsx:
--------------------------------------------------------------------------------
1 | import { Text } from 'rebass'
2 | import styled from 'styled-components'
3 |
4 | export const Wrapper = styled.div`
5 | position: relative;
6 | padding: 1rem;
7 | `
8 |
9 | export const ClickableText = styled(Text)`
10 | :hover {
11 | cursor: pointer;
12 | }
13 | color: ${({ theme }) => theme.primary1};
14 | `
15 | export const MaxButton = styled.button<{ width: string }>`
16 | padding: 0.3rem 0.5rem;
17 | background-color: ${({ theme }) => theme.bg4};
18 | border: none;
19 | border-radius: 14px;
20 | font-size: 14px;
21 | ${({ theme }) => theme.mediaWidth.upToSmall`
22 | padding: 0.25rem 0.5rem;
23 | `};
24 | font-weight: 400;
25 | cursor: pointer;
26 | margin: 0.25rem;
27 | overflow: hidden;
28 | color: ${({ theme }) => theme.text1};
29 | :hover {
30 | border: 1px solid ${({ theme }) => theme.primary1};
31 | }
32 | :focus {
33 | border: 1px solid ${({ theme }) => theme.primary1};
34 | outline: none;
35 | }
36 | `
37 |
38 | export const Dots = styled.span`
39 | &::after {
40 | display: inline-block;
41 | animation: ellipsis 1.25s infinite;
42 | content: '.';
43 | width: 1em;
44 | text-align: left;
45 | }
46 | @keyframes ellipsis {
47 | 0% {
48 | content: '.';
49 | }
50 | 33% {
51 | content: '..';
52 | }
53 | 66% {
54 | content: '...';
55 | }
56 | }
57 | `
58 |
--------------------------------------------------------------------------------
/src/assets/svg/call_type.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/src/assets/svg/walletConnect_logo.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/utils/chunkArray.ts:
--------------------------------------------------------------------------------
1 | const CONSERVATIVE_BLOCK_GAS_LIMIT = 10_000_000 // conservative, hard-coded estimate of the current block gas limit
2 | export const DEFAULT_GAS_REQUIRED = 200_000 // the default value for calls that don't specify gasRequired
3 |
4 | // chunks array into chunks
5 | // evenly distributes items among the chunks
6 | export function chunkArray(items: T[], gasLimit = CONSERVATIVE_BLOCK_GAS_LIMIT * 10): T[][] {
7 | const chunks: T[][] = []
8 | let currentChunk: T[] = []
9 | let currentChunkCumulativeGas = 0
10 |
11 | for (let i = 0; i < items.length; i++) {
12 | const item = items[i]
13 |
14 | // calculate the gas required by the current item
15 | const gasRequired = (item as { gasRequired?: number })?.gasRequired ?? DEFAULT_GAS_REQUIRED
16 |
17 | // if the current chunk is empty, or the current item wouldn't push it over the gas limit,
18 | // append the current item and increment the cumulative gas
19 | if (currentChunk.length === 0 || currentChunkCumulativeGas + gasRequired < gasLimit) {
20 | currentChunk.push(item)
21 | currentChunkCumulativeGas += gasRequired
22 | } else {
23 | // otherwise, push the current chunk and create a new chunk
24 | chunks.push(currentChunk)
25 | currentChunk = [item]
26 | currentChunkCumulativeGas = gasRequired
27 | }
28 | }
29 | if (currentChunk.length > 0) chunks.push(currentChunk)
30 |
31 | return chunks
32 | }
33 |
--------------------------------------------------------------------------------
/src/components/DoubleLogo/DoubleLogoReverse.tsx:
--------------------------------------------------------------------------------
1 | import { Currency } from '@uniswap/sdk'
2 | import React from 'react'
3 | import styled from 'styled-components'
4 | import CurrencyLogo from '../CurrencyLogo'
5 |
6 | const Wrapper = styled.div<{ mr?: string; sizeraw: number }>`
7 | position: relative;
8 | display: flex;
9 | flex-direction: row;
10 | width: ${({ sizeraw }) => sizeraw * 1.68 + 'px'};
11 | margin-right: ${({ mr }) => mr ?? 0};
12 | `
13 |
14 | interface DoubleCurrencyLogoProps {
15 | mr?: string
16 | size?: number
17 | currency0?: Currency
18 | currency1?: Currency
19 | }
20 |
21 | const HigherLogo = styled(CurrencyLogo)`
22 | z-index: 1;
23 | `
24 | const CoveredLogo = styled(CurrencyLogo)<{ sizeraw: number }>`
25 | position: absolute;
26 | left: ${({ sizeraw }) => '-' + (sizeraw / 2).toString() + 'px'} !important;
27 | `
28 |
29 | export default function DoubleCurrencyLogoReverse({ currency0, currency1, size = 16, mr }: DoubleCurrencyLogoProps) {
30 | return (
31 |
32 | {currency0 && }
33 | {currency1 && (
34 |
40 | )}
41 |
42 | )
43 | }
44 |
--------------------------------------------------------------------------------
/src/components/AccountDetails/Copy.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components'
3 | import useCopyClipboard from '../../hooks/useCopyClipboard'
4 |
5 | import { LinkStyledButton } from '../../theme'
6 | import { CheckCircle, Copy } from 'react-feather'
7 |
8 | const CopyIcon = styled(LinkStyledButton)`
9 | color: ${({ theme }) => theme.text3};
10 | flex-shrink: 0;
11 | display: flex;
12 | text-decoration: none;
13 | font-size: 0.825rem;
14 | :hover,
15 | :active,
16 | :focus {
17 | text-decoration: none;
18 | color: ${({ theme }) => theme.text1};
19 | }
20 | `
21 | const TransactionStatusText = styled.span`
22 | margin-left: 0.25rem;
23 | font-size: 0.825rem;
24 | ${({ theme }) => theme.flexRowNoWrap};
25 | align-items: center;
26 | `
27 |
28 | export default function CopyHelper(props: { toCopy: string; children?: React.ReactNode; fixedSize?: boolean }) {
29 | const [isCopied, setCopied] = useCopyClipboard()
30 |
31 | return (
32 | setCopied(props.toCopy)}>
33 | {isCopied ? (
34 |
35 |
36 | {!props.fixedSize && Copied}
37 |
38 | ) : (
39 |
40 |
41 |
42 | )}
43 | {isCopied ? '' : props.children}
44 |
45 | )
46 | }
47 |
--------------------------------------------------------------------------------
/sitemap.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | https://antimatter.finance/ecosystem
5 | 2020-06-04
6 |
7 |
8 |
9 |
10 | https://www.google.com/ping?sitemap=https://raw.githubusercontent.com/antimatter-dao/Antimatter-BullBear/master/sitemap.xml
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | https://antimatter.finance/
20 |
21 | 2021-01-01
22 |
23 | monthly
24 |
25 | 0.8
26 |
27 |
28 |
29 |
30 |
31 | https://antimatter.finance/ecosystem
32 |
33 | weekly
34 |
35 |
36 |
37 |
38 |
39 | https://explorer-test.antimatter.finance/
40 |
41 | 2021-12-23
42 |
43 | weekly
44 |
45 |
46 |
47 |
48 |
49 | http://bas-node.antimatter.finance:5000/
50 |
51 | 20202104-12-23T18:00:15+00:00
52 |
53 | 0.3
54 |
55 |
56 |
57 |
58 |
59 | https://docs.antimatter.finance/introduction/antimatter-overview
60 |
61 | 2004-11-23
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/src/state/mint/reducer.ts:
--------------------------------------------------------------------------------
1 | import { createReducer } from '@reduxjs/toolkit'
2 | import { Field, resetMintState, typeInput } from './actions'
3 |
4 | export interface MintState {
5 | readonly independentField: Field
6 | readonly typedValue: string
7 | readonly otherTypedValue: string // for the case when there's no liquidity
8 | }
9 |
10 | const initialState: MintState = {
11 | independentField: Field.CURRENCY_A,
12 | typedValue: '',
13 | otherTypedValue: ''
14 | }
15 |
16 | export default createReducer(initialState, builder =>
17 | builder
18 | .addCase(resetMintState, () => initialState)
19 | .addCase(typeInput, (state, { payload: { field, typedValue, noLiquidity } }) => {
20 | if (noLiquidity) {
21 | // they're typing into the field they've last typed in
22 | if (field === state.independentField) {
23 | return {
24 | ...state,
25 | independentField: field,
26 | typedValue
27 | }
28 | }
29 | // they're typing into a new field, store the other value
30 | else {
31 | return {
32 | ...state,
33 | independentField: field,
34 | typedValue,
35 | otherTypedValue: state.typedValue
36 | }
37 | }
38 | } else {
39 | return {
40 | ...state,
41 | independentField: field,
42 | typedValue,
43 | otherTypedValue: ''
44 | }
45 | }
46 | })
47 | )
48 |
--------------------------------------------------------------------------------
/src/pages/Swap/redirects.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react'
2 | import { useDispatch } from 'react-redux'
3 | import { Redirect, RouteComponentProps } from 'react-router-dom'
4 | import { AppDispatch } from '../../state'
5 | import { ApplicationModal, setOpenModal } from '../../state/application/actions'
6 |
7 | // Redirects to swap but only replace the pathname
8 | export function RedirectPathToSwapOnly({ location }: RouteComponentProps) {
9 | return
10 | }
11 |
12 | // Redirects from the /swap/:outputCurrency path to the /swap?outputCurrency=:outputCurrency format
13 | export function RedirectToSwap(props: RouteComponentProps<{ outputCurrency: string }>) {
14 | const {
15 | location: { search },
16 | match: {
17 | params: { outputCurrency }
18 | }
19 | } = props
20 |
21 | return (
22 | 1
28 | ? `${search}&outputCurrency=${outputCurrency}`
29 | : `?outputCurrency=${outputCurrency}`
30 | }}
31 | />
32 | )
33 | }
34 |
35 | export function OpenClaimAddressModalAndRedirectToSwap(props: RouteComponentProps) {
36 | const dispatch = useDispatch()
37 | useEffect(() => {
38 | dispatch(setOpenModal(ApplicationModal.ADDRESS_CLAIM))
39 | }, [dispatch])
40 | return
41 | }
42 |
--------------------------------------------------------------------------------
/src/components/Pagination/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import MuiPagination from '@material-ui/lab/Pagination'
3 | import styled from 'styled-components'
4 | import { ThemeProvider as MaterialThemeProvider } from '@material-ui/core/styles'
5 | import { createTheme } from '@material-ui/core/styles'
6 |
7 | const materialTheme = createTheme({
8 | palette: {
9 | type: 'dark'
10 | }
11 | })
12 |
13 | const materialThemeLight = createTheme({
14 | palette: {
15 | type: 'light'
16 | }
17 | })
18 |
19 | const StyledPagination = styled.div`
20 | display: flex;
21 | justify-content: center;
22 | & > * {
23 | margin-bottom: 20px;
24 | }
25 | `
26 |
27 | interface PaginationProps {
28 | count: number
29 | page: number
30 | setPage?: (page: number) => void
31 | onChange?: (event: object, page: number) => void
32 | isLightBg?: boolean
33 | }
34 | export default function Pagination({ count, page, onChange, setPage, isLightBg }: PaginationProps) {
35 | return (
36 |
37 | {count && (
38 |
39 | {
43 | onChange && onChange(event, page)
44 | setPage && setPage(page)
45 | }}
46 | size="large"
47 | />
48 |
49 | )}
50 |
51 | )
52 | }
53 |
--------------------------------------------------------------------------------
/src/utils/marketStrategyUtils.ts:
--------------------------------------------------------------------------------
1 | import { ChainId, Currency, ETHER, JSBI, Token, TokenAmount } from '@uniswap/sdk'
2 | import { tryParseAmount } from 'state/swap/hooks'
3 | import { absolute } from 'state/market/hooks'
4 | import { Symbol } from 'constants/index'
5 |
6 | export const isNegative = (val?: string): boolean => val?.toString()[0] === '-'
7 |
8 | export const parseBalance = ({
9 | val,
10 | token,
11 | toSignificant = 6
12 | }: {
13 | val?: string
14 | token: Token
15 | toSignificant?: number
16 | }) => {
17 | const string = val?.toString()
18 | const amount = new TokenAmount(token, JSBI.BigInt(absolute(string ?? ''))).toSignificant(toSignificant)
19 | if (string && string[0] === '-') {
20 | return '-' + amount
21 | } else {
22 | return amount
23 | }
24 | }
25 | export const parsedGreaterThan = (userInput: string, balance: string) => {
26 | if (userInput && balance) {
27 | const v1 = tryParseAmount(userInput, ETHER)?.raw
28 | const v2 = JSBI.BigInt(balance.toString())
29 | return v1 && v2 ? JSBI.greaterThan(v1, v2) : undefined
30 | }
31 | return
32 | }
33 | export const currencyNameHelper = (currency?: Currency | null, defaultString?: string, chainId: ChainId = 1) => {
34 | const symbol = currency === ETHER ? Symbol[chainId] : currency?.symbol
35 | return (
36 | (currency && symbol && symbol.length > 20
37 | ? symbol.slice(0, 4) + '...' + symbol.slice(symbol.length - 5, symbol.length)
38 | : symbol) ||
39 | defaultString ||
40 | ''
41 | )
42 | }
43 |
--------------------------------------------------------------------------------
/src/components/Popups/TransactionPopup.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react'
2 | import { AlertCircle } from 'react-feather'
3 | import styled, { ThemeContext } from 'styled-components'
4 | import { ReactComponent as CheckCircle } from '../../assets/svg/check_circle.svg'
5 | import { useActiveWeb3React } from '../../hooks'
6 | import { TYPE } from '../../theme'
7 | import { ExternalLink } from '../../theme/components'
8 | import { getEtherscanLink } from '../../utils'
9 | import { AutoColumn } from '../Column'
10 | import { AutoRow } from '../Row'
11 |
12 | const RowNoFlex = styled(AutoRow)`
13 | flex-wrap: nowrap;
14 | `
15 |
16 | export default function TransactionPopup({
17 | hash,
18 | success,
19 | summary
20 | }: {
21 | hash: string
22 | success?: boolean
23 | summary?: string
24 | }) {
25 | const { chainId } = useActiveWeb3React()
26 |
27 | const theme = useContext(ThemeContext)
28 |
29 | return (
30 |
31 |
32 |
35 | {summary ?? 'Hash: ' + hash.slice(0, 8) + '...' + hash.slice(58, 65)}{' '}
36 |
37 | {chainId && (
38 |
39 | View on explorer
40 |
41 | )}
42 |
43 | )
44 | }
45 |
--------------------------------------------------------------------------------
/src/hooks/useENSAddress.ts:
--------------------------------------------------------------------------------
1 | import { namehash } from 'ethers/lib/utils'
2 | import { useMemo } from 'react'
3 | import { useSingleCallResult } from '../state/multicall/hooks'
4 | import isZero from '../utils/isZero'
5 | import { useENSRegistrarContract, useENSResolverContract } from './useContract'
6 | import useDebounce from './useDebounce'
7 |
8 | /**
9 | * Does a lookup for an ENS name to find its address.
10 | */
11 | export default function useENSAddress(ensName?: string | null): { loading: boolean; address: string | null } {
12 | const debouncedName = useDebounce(ensName, 200)
13 | const ensNodeArgument = useMemo(() => {
14 | if (!debouncedName) return [undefined]
15 | try {
16 | return debouncedName ? [namehash(debouncedName)] : [undefined]
17 | } catch (error) {
18 | return [undefined]
19 | }
20 | }, [debouncedName])
21 | const registrarContract = useENSRegistrarContract(false)
22 | const resolverAddress = useSingleCallResult(registrarContract, 'resolver', ensNodeArgument)
23 | const resolverAddressResult = resolverAddress.result?.[0]
24 | const resolverContract = useENSResolverContract(
25 | resolverAddressResult && !isZero(resolverAddressResult) ? resolverAddressResult : undefined,
26 | false
27 | )
28 | const addr = useSingleCallResult(resolverContract, 'addr', ensNodeArgument)
29 |
30 | const changed = debouncedName !== ensName
31 | return {
32 | address: changed ? null : addr.result?.[0] ?? null,
33 | loading: changed || resolverAddress.loading || addr.loading
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/components/SwitchTab/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components'
3 |
4 | export const SwitchTabWrapper = styled.div`
5 | border-bottom: 1px solid ${({ theme }) => theme.text5};
6 | white-space: nowrap;
7 | ${({ theme }) => theme.mediaWidth.upToSmall`
8 | overflow-x: auto;
9 | overflow-y: hidden;
10 | `};
11 | `
12 |
13 | export const Tab = styled.button<{ selected: boolean }>`
14 | border: none;
15 | background: none;
16 | padding: 14px 0;
17 | margin-right: 40px;
18 | font-size: 16px;
19 | font-weight: 500;
20 | color: ${({ selected, theme }) => (selected ? theme.primary1 : theme.white)};
21 | border-bottom: 2px solid ${({ selected, theme }) => (selected ? theme.primary4 : 'transparent')};
22 | margin-bottom: -1px;
23 | transition: 0.3s;
24 | cursor: pointer;
25 | &:hover {
26 | color: ${({ theme }) => theme.primary1};
27 | }
28 | `
29 |
30 | export default function SwitchTab({
31 | currentTab,
32 | onTabClick,
33 | tabs,
34 | tabStyle
35 | }: {
36 | currentTab: string
37 | onTabClick: (tab: string) => () => void
38 | tabs: { [key: string]: string }
39 | tabStyle?: object
40 | }) {
41 | return (
42 |
43 | {Object.keys(tabs).map(tab => {
44 | const tabName = tabs[tab as keyof typeof tabs]
45 | return (
46 |
47 | {tabName}
48 |
49 | )
50 | })}
51 |
52 | )
53 | }
54 |
--------------------------------------------------------------------------------
/src/assets/svg/circle_unknown.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/pages/Info/PriceItem.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { AutoColumn } from '../../components/Column'
3 | import { TYPE } from '../../theme'
4 | import { Divider, NumberWithUnit } from './index'
5 | import { useCurrency } from '../../hooks/Tokens'
6 | import { TranslucentCard } from '../../components/Card'
7 | import { ReactComponent as CallToken } from '../../assets/svg/call_token.svg'
8 | import { ReactComponent as PutToken } from '../../assets/svg/put_token.svg'
9 | import { useUSDTPrice } from '../../utils/useUSDCPrice'
10 |
11 | export default function PriceItem({ address, total, isCall }: { address: string; total: string; isCall?: boolean }) {
12 | const currency = useCurrency(address)
13 | const price = useUSDTPrice(currency ?? undefined)
14 | return (
15 |
16 |
17 |
18 |
19 | TOTAL NUMBER OF {currency?.symbol}
20 |
21 | {isCall ? : }
22 | {total}
23 |
24 |
25 |
26 |
27 |
28 |
29 | PRICE OF {currency?.symbol}
30 |
31 |
32 |
33 |
34 |
35 | )
36 | }
37 |
--------------------------------------------------------------------------------
/test/unit/functions/approveAmountCallData.test.ts:
--------------------------------------------------------------------------------
1 | import { AddressZero } from '@ethersproject/constants'
2 | import { ChainId, Currency, CurrencyAmount, Token } from '@sushiswap/core-sdk'
3 | import approveAmountCalldata, { toHex } from 'app/functions/approveAmountCalldata'
4 |
5 | describe('approveAmountCalldata functions', () => {
6 | describe('toHex', () => {
7 | it('handles null address', () => {
8 | const input = '0x0000000000000000000000000000000000000000'
9 | expect(toHex(input)).toEqual('0x00')
10 | })
11 | })
12 | describe('approveAmountCalldata', () => {
13 | it('must be called with token', () => {
14 | const tokenAmount = CurrencyAmount.fromRawAmount({ isToken: false, decimals: 0 } as Currency, '100')
15 | const spender = AddressZero
16 |
17 | expect(() => approveAmountCalldata(tokenAmount, spender)).toThrowError('Must call with an amount of token')
18 | })
19 |
20 | it('returns data', () => {
21 | const tokenAmount = CurrencyAmount.fromRawAmount(new Token(ChainId.ETHEREUM, AddressZero, 0), '100')
22 | const spender = AddressZero
23 |
24 | const res = approveAmountCalldata(tokenAmount, spender)
25 | expect(res).toEqual({
26 | to: '0x0000000000000000000000000000000000000000',
27 | data: '0x095ea7b300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064',
28 | value: '0x0',
29 | })
30 | })
31 | })
32 | })
--------------------------------------------------------------------------------
/src/utils/computeUniCirculation.test.ts:
--------------------------------------------------------------------------------
1 | import { ChainId, JSBI, Token, TokenAmount } from '@uniswap/sdk'
2 | import { BigNumber } from 'ethers'
3 | import { ZERO_ADDRESS } from '../constants'
4 | import { computeUniCirculation } from './computeUniCirculation'
5 |
6 | describe('computeUniCirculation', () => {
7 | const token = new Token(ChainId.RINKEBY, ZERO_ADDRESS, 18)
8 |
9 | function expandTo18Decimals(num: JSBI | string | number) {
10 | return JSBI.multiply(JSBI.BigInt(num), JSBI.exponentiate(JSBI.BigInt(10), JSBI.BigInt(18)))
11 | }
12 |
13 | function tokenAmount(num: JSBI | string | number) {
14 | return new TokenAmount(token, expandTo18Decimals(num))
15 | }
16 |
17 | it('before staking', () => {
18 | expect(computeUniCirculation(token, BigNumber.from(0), undefined)).toEqual(tokenAmount(150_000_000))
19 | expect(computeUniCirculation(token, BigNumber.from(1600387200), undefined)).toEqual(tokenAmount(150_000_000))
20 | })
21 | it('mid staking', () => {
22 | expect(computeUniCirculation(token, BigNumber.from(1600387200 + 15 * 24 * 60 * 60), undefined)).toEqual(
23 | tokenAmount(155_000_000)
24 | )
25 | })
26 | it('after staking and treasury vesting cliff', () => {
27 | expect(computeUniCirculation(token, BigNumber.from(1600387200 + 60 * 24 * 60 * 60), undefined)).toEqual(
28 | tokenAmount(224_575_341)
29 | )
30 | })
31 | it('subtracts unclaimed uni', () => {
32 | expect(computeUniCirculation(token, BigNumber.from(1600387200 + 15 * 24 * 60 * 60), tokenAmount(1000))).toEqual(
33 | tokenAmount(154_999_000)
34 | )
35 | })
36 | })
37 |
--------------------------------------------------------------------------------
/src/components/Spinner/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { CircularProgress, makeStyles, createStyles } from '@material-ui/core'
3 |
4 | interface Props {
5 | size?: string | number
6 | thickness?: number
7 | color?: string
8 | marginLeft?: string | number
9 | marginRight?: string | number
10 | }
11 |
12 | const useStyles = makeStyles(() =>
13 | createStyles({
14 | root: {
15 | position: 'relative',
16 | marginLeft: (props: Props) => props.marginLeft ?? 0,
17 | marginRight: (props: Props) => props.marginRight ?? 0,
18 | height: (props: Props) => props.size,
19 | width: (props: Props) => props.size
20 | },
21 | bottom: {
22 | '& svg circle': {
23 | stroke: '#A1A1A1'
24 | }
25 | },
26 | top: {
27 | color: (props: Props) => props.color ?? '#B2F355',
28 | animationDuration: '850ms',
29 | position: 'absolute',
30 | left: 0,
31 | top: 0
32 | }
33 | })
34 | )
35 |
36 | export default function Spinner({ size = 16, thickness = 3, ...props }: Props) {
37 | const classes = useStyles({ ...props, size })
38 |
39 | return (
40 |
41 |
48 |
55 |
56 | )
57 | }
58 |
--------------------------------------------------------------------------------
/src/hooks/useCreationCallback.ts:
--------------------------------------------------------------------------------
1 | import { ChainId, Currency, WETH } from '@uniswap/sdk'
2 | import { useActiveWeb3React } from 'hooks'
3 | import { useMemo } from 'react'
4 | import { tryParseAmount } from 'state/swap/hooks'
5 | import { currencyId } from 'utils/currencyId'
6 | import { useAntimatterContract } from './useContract'
7 |
8 | const parseNumber = (val: string, currency: Currency) => {
9 | return tryParseAmount(val, currency)?.raw.toString() ?? '0'
10 | }
11 | const getAddress = (currency: Currency, chainId: ChainId) => {
12 | const id = currencyId(currency)
13 | if (id === 'ETH') {
14 | return currencyId(WETH[chainId as ChainId])
15 | }
16 | return id
17 | }
18 |
19 | export function useCreationCallback(): {
20 | callback: null | ((...args: any[]) => Promise)
21 | } {
22 | const contract = useAntimatterContract()
23 | const { chainId } = useActiveWeb3React()
24 | return useMemo(() => {
25 | if (!contract) return { callback: null }
26 | return {
27 | callback: async function(
28 | underlying: Currency,
29 | currency: Currency,
30 | priceFloor: string,
31 | priceCap: string
32 | ): Promise<{} | null> {
33 | if (!underlying || !currency || !priceCap || !priceFloor || !chainId) {
34 | return null
35 | }
36 | return contract.createOption(
37 | getAddress(underlying, chainId),
38 | getAddress(currency, chainId),
39 | parseNumber(priceFloor, currency),
40 | parseNumber(priceCap, currency)
41 | )
42 | }
43 | }
44 | }, [chainId, contract])
45 | }
46 |
--------------------------------------------------------------------------------
/src/utils/contenthashToUri.ts:
--------------------------------------------------------------------------------
1 | import CID from 'cids'
2 | import { getCodec, rmPrefix } from 'multicodec'
3 | import { decode, toB58String } from 'multihashes'
4 |
5 | export function hexToUint8Array(hex: string): Uint8Array {
6 | hex = hex.startsWith('0x') ? hex.substr(2) : hex
7 | if (hex.length % 2 !== 0) throw new Error('hex must have length that is multiple of 2')
8 | const arr = new Uint8Array(hex.length / 2)
9 | for (let i = 0; i < arr.length; i++) {
10 | arr[i] = parseInt(hex.substr(i * 2, 2), 16)
11 | }
12 | return arr
13 | }
14 |
15 | const UTF_8_DECODER = new TextDecoder()
16 |
17 | /**
18 | * Returns the URI representation of the content hash for supported codecs
19 | * @param contenthash to decode
20 | */
21 | export default function contenthashToUri(contenthash: string): string {
22 | const buff = hexToUint8Array(contenthash)
23 | const codec = getCodec(buff as Buffer) // the typing is wrong for @types/multicodec
24 | switch (codec) {
25 | case 'ipfs-ns': {
26 | const data = rmPrefix(buff as Buffer)
27 | const cid = new CID(data)
28 | return `ipfs://${toB58String(cid.multihash)}`
29 | }
30 | case 'ipns-ns': {
31 | const data = rmPrefix(buff as Buffer)
32 | const cid = new CID(data)
33 | const multihash = decode(cid.multihash)
34 | if (multihash.name === 'identity') {
35 | return `ipns://${UTF_8_DECODER.decode(multihash.digest).trim()}`
36 | } else {
37 | return `ipns://${toB58String(cid.multihash)}`
38 | }
39 | }
40 | default:
41 | throw new Error(`Unrecognized codec: ${codec}`)
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/components/Loader/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | import styled, { keyframes } from 'styled-components'
4 |
5 | const rotate = keyframes`
6 | from {
7 | transform: rotate(0deg);
8 | }
9 | to {
10 | transform: rotate(360deg);
11 | }
12 | `
13 |
14 | const StyledSVG = styled.svg<{ size: string; stroke?: string }>`
15 | animation: 2s ${rotate} linear infinite;
16 | height: ${({ size }) => size};
17 | width: ${({ size }) => size};
18 | path {
19 | stroke: ${({ stroke, theme }) => stroke ?? theme.primary1};
20 | }
21 | `
22 |
23 | /**
24 | * Takes in custom size and stroke for circle color, default to primary color as fill,
25 | * need ...rest for layered styles on top
26 | */
27 | export default function Loader({
28 | size = '16px',
29 | stroke,
30 | ...rest
31 | }: {
32 | size?: string
33 | stroke?: string
34 | [k: string]: any
35 | }) {
36 | return (
37 |
38 | {/*
44 | */}
45 |
46 |
47 |
48 |
49 | )
50 | }
51 |
--------------------------------------------------------------------------------
/src/hooks/useAddTokenToMetamask.ts:
--------------------------------------------------------------------------------
1 | import { getTokenLogoURL } from './../components/CurrencyLogo/index'
2 | import { wrappedCurrency } from 'utils/wrappedCurrency'
3 | import { Currency, Token } from '@uniswap/sdk'
4 | import { useCallback, useState } from 'react'
5 | import { useActiveWeb3React } from 'hooks'
6 |
7 | export default function useAddTokenToMetamask(
8 | currencyToAdd: Currency | undefined
9 | ): { addToken: () => void; success: boolean | undefined } {
10 | const { library, chainId } = useActiveWeb3React()
11 |
12 | const token: Token | undefined = wrappedCurrency(currencyToAdd, chainId)
13 |
14 | const [success, setSuccess] = useState()
15 |
16 | const addToken = useCallback(() => {
17 | if (library && library.provider.isMetaMask && library.provider.request && token) {
18 | library.provider
19 | .request({
20 | method: 'wallet_watchAsset',
21 | params: {
22 | // eslint-disable-next-line @typescript-eslint/ban-ts-ignore
23 | //@ts-ignore // need this for incorrect ethers provider type
24 | type: 'ERC20',
25 | options: {
26 | address: token.address,
27 | symbol: token.symbol,
28 | decimals: token.decimals,
29 | image: getTokenLogoURL(token.address)
30 | }
31 | }
32 | })
33 | .then(success => {
34 | setSuccess(success)
35 | })
36 | .catch(() => setSuccess(false))
37 | } else {
38 | setSuccess(false)
39 | }
40 | }, [library, token])
41 |
42 | return { addToken, success }
43 | }
44 |
--------------------------------------------------------------------------------
/src/assets/svg/transaction_error.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/assets/svg/put_token.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/src/state/transactions/updater.test.ts:
--------------------------------------------------------------------------------
1 | import { shouldCheck } from './updater'
2 |
3 | describe('transactions updater', () => {
4 | describe('shouldCheck', () => {
5 | it('returns true if no receipt and never checked', () => {
6 | expect(shouldCheck(10, { addedTime: 100 })).toEqual(true)
7 | })
8 | it('returns false if has receipt and never checked', () => {
9 | expect(shouldCheck(10, { addedTime: 100, receipt: {} })).toEqual(false)
10 | })
11 | it('returns true if has not been checked in 1 blocks', () => {
12 | expect(shouldCheck(10, { addedTime: new Date().getTime(), lastCheckedBlockNumber: 9 })).toEqual(true)
13 | })
14 | it('returns false if checked in last 3 blocks and greater than 20 minutes old', () => {
15 | expect(shouldCheck(10, { addedTime: new Date().getTime() - 21 * 60 * 1000, lastCheckedBlockNumber: 8 })).toEqual(
16 | false
17 | )
18 | })
19 | it('returns true if not checked in last 5 blocks and greater than 20 minutes old', () => {
20 | expect(shouldCheck(10, { addedTime: new Date().getTime() - 21 * 60 * 1000, lastCheckedBlockNumber: 5 })).toEqual(
21 | true
22 | )
23 | })
24 | it('returns false if checked in last 10 blocks and greater than 60 minutes old', () => {
25 | expect(shouldCheck(20, { addedTime: new Date().getTime() - 61 * 60 * 1000, lastCheckedBlockNumber: 11 })).toEqual(
26 | false
27 | )
28 | })
29 | it('returns true if checked in last 3 blocks and greater than 20 minutes old', () => {
30 | expect(shouldCheck(20, { addedTime: new Date().getTime() - 61 * 60 * 1000, lastCheckedBlockNumber: 10 })).toEqual(
31 | true
32 | )
33 | })
34 | })
35 | })
36 |
--------------------------------------------------------------------------------
/src/assets/svg/helper.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/src/components/Toggle/ListToggle.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components'
3 | import { ButtonOutlined } from 'components/Button'
4 |
5 | const Wrapper = styled(ButtonOutlined)<{ isActive?: boolean; activeElement?: boolean }>`
6 | background: transparent
7 | border-color:${({ theme, isActive }) => isActive && theme.primary1};
8 | display: flex;
9 | width: 80px;
10 | cursor: pointer;
11 | padding: 0.4rem 0.5rem;
12 | align-items: center;
13 | justify-content: space-between;
14 | font-size: 14px;
15 | :hover{
16 | box-shadow: unset
17 | border-color: ${({ theme }) => theme.primary1};
18 | opacity: .8
19 | }
20 | `
21 |
22 | const ToggleElement = styled.span<{ isActive?: boolean; bgColor?: string }>`
23 | border-radius: 50%;
24 | height: 15px;
25 | width: 15px;
26 | background-color: ${({ isActive, bgColor, theme }) => (isActive ? theme.primary1 : theme.bg5)};
27 | :hover {
28 | opacity: 0.8;
29 | }
30 | `
31 |
32 | const StatusText = styled.div<{ isActive?: boolean }>`
33 | margin: 0 10px;
34 | width: 24px;
35 | font-weight: 500;
36 | color: ${({ theme, isActive }) => (isActive ? theme.primary1 : theme.text3)};
37 | `
38 |
39 | export interface ToggleProps {
40 | id?: string
41 | isActive: boolean
42 | bgColor: string
43 | toggle: () => void
44 | }
45 |
46 | export default function ListToggle({ id, isActive, bgColor, toggle }: ToggleProps) {
47 | return (
48 |
49 | {isActive && ON}
50 |
51 | {!isActive && OFF}
52 |
53 | )
54 | }
55 |
--------------------------------------------------------------------------------
/src/hooks/useENSName.ts:
--------------------------------------------------------------------------------
1 | import { namehash } from 'ethers/lib/utils'
2 | import { useMemo } from 'react'
3 | import { useSingleCallResult } from '../state/multicall/hooks'
4 | import { isAddress } from '../utils'
5 | import isZero from '../utils/isZero'
6 | import { useENSRegistrarContract, useENSResolverContract } from './useContract'
7 | import useDebounce from './useDebounce'
8 |
9 | /**
10 | * Does a reverse lookup for an address to find its ENS name.
11 | * Note this is not the same as looking up an ENS name to find an address.
12 | */
13 | export default function useENSName(address?: string): { ENSName: string | null; loading: boolean } {
14 | const debouncedAddress = useDebounce(address, 200)
15 | const ensNodeArgument = useMemo(() => {
16 | if (!debouncedAddress || !isAddress(debouncedAddress)) return [undefined]
17 | try {
18 | return debouncedAddress ? [namehash(`${debouncedAddress.toLowerCase().substr(2)}.addr.reverse`)] : [undefined]
19 | } catch (error) {
20 | return [undefined]
21 | }
22 | }, [debouncedAddress])
23 | const registrarContract = useENSRegistrarContract(false)
24 | const resolverAddress = useSingleCallResult(registrarContract, 'resolver', ensNodeArgument)
25 | const resolverAddressResult = resolverAddress.result?.[0]
26 | const resolverContract = useENSResolverContract(
27 | resolverAddressResult && !isZero(resolverAddressResult) ? resolverAddressResult : undefined,
28 | false
29 | )
30 | const name = useSingleCallResult(resolverContract, 'name', ensNodeArgument)
31 |
32 | const changed = debouncedAddress !== address
33 | return {
34 | ENSName: changed ? null : name.result?.[0] ?? null,
35 | loading: changed || resolverAddress.loading || name.loading
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/assets/svg/search.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/src/connectors/Fortmatic.ts:
--------------------------------------------------------------------------------
1 | import { ChainId } from '@uniswap/sdk'
2 | import { FortmaticConnector as FortmaticConnectorCore } from '@web3-react/fortmatic-connector'
3 |
4 | export const OVERLAY_READY = 'OVERLAY_READY'
5 |
6 | type FormaticSupportedChains = ChainId | ChainId.MAINNET | ChainId.BSC | ChainId.Arbitrum | ChainId.Avalanche
7 |
8 | const CHAIN_ID_NETWORK_ARGUMENT: { readonly [chainId in FormaticSupportedChains]: string | undefined } = {
9 | [ChainId.MAINNET]: '',
10 | [ChainId.ROPSTEN]: 'ropsten',
11 | [ChainId.BSC]: '',
12 | [ChainId.Arbitrum]: '',
13 | [ChainId.Avalanche]: ''
14 | }
15 |
16 | export class FortmaticConnector extends FortmaticConnectorCore {
17 | async activate() {
18 | if (!this.fortmatic) {
19 | const { default: Fortmatic } = await import('fortmatic')
20 |
21 | const { apiKey, chainId } = this as any
22 | if (chainId in CHAIN_ID_NETWORK_ARGUMENT) {
23 | this.fortmatic = new Fortmatic(apiKey, CHAIN_ID_NETWORK_ARGUMENT[chainId as FormaticSupportedChains])
24 | } else {
25 | throw new Error(`Unsupported network ID: ${chainId}`)
26 | }
27 | }
28 |
29 | const provider = this.fortmatic.getProvider()
30 |
31 | const pollForOverlayReady = new Promise(resolve => {
32 | const interval = setInterval(() => {
33 | if (provider.overlayReady) {
34 | clearInterval(interval)
35 | this.emit(OVERLAY_READY)
36 | resolve()
37 | }
38 | }, 200)
39 | })
40 |
41 | const [account] = await Promise.all([
42 | provider.enable().then((accounts: string[]) => accounts[0]),
43 | pollForOverlayReady
44 | ])
45 |
46 | return { provider: this.fortmatic.getProvider(), chainId: (this as any).chainId, account }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/state/application/reducer.ts:
--------------------------------------------------------------------------------
1 | import { createReducer, nanoid } from '@reduxjs/toolkit'
2 | import { addPopup, PopupContent, removePopup, updateBlockNumber, ApplicationModal, setOpenModal } from './actions'
3 |
4 | type PopupList = Array<{ key: string; show: boolean; content: PopupContent; removeAfterMs: number | null }>
5 |
6 | export interface ApplicationState {
7 | readonly blockNumber: { readonly [chainId: number]: number }
8 | readonly popupList: PopupList
9 | readonly openModal: ApplicationModal | null
10 | }
11 |
12 | const initialState: ApplicationState = {
13 | blockNumber: {},
14 | popupList: [],
15 | openModal: null
16 | }
17 |
18 | export default createReducer(initialState, builder =>
19 | builder
20 | .addCase(updateBlockNumber, (state, action) => {
21 | const { chainId, blockNumber } = action.payload
22 | if (typeof state.blockNumber[chainId] !== 'number') {
23 | state.blockNumber[chainId] = blockNumber
24 | } else {
25 | state.blockNumber[chainId] = Math.max(blockNumber, state.blockNumber[chainId])
26 | }
27 | })
28 | .addCase(setOpenModal, (state, action) => {
29 | state.openModal = action.payload
30 | })
31 | .addCase(addPopup, (state, { payload: { content, key, removeAfterMs = 15000 } }) => {
32 | state.popupList = (key ? state.popupList.filter(popup => popup.key !== key) : state.popupList).concat([
33 | {
34 | key: key || nanoid(),
35 | show: true,
36 | content,
37 | removeAfterMs
38 | }
39 | ])
40 | })
41 | .addCase(removePopup, (state, { payload: { key } }) => {
42 | state.popupList.forEach(p => {
43 | if (p.key === key) {
44 | p.show = false
45 | }
46 | })
47 | })
48 | )
49 |
--------------------------------------------------------------------------------
/src/components/Toggle/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components'
3 |
4 | const ToggleElement = styled.span<{ isActive?: boolean; isOnSwitch?: boolean }>`
5 | width: 50%;
6 | height: 3rem;
7 | line-height: 48px;
8 | border-radius: 14px;
9 | background: ${({ theme, isActive }) => (isActive ? theme.primary1 : 'none')};
10 | color: ${({ theme, isActive }) => (isActive ? theme.black : theme.white)};
11 | font-size: 1rem;
12 | font-weight: 400;
13 |
14 | padding: 0 0.6rem;
15 | font-weight: ${({ isOnSwitch }) => (isOnSwitch ? '500' : '400')};
16 | :hover {
17 | user-select: ${({ isOnSwitch }) => (isOnSwitch ? 'none' : 'initial')};
18 | background: ${({ theme, isActive }) => (isActive ? theme.primary4 : 'none')};
19 | color: ${({ theme, isActive, isOnSwitch }) => (isActive ? (isOnSwitch ? theme.white : theme.text2) : theme.text3)};
20 | }
21 | `
22 |
23 | const StyledToggle = styled.button<{ isActive?: boolean; activeElement?: boolean }>`
24 | border-radius: 14px;
25 | border: 1px solid ${({ theme }) => theme.text1}
26 | background: ${({ theme }) => theme.bg1};
27 | display: flex;
28 | width: 100%;
29 | max-width: 178px
30 | cursor: pointer;
31 | outline: none;
32 | padding: 0;
33 | `
34 |
35 | export interface ToggleProps {
36 | id?: string
37 | isActive: boolean
38 | toggle: () => void
39 | }
40 |
41 | export default function Toggle({ id, isActive, toggle }: ToggleProps) {
42 | return (
43 |
44 |
45 | On
46 |
47 |
48 | Off
49 |
50 |
51 | )
52 | }
53 |
--------------------------------------------------------------------------------
/src/utils/prices.test.ts:
--------------------------------------------------------------------------------
1 | import { ChainId, JSBI, Pair, Route, Token, TokenAmount, Trade, TradeType } from '@uniswap/sdk'
2 | import { computeTradePriceBreakdown } from './prices'
3 |
4 | describe('prices', () => {
5 | const token1 = new Token(ChainId.MAINNET, '0x0000000000000000000000000000000000000001', 18)
6 | const token2 = new Token(ChainId.MAINNET, '0x0000000000000000000000000000000000000002', 18)
7 | const token3 = new Token(ChainId.MAINNET, '0x0000000000000000000000000000000000000003', 18)
8 |
9 | const pair12 = new Pair(new TokenAmount(token1, JSBI.BigInt(10000)), new TokenAmount(token2, JSBI.BigInt(20000)))
10 | const pair23 = new Pair(new TokenAmount(token2, JSBI.BigInt(20000)), new TokenAmount(token3, JSBI.BigInt(30000)))
11 |
12 | describe('computeTradePriceBreakdown', () => {
13 | it('returns undefined for undefined', () => {
14 | expect(computeTradePriceBreakdown(undefined)).toEqual({
15 | priceImpactWithoutFee: undefined,
16 | realizedLPFee: undefined
17 | })
18 | })
19 |
20 | it('correct realized lp fee for single hop', () => {
21 | expect(
22 | computeTradePriceBreakdown(
23 | new Trade(new Route([pair12], token1), new TokenAmount(token1, JSBI.BigInt(1000)), TradeType.EXACT_INPUT)
24 | ).realizedLPFee
25 | ).toEqual(new TokenAmount(token1, JSBI.BigInt(3)))
26 | })
27 |
28 | it('correct realized lp fee for double hop', () => {
29 | expect(
30 | computeTradePriceBreakdown(
31 | new Trade(
32 | new Route([pair12, pair23], token1),
33 | new TokenAmount(token1, JSBI.BigInt(1000)),
34 | TradeType.EXACT_INPUT
35 | )
36 | ).realizedLPFee
37 | ).toEqual(new TokenAmount(token1, JSBI.BigInt(5)))
38 | })
39 | })
40 | })
41 |
--------------------------------------------------------------------------------
/src/pages/Redeem/ConfirmRedeemModalBottom.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Text } from 'rebass'
3 | import { ButtonPrimary } from '../../components/Button'
4 | import { DeltaData } from '../../state/market/hooks'
5 | import { Currency, Token } from '@uniswap/sdk'
6 | import { GenerateBar } from '../../components/MarketStrategy/GenerateBar'
7 | import { parseBalance } from '../../utils/marketStrategyUtils'
8 | import { ZERO_ADDRESS } from '../../constants'
9 |
10 | export function ConfirmRedeemModalBottom({
11 | delta,
12 | callTyped,
13 | putTyped,
14 | currencyA,
15 | currencyB,
16 | onRedeem
17 | }: {
18 | delta?: DeltaData | undefined
19 | callTyped?: string
20 | putTyped?: string
21 | currencyA?: Currency | undefined | null
22 | currencyB?: Currency | undefined | null
23 | onRedeem: () => void
24 | }) {
25 | return (
26 | <>
27 |
35 |
45 |
46 |
47 | Confirm Redemption
48 |
49 |
50 | >
51 | )
52 | }
53 |
--------------------------------------------------------------------------------
/src/components/Header/URLWarning.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components'
3 |
4 | import { AlertTriangle, X } from 'react-feather'
5 | import { useURLWarningToggle, useURLWarningVisible } from '../../state/user/hooks'
6 | import { isMobile } from 'react-device-detect'
7 |
8 | const PhishAlert = styled.div<{ isActive: any }>`
9 | width: 100%;
10 | padding: 6px 6px;
11 | background-color: ${({ theme }) => theme.blue1};
12 | color: white;
13 | font-size: 11px;
14 | justify-content: space-between;
15 | align-items: center;
16 | display: ${({ isActive }) => (isActive ? 'flex' : 'none')};
17 | `
18 |
19 | export const StyledClose = styled(X)`
20 | :hover {
21 | cursor: pointer;
22 | }
23 | `
24 |
25 | export default function URLWarning() {
26 | const toggleURLWarning = useURLWarningToggle()
27 | const showURLWarning = useURLWarningVisible()
28 |
29 | return isMobile ? (
30 |
31 |
32 |
Make sure the URL is
33 |
app.antimatter.finance
34 |
35 |
36 |
37 | ) : window.location.hostname === 'app.antimatter.finance' ? (
38 |
39 |
40 |
Always make sure the URL is
41 |
app.antimatter.finance -
42 | bookmark it to be safe.
43 |
44 |
45 |
46 | ) : null
47 | }
48 |
--------------------------------------------------------------------------------
/src/hooks/useOptionList.ts:
--------------------------------------------------------------------------------
1 | import { SearchQuery } from 'components/Search'
2 | import { useEffect, useState } from 'react'
3 | import { Axios } from '../utils/option/axios'
4 | import { useActiveWeb3React } from './index'
5 | import { useBlockNumber } from 'state/application/hooks'
6 | import { useNetwork } from './useNetwork'
7 |
8 | export function useOptionList(
9 | searchParams: SearchQuery
10 | ): {
11 | page: {
12 | totalPages: number
13 | currentPage: number
14 | setCurrentPage: (page: number) => void
15 | }
16 | data: string[]
17 | firstLoading: boolean
18 | } {
19 | const [totalPages, setTotalPages] = useState(0)
20 | const [currentPage, setCurrentPage] = useState(1)
21 | const { chainId } = useActiveWeb3React()
22 | const [ids, setIds] = useState([])
23 | const blockNumber = useBlockNumber()
24 | const [firstLoading, setFirstLoading] = useState(true)
25 |
26 | const {
27 | httpHandlingFunctions: { errorFunction }
28 | } = useNetwork()
29 |
30 | useEffect(() => {
31 | ;(async () => {
32 | if (!chainId) {
33 | return
34 | }
35 | const r: any = await Axios.post(
36 | 'getCreateOptionList',
37 | {},
38 | { chainId, pageNum: currentPage, ...searchParams }
39 | ).catch(e => {
40 | console.error(e)
41 | errorFunction()
42 | // throw new Error(e)
43 | })
44 | setFirstLoading(false)
45 | setTotalPages(r?.data?.data?.pages)
46 | setIds(r?.data?.data?.list?.map(({ optionIndex }: { optionIndex: string }) => optionIndex))
47 | })()
48 | }, [chainId, currentPage, searchParams, blockNumber, errorFunction])
49 |
50 | return {
51 | data: ids,
52 | firstLoading,
53 | page: {
54 | totalPages,
55 | currentPage,
56 | setCurrentPage
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/pages/Generate/ConfirmAddModalBottom.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Text } from 'rebass'
3 | import { ButtonPrimary } from '../../components/Button'
4 | import { DeltaData } from '../../state/market/hooks'
5 | import { Currency, Token } from '@uniswap/sdk'
6 | import { GenerateBar } from '../../components/MarketStrategy/GenerateBar'
7 | import { parseBalance } from '../../utils/marketStrategyUtils'
8 |
9 | export function ConfirmGenerationModalBottom({
10 | tokenType = '',
11 | delta,
12 | callTyped,
13 | putTyped,
14 | currencyA,
15 | currencyB,
16 | onGenerate,
17 | underlyingToken,
18 | currencyToken
19 | }: {
20 | tokenType?: string
21 | delta?: DeltaData | undefined
22 | callTyped?: string
23 | putTyped?: string
24 | currencyA?: Currency | undefined | null
25 | currencyB?: Currency | undefined | null
26 | onGenerate: () => void
27 | underlyingToken: Token
28 | currencyToken: Token
29 | }) {
30 | return (
31 | <>
32 |
42 |
50 |
51 |
52 | Confirm Generation
53 |
54 |
55 | >
56 | )
57 | }
58 |
--------------------------------------------------------------------------------
/src/hooks/useCalculatorCallback.ts:
--------------------------------------------------------------------------------
1 | // import JSBI from 'jsbi'
2 | import { ETHER } from '@uniswap/sdk'
3 | import { useMemo } from 'react'
4 | import { tryParseAmount } from 'state/swap/hooks'
5 | import { useAntimatterContract } from './useContract'
6 |
7 | const parseNumber = (val: string) => {
8 | return tryParseAmount(val, ETHER)?.raw.toString() ?? '0'
9 | }
10 |
11 | export function useCalculatorCallback(): {
12 | callback: null | ((...args: any[]) => Promise)
13 | } {
14 | const contract = useAntimatterContract()
15 | return useMemo(() => {
16 | if (!contract) return { callback: null }
17 | return {
18 | callback: async function onSwap(
19 | price: string,
20 | priceFloor: string,
21 | priceCap: string,
22 | totalCall: string,
23 | totalPut: string
24 | ): Promise<{
25 | priceCall: string
26 | pricePut: string
27 | totalUnd: string
28 | totalCur: string
29 | totalValue: string
30 | } | null> {
31 | if (!price || !priceFloor || !priceCap || !totalCall || !totalPut) {
32 | return null
33 | }
34 | return contract
35 | .calcPrice(
36 | parseNumber(price),
37 | parseNumber(priceFloor),
38 | parseNumber(priceCap),
39 | parseNumber(totalCall),
40 | parseNumber(totalPut)
41 | )
42 | .then((response: any) => {
43 | return {
44 | priceCall: response[0],
45 | pricePut: response[1],
46 | totalUnd: response[2],
47 | totalCur: response[3],
48 | totalValue: response[4]
49 | }
50 | })
51 | .catch((error: any) => {
52 | throw new Error(`Calculator fail: ${error.message}`)
53 | })
54 | }
55 | }
56 | }, [contract])
57 | }
58 |
--------------------------------------------------------------------------------
/src/pages/MatterToken/ConfirmRedeemModalBottom.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Text } from 'rebass'
3 | import { ButtonPrimary } from '../../components/Button'
4 | import { DeltaData } from '../../state/market/hooks'
5 | import { Currency, Token } from '@uniswap/sdk'
6 | import { GenerateBar } from '../../components/MarketStrategy/GenerateBar'
7 | import { parseBalance } from '../../utils/marketStrategyUtils'
8 | import { ZERO_ADDRESS } from '../../constants'
9 |
10 | export function ConfirmRedeemModalBottom({
11 | tokenType = '',
12 | delta,
13 | callTyped,
14 | putTyped,
15 | currencyA,
16 | currencyB,
17 | onRedeem
18 | }: {
19 | tokenType?: string
20 | delta?: DeltaData | undefined
21 | callTyped?: string
22 | putTyped?: string
23 | currencyA?: Currency | undefined | null
24 | currencyB?: Currency | undefined | null
25 | onRedeem: () => void
26 | }) {
27 | return (
28 | <>
29 |
37 |
47 |
48 |
49 | Confirm Generation
50 |
51 |
52 | >
53 | )
54 | }
55 |
--------------------------------------------------------------------------------
/src/pages/AppBody.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components'
3 | import { TYPE } from '../theme'
4 |
5 | export const BodyWrapper = styled.div<{ maxWidth?: string; gradient1?: boolean; isCard?: boolean }>`
6 | max-width: ${({ maxWidth }) => maxWidth ?? '480px'};
7 | width: 100%;
8 | background: ${({ theme, gradient1 }) => (gradient1 ? theme.gradient1 : theme.gradient2)};
9 | border: 1px solid ${({ theme }) => theme.text5};
10 | box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.01), 0px 4px 8px rgba(0, 0, 0, 0.04), 0px 16px 24px rgba(0, 0, 0, 0.04),
11 | 0px 24px 32px rgba(0, 0, 0, 0.01);
12 | border-radius: 32px;
13 | padding: 1.5rem;
14 | ${({ theme, isCard }) => theme.mediaWidth.upToSmall`
15 | min-height:100%;
16 | padding: 16px 24px;
17 | flex-grow: 1;
18 | ${isCard ? '' : 'border-bottom-left-radius: unset;border-bottom-right-radius: unset;'}
19 |
20 | `}
21 | `
22 |
23 | /**
24 | * The styled container element that wraps the content of most pages and the tabs.
25 | */
26 | export default function AppBody({
27 | children,
28 | style,
29 | maxWidth,
30 | gradient1,
31 | isCard
32 | }: {
33 | children: React.ReactNode
34 | style?: any
35 | maxWidth?: string
36 | gradient1?: boolean
37 | isCard?: boolean
38 | }) {
39 | return (
40 |
41 | {children}
42 |
43 | )
44 | }
45 |
46 | const StyledSwapHeader = styled.div`
47 | margin-bottom: -4px;
48 | font-size: 22px;
49 | width: 100%;
50 | max-width: 480px;
51 | font-weight: 500;
52 | color: ${({ theme }) => theme.text1};
53 | `
54 |
55 | export function BodyHeader({ title }: { title: string }) {
56 | return (
57 |
58 | {title}
59 |
60 | )
61 | }
62 |
--------------------------------------------------------------------------------
/src/assets/svg/call_token.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/src/components/SearchModal/sorting.ts:
--------------------------------------------------------------------------------
1 | import { Token, TokenAmount } from '@uniswap/sdk'
2 | import { useMemo } from 'react'
3 | import { useAllTokenBalances } from '../../state/wallet/hooks'
4 |
5 | // compare two token amounts with highest one coming first
6 | function balanceComparator(balanceA?: TokenAmount, balanceB?: TokenAmount) {
7 | if (balanceA && balanceB) {
8 | return balanceA.greaterThan(balanceB) ? -1 : balanceA.equalTo(balanceB) ? 0 : 1
9 | } else if (balanceA && balanceA.greaterThan('0')) {
10 | return -1
11 | } else if (balanceB && balanceB.greaterThan('0')) {
12 | return 1
13 | }
14 | return 0
15 | }
16 |
17 | function getTokenComparator(balances: {
18 | [tokenAddress: string]: TokenAmount | undefined
19 | }): (tokenA: Token, tokenB: Token) => number {
20 | return function sortTokens(tokenA: Token, tokenB: Token): number {
21 | // -1 = a is first
22 | // 1 = b is first
23 |
24 | // sort by balances
25 | const balanceA = balances[tokenA.address]
26 | const balanceB = balances[tokenB.address]
27 |
28 | const balanceComp = balanceComparator(balanceA, balanceB)
29 | if (balanceComp !== 0) return balanceComp
30 |
31 | if (tokenA.symbol && tokenB.symbol) {
32 | // sort by symbol
33 | return tokenA.symbol.toLowerCase() < tokenB.symbol.toLowerCase() ? -1 : 1
34 | } else {
35 | return tokenA.symbol ? -1 : tokenB.symbol ? -1 : 0
36 | }
37 | }
38 | }
39 |
40 | export function useTokenComparator(inverted: boolean): (tokenA: Token, tokenB: Token) => number {
41 | const balances = useAllTokenBalances()
42 | const comparator = useMemo(() => getTokenComparator(balances ?? {}), [balances])
43 | return useMemo(() => {
44 | if (inverted) {
45 | return (tokenA: Token, tokenB: Token) => comparator(tokenA, tokenB) * -1
46 | } else {
47 | return comparator
48 | }
49 | }, [inverted, comparator])
50 | }
51 |
--------------------------------------------------------------------------------
/src/theme/styled.d.ts:
--------------------------------------------------------------------------------
1 | import { FlattenSimpleInterpolation, ThemedCssFunction } from 'styled-components'
2 |
3 | export type Color = string
4 | export interface Colors {
5 | // base
6 | white: Color
7 | black: Color
8 |
9 | // text
10 | text1: Color
11 | text2: Color
12 | text3: Color
13 | text4: Color
14 | text5: Color
15 |
16 | // backgrounds / greys
17 | bg1: Color
18 | bg2: Color
19 | bg3: Color
20 | bg4: Color
21 | bg5: Color
22 |
23 | modalBG: Color
24 | advancedBG: Color
25 |
26 | //blues
27 | primary1: Color
28 | primary2: Color
29 | primary3: Color
30 | primary4: Color
31 | primary5: Color
32 |
33 | primaryText1: Color
34 |
35 | // pinks
36 | secondary1: Color
37 | secondary2: Color
38 | secondary3: Color
39 |
40 | // other
41 | red1: Color
42 | red2: Color
43 | red3: Color
44 | green1: Color
45 | yellow1: Color
46 | yellow2: Color
47 | blue1: Color
48 |
49 | //gradient
50 | gradient1: Color
51 | gradient2: Color
52 |
53 | //opacity
54 | translucent: Color
55 | }
56 |
57 | export interface Grids {
58 | sm: number
59 | md: number
60 | lg: number
61 | }
62 |
63 | declare module 'styled-components' {
64 | export interface DefaultTheme extends Colors {
65 | grids: Grids
66 |
67 | // shadows
68 | shadow1: string
69 |
70 | // media queries
71 | mediaWidth: {
72 | upToExtraSmall: ThemedCssFunction
73 | upToSmall: ThemedCssFunction
74 | upToMedium: ThemedCssFunction
75 | upToLarge: ThemedCssFunction
76 | }
77 |
78 | // css snippets
79 | flexColumnNoWrap: FlattenSimpleInterpolation
80 | flexRowNoWrap: FlattenSimpleInterpolation
81 |
82 | //rwd
83 | mobile: FlattenSimpleInterpolation
84 | desktop: FlattenSimpleInterpolation
85 | mobileHeaderHeight: string
86 | headerHeight: string
87 | }
88 | }
89 |
--------------------------------------------------------------------------------