Skip to content

Commit

Permalink
[ECO-2177] Convert SDK and e2e tests to use the new emojicoin index…
Browse files Browse the repository at this point in the history
…er processor (#242)

Co-authored-by: matt <[email protected]>
  • Loading branch information
xbtmatt and matt authored Sep 16, 2024
1 parent 8bde35b commit 829bf56
Show file tree
Hide file tree
Showing 103 changed files with 3,853 additions and 1,980 deletions.
2 changes: 1 addition & 1 deletion .github/actions/ts-run-tests/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ runs:
name: 'pnpm-test'
uses: 'nick-fields/retry@7f8f3d9f0f62fe5925341be21c2e8314fd4f7c7c'
with:
command: 'cd ${{ env.TS_DIR }} && pnpm run test'
command: 'cd ${{ env.TS_DIR }} && pnpm run test:verbose'
max_attempts: 2
timeout_minutes: 10
- if: 'failure()'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/link-checker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ jobs:
linkChecker:
runs-on: 'ubuntu-latest'
steps:
- uses: 'actions/checkout@v3'
- uses: 'actions/checkout@v4'
- env:
GITHUB_TOKEN: '${{secrets.GITHUB_TOKEN}}'
id: 'lychee'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ name: 'Playwright Tests'
pull_request:
branches:
- 'main'
- 'production'
push:
branches:
- 'main'
- 'production'
...
3 changes: 2 additions & 1 deletion .github/workflows/pre-commit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
pre-commit:
runs-on: 'ubuntu-latest'
steps:
- uses: 'actions/checkout@v3'
- uses: 'actions/checkout@v4'
- run: 'git submodule update --init --recursive src/rust/processor'
- uses: 'actions/setup-python@v3'
with:
Expand Down Expand Up @@ -59,5 +59,6 @@ name: 'pre-commit'
push:
branches:
- 'main'
- 'production'
workflow_dispatch: null
...
3 changes: 2 additions & 1 deletion .github/workflows/ts-run-fmt.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ jobs:
ts-run-fmt:
runs-on: 'ubuntu-latest'
steps:
- uses: 'actions/checkout@v3'
- uses: 'actions/checkout@v4'
- uses: './.github/actions/ts-run-fmt'
name: 'Run the TypeScript formatter'
'on':
pull_request: null
push:
branches:
- 'main'
- 'production'
workflow_dispatch: null
...
3 changes: 2 additions & 1 deletion .github/workflows/ts-run-lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ jobs:
ts-run-lint:
runs-on: 'ubuntu-latest'
steps:
- uses: 'actions/checkout@v3'
- uses: 'actions/checkout@v4'
- uses: './.github/actions/ts-run-lint'
name: 'Run the TypeScript linter'
'on':
pull_request: null
push:
branches:
- 'main'
- 'production'
workflow_dispatch: null
...
1 change: 1 addition & 0 deletions .github/workflows/ts-run-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ name: 'Run the TypeScript E2E and unit tests with a local testnet'
push:
branches:
- 'main'
- 'production'
workflow_dispatch: null
...
3 changes: 2 additions & 1 deletion .github/workflows/verify-doc-site-build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
working-directory: 'doc/doc-site'
runs-on: 'ubuntu-latest'
steps:
- uses: 'actions/checkout@v3'
- uses: 'actions/checkout@v4'
- uses: 'actions/setup-node@v3'
with:
node-version: 20
Expand All @@ -18,6 +18,7 @@ name: 'Verify docs site build'
pull_request:
branches:
- 'main'
- 'production'
paths:
- 'doc/doc-site/**'
- '.github/workflows/verify-doc-site-build.yaml'
Expand Down
5 changes: 3 additions & 2 deletions src/docker/utils/prune.sh
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ trap cleanup EXIT
################################################################################

cd $docker_dir
docker compose -f compose.local.yaml down --volumes

postgres="local-testnet-postgres"
api="local-testnet-indexer-api"
Expand All @@ -133,5 +132,7 @@ docker rm -f $api 2>/dev/null
docker volume rm -f $postgres-data

if [ -n "$reset_localnet" ]; then
rm -rf $docker_dir/localnet/.aptos/*
docker compose -f compose.local.yaml down --volumes
else
docker compose -f compose.local.yaml down
fi
20 changes: 15 additions & 5 deletions src/typescript/.env.ci
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
START_LOCAL_NODE_FOR_TEST="true"

# The Aptos network to use
NEXT_PUBLIC_APTOS_NETWORK="testnet"
NEXT_PUBLIC_APTOS_NETWORK="local"

# The address of the main `emojicoin_dot_fun` contract module
NEXT_PUBLIC_MODULE_ADDRESS="0xbabe8f471b7f4744502b1397530bafe80e3731b358c0dfeba26b38b2603bd00d"
NEXT_PUBLIC_MODULE_ADDRESS="0xf000d910b99722d201c6cf88eb7d1112b43475b9765b118f289b5d65d919000d"

# The address of the rewards module with the overloaded swap function
NEXT_PUBLIC_REWARDS_MODULE_ADDRESS="0x76044a237dcc3f71af75fb314f016e8032633587f7d70df4e70777f2b0221e75"
NEXT_PUBLIC_REWARDS_MODULE_ADDRESS="0xf000d910b99722d201c6cf88eb7d1112b43475b9765b118f289b5d65d919000d"

# The default URL for a local inbox deployment. Do not add a slash to the end
# Set through CI env variables
Expand All @@ -20,10 +20,10 @@ INBOX_URL=""
REVALIDATION_TIME="1"

# The integrator address for the contract.
NEXT_PUBLIC_INTEGRATOR_ADDRESS="0xbabe8f471b7f4744502b1397530bafe80e3731b358c0dfeba26b38b2603bd00d"
NEXT_PUBLIC_INTEGRATOR_ADDRESS="0xf000d910b99722d201c6cf88eb7d1112b43475b9765b118f289b5d65d919000d"

# The BPS fee rate for each swap, liquidity provision, or liquidity removal.
NEXT_PUBLIC_INTEGRATOR_FEE_RATE_BPS="125"
NEXT_PUBLIC_INTEGRATOR_FEE_RATE_BPS="100"

# If false, no allowlist is set up
# If true, NEXT_PUBLIC_GALXE_CAMPAIGN_ID (and|or) ALLOWLISTER3K_URL needs to be set
Expand All @@ -47,3 +47,13 @@ NEXT_PUBLIC_GALXE_CAMPAIGN_REDIRECT=""
# protocol prefix.
# Set through CI env variables
NEXT_PUBLIC_MQTT_URL=""

# The private key used to deploy the package locally for tests.
# Note that this private key is obviously public and should never be used in
# production or for any real value transactions.
# If you change this, note that local tests will fail unless you also change
# the corresponding `EMOJICOIN_REWARDS_MODULE_ADDRESS` value.
PUBLISHER_PRIVATE_KEY="eaa964d1353b075ac63b0c5a0c1e92aa93355be1402f6077581e37e2a846105e"

# The URL to the indexer for the local network.
INDEXER_URL="http://localhost:3000"
4 changes: 3 additions & 1 deletion src/typescript/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ REVALIDATION_TIME="60"
NEXT_PUBLIC_INTEGRATOR_ADDRESS="0xbabe8f471b7f4744502b1397530bafe80e3731b358c0dfeba26b38b2603bd00d"

# The BPS fee rate for each swap, liquidity provision, or liquidity removal.
NEXT_PUBLIC_INTEGRATOR_FEE_RATE_BPS="125"
NEXT_PUBLIC_INTEGRATOR_FEE_RATE_BPS="100"

# If false, no allowlist is set up
# If true, NEXT_PUBLIC_GALXE_CAMPAIGN_ID (and|or) ALLOWLISTER3K_URL needs to be set
Expand Down Expand Up @@ -60,3 +60,5 @@ NEXT_PUBLIC_LINKS='{
"telegram": "",
"tos": ""
}'

INDEXER_URL="http://localhost:3000"
12 changes: 0 additions & 12 deletions src/typescript/.env.test

This file was deleted.

6 changes: 3 additions & 3 deletions src/typescript/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ scripts run the `dotenv-cli` package as a wrapper, like so:

```shell
# In sdk/package.json:
"test": "dotenv -e ../.env.test -- pnpm jest",
"test": "dotenv -e ../.env.ci -- pnpm jest",

# I run this command
pnpm run test

# Which loads the env variables in `../.env.test` and runs `jest`
# Which loads the env variables in `../.env.ci` and runs `jest`
```

Where `../.env.test` is the environment file located in the `typescript` parent
Where `../.env.ci` is the environment file located in the `typescript` parent
directory.

To avoid having to define environment variables in multiple places, we've
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ export const ChartContainer = (props: Omit<ChartContainerProps, "isScriptReady">
});
}, [initialize]);

// For now, we subscribe to any periodic state event instead of just a specific resolution.
// For now, we subscribe to any periodic state event instead of just a specific period duration type.
// There isn't a good reason to do otherwise since this is just the websocket subscription and we
// default to 5m candles, which will have more data than any resolution except for the 1 minute chart.
// default to 5m candles, which will have more data than any period duration type except for the 1 minute chart.
useReliableSubscribe({
periodicState: [props.marketID, null],
});
Expand Down
30 changes: 15 additions & 15 deletions src/typescript/frontend/src/components/charts/PrivateChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { useEffect, useMemo, useRef } from "react";

import {
PERIOD_TO_CANDLESTICK_RESOLUTION,
ResolutionStringsToPeriodDuration,
EXCHANGE_NAME,
MS_IN_ONE_DAY,
TV_CHARTING_LIBRARY_RESOLUTIONS,
Expand Down Expand Up @@ -71,8 +71,8 @@ export const Chart = async (props: ChartContainerProps) => {
const ref = useRef<HTMLDivElement>(null);
const router = useRouter();
const symbol = props.symbol;
const subscribeToResolution = useEventStore((s) => s.subscribeToResolution);
const unsubscribeFromResolution = useEventStore((s) => s.unsubscribeFromResolution);
const subscribeToPeriod = useEventStore((s) => s.subscribeToPeriod);
const unsubscribeFromPeriod = useEventStore((s) => s.unsubscribeFromPeriod);
const setLatestBars = useEventStore((s) => s.setLatestBars);
const getRegisteredMarketMap = useEventStore((s) => s.getRegisteredMarketMap);

Expand Down Expand Up @@ -147,7 +147,7 @@ export const Chart = async (props: ChartContainerProps) => {
getBars: async (symbolInfo, resolution, periodParams, onHistoryCallback, onErrorCallback) => {
const { from, to } = periodParams;
try {
const resolutionEnum = PERIOD_TO_CANDLESTICK_RESOLUTION[resolution.toString()];
const period = ResolutionStringsToPeriodDuration[resolution.toString()];
const start = new Date(from * 1000);
const end = new Date(to * 1000);
// TODO: Consider that if our data is internally consistent and we run into performance/scalability issues
Expand All @@ -157,7 +157,7 @@ export const Chart = async (props: ChartContainerProps) => {
marketID: props.marketID,
start,
end,
resolution: resolutionEnum,
period,
});

const isFetchForMostRecentBars = end.getTime() - new Date().getTime() > 1000;
Expand All @@ -180,11 +180,11 @@ export const Chart = async (props: ChartContainerProps) => {
const latestBars = marketViewToLatestBars(marketView);
setLatestBars({ marketID: props.marketID, latestBars });

// Get the period-specific state tracker for the current resolution and set the latest bar on the chart
// (*not* just in state) to the latest bar from that tracker.
// Get the period-specific state tracker for the current resolution/period type and set the latest bar on
// the chart- *not* just in state- to the latest bar from that tracker.
const tracker = marketView.periodicStateTrackers.find(
// These are most likely indexed in order, but in case they aren't, we use `find` here.
(v) => Number(v.period) === resolutionEnum
(v) => Number(v.period) === period
);
if (!tracker) {
throw new Error("This should never happen.");
Expand Down Expand Up @@ -222,7 +222,7 @@ export const Chart = async (props: ChartContainerProps) => {
// If this is the most recent bar fetch and there is literally zero trading activity thus far,
// we should create a single empty bar to get rid of the `No chart data` ghost error from showing.
const time = BigInt(new Date().getTime()) * 1000n;
const timeAsPeriod = getPeriodStartTimeFromTime(time, resolutionEnum) / 1000n;
const timeAsPeriod = getPeriodStartTimeFromTime(time, period) / 1000n;
bars.push({
time: Number(timeAsPeriod),
open: 0,
Expand Down Expand Up @@ -259,21 +259,21 @@ export const Chart = async (props: ChartContainerProps) => {
if (!symbolInfo.ticker) {
throw new Error(`No ticker for symbol: ${symbolInfo}`);
}
const resolutionEnum = PERIOD_TO_CANDLESTICK_RESOLUTION[resolution.toString()];
subscribeToResolution({
const period = ResolutionStringsToPeriodDuration[resolution.toString()];
subscribeToPeriod({
symbol: symbolInfo.ticker,
resolution: resolutionEnum,
period,
cb: onRealtimeCallback,
});
},
unsubscribeBars: async (subscriberUID) => {
// subscriberUIDs come in the form of `${emoji}_#_$<period as string>`
// For example: `🚀_#_5` for the `🚀` market for a resolution of period `5`.
const [symbol, resolution] = subscriberUID.split("_#_");
const resolutionEnum = PERIOD_TO_CANDLESTICK_RESOLUTION[resolution];
unsubscribeFromResolution({
const period = ResolutionStringsToPeriodDuration[resolution];
unsubscribeFromPeriod({
symbol,
resolution: resolutionEnum,
period,
});
},
}),
Expand Down
22 changes: 13 additions & 9 deletions src/typescript/frontend/src/components/charts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ most often refers to the `start time` of the `period`, although it can mean
either side of a period boundary, i.e., the start _or_ the end time for a
candlestick period.

The `PeriodDuration` enum indicates the actual time of the period in
microseconds, as specified in the Move smart contract.

## Datafeed API

The [datafeed API] provides two ways of populating data on the chart.
Expand Down Expand Up @@ -119,12 +122,13 @@ store them in state and visually update the latest bar data with the
This function is created by the datafeed API specifically for each combination
of a market and a candlestick time frame. We store this function in our
[EventStore state] in the `EventStore` market ID map, which also has a
corresponding `resolution` field containing an object that holds the callback
corresponding `period` field containing an object that holds the callback
function.

For example, if our `EventStore` encounters a swap event for the market with a
market ID of `3`, we iterate over all resolutions and check if we should update
the latest bar and/or invoke the datafeed API callback function.
market ID of `3`, we iterate over all resolutions (aka period duration types
and check if we should update the latest bar and/or invoke the datafeed API
callback function.

Something like this:

Expand All @@ -136,19 +140,19 @@ set((state) => {
// ...

// For all periods/resolutions, i.e., 1m, 5m, 15m, 30m, 1h, 4h, 1d.
for (const resolution of RESOLUTIONS_ARRAY) {
for (const period of PERIOD_DURATIONS) {
const marketID = event.marketID.toString();
const market = state.markets.get(marketID);
const resolutionData = market[resolution];
if (resolutionData) {
const periodData = market[period];
if (periodData) {
// Process the data, possibly update or create a new latest bar...
// ...

// In essence, we eventually do this:
if (resolutionData.latestBar && resolutionData.callback) {
if (periodData.latestBar && periodData.callback) {
// Thus, our callback is only invoked if we are currently subscribed
// to that specific market ID + resolution combination.
resolutionData.callback(resolutionData.latestBar);
// to that specific market ID + period combination.
periodData.callback(periodData.latestBar);
}
}
}
Expand Down
Loading

0 comments on commit 829bf56

Please sign in to comment.