diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index bf497a22a0..0000000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: CI - -on: - pull_request: - -jobs: - test: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - name: Set up pnpm - uses: dydxprotocol/setup-pnpm@v2.0.0 - - - name: Set up Node - uses: actions/setup-node@v3 - with: - node-version: 18 - cache: pnpm - - - run: | - pnpm install --ignore-scripts --frozen-lockfile - tar -xzC public -f tradingview/tradingview.tgz # manually inline postinstall script - - - run: pnpm exec vitest run \ No newline at end of file diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml deleted file mode 100644 index 5722c3164d..0000000000 --- a/.github/workflows/deploy-staging.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Deploy to v4.stage.dydx.exchange - -on: - workflow_dispatch: - -jobs: - deploy: - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Set up pnpm - uses: dydxprotocol/setup-pnpm@v2.0.0 - - - name: Set up Node - uses: actions/setup-node@v3 - with: - node-version: 18 - registry-url: https://registry.npmjs.org/ - cache: pnpm - - - name: Install dependencies - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - run: | - pnpm install --loglevel warn - - - name: Build - env: - NODE_OPTIONS: '--max-old-space-size=4096' - run: | - pnpm run build --mode staging - - - name: Upload to IPFS via web3.storage - uses: dydxprotocol/add-to-web3@v1 - id: web3storage - with: - web3_token: ${{ secrets.WEB3_STORAGE_TOKEN }} - path_to_add: 'dist' diff --git a/.github/workflows/deploy-testnet.yml b/.github/workflows/deploy-testnet.yml deleted file mode 100644 index fb5d20d44b..0000000000 --- a/.github/workflows/deploy-testnet.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: Deploy to v4.testnet.dydx.exchange - -on: - workflow_dispatch: - -jobs: - deploy: - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Set up pnpm - uses: dydxprotocol/setup-pnpm@v2.0.0 - - - name: Set up Node - uses: actions/setup-node@v3 - with: - node-version: 18 - registry-url: https://registry.npmjs.org/ - cache: pnpm - - - name: Install dependencies - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - run: | - pnpm install --loglevel warn - - - name: Build - env: - NODE_OPTIONS: '--max-old-space-size=4096' - AMPLITUDE_API_KEY: ${{ secrets.AMPLITUDE_API_KEY }} - BUGSNAG_API_KEY: ${{ secrets.BUGSNAG_API_KEY }} - STATUS_PAGE_SCRIPT_URI: ${{ secrets.STATUS_PAGE_SCRIPT_URI }} - IOS_APP_ID: ${{ secrets.IOS_APP_ID }} - run: | - pnpm run build - pnpm run build:inject-amplitude - pnpm run build:inject-google-tag-manager - pnpm run build:inject-hotjar - pnpm run build:inject-bugsnag - pnpm run build:inject-statuspage - pnpm run build:inject-smartbanner - sh scripts/inject-app-deeplinks.sh - - - name: Upload to IPFS via web3.storage - uses: dydxprotocol/add-to-web3@v1 - id: web3storage - with: - web3_token: ${{ secrets.WEB3_STORAGE_TOKEN }} - path_to_add: 'dist' - - - name: Update IPNS record via web3name - id: web3name - env: - WEB3NAME_SIGNING_KEY: ${{ secrets.WEB3NAME_SIGNING_KEY }} - run: | - echo $WEB3NAME_SIGNING_KEY | base64 -d > .web3name.key - pnpm run deploy:update-ipns --cid=${{ steps.web3storage.outputs.cid }} --key=.web3name.key diff --git a/.github/workflows/deployer.yml b/.github/workflows/deployer.yml new file mode 100644 index 0000000000..9b5cd9ec95 --- /dev/null +++ b/.github/workflows/deployer.yml @@ -0,0 +1,225 @@ +name: Deploy new upstream release to Vercel + +on: + workflow_dispatch: + repository_dispatch: + types: [deploy-upstream] + +jobs: + # ======================================== + # JOB 1: Fetch Versions + # ======================================== + fetch-versions: + runs-on: ubuntu-latest + outputs: + latest-version: ${{ steps.upstream.outputs.latest-version }} + latest-tag: ${{ steps.upstream.outputs.latest-tag }} + production-version: ${{ steps.production.outputs.production-version }} + production-tag: ${{ steps.production.outputs.production-tag }} + latest-patch-in-line-version: ${{ steps.patch-in-line.outputs.latest-patch-in-line-version }} + latest-patch-in-line-tag: ${{ steps.patch-in-line.outputs.latest-patch-in-line-tag }} + + steps: + - name: Log trigger information + run: | + echo "Workflow triggered by: ${{ github.event_name }}" + if [ "${{ github.event_name }}" = "repository_dispatch" ]; then + echo "Event type: ${{ github.event.action }}" + echo "Client payload: ${{ toJson(github.event.client_payload) }}" + fi + + - name: Generate GitHub App Token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ vars.GH_APP_ID }} + private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} + + - name: Checkout repository + uses: actions/checkout@v4 + with: + token: ${{ steps.app-token.outputs.token }} + fetch-depth: 0 # Fetch full history + + - name: Configure Git with GitHub App + run: | + git config --global user.name "dos-automation-bot[bot]" + git config --global user.email "dos-automation-bot@users.noreply.github.com" + + - name: Identify the latest upstream version + id: upstream + run: | + # Add upstream remote using HTTPS with token + git remote add upstream https://x-access-token:${{ steps.app-token.outputs.token }}@github.com/dydxprotocol/v4-web.git + + # Update origin to use HTTPS with token + git remote set-url origin https://x-access-token:${{ steps.app-token.outputs.token }}@github.com/dydxopsdao/v4-web.git + + # Fetch all tags from upstream + git fetch upstream + + # Get the latest release tag + LATEST_TAG=$(git tag -l 'release/v*' | sort -V | tail -n 1) + echo "Latest upstream tag found: ${LATEST_TAG}" + + # Check if LATEST_TAG is empty + if [ -z "$LATEST_TAG" ]; then + echo "No tags found matching 'release/v*'." + exit 1 + fi + + # Export to outputs + echo "latest-tag=${LATEST_TAG}" >> $GITHUB_OUTPUT + echo "latest-version=${LATEST_TAG#release/v}" >> $GITHUB_OUTPUT + + - name: Identify the latest production version + id: production + run: | + # Fetch all tags from the main branch + git fetch origin main --tags + + # Get the latest tag on the main branch + PRODUCTION_TAG=$(git tag --merged origin/main | sort -V | tail -n 1) + echo "Latest production tag on main branch: ${PRODUCTION_TAG}" + + # Check if PRODUCTION_TAG is empty + if [ -z "$PRODUCTION_TAG" ]; then + echo "No production tags found on main branch." + exit 1 + fi + + # Export to outputs + echo "production-tag=${PRODUCTION_TAG}" >> $GITHUB_OUTPUT + echo "production-version=${PRODUCTION_TAG#release/v}" >> $GITHUB_OUTPUT + + - name: Identify the latest patch in production version line + id: patch-in-line + run: | + # Get the production version to extract major.minor + PRODUCTION_VERSION="${{ steps.production.outputs.production-version }}" + IFS='.' read -r PROD_MAJOR PROD_MINOR PROD_PATCH <<< "$PRODUCTION_VERSION" + + echo "Production version: $PRODUCTION_VERSION (Major: $PROD_MAJOR, Minor: $PROD_MINOR, Patch: $PROD_PATCH)" + echo "Looking for latest patch in upstream version line: $PROD_MAJOR.$PROD_MINOR.x" + + # Find the latest tag in the same major.minor version line from upstream + LATEST_PATCH_IN_LINE_TAG=$(git tag -l "release/v$PROD_MAJOR.$PROD_MINOR.*" | sort -V | tail -n 1) + + if [ -z "$LATEST_PATCH_IN_LINE_TAG" ]; then + echo "No upstream tags found for version line $PROD_MAJOR.$PROD_MINOR.x" + echo "Using production version as fallback" + echo "latest-patch-in-line-tag=${{ steps.production.outputs.production-tag }}" >> $GITHUB_OUTPUT + echo "latest-patch-in-line-version=$PRODUCTION_VERSION" >> $GITHUB_OUTPUT + else + LATEST_PATCH_IN_LINE_VERSION="${LATEST_PATCH_IN_LINE_TAG#release/v}" + echo "Latest patch in upstream version line: $LATEST_PATCH_IN_LINE_TAG ($LATEST_PATCH_IN_LINE_VERSION)" + + # Export to outputs + echo "latest-patch-in-line-tag=${LATEST_PATCH_IN_LINE_TAG}" >> $GITHUB_OUTPUT + echo "latest-patch-in-line-version=${LATEST_PATCH_IN_LINE_VERSION}" >> $GITHUB_OUTPUT + fi + + # ======================================== + # JOB 2: Determine If Deployment Is Needed + # ======================================== + determine-if-deployment-needed: + runs-on: ubuntu-latest + needs: fetch-versions + outputs: + new-patch-version: ${{ steps.version-check.outputs.new-patch-version }} + + steps: + - name: Determine version type + id: version-check + run: | + echo "Checking if the version is a patch, minor, or major" + + # Extract version numbers from outputs + IFS='.' read -r PROD_MAJOR PROD_MINOR PROD_PATCH <<< "${{ needs.fetch-versions.outputs.production-version }}" + IFS='.' read -r UPSTREAM_MAJOR UPSTREAM_MINOR UPSTREAM_PATCH <<< "${{ needs.fetch-versions.outputs.latest-version }}" + IFS='.' read -r PATCH_LINE_MAJOR PATCH_LINE_MINOR PATCH_LINE_PATCH <<< "${{ needs.fetch-versions.outputs.latest-patch-in-line-version }}" + + # Log the extracted version numbers + echo "Production Version - Major: $PROD_MAJOR, Minor: $PROD_MINOR, Patch: $PROD_PATCH" + echo "Latest Patch in Line - Major: $PATCH_LINE_MAJOR, Minor: $PATCH_LINE_MINOR, Patch: $PATCH_LINE_PATCH" + echo "Latest Version - Major: $UPSTREAM_MAJOR, Minor: $UPSTREAM_MINOR, Patch: $UPSTREAM_PATCH" + + # Determine if a new patch version is detected within the same major.minor line + if [ "$PATCH_LINE_MAJOR" -eq "$PROD_MAJOR" ] && [ "$PATCH_LINE_MINOR" -eq "$PROD_MINOR" ] && [ "$PATCH_LINE_PATCH" -gt "$PROD_PATCH" ]; then + echo "New patch version detected: ${{ needs.fetch-versions.outputs.latest-patch-in-line-tag }}" + echo "new-patch-version=true" >> $GITHUB_OUTPUT + else + echo "No new patch version detected." + echo "new-patch-version=false" >> $GITHUB_OUTPUT + exit 0 + fi + + # ======================================== + # JOB 3: Deploy + # ======================================== + deploy: + runs-on: ubuntu-latest + needs: [fetch-versions, determine-if-deployment-needed] + if: needs.determine-if-deployment-needed.outputs.new-patch-version == 'true' + + steps: + - name: Generate GitHub App Token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ vars.GH_APP_ID }} + private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} + + - name: Checkout repository + uses: actions/checkout@v4 + with: + token: ${{ steps.app-token.outputs.token }} + fetch-depth: 0 # Fetch full history + + - name: Configure Git with GitHub App and GPG signing + run: | + git config --global user.name "dos-automation" + git config --global user.email "196231098+hedgie-svc@users.noreply.github.com" + + # Configure GPG for non-interactive use + mkdir -p ~/.gnupg + echo "pinentry-mode loopback" >> ~/.gnupg/gpg.conf + + # Import GPG key and configure signing + echo "${{ secrets.BOT_GPG_PRIVATE_KEY }}" | gpg --batch --yes --import + git config --global user.signingkey $(gpg --list-secret-keys --keyid-format LONG | grep sec | awk '{print $2}' | cut -d'/' -f2) + git config --global commit.gpgsign true + + - name: Setup git remotes + run: | + # Add upstream remote using HTTPS with token + git remote add upstream https://x-access-token:${{ steps.app-token.outputs.token }}@github.com/dydxprotocol/v4-web.git + + # Update origin to use HTTPS with token + git remote set-url origin https://x-access-token:${{ steps.app-token.outputs.token }}@github.com/dydxopsdao/v4-web.git + + # Fetch all tags from upstream to ensure they are available locally + git fetch upstream --tags + + - name: Create a new release branch for Vercel deployment + run: | + # Create a new branch from the latest release tag + git checkout -b dos-${{ needs.fetch-versions.outputs.latest-patch-in-line-version }} origin/main + + # Rebase commits from the latest release tag onto the new release branch + git pull --rebase upstream ${{ needs.fetch-versions.outputs.latest-patch-in-line-tag }} + + # Push the release branch to the remote repository + git push --set-upstream origin dos-${{ needs.fetch-versions.outputs.latest-patch-in-line-version }} + + - name: Reset main to the feature branch for production deployment and push all changes + run: | + # Checkout the main branch + git checkout main + + # Hard reset the main branch to the feature branch + git reset --hard origin/dos-${{ needs.fetch-versions.outputs.latest-patch-in-line-version }} + + # Force push the changes to the main branch + sleep 1 + git push --force origin main diff --git a/.github/workflows/json-tester.yml b/.github/workflows/json-tester.yml new file mode 100644 index 0000000000..6588659395 --- /dev/null +++ b/.github/workflows/json-tester.yml @@ -0,0 +1,107 @@ +name: Compare JSONs Against dYdX + +on: + push: + branches: + - dos-* + workflow_dispatch: + inputs: + dydx_url: + description: 'URL of the dYdX reference JSON file' + required: false + default: '' + dos_url: + description: 'URL of the DOS comparison JSON file' + required: false + default: '' + +jobs: + validate-json: + runs-on: ubuntu-latest + timeout-minutes: 15 + + steps: + # Step 1: Check out your repo + - name: Check out your repo + uses: actions/checkout@v3 + + # Step 2: Determine dYdX reference + - name: Set dYdX and DOS JSON URLs + id: set-urls + run: | + if [[ -n "${{ github.event.inputs.dydx_url }}" && -n "${{ github.event.inputs.dos_url }}" ]]; then + DYDX_URL="${{ github.event.inputs.dydx_url }}" + DOS_URL="${{ github.event.inputs.dos_url }}" + echo "Manual URLs detected." + else + if [[ "${GITHUB_REF_NAME}" == dos-* ]]; then + VERSION="${GITHUB_REF_NAME#dos-}" + DYDX_REFERENCE="refs/tags/release/v${VERSION}" + DYDX_URL="https://raw.githubusercontent.com/dydxprotocol/v4-web/${DYDX_REFERENCE}/public/configs/v1/env.json" + DOS_URL="https://raw.githubusercontent.com/dydxopsdao/v4-web/${GITHUB_REF_NAME}/public/configs/v1/env.json" + + # Debug constructed URLs + echo "Constructed DYDX URL: ${DYDX_URL}" + echo "Constructed DOS URL: ${DOS_URL}" + + # Validate dYdX URL existence + if ! curl -sI "${DYDX_URL}" | grep -q "^HTTP.*[2][0-9][0-9]"; then + echo "Error: dYdX release tag ${DYDX_REFERENCE} not found or inaccessible." + exit 1 + fi + else + echo "Error: Branch name must follow the format dos-x.y.z or manual URLs must be provided." + exit 1 + fi + fi + echo "DYDX_URL=${DYDX_URL}" >> $GITHUB_ENV + echo "DOS_URL=${DOS_URL}" >> $GITHUB_ENV + echo "Using dYdX JSON URL: ${DYDX_URL}" + echo "Using DOS JSON URL: ${DOS_URL}" + + # Step 3: Clone the JSON Tester Repo + - name: Clone JSON Tester Repository + run: | + git clone https://github.com/dydxopsdao/json_test json-tester + echo "Cloned JSON tester repository." + + # Step 4: Fetch JSON files + - name: Fetch JSON Files + run: | + echo "Fetching JSON files..." + curl -H "Accept: application/json" -L "${{ env.DYDX_URL }}" -o json-tester/src/dydx.json || { echo "Error: Unable to fetch dYdX JSON."; exit 1; } + curl -H "Accept: application/json" -L "${{ env.DOS_URL }}" -o json-tester/src/dos.json || { echo "Error: Unable to fetch DOS JSON."; exit 1; } + + # Step 5: Validate JSON file content + - name: Validate JSON Content + run: | + echo "Validating downloaded JSON files..." + python -c "import json; json.load(open('json-tester/src/dydx.json'))" || { echo "Error: dYdX JSON is not valid."; cat json-tester/src/dydx.json; exit 1; } + python -c "import json; json.load(open('json-tester/src/dos.json'))" || { echo "Error: DOS JSON is not valid."; cat json-tester/src/dos.json; exit 1; } + + # Step 6: Set up Python + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.10' + + - name: Install Dependencies + run: | + cd json-tester + python -m pip install --upgrade pip + pip install -r requirements.txt + + # Step 7: Run JSON Tester + - name: Validate JSON Files + run: | + cd json-tester/src + python env_config_validator.py dydx.json dos.json || exit 1 + + # Step 8: Post Validation Summary + - name: Post Validation Summary + if: success() + run: echo "✅ JSON validation completed successfully!" + + - name: Report Failure + if: failure() + run: echo "❌ JSON validation failed. Check logs for details." diff --git a/package.json b/package.json index cbcdf06bb6..19ecf0cee3 100644 --- a/package.json +++ b/package.json @@ -225,4 +225,4 @@ "includeClassNames": true } } -} +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ac015f611b..fc95846147 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22293,4 +22293,4 @@ packages: /zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} - dev: true + dev: true \ No newline at end of file diff --git a/public/.well-known/assetlinks.json b/public/.well-known/assetlinks.json index 40e33dec85..f55b5e67d5 100644 --- a/public/.well-known/assetlinks.json +++ b/public/.well-known/assetlinks.json @@ -3,19 +3,9 @@ "relation": ["delegate_permission/common.handle_all_urls"], "target": { "namespace": "android_app", - "package_name": "exchange.dydx.trading.debug", + "package_name": "trade.opsdao.dydxchain", "sha256_cert_fingerprints": [ - "8A:9C:CC:49:B0:35:9A:91:67:CB:98:B0:B5:87:92:5F:9E:B7:EF:CE:A0:47:57:85:A4:35:3E:0C:E1:56:9E:A2" - ] - } - }, - { - "relation": ["delegate_permission/common.handle_all_urls"], - "target": { - "namespace": "android_app", - "package_name": "exchange.dydx.trading", - "sha256_cert_fingerprints": [ - "B2:2D:CC:27:9D:52:05:98:63:C9:7B:34:36:70:A3:8E:00:31:28:08:2D:2E:70:76:C9:31:AE:F9:55:21:15:A5" + "78:C6:5E:5B:45:F9:9E:21:29:D5:9B:73:BC:E2:EB:22:76:51:3D:10:88:4B:FC:29:18:69:12:B6:4D:8D:69:8F" ] } }, diff --git a/public/configs/sitemap.json b/public/configs/sitemap.json index d3284bdeaf..ea69f5389a 100644 --- a/public/configs/sitemap.json +++ b/public/configs/sitemap.json @@ -1,4 +1,20 @@ { - "baseURL": "your-base-url", - "staticURLs": [] + "baseURL": "https://dydx.trade", + "staticURLs": [ + "https://dydx.trade/", + "https://dydx.trade/terms", + "https://dydx.trade/markets", + "https://dydx.trade/DYDX", + "https://dydx.trade/DYDX/trading-rewards", + "https://dydx.trade/portfolio", + "https://dydx.trade/portfolio/history/trades", + "https://dydx.trade/trade?inputCurrency=ada&outputCurrency=usd", + "https://dydx.trade/trade?inputCurrency=atom&outputCurrency=usd", + "https://dydx.trade/trade?inputCurrency=btc&outputCurrency=usd", + "https://dydx.trade/trade?inputCurrency=doge&outputCurrency=usd", + "https://dydx.trade/trade?inputCurrency=dot&outputCurrency=usd", + "https://dydx.trade/trade?inputCurrency=xrp&outputCurrency=usd", + "https://dydx.trade/?utm_source=twitter&utm_medium=social-x&utm_campaign=dydx-trading-rewards", + "https://dydx.trade/?utm_source=twitter&utm_medium=social-x&utm_campaign=incentive-program" + ] } \ No newline at end of file diff --git a/public/configs/v1/env.json b/public/configs/v1/env.json index 0ef8a4f8ab..8c2d891034 100644 --- a/public/configs/v1/env.json +++ b/public/configs/v1/env.json @@ -36,11 +36,11 @@ "image": "/currencies/usdc.png" } }, - "[mainnet chain id]": { - "comment": "Change according to mainnet release", + "dydx-mainnet-1": { + "comment": "Mainnet", "chain": { - "name": "TokenName", - "denom": "tokenDenom", + "name": "DYDX", + "denom": "adydx", "decimals": 18, "image": "/currencies/dydx.png" }, @@ -204,56 +204,56 @@ "incentiveProgram": "https://www.dydx.xyz/blog/dydx-surge", "incentiveProgramLeaderboard": "https://community.chaoslabs.xyz/dydx-v4/risk/leaderboard" }, - "[mainnet chain id]": { - "tos": "[HTTP link to TOS]", - "privacy": "[HTTP link to Privacy Policy]", - "statusPage": "[HTTP link to status page]", - "mintscan": "[HTTP link to Mintscan, with {tx_hash} placeholder]", - "mintscanBase": "[HTTP link to TOS mintscan base url]", - "feedback": "[HTTP link to feedback form, can be null]", - "blogs": "[HTTP link to blogs, can be null]", - "foundation": "[HTTP link to foundation, can be null]", - "reduceOnlyLearnMore": "[HTTP link to reduce-only learn more, can be null]", - "documentation": "[HTTP link to documentation, can be null]", - "community": "[HTTP link to community, can be null]", - "vipsChannel": "[HTTP link to vips channel, can be null]", - "help": "[HTTP link to help page, can be null]", - "vaultLearnMore": "[HTTP link to vault learn more page, can be null]", - "vaultMetrics": "[HTTP link to vault metrics page, can be null]", - "vaultTos": "[HTTP link to vault ToS page, can be null]", - "vaultOperatorLearnMore": "[HTTP link to vault operator learn more page, can be null]", - "simpleTradeLearnMore": "[HTTP link to the simple trade learn more page, can be null]", - "governanceLearnMore": "[HTTP link to governance learn more, can be null]", - "newMarketProposalLearnMore": "[HTTP link to new market proposal learn more, can be null]", - "stakingLearnMore": "[HTTP link to staking learn more, can be null]", - "keplrDashboard": "[HTTP link to keplr dashboard, can be null]", - "strideZoneApp": "[HTTP link to stride zone app, can be null]", - "accountExportLearnMore": "[HTTP link to account export learn more, can be null]", - "adjustTargetLeverageLearnMore": "[HTTP link to adjust target leverage learn more, can be null]", - "walletLearnMore": "[HTTP link to wallet learn more, can be null]", - "withdrawalGateLearnMore": "[HTTP link to withdrawal gate learn more, can be null]", - "launchIncentive": "[HTTP link to launch incentive host, can be null]", - "tradingRewardsLearnMore": "[HTTP link to trading rewards learn more, can be null]", - "exchangeStats": "[HTTP link to exchange stats, can be null]", - "initialMarginFractionLearnMore": "[HTTP link to governance functionalities liquidity tiers, can be null]", - "equityTiersLearnMore": "[HTTP link to equity tiers learn more, can be null]", - "contractLossMechanismLearnMore": "[HTTP link to documentation on contract loss mechanisms]", - "isolatedMarginLearnMore": "[HTTP link to documentation on isolated margin]", - "mintscanValidatorsLearnMore": "[HTTP link to mintscan info on validators]", - "protocolStaking": "[HTTP link to protocol staking info]", - "stakingAndClaimingRewardsLearnMore": "[HTTP link to staking and claiming rewards learn more]", - "predictionMarketLearnMore": "[HTTP link to prediction market learn more]", - "discoveryProgram": "[HTTP link to discovery program learn more]", - "getInTouch": "[HTTP link to get in touch with traders]", - "deployerTermsAndConditions": "[HTTP link to terms and conditions, can be null]", - "dydxLearnMore": "[HTTP link to information about the dYdX blockchain]", - "affiliateProgram": "[HTTP link to information about the affiliate program]", - "affiliateProgramFaq": "[HTTP link to FAQ site about the affiliate program]", - "affiliateProgramSupportEmail": "[Email address for affiliate program customer support]", - "launchMarketTos": "[HTTP link to launch market ToS]", - "launchMarketLearnMore": "[HTTP link to launch market learn more]", - "incentiveProgram": "[HTTP link to incentive program, can be null]", - "incentiveProgramLeaderboard": "[HTTP link to incentive program leaderboard, can be null]" + "dydx-mainnet-1": { + "tos": "https://dydx.exchange/v4-terms", + "privacy": "https://dydx.trade/privacy", + "statusPage": "https://status.dydx.trade/", + "mintscan": "https://www.mintscan.io/dydx/tx/{tx_hash}", + "mintscanBase": "https://www.mintscan.io/dydx", + "feedback": "https://www.dydxopsdao.com/feedback", + "blogs": "https://www.dydx.foundation/blog", + "foundation": "https://www.dydx.foundation", + "reduceOnlyLearnMore": "https://help.dydx.trade/en/articles/166978-reduce-only-order", + "documentation": "https://docs.dydx.exchange/", + "community": "https://discord.com/invite/dydx", + "vipsChannel": "https://discord.com/channels/724804754382782534/1289241014460088351", + "help": "https://help.dydx.trade/", + "governanceLearnMore": "https://help.dydx.trade/en/articles/166989-governance-and-staking-on-keplr", + "vaultLearnMore": "https://help.dydx.trade/en/articles/240151-megavault-faq", + "vaultMetrics": "https://app.gauntlet.xyz/vaults/dydx:megavault", + "vaultTos": "https://dydx.trade/terms", + "vaultOperatorLearnMore": "https://dydx.forum/t/proposal-to-set-greave-as-the-dydx-megavault-operator/3129#p-6889-who-we-are-13", + "simpleTradeLearnMore": "https://help.dydx.trade/en/articles/273843-simplified-ui-on-ios", + "newMarketProposalLearnMore": "https://dydx.exchange/blog/new-market-proposals", + "stakingLearnMore": "https://help.dydx.trade/en/articles/166989-governance-and-staking-on-keplr", + "keplrDashboard": "https://wallet.keplr.app/chains/dydx?tab=staking", + "strideZoneApp": "https://app.stride.zone/?chain=DYDX", + "accountExportLearnMore": "https://help.dydx.trade/en/articles/166999-secret-phrase-on-dydx-chain", + "adjustTargetLeverageLearnMore": "https://help.dydx.trade/en/articles/172975-isolated-margin", + "walletLearnMore": "https://help.dydx.trade/en/articles/166997-supported-default-wallets-on-dydx-chain", + "withdrawalGateLearnMore": "https://help.dydx.trade/en/articles/166971-withdrawals-on-dydx-chain", + "launchIncentive": "https://cloud.chaoslabs.co", + "tradingRewardsLearnMore": "https://docs.dydx.exchange/concepts-trading/rewards_fees_and_parameters", + "exchangeStats": "https://app.mode.com/dydx_eng/reports/58822121650d?secret_key=391d9214fe6aefec35b7d35c", + "initialMarginFractionLearnMore": "https://docs.dydx.exchange/governance/functionalities#liquidity-tiers", + "equityTiersLearnMore": "https://help.dydx.trade/en/articles/171918-equity-tiers-and-rate-limits", + "contractLossMechanismLearnMore": "https://help.dydx.trade/en/articles/166973-contract-loss-mechanisms-on-dydx-chain", + "isolatedMarginLearnMore": "https://help.dydx.trade/en/articles/172975-isolated-margin", + "mintscanValidatorsLearnMore": "https://www.mintscan.io/dydx/validators", + "protocolStaking": "https://www.mintscan.io/dydx/dydx-analytics?sector=rewards", + "stakingAndClaimingRewardsLearnMore": "https://help.dydx.trade/en/articles/178571-staking-and-unstaking-dydx-and-claiming-staking-rewards", + "predictionMarketLearnMore": "https://help.dydx.trade/en/articles/221756-prediction-markets-faq", + "discoveryProgram": "https://www.dydx.foundation/blog/dydx-discovery-user-interviews?utm_source=dYdXTelegram&utm_medium=GlobalSocial&utm_campaign=GlobalSocial", + "getInTouch": "https://t.me/+amt-yoIUwDplN2I5", + "deployerTermsAndConditions": "https://dydx.trade/terms", + "dydxLearnMore": "https://www.mintscan.io/dydx", + "affiliateProgram": "https://dydx-affiliates.fuul.xyz", + "affiliateProgramFaq": "https://help.dydx.trade/en/articles/240149-affiliate-program-faq", + "affiliateProgramSupportEmail": "dydx@fuul.xyz", + "launchMarketTos": "https://dydx.trade/terms", + "launchMarketLearnMore": "https://help.dydx.trade/en/articles/240150-instant-market-listings-faq", + "incentiveProgram": "https://www.dydx.xyz/blog/dydx-surge", + "incentiveProgramLeaderboard": "https://community.chaoslabs.xyz/dydx-v4/risk/leaderboard" } }, "wallets": { @@ -288,45 +288,45 @@ "v2": { "projectId": "47559b2ec96c09aed9ff2cb54a31ab0e", "wallets": { - "ios": [ - "c57ca95b47569778a828d19178114f4db188b89b763c899ba0be274e97267d96", - "4622a2b2d6af1c9844944291e5e7351a6aa24cd7b23099efac1b2fd875da31a0", - "971e689d0a5be527bac79629b4ee9b925e82208e5168b733496a09c0faed0709", - "c03dfee351b6fcc421b4494ea33b9d4b92a984f87aa76d1663bb28705e95034a", - "1ae92b26df02f0abca6304df07debccd18262fdf5fe82daa81593582dac9a369", - "ecc4036f814562b41a5268adc86270fba1365471402006302e70169465b7ac18", - "c286eebc742a537cd1d6818363e9dc53b21759a1e8e5d9b263d0c03ec7703576", - "ef333840daf915aafdc4a004525502d6d49d77bd9c65e0642dbaefb3c2893bef", - "38f5d18bd8522c244bdd70cb4a68e0e718865155811c043f052fb9f1c51de662", - "0b415a746fb9ee99cce155c2ceca0c6f6061b1dbca2d722b3ba16381d0562150", - "15c8b91ade1a4e58f3ce4e7a0dd7f42b47db0c8df7e0d84f63eb39bcb96c4e0f", - "19177a98252e07ddfc9af2083ba8e07ef627cb6103467ffebb3f8f4205fd7927", - "344d0e58b139eb1b6da0c29ea71d52a8eace8b57897c6098cb9b46012665c193", - "225affb176778569276e484e1b92637ad061b01e13a048b35a9d280c3b58970f", - "f2436c67184f158d1beda5df53298ee84abfc367581e4505134b5bcf5f46697d", - "18450873727504ae9315a084fa7624b5297d2fe5880f0982979c17345a138277", - "541d5dcd4ede02f3afaf75bf8e3e4c4f1fb09edb5fa6c4377ebf31c2785d9adf" - ], - "android": [ - "c57ca95b47569778a828d19178114f4db188b89b763c899ba0be274e97267d96", - "4622a2b2d6af1c9844944291e5e7351a6aa24cd7b23099efac1b2fd875da31a0", - "971e689d0a5be527bac79629b4ee9b925e82208e5168b733496a09c0faed0709", - "c03dfee351b6fcc421b4494ea33b9d4b92a984f87aa76d1663bb28705e95034a", - "1ae92b26df02f0abca6304df07debccd18262fdf5fe82daa81593582dac9a369", - "ecc4036f814562b41a5268adc86270fba1365471402006302e70169465b7ac18", - "c286eebc742a537cd1d6818363e9dc53b21759a1e8e5d9b263d0c03ec7703576", - "ef333840daf915aafdc4a004525502d6d49d77bd9c65e0642dbaefb3c2893bef", - "38f5d18bd8522c244bdd70cb4a68e0e718865155811c043f052fb9f1c51de662", - "0b415a746fb9ee99cce155c2ceca0c6f6061b1dbca2d722b3ba16381d0562150", - "15c8b91ade1a4e58f3ce4e7a0dd7f42b47db0c8df7e0d84f63eb39bcb96c4e0f", - "19177a98252e07ddfc9af2083ba8e07ef627cb6103467ffebb3f8f4205fd7927", - "344d0e58b139eb1b6da0c29ea71d52a8eace8b57897c6098cb9b46012665c193", - "225affb176778569276e484e1b92637ad061b01e13a048b35a9d280c3b58970f", - "f2436c67184f158d1beda5df53298ee84abfc367581e4505134b5bcf5f46697d", - "18450873727504ae9315a084fa7624b5297d2fe5880f0982979c17345a138277", - "541d5dcd4ede02f3afaf75bf8e3e4c4f1fb09edb5fa6c4377ebf31c2785d9adf" - ] - } + "ios": [ + "c57ca95b47569778a828d19178114f4db188b89b763c899ba0be274e97267d96", + "4622a2b2d6af1c9844944291e5e7351a6aa24cd7b23099efac1b2fd875da31a0", + "971e689d0a5be527bac79629b4ee9b925e82208e5168b733496a09c0faed0709", + "c03dfee351b6fcc421b4494ea33b9d4b92a984f87aa76d1663bb28705e95034a", + "1ae92b26df02f0abca6304df07debccd18262fdf5fe82daa81593582dac9a369", + "ecc4036f814562b41a5268adc86270fba1365471402006302e70169465b7ac18", + "c286eebc742a537cd1d6818363e9dc53b21759a1e8e5d9b263d0c03ec7703576", + "ef333840daf915aafdc4a004525502d6d49d77bd9c65e0642dbaefb3c2893bef", + "38f5d18bd8522c244bdd70cb4a68e0e718865155811c043f052fb9f1c51de662", + "0b415a746fb9ee99cce155c2ceca0c6f6061b1dbca2d722b3ba16381d0562150", + "15c8b91ade1a4e58f3ce4e7a0dd7f42b47db0c8df7e0d84f63eb39bcb96c4e0f", + "19177a98252e07ddfc9af2083ba8e07ef627cb6103467ffebb3f8f4205fd7927", + "344d0e58b139eb1b6da0c29ea71d52a8eace8b57897c6098cb9b46012665c193", + "225affb176778569276e484e1b92637ad061b01e13a048b35a9d280c3b58970f", + "f2436c67184f158d1beda5df53298ee84abfc367581e4505134b5bcf5f46697d", + "18450873727504ae9315a084fa7624b5297d2fe5880f0982979c17345a138277", + "541d5dcd4ede02f3afaf75bf8e3e4c4f1fb09edb5fa6c4377ebf31c2785d9adf" + ], + "android": [ + "c57ca95b47569778a828d19178114f4db188b89b763c899ba0be274e97267d96", + "4622a2b2d6af1c9844944291e5e7351a6aa24cd7b23099efac1b2fd875da31a0", + "971e689d0a5be527bac79629b4ee9b925e82208e5168b733496a09c0faed0709", + "c03dfee351b6fcc421b4494ea33b9d4b92a984f87aa76d1663bb28705e95034a", + "1ae92b26df02f0abca6304df07debccd18262fdf5fe82daa81593582dac9a369", + "ecc4036f814562b41a5268adc86270fba1365471402006302e70169465b7ac18", + "c286eebc742a537cd1d6818363e9dc53b21759a1e8e5d9b263d0c03ec7703576", + "ef333840daf915aafdc4a004525502d6d49d77bd9c65e0642dbaefb3c2893bef", + "38f5d18bd8522c244bdd70cb4a68e0e718865155811c043f052fb9f1c51de662", + "0b415a746fb9ee99cce155c2ceca0c6f6061b1dbca2d722b3ba16381d0562150", + "15c8b91ade1a4e58f3ce4e7a0dd7f42b47db0c8df7e0d84f63eb39bcb96c4e0f", + "19177a98252e07ddfc9af2083ba8e07ef627cb6103467ffebb3f8f4205fd7927", + "344d0e58b139eb1b6da0c29ea71d52a8eace8b57897c6098cb9b46012665c193", + "225affb176778569276e484e1b92637ad061b01e13a048b35a9d280c3b58970f", + "f2436c67184f158d1beda5df53298ee84abfc367581e4505134b5bcf5f46697d", + "18450873727504ae9315a084fa7624b5297d2fe5880f0982979c17345a138277", + "541d5dcd4ede02f3afaf75bf8e3e4c4f1fb09edb5fa6c4377ebf31c2785d9adf" + ] + } } }, "walletSegue": { @@ -339,24 +339,46 @@ "signTypedDataAction": "dYdX Chain Onboarding", "signTypedDataDomainName": "dYdX Chain" }, - "[mainnet chain id]": { + "dydx-mainnet-1": { "walletconnect": { "client": { - "name": "[Name of the app]", - "description": "[Description of the app]", - "iconUrl": "[Relative URL of the icon URL]" + "name": "dYdX v4", + "description": "dYdX v4 App", + "iconUrl": "/logos/dydx-x.png" }, "v2": { - "projectId": "[Project ID]" + "projectId": "fd67e5fbec90c07b6012699738d4a487", + "wallets": { + "ios": [ + "c57ca95b47569778a828d19178114f4db188b89b763c899ba0be274e97267d96", + "4622a2b2d6af1c9844944291e5e7351a6aa24cd7b23099efac1b2fd875da31a0", + "971e689d0a5be527bac79629b4ee9b925e82208e5168b733496a09c0faed0709", + "c03dfee351b6fcc421b4494ea33b9d4b92a984f87aa76d1663bb28705e95034a", + "1ae92b26df02f0abca6304df07debccd18262fdf5fe82daa81593582dac9a369", + "ecc4036f814562b41a5268adc86270fba1365471402006302e70169465b7ac18", + "c286eebc742a537cd1d6818363e9dc53b21759a1e8e5d9b263d0c03ec7703576", + "38f5d18bd8522c244bdd70cb4a68e0e718865155811c043f052fb9f1c51de662" + ], + "android": [ + "c57ca95b47569778a828d19178114f4db188b89b763c899ba0be274e97267d96", + "4622a2b2d6af1c9844944291e5e7351a6aa24cd7b23099efac1b2fd875da31a0", + "971e689d0a5be527bac79629b4ee9b925e82208e5168b733496a09c0faed0709", + "c03dfee351b6fcc421b4494ea33b9d4b92a984f87aa76d1663bb28705e95034a", + "1ae92b26df02f0abca6304df07debccd18262fdf5fe82daa81593582dac9a369", + "ecc4036f814562b41a5268adc86270fba1365471402006302e70169465b7ac18", + "c286eebc742a537cd1d6818363e9dc53b21759a1e8e5d9b263d0c03ec7703576", + "38f5d18bd8522c244bdd70cb4a68e0e718865155811c043f052fb9f1c51de662" + ] + } } }, "walletSegue": { - "callbackUrl": "[Relative callback URL for WalletSegue, should match apple-app-site-association]" + "callbackUrl": "/walletsegue" }, "phantom": { - "callbackUrl": "[Relative callback URL for Phantom Wallet, should match apple-app-site-association]" + "callbackUrl": "/phantom" }, - "images": "[Relative URL for wallet images]", + "images": "/wallets/", "signTypedDataAction": "dYdX Chain Onboarding", "signTypedDataDomainName": "dYdX Chain" } @@ -376,11 +398,11 @@ "newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1zjkV9R7R_7KMItuzqzvKGwefSBRfE-ZNAx1LH55OcqY/edit?usp=sharing" } }, - "[mainnet chain id]": { + "dydx-mainnet-1": { "newMarketProposal": { - "initialDepositAmount": 0, - "delayBlocks": 0, - "newMarketsMethodology": "[URL to spreadsheet or document that explains methodology]" + "initialDepositAmount": 2000000000000000000000, + "delayBlocks": 3600, + "newMarketsMethodology": "https://docs.google.com/spreadsheets/d/1046uSR2sltA6siZGnvBlgUp4xlPNM7dPFvUgdACgTy4/edit?usp=sharing" } } }, @@ -706,7 +728,7 @@ "ios": { "minimalVersion": "1.0", "build": 40000, - "url": "https://apps.apple.com/app/dydx/id1564787350" + "url": "https://apps.apple.com/app/dydx/id6475599596" }, "android": { "minimalVersion": "1.1", @@ -766,7 +788,7 @@ } }, "dydxprotocol-testnet": { - "name": "v4 Public Testnet", + "name": "Testnet", "ethereumChainId": "11155111", "dydxChainId": "dydx-testnet-4", "chainName": "dYdX Chain", @@ -1064,47 +1086,89 @@ } }, "dydxprotocol-mainnet": { - "name": "v4", + "name": "Mainnet", "ethereumChainId": "1", - "dydxChainId": "[mainnet chain id]", + "dydxChainId": "dydx-mainnet-1", "chainName": "dYdX Chain", "chainLogo": "/dydx-chain.png", - "deployerName": "[deployer name]", + "deployerName": "dYdX Ops subDAO", "rewardsHistoryStartDateMs": "1706486400000", - "megavaultHistoryStartDateMs": "1704844800000", - "megavaultOperatorName": "Contoso Corporation", + "megavaultHistoryStartDateMs": "1731679200000", + "megavaultOperatorName": "Greave Cayman Limited", "isMainNet": true, "endpoints": { "indexers": [ { - "api": "[REST endpoint]", - "socket": "[Websocket endpoint]" + "api": "https://indexer.dydx.trade", + "socket": "wss://indexer.dydx.trade" } ], "validators": [ - "[Validator endpoint 1", - "[Validator endpoint n]" + "https://dydx-dao-rpc.polkachu.com", + "https://dydx-ops-rpc.kingnodes.com", + "https://dydx-dao-rpc.enigma-validator.com" ], - "skip": "[Skip endpoint for mainnet]", - "solanaRpcUrl": "[Solana rpc url for mainnet]", - "metadataService": "[metadata service endpoint for mainnet]", - "nobleValidator": "[noble validator endpoint for mainnet]", - "osmosisValidator": "[osmosis validator endpoint for mainnet]", - "neutronValidator": "[neutron validator endpoint for mainnet]", - "geo": "[geo endpoint for mainnet]", - "stakingAPR": "[staking APR endpoint for mainnet]", - "affiliates": "[affiliates endpoint for mainnet]" + "0xsquid": "https://api.squidrouter.com", + "metadataService": "https://66iv2m87ol.execute-api.ap-northeast-1.amazonaws.com/mainnet/metadata-service/v1", + "skip": "https://skip-proxy-web-mainnet.infrastructure-34d.workers.dev", + "nobleValidator": "https://noble-yx-rpc.polkachu.com/", + "geo": "https://api.dydx.exchange/v4/geo", + "stakingAPR": "https://apybara-proxy-web-mainnet.infrastructure-34d.workers.dev/v0/protocols/dydx", + "solanaRpcUrl": "https://alchemy-solana-proxy-web-mainnet.infrastructure-34d.workers.dev", + "osmosisValidator": "https://rpc.osmosis.zone", + "neutronValidator": "https://neutron-rpc.publicnode.com", + "affiliates": "https://dydx.fuul.xyz/v1" }, - "stakingValidators": [], + "ios": { + "minimalVersion": "1.9.0", + "build": 31081, + "url": "https://apps.apple.com/app/id6475599596" + }, + "android": { + "minimalVersion": "1.11.2", + "build": 59, + "url": "https://play.google.com/store/apps/details?id=trade.opsdao.dydxchain&pli=1" + }, + "apps": { + "ios": { + "minimalVersion": "1.9.0", + "build": 31081, + "url": "https://apps.apple.com/app/id6475599596" + }, + "android": { + "minimalVersion": "1.11.2", + "build": 59, + "url": "https://play.google.com/store/apps/details?id=trade.opsdao.dydxchain&pli=1" + } + }, + "stakingValidators": [ + "dydxvaloper15xgxv2j45uc4er8z9tfz5m0f0e74ymv6xj9l9d", + "dydxvaloper1cpz0jtj6rkezzs7z8k5gy6py05sxdkmyvggvvh", + "dydxvaloper199fjq4rnfvz24cktl8cervx8h8e90ruk3yrrdn", + "dydxvaloper1mwhwf9rqh64ktr8t8xnz37nhg7vvy42ec56jwe", + "dydxvaloper140l6y2gp3gxvay6qtn70re7z2s0gn57zq7tkd8", + "dydxvaloper1y6ncfxx8x9sqec97pehjw0k32slw63850ltjrn", + "dydxvaloper15wphegl8esn7r2rgj9j3xf870v78lxg8yfjn95", + "dydxvaloper1t8hjjca8kecjtuhs2qy83maurj78fq2z5c44z5", + "dydxvaloper1j4ljutnh66r55a29jydgca7pfmhd40e3nlcfa4" + ], "featureFlags": { - "checkForGeo": false, + "checkForGeo": true, + "reduceOnlySupported": true, + "usePessimisticCollateralCheck": false, + "useOptimisticCollateralCheck": true, "withdrawalSafetyEnabled": true, "CCTPWithdrawalOnly": true, - "CCTPDepositOnly": true, + "CCTPDepositOnly": false, "isSlTpEnabled": true, "isSlTpLimitOrdersEnabled": false } } }, - "restrictedLocales": [] -} + "restrictedLocales": [ + "pt", + "de", + "es", + "tr" + ] +} \ No newline at end of file diff --git a/public/dydx-banner.png b/public/dydx-banner.png new file mode 100644 index 0000000000..d5a523f1c6 Binary files /dev/null and b/public/dydx-banner.png differ diff --git a/scripts/README.md b/scripts/README.md index da6e36ec74..744914ffec 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -65,6 +65,8 @@ Service used for live customer support (chat/inbox) as well as home for Help Art 4. In your deploy scripts add `pnpm run build:inject-intercom` after your pnpm build / vite build command. 5. If you are using with the Amplitude deployment scripts, your build command may look like the following: `pnpm build && pnpm run build:inject-amplitude && pnpm run build:inject-intercom` +DOS is currently using a US workspace but is planning to migrate to the EU. We have introduced a temporary variable INTERCOM_API_BASE that will facilitate a smooth transition during the migration period. The plan after migration is to remove the variable and revert back to using a static definition with api_base set to 'https://api-iam.eu.intercom.io'. + ### Smartbanner Smartbanner to show download links to iOS and/or Android native apps on mobile devices. diff --git a/scripts/dos-build.sh b/scripts/dos-build.sh new file mode 100755 index 0000000000..c96d450272 --- /dev/null +++ b/scripts/dos-build.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +echo "Building (DOS)..." + +pnpm run build:set-last-commit-and-tag +pnpm run build:generate-entry-points +pnpm run build:generate-sitemap +tsc +vite build +pnpm run build:inject-app-deeplinks +pnpm run build:inject-analytics +pnpm run build:inject-intercom +pnpm run build:inject-statuspage +pnpm run build:inject-smartbanner +pnpm run build:inject-google-tag-manager diff --git a/scripts/generate-entry-points.js b/scripts/generate-entry-points.js index 609ed3c923..f6f904e259 100755 --- a/scripts/generate-entry-points.js +++ b/scripts/generate-entry-points.js @@ -7,26 +7,86 @@ const projectRoot = path.dirname(currentPath); const templateFilePath = path.resolve(projectRoot, '../template.html'); const entryPointsDir = path.resolve(projectRoot, '../entry-points'); +const TOP_MARKETS_URL = 'https://indexer.dydx.trade/v4/perpetualMarkets'; const ENTRY_POINTS = [ { - title: 'dYdX', - description: 'dYdX', + title: 'dYdX | Leading Decentralized Platform for Crypto Perpetual Trading', + description: 'Experience dYdX, DeFi\'s pro decentralized trading platform, offering secure, transparent, and powerful perpetual trading.', fileName: 'index.html', }, + { + title: 'dYdX Portfolio | Track Your Orders and Holdings Seamlessly', + description: 'Manage and review your portfolio on dYdX with real-time insights, balance updates, and performance analytics for informed trading decisions.', + fileName: 'portfolio.html', + }, + { + title: 'dYdX Markets | Explore BTC, ETH, SOL and 180 more Crypto Markets', + description: 'Access over 180 cryptocurrency markets on dYdX. Trade popular crypto pairs with competitive fees and robust security on our decentralized platform.', + fileName: 'markets.html', + }, + { + title: 'dYdX Trading Rewards | Earn $DYDX Tokens Through Trading & Staking', + description: 'Maximize your trading on dYdX and earn $DYDX token rewards. Engage with the platform, contribute to the liquidity, and get rewarded.', + fileName: 'trading-rewards.html', + }, + { + title: '$DYDX Dashboard | Track Your Surge Rewards & Trading History', + description: 'Stay on top of your dYdX Surge Points. Track real-time rewards, view detailed trading history, and monitor your performance throughout each season, all in one dashboard.', + fileName: 'dydx.html', + }, ]; try { - fs.mkdir(entryPointsDir, { recursive: true }); + console.log(`Fetching top markets from ${TOP_MARKETS_URL} ...`); + for (const market of await fetchTopMarkets(TOP_MARKETS_URL)) { + const marketNoUSD = market.replace('-USD', ''); + ENTRY_POINTS.push({ + title: `Trade ${marketNoUSD} on dYdX | DeFi's pro trading platform`, + description: `Engage in decentralized ${market} trading on dYdX, benefit from deep liquidity, self-custody, and advanced trading features.`, + fileName: `trade-${market}.html`, + }); + } + + await fs.mkdir(entryPointsDir, { recursive: true }); + console.log(`Generating entry points (${ENTRY_POINTS.length})...`); + const templateHtml = await fs.readFile(templateFilePath, 'utf-8'); for (const entryPoint of ENTRY_POINTS) { - const html = await fs.readFile(templateFilePath, 'utf-8'); const destinationFilePath = path.resolve(entryPointsDir, entryPoint.fileName); - const injectedHtml = html.replace( + const injectedHtml = templateHtml.replace( 'dYdX', `${entryPoint.title}\n ` ); await fs.writeFile(destinationFilePath, injectedHtml, 'utf-8'); } + console.log(`Done!`); } catch (err) { console.error('Error generating entry points:', err); } + +/** + * Fetches the top 100 trade pairs by volume from the dYdX indexer API + * @returns {Promise} Array of top trade pairs + * @throws {Error} If the API request fails + */ +async function fetchTopMarkets(url) { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const data = await response.json(); + + // Convert markets object to array of entries and sort by volume + const sortedMarkets = Object.entries(data.markets) + .sort((a, b) => { + const volumeA = parseFloat(a[1].volume24H); + const volumeB = parseFloat(b[1].volume24H); + return volumeB - volumeA; + }) + .slice(0, 100) // Take top 100 + .map(([_, market]) => { + return market.ticker; + }); + + return sortedMarkets; +} diff --git a/scripts/inject-intercom.js b/scripts/inject-intercom.js index f6442d9de0..251e815855 100644 --- a/scripts/inject-intercom.js +++ b/scripts/inject-intercom.js @@ -4,6 +4,7 @@ import path from 'path'; import { fileURLToPath } from 'url'; const INTERCOM_APP_ID = process.env.INTERCOM_APP_ID; +const INTERCOM_API_BASE = process.env.INTERCOM_API_BASE; const currentPath = fileURLToPath(import.meta.url); const projectRoot = path.dirname(currentPath); @@ -27,7 +28,7 @@ async function inject(fileName) { - - -
- - - + + + + + + + + dYdX + + + + + + + + + + + + + + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/vercel.json b/vercel.json index daa7ecd39e..4e443395db 100644 --- a/vercel.json +++ b/vercel.json @@ -1,8 +1,40 @@ { + "$schema": "https://openapi.vercel.sh/vercel.json", "rewrites": [ + { + "source": "/portfolio(/?.*)", + "destination": "/entry-points/portfolio.html" + }, + { + "source": "/markets(/?.*)", + "destination": "/entry-points/markets.html" + }, + { + "source": "/DYDX", + "destination": "/entry-points/dydx.html" + }, + { + "source": "/DYDX/trading-rewards(/?.*)", + "destination": "/entry-points/trading-rewards.html" + }, + { + "source": "/trade/([A-Z]+-USD)(/?.*)", + "destination": "/entry-points/trade-$1.html" + }, { "source": "/(.*)", "destination": "/entry-points/index.html" } + ], + "headers": [ + { + "source": "/(.*)", + "headers": [ + { + "key": "X-Frame-Options", + "value": "DENY" + } + ] + } ] -} \ No newline at end of file +}