Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 10 additions & 6 deletions .github/workflows/deploy_vercel.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ jobs:
if: "github.event_name == 'workflow_dispatch' && github.event.inputs.release == 'production'"
runs-on: ubuntu-latest
steps:
- uses: actions/setup-node@v3
- uses: actions/setup-node@v6
with:
node-version: 20
- uses: actions/checkout@v3
node-version: 24
- uses: actions/checkout@v6
with:
persist-credentials: false
fetch-depth: 0
Expand All @@ -48,11 +48,15 @@ jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 20
node-version: 24
cache: yarn
- name: Enable Yarn
run: corepack enable
- name: Verify Node.js version
run: node --version
- run: yarn install --immutable
- run: yarn vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
- run: yarn vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}
Expand Down
9 changes: 6 additions & 3 deletions .github/workflows/jest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@ jobs:

steps:
- name: Check out Git repository
uses: actions/checkout@v3
uses: actions/checkout@v6

- name: Set up Node
uses: actions/setup-node@v3
uses: actions/setup-node@v6
with:
node-version: 20
node-version: 24

- name: Enable Yarn
run: corepack enable

- name: Install dependencies
run: yarn install --immutable
Expand Down
24 changes: 7 additions & 17 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,19 @@ jobs:

steps:
- name: Check out Git repository
uses: actions/checkout@v2
uses: actions/checkout@v6

- name: Set up node
uses: actions/setup-node@v1
uses: actions/setup-node@v6
with:
node-version: 12
always-auth: true
registry-url: https://registry.npmjs.org
node-version: 24
cache: yarn

- name: Set output of cache
id: yarn-cache
run: echo "::set-output name=dir::$(yarn cache dir)"

- name: Node dependency cache
uses: actions/cache@v1
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
yarn-
- name: Enable Yarn
run: corepack enable

- name: Install dependencies
run: yarn install --frozen-lockfile
run: yarn install --immutable

- name: Run linters
uses: wearerequired/lint-action@77d70b9a07ecb93bc98dc46dc27d96c4f004d035
Expand Down
16 changes: 10 additions & 6 deletions .github/workflows/preview_vercel.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ jobs:
if: "github.event_name == 'workflow_dispatch' && github.event.inputs.release == 'qa'"
runs-on: ubuntu-latest
steps:
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
node-version: 20
- uses: actions/checkout@v4
node-version: 24
- uses: actions/checkout@v6
with:
persist-credentials: false
fetch-depth: 0
Expand All @@ -57,13 +57,17 @@ jobs:
name: preview
url: ${{ steps.deploy.outputs.url }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha || github.ref }}
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
node-version: 20
node-version: 24
cache: yarn
- name: Enable Yarn
run: corepack enable
- name: Verify Node.js version
run: node --version
- run: yarn install --immutable
- id: check_branch
run: echo "::set-output name=branch::$(if [[ "${{ github.ref }}" == *"/staging" ]]; then echo 'staging'; else echo 'master'; fi)"
Expand Down
48 changes: 15 additions & 33 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,18 @@ on:
jobs:
integration-tests:
name: Integration tests
runs-on: ubuntu-16.04
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v1
- uses: actions/setup-node@v1
uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: '12'
always-auth: true
registry-url: https://registry.npmjs.org
node-version: 24
cache: yarn

- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/cache@v1
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- run: yarn install --frozen-lockfile
- name: Enable Yarn
run: corepack enable
- run: yarn install --immutable
- run: yarn cypress install
- run: yarn build
env:
Expand All @@ -43,23 +34,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v1
- uses: actions/setup-node@v1
uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: '12'
always-auth: true
registry-url: https://registry.npmjs.org
node-version: 24
cache: yarn

- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/cache@v1
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- run: yarn install --frozen-lockfile
- name: Enable Yarn
run: corepack enable
- run: yarn install --immutable
- run: yarn test

1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
24
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,13 @@ https://cocky-dubinsky-430a6c.netlify.app/

### Install Dependencies

Use Node.js 24 and the repository-pinned Yarn 3.6.1.

```bash
yarn
nvm install
nvm use
corepack enable
yarn install --immutable
```

### Run
Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -213,10 +213,10 @@
},
"dependencies": {
"@babel/runtime": "^7.18.9",
"@gooddollar/good-design": "file:temp-packages/@gooddollar-good-design-0.4.52.tgz",
"@gooddollar/good-design": "file:.yalc/@gooddollar/good-design",
"@gooddollar/goodprotocol": "2.2.1",
"@gooddollar/web3sdk": "0.1.59",
"@gooddollar/web3sdk-v2": "file:temp-packages/@gooddollar-web3sdk-v2-0.4.48.tgz",
"@gooddollar/web3sdk-v2": "file:.yalc/@gooddollar/web3sdk-v2",
"@goodsdks/savings-widget": "^1.0.0",
"@headlessui/react": "1.5.0",
"@lingui/format-json": "^4.0.0",
Expand Down Expand Up @@ -257,6 +257,9 @@
"wagmi": "^2.14.13",
"web3": "1.8.2"
},
"engines": {
"node": "24.x"
},
"packageManager": "yarn@3.6.1",
"jest": {
"testEnvironment": "jsdom",
Expand Down
25 changes: 1 addition & 24 deletions src/components/Modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import '@reach/dialog/styles.css'
import { transparentize } from 'polished'
import React from 'react'
import { isMobile } from 'react-device-detect'
import { animated, useSpring, useTransition } from 'react-spring'
import { useGesture } from 'react-use-gesture'
import { animated, useTransition } from 'react-spring'
import styled, { css } from 'styled-components'

const AnimatedDialogOverlay = animated(DialogOverlay)
Expand Down Expand Up @@ -115,18 +114,6 @@ export default function Modal({
leave: { opacity: 0 },
})

const [{ y }, set] = useSpring(() => ({ y: 0, config: { mass: 1, tension: 210, friction: 20 } }))
const bind = useGesture({
onDrag: (state) => {
set({
y: state.down ? state.movement[1] : 0,
})
if (state.movement[1] > 300 || (state.velocity > 3 && state.direction[1] > 0)) {
onDismiss()
}
},
})

return (
<>
{fadeTransition.map(
Expand All @@ -139,16 +126,6 @@ export default function Modal({
initialFocusRef={initialFocusRef}
>
<StyledDialogContent
{...(isMobile
? {
...bind(),
style: {
transform: y.interpolate(
(y) => `translateY(${(y as number) > 0 ? y : 0}px)`
),
},
}
: {})}
aria-label="dialog content"
minHeight={minHeight}
maxHeight={maxHeight}
Expand Down
40 changes: 40 additions & 0 deletions src/functions/rpcParsing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,44 @@ describe('rpcParsing', () => {
'50': ['https://rpc.xinfin.network'],
})
})
it('filters discovered RPCs before they can be probed', async () => {
process.env.REACT_APP_EXCLUDED_RPCS = ' RPC.FUSE.IO, 1rpc.io '
jest.spyOn(global, 'fetch').mockResolvedValue({
ok: true,
json: async () => CHAINLIST_RPCS_SOURCE,
} as Response)
const { fetchRpcsFromChainlist } = await import('./rpcParsing')
const urls = await fetchRpcsFromChainlist()
expect(urls['122']).toEqual(['https://fuse.drpc.org'])
expect(urls['1']).toEqual(['https://eth.llamarpc.com'])
expect(global.fetch).toHaveBeenCalledTimes(1)
})

it('filters configured and default fallbacks without reintroducing excluded URLs', async () => {
process.env.REACT_APP_EXCLUDED_RPCS = 'blocked.example, rpc.fuse.io'
process.env.REACT_APP_CELO_RPC = 'https://blocked.example/celo, https://allowed.example/celo'
const { getFallbackRpcsByChain } = await import('./rpcParsing')
expect(getFallbackRpcsByChain()['122']).toEqual([])
expect(getFallbackRpcsByChain()['42220']).toEqual(['https://allowed.example/celo'])
})

it('applies the same case-insensitive substring rules to cached URLs and removes duplicates', async () => {
const { filterExcludedRpcs } = await import('./rpcParsing')
expect(
filterExcludedRpcs(
[
'https://node.example/a',
'https://NODE.example/b',
' https://allowed.example/rpc ',
'https://allowed.example/rpc',
],
{ REACT_APP_EXCLUDED_RPCS: ' NODE.EXAMPLE, , ' }
)
).toEqual(['https://allowed.example/rpc'])
expect(
filterExcludedRpcs(['https://node.example/a', 'https://node.example/b'], {
REACT_APP_EXCLUDED_RPCS: 'https://node.example/a',
})
).toEqual(['https://node.example/b'])
})
})
20 changes: 17 additions & 3 deletions src/functions/rpcParsing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,18 @@ const ENV_RPC_KEYS_BY_CHAIN: Record<SupportedChainId, string> = {
'50': 'REACT_APP_XDC_RPC',
}

// Case-insensitive URL substrings: a hostname blocks every matching path on that host.
export function filterExcludedRpcs(urls: string[], env: Env = process.env): string[] {
const excluded = (env.REACT_APP_EXCLUDED_RPCS ?? '')
.split(',')
.map((value) => value.trim().toLowerCase())
.filter(Boolean)

return [...new Set(urls.map((url) => url.trim()).filter(Boolean))].filter(
(url) => !excluded.some((blocked) => url.toLowerCase().includes(blocked))
)
}

function normalizeRpcUrls(rpcs: ChainlistRpc[] = []): string[] {
return rpcs
.map((rpc) => rpc.url?.trim())
Expand All @@ -44,12 +56,14 @@ export function getFallbackRpcsByChain(env: Env = process.env): Record<Supported
.map((rpc) => rpc.trim())
.filter((rpc) => rpc.startsWith('http://') || rpc.startsWith('https://'))

result[chainId] =
result[chainId] = filterExcludedRpcs(
enabledFallbackChains.has(chainId) && configuredRpcs.length > 0
? configuredRpcs
: enabledFallbackChains.has(chainId)
? DEFAULT_FALLBACK_RPCS_BY_CHAIN[chainId]
: []
: [],
env
)

return result
}, {} as Record<SupportedChainId, string[]>)
Expand All @@ -63,7 +77,7 @@ export async function fetchRpcsFromChainlist(): Promise<Record<string, string[]>
const chainsById = new Map(chains.map((chain) => [String(chain.chainId), chain]))

return SUPPORTED_CHAIN_IDS.reduce<Record<string, string[]>>((result, chainId) => {
result[chainId] = normalizeRpcUrls(chainsById.get(chainId)?.rpc)
result[chainId] = filterExcludedRpcs(normalizeRpcUrls(chainsById.get(chainId)?.rpc))
return result
}, {})
}
Loading
Loading