diff --git a/apps/laboratory/package.json b/apps/laboratory/package.json index 27e3bd7ba6..cb6f86c44e 100644 --- a/apps/laboratory/package.json +++ b/apps/laboratory/package.json @@ -19,7 +19,7 @@ "@emotion/styled": "11.11.0", "@sentry/browser": "7.92.0", "@sentry/react": "7.92.0", - "@tanstack/react-query": "5.17.19", + "@tanstack/react-query": "5.18.1", "@web3modal/ethers": "4.0.0-648b6755", "@web3modal/ethers5": "4.0.0-648b6755", "@web3modal/wagmi": "4.0.0-648b6755", @@ -29,8 +29,8 @@ "react-icons": "4.12.0", "siwe": "2.1.4", "valtio": "1.11.2", - "viem": "2.5.0", - "wagmi": "2.5.0" + "viem": "2.7.1", + "wagmi": "2.5.5" }, "devDependencies": { "@mailsac/api": "1.0.5", diff --git a/package-lock.json b/package-lock.json index 7c9f66a9b0..734a11fbae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -76,7 +76,7 @@ "@emotion/styled": "11.11.0", "@sentry/browser": "7.92.0", "@sentry/react": "7.92.0", - "@tanstack/react-query": "5.17.19", + "@tanstack/react-query": "5.18.1", "@web3modal/ethers": "4.0.0-648b6755", "@web3modal/ethers5": "4.0.0-648b6755", "@web3modal/wagmi": "4.0.0-648b6755", @@ -86,8 +86,8 @@ "react-icons": "4.12.0", "siwe": "2.1.4", "valtio": "1.11.2", - "viem": "2.5.0", - "wagmi": "2.5.0" + "viem": "2.7.1", + "wagmi": "2.5.5" }, "devDependencies": { "@mailsac/api": "1.0.5", @@ -96,6 +96,129 @@ "ethers": "6.9.0" } }, + "apps/laboratory/node_modules/@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "apps/laboratory/node_modules/@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "apps/laboratory/node_modules/@scure/bip32": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.2.tgz", + "integrity": "sha512-N1ZhksgwD3OBlwTv3R6KFEcPojl/W4ElJOeCZdi+vuI5QmTFwLq3OFf2zd2ROpKvxFdgZ6hUpb0dx9bVNEwYCA==", + "dependencies": { + "@noble/curves": "~1.2.0", + "@noble/hashes": "~1.3.2", + "@scure/base": "~1.1.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "apps/laboratory/node_modules/@scure/bip39": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.1.tgz", + "integrity": "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==", + "dependencies": { + "@noble/hashes": "~1.3.0", + "@scure/base": "~1.1.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "apps/laboratory/node_modules/@tanstack/query-core": { + "version": "5.18.1", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.18.1.tgz", + "integrity": "sha512-fYhrG7bHgSNbnkIJF2R4VUXb4lF7EBiQjKkDc5wOlB7usdQOIN4LxxHpDxyE3qjqIst1WBGvDtL48T0sHJGKCw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "apps/laboratory/node_modules/@tanstack/react-query": { + "version": "5.18.1", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.18.1.tgz", + "integrity": "sha512-PdI07BbsahZ+04PxSuDQsQvBWe008eWFk/YYWzt8fvzt2sALUM0TpAJa/DFpqa7+SSo7j1EQR6Jx6znXNHyaXw==", + "dependencies": { + "@tanstack/query-core": "5.18.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18.0.0" + } + }, + "apps/laboratory/node_modules/@wagmi/connectors": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@wagmi/connectors/-/connectors-4.1.12.tgz", + "integrity": "sha512-zqCJMOwpi8ssFjndVxVh3iUMwzcA7dPCjswhcy4xZyy1jm/VvGYC3o1wotq/gTCqUrz0SPIMGimZm4S6865b8A==", + "dependencies": { + "@coinbase/wallet-sdk": "3.9.1", + "@metamask/sdk": "0.14.1", + "@safe-global/safe-apps-provider": "0.18.1", + "@safe-global/safe-apps-sdk": "8.1.0", + "@walletconnect/ethereum-provider": "2.11.0", + "@walletconnect/modal": "2.6.2" + }, + "funding": { + "url": "https://github.com/sponsors/wevm" + }, + "peerDependencies": { + "@wagmi/core": "2.6.3", + "typescript": ">=5.0.4", + "viem": "2.x" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "apps/laboratory/node_modules/@wagmi/core": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/@wagmi/core/-/core-2.6.3.tgz", + "integrity": "sha512-hHvJkXFqfj56nAD0SH5bAHYxBItUBDIn6yGUBguMu121v6R4NxhwciEeff56lSjnKhmXjaWdJCEJ9C1YwkmDVw==", + "dependencies": { + "eventemitter3": "5.0.1", + "mipd": "0.0.5", + "zustand": "4.4.1" + }, + "funding": { + "url": "https://github.com/sponsors/wevm" + }, + "peerDependencies": { + "@tanstack/query-core": ">=5.0.0", + "typescript": ">=5.0.4", + "viem": "2.x" + }, + "peerDependenciesMeta": { + "@tanstack/query-core": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, "apps/laboratory/node_modules/next": { "version": "14.0.4", "resolved": "https://registry.npmjs.org/next/-/next-14.0.4.tgz", @@ -142,6 +265,79 @@ } } }, + "apps/laboratory/node_modules/viem": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.7.1.tgz", + "integrity": "sha512-izAX2KedTFnI2l0ZshtnlK2ZuDvSlKeuaanWyNwC4ffDgrCGtwX1bvVXO3Krh53lZgqvjd8UGpjGaBl3WqJ4yQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "dependencies": { + "@adraffy/ens-normalize": "1.10.0", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", + "@scure/bip32": "1.3.2", + "@scure/bip39": "1.2.1", + "abitype": "1.0.0", + "isows": "1.0.3", + "ws": "8.13.0" + }, + "peerDependencies": { + "typescript": ">=5.0.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "apps/laboratory/node_modules/wagmi": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/wagmi/-/wagmi-2.5.5.tgz", + "integrity": "sha512-U9F5+e4bFXhSvIAWaImP4oCDXnOG/7q1xnBlkWBwbGy+oWg3BBiD01BZUnkplFGu6scSZ+TPURGtOkwH0rnxBQ==", + "dependencies": { + "@wagmi/connectors": "4.1.12", + "@wagmi/core": "2.6.3", + "use-sync-external-store": "1.2.0" + }, + "funding": { + "url": "https://github.com/sponsors/wevm" + }, + "peerDependencies": { + "@tanstack/react-query": ">=5.0.0", + "react": ">=18", + "typescript": ">=5.0.4", + "viem": "2.x" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "apps/laboratory/node_modules/ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "examples/html-ethers5": { "name": "@examples/html-ethers5", "version": "4.0.0-648b6755", diff --git a/packages/common/src/utils/TypeUtil.ts b/packages/common/src/utils/TypeUtil.ts index e2bb8475e4..fcf0c73b99 100644 --- a/packages/common/src/utils/TypeUtil.ts +++ b/packages/common/src/utils/TypeUtil.ts @@ -16,6 +16,7 @@ export interface Transaction { export interface TransactionMetadata { operationType: string hash: string + chain: `${string}:${string}` minedAt: string sentFrom: string sentTo: string diff --git a/packages/core/src/controllers/NetworkController.ts b/packages/core/src/controllers/NetworkController.ts index 88ff15cf09..f2fd514d78 100644 --- a/packages/core/src/controllers/NetworkController.ts +++ b/packages/core/src/controllers/NetworkController.ts @@ -1,8 +1,7 @@ import { subscribeKey as subKey } from 'valtio/utils' -import { proxy, ref } from 'valtio/vanilla' +import { proxy, ref, subscribe as sub } from 'valtio/vanilla' import type { CaipNetwork, CaipNetworkId } from '../utils/TypeUtil.js' import { PublicStateController } from './PublicStateController.js' -import { TransactionsController } from './TransactionsController.js' import { EventsController } from './EventsController.js' import { ModalController } from './ModalController.js' @@ -37,6 +36,10 @@ const state = proxy({ export const NetworkController = { state, + subscribe(callback: (newState: NetworkControllerState) => void) { + return sub(state, () => callback(state)) + }, + subscribeKey(key: K, callback: (value: NetworkControllerState[K]) => void) { return subKey(state, key, callback) }, @@ -54,9 +57,6 @@ export const NetworkController = { }, setCaipNetwork(caipNetwork: NetworkControllerState['caipNetwork']) { - TransactionsController.setPrevChainInView(TransactionsController.state.chainInView) - TransactionsController.setChainInView(caipNetwork?.name) - state.caipNetwork = caipNetwork PublicStateController.set({ selectedNetworkId: caipNetwork?.id }) this.checkIfSupportedNetwork() diff --git a/packages/core/src/controllers/TransactionsController.ts b/packages/core/src/controllers/TransactionsController.ts index 68a21d330e..52ccd4fd8a 100644 --- a/packages/core/src/controllers/TransactionsController.ts +++ b/packages/core/src/controllers/TransactionsController.ts @@ -13,8 +13,7 @@ type TransactionByYearMap = Record export interface TransactionsControllerState { transactions: Transaction[] transactionsByYear: TransactionByYearMap - chainInView: string | undefined - prevChainInView: string | undefined + lastNetworkInView: string | undefined loading: boolean empty: boolean next: string | undefined @@ -24,8 +23,7 @@ export interface TransactionsControllerState { const state = proxy({ transactions: [], transactionsByYear: {}, - chainInView: undefined, - prevChainInView: undefined, + lastNetworkInView: undefined, loading: false, empty: false, next: undefined @@ -39,12 +37,8 @@ export const TransactionsController = { return sub(state, () => callback(state)) }, - setChainInView(chainInView: TransactionsControllerState['chainInView']) { - state.chainInView = chainInView - }, - - setPrevChainInView(prevChainInView: TransactionsControllerState['prevChainInView']) { - state.prevChainInView = prevChainInView + setLastNetworkInView(lastNetworkInView: TransactionsControllerState['lastNetworkInView']) { + state.lastNetworkInView = lastNetworkInView }, async fetchTransactions(accountAddress?: string) { @@ -123,11 +117,9 @@ export const TransactionsController = { }, filterByConnectedChain(transactions: Transaction[]) { - //TOD0 - This should filter by chain - fungible info is very unrelated - const chainName = NetworkController.state.caipNetwork?.name + const chainId = NetworkController.state.caipNetwork?.id const filteredTransactions = transactions.filter( - transaction => - transaction.transfers[0]?.fungible_info?.name?.toLowerCase() === chainName?.toLowerCase() + transaction => transaction.metadata.chain === chainId ) return filteredTransactions @@ -136,6 +128,7 @@ export const TransactionsController = { resetTransactions() { state.transactions = [] state.transactionsByYear = {} + state.lastNetworkInView = undefined state.loading = false state.empty = false state.next = undefined diff --git a/packages/scaffold/src/views/w3m-transactions-view/index.ts b/packages/scaffold/src/views/w3m-transactions-view/index.ts index 3b5336f7eb..c442af1495 100644 --- a/packages/scaffold/src/views/w3m-transactions-view/index.ts +++ b/packages/scaffold/src/views/w3m-transactions-view/index.ts @@ -3,6 +3,7 @@ import type { Transaction } from '@web3modal/common' import { AccountController, EventsController, + NetworkController, OptionsController, TransactionsController } from '@web3modal/core' @@ -28,13 +29,6 @@ export class W3mTransactionsView extends LitElement { // -- State & Properties -------------------------------- // @state() private address: string | undefined = AccountController.state.address - @state() private isFirstUpdate = true - - /** Keep track of the previous chain in chase the chain changes while the component is mounted */ - @state() private chainInMemory: string | undefined - - @state() private transactions = TransactionsController.state.transactions - @state() private transactionsByYear = TransactionsController.state.transactionsByYear @state() private loading = TransactionsController.state.loading @@ -57,14 +51,10 @@ export class W3mTransactionsView extends LitElement { } } }), + NetworkController.subscribe(() => { + this.updateTransactionView() + }), TransactionsController.subscribe(val => { - if (val.chainInView !== this.chainInMemory && !this.isFirstUpdate) { - this.chainInMemory = val.chainInView - TransactionsController.resetTransactions() - TransactionsController.fetchTransactions(this.address) - TransactionsController.setPrevChainInView(val.chainInView) - } - this.transactions = val.transactions this.transactionsByYear = val.transactionsByYear this.loading = val.loading this.empty = val.empty @@ -75,19 +65,7 @@ export class W3mTransactionsView extends LitElement { } public override firstUpdated() { - const prevChainInView = TransactionsController.state.prevChainInView - const chainInView = TransactionsController.state.chainInView - this.chainInMemory = chainInView - - if (this.transactions.length === 0) { - TransactionsController.fetchTransactions(this.address) - } else if (prevChainInView !== chainInView) { - TransactionsController.resetTransactions() - TransactionsController.fetchTransactions(this.address) - } - /* Prevent resetTransactions when coming back */ - TransactionsController.setPrevChainInView(chainInView) - this.isFirstUpdate = false + this.updateTransactionView() this.createPaginationObserver() } @@ -111,6 +89,17 @@ export class W3mTransactionsView extends LitElement { } // -- Private ------------------------------------------- // + private updateTransactionView() { + const currentNetwork = NetworkController.state.caipNetwork?.id + const lastNetworkInView = TransactionsController.state.lastNetworkInView + + if (lastNetworkInView !== currentNetwork) { + TransactionsController.resetTransactions() + TransactionsController.fetchTransactions(this.address) + } + TransactionsController.setLastNetworkInView(currentNetwork) + } + private templateTransactionsByYear() { const sortedYearKeys = Object.keys(this.transactionsByYear).sort().reverse()