Skip to content

Commit

Permalink
Merge branch 'develop' into fix/cow-token-logo
Browse files Browse the repository at this point in the history
  • Loading branch information
shoom3301 authored Jan 11, 2024
2 parents 11c5637 + 440f9fe commit 957eefa
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 299 deletions.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,23 @@ yarn build
yarn test
```

# 🔎 Explorer

Start the Explorer on http://localhost:4200

[Read more about the Explorer](apps/explorer/README.md)

### Start
```bash
yarn start:explorer
```

### Build
```bash
yarn build:explorer
```


# 🖼️ Widget Configurator

Start the Widget Configurator on http://127.0.0.1:4200/widget-configurator
Expand Down
16 changes: 16 additions & 0 deletions apps/explorer/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Enables mock mode (default = true)
MOCK=true

# Enables autoconnect for mock mode (default = true)
AUTOCONNECT=true

# Public IPFS gateway
REACT_APP_IPFS_READ_URI=https://cloudflare-ipfs.com/ipfs

# Sentry
#REACT_APP_SENTRY_DSN='https://<url>'
#REACT_APP_SENTRY_TRACES_SAMPLE_RATE="1.0"
#REACT_APP_SENTRY_AUTH_TOKEN='<sentry_auth_token>'

# Orderbook API Endpoints
#REACT_APP_ORDER_BOOK_URLS='{"1":"https://YOUR_HOST","100":"https://YOUR_HOST","5":"https://YOUR_HOST"}
35 changes: 35 additions & 0 deletions apps/explorer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Explorer

## 🏃‍♀️ Run it locally

```bash
yarn start:explorer
```


## 👷‍♀️ Build app

```bash
yarn build:explorer
```

Static files will be generated inside the `build/explorer` dir.

## 🧪 Run tests

```bash
yarn test:explorer
```

## Orderbook API Endpoints

Fee quote requests and posting orders are sent to the Orderbook API. This API has the responsibility of collecting orders and
handing them to the solvers.

The reference implementation of the API is [CoW Protocol Services](https://github.com/cowprotocol/services).

The API endpoint is configured using the environment variable `REACT_APP_ORDER_BOOK_URLS`:

```ini
REACT_APP_ORDER_BOOK_URLS={"1":"https://YOUR_HOST","100":"https://YOUR_HOST","5":"https://YOUR_HOST"}
```
1 change: 0 additions & 1 deletion apps/explorer/src/api/operator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ const useMock = process.env.MOCK_OPERATOR === 'true'
export const {
// functions that have a mock
getOrder,
getOrders,
getAccountOrders,
getTxOrders,
getTrades,
Expand Down
97 changes: 1 addition & 96 deletions apps/explorer/src/api/operator/operatorApi.ts
Original file line number Diff line number Diff line change
@@ -1,62 +1,9 @@
import { Network } from 'types'
import { buildSearchString } from 'utils/url'
import { isProd, isStaging } from 'utils/env'

import { GetOrderParams, GetOrdersParams, RawOrder, RawTrade, GetTxOrdersParams, WithNetworkId } from './types'
import { fetchQuery } from 'api/baseApi'
import { GetOrderParams, RawOrder, RawTrade, GetTxOrdersParams, WithNetworkId } from './types'
import { orderBookSDK } from 'cowSdk'
import { Address, UID } from '@cowprotocol/cow-sdk'

export { getAccountOrders } from './accountOrderUtils'

// TODO: export this through the sdk
export type ApiEnv = 'prod' | 'staging'

// TODO: should come from the SDK by now, find out where this is used
function getOperatorUrl(): Partial<Record<Network, string>> {
if (isProd || isStaging) {
return {
[Network.MAINNET]: process.env.OPERATOR_URL_PROD_MAINNET,
[Network.GOERLI]: process.env.OPERATOR_URL_PROD_GOERLI,
[Network.GNOSIS_CHAIN]: process.env.OPERATOR_URL_PROD_XDAI,
}
} else {
return {
[Network.MAINNET]: process.env.OPERATOR_URL_STAGING_MAINNET,
[Network.GOERLI]: process.env.OPERATOR_URL_STAGING_GOERLI,
[Network.GNOSIS_CHAIN]: process.env.OPERATOR_URL_STAGING_XDAI,
}
}
}

const API_BASE_URL = getOperatorUrl()

const DEFAULT_HEADERS: Headers = new Headers({
'Content-Type': 'application/json',
})

/**
* Unique identifier for the order, calculated by keccak256(orderDigest, ownerAddress, validTo),
where orderDigest = keccak256(orderStruct). bytes32.
*/

function _getApiBaseUrl(networkId: Network): string {
const baseUrl = API_BASE_URL[networkId]

if (!baseUrl) {
throw new Error('Unsupported Network. The operator API is not deployed in the Network ' + networkId)
} else {
return baseUrl + '/v1'
}
}

function _get(networkId: Network, url: string): Promise<Response> {
const baseUrl = _getApiBaseUrl(networkId)
return fetch(baseUrl + url, {
headers: DEFAULT_HEADERS,
})
}

/**
* Gets a single order by id
*/
Expand All @@ -66,37 +13,6 @@ export async function getOrder(params: GetOrderParams): Promise<RawOrder | null>
return orderBookSDK.getOrderMultiEnv(orderId, { chainId: networkId })
}

/**
* Gets a list of orders
*
* Optional filters:
* - owner: address
* - sellToken: address
* - buyToken: address
* - minValidTo: number
*/
export async function getOrders(params: GetOrdersParams): Promise<RawOrder[]> {
const { networkId, ...searchParams } = params
const { owner, sellToken, buyToken, minValidTo } = searchParams
const defaultValues = {
includeFullyExecuted: 'true',
includeInvalidated: 'true',
includeInsufficientBalance: 'true',
includePresignaturePending: 'true',
includeUnsupportedTokens: 'true',
}

console.log(
`[getOrders] Fetching orders on network ${networkId} with filters: owner=${owner} sellToken=${sellToken} buyToken=${buyToken}`
)

const searchString = buildSearchString({ ...searchParams, ...defaultValues, minValidTo: String(minValidTo) })

const queryString = '/orders/' + searchString

return _fetchQuery(networkId, queryString)
}

/**
* Gets a order list within Tx
*/
Expand Down Expand Up @@ -148,14 +64,3 @@ export async function getTrades(

return [...trades[0], ...trades[1]]
}

function _fetchQuery<T>(networkId: Network, queryString: string): Promise<T>
function _fetchQuery<T>(networkId: Network, queryString: string, nullOn404: true): Promise<T | null>
function _fetchQuery<T>(networkId: Network, queryString: string, nullOn404?: boolean): Promise<T | null> {
const get = (): Promise<Response> => _get(networkId, queryString)
if (nullOn404) {
return fetchQuery({ get }, queryString, nullOn404)
}

return fetchQuery({ get }, queryString)
}
9 changes: 8 additions & 1 deletion apps/explorer/src/cowSdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@ import { OrderBookApi, SubgraphApi } from '@cowprotocol/cow-sdk'
import { MetadataApi } from '@cowprotocol/app-data'
import { SUBGRAPH_URLS } from './consts/subgraphUrls'

export const orderBookSDK = new OrderBookApi({ env: 'prod' })
const prodBaseUrls = process.env.REACT_APP_ORDER_BOOK_URLS
? JSON.parse(process.env.REACT_APP_ORDER_BOOK_URLS)
: undefined

export const orderBookSDK = new OrderBookApi({
env: 'prod',
...(prodBaseUrls ? { baseUrls: prodBaseUrls } : undefined),
})
export const subgraphApiSDK = new SubgraphApi({
baseUrls: SUBGRAPH_URLS,
})
Expand Down
120 changes: 1 addition & 119 deletions apps/explorer/src/explorer/pages/AppData/EncodePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ const EncodePage: React.FC<EncodeProps> = ({ tabData, setTabData /* handleTabCha
useEffect(() => {
setIsLoading(true)

// Get the fullAppData (dermenistic stringify JSON)
// Get the fullAppData (deterministic stringify JSON)
_toFullAppData(appDataForm)
.then((fullAppData) => {
// Update the fullAppData
Expand Down Expand Up @@ -133,11 +133,6 @@ const EncodePage: React.FC<EncodeProps> = ({ tabData, setTabData /* handleTabCha
[]
)

// const handleIPFSErrors = useCallback(
// (_: FormProps, errors: FormValidation): FormValidation => handleErrors(ipfsFormRef, errors, setDisabledIPFS),
// [],
// )

const handleOnChange = useCallback(
({ formData }: FormProps): void => {
const resetFormFields = (form: string): void => {
Expand All @@ -157,34 +152,6 @@ const EncodePage: React.FC<EncodeProps> = ({ tabData, setTabData /* handleTabCha
[ipfsHashInfo]
)

// const handleIPFSOnChange = useCallback(({ formData: ipfsData }: FormProps): void => {
// setIpfsCredentials(ipfsData)
// if (JSON.stringify(ipfsData) !== JSON.stringify({})) {
// setDisabledIPFS(false)
// }
// }, [])

// const onUploadToIPFS = useCallback(
// async ({ formData }: FormProps): Promise<void> => {
// if (!ipfsHashInfo) return
// setIsLoading(true)
// try {
// await metadataApiSDK.uploadMetadataDocToIpfsLegacy(handleFormatData(appDataForm), formData)
// setIsDocUploaded(true)
// } catch (e) {
// if (INVALID_IPFS_CREDENTIALS.includes(e.message)) {
// e.message = 'Invalid API keys provided.'
// }
// setError(e.message)
// setIsDocUploaded(false)
// } finally {
// setIsLoading(false)
// toggleInvalid({ ipfs: true })
// }
// },
// [appDataForm, ipfsHashInfo],
// )

return (
<>
<div className="info-header box">
Expand Down Expand Up @@ -319,91 +286,6 @@ const EncodePage: React.FC<EncodeProps> = ({ tabData, setTabData /* handleTabCha
</div>
</AppDataWrapper>
</div>
{/* <div className="ipfs-container">
{ipfsHashInfo && (
<>
<IpfsWrapper>
<div className="info-header inner-form">
<h2>IPFS UPLOAD</h2>
<p>
We offer an integrated way to upload the generated file to IPFS directly through
<a target="_blank" href="https://docs.pinata.cloud/pinata-api" rel="noreferrer">
Pinata’s
</a>
API.
</p>
<p>
Insert your credentials and hit upload. The resulting <strong>appData</strong> hash is displayed on
the generated section.
</p>
<p>
Once uploaded, you can use the <strong>appData</strong> hash in the
<a onClick={(): void => handleTabChange(TabView.DECODE)}>Decode</a>
tab to verify it.
</p>
</div>
<Form
className="data-form"
showErrorList={false}
onSubmit={onUploadToIPFS}
liveValidate={invalidFormDataAttempted.ipfs}
onChange={handleIPFSOnChange}
formData={ipfsCredentials}
validate={handleIPFSErrors}
fields={{ cField: CustomField }}
ref={ipfsFormRef}
noHtml5Validate
onError={(): void => toggleInvalid({ ipfs: true })}
transformErrors={transformErrors}
schema={ipfsSchema}
uiSchema={ipfsUiSchema}
>
<span className="disclaimer">
<strong>Notes:</strong>
<ol>
<li>
The credentials are kept in memory only while you are at this page. When you navigate away or
close the browser tab it’ll be cleared.
</li>
<li>
If you upload the file directly, the resulting hash/appDataHash might differ. The hash/IPFS CID
calculated by the tool is a minified and stringified file without a new line at the end. That
means that you will get different results if the file is uploaded directly as a file.
</li>
</ol>
</span>
<button className="btn btn-info" disabled={disabledIPFS} type="submit">
UPLOAD APPDATA TO IPFS
</button>
</Form>
</IpfsWrapper>
</>
)}
{isDocUploaded && (
<>
<RowWithCopyButton
className="appData-hash"
textToCopy={`${DEFAULT_IPFS_READ_URI}/${ipfsHashInfo?.cid}`}
contentsToDisplay={
<a href={`${DEFAULT_IPFS_READ_URI}/${ipfsHashInfo?.cid}`} target="_blank" rel="noopener noreferrer">
{ipfsHashInfo?.cid}
</a>
}
/>
<Notification
type="success"
message="Document uploaded successfully!"
closable={false}
appendMessage={false}
/>
</>
)}
{isLoading && <Spinner />}
{error && !isDocUploaded && (
<Notification type="error" message={error} closable={false} appendMessage={false} />
)}
</div>
*/}
</>
)
}
Expand Down
Loading

0 comments on commit 957eefa

Please sign in to comment.