Skip to content
This repository has been archived by the owner on Jun 24, 2022. It is now read-only.

Commit

Permalink
1334/activity orders from api rebased (#1639)
Browse files Browse the repository at this point in the history
* Added /account/<address>/orders api endpoint

* Added helper function to get explorer address link

* Requiring needed properties instead of concrete types on utils fns

* Added addOrUpdateOrdersBatch to orders/actions

* Added useAddOrUpdateOrdersBatch to orders/hooks

* Added addOrUpdateOrdersBatch to orders/reducer

* Added APIOrdersUpdater that checks for orders from API on connection

* Adjusted displayed orders:

- At most 10 regular orders and as much pending as there are
- Show only connected account orders
- Sort orders by creation date descending

* Show only txs for connected account

* Refactoring

* Don't actually need a helper fn...

* Added comment to make sort more explicit

* Using 'Link to Explorer' instead of 'Clear activities'

* Refactoring

* Refactor: cache tokens loaded const

* Refactor: removed duplicated css property

* Refactor: removed duplicated CSS property

* Refactor: extracted function transformApiOrderToStoreOrder

* Refactor: renamed _orders to apiOrders

* Refactor: removed duplicated CSS property

* Adjusting `View all orders` link size

* Added `View all orders` to the bottom of account activity

* Refactored computeOrderSummary to deal with pending orders

* Computing order summary for orders loaded from API

* Setting isCancelling state if order is pending and cancelled on API

* Actually syncing `isCancelling` flag for existing orders

* Refactor: created const for magic number MAXIMUM_ORDERS_TO_DISPLAY

* Refactor: simplified addOrUpdateOrdersBatch reducer

* Refactor: renamed API -> Api on file name

* Refactor: replaced magic number with AMOUNT_OF_ORDERS_TO_FETCH

* Refactor: converted classifyLocalStatus fn to a map

* Refactor: removed `Batch` from addOrUpdateOrders

* Refactor: moved error exit condition up

* 1334/load new tokens not yet loaded (#1504)

* Added non-hook methods for dealing with contracts

* New hook useTokensLazy

* Exporting stuff from original codebase

* Added getMultipleCallsResults under custom/state/multicall/utils

Non-hook way of fetching multiple onchain queries through multicall

* Refactor ApiOrdersUpdater to load tokens not yet in the UI

* Typo fix

* 1334/do not refetch when token added (#1536)

* Removing annoying log

* No longer re-fetching orders when a token is added to the list

Co-authored-by: Leandro Boscariol <[email protected]>

* Refactored useTokensLazy:

- Added contracts cache
- Improved comments

* Improved doc string on multicall utils

Co-authored-by: Leandro Boscariol <[email protected]>

* Fix new Erc20 import path

* Adjust to new multicall interface and fetchChunk changes

* Adapt to renamed of ApiOrderStatus to OrderTransitionStatus

* Adjusting (again) styles for `view all activity`

* Handling presignaturePending state from backend

* The order is concrete at this point, no need for `?.`

* 1334/only update connected wallet (#1684)

* Only update cancelled orders for connected wallet

* Only check for unfillable orders for connected wallet

* Only check pending orders for connected wallet

* Always create a new state object when adding an order (#1686)

Co-authored-by: Leandro Boscariol <[email protected]>

* Refactor: comparing account with order.owner lowercased for safety

Co-authored-by: Leandro Boscariol <[email protected]>

* Added new hook useTokenLazyNoMulticall to fetch token data one by one

* Using new hook to fetch tokens instead of multicall

* Removed multicall/utils

* Removed useTokensLazy hook

* Renamed file useTokensLazy to useTokenLazy

* Renamed useTokenLazyNoMulticall to useTokenLazy

* Removed unused import

* Updated debug log messages

* Small refactor in #1639 (#1857)

* Only init bytes32Contract if we really need to

* Fixing build error: only proceed if library is set

Co-authored-by: Leandro Boscariol <[email protected]>

* 1334/with swr (#1906)

* Refactor: removed unnecessary variable

* Added SWR as dev dependency

* Added hook useApiOrders using useSWR hook

* Using new hook for fetching api orders

* Removed unused imports...

Co-authored-by: Leandro Boscariol <[email protected]>

Co-authored-by: Leandro Boscariol <[email protected]>
Co-authored-by: Anxo Rodriguez <[email protected]>
  • Loading branch information
3 people authored Nov 29, 2021
1 parent 8663505 commit 2fc6c81
Show file tree
Hide file tree
Showing 29 changed files with 673 additions and 125 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@
"start-server-and-test": "^1.11.0",
"styled-components": "^5.3.0",
"styled-system": "^5.1.5",
"swr": "^1.0.1",
"typechain": "^5.0.0",
"typescript": "^4.4.2",
"ua-parser-js": "^0.7.28",
Expand Down
1 change: 0 additions & 1 deletion src/components/AccountDetails/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@ const AddressLink = styled(ExternalLink)<{ hasENS: boolean; isENS: boolean }>`
font-size: 0.825rem;
color: ${({ theme }) => theme.text3};
margin-left: 1rem;
font-size: 0.825rem;
display: flex;
:hover {
color: ${({ theme }) => theme.text2};
Expand Down
2 changes: 2 additions & 0 deletions src/custom/abis/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@
export type { GPv2Settlement } from './GPv2Settlement'

export { GPv2Settlement__factory } from './factories/GPv2Settlement__factory'

export * from '@src/abis/types'
23 changes: 22 additions & 1 deletion src/custom/api/gnosisProtocol/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ const API_NAME = 'Gnosis Protocol'
const ENABLED = process.env.REACT_APP_PRICE_FEED_GP_ENABLED !== 'false'
/**
* Unique identifier for the order, calculated by keccak256(orderDigest, ownerAddress, validTo),
where orderDigest = keccak256(orderStruct). bytes32.
* where orderDigest = keccak256(orderStruct). bytes32.
*/
export type OrderID = string
export type ApiOrderStatus = 'fulfilled' | 'expired' | 'cancelled' | 'presignaturePending' | 'open'
Expand All @@ -95,6 +95,7 @@ export interface OrderMetaData {
signature: string
signingScheme: SigningSchemeValue
status: ApiOrderStatus
receiver: string
}

export interface TradeMetaData {
Expand Down Expand Up @@ -330,6 +331,26 @@ export async function getOrder(chainId: ChainId, orderId: string): Promise<Order
}
}

export async function getOrders(chainId: ChainId, owner: string, limit = 1000, offset = 0): Promise<OrderMetaData[]> {
console.log(`[api:${API_NAME}] Get orders for `, chainId, owner, limit, offset)

const queryString = stringify({ limit, offset }, { addQueryPrefix: true })

try {
const response = await _get(chainId, `/account/${owner}/orders/${queryString}`)

if (!response.ok) {
const errorResponse: ApiErrorObject = await response.json()
throw new OperatorError(errorResponse)
} else {
return response.json()
}
} catch (error) {
console.error('Error getting orders information:', error)
throw new OperatorError(UNHANDLED_ORDER_ERROR)
}
}

type GetTradesParams = {
chainId: ChainId
owner: string
Expand Down
15 changes: 15 additions & 0 deletions src/custom/api/gnosisProtocol/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import useSWR from 'swr'

import { useActiveWeb3React } from 'hooks/web3'
import { getOrders, OrderMetaData } from 'api/gnosisProtocol/api'
import { AMOUNT_OF_ORDERS_TO_FETCH } from 'constants/index'

export function useApiOrders(account?: string | null): OrderMetaData[] | undefined {
const { chainId } = useActiveWeb3React()

const { data } = useSWR<OrderMetaData[]>(['orders', account, chainId], () =>
chainId && account ? getOrders(chainId, account, AMOUNT_OF_ORDERS_TO_FETCH) : []
)

return data
}
25 changes: 7 additions & 18 deletions src/custom/components/AccountDetails/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import React, { useCallback, Fragment } from 'react'
import { batch, useDispatch } from 'react-redux'
import React, { Fragment } from 'react'

import { useActiveWeb3React } from 'hooks/web3'
import { AppDispatch } from 'state'
import { clearAllTransactions } from 'state/enhancedTransactions/actions'
import { getExplorerLabel, shortenAddress } from 'utils'

import Copy from 'components/Copy'
Expand All @@ -17,8 +14,6 @@ import WalletConnectIcon from 'assets/images/walletConnectIcon.svg'
import FortmaticIcon from 'assets/images/fortmaticIcon.png'
import PortisIcon from 'assets/images/portisIcon.png'
import Identicon from 'components/Identicon'
import { LinkStyledButton } from 'theme'
import { clearOrders } from 'state/orders/actions'
import { NETWORK_LABELS } from 'components/Header'
import {
WalletName,
Expand Down Expand Up @@ -46,6 +41,8 @@ import { MouseoverTooltip } from 'components/Tooltip'
import { supportedChainId } from 'utils/supportedChainId'
import { groupActivitiesByDay, useMultipleActivityDescriptors } from 'hooks/useRecentActivity'
import { CreationDateText } from 'components/AccountDetails/Transaction/styled'
import { ExternalLink } from 'theme'
import { getExplorerAddressLink } from 'utils/explorer'

const DATE_FORMAT_OPTION: Intl.DateTimeFormatOptions = {
dateStyle: 'long',
Expand Down Expand Up @@ -153,17 +150,8 @@ export default function AccountDetails({
const { account, connector, chainId: connectedChainId } = useActiveWeb3React()
const chainId = supportedChainId(connectedChainId)
const walletInfo = useWalletInfo()
// const theme = useContext(ThemeContext)
const dispatch = useDispatch<AppDispatch>()

const clearAllActivityCallback = useCallback(() => {
if (chainId) {
batch(() => {
dispatch(clearAllTransactions({ chainId }))
dispatch(clearOrders({ chainId }))
})
}
}, [dispatch, chainId])
const explorerOrdersLink = account && connectedChainId && getExplorerAddressLink(connectedChainId, account)
const explorerLabel = chainId && account ? getExplorerLabel(chainId, account, 'address') : undefined

const activities =
Expand Down Expand Up @@ -216,7 +204,7 @@ export default function AccountDetails({
{chainId && account && (
<AddressLink
hasENS={!!ENSName}
isENS={ENSName ? true : false}
isENS={!!ENSName}
href={getEtherscanLink(chainId, ENSName ? ENSName : account, 'address')}
>
{explorerLabel}
Expand All @@ -234,7 +222,7 @@ export default function AccountDetails({
<h5>
Recent Activity <span>{`(${activityTotalCount})`}</span>
</h5>
<LinkStyledButton onClick={clearAllActivityCallback}>Clear activity</LinkStyledButton>
{explorerOrdersLink && <ExternalLink href={explorerOrdersLink}>View all orders</ExternalLink>}
</span>

<div>
Expand All @@ -245,6 +233,7 @@ export default function AccountDetails({
{renderActivities(activities)}
</Fragment>
))}
{explorerOrdersLink && <ExternalLink href={explorerOrdersLink}>View all orders</ExternalLink>}
</div>
</LowerSection>
) : (
Expand Down
14 changes: 10 additions & 4 deletions src/custom/components/AccountDetails/styled.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import styled from 'styled-components/macro'
import { CopyIcon, TransactionStatusText } from 'components/Copy'
import { LinkStyledButton } from 'theme'
import { LinkStyledButton, StyledLink } from 'theme'
import {
WalletName,
AccountSection as AccountSectionMod,
Expand Down Expand Up @@ -208,10 +208,14 @@ export const LowerSection = styled.div`
> div {
display: flex;
flex-flow: column wrap;
padding: 0;
width: 100%;
background-color: inherit;
padding: 0 0 48px;
${StyledLink} {
align-self: center;
margin: 20px 0;
}
}
h5 {
Expand All @@ -227,14 +231,16 @@ export const LowerSection = styled.div`
}
}
${LinkStyledButton} {
${LinkStyledButton},${StyledLink} {
opacity: 0.7;
color: ${({ theme }) => theme.text1};
text-decoration: underline;
font-size: 14px;
&:hover {
opacity: 1;
}
}
`

const NetworkCardUni = styled(YellowCard)`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ const NameOverflow = styled.div`
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
text-overflow: ellipsis;
max-width: 140px;
font-size: 12px;
`
Expand Down
3 changes: 3 additions & 0 deletions src/custom/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,5 +106,8 @@ export const FEE_SIZE_THRESHOLD = new Fraction(10, 100) // 30%
// default value provided as userAddress to Paraswap API if the user wallet is not connected
export const SOLVER_ADDRESS = '0xa6ddbd0de6b310819b49f680f65871bee85f517e'

export const MAXIMUM_ORDERS_TO_DISPLAY = 10
export const AMOUNT_OF_ORDERS_TO_FETCH = 100

// last wallet provider key used in local storage
export const STORAGE_KEY_LAST_PROVIDER = 'lastProvider'
56 changes: 55 additions & 1 deletion src/custom/hooks/useContract.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Contract } from '@ethersproject/contracts'
import { Web3Provider } from '@ethersproject/providers'
import { useActiveWeb3React } from 'hooks/web3'

import { useContract } from '@src/hooks/useContract'
Expand All @@ -7,8 +8,11 @@ import { GP_SETTLEMENT_CONTRACT_ADDRESS } from 'constants/index'
import { SupportedChainId as ChainId } from 'constants/chains'

import ENS_ABI from 'abis/ens-registrar.json'
import { getContract } from 'utils'
import ERC20_ABI from 'abis/erc20.json'
import ERC20_BYTES32_ABI from 'abis/erc20_bytes32.json'

import { GPv2Settlement } from 'abis/types'
import { GPv2Settlement, Erc20 } from 'abis/types'
import GPv2_SETTLEMENT_ABI from 'abis/GPv2Settlement.json'

export * from '@src/hooks/useContract'
Expand Down Expand Up @@ -40,3 +44,53 @@ export function useENSRegistrarContract(withSignerIfPossible?: boolean): Contrac
}
return useContract(address, ENS_ABI, withSignerIfPossible)
}

/**
* Non-hook version of useContract
*/
function _getContract<T extends Contract = Contract>(
addressOrAddressMap: string | { [chainId: number]: string } | undefined,
ABI: any,
withSignerIfPossible = true,
library?: Web3Provider,
account?: string,
chainId?: ChainId
): T | null {
if (!addressOrAddressMap || !ABI || !library || !chainId) return null
let address: string | undefined
if (typeof addressOrAddressMap === 'string') address = addressOrAddressMap
else address = addressOrAddressMap[chainId]
if (!address) return null
try {
return getContract(address, ABI, library, withSignerIfPossible && account ? account : undefined) as T
} catch (error) {
console.error('Failed to get contract', error)
return null
}
}

/**
* Non-hook version of useTokenContract
*/
export function getTokenContract(
tokenAddress?: string,
withSignerIfPossible?: boolean,
library?: Web3Provider,
account?: string,
chainId?: ChainId
): Erc20 | null {
return _getContract<Erc20>(tokenAddress, ERC20_ABI, withSignerIfPossible, library, account, chainId)
}

/**
* Non-hook version of useBytes32TokenContract
*/
export function getBytes32TokenContract(
tokenAddress?: string,
withSignerIfPossible?: boolean,
library?: Web3Provider,
account?: string,
chainId?: ChainId
): Contract | null {
return _getContract(tokenAddress, ERC20_BYTES32_ABI, withSignerIfPossible, library, account, chainId)
}
Loading

0 comments on commit 2fc6c81

Please sign in to comment.