Skip to content

Commit

Permalink
Redux Redux: A few QOL fixes + Manifest v3 (#3757)
Browse files Browse the repository at this point in the history
Sundry:
- Manifest v3 support by moving window provider to an injected content
script instead of the previous injection (h/t @hyphenized) as well as a
version bump on webext-redux and a variety of other small changes to
deal with related dependency updates.
- Improved logging details across the board.
- Common address copying logic.
- Added Open in Explorer to the account popup menu in the account
slideover.
- Main is refactored to ReduxService, with store logic in its own file.
- Support for certain invocations of wallet_requestPermissions, the lack
of which was breaking some sites.
- Fixes for tracking networks that were marked as inactive but were
reactivated.
- Improvements for fallback behavior that was unnecessarily retrying
connections.
- Fixes for RPC batching to avoid issues with excessive batch sizes.
- Improved redux store performance for certain actions that can be
batched.
- Fixes #3397.

Latest build:
[extension-builds-3757](https://github.com/tahowallet/extension/suites/32443165539/artifacts/2362331963)
(as of Thu, 26 Dec 2024 02:45:08 GMT).
  • Loading branch information
mhluongo authored Dec 27, 2024
2 parents c91a9ef + 7eaefad commit 804ff05
Show file tree
Hide file tree
Showing 71 changed files with 1,428 additions and 2,292 deletions.
10 changes: 5 additions & 5 deletions .env.defaults
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,18 @@ POSTHOG_API_KEY="phc_VzveyNxrn2xyiKDYn7XjrgaqELGeUilDZGiBVh6jNmh"
POSTHOG_PERSONAL_API_KEY="phx_pE7GvpSzv207stzDwDqUOMfg8SzNzojzaFLrSdwKWE9"
USE_ANALYTICS_SOURCE="DEV"
POAP_API_KEY="Djq0jJrWaQCzzvvoTqy0BgFidzy4bugDX1mTY28EZpqcUDSNICLcVQnex2wY7D9t5QB2aQlPQRdw8GiOVcE5kgQywGiDraJDfd3GVxnDASm1PoRBjOBh9fOrgymNsMQc"
HIDE_TOKEN_FEATURES=true
HIDE_IMPORT_DERIVATION_PATH=true
HIDE_SWAP_REWARDS=true
SHOW_TOKEN_FEATURES=false
SHOW_IMPORT_DERIVATION_PATH=false
SHOW_SWAP_REWARDS=false
SUPPORT_WALLET_CONNECT=false
SUPPORT_CUSTOM_RPCS=false
SUPPORT_MULTIPLE_LANGUAGES=false
SUPPORT_ARBITRUM_NOVA=false
SUPPORT_SWAP_QUOTE_REFRESH=false
SUPPORT_ACHIEVEMENTS_BANNER=false
SUPPORT_NFT_SEND=false
HIDE_ISLAND_UI=true
SUPPORT_THE_ISLAND=true
SHOW_ISLAND_UI=false
SUPPORT_THE_ISLAND=false
SUPPORT_THE_ISLAND_ON_TENDERLY=false
USE_MAINNET_FORK=false
ARBITRUM_FORK_RPC=https://rpc.tenderly.co/fork/2fc2cf12-5c58-439f-9b5e-967bfd02191a
Expand Down
2 changes: 1 addition & 1 deletion babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module.exports = {
"@babel/env",
{
targets: {
browsers: ["chrome >= 90", "firefox >= 89"],
browsers: ["chrome >= 107", "firefox >= 107"],
},
},
],
Expand Down
2 changes: 2 additions & 0 deletions background/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export const STATE_KEY = "tally"

export const POPUP_MONITOR_PORT_NAME = "popup-monitor"

export const NETWORK_TYPES = {
ethereum: "ethereum",
}
Expand Down
12 changes: 6 additions & 6 deletions background/features.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ const BuildTimeFlag = {
*/
export const RuntimeFlag = {
USE_MAINNET_FORK: process.env.USE_MAINNET_FORK === "true",
HIDE_IMPORT_DERIVATION_PATH:
process.env.HIDE_IMPORT_DERIVATION_PATH === "true",
HIDE_SWAP_REWARDS: process.env.HIDE_SWAP_REWARDS === "true",
SHOW_IMPORT_DERIVATION_PATH:
process.env.SHOW_IMPORT_DERIVATION_PATH === "true",
SHOW_SWAP_REWARDS: process.env.SHOW_SWAP_REWARDS === "true",
SUPPORT_MULTIPLE_LANGUAGES: process.env.SUPPORT_MULTIPLE_LANGUAGES === "true",
HIDE_TOKEN_FEATURES: process.env.HIDE_TOKEN_FEATURES === "true",
SHOW_TOKEN_FEATURES: process.env.SHOW_TOKEN_FEATURES === "true",
SUPPORT_ARBITRUM_NOVA: process.env.SUPPORT_ARBITRUM_NOVA === "true",
SUPPORT_ACHIEVEMENTS_BANNER:
process.env.SUPPORT_ACHIEVEMENTS_BANNER === "true",
Expand All @@ -23,7 +23,7 @@ export const RuntimeFlag = {
SUPPORT_SWAP_QUOTE_REFRESH: process.env.SUPPORT_SWAP_QUOTE_REFRESH === "true",
SUPPORT_CUSTOM_NETWORKS: process.env.SUPPORT_CUSTOM_NETWORKS === "true",
SUPPORT_CUSTOM_RPCS: process.env.SUPPORT_CUSTOM_RPCS === "true",
HIDE_ISLAND_UI: process.env.HIDE_ISLAND_UI === "true",
SHOW_ISLAND_UI: process.env.SHOW_ISLAND_UI === "true",
SUPPORT_THE_ISLAND: process.env.SUPPORT_THE_ISLAND === "true",
SUPPORT_THE_ISLAND_ON_TENDERLY:
process.env.SUPPORT_THE_ISLAND_ON_TENDERLY === "true",
Expand Down Expand Up @@ -73,7 +73,7 @@ export function isEnabled(
}

if (checkBrowserStorage) {
const state = localStorage.getItem(flagName)
const state = "" as string // localStorage.getItem(flagName)
return state !== null ? state === "true" : RuntimeFlag[flagName]
}

Expand Down
16 changes: 8 additions & 8 deletions background/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { Store as ProxyStore } from "webext-redux"
import { produce } from "immer"
import { Action, AnyAction, ThunkAction, ThunkDispatch } from "@reduxjs/toolkit"

import { Delta, patch as patchDeepDiff } from "./differ"
import Main from "./main"
import { Delta, patch as patchDeepDiff } from "./services/redux/differ"
import ReduxService from "./services/redux"
import { encodeJSON, decodeJSON } from "./lib/utils"

import { RootState } from "./redux-slices"
Expand Down Expand Up @@ -46,7 +46,7 @@ type BackgroundAsyncThunkDispatchify<T> = T extends ThunkDispatch<
: never

export type BackgroundDispatch = BackgroundAsyncThunkDispatchify<
Main["store"]["dispatch"]
ReduxService["store"]["dispatch"]
>

/**
Expand Down Expand Up @@ -82,12 +82,12 @@ export async function newProxyStore(): Promise<
}

/**
* Starts the API subsystems, including all services.
* Starts the Redux subsystems, including all services.
*/
export async function startMain(): Promise<Main> {
const mainService = await Main.create()
export async function startRedux(): Promise<ReduxService> {
const reduxService = await ReduxService.create()

mainService.startService()
reduxService.startService()

return mainService.started()
return reduxService.started()
}
4 changes: 2 additions & 2 deletions background/lib/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ const HOUR = 1000 * 60 * 60

const store = {
get(key: string): string {

Check failure on line 8 in background/lib/logger.ts

View workflow job for this annotation

GitHub Actions / lint

'key' is defined but never used. Allowed unused args must match /^_+$/u
return window.localStorage.getItem(key) ?? ""
return "" // return window.localStorage.getItem(key) ?? ""
},
set(key: string, value: string): void {

Check failure on line 11 in background/lib/logger.ts

View workflow job for this annotation

GitHub Actions / lint

'key' is defined but never used. Allowed unused args must match /^_+$/u

Check failure on line 11 in background/lib/logger.ts

View workflow job for this annotation

GitHub Actions / lint

'value' is defined but never used. Allowed unused args must match /^_+$/u
window.localStorage.setItem(key, value)
// window.localStorage.setItem(key, value)
},
}

Expand Down
3 changes: 2 additions & 1 deletion background/lib/posthog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ export function createPosthogPayload(
$lib: USE_ANALYTICS_SOURCE,
// properties[$current_url] is a convention used by posthog
// Let's store the URL so we can differentiate between the sources later on.
$current_url: window.location.href,
$current_url:
typeof window !== "undefined" ? window.location.href : "service-worker",
// Let's also send in anything that we might send with the event. Eg time
...payload,
},
Expand Down
28 changes: 28 additions & 0 deletions background/lib/priceOracle.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as ethers from "ethers"
import { Fragment, FunctionFragment } from "ethers/lib/utils"
import _ from "lodash"
import {
AnyAsset,
FungibleAsset,
Expand Down Expand Up @@ -30,6 +31,12 @@ import {
import { toFixedPoint } from "./fixed-point"
import SerialFallbackProvider from "../services/chain/serial-fallback-provider"
import { EVMNetwork } from "../networks"
import logger from "./logger"

// The size of a batch of on-chain price lookups. Too high and the request will
// fail due to running out of gas, as eth_call is still subject to gas limits.
// Too low and we will make additional unnecessary RPC requests.
const BATCH_SIZE = 20

// Oracle Documentation and Address references can be found
// at https://docs.1inch.io/docs/spot-price-aggregator/introduction/
Expand Down Expand Up @@ -213,6 +220,27 @@ export async function getUSDPriceForTokens(
): Promise<{
[contractAddress: string]: UnitPricePoint<FungibleAsset>
}> {
if (assets.length > BATCH_SIZE) {
logger.debug(
"Batching assets price lookup by length",
assets.length,
BATCH_SIZE,
)
// Batch assets when we get to BATCH_SIZE so we're not trying to construct
// megatransactions with 10s and 100s of assets that blow up RPC nodes.
return (
await Promise.all(
_.range(0, assets.length / BATCH_SIZE)
.map((batch) =>
assets.slice(0 + batch * BATCH_SIZE, batch * BATCH_SIZE),
)
.map((subAssets) =>
getUSDPriceForTokens(subAssets, network, provider),
),
)
).reduce((allPrices, pricesSubset) => ({ ...allPrices, ...pricesSubset }))
}

const tokenRates = await getRatesForTokens(assets, provider, network)

const pricePoints: {
Expand Down
2 changes: 1 addition & 1 deletion background/lib/prices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ export async function getTokenPrices(
})
} catch (err) {
logger.error(
"Error fetching price for tokens on network.",
"Error fetching price for tokens on network from Coingecko",
tokenAddresses,
network,
err,
Expand Down
8 changes: 6 additions & 2 deletions background/lib/token-lists.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,12 @@ export function mergeAssets<T extends FungibleAsset>(
metadata: {
...matchingAsset.metadata,
...asset.metadata,
tokenLists: (matchingAsset.metadata?.tokenLists || [])?.concat(
asset.metadata?.tokenLists ?? [],
tokenLists: Array.from(
new Set(
(matchingAsset.metadata?.tokenLists || [])?.concat(
asset.metadata?.tokenLists ?? [],
),
).values(),
),
},
}
Expand Down
6 changes: 3 additions & 3 deletions background/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,14 @@
"siwe": "^1.1.0",
"util": "^0.12.4",
"uuid": "^9.0.0",
"webextension-polyfill": "^0.8.0"
"webextension-polyfill": "^0.12.0"
},
"devDependencies": {
"@reduxjs/toolkit": "^1.9.4",
"@types/argon2-browser": "^1.18.1",
"@types/sinon": "^10.0.12",
"@types/uuid": "^8.3.4",
"@types/webextension-polyfill": "^0.8.0",
"@types/webextension-polyfill": "^0.12.0",
"@walletconnect/legacy-types": "^2.0.0",
"@walletconnect/types": "^2.7.7",
"crypto-browserify": "^3.12.0",
Expand All @@ -81,6 +81,6 @@
"redux": "^4.1.1",
"sqlite3": "5.1.1",
"ts-node": "^10.4.0",
"webext-redux": "^2.1.7"
"webext-redux": "^4.0.0"
}
}
49 changes: 32 additions & 17 deletions background/redux-slices/accounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,24 +422,39 @@ const accountSlice = createSlice({
*/
updateAssetReferences: (
immerState,
{ payload: asset }: { payload: SmartContractFungibleAsset },
{ payload: assets }: { payload: SmartContractFungibleAsset[] },
) => {
const allAccounts = immerState.accountsData.evm[asset.homeNetwork.chainID]
Object.keys(allAccounts ?? {}).forEach((address) => {
const account = allAccounts[address]
if (account !== "loading") {
Object.values(account.balances).forEach(({ assetAmount }) => {
if (
isSmartContractFungibleAsset(assetAmount.asset) &&
sameEVMAddress(
assetAmount.asset.contractAddress,
asset.contractAddress,
)
) {
Object.assign(assetAmount.asset, asset)
}
})
}
const assetsByChainID: {
[chainID: string]: SmartContractFungibleAsset[]
} = {}
assets.forEach((asset) => {
assetsByChainID[asset.homeNetwork.chainID] ??= []
assetsByChainID[asset.homeNetwork.chainID].push(asset)
})

Object.keys(assetsByChainID).forEach((chainID) => {
const allAccounts = immerState.accountsData.evm[chainID]
Object.keys(allAccounts ?? {}).forEach((address) => {
const account = allAccounts[address]
if (account !== "loading") {
assetsByChainID[chainID].forEach((asset) => {
const { assetAmount } = account.balances[
getFullAssetID(asset)
] ?? { assetAmount: undefined }

if (
assetAmount &&
isSmartContractFungibleAsset(assetAmount.asset) &&
sameEVMAddress(
assetAmount.asset.contractAddress,
asset.contractAddress,
)
) {
Object.assign(assetAmount.asset, asset)
}
})
}
})
})

updateCombinedData(immerState)
Expand Down
Loading

0 comments on commit 804ff05

Please sign in to comment.