Skip to content

Commit

Permalink
Add basic tests and fix issues for adding an asset
Browse files Browse the repository at this point in the history
  • Loading branch information
Karolina Kosiorowska committed Jun 23, 2023
1 parent ee820f5 commit 12dce07
Show file tree
Hide file tree
Showing 3 changed files with 190 additions and 53 deletions.
58 changes: 5 additions & 53 deletions background/services/indexing/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@ import {
normalizeEVMAddress,
sameEVMAddress,
} from "../../lib/utils"
import { isVerifiedAsset } from "../../redux-slices/utils/asset-utils"
import {
getActiveAssetsByAddressForNetwork,
getAssetsByAddress,
shouldRefreshKnownAsset,
} from "./utils"

// Transactions seen within this many blocks of the chain tip will schedule a
// token refresh sooner than the standard rate.
Expand Down Expand Up @@ -76,58 +80,6 @@ interface Events extends ServiceLifecycleEvents {
removeAssetData: SmartContractFungibleAsset
}

const getAssetsByAddress = (assets: SmartContractFungibleAsset[]) => {
const activeAssetsByAddress = assets.reduce((agg, t) => {
const newAgg = {
...agg,
}
newAgg[t.contractAddress.toLowerCase()] = t
return newAgg
}, {} as { [address: string]: SmartContractFungibleAsset })

return activeAssetsByAddress
}

const getActiveAssetsByAddressForNetwork = (
network: EVMNetwork,
activeAssetsToTrack: SmartContractFungibleAsset[]
) => {
const networkActiveAssets = activeAssetsToTrack.filter(
(asset) => asset.homeNetwork.chainID === network.chainID
)

return getAssetsByAddress(networkActiveAssets)
}

function shouldRefreshKnownAsset(
asset: SmartContractFungibleAsset,
metadata: {
discoveryTxHash?: {
[address: HexString]: HexString
}
verified?: boolean
}
): boolean {
const newDiscoveryTxHash = metadata?.discoveryTxHash
const addressForDiscoveryTxHash = newDiscoveryTxHash
? Object.keys(newDiscoveryTxHash)[0]
: undefined
const existingDiscoveryTxHash = addressForDiscoveryTxHash
? asset.metadata?.discoveryTxHash?.[addressForDiscoveryTxHash]
: undefined

// If a known asset does not yet have a tx detection hash, update it.
const noExistingDiscoveryTxHash = !existingDiscoveryTxHash

// Refresh a known unverified asset if it has been manually imported.
// This check allows the user to add an asset from the unverified list.
const isManuallyImported = metadata?.verified
const allowUpdateUnverifiedAsset =
!isVerifiedAsset(asset) && isManuallyImported

return allowUpdateUnverifiedAsset || noExistingDiscoveryTxHash
}

/**
* IndexingService is responsible for pulling and maintaining all application-
* level "indexing" data — things like fungible token balances and NFTs, as well
Expand Down
70 changes: 70 additions & 0 deletions background/services/indexing/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { SmartContractFungibleAsset } from "../../../assets"
import { EVMNetwork } from "../../../networks"
import {
isUntrustedAsset,
isVerifiedAsset,
} from "../../../redux-slices/utils/asset-utils"
import { HexString } from "../../../types"

export const getAssetsByAddress = (
assets: SmartContractFungibleAsset[]
): {
[address: string]: SmartContractFungibleAsset
} => {
const activeAssetsByAddress = assets.reduce((agg, t) => {
const newAgg = {
...agg,
}
newAgg[t.contractAddress.toLowerCase()] = t
return newAgg
}, {} as { [address: string]: SmartContractFungibleAsset })

return activeAssetsByAddress
}

export const getActiveAssetsByAddressForNetwork = (
network: EVMNetwork,
activeAssetsToTrack: SmartContractFungibleAsset[]
): {
[address: string]: SmartContractFungibleAsset
} => {
const networkActiveAssets = activeAssetsToTrack.filter(
(asset) => asset.homeNetwork.chainID === network.chainID
)

return getAssetsByAddress(networkActiveAssets)
}

export function shouldRefreshKnownAsset(
asset: SmartContractFungibleAsset,
metadata: {
discoveryTxHash?: {
[address: HexString]: HexString
}
verified?: boolean
}
): boolean {
const newDiscoveryTxHash = metadata?.discoveryTxHash
const addressForDiscoveryTxHash = newDiscoveryTxHash
? Object.keys(newDiscoveryTxHash)[0]
: undefined
const existingDiscoveryTxHash = addressForDiscoveryTxHash
? asset.metadata?.discoveryTxHash?.[addressForDiscoveryTxHash]
: undefined
const noExistingDiscoveryTxHash = !!existingDiscoveryTxHash

// If the discovery tx hash is specified
// or if it does not already exists in the asset, do update the asset.
// However, this should only happen for untrusted assets.
const allowAddDiscoveryTxHash =
isUntrustedAsset(asset) &&
(!!newDiscoveryTxHash || noExistingDiscoveryTxHash)

// Refresh a known unverified asset if it has been manually imported.
// This check allows the user to add an asset from the unverified list.
const isManuallyImported = metadata?.verified
const allowVerifyAssetByManualImport =
!isVerifiedAsset(asset) && isManuallyImported

return allowVerifyAssetByManualImport || allowAddDiscoveryTxHash
}
115 changes: 115 additions & 0 deletions background/services/indexing/utils/tests/index.unit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { shouldRefreshKnownAsset } from ".."
import { createSmartContractAsset } from "../../../../tests/factories"
import * as featureFlags from "../../../../features"

const ADDRESS = "0x0000000000000000000000000000000000000000"
const DISCOVERY_TX_HASH = "0x0000000000000000000000000000000000000000"
const METADATA_TX = {
discoveryTxHash: {
[ADDRESS]: DISCOVERY_TX_HASH,
},
}
const METADATA_VERIFIED = {
verified: true,
}

const TRUSTED_ASSET = createSmartContractAsset()
const UNTRUSTED_ASSET = createSmartContractAsset({
metadata: { tokenLists: [] },
})

describe("IndexingService utils", () => {
describe("shouldRefreshKnownAsset", () => {
beforeAll(() => {
jest.spyOn(featureFlags, "isEnabled").mockImplementation(() => true)
})

it("Refresh the untrusted asset if manually imported", () => {
const shouldBeRefreshed = shouldRefreshKnownAsset(
UNTRUSTED_ASSET,
METADATA_VERIFIED
)

expect(shouldBeRefreshed).toBe(true)
})

it("Not refresh the untrusted asset if not manually imported", () => {
const shouldBeRefreshed = shouldRefreshKnownAsset(UNTRUSTED_ASSET, {})

expect(shouldBeRefreshed).toBe(false)
})

it("Not refresh the trusted asset if not manually imported", () => {
const shouldBeRefreshed = shouldRefreshKnownAsset(TRUSTED_ASSET, {})

expect(shouldBeRefreshed).toBe(false)
})

// This state is not quite possible in the app because the user is not able to manually import a trusted asset that exists.
it("Not refresh the trusted asset if manually imported", () => {
const shouldBeRefreshed = shouldRefreshKnownAsset(
TRUSTED_ASSET,
METADATA_VERIFIED
)

expect(shouldBeRefreshed).toBe(false)
})

it("Refresh the untrusted asset if it does not already have a discovered tx hash", () => {
const shouldBeRefreshed = shouldRefreshKnownAsset(
UNTRUSTED_ASSET,
METADATA_TX
)

expect(shouldBeRefreshed).toBe(true)
})

it("Not refresh the trusted asset if it does not already have a discovered tx hash", () => {
const shouldBeRefreshed = shouldRefreshKnownAsset(
TRUSTED_ASSET,
METADATA_TX
)

expect(shouldBeRefreshed).toBe(false)
})

it("Not refresh the untrusted asset if it does already have a discovered tx hash", () => {
const asset = {
...UNTRUSTED_ASSET,
metadata: { ...UNTRUSTED_ASSET, ...METADATA_TX },
}
const shouldBeRefreshed = shouldRefreshKnownAsset(asset, METADATA_TX)

expect(shouldBeRefreshed).toBe(false)
})

it("Not refresh the trusted asset if it does already have a discovered tx hash", () => {
const asset = {
...TRUSTED_ASSET,
metadata: { ...TRUSTED_ASSET, ...METADATA_TX },
}
const shouldBeRefreshed = shouldRefreshKnownAsset(asset, METADATA_TX)

expect(shouldBeRefreshed).toBe(false)
})

it("Not refresh the trusted asset if discovered tx hash is not specified", () => {
const asset = {
...TRUSTED_ASSET,
metadata: { ...TRUSTED_ASSET, ...METADATA_TX },
}

expect(shouldRefreshKnownAsset(TRUSTED_ASSET, {})).toBe(false)
expect(shouldRefreshKnownAsset(asset, {})).toBe(false)
})
it("Not refresh the untrusted asset if discovered tx hash is not specified", () => {
const asset = {
...UNTRUSTED_ASSET,
metadata: { ...UNTRUSTED_ASSET, ...METADATA_TX },
}

expect(shouldRefreshKnownAsset(UNTRUSTED_ASSET, {})).toBe(false)
expect(shouldRefreshKnownAsset(asset, {})).toBe(false)
})
})
})

0 comments on commit 12dce07

Please sign in to comment.