Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix MV3 provider injection #3752

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
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
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
2 changes: 1 addition & 1 deletion background/features.ts
Original file line number Diff line number Diff line change
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 {
return window.localStorage.getItem(key) ?? ""
return "" // return window.localStorage.getItem(key) ?? ""
},
set(key: string, value: string): void {
window.localStorage.setItem(key, value)
// window.localStorage.setItem(key, value)
},
}

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"
}
}
117 changes: 82 additions & 35 deletions background/redux-slices/assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,55 +30,100 @@ const assetsSlice = createSlice({
reducers: {
assetsLoaded: (
immerState,
{ payload: newAssets }: { payload: AnyAsset[] },
) => {
const mappedAssets: { [sym: string]: SingleAssetState[] } = {}
// bin existing known assets
immerState.forEach((asset) => {
if (mappedAssets[asset.symbol] === undefined) {
mappedAssets[asset.symbol] = []
{
payload: { assets: newAssets, loadingScope },
}: {
payload: {
assets: AnyAsset[]
loadingScope: "all" | "network" | "incremental"
}
// if an asset is already in state, assume unique checks have been done
// no need to check network, contract address, etc
mappedAssets[asset.symbol].push(asset)
})
},
) => {
// For loading scope `network`, any network mentioned in `newAssets` is a
// complete set and thus should replace data currently in the store.
const networksToReset =
loadingScope === "network"
? newAssets.flatMap((asset) =>
"homeNetwork" in asset ? [asset.homeNetwork] : [],
)
: []

type AssetEntry = { asset: SingleAssetState; stateIndex: number }

const existingAssetEntriesBySymbol: {
[assetSymbol: string]: AssetEntry[]
} = {}

// If loadingScope is `all`, mappedAssets is left empty as the incoming
// asset list is comprehensive. Otherwise, bin existing known assets so
// their data can be updated.
if (loadingScope !== "all") {
immerState.forEach((asset, i) => {
existingAssetEntriesBySymbol[asset.symbol] ??= []

existingAssetEntriesBySymbol[asset.symbol].push({
asset,
stateIndex: i,
})
})
} else {
immerState.splice(0, immerState.length)
}

// merge in new assets
newAssets.forEach((newAsset) => {
if (mappedAssets[newAsset.symbol] === undefined) {
mappedAssets[newAsset.symbol] = [
{
...newAsset,
},
]
if (existingAssetEntriesBySymbol[newAsset.symbol] === undefined) {
// Unseen asset, add to the state.
immerState.push({ ...newAsset })
} else {
const duplicateIndexes = mappedAssets[newAsset.symbol].reduce<
number[]
>((acc, existingAsset, id) => {
if (isSameAsset(newAsset, existingAsset)) {
acc.push(id)
// We've got entries for the symbol, check for actual duplicates of
// the asset.
const duplicateIndexes = existingAssetEntriesBySymbol[
newAsset.symbol
].reduce<AssetEntry[]>((acc, existingAssetEntry) => {
if (isSameAsset(newAsset, existingAssetEntry.asset)) {
acc.push(existingAssetEntry)
}
return acc
}, [])

// if there aren't duplicates, add the asset
if (duplicateIndexes.length === 0) {
mappedAssets[newAsset.symbol].push({
...newAsset,
// If there aren't duplicates, add to the state.
immerState.push({ ...newAsset })
} else if (
"homeNetwork" in newAsset &&
networksToReset.some(
(network) => newAsset.homeNetwork.chainID === network.chainID,
)
) {
// If there are duplicates but the network is being reset, replace
// all the data at all duplicate indices, but not the objects
// themselves, so that diffing continues to identify the objects in
// the array as unchanged (though their properties might be).
//
// Do a property copy instead of an object replacement to maintain
// object identity for diffing purposes.
//
// NOTE: this doesn't delete properties!
duplicateIndexes.forEach(({ stateIndex }) => {
const existingAsset = immerState[stateIndex] as Record<
string,
unknown
>

Object.keys(newAsset).forEach((key) => {
existingAsset[key] = (newAsset as Record<string, unknown>)[key]
})
})
} else {
// TODO if there are duplicates... when should we replace assets?
duplicateIndexes.forEach((id) => {
// Update only the metadata for the duplicate
mappedAssets[newAsset.symbol][id] = {
...mappedAssets[newAsset.symbol][id],
metadata: newAsset.metadata,
}
// If there are duplicates but we aren't resetting the network,
// only update metadata.
duplicateIndexes.forEach(({ stateIndex }) => {
immerState[stateIndex].metadata = newAsset.metadata
})
}
}
})

return Object.values(mappedAssets).flat()
},
removeAsset: (
immerState,
Expand Down Expand Up @@ -118,7 +163,9 @@ export const refreshAsset = createBackgroundAsyncThunk(
{ dispatch },
) => {
// Update assets slice
await dispatch(assetsLoaded([asset]))
await dispatch(
assetsLoaded({ assets: [asset], loadingScope: "incremental" }),
)
// Update accounts slice cached data about this asset
await dispatch(updateAssetReferences(asset))
},
Expand Down
10 changes: 8 additions & 2 deletions background/redux-slices/tests/assets.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,19 @@ const pricesState: PricesState = {
describe("Reducers", () => {
describe("assetsLoaded", () => {
test("updates cached asset metadata", () => {
const state = reducer([], assetsLoaded([asset]))
const state = reducer(
[],
assetsLoaded({ assets: [asset], loadingScope: "incremental" }),
)

expect(state[0].metadata?.verified).not.toBeDefined()

const newState = reducer(
state,
assetsLoaded([{ ...asset, metadata: { verified: true } }]),
assetsLoaded({
assets: [{ ...asset, metadata: { verified: true } }],
loadingScope: "incremental",
}),
)

expect(newState[0].metadata?.verified).toBeTruthy()
Expand Down
6 changes: 3 additions & 3 deletions background/redux-slices/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import logger from "../lib/logger"
// FIXME: this utility file should not depend on actual services.
// Creating a properly typed version of `createBackgroundAsyncThunk`
// elsewhere has proven quite hard, so we are hardwiring typing here.
import type Main from "../main"
import type ReduxService from "../services/redux"

// Below, we use `any` to deal with the fact that allAliases is a heterogeneous
// collection of async thunk actions whose payload types have little in common
Expand Down Expand Up @@ -87,7 +87,7 @@ export type BackgroundAsyncThunk<
TypePrefix extends string,
Returned,
ThunkArg = void,
ThunkApiConfig extends AsyncThunkConfig = { extra: { main: Main } },
ThunkApiConfig extends AsyncThunkConfig = { extra: { main: ReduxService } },
> = ((
payload: ThunkArg,
) => BackgroundAsyncThunkAction<TypePrefix, Returned> & { payload: ThunkArg }) &
Expand Down Expand Up @@ -143,7 +143,7 @@ export function createBackgroundAsyncThunk<
TypePrefix extends string,
Returned,
ThunkArg = void,
ThunkApiConfig extends AsyncThunkConfig = { extra: { main: Main } },
ThunkApiConfig extends AsyncThunkConfig = { extra: { main: ReduxService } },
>(
typePrefix: TypePrefix,
payloadCreator: AsyncThunkPayloadCreator<Returned, ThunkArg, ThunkApiConfig>,
Expand Down
2 changes: 1 addition & 1 deletion background/redux-slices/utils/contract-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const internalProviderPort = {
removeEventListener(toRemove: (message: any) => unknown): void {
this.listeners = this.listeners.filter((listener) => listener !== toRemove)
},
origin: window.location.origin,
origin: window?.location?.origin ?? "service-worker",
postMessage(message: any): void {
this.emitter.emit("message", message)
},
Expand Down
4 changes: 2 additions & 2 deletions background/services/abilities/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ export default class AbilitiesService extends BaseService<Events> {
}

async fetchAbilities(): Promise<void> {
localStorage.setItem(this.ABILITY_TIME_KEY, Date.now().toString())
// localStorage.setItem(this.ABILITY_TIME_KEY, Date.now().toString())
const accountsToTrack = await this.chainService.getAccountsToTrack()
const addresses = new Set(
accountsToTrack.map((account) => normalizeEVMAddress(account.address)),
Expand All @@ -210,7 +210,7 @@ export default class AbilitiesService extends BaseService<Events> {
}

async refreshAbilities(): Promise<void> {
const lastFetchTime = localStorage.getItem(this.ABILITY_TIME_KEY)
const lastFetchTime = Date.now() // localStorage.getItem(this.ABILITY_TIME_KEY)

if (lastFetchTime && Number(lastFetchTime) + HOUR > Date.now()) {
return
Expand Down
13 changes: 13 additions & 0 deletions background/services/chain/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
toHexChainID,
NetworkBaseAsset,
sameChainID,
sameNetwork,
} from "../../networks"
import {
AnyAssetAmount,
Expand Down Expand Up @@ -1262,6 +1263,18 @@ export default class ChainService extends BaseService<Events> {
address,
network,
}: AddressOnNetwork): Promise<void> {
// If we find ourselves having untracked this account for some reason and
// there's activity on it, track it.
if (
!(await this.getAccountsToTrack(false)).some(
(account) =>
sameEVMAddress(account.address, address) &&
sameNetwork(account.network, network),
)
) {
await this.addAccountToTrack({ address, network })
}

const addressWasInactive = this.addressIsInactive(address)
const networkWasInactive = this.networkIsInactive(network.chainID)
this.markNetworkActivity(network.chainID)
Expand Down
1 change: 0 additions & 1 deletion background/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ export { default as LedgerService } from "./ledger"
export { default as SigningService } from "./signing"
export { default as AnalyticsService } from "./analytics"
export { default as NFTsService } from "./nfts"
export { default as WalletConnectService } from "./wallet-connect"

export function getNoopService<T>(): T {
return Promise.resolve({
Expand Down
Loading
Loading