Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

332/Store slippage info on appData #629

Merged
merged 33 commits into from
Jul 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
1f25a2b
Bumped latest cow-sdk version
alfetopito May 30, 2022
84f7dbb
Creating cow-sdk instances for all networks
alfetopito May 30, 2022
d76b71e
Removed redundant import
alfetopito May 30, 2022
a5c81c9
Updated .env files with now mandatory env var for IPFS uploading
alfetopito Jun 3, 2022
2936196
Added/moved appCode related consts to constants file
alfetopito Jun 3, 2022
8aed31c
New hook useAppCode
alfetopito Jun 3, 2022
a493587
Added appData/atoms using Jotai
alfetopito Jun 3, 2022
c06a33b
New utils for dealing with appData
alfetopito Jun 3, 2022
729f2b8
New hook useAppData
alfetopito Jun 3, 2022
fbd2642
Adding newly calculated appData to order and storing it in the to-be-…
alfetopito Jun 3, 2022
da615c6
Added appData/updater
alfetopito Jun 3, 2022
369794a
Disabling affiliate data IPFS upload; will be handled on every order
alfetopito Jun 3, 2022
2e3005b
Removing helper files no longer in use
alfetopito Jun 3, 2022
ca7b4fe
Refactored state/appData/types
alfetopito Jun 6, 2022
b91b89c
Refactored state/appData/atoms
alfetopito Jun 6, 2022
1ebfc38
Refactored state/AppData/hooks
alfetopito Jun 6, 2022
656fc09
Updater state/appData/updater does not need to be tsx file
alfetopito Jun 6, 2022
645bdb6
Added state/appData/utils to handle key creation/parsing
alfetopito Jun 6, 2022
b02fdc6
Refactored upload queue to a flat object rather than nested by network
alfetopito Jun 6, 2022
06dc2f7
Removing debug loggs from state/appData/atoms
alfetopito Jun 6, 2022
972c240
Refactored state/appData/updater
alfetopito Jun 6, 2022
61445de
`environment` is now part of the appData rather than a metadata
alfetopito Jun 8, 2022
1e9acbd
Forcing all inputs in an attempt to fix cypress occasional failures
alfetopito Jun 8, 2022
8d01b13
Refactor: removed redundant initial state on state/appData/atoms
alfetopito Jun 22, 2022
d18e37f
Refactor: improved logging in case of appDataHash generation
alfetopito Jun 22, 2022
76be5af
332/exponential back off (#726)
alfetopito Jun 23, 2022
45d3e68
332/update affiliate flow (#647)
alfetopito Jun 24, 2022
e625664
332/warning when pinata envs not set locally (#659)
alfetopito Jun 24, 2022
26d1c6b
332/quote id on metadata (#750)
alfetopito Jun 30, 2022
fa48891
Refactor: Replaced map upload queue with arrary (#747)
alfetopito Jun 29, 2022
2588905
332/slippage bips rather than amounts on metadata (#758)
alfetopito Jun 30, 2022
a2c133a
332/upload right away (#767)
alfetopito Jul 1, 2022
64cb1e1
332/refactor use address (#748)
alfetopito Jul 1, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,7 @@ REACT_APP_MOCK=true

# Locales
REACT_APP_LOCALES="locales"

# IPFS uploading
REACT_APP_PINATA_API_KEY=
REACT_APP_PINATA_SECRET_API_KEY=
4 changes: 4 additions & 0 deletions .env.production
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,7 @@ REACT_APP_MOCK=false

# Locales
REACT_APP_LOCALES="locales"

# IPFS uploading
#REACT_APP_PINATA_API_KEY=
#REACT_APP_PINATA_SECRET_API_KEY=
alfetopito marked this conversation as resolved.
Show resolved Hide resolved
12 changes: 6 additions & 6 deletions cypress-custom/integration/swapMod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,22 @@ describe('Swap (mod)', () => {

it('can enter an amount into input', () => {
cy.get('#swap-currency-input .token-amount-input')
.clear()
.type('0.001', { delay: 400, force: true })
.type('{selectall}{backspace}{selectall}{backspace}')
.type('0.001')
.should('have.value', '0.001')
})

it('zero swap amount', () => {
cy.get('#swap-currency-input .token-amount-input')
.clear()
.type('0.0', { delay: 400, force: true })
.type('{selectall}{backspace}{selectall}{backspace}')
.type('0.0')
.should('have.value', '0.0')
})

it('invalid swap amount', () => {
cy.get('#swap-currency-input .token-amount-input')
.clear()
.type('\\', { delay: 400, force: true })
.type('{selectall}{backspace}{selectall}{backspace}')
.type('\\')
.should('have.value', '')
})

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"@babel/preset-env": "^7.16.11",
"@babel/preset-react": "^7.16.7",
"@babel/preset-typescript": "^7.16.7",
"@cowprotocol/cow-sdk": "^0.0.14",
"@cowprotocol/cow-sdk": "^0.0.15-RC.0",
"@craco/craco": "^5.7.0",
"@ethersproject/experimental": "^5.4.0",
"@graphql-codegen/cli": "1.21.5",
Expand Down
37 changes: 0 additions & 37 deletions src/custom/api/ipfs/index.ts

This file was deleted.

82 changes: 52 additions & 30 deletions src/custom/components/AffiliateStatusCheck/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@ import React, { useCallback, useEffect, useState, useRef, useMemo } from 'react'
import { useHistory, useLocation } from 'react-router-dom'
import { useActiveWeb3React } from 'hooks/web3'
import NotificationBanner from 'components/NotificationBanner'
import { useReferralAddress, useResetReferralAddress } from 'state/affiliate/hooks'
import { updateAppDataHash } from 'state/affiliate/actions'
import { useAppDispatch } from 'state/hooks'
import { useReferralAddress, useResetReferralAddress, useSetReferralAddressActive } from 'state/affiliate/hooks'
import { hasTrades } from 'utils/trade'
import { generateReferralMetadataDoc, uploadMetadataDocToIpfs } from 'utils/metadata'
import { retry, RetryOptions } from 'utils/retry'
import { SupportedChainId } from 'constants/chains'
import useParseReferralQueryParam from 'hooks/useParseReferralQueryParam'
Expand All @@ -26,39 +23,59 @@ const STATUS_TO_MESSAGE_MAPPING: Record<AffiliateStatus, string> = {
const DEFAULT_RETRY_OPTIONS: RetryOptions = { n: 3, minWait: 1000, maxWait: 3000 }

export default function AffiliateStatusCheck() {
const appDispatch = useAppDispatch()
const resetReferralAddress = useResetReferralAddress()
const setReferralAddressActive = useSetReferralAddressActive()
const history = useHistory()
const location = useLocation()
const { account, chainId } = useActiveWeb3React()
const referralAddress = useReferralAddress()
const referralAddressQueryParam = useParseReferralQueryParam()
const allRecentActivity = useRecentActivity()
const [affiliateState, setAffiliateState] = useState<AffiliateStatus | null>()
const [affiliateState, _setAffiliateState] = useState<AffiliateStatus | null>()

/**
* Wrapper around setAffiliateState (local) and setReferralAddressActive (global)
* Need to keep track when affiliate is ACTIVE to know whether it should be included in the
* metadata, no longer uploaded to IPFS here
*/
const setAffiliateState = useCallback(
(state: AffiliateStatus | null) => {
_setAffiliateState(state)
setReferralAddressActive(state === 'ACTIVE')
},
[setReferralAddressActive]
)

// De-normalized to avoid unnecessary useEffect triggers
const isReferralAddressNotSet = !referralAddress
const referralAddressAccount = referralAddress?.value
const referralAddressIsValid = referralAddress?.isValid

const [error, setError] = useState('')
const isFirstTrade = useRef(false)
const fulfilledOrders = allRecentActivity.filter((data) => {
return 'appData' in data && data.status === OrderStatus.FULFILLED
})

const notificationBannerId = useMemo(() => {
if (!referralAddress?.value) {
if (!referralAddressAccount) {
return
}

if (!account) {
return `referral-${referralAddress.value}`
return `referral-${referralAddressAccount}`
}

return `wallet-${account}:referral-${referralAddress.value}:chain-${chainId}`
}, [account, chainId, referralAddress?.value])
return `wallet-${account}:referral-${referralAddressAccount}:chain-${chainId}`
}, [account, chainId, referralAddressAccount])

const handleAffiliateState = useCallback(async () => {
if (!chainId || !account || !referralAddress) {
if (!chainId || !account) {
return
}

if (!referralAddress.isValid) {
// Note: comparing with `false` because in case `undefined` msg shouldn't be displayed
if (referralAddressIsValid === false) {
setError('Affiliate program: The referral address is invalid.')
return
}
Expand All @@ -85,28 +102,23 @@ export default function AffiliateStatusCheck() {

setAffiliateState('ACTIVE')
isFirstTrade.current = true
}, [referralAddress, chainId, account, fulfilledOrders.length, history, resetReferralAddress])

useEffect(() => {
async function handleReferralAddress(referralAddress: { value: string; isValid: boolean } | undefined) {
if (!referralAddress?.value) return
try {
const appDataHash = await uploadMetadataDocToIpfs(generateReferralMetadataDoc(referralAddress.value))
appDispatch(updateAppDataHash(appDataHash))
} catch (e) {
console.error(e)
setError('Affiliate program: There was an error while uploading your referral data. Please try again later.')
}
}
if (affiliateState === 'ACTIVE') handleReferralAddress(referralAddress)
}, [referralAddress, affiliateState, appDispatch])
}, [
account,
chainId,
fulfilledOrders.length,
history,
referralAddressIsValid,
resetReferralAddress,
setAffiliateState,
])

useEffect(() => {
if (!referralAddress) {
if (isReferralAddressNotSet) {
return
}

setError('')
setAffiliateState(null)

if (!account) {
setAffiliateState('NOT_CONNECTED')
Expand All @@ -118,7 +130,7 @@ export default function AffiliateStatusCheck() {
return
}

if (referralAddress.value === account) {
if (referralAddressAccount === account) {
// clean-up saved referral address if the user follows its own referral link
setAffiliateState('OWN_LINK')

Expand All @@ -129,7 +141,17 @@ export default function AffiliateStatusCheck() {
}

handleAffiliateState()
}, [referralAddress, account, history, chainId, handleAffiliateState, location.search, referralAddressQueryParam])
}, [
account,
history,
chainId,
handleAffiliateState,
location.search,
referralAddressQueryParam,
setAffiliateState,
referralAddressAccount,
isReferralAddressNotSet,
])

if (error) {
return (
Expand Down
1 change: 1 addition & 0 deletions src/custom/components/Header/URLWarning/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export default function URLWarning() {

const announcementVisible = useAnnouncementVisible(contentHash)
const closeAnnouncement = useCloseAnnouncement()

const announcement = announcementVisible && announcementText && (
<>
<div style={{ display: 'flex' }}>
Expand Down
4 changes: 4 additions & 0 deletions src/custom/components/Popups/PopupItemMod.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import TransactionPopup from './TransactionPopupMod'

// MOD imports
import ListUpdatePopup from 'components/Popups/ListUpdatePopup'
import { WarningPopup } from 'components/Popups/WarningPopup'

export const StyledClose = styled(X)`
position: absolute;
Expand Down Expand Up @@ -84,6 +85,7 @@ export default function PopupItem({
const isListUpdate = 'listUpdate' in content
const isUnsupportedNetwork = 'unsupportedNetwork' in content
const isMetaTxn = 'metatxn' in content
const isWarningTxn = 'warning' in content

let popupContent
if (isTxn) {
Expand All @@ -105,6 +107,8 @@ export default function PopupItem({
popupContent = <FailedNetworkSwitchPopup chainId={content.failedSwitchNetwork} isUnsupportedNetwork />
} else if ('failedSwitchNetwork' in content) {
popupContent = <FailedNetworkSwitchPopup chainId={content.failedSwitchNetwork} />
} else if (isWarningTxn) {
popupContent = <WarningPopup warning={content.warning} />
}

const faderStyle = useSpring({
Expand Down
28 changes: 28 additions & 0 deletions src/custom/components/Popups/WarningPopup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useContext } from 'react'
import styled, { ThemeContext } from 'styled-components/macro'

import { ThemedText } from 'theme'
import { AutoColumn } from 'components/Column'
import { AutoRow } from 'components/Row'
import { AlertCircle } from 'react-feather'

const RowNoFlex = styled(AutoRow)`
flex-wrap: nowrap;
`

export function WarningPopup({ warning }: { warning: string | JSX.Element }) {
const theme = useContext(ThemeContext)

return (
<RowNoFlex>
<div style={{ paddingRight: 16 }}>
<AlertCircle color={theme.red1} size={24} />
</div>
<AutoColumn gap="sm">
<ThemedText.Body fontWeight={'bold'} color={theme.danger}>
{warning}
</ThemedText.Body>
</AutoColumn>
</RowNoFlex>
)
}
4 changes: 4 additions & 0 deletions src/custom/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ export const SHORT_LOAD_THRESHOLD = 500
export const LONG_LOAD_THRESHOLD = 2000

export const APP_DATA_HASH = getAppDataHash()
export const DEFAULT_APP_CODE = 'CowSwap'
export const SAFE_APP_CODE = `${DEFAULT_APP_CODE}-SafeApp`

export const PRODUCTION_URL = 'cowswap.exchange'
export const BARN_URL = `barn.${PRODUCTION_URL}`

Expand Down Expand Up @@ -170,6 +173,7 @@ export const SWR_OPTIONS = {
revalidateOnFocus: false,
}

// TODO: show banner warning when PINATA env vars are missing
alfetopito marked this conversation as resolved.
Show resolved Hide resolved
const COW_SDK_OPTIONS = {
ipfs: { pinataApiKey: PINATA_API_KEY, pinataApiSecret: PINATA_SECRET_API_KEY },
}
Expand Down
2 changes: 0 additions & 2 deletions src/custom/constants/ipfs.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
export const PINATA_API_KEY = process.env.REACT_APP_PINATA_API_KEY as string
export const PINATA_SECRET_API_KEY = process.env.REACT_APP_PINATA_SECRET_API_KEY as string
export const PINATA_API_URL = process.env.REACT_APP_PINATA_API_URL || 'https://api.pinata.cloud'
export const IPFS_URI = process.env.REACT_APP_IPFS_URI || 'https://ipfs.infura.io:5001/api/v0'
15 changes: 15 additions & 0 deletions src/custom/hooks/useAppCode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useIsGnosisSafeApp } from 'hooks/useWalletInfo'
import { DEFAULT_APP_CODE, SAFE_APP_CODE } from 'constants/index'

const APP_CODE = process.env.REACT_APP_APP_CODE

export function useAppCode(): string {
const isSafeApp = useIsGnosisSafeApp()

if (APP_CODE) {
// appCode coming from env var has priority
return APP_CODE
alfetopito marked this conversation as resolved.
Show resolved Hide resolved
}

return isSafeApp ? SAFE_APP_CODE : DEFAULT_APP_CODE
}
Loading